Coverage Report

Created: 2025-02-15 06:44

/src/glaze/include/glaze/json/json_format.hpp
Line
Count
Source (jump to first uncovered line)
1
// Glaze Library
2
// For the license information refer to glaze.hpp
3
4
#pragma once
5
6
#include "glaze/core/common.hpp"
7
#include "glaze/core/opts.hpp"
8
#include "glaze/util/dump.hpp"
9
#include "glaze/util/parse.hpp"
10
11
namespace glz::detail
12
{
13
   enum struct json_type : char {
14
      Unset = 'x',
15
      String = '"',
16
      Comma = ',',
17
      Number = '-',
18
      Colon = ':',
19
      Array_Start = '[',
20
      Array_End = ']',
21
      Null = 'n',
22
      Bool = 't',
23
      Object_Start = '{',
24
      Object_End = '}',
25
      Comment = '/'
26
   };
27
28
   constexpr std::array<json_type, 256> json_types = [] {
29
      std::array<json_type, 256> t{};
30
      using enum json_type;
31
      t['"'] = String;
32
      t[','] = Comma;
33
      t['0'] = Number;
34
      t['1'] = Number;
35
      t['2'] = Number;
36
      t['3'] = Number;
37
      t['4'] = Number;
38
      t['5'] = Number;
39
      t['6'] = Number;
40
      t['7'] = Number;
41
      t['8'] = Number;
42
      t['9'] = Number;
43
      t['-'] = Number;
44
      t[':'] = Colon;
45
      t['['] = Array_Start;
46
      t[']'] = Array_End;
47
      t['n'] = Null;
48
      t['t'] = Bool;
49
      t['f'] = Bool;
50
      t['{'] = Object_Start;
51
      t['}'] = Object_End;
52
      t['/'] = Comment;
53
      return t;
54
   }();
55
56
   template <bool use_tabs, uint8_t indentation_width>
57
   inline void append_new_line(auto&& b, auto&& ix, const int64_t indent)
58
203k
   {
59
203k
      dump<'\n'>(b, ix);
60
      if constexpr (use_tabs) {
61
         dumpn<'\t'>(indent, b, ix);
62
      }
63
203k
      else {
64
203k
         dumpn<' '>(indent * indentation_width, b, ix);
65
203k
      }
66
203k
   };
67
68
   template <opts Opts>
69
      requires(has_is_padded(Opts))
70
   sv read_json_string(auto&& it, auto&& end) noexcept
71
1.15k
   {
72
1.15k
      auto start = it;
73
1.15k
      ++it; // skip quote
74
605k
      while (it < end) [[likely]] {
75
605k
         uint64_t chunk;
76
605k
         std::memcpy(&chunk, it, 8);
77
605k
         const uint64_t quote = has_quote(chunk);
78
605k
         if (quote) {
79
1.63k
            it += (countr_zero(quote) >> 3);
80
81
1.63k
            auto* prev = it - 1;
82
2.38k
            while (*prev == '\\') {
83
757
               --prev;
84
757
            }
85
1.63k
            if (size_t(it - prev) % 2) {
86
1.10k
               ++it; // add quote
87
1.10k
               return {start, size_t(it - start)};
88
1.10k
            }
89
527
            ++it; // skip escaped quote and continue
90
527
         }
91
604k
         else {
92
604k
            it += 8;
93
604k
         }
94
605k
      }
95
96
48
      return {};
97
1.15k
   }
98
99
   template <opts Opts>
100
      requires(!has_is_padded(Opts))
101
   sv read_json_string(auto&& it, auto&& end) noexcept
102
27.0k
   {
103
27.0k
      auto start = it;
104
27.0k
      ++it; // skip quote
105
1.02M
      for (const auto end_m7 = end - 7; it < end_m7;) {
106
1.02M
         uint64_t chunk;
107
1.02M
         std::memcpy(&chunk, it, 8);
108
1.02M
         const uint64_t quote = has_quote(chunk);
109
1.02M
         if (quote) {
110
27.0k
            it += (countr_zero(quote) >> 3);
111
112
27.0k
            auto* prev = it - 1;
113
27.6k
            while (*prev == '\\') {
114
600
               --prev;
115
600
            }
116
27.0k
            if (size_t(it - prev) % 2) {
117
27.0k
               ++it; // add quote
118
27.0k
               return {start, size_t(it - start)};
119
27.0k
            }
120
40
            ++it; // skip escaped quote and continue
121
40
         }
122
1.00M
         else {
123
1.00M
            it += 8;
124
1.00M
         }
125
1.02M
      }
126
127
      // Tail end of buffer. Should be rare we even get here
128
26
      while (it < end) {
129
21
         if (*it == '"') {
130
1
            auto* prev = it - 1;
131
1
            while (*prev == '\\') {
132
0
               --prev;
133
0
            }
134
1
            if (size_t(it - prev) % 2) {
135
1
               ++it; // add quote
136
1
               return {start, size_t(it - start)};
137
1
            }
138
1
         }
139
20
         ++it;
140
20
      }
141
142
5
      return {};
143
6
   }
144
145
   // Reads /* my comment */ style comments
146
   inline sv read_jsonc_comment(auto&& it, auto&& end) noexcept
147
   {
148
      auto start = it;
149
      it += 2; // skip /*
150
      for (const auto end_m7 = end - 7; it < end_m7;) {
151
         uint64_t chunk;
152
         std::memcpy(&chunk, it, 8);
153
         const uint64_t slash = has_char<'/'>(chunk);
154
         if (slash) {
155
            it += (countr_zero(slash) >> 3);
156
157
            if (it[-1] == '*') {
158
               ++it; // add slash
159
               return {start, size_t(it - start)};
160
            }
161
            // skip slash and continue
162
            ++it;
163
         }
164
         else {
165
            it += 8;
166
         }
167
      }
168
169
      // Tail end of buffer. Should be rare we even get here
170
      while (it < end) {
171
         if (it[-1] == '*' && *it == '/') {
172
            ++it; // add slash
173
            return {start, size_t(it - start)};
174
         }
175
         ++it;
176
      }
177
178
      return {};
179
   }
180
181
   inline sv read_json_number(auto&& it) noexcept
182
41.7k
   {
183
41.7k
      auto start = it;
184
470k
      while (numeric_table[uint8_t(*it)]) {
185
429k
         ++it;
186
429k
      }
187
41.7k
      return {start, size_t(it - start)};
188
41.7k
   }
189
}