Coverage Report

Created: 2025-11-15 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glaze/include/glaze/json/skip.hpp
Line
Count
Source
1
// Glaze Library
2
// For the license information refer to glaze.hpp
3
4
#pragma once
5
6
#include "glaze/util/parse.hpp"
7
8
namespace glz
9
{
10
   template <>
11
   struct skip_value<JSON>
12
   {
13
      template <auto Opts>
14
         requires(not Opts.comments)
15
      GLZ_ALWAYS_INLINE static void op(is_context auto&& ctx, auto&& it, auto&& end) noexcept;
16
17
      template <auto Opts>
18
         requires(bool(Opts.comments))
19
      GLZ_ALWAYS_INLINE static void op(is_context auto&& ctx, auto&& it, auto&& end) noexcept;
20
   };
21
22
   template <auto Opts>
23
   void skip_object(is_context auto&& ctx, auto&& it, auto&& end) noexcept
24
   {
25
      if constexpr (!check_validate_skipped(Opts)) {
26
         ++it;
27
         if constexpr (not Opts.null_terminated) {
28
            if (it == end) [[unlikely]] {
29
               ctx.error = error_code::unexpected_end;
30
               return;
31
            }
32
         }
33
         skip_until_closed<Opts, '{', '}'>(ctx, it, end);
34
      }
35
      else {
36
         if constexpr (not Opts.null_terminated) {
37
            ++ctx.indentation_level;
38
         }
39
         ++it;
40
         if constexpr (not Opts.null_terminated) {
41
            if (it == end) [[unlikely]] {
42
               ctx.error = error_code::unexpected_end;
43
               return;
44
            }
45
         }
46
         if (skip_ws<Opts>(ctx, it, end)) {
47
            return;
48
         }
49
         if (*it == '}') {
50
            if constexpr (not Opts.null_terminated) {
51
               --ctx.indentation_level;
52
            }
53
            ++it;
54
            if constexpr (not Opts.null_terminated) {
55
               if (it == end) {
56
                  ctx.error = error_code::end_reached;
57
                  return;
58
               }
59
            }
60
            return;
61
         }
62
         while (true) {
63
            if (*it != '"') {
64
               ctx.error = error_code::syntax_error;
65
               return;
66
            }
67
            skip_string<Opts>(ctx, it, end);
68
            if (bool(ctx.error)) [[unlikely]]
69
               return;
70
            if (skip_ws<Opts>(ctx, it, end)) {
71
               return;
72
            }
73
            if (match_invalid_end<':', Opts>(ctx, it, end)) {
74
               return;
75
            }
76
            if (skip_ws<Opts>(ctx, it, end)) {
77
               return;
78
            }
79
            skip_value<JSON>::op<Opts>(ctx, it, end);
80
            if (bool(ctx.error)) [[unlikely]]
81
               return;
82
            if (skip_ws<Opts>(ctx, it, end)) {
83
               return;
84
            }
85
            if (*it != ',') break;
86
            ++it;
87
            if constexpr (not Opts.null_terminated) {
88
               if (it == end) [[unlikely]] {
89
                  ctx.error = error_code::unexpected_end;
90
                  return;
91
               }
92
            }
93
            if (skip_ws<Opts>(ctx, it, end)) {
94
               return;
95
            }
96
         }
97
         match<'}'>(ctx, it);
98
         if constexpr (not Opts.null_terminated) {
99
            --ctx.indentation_level;
100
         }
101
         if constexpr (not Opts.null_terminated) {
102
            if (it == end) {
103
               ctx.error = error_code::end_reached;
104
               return;
105
            }
106
         }
107
      }
108
   }
109
110
   template <auto Opts>
111
      requires(Opts.format == JSON || Opts.format == NDJSON)
112
   void skip_array(is_context auto&& ctx, auto&& it, auto&& end) noexcept
113
   {
114
      if constexpr (!check_validate_skipped(Opts)) {
115
         ++it;
116
         if constexpr (not Opts.null_terminated) {
117
            if (it == end) [[unlikely]] {
118
               ctx.error = error_code::unexpected_end;
119
               return;
120
            }
121
         }
122
         skip_until_closed<Opts, '[', ']'>(ctx, it, end);
123
      }
124
      else {
125
         if constexpr (not Opts.null_terminated) {
126
            ++ctx.indentation_level;
127
         }
128
         ++it;
129
         if constexpr (not Opts.null_terminated) {
130
            if (it == end) [[unlikely]] {
131
               ctx.error = error_code::unexpected_end;
132
               return;
133
            }
134
         }
135
         if (skip_ws<Opts>(ctx, it, end)) {
136
            return;
137
         }
138
         if (*it == ']') {
139
            if constexpr (not Opts.null_terminated) {
140
               --ctx.indentation_level;
141
            }
142
            ++it;
143
            if constexpr (not Opts.null_terminated) {
144
               if (it == end) {
145
                  ctx.error = error_code::end_reached;
146
                  return;
147
               }
148
            }
149
            return;
150
         }
151
         while (true) {
152
            skip_value<JSON>::op<Opts>(ctx, it, end);
153
            if (bool(ctx.error)) [[unlikely]]
154
               return;
155
            if (skip_ws<Opts>(ctx, it, end)) {
156
               return;
157
            }
158
            if (*it != ',') break;
159
            ++it;
160
            if constexpr (not Opts.null_terminated) {
161
               if (it == end) [[unlikely]] {
162
                  ctx.error = error_code::unexpected_end;
163
                  return;
164
               }
165
            }
166
            if (skip_ws<Opts>(ctx, it, end)) {
167
               return;
168
            }
169
         }
170
         match<']'>(ctx, it);
171
         if constexpr (not Opts.null_terminated) {
172
            --ctx.indentation_level;
173
         }
174
         if constexpr (not Opts.null_terminated) {
175
            if (it == end) {
176
               ctx.error = error_code::end_reached;
177
               return;
178
            }
179
         }
180
      }
181
   }
182
183
   // parse_value is used for JSON pointer reading
184
   // we want the JSON pointer access to not care about trailing whitespace
185
   // so we use validate_skipped for precise validation and value skipping
186
   // expects opening whitespace to be handled
187
   template <auto Opts>
188
   GLZ_ALWAYS_INLINE auto parse_value(is_context auto&& ctx, auto&& it, auto&& end) noexcept
189
   {
190
      auto start = it;
191
      struct opts_validate_skipped : std::decay_t<decltype(Opts)>
192
      {
193
         bool validate_skipped = true;
194
      };
195
      skip_value<JSON>::op<opts_validate_skipped{{Opts}}>(ctx, it, end);
196
      return std::span{start, size_t(it - start)};
197
   }
198
199
   template <auto Opts>
200
      requires(not Opts.comments)
201
   GLZ_ALWAYS_INLINE void skip_value<JSON>::op(is_context auto&& ctx, auto&& it, auto&& end) noexcept
202
6.51k
   {
203
6.51k
      using namespace glz::detail;
204
205
6.51k
      if constexpr (not check_validate_skipped(Opts)) {
206
6.51k
         if constexpr (not check_ws_handled(Opts)) {
207
6.51k
            if (skip_ws<Opts>(ctx, it, end)) {
208
116
               return;
209
116
            }
210
6.51k
         }
211
7.39k
         while (true) {
212
7.25k
            switch (*it) {
213
890
            case '{':
214
890
               ++it;
215
890
               if constexpr (not Opts.null_terminated) {
216
426
                  if (it == end) [[unlikely]] {
217
3
                     ctx.error = error_code::unexpected_end;
218
3
                     return;
219
3
                  }
220
426
               }
221
423
               skip_until_closed<Opts, '{', '}'>(ctx, it, end);
222
890
               if (bool(ctx.error)) [[unlikely]]
223
314
                  return;
224
576
               break;
225
1.46k
            case '[':
226
1.46k
               ++it;
227
1.46k
               if constexpr (not Opts.null_terminated) {
228
466
                  if (it == end) [[unlikely]] {
229
5
                     ctx.error = error_code::unexpected_end;
230
5
                     return;
231
5
                  }
232
466
               }
233
461
               skip_until_closed<Opts, '[', ']'>(ctx, it, end);
234
1.46k
               if (bool(ctx.error)) [[unlikely]]
235
341
                  return;
236
1.12k
               break;
237
1.12k
            case '"':
238
757
               skip_string<Opts>(ctx, it, end);
239
757
               if (bool(ctx.error)) [[unlikely]]
240
30
                  return;
241
727
               break;
242
3.02k
            case ',':
243
3.02k
            case '}':
244
3.04k
            case ']':
245
3.04k
               break;
246
223
            case '\0':
247
223
               ctx.error = error_code::unexpected_end;
248
223
               return;
249
880
            default: {
250
880
               ++it;
251
880
               if constexpr (not Opts.null_terminated) {
252
319
                  if (it == end) [[unlikely]] {
253
26
                     ctx.error = error_code::unexpected_end;
254
26
                     return;
255
26
                  }
256
319
               }
257
293
               continue;
258
3.02k
            }
259
7.25k
            }
260
261
5.45k
            break;
262
7.25k
         }
263
      }
264
      else {
265
         if constexpr (not check_ws_handled(Opts)) {
266
            if (skip_ws<Opts>(ctx, it, end)) {
267
               return;
268
            }
269
         }
270
         switch (*it) {
271
         case '{': {
272
            skip_object<Opts>(ctx, it, end);
273
            break;
274
         }
275
         case '[': {
276
            skip_array<Opts>(ctx, it, end);
277
            break;
278
         }
279
         case '"': {
280
            skip_string<Opts>(ctx, it, end);
281
            break;
282
         }
283
         case 'n': {
284
            ++it;
285
            match<"ull", Opts>(ctx, it, end);
286
            break;
287
         }
288
         case 'f': {
289
            ++it;
290
            match<"alse", Opts>(ctx, it, end);
291
            break;
292
         }
293
         case 't': {
294
            ++it;
295
            match<"rue", Opts>(ctx, it, end);
296
            break;
297
         }
298
         case '\0': {
299
            ctx.error = error_code::unexpected_end;
300
            break;
301
         }
302
         default: {
303
            skip_number<Opts>(ctx, it, end);
304
         }
305
         }
306
      }
307
6.51k
   }
_ZN3glz10skip_valueILj10EE2opITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEETkNS_10is_contextERNS_7contextERPKcS8_QntdtT_8commentsEEvOT0_OT1_OT2_
Line
Count
Source
202
3.97k
   {
203
3.97k
      using namespace glz::detail;
204
205
3.97k
      if constexpr (not check_validate_skipped(Opts)) {
206
3.97k
         if constexpr (not check_ws_handled(Opts)) {
207
3.97k
            if (skip_ws<Opts>(ctx, it, end)) {
208
0
               return;
209
0
            }
210
3.97k
         }
211
4.53k
         while (true) {
212
4.53k
            switch (*it) {
213
464
            case '{':
214
464
               ++it;
215
               if constexpr (not Opts.null_terminated) {
216
                  if (it == end) [[unlikely]] {
217
                     ctx.error = error_code::unexpected_end;
218
                     return;
219
                  }
220
               }
221
464
               skip_until_closed<Opts, '{', '}'>(ctx, it, end);
222
464
               if (bool(ctx.error)) [[unlikely]]
223
158
                  return;
224
306
               break;
225
998
            case '[':
226
998
               ++it;
227
               if constexpr (not Opts.null_terminated) {
228
                  if (it == end) [[unlikely]] {
229
                     ctx.error = error_code::unexpected_end;
230
                     return;
231
                  }
232
               }
233
998
               skip_until_closed<Opts, '[', ']'>(ctx, it, end);
234
998
               if (bool(ctx.error)) [[unlikely]]
235
172
                  return;
236
826
               break;
237
826
            case '"':
238
507
               skip_string<Opts>(ctx, it, end);
239
507
               if (bool(ctx.error)) [[unlikely]]
240
14
                  return;
241
493
               break;
242
1.78k
            case ',':
243
1.78k
            case '}':
244
1.78k
            case ']':
245
1.78k
               break;
246
216
            case '\0':
247
216
               ctx.error = error_code::unexpected_end;
248
216
               return;
249
561
            default: {
250
561
               ++it;
251
               if constexpr (not Opts.null_terminated) {
252
                  if (it == end) [[unlikely]] {
253
                     ctx.error = error_code::unexpected_end;
254
                     return;
255
                  }
256
               }
257
561
               continue;
258
1.78k
            }
259
4.53k
            }
260
261
3.41k
            break;
262
4.53k
         }
263
      }
264
      else {
265
         if constexpr (not check_ws_handled(Opts)) {
266
            if (skip_ws<Opts>(ctx, it, end)) {
267
               return;
268
            }
269
         }
270
         switch (*it) {
271
         case '{': {
272
            skip_object<Opts>(ctx, it, end);
273
            break;
274
         }
275
         case '[': {
276
            skip_array<Opts>(ctx, it, end);
277
            break;
278
         }
279
         case '"': {
280
            skip_string<Opts>(ctx, it, end);
281
            break;
282
         }
283
         case 'n': {
284
            ++it;
285
            match<"ull", Opts>(ctx, it, end);
286
            break;
287
         }
288
         case 'f': {
289
            ++it;
290
            match<"alse", Opts>(ctx, it, end);
291
            break;
292
         }
293
         case 't': {
294
            ++it;
295
            match<"rue", Opts>(ctx, it, end);
296
            break;
297
         }
298
         case '\0': {
299
            ctx.error = error_code::unexpected_end;
300
            break;
301
         }
302
         default: {
303
            skip_number<Opts>(ctx, it, end);
304
         }
305
         }
306
      }
307
3.97k
   }
_ZN3glz10skip_valueILj10EE2opITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEETkNS_10is_contextERNS_7contextERPKcS8_QntdtT_8commentsEEvOT0_OT1_OT2_
Line
Count
Source
202
2.54k
   {
203
2.54k
      using namespace glz::detail;
204
205
2.54k
      if constexpr (not check_validate_skipped(Opts)) {
206
2.54k
         if constexpr (not check_ws_handled(Opts)) {
207
2.54k
            if (skip_ws<Opts>(ctx, it, end)) {
208
116
               return;
209
116
            }
210
2.54k
         }
211
2.86k
         while (true) {
212
2.72k
            switch (*it) {
213
426
            case '{':
214
426
               ++it;
215
426
               if constexpr (not Opts.null_terminated) {
216
426
                  if (it == end) [[unlikely]] {
217
3
                     ctx.error = error_code::unexpected_end;
218
3
                     return;
219
3
                  }
220
426
               }
221
423
               skip_until_closed<Opts, '{', '}'>(ctx, it, end);
222
426
               if (bool(ctx.error)) [[unlikely]]
223
156
                  return;
224
270
               break;
225
466
            case '[':
226
466
               ++it;
227
466
               if constexpr (not Opts.null_terminated) {
228
466
                  if (it == end) [[unlikely]] {
229
5
                     ctx.error = error_code::unexpected_end;
230
5
                     return;
231
5
                  }
232
466
               }
233
461
               skip_until_closed<Opts, '[', ']'>(ctx, it, end);
234
466
               if (bool(ctx.error)) [[unlikely]]
235
169
                  return;
236
297
               break;
237
297
            case '"':
238
250
               skip_string<Opts>(ctx, it, end);
239
250
               if (bool(ctx.error)) [[unlikely]]
240
16
                  return;
241
234
               break;
242
1.23k
            case ',':
243
1.24k
            case '}':
244
1.25k
            case ']':
245
1.25k
               break;
246
7
            case '\0':
247
7
               ctx.error = error_code::unexpected_end;
248
7
               return;
249
319
            default: {
250
319
               ++it;
251
319
               if constexpr (not Opts.null_terminated) {
252
319
                  if (it == end) [[unlikely]] {
253
26
                     ctx.error = error_code::unexpected_end;
254
26
                     return;
255
26
                  }
256
319
               }
257
293
               continue;
258
1.24k
            }
259
2.72k
            }
260
261
2.04k
            break;
262
2.72k
         }
263
      }
264
      else {
265
         if constexpr (not check_ws_handled(Opts)) {
266
            if (skip_ws<Opts>(ctx, it, end)) {
267
               return;
268
            }
269
         }
270
         switch (*it) {
271
         case '{': {
272
            skip_object<Opts>(ctx, it, end);
273
            break;
274
         }
275
         case '[': {
276
            skip_array<Opts>(ctx, it, end);
277
            break;
278
         }
279
         case '"': {
280
            skip_string<Opts>(ctx, it, end);
281
            break;
282
         }
283
         case 'n': {
284
            ++it;
285
            match<"ull", Opts>(ctx, it, end);
286
            break;
287
         }
288
         case 'f': {
289
            ++it;
290
            match<"alse", Opts>(ctx, it, end);
291
            break;
292
         }
293
         case 't': {
294
            ++it;
295
            match<"rue", Opts>(ctx, it, end);
296
            break;
297
         }
298
         case '\0': {
299
            ctx.error = error_code::unexpected_end;
300
            break;
301
         }
302
         default: {
303
            skip_number<Opts>(ctx, it, end);
304
         }
305
         }
306
      }
307
2.54k
   }
308
309
   template <auto Opts>
310
      requires(bool(Opts.comments))
311
   GLZ_ALWAYS_INLINE void skip_value<JSON>::op(is_context auto&& ctx, auto&& it, auto&& end) noexcept
312
   {
313
      using namespace glz::detail;
314
315
      if constexpr (not check_ws_handled(Opts)) {
316
         if (skip_ws<Opts>(ctx, it, end)) {
317
            return;
318
         }
319
      }
320
      switch (*it) {
321
      case '{': {
322
         skip_object<Opts>(ctx, it, end);
323
         break;
324
      }
325
      case '[': {
326
         skip_array<Opts>(ctx, it, end);
327
         break;
328
      }
329
      case '"': {
330
         skip_string<Opts>(ctx, it, end);
331
         break;
332
      }
333
      case '/': {
334
         skip_comment(ctx, it, end);
335
         if (bool(ctx.error)) [[unlikely]]
336
            return;
337
         break;
338
      }
339
      case 'n': {
340
         ++it;
341
         match<"ull", Opts>(ctx, it, end);
342
         break;
343
      }
344
      case 'f': {
345
         ++it;
346
         match<"alse", Opts>(ctx, it, end);
347
         break;
348
      }
349
      case 't': {
350
         ++it;
351
         match<"rue", Opts>(ctx, it, end);
352
         break;
353
      }
354
      case '\0': {
355
         ctx.error = error_code::unexpected_end;
356
         break;
357
      }
358
      default: {
359
         skip_number<Opts>(ctx, it, end);
360
      }
361
      }
362
   }
363
}