Coverage Report

Created: 2025-07-11 06:48

/src/glaze/include/glaze/json/read.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 <charconv>
7
#include <climits>
8
#include <cwchar>
9
#include <filesystem>
10
#include <iterator>
11
#include <ranges>
12
#include <type_traits>
13
14
#include "glaze/core/common.hpp"
15
#include "glaze/core/opts.hpp"
16
#include "glaze/core/read.hpp"
17
#include "glaze/core/reflect.hpp"
18
#include "glaze/file/file_ops.hpp"
19
#include "glaze/json/json_concepts.hpp"
20
#include "glaze/json/skip.hpp"
21
#include "glaze/util/for_each.hpp"
22
#include "glaze/util/glaze_fast_float.hpp"
23
#include "glaze/util/type_traits.hpp"
24
#include "glaze/util/variant.hpp"
25
26
#ifdef _MSC_VER
27
// Turn off MSVC warning for unreachable code due to constexpr branching
28
#pragma warning(push)
29
#pragma warning(disable : 4702)
30
#endif
31
32
namespace glz
33
{
34
   // forward declare from json/wrappers.hpp to avoid circular include
35
   template <class T>
36
   struct quoted_t;
37
38
   template <>
39
   struct parse<JSON>
40
   {
41
      template <auto Opts, class T, is_context Ctx, class It0, class It1>
42
      GLZ_ALWAYS_INLINE static void op(T&& value, Ctx&& ctx, It0&& it, It1&& end)
43
42.6k
      {
44
         if constexpr (const_value_v<T>) {
45
            if constexpr (Opts.error_on_const_read) {
46
               ctx.error = error_code::attempt_const_read;
47
            }
48
            else {
49
               // do not read anything into the const value
50
               skip_value<JSON>::op<Opts>(std::forward<Ctx>(ctx), std::forward<It0>(it), std::forward<It1>(end));
51
            }
52
         }
53
42.6k
         else {
54
42.6k
            using V = std::remove_cvref_t<T>;
55
42.6k
            from<JSON, V>::template op<Opts>(std::forward<T>(value), std::forward<Ctx>(ctx), std::forward<It0>(it),
56
42.6k
                                             std::forward<It1>(end));
57
42.6k
         }
58
42.6k
      }
_ZN3glz5parseILj10EE2opITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEER9my_structTkNS_10is_contextERNS_7contextERPKcSA_EEvOT0_OT1_OT2_OT3_
Line
Count
Source
43
4.57k
      {
44
         if constexpr (const_value_v<T>) {
45
            if constexpr (Opts.error_on_const_read) {
46
               ctx.error = error_code::attempt_const_read;
47
            }
48
            else {
49
               // do not read anything into the const value
50
               skip_value<JSON>::op<Opts>(std::forward<Ctx>(ctx), std::forward<It0>(it), std::forward<It1>(end));
51
            }
52
         }
53
4.57k
         else {
54
4.57k
            using V = std::remove_cvref_t<T>;
55
4.57k
            from<JSON, V>::template op<Opts>(std::forward<T>(value), std::forward<Ctx>(ctx), std::forward<It0>(it),
56
4.57k
                                             std::forward<It1>(end));
57
4.57k
         }
58
4.57k
      }
_ZN3glz5parseILj10EE2opITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERmTkNS_10is_contextERNS_7contextERPKcS9_EEvOT0_OT1_OT2_OT3_
Line
Count
Source
43
16.7k
      {
44
         if constexpr (const_value_v<T>) {
45
            if constexpr (Opts.error_on_const_read) {
46
               ctx.error = error_code::attempt_const_read;
47
            }
48
            else {
49
               // do not read anything into the const value
50
               skip_value<JSON>::op<Opts>(std::forward<Ctx>(ctx), std::forward<It0>(it), std::forward<It1>(end));
51
            }
52
         }
53
16.7k
         else {
54
16.7k
            using V = std::remove_cvref_t<T>;
55
16.7k
            from<JSON, V>::template op<Opts>(std::forward<T>(value), std::forward<Ctx>(ctx), std::forward<It0>(it),
56
16.7k
                                             std::forward<It1>(end));
57
16.7k
         }
58
16.7k
      }
_ZN3glz5parseILj10EE2opITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEER9my_structTkNS_10is_contextERNS_7contextERPKcSA_EEvOT0_OT1_OT2_OT3_
Line
Count
Source
43
4.57k
      {
44
         if constexpr (const_value_v<T>) {
45
            if constexpr (Opts.error_on_const_read) {
46
               ctx.error = error_code::attempt_const_read;
47
            }
48
            else {
49
               // do not read anything into the const value
50
               skip_value<JSON>::op<Opts>(std::forward<Ctx>(ctx), std::forward<It0>(it), std::forward<It1>(end));
51
            }
52
         }
53
4.57k
         else {
54
4.57k
            using V = std::remove_cvref_t<T>;
55
4.57k
            from<JSON, V>::template op<Opts>(std::forward<T>(value), std::forward<Ctx>(ctx), std::forward<It0>(it),
56
4.57k
                                             std::forward<It1>(end));
57
4.57k
         }
58
4.57k
      }
_ZN3glz5parseILj10EE2opITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERmTkNS_10is_contextERNS_7contextERPKcS9_EEvOT0_OT1_OT2_OT3_
Line
Count
Source
43
16.8k
      {
44
         if constexpr (const_value_v<T>) {
45
            if constexpr (Opts.error_on_const_read) {
46
               ctx.error = error_code::attempt_const_read;
47
            }
48
            else {
49
               // do not read anything into the const value
50
               skip_value<JSON>::op<Opts>(std::forward<Ctx>(ctx), std::forward<It0>(it), std::forward<It1>(end));
51
            }
52
         }
53
16.8k
         else {
54
16.8k
            using V = std::remove_cvref_t<T>;
55
16.8k
            from<JSON, V>::template op<Opts>(std::forward<T>(value), std::forward<Ctx>(ctx), std::forward<It0>(it),
56
16.8k
                                             std::forward<It1>(end));
57
16.8k
         }
58
16.8k
      }
59
60
      // This unknown key handler should not be given unescaped keys, that is for the user to handle.
61
      template <auto Opts, class T, is_context Ctx, class It0, class It1>
62
      static void handle_unknown(const sv& key, T&& value, Ctx&& ctx, It0&& it, It1&& end)
63
      {
64
         using ValueType = std::decay_t<decltype(value)>;
65
         if constexpr (has_unknown_reader<ValueType>) {
66
            constexpr auto& reader = meta_unknown_read_v<ValueType>;
67
            using ReaderType = meta_unknown_read_t<ValueType>;
68
            if constexpr (std::is_member_object_pointer_v<ReaderType>) {
69
               using MemberType = typename member_value<ReaderType>::type;
70
               if constexpr (map_subscriptable<MemberType>) {
71
                  parse<JSON>::op<Opts>((value.*reader)[key], ctx, it, end);
72
               }
73
               else {
74
                  static_assert(false_v<T>, "target must have subscript operator");
75
               }
76
            }
77
            else if constexpr (std::is_member_function_pointer_v<ReaderType>) {
78
               using ReturnType = typename return_type<ReaderType>::type;
79
               if constexpr (std::is_void_v<ReturnType>) {
80
                  using TupleType = typename inputs_as_tuple<ReaderType>::type;
81
                  if constexpr (glz::tuple_size_v<TupleType> == 2) {
82
                     std::decay_t<glz::tuple_element_t<1, TupleType>> input{};
83
                     parse<JSON>::op<Opts>(input, ctx, it, end);
84
                     if (bool(ctx.error)) [[unlikely]]
85
                        return;
86
                     (value.*reader)(key, input);
87
                  }
88
                  else {
89
                     static_assert(false_v<T>, "method must have 2 args");
90
                  }
91
               }
92
               else {
93
                  static_assert(false_v<T>, "method must have void return");
94
               }
95
            }
96
            else {
97
               static_assert(false_v<T>, "unknown_read type not handled");
98
            }
99
         }
100
         else {
101
            skip_value<JSON>::op<Opts>(ctx, it, end);
102
         }
103
      }
104
   };
105
106
   // Unless we can mutate the input buffer we need somewhere to store escaped strings for key lookup, etc.
107
   // We don't put this in the context because we don't want to continually reallocate.
108
   // IMPORTANT: Do not call use this when nested calls may be made that need additional buffers on the same thread.
109
   inline std::string& string_buffer() noexcept
110
0
   {
111
0
      static thread_local std::string buffer(256, '\0');
112
0
      return buffer;
113
0
   }
114
115
   // We use an error buffer to avoid multiple allocations in the case that errors occur multiple times.
116
   inline std::string& error_buffer() noexcept
117
0
   {
118
0
      static thread_local std::string buffer(256, '\0');
119
0
      return buffer;
120
0
   }
121
122
   template <class T>
123
      requires(glaze_value_t<T> && !custom_read<T>)
124
   struct from<JSON, T>
125
   {
126
      template <auto Opts, class Value, is_context Ctx, class It0, class It1>
127
      GLZ_ALWAYS_INLINE static void op(Value&& value, Ctx&& ctx, It0&& it, It1&& end)
128
      {
129
         using V = std::decay_t<decltype(get_member(std::declval<Value>(), meta_wrapper_v<T>))>;
130
         from<JSON, V>::template op<Opts>(get_member(std::forward<Value>(value), meta_wrapper_v<T>),
131
                                          std::forward<Ctx>(ctx), std::forward<It0>(it), std::forward<It1>(end));
132
      }
133
   };
134
135
   template <auto Opts>
136
   GLZ_ALWAYS_INLINE bool parse_ws_colon(is_context auto& ctx, auto&& it, auto&& end) noexcept
137
   {
138
      if (skip_ws<Opts>(ctx, it, end)) {
139
         return true;
140
      }
141
      if (match_invalid_end<':', Opts>(ctx, it, end)) {
142
         return true;
143
      }
144
      if (skip_ws<Opts>(ctx, it, end)) {
145
         return true;
146
      }
147
      return false;
148
   }
149
150
   template <auto Opts, class T, size_t I, class Value, class... SelectedIndex>
151
      requires(glaze_object_t<T> || reflectable<T>)
152
   void decode_index(Value&& value, is_context auto&& ctx, auto&& it, auto&& end, SelectedIndex&&... selected_index)
153
64.8k
   {
154
64.8k
      static constexpr auto Key = get<I>(reflect<T>::keys);
155
64.8k
      static constexpr auto KeyWithEndQuote = join_v<Key, chars<"\"">>;
156
64.8k
      static constexpr auto Length = KeyWithEndQuote.size();
157
158
64.8k
      if (((it + Length) < end) && comparitor<KeyWithEndQuote>(it)) [[likely]] {
159
64.7k
         it += Length;
160
64.7k
         if constexpr (not Opts.null_terminated) {
161
32.3k
            if (it == end) [[unlikely]] {
162
0
               ctx.error = error_code::unexpected_end;
163
0
               return;
164
0
            }
165
32.3k
         }
166
167
64.7k
         if (skip_ws<Opts>(ctx, it, end)) {
168
47
            return;
169
47
         }
170
64.6k
         if (match_invalid_end<':', Opts>(ctx, it, end)) {
171
174
            return;
172
174
         }
173
64.4k
         if (skip_ws<Opts>(ctx, it, end)) {
174
53
            return;
175
53
         }
176
177
64.4k
         using V = refl_t<T, I>;
178
179
         if constexpr (const_value_v<V>) {
180
            if constexpr (Opts.error_on_const_read) {
181
               ctx.error = error_code::attempt_const_read;
182
            }
183
            else {
184
               // do not read anything into the const value
185
               skip_value<JSON>::op<Opts>(ctx, it, end);
186
            }
187
         }
188
64.4k
         else {
189
            if constexpr (glaze_object_t<T>) {
190
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
191
                  get_member(value, get<I>(reflect<T>::values)), ctx, it, end);
192
            }
193
64.4k
            else {
194
64.4k
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
195
64.4k
                  get_member(value, get<I>(to_tie(value))), ctx, it, end);
196
64.4k
            }
197
64.4k
         }
198
199
         if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
200
            ((selected_index = I), ...);
201
         }
202
64.4k
      }
203
164
      else [[unlikely]] {
204
164
         if constexpr (Opts.error_on_unknown_keys) {
205
164
            ctx.error = error_code::unknown_key;
206
         }
207
         else {
208
            auto* start = it;
209
            skip_string_view<Opts>(ctx, it, end);
210
            if (bool(ctx.error)) [[unlikely]]
211
               return;
212
            const sv key = {start, size_t(it - start)};
213
            ++it;
214
            if constexpr (not Opts.null_terminated) {
215
               if (it == end) [[unlikely]] {
216
                  ctx.error = error_code::unexpected_end;
217
                  return;
218
               }
219
            }
220
221
            if (parse_ws_colon<Opts>(ctx, it, end)) {
222
               return;
223
            }
224
225
            parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
226
         }
227
164
      }
228
64.8k
   }
_ZN3glz12decode_indexITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structLm0ERS2_JETkNS_10is_contextERNS_7contextERPKcS8_Qoo14glaze_object_tIT0_E11reflectableIS9_EEEvOT2_OT4_OT5_OT6_DpOT3_
Line
Count
Source
153
8.52k
   {
154
8.52k
      static constexpr auto Key = get<I>(reflect<T>::keys);
155
8.52k
      static constexpr auto KeyWithEndQuote = join_v<Key, chars<"\"">>;
156
8.52k
      static constexpr auto Length = KeyWithEndQuote.size();
157
158
8.52k
      if (((it + Length) < end) && comparitor<KeyWithEndQuote>(it)) [[likely]] {
159
8.50k
         it += Length;
160
8.50k
         if constexpr (not Opts.null_terminated) {
161
8.50k
            if (it == end) [[unlikely]] {
162
0
               ctx.error = error_code::unexpected_end;
163
0
               return;
164
0
            }
165
8.50k
         }
166
167
8.50k
         if (skip_ws<Opts>(ctx, it, end)) {
168
16
            return;
169
16
         }
170
8.49k
         if (match_invalid_end<':', Opts>(ctx, it, end)) {
171
28
            return;
172
28
         }
173
8.46k
         if (skip_ws<Opts>(ctx, it, end)) {
174
18
            return;
175
18
         }
176
177
8.44k
         using V = refl_t<T, I>;
178
179
         if constexpr (const_value_v<V>) {
180
            if constexpr (Opts.error_on_const_read) {
181
               ctx.error = error_code::attempt_const_read;
182
            }
183
            else {
184
               // do not read anything into the const value
185
               skip_value<JSON>::op<Opts>(ctx, it, end);
186
            }
187
         }
188
8.44k
         else {
189
            if constexpr (glaze_object_t<T>) {
190
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
191
                  get_member(value, get<I>(reflect<T>::values)), ctx, it, end);
192
            }
193
8.44k
            else {
194
8.44k
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
195
8.44k
                  get_member(value, get<I>(to_tie(value))), ctx, it, end);
196
8.44k
            }
197
8.44k
         }
198
199
         if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
200
            ((selected_index = I), ...);
201
         }
202
8.44k
      }
203
21
      else [[unlikely]] {
204
21
         if constexpr (Opts.error_on_unknown_keys) {
205
21
            ctx.error = error_code::unknown_key;
206
         }
207
         else {
208
            auto* start = it;
209
            skip_string_view<Opts>(ctx, it, end);
210
            if (bool(ctx.error)) [[unlikely]]
211
               return;
212
            const sv key = {start, size_t(it - start)};
213
            ++it;
214
            if constexpr (not Opts.null_terminated) {
215
               if (it == end) [[unlikely]] {
216
                  ctx.error = error_code::unexpected_end;
217
                  return;
218
               }
219
            }
220
221
            if (parse_ws_colon<Opts>(ctx, it, end)) {
222
               return;
223
            }
224
225
            parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
226
         }
227
21
      }
228
8.52k
   }
_ZN3glz12decode_indexITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structLm1ERS2_JETkNS_10is_contextERNS_7contextERPKcS8_Qoo14glaze_object_tIT0_E11reflectableIS9_EEEvOT2_OT4_OT5_OT6_DpOT3_
Line
Count
Source
153
14.8k
   {
154
14.8k
      static constexpr auto Key = get<I>(reflect<T>::keys);
155
14.8k
      static constexpr auto KeyWithEndQuote = join_v<Key, chars<"\"">>;
156
14.8k
      static constexpr auto Length = KeyWithEndQuote.size();
157
158
14.8k
      if (((it + Length) < end) && comparitor<KeyWithEndQuote>(it)) [[likely]] {
159
14.8k
         it += Length;
160
14.8k
         if constexpr (not Opts.null_terminated) {
161
14.8k
            if (it == end) [[unlikely]] {
162
0
               ctx.error = error_code::unexpected_end;
163
0
               return;
164
0
            }
165
14.8k
         }
166
167
14.8k
         if (skip_ws<Opts>(ctx, it, end)) {
168
16
            return;
169
16
         }
170
14.7k
         if (match_invalid_end<':', Opts>(ctx, it, end)) {
171
24
            return;
172
24
         }
173
14.7k
         if (skip_ws<Opts>(ctx, it, end)) {
174
17
            return;
175
17
         }
176
177
14.7k
         using V = refl_t<T, I>;
178
179
         if constexpr (const_value_v<V>) {
180
            if constexpr (Opts.error_on_const_read) {
181
               ctx.error = error_code::attempt_const_read;
182
            }
183
            else {
184
               // do not read anything into the const value
185
               skip_value<JSON>::op<Opts>(ctx, it, end);
186
            }
187
         }
188
14.7k
         else {
189
            if constexpr (glaze_object_t<T>) {
190
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
191
                  get_member(value, get<I>(reflect<T>::values)), ctx, it, end);
192
            }
193
14.7k
            else {
194
14.7k
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
195
14.7k
                  get_member(value, get<I>(to_tie(value))), ctx, it, end);
196
14.7k
            }
197
14.7k
         }
198
199
         if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
200
            ((selected_index = I), ...);
201
         }
202
14.7k
      }
203
29
      else [[unlikely]] {
204
29
         if constexpr (Opts.error_on_unknown_keys) {
205
29
            ctx.error = error_code::unknown_key;
206
         }
207
         else {
208
            auto* start = it;
209
            skip_string_view<Opts>(ctx, it, end);
210
            if (bool(ctx.error)) [[unlikely]]
211
               return;
212
            const sv key = {start, size_t(it - start)};
213
            ++it;
214
            if constexpr (not Opts.null_terminated) {
215
               if (it == end) [[unlikely]] {
216
                  ctx.error = error_code::unexpected_end;
217
                  return;
218
               }
219
            }
220
221
            if (parse_ws_colon<Opts>(ctx, it, end)) {
222
               return;
223
            }
224
225
            parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
226
         }
227
29
      }
228
14.8k
   }
_ZN3glz12decode_indexITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structLm2ERS2_JETkNS_10is_contextERNS_7contextERPKcS8_Qoo14glaze_object_tIT0_E11reflectableIS9_EEEvOT2_OT4_OT5_OT6_DpOT3_
Line
Count
Source
153
3
   {
154
3
      static constexpr auto Key = get<I>(reflect<T>::keys);
155
3
      static constexpr auto KeyWithEndQuote = join_v<Key, chars<"\"">>;
156
3
      static constexpr auto Length = KeyWithEndQuote.size();
157
158
3
      if (((it + Length) < end) && comparitor<KeyWithEndQuote>(it)) [[likely]] {
159
0
         it += Length;
160
0
         if constexpr (not Opts.null_terminated) {
161
0
            if (it == end) [[unlikely]] {
162
0
               ctx.error = error_code::unexpected_end;
163
0
               return;
164
0
            }
165
0
         }
166
167
0
         if (skip_ws<Opts>(ctx, it, end)) {
168
0
            return;
169
0
         }
170
0
         if (match_invalid_end<':', Opts>(ctx, it, end)) {
171
0
            return;
172
0
         }
173
0
         if (skip_ws<Opts>(ctx, it, end)) {
174
0
            return;
175
0
         }
176
177
0
         using V = refl_t<T, I>;
178
179
         if constexpr (const_value_v<V>) {
180
            if constexpr (Opts.error_on_const_read) {
181
               ctx.error = error_code::attempt_const_read;
182
            }
183
            else {
184
               // do not read anything into the const value
185
               skip_value<JSON>::op<Opts>(ctx, it, end);
186
            }
187
         }
188
0
         else {
189
            if constexpr (glaze_object_t<T>) {
190
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
191
                  get_member(value, get<I>(reflect<T>::values)), ctx, it, end);
192
            }
193
0
            else {
194
0
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
195
0
                  get_member(value, get<I>(to_tie(value))), ctx, it, end);
196
0
            }
197
0
         }
198
199
         if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
200
            ((selected_index = I), ...);
201
         }
202
0
      }
203
3
      else [[unlikely]] {
204
3
         if constexpr (Opts.error_on_unknown_keys) {
205
3
            ctx.error = error_code::unknown_key;
206
         }
207
         else {
208
            auto* start = it;
209
            skip_string_view<Opts>(ctx, it, end);
210
            if (bool(ctx.error)) [[unlikely]]
211
               return;
212
            const sv key = {start, size_t(it - start)};
213
            ++it;
214
            if constexpr (not Opts.null_terminated) {
215
               if (it == end) [[unlikely]] {
216
                  ctx.error = error_code::unexpected_end;
217
                  return;
218
               }
219
            }
220
221
            if (parse_ws_colon<Opts>(ctx, it, end)) {
222
               return;
223
            }
224
225
            parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
226
         }
227
3
      }
228
3
   }
_ZN3glz12decode_indexITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structLm3ERS2_JETkNS_10is_contextERNS_7contextERPKcS8_Qoo14glaze_object_tIT0_E11reflectableIS9_EEEvOT2_OT4_OT5_OT6_DpOT3_
Line
Count
Source
153
9.06k
   {
154
9.06k
      static constexpr auto Key = get<I>(reflect<T>::keys);
155
9.06k
      static constexpr auto KeyWithEndQuote = join_v<Key, chars<"\"">>;
156
9.06k
      static constexpr auto Length = KeyWithEndQuote.size();
157
158
9.06k
      if (((it + Length) < end) && comparitor<KeyWithEndQuote>(it)) [[likely]] {
159
9.03k
         it += Length;
160
9.03k
         if constexpr (not Opts.null_terminated) {
161
9.03k
            if (it == end) [[unlikely]] {
162
0
               ctx.error = error_code::unexpected_end;
163
0
               return;
164
0
            }
165
9.03k
         }
166
167
9.03k
         if (skip_ws<Opts>(ctx, it, end)) {
168
15
            return;
169
15
         }
170
9.01k
         if (match_invalid_end<':', Opts>(ctx, it, end)) {
171
20
            return;
172
20
         }
173
8.99k
         if (skip_ws<Opts>(ctx, it, end)) {
174
18
            return;
175
18
         }
176
177
8.98k
         using V = refl_t<T, I>;
178
179
         if constexpr (const_value_v<V>) {
180
            if constexpr (Opts.error_on_const_read) {
181
               ctx.error = error_code::attempt_const_read;
182
            }
183
            else {
184
               // do not read anything into the const value
185
               skip_value<JSON>::op<Opts>(ctx, it, end);
186
            }
187
         }
188
8.98k
         else {
189
            if constexpr (glaze_object_t<T>) {
190
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
191
                  get_member(value, get<I>(reflect<T>::values)), ctx, it, end);
192
            }
193
8.98k
            else {
194
8.98k
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
195
8.98k
                  get_member(value, get<I>(to_tie(value))), ctx, it, end);
196
8.98k
            }
197
8.98k
         }
198
199
         if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
200
            ((selected_index = I), ...);
201
         }
202
8.98k
      }
203
29
      else [[unlikely]] {
204
29
         if constexpr (Opts.error_on_unknown_keys) {
205
29
            ctx.error = error_code::unknown_key;
206
         }
207
         else {
208
            auto* start = it;
209
            skip_string_view<Opts>(ctx, it, end);
210
            if (bool(ctx.error)) [[unlikely]]
211
               return;
212
            const sv key = {start, size_t(it - start)};
213
            ++it;
214
            if constexpr (not Opts.null_terminated) {
215
               if (it == end) [[unlikely]] {
216
                  ctx.error = error_code::unexpected_end;
217
                  return;
218
               }
219
            }
220
221
            if (parse_ws_colon<Opts>(ctx, it, end)) {
222
               return;
223
            }
224
225
            parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
226
         }
227
29
      }
228
9.06k
   }
_ZN3glz12decode_indexITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structLm0ERS2_JETkNS_10is_contextERNS_7contextERPKcS8_Qoo14glaze_object_tIT0_E11reflectableIS9_EEEvOT2_OT4_OT5_OT6_DpOT3_
Line
Count
Source
153
8.52k
   {
154
8.52k
      static constexpr auto Key = get<I>(reflect<T>::keys);
155
8.52k
      static constexpr auto KeyWithEndQuote = join_v<Key, chars<"\"">>;
156
8.52k
      static constexpr auto Length = KeyWithEndQuote.size();
157
158
8.52k
      if (((it + Length) < end) && comparitor<KeyWithEndQuote>(it)) [[likely]] {
159
8.50k
         it += Length;
160
         if constexpr (not Opts.null_terminated) {
161
            if (it == end) [[unlikely]] {
162
               ctx.error = error_code::unexpected_end;
163
               return;
164
            }
165
         }
166
167
8.50k
         if (skip_ws<Opts>(ctx, it, end)) {
168
0
            return;
169
0
         }
170
8.50k
         if (match_invalid_end<':', Opts>(ctx, it, end)) {
171
37
            return;
172
37
         }
173
8.46k
         if (skip_ws<Opts>(ctx, it, end)) {
174
0
            return;
175
0
         }
176
177
8.46k
         using V = refl_t<T, I>;
178
179
         if constexpr (const_value_v<V>) {
180
            if constexpr (Opts.error_on_const_read) {
181
               ctx.error = error_code::attempt_const_read;
182
            }
183
            else {
184
               // do not read anything into the const value
185
               skip_value<JSON>::op<Opts>(ctx, it, end);
186
            }
187
         }
188
8.46k
         else {
189
            if constexpr (glaze_object_t<T>) {
190
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
191
                  get_member(value, get<I>(reflect<T>::values)), ctx, it, end);
192
            }
193
8.46k
            else {
194
8.46k
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
195
8.46k
                  get_member(value, get<I>(to_tie(value))), ctx, it, end);
196
8.46k
            }
197
8.46k
         }
198
199
         if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
200
            ((selected_index = I), ...);
201
         }
202
8.46k
      }
203
21
      else [[unlikely]] {
204
21
         if constexpr (Opts.error_on_unknown_keys) {
205
21
            ctx.error = error_code::unknown_key;
206
         }
207
         else {
208
            auto* start = it;
209
            skip_string_view<Opts>(ctx, it, end);
210
            if (bool(ctx.error)) [[unlikely]]
211
               return;
212
            const sv key = {start, size_t(it - start)};
213
            ++it;
214
            if constexpr (not Opts.null_terminated) {
215
               if (it == end) [[unlikely]] {
216
                  ctx.error = error_code::unexpected_end;
217
                  return;
218
               }
219
            }
220
221
            if (parse_ws_colon<Opts>(ctx, it, end)) {
222
               return;
223
            }
224
225
            parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
226
         }
227
21
      }
228
8.52k
   }
_ZN3glz12decode_indexITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structLm1ERS2_JETkNS_10is_contextERNS_7contextERPKcS8_Qoo14glaze_object_tIT0_E11reflectableIS9_EEEvOT2_OT4_OT5_OT6_DpOT3_
Line
Count
Source
153
14.8k
   {
154
14.8k
      static constexpr auto Key = get<I>(reflect<T>::keys);
155
14.8k
      static constexpr auto KeyWithEndQuote = join_v<Key, chars<"\"">>;
156
14.8k
      static constexpr auto Length = KeyWithEndQuote.size();
157
158
14.8k
      if (((it + Length) < end) && comparitor<KeyWithEndQuote>(it)) [[likely]] {
159
14.8k
         it += Length;
160
         if constexpr (not Opts.null_terminated) {
161
            if (it == end) [[unlikely]] {
162
               ctx.error = error_code::unexpected_end;
163
               return;
164
            }
165
         }
166
167
14.8k
         if (skip_ws<Opts>(ctx, it, end)) {
168
0
            return;
169
0
         }
170
14.8k
         if (match_invalid_end<':', Opts>(ctx, it, end)) {
171
35
            return;
172
35
         }
173
14.7k
         if (skip_ws<Opts>(ctx, it, end)) {
174
0
            return;
175
0
         }
176
177
14.7k
         using V = refl_t<T, I>;
178
179
         if constexpr (const_value_v<V>) {
180
            if constexpr (Opts.error_on_const_read) {
181
               ctx.error = error_code::attempt_const_read;
182
            }
183
            else {
184
               // do not read anything into the const value
185
               skip_value<JSON>::op<Opts>(ctx, it, end);
186
            }
187
         }
188
14.7k
         else {
189
            if constexpr (glaze_object_t<T>) {
190
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
191
                  get_member(value, get<I>(reflect<T>::values)), ctx, it, end);
192
            }
193
14.7k
            else {
194
14.7k
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
195
14.7k
                  get_member(value, get<I>(to_tie(value))), ctx, it, end);
196
14.7k
            }
197
14.7k
         }
198
199
         if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
200
            ((selected_index = I), ...);
201
         }
202
14.7k
      }
203
29
      else [[unlikely]] {
204
29
         if constexpr (Opts.error_on_unknown_keys) {
205
29
            ctx.error = error_code::unknown_key;
206
         }
207
         else {
208
            auto* start = it;
209
            skip_string_view<Opts>(ctx, it, end);
210
            if (bool(ctx.error)) [[unlikely]]
211
               return;
212
            const sv key = {start, size_t(it - start)};
213
            ++it;
214
            if constexpr (not Opts.null_terminated) {
215
               if (it == end) [[unlikely]] {
216
                  ctx.error = error_code::unexpected_end;
217
                  return;
218
               }
219
            }
220
221
            if (parse_ws_colon<Opts>(ctx, it, end)) {
222
               return;
223
            }
224
225
            parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
226
         }
227
29
      }
228
14.8k
   }
_ZN3glz12decode_indexITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structLm2ERS2_JETkNS_10is_contextERNS_7contextERPKcS8_Qoo14glaze_object_tIT0_E11reflectableIS9_EEEvOT2_OT4_OT5_OT6_DpOT3_
Line
Count
Source
153
3
   {
154
3
      static constexpr auto Key = get<I>(reflect<T>::keys);
155
3
      static constexpr auto KeyWithEndQuote = join_v<Key, chars<"\"">>;
156
3
      static constexpr auto Length = KeyWithEndQuote.size();
157
158
3
      if (((it + Length) < end) && comparitor<KeyWithEndQuote>(it)) [[likely]] {
159
0
         it += Length;
160
         if constexpr (not Opts.null_terminated) {
161
            if (it == end) [[unlikely]] {
162
               ctx.error = error_code::unexpected_end;
163
               return;
164
            }
165
         }
166
167
0
         if (skip_ws<Opts>(ctx, it, end)) {
168
0
            return;
169
0
         }
170
0
         if (match_invalid_end<':', Opts>(ctx, it, end)) {
171
0
            return;
172
0
         }
173
0
         if (skip_ws<Opts>(ctx, it, end)) {
174
0
            return;
175
0
         }
176
177
0
         using V = refl_t<T, I>;
178
179
         if constexpr (const_value_v<V>) {
180
            if constexpr (Opts.error_on_const_read) {
181
               ctx.error = error_code::attempt_const_read;
182
            }
183
            else {
184
               // do not read anything into the const value
185
               skip_value<JSON>::op<Opts>(ctx, it, end);
186
            }
187
         }
188
0
         else {
189
            if constexpr (glaze_object_t<T>) {
190
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
191
                  get_member(value, get<I>(reflect<T>::values)), ctx, it, end);
192
            }
193
0
            else {
194
0
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
195
0
                  get_member(value, get<I>(to_tie(value))), ctx, it, end);
196
0
            }
197
0
         }
198
199
         if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
200
            ((selected_index = I), ...);
201
         }
202
0
      }
203
3
      else [[unlikely]] {
204
3
         if constexpr (Opts.error_on_unknown_keys) {
205
3
            ctx.error = error_code::unknown_key;
206
         }
207
         else {
208
            auto* start = it;
209
            skip_string_view<Opts>(ctx, it, end);
210
            if (bool(ctx.error)) [[unlikely]]
211
               return;
212
            const sv key = {start, size_t(it - start)};
213
            ++it;
214
            if constexpr (not Opts.null_terminated) {
215
               if (it == end) [[unlikely]] {
216
                  ctx.error = error_code::unexpected_end;
217
                  return;
218
               }
219
            }
220
221
            if (parse_ws_colon<Opts>(ctx, it, end)) {
222
               return;
223
            }
224
225
            parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
226
         }
227
3
      }
228
3
   }
_ZN3glz12decode_indexITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structLm3ERS2_JETkNS_10is_contextERNS_7contextERPKcS8_Qoo14glaze_object_tIT0_E11reflectableIS9_EEEvOT2_OT4_OT5_OT6_DpOT3_
Line
Count
Source
153
9.06k
   {
154
9.06k
      static constexpr auto Key = get<I>(reflect<T>::keys);
155
9.06k
      static constexpr auto KeyWithEndQuote = join_v<Key, chars<"\"">>;
156
9.06k
      static constexpr auto Length = KeyWithEndQuote.size();
157
158
9.06k
      if (((it + Length) < end) && comparitor<KeyWithEndQuote>(it)) [[likely]] {
159
9.03k
         it += Length;
160
         if constexpr (not Opts.null_terminated) {
161
            if (it == end) [[unlikely]] {
162
               ctx.error = error_code::unexpected_end;
163
               return;
164
            }
165
         }
166
167
9.03k
         if (skip_ws<Opts>(ctx, it, end)) {
168
0
            return;
169
0
         }
170
9.03k
         if (match_invalid_end<':', Opts>(ctx, it, end)) {
171
30
            return;
172
30
         }
173
9.00k
         if (skip_ws<Opts>(ctx, it, end)) {
174
0
            return;
175
0
         }
176
177
9.00k
         using V = refl_t<T, I>;
178
179
         if constexpr (const_value_v<V>) {
180
            if constexpr (Opts.error_on_const_read) {
181
               ctx.error = error_code::attempt_const_read;
182
            }
183
            else {
184
               // do not read anything into the const value
185
               skip_value<JSON>::op<Opts>(ctx, it, end);
186
            }
187
         }
188
9.00k
         else {
189
            if constexpr (glaze_object_t<T>) {
190
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
191
                  get_member(value, get<I>(reflect<T>::values)), ctx, it, end);
192
            }
193
9.00k
            else {
194
9.00k
               from<JSON, std::remove_cvref_t<V>>::template op<ws_handled<Opts>()>(
195
9.00k
                  get_member(value, get<I>(to_tie(value))), ctx, it, end);
196
9.00k
            }
197
9.00k
         }
198
199
         if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
200
            ((selected_index = I), ...);
201
         }
202
9.00k
      }
203
29
      else [[unlikely]] {
204
29
         if constexpr (Opts.error_on_unknown_keys) {
205
29
            ctx.error = error_code::unknown_key;
206
         }
207
         else {
208
            auto* start = it;
209
            skip_string_view<Opts>(ctx, it, end);
210
            if (bool(ctx.error)) [[unlikely]]
211
               return;
212
            const sv key = {start, size_t(it - start)};
213
            ++it;
214
            if constexpr (not Opts.null_terminated) {
215
               if (it == end) [[unlikely]] {
216
                  ctx.error = error_code::unexpected_end;
217
                  return;
218
               }
219
            }
220
221
            if (parse_ws_colon<Opts>(ctx, it, end)) {
222
               return;
223
            }
224
225
            parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
226
         }
227
29
      }
228
9.06k
   }
229
230
   template <auto Opts, class T, size_t I, class Value>
231
      requires(glaze_enum_t<T> || (meta_keys<T> && std::is_enum_v<T>))
232
   void decode_index(Value&& value, is_context auto&& ctx, auto&& it, auto&& end) noexcept
233
   {
234
      static constexpr auto TargetKey = glz::get<I>(reflect<T>::keys);
235
      static constexpr auto Length = TargetKey.size();
236
237
      if (((it + Length) < end) && comparitor<TargetKey>(it)) [[likely]] {
238
         it += Length;
239
         if (*it != '"') [[unlikely]] {
240
            ctx.error = error_code::unexpected_enum;
241
            return;
242
         }
243
         value = get<I>(reflect<T>::values);
244
245
         ++it;
246
         if constexpr (not Opts.null_terminated) {
247
            if (it == end) {
248
               ctx.error = error_code::end_reached;
249
               return;
250
            }
251
         }
252
      }
253
      else [[unlikely]] {
254
         ctx.error = error_code::unexpected_enum;
255
         return;
256
      }
257
   }
258
259
   template <auto Opts, class T, auto& HashInfo, class Value, class... SelectedIndex>
260
      requires(glaze_object_t<T> || reflectable<T>)
261
   GLZ_ALWAYS_INLINE constexpr void parse_and_invoke(Value&& value, is_context auto&& ctx, auto&& it, auto&& end,
262
                                                     SelectedIndex&&... selected_index)
263
64.9k
   {
264
64.9k
      constexpr auto type = HashInfo.type;
265
64.9k
      constexpr auto N = reflect<T>::size;
266
267
64.9k
      static_assert(bool(type), "invalid hash algorithm");
268
269
      if constexpr (N == 1) {
270
         decode_index<Opts, T, 0>(value, ctx, it, end, selected_index...);
271
      }
272
64.9k
      else {
273
64.9k
         const auto index = decode_hash<JSON, T, HashInfo, HashInfo.type>::op(it, end);
274
275
64.9k
         if (index >= N) [[unlikely]] {
276
98
            if constexpr (Opts.error_on_unknown_keys) {
277
98
               ctx.error = error_code::unknown_key;
278
98
               return;
279
            }
280
            else {
281
               // we need to search until we find the ending quote of the key
282
               auto start = it;
283
               skip_string_view<Opts>(ctx, it, end);
284
               if (bool(ctx.error)) [[unlikely]]
285
                  return;
286
               const sv key = {start, size_t(it - start)};
287
               ++it; // skip the quote
288
               if constexpr (not Opts.null_terminated) {
289
                  if (it == end) [[unlikely]] {
290
                     ctx.error = error_code::unexpected_end;
291
                     return;
292
                  }
293
               }
294
295
               if (parse_ws_colon<Opts>(ctx, it, end)) {
296
                  return;
297
               }
298
299
               parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
300
               return;
301
            }
302
98
         }
303
304
         if constexpr (N == 2) {
305
            if (index == 0) {
306
               decode_index<Opts, T, 0>(value, ctx, it, end, selected_index...);
307
            }
308
            else {
309
               decode_index<Opts, T, 1>(value, ctx, it, end, selected_index...);
310
            }
311
         }
312
64.9k
         else {
313
64.9k
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end, selected_index...); }, index);
_ZZN3glz16parse_and_invokeITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structTnRDaL_ZNS_9hash_infoIS2_EEERS2_JETkNS_10is_contextERNS_7contextERPKcSA_Qoo14glaze_object_tIT0_E11reflectableISB_EEEvOT2_OT4_OT5_OT6_DpOT3_ENKUlTnmvE_clILm0EEEDav
Line
Count
Source
313
8.52k
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end, selected_index...); }, index);
_ZZN3glz16parse_and_invokeITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structTnRDaL_ZNS_9hash_infoIS2_EEERS2_JETkNS_10is_contextERNS_7contextERPKcSA_Qoo14glaze_object_tIT0_E11reflectableISB_EEEvOT2_OT4_OT5_OT6_DpOT3_ENKUlTnmvE_clILm1EEEDav
Line
Count
Source
313
14.8k
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end, selected_index...); }, index);
_ZZN3glz16parse_and_invokeITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structTnRDaL_ZNS_9hash_infoIS2_EEERS2_JETkNS_10is_contextERNS_7contextERPKcSA_Qoo14glaze_object_tIT0_E11reflectableISB_EEEvOT2_OT4_OT5_OT6_DpOT3_ENKUlTnmvE_clILm2EEEDav
Line
Count
Source
313
3
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end, selected_index...); }, index);
_ZZN3glz16parse_and_invokeITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structTnRDaL_ZNS_9hash_infoIS2_EEERS2_JETkNS_10is_contextERNS_7contextERPKcSA_Qoo14glaze_object_tIT0_E11reflectableISB_EEEvOT2_OT4_OT5_OT6_DpOT3_ENKUlTnmvE_clILm3EEEDav
Line
Count
Source
313
9.06k
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end, selected_index...); }, index);
_ZZN3glz16parse_and_invokeITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structTnRDaL_ZNS_9hash_infoIS2_EEERS2_JETkNS_10is_contextERNS_7contextERPKcSA_Qoo14glaze_object_tIT0_E11reflectableISB_EEEvOT2_OT4_OT5_OT6_DpOT3_ENKUlTnmvE_clILm0EEEDav
Line
Count
Source
313
8.52k
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end, selected_index...); }, index);
_ZZN3glz16parse_and_invokeITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structTnRDaL_ZNS_9hash_infoIS2_EEERS2_JETkNS_10is_contextERNS_7contextERPKcSA_Qoo14glaze_object_tIT0_E11reflectableISB_EEEvOT2_OT4_OT5_OT6_DpOT3_ENKUlTnmvE_clILm1EEEDav
Line
Count
Source
313
14.8k
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end, selected_index...); }, index);
_ZZN3glz16parse_and_invokeITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structTnRDaL_ZNS_9hash_infoIS2_EEERS2_JETkNS_10is_contextERNS_7contextERPKcSA_Qoo14glaze_object_tIT0_E11reflectableISB_EEEvOT2_OT4_OT5_OT6_DpOT3_ENKUlTnmvE_clILm2EEEDav
Line
Count
Source
313
3
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end, selected_index...); }, index);
_ZZN3glz16parse_and_invokeITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structTnRDaL_ZNS_9hash_infoIS2_EEERS2_JETkNS_10is_contextERNS_7contextERPKcSA_Qoo14glaze_object_tIT0_E11reflectableISB_EEEvOT2_OT4_OT5_OT6_DpOT3_ENKUlTnmvE_clILm3EEEDav
Line
Count
Source
313
9.06k
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end, selected_index...); }, index);
314
64.9k
         }
315
64.9k
      }
316
64.9k
   }
_ZN3glz16parse_and_invokeITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structTnRDaL_ZNS_9hash_infoIS2_EEERS2_JETkNS_10is_contextERNS_7contextERPKcSA_Qoo14glaze_object_tIT0_E11reflectableISB_EEEvOT2_OT4_OT5_OT6_DpOT3_
Line
Count
Source
263
32.4k
   {
264
32.4k
      constexpr auto type = HashInfo.type;
265
32.4k
      constexpr auto N = reflect<T>::size;
266
267
32.4k
      static_assert(bool(type), "invalid hash algorithm");
268
269
      if constexpr (N == 1) {
270
         decode_index<Opts, T, 0>(value, ctx, it, end, selected_index...);
271
      }
272
32.4k
      else {
273
32.4k
         const auto index = decode_hash<JSON, T, HashInfo, HashInfo.type>::op(it, end);
274
275
32.4k
         if (index >= N) [[unlikely]] {
276
37
            if constexpr (Opts.error_on_unknown_keys) {
277
37
               ctx.error = error_code::unknown_key;
278
37
               return;
279
            }
280
            else {
281
               // we need to search until we find the ending quote of the key
282
               auto start = it;
283
               skip_string_view<Opts>(ctx, it, end);
284
               if (bool(ctx.error)) [[unlikely]]
285
                  return;
286
               const sv key = {start, size_t(it - start)};
287
               ++it; // skip the quote
288
               if constexpr (not Opts.null_terminated) {
289
                  if (it == end) [[unlikely]] {
290
                     ctx.error = error_code::unexpected_end;
291
                     return;
292
                  }
293
               }
294
295
               if (parse_ws_colon<Opts>(ctx, it, end)) {
296
                  return;
297
               }
298
299
               parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
300
               return;
301
            }
302
37
         }
303
304
         if constexpr (N == 2) {
305
            if (index == 0) {
306
               decode_index<Opts, T, 0>(value, ctx, it, end, selected_index...);
307
            }
308
            else {
309
               decode_index<Opts, T, 1>(value, ctx, it, end, selected_index...);
310
            }
311
         }
312
32.4k
         else {
313
32.4k
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end, selected_index...); }, index);
314
32.4k
         }
315
32.4k
      }
316
32.4k
   }
_ZN3glz16parse_and_invokeITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEE9my_structTnRDaL_ZNS_9hash_infoIS2_EEERS2_JETkNS_10is_contextERNS_7contextERPKcSA_Qoo14glaze_object_tIT0_E11reflectableISB_EEEvOT2_OT4_OT5_OT6_DpOT3_
Line
Count
Source
263
32.4k
   {
264
32.4k
      constexpr auto type = HashInfo.type;
265
32.4k
      constexpr auto N = reflect<T>::size;
266
267
32.4k
      static_assert(bool(type), "invalid hash algorithm");
268
269
      if constexpr (N == 1) {
270
         decode_index<Opts, T, 0>(value, ctx, it, end, selected_index...);
271
      }
272
32.4k
      else {
273
32.4k
         const auto index = decode_hash<JSON, T, HashInfo, HashInfo.type>::op(it, end);
274
275
32.4k
         if (index >= N) [[unlikely]] {
276
61
            if constexpr (Opts.error_on_unknown_keys) {
277
61
               ctx.error = error_code::unknown_key;
278
61
               return;
279
            }
280
            else {
281
               // we need to search until we find the ending quote of the key
282
               auto start = it;
283
               skip_string_view<Opts>(ctx, it, end);
284
               if (bool(ctx.error)) [[unlikely]]
285
                  return;
286
               const sv key = {start, size_t(it - start)};
287
               ++it; // skip the quote
288
               if constexpr (not Opts.null_terminated) {
289
                  if (it == end) [[unlikely]] {
290
                     ctx.error = error_code::unexpected_end;
291
                     return;
292
                  }
293
               }
294
295
               if (parse_ws_colon<Opts>(ctx, it, end)) {
296
                  return;
297
               }
298
299
               parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
300
               return;
301
            }
302
61
         }
303
304
         if constexpr (N == 2) {
305
            if (index == 0) {
306
               decode_index<Opts, T, 0>(value, ctx, it, end, selected_index...);
307
            }
308
            else {
309
               decode_index<Opts, T, 1>(value, ctx, it, end, selected_index...);
310
            }
311
         }
312
32.4k
         else {
313
32.4k
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end, selected_index...); }, index);
314
32.4k
         }
315
32.4k
      }
316
32.4k
   }
317
318
   template <is_member_function_pointer T>
319
   struct from<JSON, T>
320
   {
321
      template <auto Opts>
322
      GLZ_ALWAYS_INLINE static void op(auto&&, is_context auto&& ctx, auto&&...) noexcept
323
      {
324
         ctx.error = error_code::attempt_member_func_read;
325
      }
326
   };
327
328
   template <is_includer T>
329
   struct from<JSON, T>
330
   {
331
      template <auto Opts, class... Args>
332
      static void op(auto&&, is_context auto&& ctx, auto&& it, auto&& end) noexcept
333
      {
334
         if constexpr (!check_ws_handled(Opts)) {
335
            if (skip_ws<Opts>(ctx, it, end)) {
336
               return;
337
            }
338
         }
339
340
         match<R"("")", Opts>(ctx, it, end);
341
      }
342
   };
343
344
   template <is_bitset T>
345
   struct from<JSON, T>
346
   {
347
      template <auto Opts>
348
      static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end) noexcept
349
      {
350
         if (match_invalid_end<'"', Opts>(ctx, it, end)) {
351
            return;
352
         }
353
354
         const auto n = value.size();
355
         for (size_t i = 1; it < end; ++i, ++it) {
356
            if (*it == '"') {
357
               ++it;
358
               if constexpr (not Opts.null_terminated) {
359
                  if (it == end) {
360
                     ctx.error = error_code::end_reached;
361
                     return;
362
                  }
363
               }
364
               return;
365
            }
366
367
            if (i > n) {
368
               ctx.error = error_code::exceeded_static_array_size;
369
               return;
370
            }
371
372
            if (*it == '0') {
373
               value[n - i] = 0;
374
            }
375
            else if (*it == '1') {
376
               value[n - i] = 1;
377
            }
378
            else [[unlikely]] {
379
               ctx.error = error_code::syntax_error;
380
               return;
381
            }
382
         }
383
384
         ctx.error = error_code::expected_quote;
385
      }
386
   };
387
388
   template <>
389
   struct from<JSON, skip>
390
   {
391
      template <auto Opts>
392
      GLZ_ALWAYS_INLINE static void op(auto&&, is_context auto&& ctx, auto&&... args) noexcept
393
      {
394
         skip_value<JSON>::op<Opts>(ctx, args...);
395
      }
396
   };
397
398
   template <is_reference_wrapper T>
399
   struct from<JSON, T>
400
   {
401
      template <auto Opts, class... Args>
402
      GLZ_ALWAYS_INLINE static void op(auto&& value, Args&&... args)
403
      {
404
         using V = std::decay_t<decltype(value.get())>;
405
         from<JSON, V>::template op<Opts>(value.get(), std::forward<Args>(args)...);
406
      }
407
   };
408
409
   template <>
410
   struct from<JSON, hidden>
411
   {
412
      template <auto Opts>
413
      GLZ_ALWAYS_INLINE static void op(auto&&, is_context auto&& ctx, auto&&...) noexcept
414
      {
415
         ctx.error = error_code::attempt_read_hidden;
416
      }
417
   };
418
419
   template <complex_t T>
420
   struct from<JSON, T>
421
   {
422
      template <auto Options>
423
      static void op(auto&& v, is_context auto&& ctx, auto&& it, auto&& end) noexcept
424
      {
425
         constexpr auto Opts = ws_handled_off<Options>();
426
         if constexpr (!check_ws_handled(Options)) {
427
            if (skip_ws<Opts>(ctx, it, end)) {
428
               return;
429
            }
430
         }
431
         if (match_invalid_end<'[', Opts>(ctx, it, end)) {
432
            return;
433
         }
434
         if constexpr (not Opts.null_terminated) {
435
            ++ctx.indentation_level;
436
         }
437
438
         auto* ptr = reinterpret_cast<typename T::value_type*>(&v);
439
         static_assert(sizeof(T) == sizeof(typename T::value_type) * 2);
440
         parse<JSON>::op<Opts>(ptr[0], ctx, it, end);
441
         if (bool(ctx.error)) [[unlikely]]
442
            return;
443
444
         if (skip_ws<Opts>(ctx, it, end)) {
445
            return;
446
         }
447
448
         if (match_invalid_end<',', Opts>(ctx, it, end)) {
449
            return;
450
         }
451
452
         parse<JSON>::op<Opts>(ptr[1], ctx, it, end);
453
         if (bool(ctx.error)) [[unlikely]]
454
            return;
455
456
         if (skip_ws<Opts>(ctx, it, end)) {
457
            return;
458
         }
459
         match<']'>(ctx, it);
460
         if constexpr (not Opts.null_terminated) {
461
            --ctx.indentation_level;
462
         }
463
      }
464
   };
465
466
   template <always_null_t T>
467
   struct from<JSON, T>
468
   {
469
      template <auto Opts>
470
      GLZ_ALWAYS_INLINE static void op(auto&&, is_context auto&& ctx, auto&& it, auto&& end) noexcept
471
      {
472
         if constexpr (!check_ws_handled(Opts)) {
473
            if (skip_ws<Opts>(ctx, it, end)) {
474
               return;
475
            }
476
         }
477
         static constexpr sv null_string = "null";
478
         if constexpr (not check_is_padded(Opts)) {
479
            const auto n = size_t(end - it);
480
            if ((n < 4) || not comparitor<null_string>(it)) [[unlikely]] {
481
               ctx.error = error_code::syntax_error;
482
            }
483
         }
484
         else {
485
            if (not comparitor<null_string>(it)) [[unlikely]] {
486
               ctx.error = error_code::syntax_error;
487
            }
488
         }
489
         it += 4; // always advance for performance
490
      }
491
   };
492
493
   template <bool_t T>
494
   struct from<JSON, T>
495
   {
496
      template <auto Opts>
497
      static void op(bool_t auto&& value, is_context auto&& ctx, auto&& it, auto&& end) noexcept
498
      {
499
         if constexpr (Opts.quoted_num) {
500
            if (skip_ws<Opts>(ctx, it, end)) {
501
               return;
502
            }
503
            if (match_invalid_end<'"', Opts>(ctx, it, end)) {
504
               return;
505
            }
506
         }
507
508
         if constexpr (!check_ws_handled(Opts)) {
509
            if (skip_ws<Opts>(ctx, it, end)) {
510
               return;
511
            }
512
         }
513
514
         if constexpr (Opts.bools_as_numbers) {
515
            if (*it == '1') {
516
               value = true;
517
               ++it;
518
            }
519
            else if (*it == '0') {
520
               value = false;
521
               ++it;
522
            }
523
            else {
524
               ctx.error = error_code::syntax_error;
525
               return;
526
            }
527
         }
528
         else {
529
            if constexpr (not check_is_padded(Opts)) {
530
               if (size_t(end - it) < 4) [[unlikely]] {
531
                  ctx.error = error_code::expected_true_or_false;
532
                  return;
533
               }
534
            }
535
536
            uint32_t c;
537
            static constexpr uint32_t u_true = 0b01100101'01110101'01110010'01110100;
538
            static constexpr uint32_t u_fals = 0b01110011'01101100'01100001'01100110;
539
            std::memcpy(&c, it, 4);
540
            it += 4;
541
            if (c == u_true) {
542
               value = true;
543
            }
544
            else if (it == end) [[unlikely]] {
545
               ctx.error = error_code::unexpected_end;
546
               return;
547
            }
548
            else {
549
               if (c == u_fals && (*it == 'e')) [[likely]] {
550
                  value = false;
551
                  ++it;
552
               }
553
               else [[unlikely]] {
554
                  ctx.error = error_code::expected_true_or_false;
555
                  return;
556
               }
557
            }
558
         }
559
560
         if constexpr (Opts.quoted_num) {
561
            if constexpr (not Opts.null_terminated) {
562
               if (it == end) [[unlikely]] {
563
                  ctx.error = error_code::unexpected_end;
564
                  return;
565
               }
566
            }
567
            if (match<'"'>(ctx, it)) {
568
               return;
569
            }
570
            if constexpr (not Opts.null_terminated) {
571
               if (it == end) {
572
                  ctx.error = error_code::end_reached;
573
                  return;
574
               }
575
            }
576
         }
577
         else {
578
            if constexpr (not Opts.null_terminated) {
579
               if (it == end) {
580
                  ctx.error = error_code::end_reached;
581
                  return;
582
               }
583
            }
584
         }
585
      }
586
   };
587
588
   template <num_t T>
589
   struct from<JSON, T>
590
   {
591
      template <auto Opts, class It>
592
      GLZ_ALWAYS_INLINE static void op(auto&& value, is_context auto&& ctx, It&& it, auto&& end) noexcept
593
79.9k
      {
594
         if constexpr (Opts.quoted_num) {
595
            if (skip_ws<Opts>(ctx, it, end)) {
596
               return;
597
            }
598
            if (match_invalid_end<'"', Opts>(ctx, it, end)) {
599
               return;
600
            }
601
         }
602
603
         if constexpr (!check_ws_handled(Opts)) {
604
            if (skip_ws<Opts>(ctx, it, end)) {
605
               return;
606
            }
607
         }
608
609
79.9k
         using V = std::decay_t<decltype(value)>;
610
79.9k
         if constexpr (int_t<V>) {
611
50.4k
            static_assert(sizeof(*it) == sizeof(char));
612
613
50.4k
            if constexpr (Opts.null_terminated) {
614
25.2k
               if (not glz::atoi(value, it)) [[unlikely]] {
615
610
                  ctx.error = error_code::parse_number_failure;
616
610
                  return;
617
610
               }
618
            }
619
25.1k
            else {
620
25.1k
               if (not glz::atoi(value, it, end)) [[unlikely]] {
621
496
                  ctx.error = error_code::parse_number_failure;
622
496
                  return;
623
496
               }
624
25.1k
            }
625
         }
626
29.5k
         else {
627
            if constexpr (is_float128<V>) {
628
               auto [ptr, ec] = std::from_chars(it, end, value);
629
               if (ec != std::errc()) {
630
                  ctx.error = error_code::parse_number_failure;
631
                  return;
632
               }
633
               it = ptr;
634
            }
635
29.5k
            else {
636
               if constexpr (std::is_volatile_v<std::remove_reference_t<decltype(value)>>) {
637
                  // Hardware may interact with value changes, so we parse into a temporary and assign in one
638
                  // place
639
                  V temp;
640
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, temp);
641
                  if (ec != std::errc()) [[unlikely]] {
642
                     ctx.error = error_code::parse_number_failure;
643
                     return;
644
                  }
645
                  value = temp;
646
                  it = ptr;
647
               }
648
29.5k
               else {
649
29.5k
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, value);
650
29.5k
                  if (ec != std::errc()) [[unlikely]] {
651
594
                     ctx.error = error_code::parse_number_failure;
652
594
                     return;
653
594
                  }
654
28.9k
                  it = ptr;
655
28.9k
               }
656
29.5k
            }
657
29.5k
         }
658
659
         if constexpr (Opts.quoted_num) {
660
            if constexpr (not Opts.null_terminated) {
661
               if (it == end) [[unlikely]] {
662
                  ctx.error = error_code::unexpected_end;
663
                  return;
664
               }
665
            }
666
            if (match<'"'>(ctx, it)) {
667
               return;
668
            }
669
            if constexpr (not Opts.null_terminated) {
670
               if (it == end) {
671
                  ctx.error = error_code::end_reached;
672
                  return;
673
               }
674
            }
675
         }
676
79.9k
         else {
677
79.9k
            if constexpr (not Opts.null_terminated) {
678
39.9k
               if (it == end) {
679
2.51k
                  ctx.error = error_code::end_reached;
680
2.51k
                  return;
681
2.51k
               }
682
39.9k
            }
683
79.9k
         }
684
79.9k
      }
_ZN3glz4fromILj10EiE2opITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERPKcRiTkNS_10is_contextERNS_7contextES6_EEvOT1_OT2_OT0_OT3_
Line
Count
Source
593
8.44k
      {
594
         if constexpr (Opts.quoted_num) {
595
            if (skip_ws<Opts>(ctx, it, end)) {
596
               return;
597
            }
598
            if (match_invalid_end<'"', Opts>(ctx, it, end)) {
599
               return;
600
            }
601
         }
602
603
         if constexpr (!check_ws_handled(Opts)) {
604
            if (skip_ws<Opts>(ctx, it, end)) {
605
               return;
606
            }
607
         }
608
609
8.44k
         using V = std::decay_t<decltype(value)>;
610
8.44k
         if constexpr (int_t<V>) {
611
8.44k
            static_assert(sizeof(*it) == sizeof(char));
612
613
            if constexpr (Opts.null_terminated) {
614
               if (not glz::atoi(value, it)) [[unlikely]] {
615
                  ctx.error = error_code::parse_number_failure;
616
                  return;
617
               }
618
            }
619
8.44k
            else {
620
8.44k
               if (not glz::atoi(value, it, end)) [[unlikely]] {
621
201
                  ctx.error = error_code::parse_number_failure;
622
201
                  return;
623
201
               }
624
8.44k
            }
625
         }
626
         else {
627
            if constexpr (is_float128<V>) {
628
               auto [ptr, ec] = std::from_chars(it, end, value);
629
               if (ec != std::errc()) {
630
                  ctx.error = error_code::parse_number_failure;
631
                  return;
632
               }
633
               it = ptr;
634
            }
635
            else {
636
               if constexpr (std::is_volatile_v<std::remove_reference_t<decltype(value)>>) {
637
                  // Hardware may interact with value changes, so we parse into a temporary and assign in one
638
                  // place
639
                  V temp;
640
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, temp);
641
                  if (ec != std::errc()) [[unlikely]] {
642
                     ctx.error = error_code::parse_number_failure;
643
                     return;
644
                  }
645
                  value = temp;
646
                  it = ptr;
647
               }
648
               else {
649
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, value);
650
                  if (ec != std::errc()) [[unlikely]] {
651
                     ctx.error = error_code::parse_number_failure;
652
                     return;
653
                  }
654
                  it = ptr;
655
               }
656
            }
657
         }
658
659
         if constexpr (Opts.quoted_num) {
660
            if constexpr (not Opts.null_terminated) {
661
               if (it == end) [[unlikely]] {
662
                  ctx.error = error_code::unexpected_end;
663
                  return;
664
               }
665
            }
666
            if (match<'"'>(ctx, it)) {
667
               return;
668
            }
669
            if constexpr (not Opts.null_terminated) {
670
               if (it == end) {
671
                  ctx.error = error_code::end_reached;
672
                  return;
673
               }
674
            }
675
         }
676
8.44k
         else {
677
8.44k
            if constexpr (not Opts.null_terminated) {
678
8.44k
               if (it == end) {
679
146
                  ctx.error = error_code::end_reached;
680
146
                  return;
681
146
               }
682
8.44k
            }
683
8.44k
         }
684
8.44k
      }
_ZN3glz4fromILj10EdE2opITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERPKcRdTkNS_10is_contextERNS_7contextES6_EEvOT1_OT2_OT0_OT3_
Line
Count
Source
593
14.7k
      {
594
         if constexpr (Opts.quoted_num) {
595
            if (skip_ws<Opts>(ctx, it, end)) {
596
               return;
597
            }
598
            if (match_invalid_end<'"', Opts>(ctx, it, end)) {
599
               return;
600
            }
601
         }
602
603
         if constexpr (!check_ws_handled(Opts)) {
604
            if (skip_ws<Opts>(ctx, it, end)) {
605
               return;
606
            }
607
         }
608
609
14.7k
         using V = std::decay_t<decltype(value)>;
610
         if constexpr (int_t<V>) {
611
            static_assert(sizeof(*it) == sizeof(char));
612
613
            if constexpr (Opts.null_terminated) {
614
               if (not glz::atoi(value, it)) [[unlikely]] {
615
                  ctx.error = error_code::parse_number_failure;
616
                  return;
617
               }
618
            }
619
            else {
620
               if (not glz::atoi(value, it, end)) [[unlikely]] {
621
                  ctx.error = error_code::parse_number_failure;
622
                  return;
623
               }
624
            }
625
         }
626
14.7k
         else {
627
            if constexpr (is_float128<V>) {
628
               auto [ptr, ec] = std::from_chars(it, end, value);
629
               if (ec != std::errc()) {
630
                  ctx.error = error_code::parse_number_failure;
631
                  return;
632
               }
633
               it = ptr;
634
            }
635
14.7k
            else {
636
               if constexpr (std::is_volatile_v<std::remove_reference_t<decltype(value)>>) {
637
                  // Hardware may interact with value changes, so we parse into a temporary and assign in one
638
                  // place
639
                  V temp;
640
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, temp);
641
                  if (ec != std::errc()) [[unlikely]] {
642
                     ctx.error = error_code::parse_number_failure;
643
                     return;
644
                  }
645
                  value = temp;
646
                  it = ptr;
647
               }
648
14.7k
               else {
649
14.7k
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, value);
650
14.7k
                  if (ec != std::errc()) [[unlikely]] {
651
286
                     ctx.error = error_code::parse_number_failure;
652
286
                     return;
653
286
                  }
654
14.4k
                  it = ptr;
655
14.4k
               }
656
14.7k
            }
657
14.7k
         }
658
659
         if constexpr (Opts.quoted_num) {
660
            if constexpr (not Opts.null_terminated) {
661
               if (it == end) [[unlikely]] {
662
                  ctx.error = error_code::unexpected_end;
663
                  return;
664
               }
665
            }
666
            if (match<'"'>(ctx, it)) {
667
               return;
668
            }
669
            if constexpr (not Opts.null_terminated) {
670
               if (it == end) {
671
                  ctx.error = error_code::end_reached;
672
                  return;
673
               }
674
            }
675
         }
676
14.7k
         else {
677
14.7k
            if constexpr (not Opts.null_terminated) {
678
14.7k
               if (it == end) {
679
2.16k
                  ctx.error = error_code::end_reached;
680
2.16k
                  return;
681
2.16k
               }
682
14.7k
            }
683
14.7k
         }
684
14.7k
      }
_ZN3glz4fromILj10EmE2opITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERPKcRmTkNS_10is_contextERNS_7contextES6_EEvOT1_OT2_OT0_OT3_
Line
Count
Source
593
16.7k
      {
594
         if constexpr (Opts.quoted_num) {
595
            if (skip_ws<Opts>(ctx, it, end)) {
596
               return;
597
            }
598
            if (match_invalid_end<'"', Opts>(ctx, it, end)) {
599
               return;
600
            }
601
         }
602
603
         if constexpr (!check_ws_handled(Opts)) {
604
            if (skip_ws<Opts>(ctx, it, end)) {
605
               return;
606
            }
607
         }
608
609
16.7k
         using V = std::decay_t<decltype(value)>;
610
16.7k
         if constexpr (int_t<V>) {
611
16.7k
            static_assert(sizeof(*it) == sizeof(char));
612
613
            if constexpr (Opts.null_terminated) {
614
               if (not glz::atoi(value, it)) [[unlikely]] {
615
                  ctx.error = error_code::parse_number_failure;
616
                  return;
617
               }
618
            }
619
16.7k
            else {
620
16.7k
               if (not glz::atoi(value, it, end)) [[unlikely]] {
621
295
                  ctx.error = error_code::parse_number_failure;
622
295
                  return;
623
295
               }
624
16.7k
            }
625
         }
626
         else {
627
            if constexpr (is_float128<V>) {
628
               auto [ptr, ec] = std::from_chars(it, end, value);
629
               if (ec != std::errc()) {
630
                  ctx.error = error_code::parse_number_failure;
631
                  return;
632
               }
633
               it = ptr;
634
            }
635
            else {
636
               if constexpr (std::is_volatile_v<std::remove_reference_t<decltype(value)>>) {
637
                  // Hardware may interact with value changes, so we parse into a temporary and assign in one
638
                  // place
639
                  V temp;
640
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, temp);
641
                  if (ec != std::errc()) [[unlikely]] {
642
                     ctx.error = error_code::parse_number_failure;
643
                     return;
644
                  }
645
                  value = temp;
646
                  it = ptr;
647
               }
648
               else {
649
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, value);
650
                  if (ec != std::errc()) [[unlikely]] {
651
                     ctx.error = error_code::parse_number_failure;
652
                     return;
653
                  }
654
                  it = ptr;
655
               }
656
            }
657
         }
658
659
         if constexpr (Opts.quoted_num) {
660
            if constexpr (not Opts.null_terminated) {
661
               if (it == end) [[unlikely]] {
662
                  ctx.error = error_code::unexpected_end;
663
                  return;
664
               }
665
            }
666
            if (match<'"'>(ctx, it)) {
667
               return;
668
            }
669
            if constexpr (not Opts.null_terminated) {
670
               if (it == end) {
671
                  ctx.error = error_code::end_reached;
672
                  return;
673
               }
674
            }
675
         }
676
16.7k
         else {
677
16.7k
            if constexpr (not Opts.null_terminated) {
678
16.7k
               if (it == end) {
679
203
                  ctx.error = error_code::end_reached;
680
203
                  return;
681
203
               }
682
16.7k
            }
683
16.7k
         }
684
16.7k
      }
_ZN3glz4fromILj10EiE2opITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERPKcRiTkNS_10is_contextERNS_7contextES6_EEvOT1_OT2_OT0_OT3_
Line
Count
Source
593
8.46k
      {
594
         if constexpr (Opts.quoted_num) {
595
            if (skip_ws<Opts>(ctx, it, end)) {
596
               return;
597
            }
598
            if (match_invalid_end<'"', Opts>(ctx, it, end)) {
599
               return;
600
            }
601
         }
602
603
         if constexpr (!check_ws_handled(Opts)) {
604
            if (skip_ws<Opts>(ctx, it, end)) {
605
               return;
606
            }
607
         }
608
609
8.46k
         using V = std::decay_t<decltype(value)>;
610
8.46k
         if constexpr (int_t<V>) {
611
8.46k
            static_assert(sizeof(*it) == sizeof(char));
612
613
8.46k
            if constexpr (Opts.null_terminated) {
614
8.46k
               if (not glz::atoi(value, it)) [[unlikely]] {
615
226
                  ctx.error = error_code::parse_number_failure;
616
226
                  return;
617
226
               }
618
            }
619
            else {
620
               if (not glz::atoi(value, it, end)) [[unlikely]] {
621
                  ctx.error = error_code::parse_number_failure;
622
                  return;
623
               }
624
            }
625
         }
626
         else {
627
            if constexpr (is_float128<V>) {
628
               auto [ptr, ec] = std::from_chars(it, end, value);
629
               if (ec != std::errc()) {
630
                  ctx.error = error_code::parse_number_failure;
631
                  return;
632
               }
633
               it = ptr;
634
            }
635
            else {
636
               if constexpr (std::is_volatile_v<std::remove_reference_t<decltype(value)>>) {
637
                  // Hardware may interact with value changes, so we parse into a temporary and assign in one
638
                  // place
639
                  V temp;
640
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, temp);
641
                  if (ec != std::errc()) [[unlikely]] {
642
                     ctx.error = error_code::parse_number_failure;
643
                     return;
644
                  }
645
                  value = temp;
646
                  it = ptr;
647
               }
648
               else {
649
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, value);
650
                  if (ec != std::errc()) [[unlikely]] {
651
                     ctx.error = error_code::parse_number_failure;
652
                     return;
653
                  }
654
                  it = ptr;
655
               }
656
            }
657
         }
658
659
         if constexpr (Opts.quoted_num) {
660
            if constexpr (not Opts.null_terminated) {
661
               if (it == end) [[unlikely]] {
662
                  ctx.error = error_code::unexpected_end;
663
                  return;
664
               }
665
            }
666
            if (match<'"'>(ctx, it)) {
667
               return;
668
            }
669
            if constexpr (not Opts.null_terminated) {
670
               if (it == end) {
671
                  ctx.error = error_code::end_reached;
672
                  return;
673
               }
674
            }
675
         }
676
8.46k
         else {
677
            if constexpr (not Opts.null_terminated) {
678
               if (it == end) {
679
                  ctx.error = error_code::end_reached;
680
                  return;
681
               }
682
            }
683
8.46k
         }
684
8.46k
      }
_ZN3glz4fromILj10EdE2opITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERPKcRdTkNS_10is_contextERNS_7contextES6_EEvOT1_OT2_OT0_OT3_
Line
Count
Source
593
14.7k
      {
594
         if constexpr (Opts.quoted_num) {
595
            if (skip_ws<Opts>(ctx, it, end)) {
596
               return;
597
            }
598
            if (match_invalid_end<'"', Opts>(ctx, it, end)) {
599
               return;
600
            }
601
         }
602
603
         if constexpr (!check_ws_handled(Opts)) {
604
            if (skip_ws<Opts>(ctx, it, end)) {
605
               return;
606
            }
607
         }
608
609
14.7k
         using V = std::decay_t<decltype(value)>;
610
         if constexpr (int_t<V>) {
611
            static_assert(sizeof(*it) == sizeof(char));
612
613
            if constexpr (Opts.null_terminated) {
614
               if (not glz::atoi(value, it)) [[unlikely]] {
615
                  ctx.error = error_code::parse_number_failure;
616
                  return;
617
               }
618
            }
619
            else {
620
               if (not glz::atoi(value, it, end)) [[unlikely]] {
621
                  ctx.error = error_code::parse_number_failure;
622
                  return;
623
               }
624
            }
625
         }
626
14.7k
         else {
627
            if constexpr (is_float128<V>) {
628
               auto [ptr, ec] = std::from_chars(it, end, value);
629
               if (ec != std::errc()) {
630
                  ctx.error = error_code::parse_number_failure;
631
                  return;
632
               }
633
               it = ptr;
634
            }
635
14.7k
            else {
636
               if constexpr (std::is_volatile_v<std::remove_reference_t<decltype(value)>>) {
637
                  // Hardware may interact with value changes, so we parse into a temporary and assign in one
638
                  // place
639
                  V temp;
640
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, temp);
641
                  if (ec != std::errc()) [[unlikely]] {
642
                     ctx.error = error_code::parse_number_failure;
643
                     return;
644
                  }
645
                  value = temp;
646
                  it = ptr;
647
               }
648
14.7k
               else {
649
14.7k
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, value);
650
14.7k
                  if (ec != std::errc()) [[unlikely]] {
651
308
                     ctx.error = error_code::parse_number_failure;
652
308
                     return;
653
308
                  }
654
14.4k
                  it = ptr;
655
14.4k
               }
656
14.7k
            }
657
14.7k
         }
658
659
         if constexpr (Opts.quoted_num) {
660
            if constexpr (not Opts.null_terminated) {
661
               if (it == end) [[unlikely]] {
662
                  ctx.error = error_code::unexpected_end;
663
                  return;
664
               }
665
            }
666
            if (match<'"'>(ctx, it)) {
667
               return;
668
            }
669
            if constexpr (not Opts.null_terminated) {
670
               if (it == end) {
671
                  ctx.error = error_code::end_reached;
672
                  return;
673
               }
674
            }
675
         }
676
14.7k
         else {
677
            if constexpr (not Opts.null_terminated) {
678
               if (it == end) {
679
                  ctx.error = error_code::end_reached;
680
                  return;
681
               }
682
            }
683
14.7k
         }
684
14.7k
      }
_ZN3glz4fromILj10EmE2opITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERPKcRmTkNS_10is_contextERNS_7contextES6_EEvOT1_OT2_OT0_OT3_
Line
Count
Source
593
16.8k
      {
594
         if constexpr (Opts.quoted_num) {
595
            if (skip_ws<Opts>(ctx, it, end)) {
596
               return;
597
            }
598
            if (match_invalid_end<'"', Opts>(ctx, it, end)) {
599
               return;
600
            }
601
         }
602
603
         if constexpr (!check_ws_handled(Opts)) {
604
            if (skip_ws<Opts>(ctx, it, end)) {
605
               return;
606
            }
607
         }
608
609
16.8k
         using V = std::decay_t<decltype(value)>;
610
16.8k
         if constexpr (int_t<V>) {
611
16.8k
            static_assert(sizeof(*it) == sizeof(char));
612
613
16.8k
            if constexpr (Opts.null_terminated) {
614
16.8k
               if (not glz::atoi(value, it)) [[unlikely]] {
615
384
                  ctx.error = error_code::parse_number_failure;
616
384
                  return;
617
384
               }
618
            }
619
            else {
620
               if (not glz::atoi(value, it, end)) [[unlikely]] {
621
                  ctx.error = error_code::parse_number_failure;
622
                  return;
623
               }
624
            }
625
         }
626
         else {
627
            if constexpr (is_float128<V>) {
628
               auto [ptr, ec] = std::from_chars(it, end, value);
629
               if (ec != std::errc()) {
630
                  ctx.error = error_code::parse_number_failure;
631
                  return;
632
               }
633
               it = ptr;
634
            }
635
            else {
636
               if constexpr (std::is_volatile_v<std::remove_reference_t<decltype(value)>>) {
637
                  // Hardware may interact with value changes, so we parse into a temporary and assign in one
638
                  // place
639
                  V temp;
640
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, temp);
641
                  if (ec != std::errc()) [[unlikely]] {
642
                     ctx.error = error_code::parse_number_failure;
643
                     return;
644
                  }
645
                  value = temp;
646
                  it = ptr;
647
               }
648
               else {
649
                  auto [ptr, ec] = glz::from_chars<Opts.null_terminated>(it, end, value);
650
                  if (ec != std::errc()) [[unlikely]] {
651
                     ctx.error = error_code::parse_number_failure;
652
                     return;
653
                  }
654
                  it = ptr;
655
               }
656
            }
657
         }
658
659
         if constexpr (Opts.quoted_num) {
660
            if constexpr (not Opts.null_terminated) {
661
               if (it == end) [[unlikely]] {
662
                  ctx.error = error_code::unexpected_end;
663
                  return;
664
               }
665
            }
666
            if (match<'"'>(ctx, it)) {
667
               return;
668
            }
669
            if constexpr (not Opts.null_terminated) {
670
               if (it == end) {
671
                  ctx.error = error_code::end_reached;
672
                  return;
673
               }
674
            }
675
         }
676
16.8k
         else {
677
            if constexpr (not Opts.null_terminated) {
678
               if (it == end) {
679
                  ctx.error = error_code::end_reached;
680
                  return;
681
               }
682
            }
683
16.8k
         }
684
16.8k
      }
685
   };
686
687
   template <string_t T>
688
   struct from<JSON, T>
689
   {
690
      template <auto Opts, class It, class End>
691
         requires(check_is_padded(Opts))
692
      static void op(auto& value, is_context auto&& ctx, It&& it, End&& end)
693
      {
694
         if constexpr (Opts.number) {
695
            auto start = it;
696
            skip_number<Opts>(ctx, it, end);
697
            if (bool(ctx.error)) [[unlikely]] {
698
               return;
699
            }
700
            value.append(start, size_t(it - start));
701
         }
702
         else {
703
            if constexpr (!check_opening_handled(Opts)) {
704
               if constexpr (!check_ws_handled(Opts)) {
705
                  if (skip_ws<Opts>(ctx, it, end)) {
706
                     return;
707
                  }
708
               }
709
710
               if (match_invalid_end<'"', Opts>(ctx, it, end)) {
711
                  return;
712
               }
713
            }
714
715
            if constexpr (not Opts.raw_string) {
716
               static constexpr auto string_padding_bytes = 8;
717
718
               auto start = it;
719
               while (true) {
720
                  if (it >= end) [[unlikely]] {
721
                     ctx.error = error_code::unexpected_end;
722
                     return;
723
                  }
724
725
                  uint64_t chunk;
726
                  std::memcpy(&chunk, it, 8);
727
                  const uint64_t test_chars = has_quote(chunk);
728
                  if (test_chars) {
729
                     it += (countr_zero(test_chars) >> 3);
730
731
                     auto* prev = it - 1;
732
                     while (*prev == '\\') {
733
                        --prev;
734
                     }
735
                     if (size_t(it - prev) % 2) {
736
                        break;
737
                     }
738
                     ++it; // skip the escaped quote
739
                  }
740
                  else {
741
                     it += 8;
742
                  }
743
               }
744
745
               auto n = size_t(it - start);
746
               value.resize(n + string_padding_bytes);
747
748
               auto* p = value.data();
749
750
               while (true) {
751
                  if (start >= it) {
752
                     break;
753
                  }
754
755
                  std::memcpy(p, start, 8);
756
                  uint64_t swar;
757
                  std::memcpy(&swar, p, 8);
758
759
                  constexpr uint64_t lo7_mask = repeat_byte8(0b01111111);
760
                  const uint64_t lo7 = swar & lo7_mask;
761
                  const uint64_t backslash = (lo7 ^ repeat_byte8('\\')) + lo7_mask;
762
                  const uint64_t less_32 = (swar & repeat_byte8(0b01100000)) + lo7_mask;
763
                  uint64_t next = ~((backslash & less_32) | swar);
764
765
                  next &= repeat_byte8(0b10000000);
766
                  if (next == 0) {
767
                     start += 8;
768
                     p += 8;
769
                     continue;
770
                  }
771
772
                  next = countr_zero(next) >> 3;
773
                  start += next;
774
                  if (start >= it) {
775
                     break;
776
                  }
777
778
                  if ((*start & 0b11100000) == 0) [[unlikely]] {
779
                     ctx.error = error_code::syntax_error;
780
                     return;
781
                  }
782
                  ++start; // skip the escape
783
                  if (*start == 'u') {
784
                     ++start;
785
                     p += next;
786
                     const auto mark = start;
787
                     const auto offset = handle_unicode_code_point(start, p, end);
788
                     if (offset == 0) [[unlikely]] {
789
                        ctx.error = error_code::unicode_escape_conversion_failure;
790
                        return;
791
                     }
792
                     n += offset;
793
                     // escape + u + unicode code points
794
                     n -= 2 + uint32_t(start - mark);
795
                  }
796
                  else {
797
                     p += next;
798
                     *p = char_unescape_table[uint8_t(*start)];
799
                     if (*p == 0) [[unlikely]] {
800
                        ctx.error = error_code::invalid_escape;
801
                        return;
802
                     }
803
                     ++p;
804
                     ++start;
805
                     --n;
806
                  }
807
               }
808
809
               value.resize(n);
810
               ++it;
811
            }
812
            else {
813
               // raw_string
814
               auto start = it;
815
               skip_string_view<Opts>(ctx, it, end);
816
               if (bool(ctx.error)) [[unlikely]]
817
                  return;
818
819
               value.assign(start, size_t(it - start));
820
               ++it;
821
            }
822
         }
823
      }
824
825
      template <auto Opts, class It, class End>
826
         requires(not check_is_padded(Opts))
827
      static void op(auto& value, is_context auto&& ctx, It&& it, End&& end)
828
0
      {
829
         if constexpr (Opts.number) {
830
            auto start = it;
831
            skip_number<Opts>(ctx, it, end);
832
            if (bool(ctx.error)) [[unlikely]] {
833
               return;
834
            }
835
            if (start == it) [[unlikely]] {
836
               ctx.error = error_code::parse_number_failure;
837
               return;
838
            }
839
            value.append(start, size_t(it - start));
840
         }
841
0
         else {
842
0
            if constexpr (!check_opening_handled(Opts)) {
843
               if constexpr (!check_ws_handled(Opts)) {
844
                  if (skip_ws<Opts>(ctx, it, end)) {
845
                     return;
846
                  }
847
               }
848
849
0
               if (match_invalid_end<'"', Opts>(ctx, it, end)) {
850
0
                  return;
851
0
               }
852
0
            }
853
854
0
            if constexpr (not Opts.raw_string) {
855
0
               static constexpr auto string_padding_bytes = 8;
856
857
0
               if (size_t(end - it) >= 8) {
858
0
                  auto start = it;
859
0
                  const auto end8 = end - 8;
860
0
                  while (true) {
861
0
                     if (it >= end8) [[unlikely]] {
862
0
                        break;
863
0
                     }
864
865
0
                     uint64_t chunk;
866
0
                     std::memcpy(&chunk, it, 8);
867
0
                     const uint64_t test_chars = has_quote(chunk);
868
0
                     if (test_chars) {
869
0
                        it += (countr_zero(test_chars) >> 3);
870
871
0
                        auto* prev = it - 1;
872
0
                        while (*prev == '\\') {
873
0
                           --prev;
874
0
                        }
875
0
                        if (size_t(it - prev) % 2) {
876
0
                           goto continue_decode;
877
0
                        }
878
0
                        ++it; // skip the escaped quote
879
0
                     }
880
0
                     else {
881
0
                        it += 8;
882
0
                     }
883
0
                  }
884
885
0
                  while (it[-1] == '\\') [[unlikely]] {
886
                     // if we ended on an escape character then we need to rewind
887
                     // because we lost our context
888
0
                     --it;
889
0
                  }
890
891
0
                  for (; it < end; ++it) {
892
0
                     if (*it == '"') {
893
0
                        auto* prev = it - 1;
894
0
                        while (*prev == '\\') {
895
0
                           --prev;
896
0
                        }
897
0
                        if (size_t(it - prev) % 2) {
898
0
                           goto continue_decode;
899
0
                        }
900
0
                     }
901
0
                  }
902
903
0
                  ctx.error = error_code::unexpected_end;
904
0
                  return;
905
906
0
               continue_decode:
907
908
0
                  const auto available_padding = size_t(end - it);
909
0
                  auto n = size_t(it - start);
910
0
                  if (available_padding >= 8) [[likely]] {
911
0
                     value.resize(n + string_padding_bytes);
912
913
0
                     auto* p = value.data();
914
915
0
                     while (true) {
916
0
                        if (start >= it) {
917
0
                           break;
918
0
                        }
919
920
0
                        std::memcpy(p, start, 8);
921
0
                        uint64_t swar;
922
0
                        std::memcpy(&swar, p, 8);
923
924
0
                        constexpr uint64_t lo7_mask = repeat_byte8(0b01111111);
925
0
                        const uint64_t lo7 = swar & lo7_mask;
926
0
                        const uint64_t backslash = (lo7 ^ repeat_byte8('\\')) + lo7_mask;
927
0
                        const uint64_t less_32 = (swar & repeat_byte8(0b01100000)) + lo7_mask;
928
0
                        uint64_t next = ~((backslash & less_32) | swar);
929
930
0
                        next &= repeat_byte8(0b10000000);
931
0
                        if (next == 0) {
932
0
                           start += 8;
933
0
                           p += 8;
934
0
                           continue;
935
0
                        }
936
937
0
                        next = countr_zero(next) >> 3;
938
0
                        start += next;
939
0
                        if (start >= it) {
940
0
                           break;
941
0
                        }
942
943
0
                        if ((*start & 0b11100000) == 0) [[unlikely]] {
944
0
                           ctx.error = error_code::syntax_error;
945
0
                           return;
946
0
                        }
947
0
                        ++start; // skip the escape
948
0
                        if (*start == 'u') {
949
0
                           ++start;
950
0
                           p += next;
951
0
                           const auto mark = start;
952
0
                           const auto offset = handle_unicode_code_point(start, p, end);
953
0
                           if (offset == 0) [[unlikely]] {
954
0
                              ctx.error = error_code::unicode_escape_conversion_failure;
955
0
                              return;
956
0
                           }
957
0
                           n += offset;
958
                           // escape + u + unicode code points
959
0
                           n -= 2 + uint32_t(start - mark);
960
0
                        }
961
0
                        else {
962
0
                           p += next;
963
0
                           *p = char_unescape_table[uint8_t(*start)];
964
0
                           if (*p == 0) [[unlikely]] {
965
0
                              ctx.error = error_code::invalid_escape;
966
0
                              return;
967
0
                           }
968
0
                           ++p;
969
0
                           ++start;
970
0
                           --n;
971
0
                        }
972
0
                     }
973
974
0
                     value.resize(n);
975
0
                     ++it;
976
0
                  }
977
0
                  else {
978
                     // For large inputs this case of running out of buffer is very rare
979
0
                     value.resize(n);
980
0
                     auto* p = value.data();
981
982
0
                     it = start;
983
0
                     while (it < end) [[likely]] {
984
0
                        if (*it == '"') {
985
0
                           value.resize(size_t(p - value.data()));
986
0
                           ++it;
987
0
                           return;
988
0
                        }
989
990
0
                        *p = *it;
991
992
0
                        if (*it == '\\') {
993
0
                           ++it; // skip the escape
994
0
                           if (*it == 'u') {
995
0
                              ++it;
996
0
                              if (!handle_unicode_code_point(it, p, end)) [[unlikely]] {
997
0
                                 ctx.error = error_code::unicode_escape_conversion_failure;
998
0
                                 return;
999
0
                              }
1000
0
                           }
1001
0
                           else {
1002
0
                              *p = char_unescape_table[uint8_t(*it)];
1003
0
                              if (*p == 0) [[unlikely]] {
1004
0
                                 ctx.error = error_code::invalid_escape;
1005
0
                                 return;
1006
0
                              }
1007
0
                              ++p;
1008
0
                              ++it;
1009
0
                           }
1010
0
                        }
1011
0
                        else {
1012
0
                           ++it;
1013
0
                           ++p;
1014
0
                        }
1015
0
                     }
1016
1017
0
                     ctx.error = error_code::unexpected_end;
1018
0
                  }
1019
0
               }
1020
0
               else {
1021
                  // For short strings
1022
1023
0
                  std::array<char, 8> buffer{};
1024
1025
0
                  auto* p = buffer.data();
1026
1027
0
                  while (it < end) [[likely]] {
1028
0
                     *p = *it;
1029
0
                     if (*it == '"') {
1030
0
                        value.assign(buffer.data(), size_t(p - buffer.data()));
1031
0
                        ++it;
1032
0
                        if constexpr (not Opts.null_terminated) {
1033
0
                           if (it == end) {
1034
0
                              ctx.error = error_code::end_reached;
1035
0
                              return;
1036
0
                           }
1037
0
                        }
1038
0
                        return;
1039
0
                     }
1040
0
                     else if (*it == '\\') {
1041
0
                        ++it; // skip the escape
1042
0
                        if constexpr (not Opts.null_terminated) {
1043
0
                           if (it == end) [[unlikely]] {
1044
0
                              ctx.error = error_code::unexpected_end;
1045
0
                              return;
1046
0
                           }
1047
0
                        }
1048
0
                        if (*it == 'u') {
1049
0
                           ++it;
1050
0
                           if constexpr (not Opts.null_terminated) {
1051
0
                              if (it == end) [[unlikely]] {
1052
0
                                 ctx.error = error_code::unexpected_end;
1053
0
                                 return;
1054
0
                              }
1055
0
                           }
1056
0
                           if (!handle_unicode_code_point(it, p, end)) [[unlikely]] {
1057
0
                              ctx.error = error_code::unicode_escape_conversion_failure;
1058
0
                              return;
1059
0
                           }
1060
0
                        }
1061
0
                        else {
1062
0
                           *p = char_unescape_table[uint8_t(*it)];
1063
0
                           if (*p == 0) [[unlikely]] {
1064
0
                              ctx.error = error_code::invalid_escape;
1065
0
                              return;
1066
0
                           }
1067
0
                           ++p;
1068
0
                           ++it;
1069
0
                        }
1070
0
                     }
1071
0
                     else {
1072
0
                        ++it;
1073
0
                        ++p;
1074
0
                     }
1075
0
                  }
1076
1077
0
                  ctx.error = error_code::unexpected_end;
1078
0
               }
1079
            }
1080
            else {
1081
               // raw_string
1082
               auto start = it;
1083
               skip_string_view<Opts>(ctx, it, end);
1084
               if (bool(ctx.error)) [[unlikely]]
1085
                  return;
1086
1087
               value.assign(start, size_t(it - start));
1088
               ++it;
1089
            }
1090
0
         }
1091
0
      }
Unexecuted instantiation: _ZN3glz4fromILj10ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEE2opITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERPKcSD_S7_TkNS_10is_contextERNS_7contextEQntcl15check_is_paddedTL0__EEEvRT2_OT3_OT0_OT1_
Unexecuted instantiation: _ZN3glz4fromILj10ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEE2opITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERPKcSD_S7_TkNS_10is_contextERNS_7contextEQntcl15check_is_paddedTL0__EEEvRT2_OT3_OT0_OT1_
1092
   };
1093
1094
   template <class T>
1095
      requires(string_view_t<T> || char_array_t<T> || array_char_t<T> || static_string_t<T>)
1096
   struct from<JSON, T>
1097
   {
1098
      template <auto Opts, class It, class End>
1099
      GLZ_ALWAYS_INLINE static void op(auto& value, is_context auto&& ctx, It&& it, End&& end) noexcept
1100
      {
1101
         if constexpr (!check_opening_handled(Opts)) {
1102
            if constexpr (!check_ws_handled(Opts)) {
1103
               if (skip_ws<Opts>(ctx, it, end)) {
1104
                  return;
1105
               }
1106
            }
1107
1108
            if (match_invalid_end<'"', Opts>(ctx, it, end)) {
1109
               return;
1110
            }
1111
         }
1112
1113
         auto start = it;
1114
         skip_string_view<Opts>(ctx, it, end);
1115
         if (bool(ctx.error)) [[unlikely]]
1116
            return;
1117
1118
         if constexpr (string_view_t<T>) {
1119
            value = {start, size_t(it - start)};
1120
         }
1121
         else if constexpr (char_array_t<T>) {
1122
            const size_t n = it - start;
1123
            if ((n + 1) > sizeof(value)) {
1124
               ctx.error = error_code::unexpected_end;
1125
               return;
1126
            }
1127
            std::memcpy(value, start, n);
1128
            value[n] = '\0';
1129
         }
1130
         else if constexpr (array_char_t<T>) {
1131
            const size_t n = it - start;
1132
            if ((n + 1) > value.size()) {
1133
               ctx.error = error_code::unexpected_end;
1134
               return;
1135
            }
1136
            std::memcpy(value.data(), start, n);
1137
            value[n] = '\0';
1138
         }
1139
         else if constexpr (static_string_t<T>) {
1140
            const size_t n = it - start;
1141
            if (n > value.capacity()) {
1142
               ctx.error = error_code::unexpected_end;
1143
               return;
1144
            }
1145
            value.assign(start, n);
1146
         }
1147
         ++it; // skip closing quote
1148
         if constexpr (not Opts.null_terminated) {
1149
            if (it == end) {
1150
               ctx.error = error_code::end_reached;
1151
               return;
1152
            }
1153
         }
1154
      }
1155
   };
1156
1157
   template <char_t T>
1158
   struct from<JSON, T>
1159
   {
1160
      template <auto Opts>
1161
      static void op(auto& value, is_context auto&& ctx, auto&& it, auto&& end) noexcept
1162
      {
1163
         if constexpr (!check_opening_handled(Opts)) {
1164
            if constexpr (!check_ws_handled(Opts)) {
1165
               if (skip_ws<Opts>(ctx, it, end)) {
1166
                  return;
1167
               }
1168
            }
1169
1170
            if (match_invalid_end<'"', Opts>(ctx, it, end)) {
1171
               return;
1172
            }
1173
         }
1174
1175
         if (*it == '\\') [[unlikely]] {
1176
            ++it;
1177
            switch (*it) {
1178
            case '\0': {
1179
               ctx.error = error_code::unexpected_end;
1180
               return;
1181
            }
1182
            case '"':
1183
            case '\\':
1184
            case '/':
1185
               value = *it++;
1186
               break;
1187
            case 'b':
1188
               value = '\b';
1189
               ++it;
1190
               break;
1191
            case 'f':
1192
               value = '\f';
1193
               ++it;
1194
               break;
1195
            case 'n':
1196
               value = '\n';
1197
               ++it;
1198
               break;
1199
            case 'r':
1200
               value = '\r';
1201
               ++it;
1202
               break;
1203
            case 't':
1204
               value = '\t';
1205
               ++it;
1206
               break;
1207
            case 'u': {
1208
               ctx.error = error_code::unicode_escape_conversion_failure;
1209
               return;
1210
            }
1211
            default: {
1212
               ctx.error = error_code::invalid_escape;
1213
               return;
1214
            }
1215
            }
1216
         }
1217
         else {
1218
            if (it == end) [[unlikely]] {
1219
               ctx.error = error_code::unexpected_end;
1220
               return;
1221
            }
1222
            value = *it++;
1223
         }
1224
         if constexpr (not Opts.null_terminated) {
1225
            if (it == end) [[unlikely]] {
1226
               ctx.error = error_code::unexpected_end;
1227
               return;
1228
            }
1229
         }
1230
         if (match<'"'>(ctx, it)) {
1231
            return;
1232
         }
1233
         if constexpr (not Opts.null_terminated) {
1234
            if (it == end) {
1235
               ctx.error = error_code::end_reached;
1236
               return;
1237
            }
1238
         }
1239
      }
1240
   };
1241
1242
   template <class T>
1243
      requires(is_named_enum<T>)
1244
   struct from<JSON, T>
1245
   {
1246
      template <auto Opts>
1247
      static void op(auto& value, is_context auto&& ctx, auto&& it, auto&& end) noexcept
1248
      {
1249
         if constexpr (!check_ws_handled(Opts)) {
1250
            if (skip_ws<Opts>(ctx, it, end)) {
1251
               return;
1252
            }
1253
         }
1254
1255
         constexpr auto N = reflect<T>::size;
1256
1257
         if (*it != '"') [[unlikely]] {
1258
            ctx.error = error_code::expected_quote;
1259
            return;
1260
         }
1261
         ++it;
1262
         if constexpr (not Opts.null_terminated) {
1263
            if (it == end) [[unlikely]] {
1264
               ctx.error = error_code::unexpected_end;
1265
               return;
1266
            }
1267
         }
1268
1269
         if constexpr (N == 1) {
1270
            decode_index<Opts, T, 0>(value, ctx, it, end);
1271
         }
1272
         else {
1273
            static constexpr auto HashInfo = hash_info<T>;
1274
1275
            const auto index = decode_hash<JSON, T, HashInfo, HashInfo.type>::op(it, end);
1276
1277
            if (index >= N) [[unlikely]] {
1278
               ctx.error = error_code::unexpected_enum;
1279
               return;
1280
            }
1281
1282
            visit<N>([&]<size_t I>() { decode_index<Opts, T, I>(value, ctx, it, end); }, index);
1283
         }
1284
      }
1285
   };
1286
1287
   template <class T>
1288
      requires(std::is_enum_v<T> && !glaze_enum_t<T> && !meta_keys<T> && !custom_read<T>)
1289
   struct from<JSON, T>
1290
   {
1291
      template <auto Opts>
1292
      static void op(auto& value, is_context auto&& ctx, auto&& it, auto&& end) noexcept
1293
      {
1294
         // TODO: use std::bit_cast???
1295
         std::underlying_type_t<std::decay_t<T>> x{};
1296
         parse<JSON>::op<Opts>(x, ctx, it, end);
1297
         value = static_cast<std::decay_t<T>>(x);
1298
      }
1299
   };
1300
1301
   template <func_t T>
1302
   struct from<JSON, T>
1303
   {
1304
      template <auto Opts>
1305
      static void op(auto& /*value*/, is_context auto&& ctx, auto&& it, auto&& end)
1306
      {
1307
         if constexpr (!check_ws_handled(Opts)) {
1308
            if (skip_ws<Opts>(ctx, it, end)) {
1309
               return;
1310
            }
1311
         }
1312
         if (match_invalid_end<'"', Opts>(ctx, it, end)) {
1313
            return;
1314
         }
1315
         skip_string_view<Opts>(ctx, it, end);
1316
         if (bool(ctx.error)) [[unlikely]]
1317
            return;
1318
         if (match<'"'>(ctx, it)) {
1319
            return;
1320
         }
1321
         if constexpr (not Opts.null_terminated) {
1322
            if (it == end) {
1323
               ctx.error = error_code::end_reached;
1324
               return;
1325
            }
1326
         }
1327
      }
1328
   };
1329
1330
   template <class T>
1331
   struct from<JSON, basic_raw_json<T>>
1332
   {
1333
      template <auto Opts>
1334
      GLZ_ALWAYS_INLINE static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end)
1335
      {
1336
         auto it_start = it;
1337
         if (*it == 'n') {
1338
            match<"null", Opts>(ctx, it, end);
1339
         }
1340
         else if (is_digit(uint8_t(*it))) {
1341
            skip_number<Opts>(ctx, it, end);
1342
         }
1343
         else {
1344
            skip_value<JSON>::op<Opts>(ctx, it, end);
1345
         }
1346
         if (bool(ctx.error)) [[unlikely]]
1347
            return;
1348
         value.str = {it_start, static_cast<size_t>(it - it_start)};
1349
      }
1350
   };
1351
1352
   template <class T>
1353
   struct from<JSON, basic_text<T>>
1354
   {
1355
      template <auto Opts>
1356
      GLZ_ALWAYS_INLINE static void op(auto&& value, is_context auto&&, auto&& it, auto&& end)
1357
      {
1358
         value.str = {it, static_cast<size_t>(end - it)}; // read entire contents as string
1359
         it = end;
1360
      }
1361
   };
1362
1363
   // for set types
1364
   template <class T>
1365
      requires(readable_array_t<T> && !emplace_backable<T> && !resizable<T> && emplaceable<T>)
1366
   struct from<JSON, T>
1367
   {
1368
      template <auto Options>
1369
      static void op(auto& value, is_context auto&& ctx, auto&& it, auto&& end)
1370
      {
1371
         constexpr auto Opts = ws_handled_off<Options>();
1372
         if constexpr (!check_ws_handled(Options)) {
1373
            if (skip_ws<Opts>(ctx, it, end)) {
1374
               return;
1375
            }
1376
         }
1377
1378
         if (match_invalid_end<'[', Opts>(ctx, it, end)) {
1379
            return;
1380
         }
1381
         if constexpr (not Opts.null_terminated) {
1382
            ++ctx.indentation_level;
1383
         }
1384
         if (skip_ws<Opts>(ctx, it, end)) {
1385
            return;
1386
         }
1387
1388
         value.clear();
1389
         if (*it == ']') [[unlikely]] {
1390
            if constexpr (not Opts.null_terminated) {
1391
               --ctx.indentation_level;
1392
            }
1393
            ++it;
1394
            return;
1395
         }
1396
1397
         while (true) {
1398
            using V = range_value_t<T>;
1399
            V v;
1400
            parse<JSON>::op<Opts>(v, ctx, it, end);
1401
            if (bool(ctx.error)) [[unlikely]]
1402
               return;
1403
            value.emplace(std::move(v));
1404
            if (skip_ws<Opts>(ctx, it, end)) {
1405
               return;
1406
            }
1407
            if (*it == ']') {
1408
               if constexpr (not Opts.null_terminated) {
1409
                  --ctx.indentation_level;
1410
               }
1411
               ++it;
1412
               return;
1413
            }
1414
            if (match_invalid_end<',', Opts>(ctx, it, end)) {
1415
               return;
1416
            }
1417
            if (skip_ws<Opts>(ctx, it, end)) {
1418
               return;
1419
            }
1420
         }
1421
      }
1422
   };
1423
1424
   // for types like std::vector, std::array, std::deque, etc.
1425
   template <class T>
1426
      requires(readable_array_t<T> && (emplace_backable<T> || is_inplace_vector<T> || !resizable<T>) && !emplaceable<T>)
1427
   struct from<JSON, T>
1428
   {
1429
      template <auto Options>
1430
      static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end)
1431
17.9k
      {
1432
17.9k
         constexpr auto Opts = ws_handled_off<Options>();
1433
         if constexpr (!check_ws_handled(Options)) {
1434
            if (skip_ws<Opts>(ctx, it, end)) {
1435
               return;
1436
            }
1437
         }
1438
1439
17.9k
         if (match_invalid_end<'[', Opts>(ctx, it, end)) {
1440
50
            return;
1441
50
         }
1442
17.9k
         if constexpr (not Opts.null_terminated) {
1443
8.96k
            ++ctx.indentation_level;
1444
8.96k
         }
1445
1446
17.9k
         const auto ws_start = it;
1447
17.9k
         if (skip_ws<Opts>(ctx, it, end)) {
1448
35
            return;
1449
35
         }
1450
1451
17.9k
         if (*it == ']') {
1452
1.60k
            if constexpr (not Opts.null_terminated) {
1453
804
               --ctx.indentation_level;
1454
804
            }
1455
1.60k
            ++it;
1456
            if constexpr ((resizable<T> || is_inplace_vector<T>) && not Opts.append_arrays) {
1457
               value.clear();
1458
1459
               if constexpr (check_shrink_to_fit(Opts)) {
1460
                  value.shrink_to_fit();
1461
               }
1462
            }
1463
1.60k
            return;
1464
1.60k
         }
1465
1466
16.2k
         const size_t ws_size = size_t(it - ws_start);
1467
1468
16.2k
         static constexpr bool should_append = (resizable<T> || is_inplace_vector<T>) && Opts.append_arrays;
1469
16.2k
         if constexpr (not should_append) {
1470
16.2k
            const auto n = value.size();
1471
1472
16.2k
            auto value_it = value.begin();
1473
1474
33.5k
            for (size_t i = 0; i < n; ++i) {
1475
33.5k
               parse<JSON>::op<ws_handled<Opts>()>(*value_it++, ctx, it, end);
1476
33.5k
               if (bool(ctx.error)) [[unlikely]]
1477
882
                  return;
1478
32.6k
               if (skip_ws<Opts>(ctx, it, end)) {
1479
16
                  return;
1480
16
               }
1481
32.6k
               if (*it == ',') {
1482
17.3k
                  ++it;
1483
1484
17.3k
                  if constexpr (!Opts.minified) {
1485
17.3k
                     if (ws_size && ws_size < size_t(end - it)) {
1486
5.81k
                        skip_matching_ws(ws_start, it, ws_size);
1487
5.81k
                     }
1488
17.3k
                  }
1489
1490
17.3k
                  if (skip_ws<Opts>(ctx, it, end)) {
1491
53
                     return;
1492
53
                  }
1493
17.3k
               }
1494
15.2k
               else if (*it == ']') {
1495
14.7k
                  if constexpr (not Opts.null_terminated) {
1496
7.39k
                     --ctx.indentation_level;
1497
7.39k
                  }
1498
14.7k
                  ++it;
1499
                  if constexpr (erasable<T>) {
1500
                     value.erase(value_it,
1501
                                 value.end()); // use erase rather than resize for non-default constructible elements
1502
1503
                     if constexpr (check_shrink_to_fit(Opts)) {
1504
                        value.shrink_to_fit();
1505
                     }
1506
                  }
1507
14.7k
                  return;
1508
14.7k
               }
1509
489
               else [[unlikely]] {
1510
489
                  ctx.error = error_code::expected_bracket;
1511
489
                  return;
1512
489
               }
1513
32.6k
            }
1514
16.2k
         }
1515
1516
         if constexpr (Opts.partial_read) {
1517
            return;
1518
         }
1519
16.2k
         else {
1520
            // growing
1521
            if constexpr (emplace_backable<T> || has_try_emplace_back<T>) {
1522
               while (it < end) {
1523
                  if constexpr (has_try_emplace_back<T>) {
1524
                     if (value.try_emplace_back() != nullptr)
1525
                        parse<JSON>::op<ws_handled<Opts>()>(value.back(), ctx, it, end);
1526
                     else
1527
                        ctx.error = error_code::exceeded_static_array_size;
1528
                  }
1529
                  else {
1530
                     parse<JSON>::op<ws_handled<Opts>()>(value.emplace_back(), ctx, it, end);
1531
                  }
1532
1533
                  if (bool(ctx.error)) [[unlikely]]
1534
                     return;
1535
                  if (skip_ws<Opts>(ctx, it, end)) {
1536
                     return;
1537
                  }
1538
                  if (*it == ',') [[likely]] {
1539
                     ++it;
1540
1541
                     if constexpr (!Opts.minified) {
1542
                        if (ws_size && ws_size < size_t(end - it)) {
1543
                           skip_matching_ws(ws_start, it, ws_size);
1544
                        }
1545
                     }
1546
1547
                     if (skip_ws<Opts>(ctx, it, end)) {
1548
                        return;
1549
                     }
1550
                  }
1551
                  else if (*it == ']') {
1552
                     if constexpr (not Opts.null_terminated) {
1553
                        --ctx.indentation_level;
1554
                     }
1555
                     ++it;
1556
                     return;
1557
                  }
1558
                  else [[unlikely]] {
1559
                     ctx.error = error_code::expected_bracket;
1560
                     return;
1561
                  }
1562
               }
1563
            }
1564
16.2k
            else {
1565
16.2k
               ctx.error = error_code::exceeded_static_array_size;
1566
16.2k
            }
1567
16.2k
         }
1568
16.2k
      }
_ZN3glz4fromILj10ENSt3__15arrayImLm3EEEE2opITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERS3_TkNS_10is_contextERNS_7contextERPKcSC_EEvOT0_OT1_OT2_OT3_
Line
Count
Source
1431
8.98k
      {
1432
8.98k
         constexpr auto Opts = ws_handled_off<Options>();
1433
         if constexpr (!check_ws_handled(Options)) {
1434
            if (skip_ws<Opts>(ctx, it, end)) {
1435
               return;
1436
            }
1437
         }
1438
1439
8.98k
         if (match_invalid_end<'[', Opts>(ctx, it, end)) {
1440
17
            return;
1441
17
         }
1442
8.96k
         if constexpr (not Opts.null_terminated) {
1443
8.96k
            ++ctx.indentation_level;
1444
8.96k
         }
1445
1446
8.96k
         const auto ws_start = it;
1447
8.96k
         if (skip_ws<Opts>(ctx, it, end)) {
1448
35
            return;
1449
35
         }
1450
1451
8.92k
         if (*it == ']') {
1452
804
            if constexpr (not Opts.null_terminated) {
1453
804
               --ctx.indentation_level;
1454
804
            }
1455
804
            ++it;
1456
            if constexpr ((resizable<T> || is_inplace_vector<T>) && not Opts.append_arrays) {
1457
               value.clear();
1458
1459
               if constexpr (check_shrink_to_fit(Opts)) {
1460
                  value.shrink_to_fit();
1461
               }
1462
            }
1463
804
            return;
1464
804
         }
1465
1466
8.12k
         const size_t ws_size = size_t(it - ws_start);
1467
1468
8.12k
         static constexpr bool should_append = (resizable<T> || is_inplace_vector<T>) && Opts.append_arrays;
1469
8.12k
         if constexpr (not should_append) {
1470
8.12k
            const auto n = value.size();
1471
1472
8.12k
            auto value_it = value.begin();
1473
1474
16.7k
            for (size_t i = 0; i < n; ++i) {
1475
16.7k
               parse<JSON>::op<ws_handled<Opts>()>(*value_it++, ctx, it, end);
1476
16.7k
               if (bool(ctx.error)) [[unlikely]]
1477
498
                  return;
1478
16.2k
               if (skip_ws<Opts>(ctx, it, end)) {
1479
16
                  return;
1480
16
               }
1481
16.2k
               if (*it == ',') {
1482
8.66k
                  ++it;
1483
1484
8.66k
                  if constexpr (!Opts.minified) {
1485
8.66k
                     if (ws_size && ws_size < size_t(end - it)) {
1486
2.90k
                        skip_matching_ws(ws_start, it, ws_size);
1487
2.90k
                     }
1488
8.66k
                  }
1489
1490
8.66k
                  if (skip_ws<Opts>(ctx, it, end)) {
1491
53
                     return;
1492
53
                  }
1493
8.66k
               }
1494
7.53k
               else if (*it == ']') {
1495
7.39k
                  if constexpr (not Opts.null_terminated) {
1496
7.39k
                     --ctx.indentation_level;
1497
7.39k
                  }
1498
7.39k
                  ++it;
1499
                  if constexpr (erasable<T>) {
1500
                     value.erase(value_it,
1501
                                 value.end()); // use erase rather than resize for non-default constructible elements
1502
1503
                     if constexpr (check_shrink_to_fit(Opts)) {
1504
                        value.shrink_to_fit();
1505
                     }
1506
                  }
1507
7.39k
                  return;
1508
7.39k
               }
1509
135
               else [[unlikely]] {
1510
135
                  ctx.error = error_code::expected_bracket;
1511
135
                  return;
1512
135
               }
1513
16.2k
            }
1514
8.12k
         }
1515
1516
         if constexpr (Opts.partial_read) {
1517
            return;
1518
         }
1519
8.12k
         else {
1520
            // growing
1521
            if constexpr (emplace_backable<T> || has_try_emplace_back<T>) {
1522
               while (it < end) {
1523
                  if constexpr (has_try_emplace_back<T>) {
1524
                     if (value.try_emplace_back() != nullptr)
1525
                        parse<JSON>::op<ws_handled<Opts>()>(value.back(), ctx, it, end);
1526
                     else
1527
                        ctx.error = error_code::exceeded_static_array_size;
1528
                  }
1529
                  else {
1530
                     parse<JSON>::op<ws_handled<Opts>()>(value.emplace_back(), ctx, it, end);
1531
                  }
1532
1533
                  if (bool(ctx.error)) [[unlikely]]
1534
                     return;
1535
                  if (skip_ws<Opts>(ctx, it, end)) {
1536
                     return;
1537
                  }
1538
                  if (*it == ',') [[likely]] {
1539
                     ++it;
1540
1541
                     if constexpr (!Opts.minified) {
1542
                        if (ws_size && ws_size < size_t(end - it)) {
1543
                           skip_matching_ws(ws_start, it, ws_size);
1544
                        }
1545
                     }
1546
1547
                     if (skip_ws<Opts>(ctx, it, end)) {
1548
                        return;
1549
                     }
1550
                  }
1551
                  else if (*it == ']') {
1552
                     if constexpr (not Opts.null_terminated) {
1553
                        --ctx.indentation_level;
1554
                     }
1555
                     ++it;
1556
                     return;
1557
                  }
1558
                  else [[unlikely]] {
1559
                     ctx.error = error_code::expected_bracket;
1560
                     return;
1561
                  }
1562
               }
1563
            }
1564
8.12k
            else {
1565
8.12k
               ctx.error = error_code::exceeded_static_array_size;
1566
8.12k
            }
1567
8.12k
         }
1568
8.12k
      }
_ZN3glz4fromILj10ENSt3__15arrayImLm3EEEE2opITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELb0ELj4EEERS3_TkNS_10is_contextERNS_7contextERPKcSC_EEvOT0_OT1_OT2_OT3_
Line
Count
Source
1431
9.00k
      {
1432
9.00k
         constexpr auto Opts = ws_handled_off<Options>();
1433
         if constexpr (!check_ws_handled(Options)) {
1434
            if (skip_ws<Opts>(ctx, it, end)) {
1435
               return;
1436
            }
1437
         }
1438
1439
9.00k
         if (match_invalid_end<'[', Opts>(ctx, it, end)) {
1440
33
            return;
1441
33
         }
1442
         if constexpr (not Opts.null_terminated) {
1443
            ++ctx.indentation_level;
1444
         }
1445
1446
8.97k
         const auto ws_start = it;
1447
8.97k
         if (skip_ws<Opts>(ctx, it, end)) {
1448
0
            return;
1449
0
         }
1450
1451
8.97k
         if (*it == ']') {
1452
            if constexpr (not Opts.null_terminated) {
1453
               --ctx.indentation_level;
1454
            }
1455
804
            ++it;
1456
            if constexpr ((resizable<T> || is_inplace_vector<T>) && not Opts.append_arrays) {
1457
               value.clear();
1458
1459
               if constexpr (check_shrink_to_fit(Opts)) {
1460
                  value.shrink_to_fit();
1461
               }
1462
            }
1463
804
            return;
1464
804
         }
1465
1466
8.16k
         const size_t ws_size = size_t(it - ws_start);
1467
1468
8.16k
         static constexpr bool should_append = (resizable<T> || is_inplace_vector<T>) && Opts.append_arrays;
1469
8.16k
         if constexpr (not should_append) {
1470
8.16k
            const auto n = value.size();
1471
1472
8.16k
            auto value_it = value.begin();
1473
1474
16.8k
            for (size_t i = 0; i < n; ++i) {
1475
16.8k
               parse<JSON>::op<ws_handled<Opts>()>(*value_it++, ctx, it, end);
1476
16.8k
               if (bool(ctx.error)) [[unlikely]]
1477
384
                  return;
1478
16.4k
               if (skip_ws<Opts>(ctx, it, end)) {
1479
0
                  return;
1480
0
               }
1481
16.4k
               if (*it == ',') {
1482
8.66k
                  ++it;
1483
1484
8.66k
                  if constexpr (!Opts.minified) {
1485
8.66k
                     if (ws_size && ws_size < size_t(end - it)) {
1486
2.90k
                        skip_matching_ws(ws_start, it, ws_size);
1487
2.90k
                     }
1488
8.66k
                  }
1489
1490
8.66k
                  if (skip_ws<Opts>(ctx, it, end)) {
1491
0
                     return;
1492
0
                  }
1493
8.66k
               }
1494
7.75k
               else if (*it == ']') {
1495
                  if constexpr (not Opts.null_terminated) {
1496
                     --ctx.indentation_level;
1497
                  }
1498
7.39k
                  ++it;
1499
                  if constexpr (erasable<T>) {
1500
                     value.erase(value_it,
1501
                                 value.end()); // use erase rather than resize for non-default constructible elements
1502
1503
                     if constexpr (check_shrink_to_fit(Opts)) {
1504
                        value.shrink_to_fit();
1505
                     }
1506
                  }
1507
7.39k
                  return;
1508
7.39k
               }
1509
354
               else [[unlikely]] {
1510
354
                  ctx.error = error_code::expected_bracket;
1511
354
                  return;
1512
354
               }
1513
16.4k
            }
1514
8.16k
         }
1515
1516
         if constexpr (Opts.partial_read) {
1517
            return;
1518
         }
1519
8.16k
         else {
1520
            // growing
1521
            if constexpr (emplace_backable<T> || has_try_emplace_back<T>) {
1522
               while (it < end) {
1523
                  if constexpr (has_try_emplace_back<T>) {
1524
                     if (value.try_emplace_back() != nullptr)
1525
                        parse<JSON>::op<ws_handled<Opts>()>(value.back(), ctx, it, end);
1526
                     else
1527
                        ctx.error = error_code::exceeded_static_array_size;
1528
                  }
1529
                  else {
1530
                     parse<JSON>::op<ws_handled<Opts>()>(value.emplace_back(), ctx, it, end);
1531
                  }
1532
1533
                  if (bool(ctx.error)) [[unlikely]]
1534
                     return;
1535
                  if (skip_ws<Opts>(ctx, it, end)) {
1536
                     return;
1537
                  }
1538
                  if (*it == ',') [[likely]] {
1539
                     ++it;
1540
1541
                     if constexpr (!Opts.minified) {
1542
                        if (ws_size && ws_size < size_t(end - it)) {
1543
                           skip_matching_ws(ws_start, it, ws_size);
1544
                        }
1545
                     }
1546
1547
                     if (skip_ws<Opts>(ctx, it, end)) {
1548
                        return;
1549
                     }
1550
                  }
1551
                  else if (*it == ']') {
1552
                     if constexpr (not Opts.null_terminated) {
1553
                        --ctx.indentation_level;
1554
                     }
1555
                     ++it;
1556
                     return;
1557
                  }
1558
                  else [[unlikely]] {
1559
                     ctx.error = error_code::expected_bracket;
1560
                     return;
1561
                  }
1562
               }
1563
            }
1564
8.16k
            else {
1565
8.16k
               ctx.error = error_code::exceeded_static_array_size;
1566
8.16k
            }
1567
8.16k
         }
1568
8.16k
      }
1569
1570
      // for types like std::vector<std::pair...> that can't look up with operator[]
1571
      // Intead of hashing or linear searching, we just clear the input and overwrite the entire contents
1572
      template <auto Options>
1573
         requires(pair_t<range_value_t<T>> && check_concatenate(Options) == true)
1574
      static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end)
1575
      {
1576
         static constexpr auto Opts = opening_handled_off<ws_handled_off<Options>()>();
1577
         if constexpr (!check_opening_handled(Options)) {
1578
            if constexpr (!check_ws_handled(Options)) {
1579
               if (skip_ws<Opts>(ctx, it, end)) {
1580
                  return;
1581
               }
1582
            }
1583
            if (match_invalid_end<'{', Opts>(ctx, it, end)) {
1584
               return;
1585
            }
1586
            if constexpr (not Opts.null_terminated) {
1587
               if (it == end) [[unlikely]] {
1588
                  ctx.error = error_code::unexpected_end;
1589
                  return;
1590
               }
1591
            }
1592
            if constexpr (not Opts.null_terminated) {
1593
               ++ctx.indentation_level;
1594
            }
1595
         }
1596
1597
         // clear all contents and repopulate
1598
         value.clear();
1599
1600
         while (it < end) {
1601
            if (skip_ws<Opts>(ctx, it, end)) {
1602
               return;
1603
            }
1604
1605
            if (*it == '}') {
1606
               ++it;
1607
               if constexpr (not Opts.null_terminated) {
1608
                  --ctx.indentation_level;
1609
               }
1610
               if constexpr (not Opts.null_terminated) {
1611
                  if (it == end) {
1612
                     ctx.error = error_code::end_reached;
1613
                     return;
1614
                  }
1615
               }
1616
               return;
1617
            }
1618
1619
            if constexpr (has_try_emplace_back<T>) {
1620
               if (value.try_emplace_back() == nullptr) [[unlikely]] {
1621
                  ctx.error = error_code::exceeded_static_array_size;
1622
                  return;
1623
               }
1624
            }
1625
            else {
1626
               value.emplace_back();
1627
            }
1628
            auto& item = value.back();
1629
1630
            using V = std::decay_t<decltype(item)>;
1631
1632
            if constexpr (str_t<typename V::first_type> ||
1633
                          (std::is_enum_v<typename V::first_type> && glaze_t<typename V::first_type>)) {
1634
               parse<JSON>::op<Opts>(item.first, ctx, it, end);
1635
               if (bool(ctx.error)) [[unlikely]]
1636
                  return;
1637
            }
1638
            else {
1639
               std::string_view key;
1640
               parse<JSON>::op<Opts>(key, ctx, it, end);
1641
               if (bool(ctx.error)) [[unlikely]]
1642
                  return;
1643
               if constexpr (Opts.null_terminated) {
1644
                  parse<JSON>::op<Opts>(item.first, ctx, key.data(), key.data() + key.size());
1645
               }
1646
               else {
1647
                  if (size_t(end - it) == key.size()) [[unlikely]] {
1648
                     ctx.error = error_code::unexpected_end;
1649
                     return;
1650
                  }
1651
                  // For the non-null terminated case we just want one more character so that we don't parse
1652
                  // until the end of the buffer and create an end_reached code (unless there is an error).
1653
                  parse<JSON>::op<Opts>(item.first, ctx, key.data(), key.data() + key.size() + 1);
1654
               }
1655
               if (bool(ctx.error)) [[unlikely]]
1656
                  return;
1657
            }
1658
1659
            if (parse_ws_colon<Opts>(ctx, it, end)) {
1660
               return;
1661
            }
1662
1663
            parse<JSON>::op<Opts>(item.second, ctx, it, end);
1664
            if (bool(ctx.error)) [[unlikely]]
1665
               return;
1666
1667
            if (skip_ws<Opts>(ctx, it, end)) {
1668
               return;
1669
            }
1670
1671
            if (*it == ',') {
1672
               ++it;
1673
               if constexpr (not Opts.null_terminated) {
1674
                  if (it == end) [[unlikely]] {
1675
                     ctx.error = error_code::unexpected_end;
1676
                     return;
1677
                  }
1678
               }
1679
            }
1680
         }
1681
1682
         ctx.error = error_code::unexpected_end;
1683
      }
1684
   };
1685
1686
   // counts the number of JSON array elements
1687
   // needed for classes that are resizable, but do not have an emplace_back
1688
   // 'it' is copied so that it does not actually progress the iterator
1689
   // expects the opening brace ([) to have already been consumed
1690
   template <auto Opts>
1691
   [[nodiscard]] size_t number_of_array_elements(is_context auto&& ctx, auto it, auto&& end) noexcept
1692
   {
1693
      skip_ws<Opts>(ctx, it, end);
1694
      if (bool(ctx.error)) [[unlikely]]
1695
         return {};
1696
1697
      if (*it == ']') [[unlikely]] {
1698
         return 0;
1699
      }
1700
      size_t count = 1;
1701
      while (true) {
1702
         switch (*it) {
1703
         case ',': {
1704
            ++count;
1705
            ++it;
1706
            break;
1707
         }
1708
         case '/': {
1709
            skip_comment(ctx, it, end);
1710
            if (bool(ctx.error)) [[unlikely]]
1711
               return {};
1712
            break;
1713
         }
1714
         case '{':
1715
            ++it;
1716
            skip_until_closed<Opts, '{', '}'>(ctx, it, end);
1717
            if (bool(ctx.error)) [[unlikely]]
1718
               return {};
1719
            break;
1720
         case '[':
1721
            ++it;
1722
            skip_until_closed<Opts, '[', ']'>(ctx, it, end);
1723
            if (bool(ctx.error)) [[unlikely]]
1724
               return {};
1725
            break;
1726
         case '"': {
1727
            skip_string<Opts>(ctx, it, end);
1728
            if (bool(ctx.error)) [[unlikely]]
1729
               return {};
1730
            break;
1731
         }
1732
         case ']': {
1733
            return count;
1734
         }
1735
         case '\0': {
1736
            ctx.error = error_code::unexpected_end;
1737
            return {};
1738
         }
1739
         default:
1740
            ++it;
1741
         }
1742
      }
1743
      unreachable();
1744
   }
1745
1746
   // For types like std::forward_list
1747
   template <class T>
1748
      requires readable_array_t<T> && (!emplace_backable<T> && resizable<T>)
1749
   struct from<JSON, T>
1750
   {
1751
      template <auto Options>
1752
      static void op(auto& value, is_context auto&& ctx, auto&& it, auto&& end)
1753
      {
1754
         constexpr auto Opts = ws_handled_off<Options>();
1755
         if constexpr (!check_ws_handled(Options)) {
1756
            if (skip_ws<Opts>(ctx, it, end)) {
1757
               return;
1758
            }
1759
         }
1760
1761
         if (match_invalid_end<'[', Opts>(ctx, it, end)) {
1762
            return;
1763
         }
1764
         if constexpr (not Opts.null_terminated) {
1765
            ++ctx.indentation_level;
1766
         }
1767
         const auto n = number_of_array_elements<Opts>(ctx, it, end);
1768
         if (bool(ctx.error)) [[unlikely]]
1769
            return;
1770
         value.resize(n);
1771
         size_t i = 0;
1772
         for (auto& x : value) {
1773
            parse<JSON>::op<Opts>(x, ctx, it, end);
1774
            if (bool(ctx.error)) [[unlikely]]
1775
               return;
1776
1777
            if (skip_ws<Opts>(ctx, it, end)) {
1778
               return;
1779
            }
1780
            if (i < n - 1) {
1781
               if (match_invalid_end<',', Opts>(ctx, it, end)) {
1782
                  return;
1783
               }
1784
            }
1785
            ++i;
1786
         }
1787
         match<']'>(ctx, it);
1788
         if constexpr (not Opts.null_terminated) {
1789
            --ctx.indentation_level;
1790
         }
1791
      }
1792
   };
1793
1794
   template <class T>
1795
      requires glaze_array_t<T> || tuple_t<T> || is_std_tuple<T>
1796
   struct from<JSON, T>
1797
   {
1798
      template <auto Opts>
1799
      static void op(auto& value, is_context auto&& ctx, auto&& it, auto&& end)
1800
      {
1801
         static constexpr auto N = []() constexpr {
1802
            if constexpr (glaze_array_t<T>) {
1803
               return reflect<T>::size;
1804
            }
1805
            else {
1806
               return glz::tuple_size_v<T>;
1807
            }
1808
         }();
1809
1810
         if constexpr (!check_ws_handled(Opts)) {
1811
            if (skip_ws<Opts>(ctx, it, end)) {
1812
               return;
1813
            }
1814
         }
1815
1816
         if (match_invalid_end<'[', Opts>(ctx, it, end)) {
1817
            return;
1818
         }
1819
         if constexpr (not Opts.null_terminated) {
1820
            ++ctx.indentation_level;
1821
         }
1822
         if (skip_ws<Opts>(ctx, it, end)) {
1823
            return;
1824
         }
1825
1826
         for_each<N>([&]<size_t I>() {
1827
            if (bool(ctx.error)) [[unlikely]]
1828
               return;
1829
1830
            if (*it == ']') {
1831
               if constexpr (not Opts.null_terminated) {
1832
                  --ctx.indentation_level;
1833
               }
1834
               return;
1835
            }
1836
            if constexpr (I != 0) {
1837
               if (match_invalid_end<',', Opts>(ctx, it, end)) {
1838
                  return;
1839
               }
1840
               if (skip_ws<Opts>(ctx, it, end)) {
1841
                  return;
1842
               }
1843
            }
1844
            if constexpr (is_std_tuple<T>) {
1845
               parse<JSON>::op<ws_handled<Opts>()>(std::get<I>(value), ctx, it, end);
1846
               if (bool(ctx.error)) [[unlikely]]
1847
                  return;
1848
            }
1849
            else if constexpr (glaze_array_t<T>) {
1850
               parse<JSON>::op<ws_handled<Opts>()>(get_member(value, glz::get<I>(meta_v<T>)), ctx, it, end);
1851
               if (bool(ctx.error)) [[unlikely]]
1852
                  return;
1853
            }
1854
            else {
1855
               parse<JSON>::op<ws_handled<Opts>()>(glz::get<I>(value), ctx, it, end);
1856
               if (bool(ctx.error)) [[unlikely]]
1857
                  return;
1858
            }
1859
            if (skip_ws<Opts>(ctx, it, end)) {
1860
               return;
1861
            }
1862
         });
1863
1864
         if constexpr (Opts.partial_read) {
1865
            return;
1866
         }
1867
         else {
1868
            if (bool(ctx.error)) [[unlikely]]
1869
               return;
1870
            match<']'>(ctx, it);
1871
            if constexpr (not Opts.null_terminated) {
1872
               --ctx.indentation_level;
1873
            }
1874
            if constexpr (not Opts.null_terminated) {
1875
               if (it == end) {
1876
                  ctx.error = error_code::end_reached;
1877
                  return;
1878
               }
1879
            }
1880
         }
1881
      }
1882
   };
1883
1884
   template <glaze_flags_t T>
1885
   struct from<JSON, T>
1886
   {
1887
      template <auto Opts>
1888
      static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end)
1889
      {
1890
         if constexpr (!check_ws_handled(Opts)) {
1891
            if (skip_ws<Opts>(ctx, it, end)) {
1892
               return;
1893
            }
1894
         }
1895
1896
         if (match_invalid_end<'[', Opts>(ctx, it, end)) {
1897
            return;
1898
         }
1899
         if constexpr (not Opts.null_terminated) {
1900
            ++ctx.indentation_level;
1901
         }
1902
1903
         std::string& s = string_buffer();
1904
1905
         constexpr auto& HashInfo = hash_info<T>;
1906
         static_assert(bool(HashInfo.type));
1907
1908
         while (true) {
1909
            parse<JSON>::op<ws_handled_off<Opts>()>(s, ctx, it, end);
1910
            if (bool(ctx.error)) [[unlikely]]
1911
               return;
1912
1913
            const auto index =
1914
               decode_hash_with_size<JSON, T, HashInfo, HashInfo.type>::op(s.data(), s.data() + s.size(), s.size());
1915
1916
            constexpr auto N = reflect<T>::size;
1917
            if (index < N) [[likely]] {
1918
               visit<N>([&]<size_t I>() { get_member(value, get<I>(reflect<T>::values)) = true; }, index);
1919
            }
1920
            else [[unlikely]] {
1921
               ctx.error = error_code::invalid_flag_input;
1922
               return;
1923
            }
1924
1925
            if (skip_ws<Opts>(ctx, it, end)) {
1926
               return;
1927
            }
1928
            if (*it == ']') {
1929
               if constexpr (not Opts.null_terminated) {
1930
                  --ctx.indentation_level;
1931
               }
1932
               ++it;
1933
               if constexpr (not Opts.null_terminated) {
1934
                  if (it == end) {
1935
                     ctx.error = error_code::end_reached;
1936
                     return;
1937
                  }
1938
               }
1939
               return;
1940
            }
1941
            if (match_invalid_end<',', Opts>(ctx, it, end)) {
1942
               return;
1943
            }
1944
         }
1945
      }
1946
   };
1947
1948
   template <class T>
1949
   struct from<JSON, includer<T>>
1950
   {
1951
      template <auto Options>
1952
      static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end)
1953
      {
1954
         constexpr auto Opts = ws_handled_off<Options>();
1955
         std::string buffer{};
1956
         parse<JSON>::op<Opts>(buffer, ctx, it, end);
1957
         if (bool(ctx.error)) [[unlikely]]
1958
            return;
1959
1960
         const auto file_path = relativize_if_not_absolute(std::filesystem::path(ctx.current_file).parent_path(),
1961
                                                           std::filesystem::path{buffer});
1962
1963
         const auto string_file_path = file_path.string();
1964
         const auto ec = file_to_buffer(buffer, string_file_path);
1965
1966
         if (bool(ec)) [[unlikely]] {
1967
            ctx.error = error_code::includer_error;
1968
            auto& error_msg = error_buffer();
1969
            error_msg = "file failed to open: " + string_file_path;
1970
            ctx.includer_error = error_msg;
1971
            return;
1972
         }
1973
1974
         const auto current_file = ctx.current_file;
1975
         ctx.current_file = string_file_path;
1976
1977
         // We need to allocate a new buffer here because we could call another includer that uses the buffer
1978
         std::string nested_buffer = buffer;
1979
         static constexpr auto NestedOpts = opt_true<disable_padding_on<Opts>(), &opts::null_terminated>;
1980
         const auto ecode = glz::read<NestedOpts>(value.value, nested_buffer, ctx);
1981
         if (bool(ctx.error)) [[unlikely]] {
1982
            ctx.error = error_code::includer_error;
1983
            auto& error_msg = error_buffer();
1984
            error_msg = glz::format_error(ecode, nested_buffer);
1985
            ctx.includer_error = error_msg;
1986
            return;
1987
         }
1988
1989
         ctx.current_file = current_file;
1990
      }
1991
   };
1992
1993
   template <pair_t T>
1994
   struct from<JSON, T>
1995
   {
1996
      template <auto Options, string_literal tag = "">
1997
      static void op(T& value, is_context auto&& ctx, auto&& it, auto&& end)
1998
      {
1999
         constexpr auto Opts = opening_handled_off<ws_handled_off<Options>()>();
2000
         if constexpr (!check_opening_handled(Options)) {
2001
            if constexpr (!check_ws_handled(Options)) {
2002
               if (skip_ws<Opts>(ctx, it, end)) {
2003
                  return;
2004
               }
2005
            }
2006
            if (match_invalid_end<'{', Opts>(ctx, it, end)) {
2007
               return;
2008
            }
2009
            if constexpr (not Opts.null_terminated) {
2010
               ++ctx.indentation_level;
2011
            }
2012
         }
2013
         if (skip_ws<Opts>(ctx, it, end)) {
2014
            return;
2015
         }
2016
2017
         if (*it == '}') {
2018
            if constexpr (not Opts.null_terminated) {
2019
               --ctx.indentation_level;
2020
            }
2021
            if constexpr (Opts.error_on_missing_keys) {
2022
               ctx.error = error_code::missing_key;
2023
            }
2024
            return;
2025
         }
2026
2027
         using first_type = typename T::first_type;
2028
         if constexpr (str_t<first_type> || is_named_enum<first_type>) {
2029
            parse<JSON>::op<Opts>(value.first, ctx, it, end);
2030
            if (bool(ctx.error)) [[unlikely]]
2031
               return;
2032
         }
2033
         else {
2034
            std::string_view key;
2035
            parse<JSON>::op<Opts>(key, ctx, it, end);
2036
            if (bool(ctx.error)) [[unlikely]]
2037
               return;
2038
            if constexpr (Opts.null_terminated) {
2039
               parse<JSON>::op<Opts>(value.first, ctx, key.data(), key.data() + key.size());
2040
            }
2041
            else {
2042
               if (size_t(end - it) == key.size()) [[unlikely]] {
2043
                  ctx.error = error_code::unexpected_end;
2044
                  return;
2045
               }
2046
               // For the non-null terminated case we just want one more character so that we don't parse
2047
               // until the end of the buffer and create an end_reached code (unless there is an error).
2048
               parse<JSON>::op<Opts>(value.first, ctx, key.data(), key.data() + key.size() + 1);
2049
            }
2050
            if (bool(ctx.error)) [[unlikely]]
2051
               return;
2052
         }
2053
2054
         if (parse_ws_colon<Opts>(ctx, it, end)) {
2055
            return;
2056
         }
2057
2058
         parse<JSON>::op<Opts>(value.second, ctx, it, end);
2059
         if (bool(ctx.error)) [[unlikely]]
2060
            return;
2061
2062
         if (skip_ws<Opts>(ctx, it, end)) {
2063
            return;
2064
         }
2065
2066
         match<'}'>(ctx, it);
2067
         if constexpr (not Opts.null_terminated) {
2068
            --ctx.indentation_level;
2069
         }
2070
         if constexpr (not Opts.null_terminated) {
2071
            if (it == end) {
2072
               ctx.error = error_code::end_reached;
2073
               return;
2074
            }
2075
         }
2076
      }
2077
   };
2078
2079
   template <class T, string_literal Tag>
2080
   inline consteval bool contains_tag()
2081
   {
2082
      auto& keys = reflect<T>::keys;
2083
      for (size_t i = 0; i < keys.size(); ++i) {
2084
         if (Tag.sv() == keys[i]) {
2085
            return true;
2086
         }
2087
      }
2088
      return false;
2089
   }
2090
2091
   template <class T>
2092
      requires((readable_map_t<T> || glaze_object_t<T> || reflectable<T>) && not custom_read<T>)
2093
   struct from<JSON, T>
2094
   {
2095
      template <auto Options, string_literal tag = "">
2096
      static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end)
2097
9.14k
      {
2098
9.14k
         static constexpr auto num_members = reflect<T>::size;
2099
2100
9.14k
         static constexpr auto Opts = opening_handled_off<ws_handled_off<Options>()>();
2101
9.14k
         if constexpr (!check_opening_handled(Options)) {
2102
9.14k
            if constexpr (!check_ws_handled(Options)) {
2103
9.14k
               if (skip_ws<Opts>(ctx, it, end)) {
2104
13
                  return;
2105
13
               }
2106
9.14k
            }
2107
9.14k
            if (match_invalid_end<'{', Opts>(ctx, it, end)) {
2108
51
               return;
2109
51
            }
2110
9.09k
            if constexpr (not Opts.null_terminated) {
2111
4.55k
               if (it == end) [[unlikely]] {
2112
0
                  ctx.error = error_code::unexpected_end;
2113
0
                  return;
2114
0
               }
2115
4.55k
            }
2116
4.55k
            if constexpr (not Opts.null_terminated) {
2117
4.55k
               ++ctx.indentation_level;
2118
4.55k
            }
2119
9.09k
         }
2120
4.54k
         const auto ws_start = it;
2121
9.14k
         if (skip_ws<Opts>(ctx, it, end)) {
2122
24
            return;
2123
24
         }
2124
9.12k
         const size_t ws_size = size_t(it - ws_start);
2125
2126
         if constexpr ((glaze_object_t<T> || reflectable<T>) && num_members == 0 && Opts.error_on_unknown_keys) {
2127
            if constexpr (not tag.sv().empty()) {
2128
               if (*it == '"') {
2129
                  ++it;
2130
                  if constexpr (not Opts.null_terminated) {
2131
                     if (it == end) [[unlikely]] {
2132
                        ctx.error = error_code::unexpected_end;
2133
                        return;
2134
                     }
2135
                  }
2136
2137
                  const auto start = it;
2138
                  skip_string_view<Opts>(ctx, it, end);
2139
                  if (bool(ctx.error)) [[unlikely]]
2140
                     return;
2141
                  const sv key{start, size_t(it - start)};
2142
                  ++it;
2143
                  if constexpr (not Opts.null_terminated) {
2144
                     if (it == end) [[unlikely]] {
2145
                        ctx.error = error_code::unexpected_end;
2146
                        return;
2147
                     }
2148
                  }
2149
2150
                  if (key == tag.sv()) {
2151
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2152
                        return;
2153
                     }
2154
2155
                     parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
2156
                     if (bool(ctx.error)) [[unlikely]]
2157
                        return;
2158
2159
                     if (skip_ws<Opts>(ctx, it, end)) {
2160
                        return;
2161
                     }
2162
                  }
2163
                  else {
2164
                     ctx.error = error_code::unknown_key;
2165
                     return;
2166
                  }
2167
               }
2168
            }
2169
2170
            if (*it == '}') [[likely]] {
2171
               if constexpr (not Opts.null_terminated) {
2172
                  --ctx.indentation_level;
2173
               }
2174
               ++it;
2175
               if constexpr (not Opts.null_terminated) {
2176
                  if (it == end) {
2177
                     ctx.error = error_code::end_reached;
2178
                     return;
2179
                  }
2180
               }
2181
               if constexpr (Opts.partial_read) {
2182
                  ctx.error = error_code::partial_read_complete;
2183
               }
2184
               return;
2185
            }
2186
            ctx.error = error_code::unknown_key;
2187
            return;
2188
         }
2189
9.12k
         else {
2190
9.12k
            decltype(auto) fields = [&]() -> decltype(auto) {
2191
               if constexpr ((glaze_object_t<T> || reflectable<T>) &&
2192
                             (Opts.error_on_missing_keys || Opts.partial_read)) {
2193
                  return bit_array<num_members>{};
2194
               }
2195
9.06k
               else {
2196
9.06k
                  return nullptr;
2197
9.06k
               }
2198
9.06k
            }();
_ZZN3glz4fromILj10E9my_structE2opITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEETnNS_14string_literalEXtlNS5_ILm1EEEEERS1_TkNS_10is_contextERNS_7contextERPKcSC_EEvOT1_OT2_OT3_OT4_ENKUlvE_clEv
Line
Count
Source
2190
4.51k
            decltype(auto) fields = [&]() -> decltype(auto) {
2191
               if constexpr ((glaze_object_t<T> || reflectable<T>) &&
2192
                             (Opts.error_on_missing_keys || Opts.partial_read)) {
2193
                  return bit_array<num_members>{};
2194
               }
2195
4.51k
               else {
2196
4.51k
                  return nullptr;
2197
4.51k
               }
2198
4.51k
            }();
_ZZN3glz4fromILj10E9my_structE2opITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEETnNS_14string_literalEXtlNS5_ILm1EEEEERS1_TkNS_10is_contextERNS_7contextERPKcSC_EEvOT1_OT2_OT3_OT4_ENKUlvE_clEv
Line
Count
Source
2190
4.54k
            decltype(auto) fields = [&]() -> decltype(auto) {
2191
               if constexpr ((glaze_object_t<T> || reflectable<T>) &&
2192
                             (Opts.error_on_missing_keys || Opts.partial_read)) {
2193
                  return bit_array<num_members>{};
2194
               }
2195
4.54k
               else {
2196
4.54k
                  return nullptr;
2197
4.54k
               }
2198
4.54k
            }();
2199
2200
9.12k
            size_t read_count{}; // for partial_read
2201
2202
9.12k
            bool first = true;
2203
74.5k
            while (true) {
2204
               if constexpr ((glaze_object_t<T> || reflectable<T>) && Opts.partial_read) {
2205
                  static constexpr bit_array<num_members> all_fields = [] {
2206
                     bit_array<num_members> arr{};
2207
                     for (size_t i = 0; i < num_members; ++i) {
2208
                        arr[i] = true;
2209
                     }
2210
                     return arr;
2211
                  }();
2212
2213
                  if ((all_fields & fields) == all_fields) {
2214
                     ctx.error = error_code::partial_read_complete;
2215
                     return;
2216
                  }
2217
               }
2218
2219
68.5k
               if (*it == '}') {
2220
6
                  if constexpr (not Opts.null_terminated) {
2221
3
                     --ctx.indentation_level;
2222
3
                  }
2223
                  if constexpr ((glaze_object_t<T> || reflectable<T>) &&
2224
                                (Opts.partial_read && Opts.error_on_missing_keys)) {
2225
                     ctx.error = error_code::missing_key;
2226
                     return;
2227
                  }
2228
6
                  else {
2229
                     if constexpr ((glaze_object_t<T> || reflectable<T>) && Opts.error_on_missing_keys) {
2230
                        constexpr auto req_fields = required_fields<T, Opts>();
2231
                        if ((req_fields & fields) != req_fields) {
2232
                           for (size_t i = 0; i < num_members; ++i) {
2233
                              if (not fields[i]) {
2234
                                 ctx.custom_error_message = reflect<T>::keys[i];
2235
                                 // We just return the first missing key in order to avoid heap allocations
2236
                                 break;
2237
                              }
2238
                           }
2239
2240
                           ctx.error = error_code::missing_key;
2241
                           return;
2242
                        }
2243
                     }
2244
6
                     ++it; // Increment after checking for mising keys so errors are within buffer bounds
2245
6
                     if constexpr (not Opts.null_terminated) {
2246
3
                        if (it == end) {
2247
2
                           ctx.error = error_code::end_reached;
2248
2
                           return;
2249
2
                        }
2250
3
                     }
2251
6
                  }
2252
1
                  return;
2253
6
               }
2254
68.5k
               else if (first) {
2255
9.05k
                  first = false;
2256
9.05k
               }
2257
59.4k
               else {
2258
59.4k
                  if (match_invalid_end<',', Opts>(ctx, it, end)) {
2259
2.99k
                     return;
2260
2.99k
                  }
2261
56.4k
                  if constexpr (not Opts.null_terminated) {
2262
28.2k
                     if (it == end) [[unlikely]] {
2263
0
                        ctx.error = error_code::unexpected_end;
2264
0
                        return;
2265
0
                     }
2266
28.2k
                  }
2267
2268
56.4k
                  if constexpr ((not Opts.minified) && (num_members > 1 || not Opts.error_on_unknown_keys)) {
2269
56.4k
                     if (ws_size && ws_size < size_t(end - it)) {
2270
12.2k
                        skip_matching_ws(ws_start, it, ws_size);
2271
12.2k
                     }
2272
56.4k
                  }
2273
2274
56.4k
                  if (skip_ws<Opts>(ctx, it, end)) {
2275
24
                     return;
2276
24
                  }
2277
56.4k
               }
2278
2279
65.4k
               constexpr auto reflection_type = glaze_object_t<T> || reflectable<T>;
2280
2281
               if constexpr (reflection_type && (num_members == 0)) {
2282
                  if constexpr (Opts.error_on_unknown_keys) {
2283
                     static_assert(false_v<T>, "This should be unreachable");
2284
                  }
2285
                  else {
2286
                     if (match_invalid_end<'"', Opts>(ctx, it, end)) {
2287
                        return;
2288
                     }
2289
2290
                     // parsing to an empty object, but at this point the JSON presents keys
2291
2292
                     // Unknown key handler does not unescape keys. Unknown escaped keys are
2293
                     // handled by the user.
2294
2295
                     const auto start = it;
2296
                     skip_string_view<Opts>(ctx, it, end);
2297
                     if (bool(ctx.error)) [[unlikely]]
2298
                        return;
2299
                     const sv key{start, size_t(it - start)};
2300
                     ++it;
2301
                     if constexpr (not Opts.null_terminated) {
2302
                        if (it == end) [[unlikely]] {
2303
                           ctx.error = error_code::unexpected_end;
2304
                           return;
2305
                        }
2306
                     }
2307
2308
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2309
                        return;
2310
                     }
2311
2312
                     parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
2313
                     if (bool(ctx.error)) [[unlikely]]
2314
                        return;
2315
                     if constexpr (not Opts.null_terminated) {
2316
                        if (it == end) [[unlikely]] {
2317
                           ctx.error = error_code::unexpected_end;
2318
                           return;
2319
                        }
2320
                     }
2321
                  }
2322
               }
2323
65.4k
               else if constexpr (reflection_type) {
2324
65.4k
                  static_assert(bool(hash_info<T>.type));
2325
2326
65.4k
                  if (*it != '"') [[unlikely]] {
2327
496
                     ctx.error = error_code::expected_quote;
2328
496
                     return;
2329
496
                  }
2330
64.9k
                  ++it;
2331
64.9k
                  if constexpr (not Opts.null_terminated) {
2332
32.4k
                     if (it == end) [[unlikely]] {
2333
24
                        ctx.error = error_code::unexpected_end;
2334
24
                        return;
2335
24
                     }
2336
32.4k
                  }
2337
2338
                  if constexpr (not tag.sv().empty() && not contains_tag<T, tag>()) {
2339
                     // For tagged variants we first check to see if the key matches the tag
2340
                     // We only need to do this if the tag is not part of the keys
2341
2342
                     const auto start = it;
2343
                     skip_string_view<Opts>(ctx, it, end);
2344
                     if (bool(ctx.error)) [[unlikely]]
2345
                        return;
2346
                     const sv key{start, size_t(it - start)};
2347
                     ++it;
2348
                     if constexpr (not Opts.null_terminated) {
2349
                        if (it == end) [[unlikely]] {
2350
                           ctx.error = error_code::unexpected_end;
2351
                           return;
2352
                        }
2353
                     }
2354
2355
                     if (key == tag.sv()) {
2356
                        if (parse_ws_colon<Opts>(ctx, it, end)) {
2357
                           return;
2358
                        }
2359
2360
                        parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
2361
                        if (bool(ctx.error)) [[unlikely]]
2362
                           return;
2363
2364
                        if (skip_ws<Opts>(ctx, it, end)) {
2365
                           return;
2366
                        }
2367
                        continue;
2368
                     }
2369
                     else {
2370
                        it = start; // reset the iterator
2371
                     }
2372
                  }
2373
2374
                  if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
2375
                     size_t index = num_members;
2376
                     parse_and_invoke<Opts, T, hash_info<T>>(value, ctx, it, end, index);
2377
                     if (bool(ctx.error)) [[unlikely]]
2378
                        return;
2379
                     if (index < num_members) {
2380
                        fields[index] = true;
2381
                     }
2382
                  }
2383
64.9k
                  else {
2384
64.9k
                     parse_and_invoke<Opts, T, hash_info<T>>(value, ctx, it, end);
2385
64.9k
                     if (bool(ctx.error)) [[unlikely]]
2386
5.45k
                        return;
2387
64.9k
                  }
2388
               }
2389
               else {
2390
                  // For types like std::map, std::unordered_map
2391
2392
                  auto reading = [&](auto&& key) {
2393
                     if constexpr (Opts.partial_read) {
2394
                        if (auto element = value.find(key); element != value.end()) {
2395
                           ++read_count;
2396
                           parse<JSON>::op<ws_handled<Opts>()>(element->second, ctx, it, end);
2397
                        }
2398
                        else {
2399
                           skip_value<JSON>::op<Opts>(ctx, it, end);
2400
                        }
2401
                     }
2402
                     else {
2403
                        parse<JSON>::op<ws_handled<Opts>()>(value[key], ctx, it, end);
2404
                     }
2405
                  };
2406
2407
                  // using Key = std::conditional_t<heterogeneous_map<T>, sv, typename T::key_type>;
2408
                  using Key = typename T::key_type;
2409
                  if constexpr (std::is_same_v<Key, std::string>) {
2410
                     static thread_local Key key;
2411
                     parse<JSON>::op<Opts>(key, ctx, it, end);
2412
                     if (bool(ctx.error)) [[unlikely]]
2413
                        return;
2414
2415
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2416
                        return;
2417
                     }
2418
2419
                     reading(key);
2420
                     if constexpr (Opts.partial_read) {
2421
                        if (read_count == value.size()) {
2422
                           return;
2423
                        }
2424
                     }
2425
                     if (bool(ctx.error)) [[unlikely]]
2426
                        return;
2427
                  }
2428
                  else if constexpr (str_t<Key>) {
2429
                     Key key;
2430
                     parse<JSON>::op<Opts>(key, ctx, it, end);
2431
                     if (bool(ctx.error)) [[unlikely]]
2432
                        return;
2433
2434
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2435
                        return;
2436
                     }
2437
2438
                     reading(key);
2439
                     if constexpr (Opts.partial_read) {
2440
                        if (read_count == value.size()) {
2441
                           return;
2442
                        }
2443
                     }
2444
                     if (bool(ctx.error)) [[unlikely]]
2445
                        return;
2446
                  }
2447
                  else {
2448
                     Key key_value{};
2449
                     if constexpr (glaze_enum_t<Key>) {
2450
                        parse<JSON>::op<Opts>(key_value, ctx, it, end);
2451
                     }
2452
                     else if constexpr (std::is_arithmetic_v<Key>) {
2453
                        // prefer over quoted_t below to avoid double parsing of quoted_t
2454
                        parse<JSON>::op<opt_true<Opts, &opts::quoted_num>>(key_value, ctx, it, end);
2455
                     }
2456
                     else {
2457
                        parse<JSON>::op<opt_false<Opts, &opts::raw_string>>(quoted_t<Key>{key_value}, ctx, it, end);
2458
                     }
2459
                     if (bool(ctx.error)) [[unlikely]]
2460
                        return;
2461
2462
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2463
                        return;
2464
                     }
2465
2466
                     reading(key_value);
2467
                     if constexpr (Opts.partial_read) {
2468
                        if (read_count == value.size()) {
2469
                           return;
2470
                        }
2471
                     }
2472
                     if (bool(ctx.error)) [[unlikely]]
2473
                        return;
2474
                  }
2475
               }
2476
65.4k
               if (skip_ws<Opts>(ctx, it, end)) {
2477
61
                  return;
2478
61
               }
2479
65.4k
            }
2480
9.12k
         }
2481
9.12k
      }
_ZN3glz4fromILj10E9my_structE2opITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEETnNS_14string_literalEXtlNS5_ILm1EEEEERS1_TkNS_10is_contextERNS_7contextERPKcSC_EEvOT1_OT2_OT3_OT4_
Line
Count
Source
2097
4.57k
      {
2098
4.57k
         static constexpr auto num_members = reflect<T>::size;
2099
2100
4.57k
         static constexpr auto Opts = opening_handled_off<ws_handled_off<Options>()>();
2101
4.57k
         if constexpr (!check_opening_handled(Options)) {
2102
4.57k
            if constexpr (!check_ws_handled(Options)) {
2103
4.57k
               if (skip_ws<Opts>(ctx, it, end)) {
2104
13
                  return;
2105
13
               }
2106
4.57k
            }
2107
4.57k
            if (match_invalid_end<'{', Opts>(ctx, it, end)) {
2108
20
               return;
2109
20
            }
2110
4.55k
            if constexpr (not Opts.null_terminated) {
2111
4.55k
               if (it == end) [[unlikely]] {
2112
0
                  ctx.error = error_code::unexpected_end;
2113
0
                  return;
2114
0
               }
2115
4.55k
            }
2116
4.55k
            if constexpr (not Opts.null_terminated) {
2117
4.55k
               ++ctx.indentation_level;
2118
4.55k
            }
2119
4.55k
         }
2120
0
         const auto ws_start = it;
2121
4.57k
         if (skip_ws<Opts>(ctx, it, end)) {
2122
24
            return;
2123
24
         }
2124
4.55k
         const size_t ws_size = size_t(it - ws_start);
2125
2126
         if constexpr ((glaze_object_t<T> || reflectable<T>) && num_members == 0 && Opts.error_on_unknown_keys) {
2127
            if constexpr (not tag.sv().empty()) {
2128
               if (*it == '"') {
2129
                  ++it;
2130
                  if constexpr (not Opts.null_terminated) {
2131
                     if (it == end) [[unlikely]] {
2132
                        ctx.error = error_code::unexpected_end;
2133
                        return;
2134
                     }
2135
                  }
2136
2137
                  const auto start = it;
2138
                  skip_string_view<Opts>(ctx, it, end);
2139
                  if (bool(ctx.error)) [[unlikely]]
2140
                     return;
2141
                  const sv key{start, size_t(it - start)};
2142
                  ++it;
2143
                  if constexpr (not Opts.null_terminated) {
2144
                     if (it == end) [[unlikely]] {
2145
                        ctx.error = error_code::unexpected_end;
2146
                        return;
2147
                     }
2148
                  }
2149
2150
                  if (key == tag.sv()) {
2151
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2152
                        return;
2153
                     }
2154
2155
                     parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
2156
                     if (bool(ctx.error)) [[unlikely]]
2157
                        return;
2158
2159
                     if (skip_ws<Opts>(ctx, it, end)) {
2160
                        return;
2161
                     }
2162
                  }
2163
                  else {
2164
                     ctx.error = error_code::unknown_key;
2165
                     return;
2166
                  }
2167
               }
2168
            }
2169
2170
            if (*it == '}') [[likely]] {
2171
               if constexpr (not Opts.null_terminated) {
2172
                  --ctx.indentation_level;
2173
               }
2174
               ++it;
2175
               if constexpr (not Opts.null_terminated) {
2176
                  if (it == end) {
2177
                     ctx.error = error_code::end_reached;
2178
                     return;
2179
                  }
2180
               }
2181
               if constexpr (Opts.partial_read) {
2182
                  ctx.error = error_code::partial_read_complete;
2183
               }
2184
               return;
2185
            }
2186
            ctx.error = error_code::unknown_key;
2187
            return;
2188
         }
2189
4.55k
         else {
2190
4.55k
            decltype(auto) fields = [&]() -> decltype(auto) {
2191
4.55k
               if constexpr ((glaze_object_t<T> || reflectable<T>) &&
2192
4.55k
                             (Opts.error_on_missing_keys || Opts.partial_read)) {
2193
4.55k
                  return bit_array<num_members>{};
2194
4.55k
               }
2195
4.55k
               else {
2196
4.55k
                  return nullptr;
2197
4.55k
               }
2198
4.55k
            }();
2199
2200
4.55k
            size_t read_count{}; // for partial_read
2201
2202
4.55k
            bool first = true;
2203
37.1k
            while (true) {
2204
               if constexpr ((glaze_object_t<T> || reflectable<T>) && Opts.partial_read) {
2205
                  static constexpr bit_array<num_members> all_fields = [] {
2206
                     bit_array<num_members> arr{};
2207
                     for (size_t i = 0; i < num_members; ++i) {
2208
                        arr[i] = true;
2209
                     }
2210
                     return arr;
2211
                  }();
2212
2213
                  if ((all_fields & fields) == all_fields) {
2214
                     ctx.error = error_code::partial_read_complete;
2215
                     return;
2216
                  }
2217
               }
2218
2219
33.0k
               if (*it == '}') {
2220
3
                  if constexpr (not Opts.null_terminated) {
2221
3
                     --ctx.indentation_level;
2222
3
                  }
2223
                  if constexpr ((glaze_object_t<T> || reflectable<T>) &&
2224
                                (Opts.partial_read && Opts.error_on_missing_keys)) {
2225
                     ctx.error = error_code::missing_key;
2226
                     return;
2227
                  }
2228
3
                  else {
2229
                     if constexpr ((glaze_object_t<T> || reflectable<T>) && Opts.error_on_missing_keys) {
2230
                        constexpr auto req_fields = required_fields<T, Opts>();
2231
                        if ((req_fields & fields) != req_fields) {
2232
                           for (size_t i = 0; i < num_members; ++i) {
2233
                              if (not fields[i]) {
2234
                                 ctx.custom_error_message = reflect<T>::keys[i];
2235
                                 // We just return the first missing key in order to avoid heap allocations
2236
                                 break;
2237
                              }
2238
                           }
2239
2240
                           ctx.error = error_code::missing_key;
2241
                           return;
2242
                        }
2243
                     }
2244
3
                     ++it; // Increment after checking for mising keys so errors are within buffer bounds
2245
3
                     if constexpr (not Opts.null_terminated) {
2246
3
                        if (it == end) {
2247
2
                           ctx.error = error_code::end_reached;
2248
2
                           return;
2249
2
                        }
2250
3
                     }
2251
3
                  }
2252
1
                  return;
2253
3
               }
2254
33.0k
               else if (first) {
2255
4.51k
                  first = false;
2256
4.51k
               }
2257
28.5k
               else {
2258
28.5k
                  if (match_invalid_end<',', Opts>(ctx, it, end)) {
2259
335
                     return;
2260
335
                  }
2261
28.2k
                  if constexpr (not Opts.null_terminated) {
2262
28.2k
                     if (it == end) [[unlikely]] {
2263
0
                        ctx.error = error_code::unexpected_end;
2264
0
                        return;
2265
0
                     }
2266
28.2k
                  }
2267
2268
28.2k
                  if constexpr ((not Opts.minified) && (num_members > 1 || not Opts.error_on_unknown_keys)) {
2269
28.2k
                     if (ws_size && ws_size < size_t(end - it)) {
2270
6.11k
                        skip_matching_ws(ws_start, it, ws_size);
2271
6.11k
                     }
2272
28.2k
                  }
2273
2274
28.2k
                  if (skip_ws<Opts>(ctx, it, end)) {
2275
24
                     return;
2276
24
                  }
2277
28.2k
               }
2278
2279
32.6k
               constexpr auto reflection_type = glaze_object_t<T> || reflectable<T>;
2280
2281
               if constexpr (reflection_type && (num_members == 0)) {
2282
                  if constexpr (Opts.error_on_unknown_keys) {
2283
                     static_assert(false_v<T>, "This should be unreachable");
2284
                  }
2285
                  else {
2286
                     if (match_invalid_end<'"', Opts>(ctx, it, end)) {
2287
                        return;
2288
                     }
2289
2290
                     // parsing to an empty object, but at this point the JSON presents keys
2291
2292
                     // Unknown key handler does not unescape keys. Unknown escaped keys are
2293
                     // handled by the user.
2294
2295
                     const auto start = it;
2296
                     skip_string_view<Opts>(ctx, it, end);
2297
                     if (bool(ctx.error)) [[unlikely]]
2298
                        return;
2299
                     const sv key{start, size_t(it - start)};
2300
                     ++it;
2301
                     if constexpr (not Opts.null_terminated) {
2302
                        if (it == end) [[unlikely]] {
2303
                           ctx.error = error_code::unexpected_end;
2304
                           return;
2305
                        }
2306
                     }
2307
2308
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2309
                        return;
2310
                     }
2311
2312
                     parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
2313
                     if (bool(ctx.error)) [[unlikely]]
2314
                        return;
2315
                     if constexpr (not Opts.null_terminated) {
2316
                        if (it == end) [[unlikely]] {
2317
                           ctx.error = error_code::unexpected_end;
2318
                           return;
2319
                        }
2320
                     }
2321
                  }
2322
               }
2323
32.6k
               else if constexpr (reflection_type) {
2324
32.6k
                  static_assert(bool(hash_info<T>.type));
2325
2326
32.6k
                  if (*it != '"') [[unlikely]] {
2327
200
                     ctx.error = error_code::expected_quote;
2328
200
                     return;
2329
200
                  }
2330
32.4k
                  ++it;
2331
32.4k
                  if constexpr (not Opts.null_terminated) {
2332
32.4k
                     if (it == end) [[unlikely]] {
2333
24
                        ctx.error = error_code::unexpected_end;
2334
24
                        return;
2335
24
                     }
2336
32.4k
                  }
2337
2338
                  if constexpr (not tag.sv().empty() && not contains_tag<T, tag>()) {
2339
                     // For tagged variants we first check to see if the key matches the tag
2340
                     // We only need to do this if the tag is not part of the keys
2341
2342
                     const auto start = it;
2343
                     skip_string_view<Opts>(ctx, it, end);
2344
                     if (bool(ctx.error)) [[unlikely]]
2345
                        return;
2346
                     const sv key{start, size_t(it - start)};
2347
                     ++it;
2348
                     if constexpr (not Opts.null_terminated) {
2349
                        if (it == end) [[unlikely]] {
2350
                           ctx.error = error_code::unexpected_end;
2351
                           return;
2352
                        }
2353
                     }
2354
2355
                     if (key == tag.sv()) {
2356
                        if (parse_ws_colon<Opts>(ctx, it, end)) {
2357
                           return;
2358
                        }
2359
2360
                        parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
2361
                        if (bool(ctx.error)) [[unlikely]]
2362
                           return;
2363
2364
                        if (skip_ws<Opts>(ctx, it, end)) {
2365
                           return;
2366
                        }
2367
                        continue;
2368
                     }
2369
                     else {
2370
                        it = start; // reset the iterator
2371
                     }
2372
                  }
2373
2374
                  if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
2375
                     size_t index = num_members;
2376
                     parse_and_invoke<Opts, T, hash_info<T>>(value, ctx, it, end, index);
2377
                     if (bool(ctx.error)) [[unlikely]]
2378
                        return;
2379
                     if (index < num_members) {
2380
                        fields[index] = true;
2381
                     }
2382
                  }
2383
32.4k
                  else {
2384
32.4k
                     parse_and_invoke<Opts, T, hash_info<T>>(value, ctx, it, end);
2385
32.4k
                     if (bool(ctx.error)) [[unlikely]]
2386
3.87k
                        return;
2387
32.4k
                  }
2388
               }
2389
               else {
2390
                  // For types like std::map, std::unordered_map
2391
2392
                  auto reading = [&](auto&& key) {
2393
                     if constexpr (Opts.partial_read) {
2394
                        if (auto element = value.find(key); element != value.end()) {
2395
                           ++read_count;
2396
                           parse<JSON>::op<ws_handled<Opts>()>(element->second, ctx, it, end);
2397
                        }
2398
                        else {
2399
                           skip_value<JSON>::op<Opts>(ctx, it, end);
2400
                        }
2401
                     }
2402
                     else {
2403
                        parse<JSON>::op<ws_handled<Opts>()>(value[key], ctx, it, end);
2404
                     }
2405
                  };
2406
2407
                  // using Key = std::conditional_t<heterogeneous_map<T>, sv, typename T::key_type>;
2408
                  using Key = typename T::key_type;
2409
                  if constexpr (std::is_same_v<Key, std::string>) {
2410
                     static thread_local Key key;
2411
                     parse<JSON>::op<Opts>(key, ctx, it, end);
2412
                     if (bool(ctx.error)) [[unlikely]]
2413
                        return;
2414
2415
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2416
                        return;
2417
                     }
2418
2419
                     reading(key);
2420
                     if constexpr (Opts.partial_read) {
2421
                        if (read_count == value.size()) {
2422
                           return;
2423
                        }
2424
                     }
2425
                     if (bool(ctx.error)) [[unlikely]]
2426
                        return;
2427
                  }
2428
                  else if constexpr (str_t<Key>) {
2429
                     Key key;
2430
                     parse<JSON>::op<Opts>(key, ctx, it, end);
2431
                     if (bool(ctx.error)) [[unlikely]]
2432
                        return;
2433
2434
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2435
                        return;
2436
                     }
2437
2438
                     reading(key);
2439
                     if constexpr (Opts.partial_read) {
2440
                        if (read_count == value.size()) {
2441
                           return;
2442
                        }
2443
                     }
2444
                     if (bool(ctx.error)) [[unlikely]]
2445
                        return;
2446
                  }
2447
                  else {
2448
                     Key key_value{};
2449
                     if constexpr (glaze_enum_t<Key>) {
2450
                        parse<JSON>::op<Opts>(key_value, ctx, it, end);
2451
                     }
2452
                     else if constexpr (std::is_arithmetic_v<Key>) {
2453
                        // prefer over quoted_t below to avoid double parsing of quoted_t
2454
                        parse<JSON>::op<opt_true<Opts, &opts::quoted_num>>(key_value, ctx, it, end);
2455
                     }
2456
                     else {
2457
                        parse<JSON>::op<opt_false<Opts, &opts::raw_string>>(quoted_t<Key>{key_value}, ctx, it, end);
2458
                     }
2459
                     if (bool(ctx.error)) [[unlikely]]
2460
                        return;
2461
2462
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2463
                        return;
2464
                     }
2465
2466
                     reading(key_value);
2467
                     if constexpr (Opts.partial_read) {
2468
                        if (read_count == value.size()) {
2469
                           return;
2470
                        }
2471
                     }
2472
                     if (bool(ctx.error)) [[unlikely]]
2473
                        return;
2474
                  }
2475
               }
2476
32.6k
               if (skip_ws<Opts>(ctx, it, end)) {
2477
61
                  return;
2478
61
               }
2479
32.6k
            }
2480
4.55k
         }
2481
4.55k
      }
_ZN3glz4fromILj10E9my_structE2opITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1ELb0ELb0ELc32ELh3ELb1EEETnNS_14string_literalEXtlNS5_ILm1EEEEERS1_TkNS_10is_contextERNS_7contextERPKcSC_EEvOT1_OT2_OT3_OT4_
Line
Count
Source
2097
4.57k
      {
2098
4.57k
         static constexpr auto num_members = reflect<T>::size;
2099
2100
4.57k
         static constexpr auto Opts = opening_handled_off<ws_handled_off<Options>()>();
2101
4.57k
         if constexpr (!check_opening_handled(Options)) {
2102
4.57k
            if constexpr (!check_ws_handled(Options)) {
2103
4.57k
               if (skip_ws<Opts>(ctx, it, end)) {
2104
0
                  return;
2105
0
               }
2106
4.57k
            }
2107
4.57k
            if (match_invalid_end<'{', Opts>(ctx, it, end)) {
2108
31
               return;
2109
31
            }
2110
            if constexpr (not Opts.null_terminated) {
2111
               if (it == end) [[unlikely]] {
2112
                  ctx.error = error_code::unexpected_end;
2113
                  return;
2114
               }
2115
            }
2116
            if constexpr (not Opts.null_terminated) {
2117
               ++ctx.indentation_level;
2118
            }
2119
4.54k
         }
2120
4.54k
         const auto ws_start = it;
2121
4.57k
         if (skip_ws<Opts>(ctx, it, end)) {
2122
0
            return;
2123
0
         }
2124
4.57k
         const size_t ws_size = size_t(it - ws_start);
2125
2126
         if constexpr ((glaze_object_t<T> || reflectable<T>) && num_members == 0 && Opts.error_on_unknown_keys) {
2127
            if constexpr (not tag.sv().empty()) {
2128
               if (*it == '"') {
2129
                  ++it;
2130
                  if constexpr (not Opts.null_terminated) {
2131
                     if (it == end) [[unlikely]] {
2132
                        ctx.error = error_code::unexpected_end;
2133
                        return;
2134
                     }
2135
                  }
2136
2137
                  const auto start = it;
2138
                  skip_string_view<Opts>(ctx, it, end);
2139
                  if (bool(ctx.error)) [[unlikely]]
2140
                     return;
2141
                  const sv key{start, size_t(it - start)};
2142
                  ++it;
2143
                  if constexpr (not Opts.null_terminated) {
2144
                     if (it == end) [[unlikely]] {
2145
                        ctx.error = error_code::unexpected_end;
2146
                        return;
2147
                     }
2148
                  }
2149
2150
                  if (key == tag.sv()) {
2151
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2152
                        return;
2153
                     }
2154
2155
                     parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
2156
                     if (bool(ctx.error)) [[unlikely]]
2157
                        return;
2158
2159
                     if (skip_ws<Opts>(ctx, it, end)) {
2160
                        return;
2161
                     }
2162
                  }
2163
                  else {
2164
                     ctx.error = error_code::unknown_key;
2165
                     return;
2166
                  }
2167
               }
2168
            }
2169
2170
            if (*it == '}') [[likely]] {
2171
               if constexpr (not Opts.null_terminated) {
2172
                  --ctx.indentation_level;
2173
               }
2174
               ++it;
2175
               if constexpr (not Opts.null_terminated) {
2176
                  if (it == end) {
2177
                     ctx.error = error_code::end_reached;
2178
                     return;
2179
                  }
2180
               }
2181
               if constexpr (Opts.partial_read) {
2182
                  ctx.error = error_code::partial_read_complete;
2183
               }
2184
               return;
2185
            }
2186
            ctx.error = error_code::unknown_key;
2187
            return;
2188
         }
2189
4.57k
         else {
2190
4.57k
            decltype(auto) fields = [&]() -> decltype(auto) {
2191
4.57k
               if constexpr ((glaze_object_t<T> || reflectable<T>) &&
2192
4.57k
                             (Opts.error_on_missing_keys || Opts.partial_read)) {
2193
4.57k
                  return bit_array<num_members>{};
2194
4.57k
               }
2195
4.57k
               else {
2196
4.57k
                  return nullptr;
2197
4.57k
               }
2198
4.57k
            }();
2199
2200
4.57k
            size_t read_count{}; // for partial_read
2201
2202
4.57k
            bool first = true;
2203
37.3k
            while (true) {
2204
               if constexpr ((glaze_object_t<T> || reflectable<T>) && Opts.partial_read) {
2205
                  static constexpr bit_array<num_members> all_fields = [] {
2206
                     bit_array<num_members> arr{};
2207
                     for (size_t i = 0; i < num_members; ++i) {
2208
                        arr[i] = true;
2209
                     }
2210
                     return arr;
2211
                  }();
2212
2213
                  if ((all_fields & fields) == all_fields) {
2214
                     ctx.error = error_code::partial_read_complete;
2215
                     return;
2216
                  }
2217
               }
2218
2219
35.4k
               if (*it == '}') {
2220
                  if constexpr (not Opts.null_terminated) {
2221
                     --ctx.indentation_level;
2222
                  }
2223
                  if constexpr ((glaze_object_t<T> || reflectable<T>) &&
2224
                                (Opts.partial_read && Opts.error_on_missing_keys)) {
2225
                     ctx.error = error_code::missing_key;
2226
                     return;
2227
                  }
2228
3
                  else {
2229
                     if constexpr ((glaze_object_t<T> || reflectable<T>) && Opts.error_on_missing_keys) {
2230
                        constexpr auto req_fields = required_fields<T, Opts>();
2231
                        if ((req_fields & fields) != req_fields) {
2232
                           for (size_t i = 0; i < num_members; ++i) {
2233
                              if (not fields[i]) {
2234
                                 ctx.custom_error_message = reflect<T>::keys[i];
2235
                                 // We just return the first missing key in order to avoid heap allocations
2236
                                 break;
2237
                              }
2238
                           }
2239
2240
                           ctx.error = error_code::missing_key;
2241
                           return;
2242
                        }
2243
                     }
2244
3
                     ++it; // Increment after checking for mising keys so errors are within buffer bounds
2245
                     if constexpr (not Opts.null_terminated) {
2246
                        if (it == end) {
2247
                           ctx.error = error_code::end_reached;
2248
                           return;
2249
                        }
2250
                     }
2251
3
                  }
2252
3
                  return;
2253
3
               }
2254
35.4k
               else if (first) {
2255
4.54k
                  first = false;
2256
4.54k
               }
2257
30.9k
               else {
2258
30.9k
                  if (match_invalid_end<',', Opts>(ctx, it, end)) {
2259
2.66k
                     return;
2260
2.66k
                  }
2261
                  if constexpr (not Opts.null_terminated) {
2262
                     if (it == end) [[unlikely]] {
2263
                        ctx.error = error_code::unexpected_end;
2264
                        return;
2265
                     }
2266
                  }
2267
2268
28.2k
                  if constexpr ((not Opts.minified) && (num_members > 1 || not Opts.error_on_unknown_keys)) {
2269
28.2k
                     if (ws_size && ws_size < size_t(end - it)) {
2270
6.11k
                        skip_matching_ws(ws_start, it, ws_size);
2271
6.11k
                     }
2272
28.2k
                  }
2273
2274
28.2k
                  if (skip_ws<Opts>(ctx, it, end)) {
2275
0
                     return;
2276
0
                  }
2277
28.2k
               }
2278
2279
32.7k
               constexpr auto reflection_type = glaze_object_t<T> || reflectable<T>;
2280
2281
               if constexpr (reflection_type && (num_members == 0)) {
2282
                  if constexpr (Opts.error_on_unknown_keys) {
2283
                     static_assert(false_v<T>, "This should be unreachable");
2284
                  }
2285
                  else {
2286
                     if (match_invalid_end<'"', Opts>(ctx, it, end)) {
2287
                        return;
2288
                     }
2289
2290
                     // parsing to an empty object, but at this point the JSON presents keys
2291
2292
                     // Unknown key handler does not unescape keys. Unknown escaped keys are
2293
                     // handled by the user.
2294
2295
                     const auto start = it;
2296
                     skip_string_view<Opts>(ctx, it, end);
2297
                     if (bool(ctx.error)) [[unlikely]]
2298
                        return;
2299
                     const sv key{start, size_t(it - start)};
2300
                     ++it;
2301
                     if constexpr (not Opts.null_terminated) {
2302
                        if (it == end) [[unlikely]] {
2303
                           ctx.error = error_code::unexpected_end;
2304
                           return;
2305
                        }
2306
                     }
2307
2308
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2309
                        return;
2310
                     }
2311
2312
                     parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
2313
                     if (bool(ctx.error)) [[unlikely]]
2314
                        return;
2315
                     if constexpr (not Opts.null_terminated) {
2316
                        if (it == end) [[unlikely]] {
2317
                           ctx.error = error_code::unexpected_end;
2318
                           return;
2319
                        }
2320
                     }
2321
                  }
2322
               }
2323
32.7k
               else if constexpr (reflection_type) {
2324
32.7k
                  static_assert(bool(hash_info<T>.type));
2325
2326
32.7k
                  if (*it != '"') [[unlikely]] {
2327
296
                     ctx.error = error_code::expected_quote;
2328
296
                     return;
2329
296
                  }
2330
32.4k
                  ++it;
2331
                  if constexpr (not Opts.null_terminated) {
2332
                     if (it == end) [[unlikely]] {
2333
                        ctx.error = error_code::unexpected_end;
2334
                        return;
2335
                     }
2336
                  }
2337
2338
                  if constexpr (not tag.sv().empty() && not contains_tag<T, tag>()) {
2339
                     // For tagged variants we first check to see if the key matches the tag
2340
                     // We only need to do this if the tag is not part of the keys
2341
2342
                     const auto start = it;
2343
                     skip_string_view<Opts>(ctx, it, end);
2344
                     if (bool(ctx.error)) [[unlikely]]
2345
                        return;
2346
                     const sv key{start, size_t(it - start)};
2347
                     ++it;
2348
                     if constexpr (not Opts.null_terminated) {
2349
                        if (it == end) [[unlikely]] {
2350
                           ctx.error = error_code::unexpected_end;
2351
                           return;
2352
                        }
2353
                     }
2354
2355
                     if (key == tag.sv()) {
2356
                        if (parse_ws_colon<Opts>(ctx, it, end)) {
2357
                           return;
2358
                        }
2359
2360
                        parse<JSON>::handle_unknown<Opts>(key, value, ctx, it, end);
2361
                        if (bool(ctx.error)) [[unlikely]]
2362
                           return;
2363
2364
                        if (skip_ws<Opts>(ctx, it, end)) {
2365
                           return;
2366
                        }
2367
                        continue;
2368
                     }
2369
                     else {
2370
                        it = start; // reset the iterator
2371
                     }
2372
                  }
2373
2374
                  if constexpr (Opts.error_on_missing_keys || Opts.partial_read) {
2375
                     size_t index = num_members;
2376
                     parse_and_invoke<Opts, T, hash_info<T>>(value, ctx, it, end, index);
2377
                     if (bool(ctx.error)) [[unlikely]]
2378
                        return;
2379
                     if (index < num_members) {
2380
                        fields[index] = true;
2381
                     }
2382
                  }
2383
32.4k
                  else {
2384
32.4k
                     parse_and_invoke<Opts, T, hash_info<T>>(value, ctx, it, end);
2385
32.4k
                     if (bool(ctx.error)) [[unlikely]]
2386
1.58k
                        return;
2387
32.4k
                  }
2388
               }
2389
               else {
2390
                  // For types like std::map, std::unordered_map
2391
2392
                  auto reading = [&](auto&& key) {
2393
                     if constexpr (Opts.partial_read) {
2394
                        if (auto element = value.find(key); element != value.end()) {
2395
                           ++read_count;
2396
                           parse<JSON>::op<ws_handled<Opts>()>(element->second, ctx, it, end);
2397
                        }
2398
                        else {
2399
                           skip_value<JSON>::op<Opts>(ctx, it, end);
2400
                        }
2401
                     }
2402
                     else {
2403
                        parse<JSON>::op<ws_handled<Opts>()>(value[key], ctx, it, end);
2404
                     }
2405
                  };
2406
2407
                  // using Key = std::conditional_t<heterogeneous_map<T>, sv, typename T::key_type>;
2408
                  using Key = typename T::key_type;
2409
                  if constexpr (std::is_same_v<Key, std::string>) {
2410
                     static thread_local Key key;
2411
                     parse<JSON>::op<Opts>(key, ctx, it, end);
2412
                     if (bool(ctx.error)) [[unlikely]]
2413
                        return;
2414
2415
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2416
                        return;
2417
                     }
2418
2419
                     reading(key);
2420
                     if constexpr (Opts.partial_read) {
2421
                        if (read_count == value.size()) {
2422
                           return;
2423
                        }
2424
                     }
2425
                     if (bool(ctx.error)) [[unlikely]]
2426
                        return;
2427
                  }
2428
                  else if constexpr (str_t<Key>) {
2429
                     Key key;
2430
                     parse<JSON>::op<Opts>(key, ctx, it, end);
2431
                     if (bool(ctx.error)) [[unlikely]]
2432
                        return;
2433
2434
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2435
                        return;
2436
                     }
2437
2438
                     reading(key);
2439
                     if constexpr (Opts.partial_read) {
2440
                        if (read_count == value.size()) {
2441
                           return;
2442
                        }
2443
                     }
2444
                     if (bool(ctx.error)) [[unlikely]]
2445
                        return;
2446
                  }
2447
                  else {
2448
                     Key key_value{};
2449
                     if constexpr (glaze_enum_t<Key>) {
2450
                        parse<JSON>::op<Opts>(key_value, ctx, it, end);
2451
                     }
2452
                     else if constexpr (std::is_arithmetic_v<Key>) {
2453
                        // prefer over quoted_t below to avoid double parsing of quoted_t
2454
                        parse<JSON>::op<opt_true<Opts, &opts::quoted_num>>(key_value, ctx, it, end);
2455
                     }
2456
                     else {
2457
                        parse<JSON>::op<opt_false<Opts, &opts::raw_string>>(quoted_t<Key>{key_value}, ctx, it, end);
2458
                     }
2459
                     if (bool(ctx.error)) [[unlikely]]
2460
                        return;
2461
2462
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2463
                        return;
2464
                     }
2465
2466
                     reading(key_value);
2467
                     if constexpr (Opts.partial_read) {
2468
                        if (read_count == value.size()) {
2469
                           return;
2470
                        }
2471
                     }
2472
                     if (bool(ctx.error)) [[unlikely]]
2473
                        return;
2474
                  }
2475
               }
2476
32.7k
               if (skip_ws<Opts>(ctx, it, end)) {
2477
0
                  return;
2478
0
               }
2479
32.7k
            }
2480
4.57k
         }
2481
4.57k
      }
2482
   };
2483
2484
   template <is_variant T>
2485
   consteval auto variant_is_auto_deducible()
2486
   {
2487
      // Contains at most one each of the basic json types bool, numeric, string, object, array
2488
      // If all objects are meta-objects then we can attempt to deduce them as well either through a type tag or
2489
      // unique combinations of keys
2490
      int bools{}, numbers{}, strings{}, objects{}, meta_objects{}, arrays{};
2491
      constexpr auto N = std::variant_size_v<T>;
2492
      for_each<N>([&]<auto I>() {
2493
         using V = std::decay_t<std::variant_alternative_t<I, T>>;
2494
         // ICE workaround
2495
         bools += bool_t<V>;
2496
         numbers += num_t<V>;
2497
         strings += str_t<V>;
2498
         strings += glaze_enum_t<V>;
2499
         objects += pair_t<V>;
2500
         objects += (writable_map_t<V> || readable_map_t<V> || is_memory_object<V>);
2501
         objects += glaze_object_t<V>;
2502
         meta_objects += glaze_object_t<V> || reflectable<V> || is_memory_object<V>;
2503
         arrays += glaze_array_t<V>;
2504
         arrays += array_t<V>;
2505
         // TODO null
2506
      });
2507
      return bools < 2 && numbers < 2 && strings < 2 && (objects < 2 || meta_objects == objects) && arrays < 2;
2508
   }
2509
2510
   template <class>
2511
   struct variant_types;
2512
2513
   template <class... Ts>
2514
   struct variant_types<std::variant<Ts...>>
2515
   {
2516
      // TODO: this way of filtering types is compile time intensive.
2517
      using bool_types =
2518
         decltype(tuplet::tuple_cat(std::conditional_t<bool_t<remove_meta_wrapper_t<Ts>>, tuple<Ts>, tuple<>>{}...));
2519
      using number_types =
2520
         decltype(tuplet::tuple_cat(std::conditional_t<num_t<remove_meta_wrapper_t<Ts>>, tuple<Ts>, tuple<>>{}...));
2521
      using string_types = decltype(tuplet::tuple_cat( // glaze_enum_t remove_meta_wrapper_t supports constexpr
2522
                                                       // types while the other supports non const
2523
         std::conditional_t < str_t<remove_meta_wrapper_t<Ts>> || glaze_enum_t<remove_meta_wrapper_t<Ts>> ||
2524
            glaze_enum_t<Ts>,
2525
         tuple<Ts>, tuple < >> {}...));
2526
      using object_types = decltype(tuplet::tuple_cat(std::conditional_t<json_object<Ts>, tuple<Ts>, tuple<>>{}...));
2527
      using array_types = decltype(tuplet::tuple_cat(
2528
         std::conditional_t < array_t<remove_meta_wrapper_t<Ts>> || glaze_array_t<Ts>, tuple<Ts>, tuple < >> {}...));
2529
      using nullable_types = decltype(tuplet::tuple_cat(std::conditional_t<null_t<Ts>, tuple<Ts>, tuple<>>{}...));
2530
      using nullable_objects =
2531
         decltype(tuplet::tuple_cat(std::conditional_t<is_memory_object<Ts>, tuple<Ts>, tuple<>>{}...));
2532
   };
2533
2534
   // post process output of variant_types
2535
   template <class>
2536
   struct tuple_types;
2537
2538
   template <class... Ts>
2539
   struct tuple_types<tuple<Ts...>>
2540
   {
2541
      using glaze_const_types =
2542
         decltype(tuplet::tuple_cat(std::conditional_t<glaze_const_value_t<Ts>, tuple<Ts>, tuple<>>{}...));
2543
      using glaze_non_const_types =
2544
         decltype(tuplet::tuple_cat(std::conditional_t<!glaze_const_value_t<Ts>, tuple<Ts>, tuple<>>{}...));
2545
   };
2546
2547
   template <class>
2548
   struct variant_type_count;
2549
2550
   template <class... Ts>
2551
   struct variant_type_count<std::variant<Ts...>>
2552
   {
2553
      using V = variant_types<std::variant<Ts...>>;
2554
      static constexpr auto n_bool = glz::tuple_size_v<typename V::bool_types>;
2555
      static constexpr auto n_number = glz::tuple_size_v<typename V::number_types>;
2556
      static constexpr auto n_string = glz::tuple_size_v<typename V::string_types>;
2557
      static constexpr auto n_nullable_object = glz::tuple_size_v<typename V::nullable_objects>;
2558
      static constexpr auto n_object = glz::tuple_size_v<typename V::object_types> + n_nullable_object;
2559
      static constexpr auto n_array = glz::tuple_size_v<typename V::array_types>;
2560
      static constexpr auto n_null = glz::tuple_size_v<typename V::nullable_types>;
2561
   };
2562
2563
   template <class Tuple>
2564
   struct process_arithmetic_boolean_string_or_array
2565
   {
2566
      template <auto Options>
2567
      static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end)
2568
      {
2569
         if constexpr (glz::tuple_size_v<Tuple> < 1) {
2570
            ctx.error = error_code::no_matching_variant_type;
2571
         }
2572
         else {
2573
            using const_glaze_types = typename tuple_types<Tuple>::glaze_const_types;
2574
            bool found_match{};
2575
            for_each<glz::tuple_size_v<const_glaze_types>>([&]<size_t I>() {
2576
               if (found_match) {
2577
                  return;
2578
               }
2579
               using V = glz::tuple_element_t<I, const_glaze_types>;
2580
               // run time substitute to compare to const value
2581
               std::remove_const_t<std::remove_pointer_t<std::remove_const_t<meta_wrapper_t<V>>>> substitute{};
2582
               auto copy_it{it};
2583
               parse<JSON>::op<ws_handled<Options>()>(substitute, ctx, it, end);
2584
               static constexpr auto const_value{*meta_wrapper_v<V>};
2585
               if (substitute == const_value) {
2586
                  found_match = true;
2587
                  if (!std::holds_alternative<V>(value)) {
2588
                     value = V{};
2589
                  }
2590
               }
2591
               else {
2592
                  if constexpr (not Options.null_terminated) {
2593
                     if (ctx.error == error_code::end_reached) {
2594
                        // reset the context for next attempt
2595
                        ctx.error = error_code::none;
2596
                     }
2597
                  }
2598
                  it = copy_it;
2599
               }
2600
            });
2601
            if (found_match) {
2602
               return;
2603
            }
2604
2605
            using non_const_types = typename tuple_types<Tuple>::glaze_non_const_types;
2606
            if constexpr (glz::tuple_size_v < non_const_types >> 0) {
2607
               using V = glz::tuple_element_t<0, non_const_types>;
2608
               if (!std::holds_alternative<V>(value)) value = V{};
2609
               parse<JSON>::op<ws_handled<Options>()>(std::get<V>(value), ctx, it, end);
2610
            }
2611
            else {
2612
               ctx.error = error_code::no_matching_variant_type;
2613
            }
2614
         }
2615
      }
2616
   };
2617
2618
   template <is_variant T>
2619
   struct from<JSON, T>
2620
   {
2621
      // Note that items in the variant are required to be default constructable for us to switch types
2622
      template <auto Options>
2623
      static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end)
2624
      {
2625
         constexpr auto Opts = ws_handled_off<Options>();
2626
         if constexpr (variant_is_auto_deducible<T>()) {
2627
            if constexpr (not check_ws_handled(Options)) {
2628
               if (skip_ws<Opts>(ctx, it, end)) {
2629
                  return;
2630
               }
2631
            }
2632
2633
            switch (*it) {
2634
            case '\0':
2635
               ctx.error = error_code::unexpected_end;
2636
               return;
2637
            case '{':
2638
               if (ctx.indentation_level >= max_recursive_depth_limit) {
2639
                  ctx.error = error_code::exceeded_max_recursive_depth;
2640
                  return;
2641
               }
2642
               // In the null terminated case this guards for stack overflow
2643
               // Depth counting is done at the object level when not null terminated
2644
               ++ctx.indentation_level;
2645
2646
               ++it;
2647
               if constexpr (not Opts.null_terminated) {
2648
                  if (it == end) [[unlikely]] {
2649
                     ctx.error = error_code::unexpected_end;
2650
                     return;
2651
                  }
2652
               }
2653
               using type_counts = variant_type_count<T>;
2654
               using object_types = typename variant_types<T>::object_types;
2655
               if constexpr ((type_counts::n_object < 1) //
2656
                             && (type_counts::n_nullable_object < 1)) {
2657
                  ctx.error = error_code::no_matching_variant_type;
2658
                  return;
2659
               }
2660
               else if constexpr ((type_counts::n_object + type_counts::n_nullable_object) == 1 && tag_v<T>.empty()) {
2661
                  using V = glz::tuple_element_t<0, object_types>;
2662
                  if (!std::holds_alternative<V>(value)) value = V{};
2663
                  parse<JSON>::op<opening_handled<Opts>()>(std::get<V>(value), ctx, it, end);
2664
                  if constexpr (Opts.null_terminated) {
2665
                     // In the null terminated case this guards for stack overflow
2666
                     // Depth counting is done at the object level when not null terminated
2667
                     --ctx.indentation_level;
2668
                  }
2669
                  return;
2670
               }
2671
               else {
2672
                  auto possible_types = bit_array<std::variant_size_v<T>>{}.flip();
2673
                  static constexpr auto deduction_map = make_variant_deduction_map<T>();
2674
                  static constexpr auto tag_literal = string_literal_from_view<tag_v<T>.size()>(tag_v<T>);
2675
                  if (skip_ws<Opts>(ctx, it, end)) {
2676
                     return;
2677
                  }
2678
                  auto start = it;
2679
                  while (*it != '}') {
2680
                     if (it != start) {
2681
                        if (match_invalid_end<',', Opts>(ctx, it, end)) {
2682
                           return;
2683
                        }
2684
                     }
2685
2686
                     if (skip_ws<Opts>(ctx, it, end)) {
2687
                        return;
2688
                     }
2689
                     if (match_invalid_end<'"', Opts>(ctx, it, end)) {
2690
                        return;
2691
                     }
2692
2693
                     auto* key_start = it;
2694
                     skip_string_view<Opts>(ctx, it, end);
2695
                     if (bool(ctx.error)) [[unlikely]]
2696
                        return;
2697
                     const sv key = {key_start, size_t(it - key_start)};
2698
2699
                     if (match_invalid_end<'"', Opts>(ctx, it, end)) {
2700
                        return;
2701
                     }
2702
2703
                     if constexpr (deduction_map.size()) {
2704
                        // We first check if a tag is defined and see if the key matches the tag
2705
                        if constexpr (not tag_v<T>.empty()) {
2706
                           if (key == tag_v<T>) {
2707
                              if (parse_ws_colon<Opts>(ctx, it, end)) {
2708
                                 return;
2709
                              }
2710
2711
                              using id_type = std::decay_t<decltype(ids_v<T>[0])>;
2712
2713
                              std::conditional_t<std::integral<id_type>, id_type, sv> type_id{};
2714
                              if constexpr (std::integral<id_type>) {
2715
                                 from<JSON, id_type>::template op<ws_handled<Opts>()>(type_id, ctx, it, end);
2716
                              }
2717
                              else {
2718
                                 from<JSON, sv>::template op<ws_handled<Opts>()>(type_id, ctx, it, end);
2719
                              }
2720
                              if (bool(ctx.error)) [[unlikely]]
2721
                                 return;
2722
                              if (skip_ws<Opts>(ctx, it, end)) {
2723
                                 return;
2724
                              }
2725
                              if (!(*it == ',' || *it == '}')) [[unlikely]] {
2726
                                 ctx.error = error_code::syntax_error;
2727
                                 return;
2728
                              }
2729
2730
                              static constexpr auto id_map = make_variant_id_map<T>();
2731
                              auto id_it = id_map.find(type_id);
2732
                              if (id_it != id_map.end()) [[likely]] {
2733
                                 it = start; // we restart our object parsing now that we know the target type
2734
                                 const auto type_index = id_it->second;
2735
                                 if (value.index() != type_index) value = runtime_variant_map<T>()[type_index];
2736
                                 std::visit(
2737
                                    [&](auto&& v) {
2738
                                       using V = std::decay_t<decltype(v)>;
2739
                                       constexpr bool is_object = glaze_object_t<V> || reflectable<V>;
2740
                                       if constexpr (is_object) {
2741
                                          from<JSON, V>::template op<opening_handled<Opts>(), tag_literal>(v, ctx, it,
2742
                                                                                                           end);
2743
                                       }
2744
                                       else if constexpr (is_memory_object<V>) {
2745
                                          if (!v) {
2746
                                             if constexpr (is_specialization_v<V, std::optional>) {
2747
                                                if constexpr (requires { v.emplace(); }) {
2748
                                                   v.emplace();
2749
                                                }
2750
                                                else {
2751
                                                   v = typename V::value_type{};
2752
                                                }
2753
                                             }
2754
                                             else if constexpr (is_specialization_v<V, std::unique_ptr>)
2755
                                                v = std::make_unique<typename V::element_type>();
2756
                                             else if constexpr (is_specialization_v<V, std::shared_ptr>)
2757
                                                v = std::make_shared<typename V::element_type>();
2758
                                             else if constexpr (constructible<V>) {
2759
                                                v = meta_construct_v<V>();
2760
                                             }
2761
                                             else {
2762
                                                ctx.error = error_code::invalid_nullable_read;
2763
                                                return;
2764
                                                // Cannot read into unset nullable that is not std::optional,
2765
                                                // std::unique_ptr, or std::shared_ptr
2766
                                             }
2767
                                          }
2768
                                          from<JSON, memory_type<V>>::template op<opening_handled<Opts>(), tag_literal>(
2769
                                             *v, ctx, it, end);
2770
                                       }
2771
                                    },
2772
                                    value);
2773
2774
                                 if constexpr (Opts.null_terminated) {
2775
                                    // In the null terminated case this guards for stack overflow
2776
                                    // Depth counting is done at the object level when not null terminated
2777
                                    --ctx.indentation_level;
2778
                                 }
2779
                                 return; // we've decoded our target type
2780
                              }
2781
                              else [[unlikely]] {
2782
                                 ctx.error = error_code::no_matching_variant_type;
2783
                                 return;
2784
                              }
2785
                           }
2786
                        }
2787
2788
                        auto deduction_it = deduction_map.find(key);
2789
                        if (deduction_it != deduction_map.end()) [[likely]] {
2790
                           possible_types &= deduction_it->second;
2791
                        }
2792
                        else if constexpr (Opts.error_on_unknown_keys) {
2793
                           ctx.error = error_code::unknown_key;
2794
                           return;
2795
                        }
2796
                     }
2797
                     else if constexpr (not tag_v<T>.empty()) {
2798
                        // empty object case for variant, if there are no normal elements
2799
                        if (key == tag_v<T>) {
2800
                           if (parse_ws_colon<Opts>(ctx, it, end)) {
2801
                              return;
2802
                           }
2803
2804
                           std::string_view type_id{};
2805
                           parse<JSON>::op<ws_handled<Opts>()>(type_id, ctx, it, end);
2806
                           if (bool(ctx.error)) [[unlikely]]
2807
                              return;
2808
                           if (skip_ws<Opts>(ctx, it, end)) {
2809
                              return;
2810
                           }
2811
2812
                           static constexpr auto id_map = make_variant_id_map<T>();
2813
                           auto id_it = id_map.find(type_id);
2814
                           if (id_it != id_map.end()) [[likely]] {
2815
                              it = start;
2816
                              const auto type_index = id_it->second;
2817
                              if (value.index() != type_index) value = runtime_variant_map<T>()[type_index];
2818
                              return;
2819
                           }
2820
                           else {
2821
                              ctx.error = error_code::no_matching_variant_type;
2822
                              return;
2823
                           }
2824
                        }
2825
                        else if constexpr (Opts.error_on_unknown_keys) {
2826
                           ctx.error = error_code::unknown_key;
2827
                           return;
2828
                        }
2829
                     }
2830
                     else if constexpr (Opts.error_on_unknown_keys) {
2831
                        ctx.error = error_code::unknown_key;
2832
                        return;
2833
                     }
2834
2835
                     auto matching_types = possible_types.popcount();
2836
                     if (matching_types == 0) {
2837
                        ctx.error = error_code::no_matching_variant_type;
2838
                        return;
2839
                     }
2840
                     else if (matching_types == 1) {
2841
                        it = start;
2842
                        const auto type_index = possible_types.countr_zero();
2843
                        if (value.index() != static_cast<size_t>(type_index))
2844
                           value = runtime_variant_map<T>()[type_index];
2845
                        std::visit(
2846
                           [&](auto&& v) {
2847
                              using V = std::decay_t<decltype(v)>;
2848
                              constexpr bool is_object = glaze_object_t<V> || reflectable<V>;
2849
                              if constexpr (is_object) {
2850
                                 from<JSON, V>::template op<opening_handled<Opts>(), tag_literal>(v, ctx, it, end);
2851
                              }
2852
                              else if constexpr (is_memory_object<V>) {
2853
                                 if (!v) {
2854
                                    if constexpr (is_specialization_v<V, std::optional>) {
2855
                                       if constexpr (requires { v.emplace(); }) {
2856
                                          v.emplace();
2857
                                       }
2858
                                       else {
2859
                                          v = typename V::value_type{};
2860
                                       }
2861
                                    }
2862
                                    else if constexpr (is_specialization_v<V, std::unique_ptr>)
2863
                                       v = std::make_unique<typename V::element_type>();
2864
                                    else if constexpr (is_specialization_v<V, std::shared_ptr>)
2865
                                       v = std::make_shared<typename V::element_type>();
2866
                                    else if constexpr (constructible<V>) {
2867
                                       v = meta_construct_v<V>();
2868
                                    }
2869
                                    else {
2870
                                       ctx.error = error_code::invalid_nullable_read;
2871
                                       return;
2872
                                       // Cannot read into unset nullable that is not std::optional,
2873
                                       // std::unique_ptr, or std::shared_ptr
2874
                                    }
2875
                                 }
2876
                                 from<JSON, memory_type<V>>::template op<opening_handled<Opts>(), tag_literal>(*v, ctx,
2877
                                                                                                               it, end);
2878
                              }
2879
                           },
2880
                           value);
2881
2882
                        if constexpr (Opts.null_terminated) {
2883
                           // In the null terminated case this guards for stack overflow
2884
                           // Depth counting is done at the object level when not null terminated
2885
                           --ctx.indentation_level;
2886
                        }
2887
                        return; // we've decoded our target type
2888
                     }
2889
                     if (parse_ws_colon<Opts>(ctx, it, end)) {
2890
                        return;
2891
                     }
2892
2893
                     skip_value<JSON>::op<Opts>(ctx, it, end);
2894
                     if (bool(ctx.error)) [[unlikely]]
2895
                        return;
2896
                     if (skip_ws<Opts>(ctx, it, end)) {
2897
                        return;
2898
                     }
2899
                  }
2900
                  ctx.error = error_code::no_matching_variant_type;
2901
               }
2902
               break;
2903
            case '[':
2904
               using array_types = typename variant_types<T>::array_types;
2905
2906
               if (ctx.indentation_level >= max_recursive_depth_limit) {
2907
                  ctx.error = error_code::exceeded_max_recursive_depth;
2908
                  return;
2909
               }
2910
               if constexpr (Opts.null_terminated) {
2911
                  // In the null terminated case this guards for stack overflow
2912
                  // Depth counting is done at the object level when not null terminated
2913
                  ++ctx.indentation_level;
2914
               }
2915
               process_arithmetic_boolean_string_or_array<array_types>::template op<Opts>(value, ctx, it, end);
2916
               if constexpr (Opts.null_terminated) {
2917
                  --ctx.indentation_level;
2918
               }
2919
               break;
2920
            case '"': {
2921
               using string_types = typename variant_types<T>::string_types;
2922
               process_arithmetic_boolean_string_or_array<string_types>::template op<Opts>(value, ctx, it, end);
2923
               break;
2924
            }
2925
            case 't':
2926
            case 'f': {
2927
               using bool_types = typename variant_types<T>::bool_types;
2928
               process_arithmetic_boolean_string_or_array<bool_types>::template op<Opts>(value, ctx, it, end);
2929
               break;
2930
            }
2931
            case 'n':
2932
               using nullable_types = typename variant_types<T>::nullable_types;
2933
               if constexpr (glz::tuple_size_v<nullable_types> < 1) {
2934
                  ctx.error = error_code::no_matching_variant_type;
2935
               }
2936
               else {
2937
                  using V = glz::tuple_element_t<0, nullable_types>;
2938
                  if (!std::holds_alternative<V>(value)) value = V{};
2939
                  match<"null", Opts>(ctx, it, end);
2940
               }
2941
               break;
2942
            default: {
2943
               // Not bool, string, object, or array so must be number or null
2944
               using number_types = typename variant_types<T>::number_types;
2945
               process_arithmetic_boolean_string_or_array<number_types>::template op<Opts>(value, ctx, it, end);
2946
            }
2947
            }
2948
         }
2949
         else {
2950
            std::visit([&](auto&& v) { parse<JSON>::op<Options>(v, ctx, it, end); }, value);
2951
         }
2952
      }
2953
   };
2954
2955
   template <class T>
2956
   struct from<JSON, array_variant_wrapper<T>>
2957
   {
2958
      template <auto Options>
2959
      static void op(auto&& wrapper, is_context auto&& ctx, auto&& it, auto&& end)
2960
      {
2961
         auto& value = wrapper.value;
2962
2963
         constexpr auto Opts = ws_handled_off<Options>();
2964
         if constexpr (!check_ws_handled(Options)) {
2965
            if (skip_ws<Opts>(ctx, it, end)) {
2966
               return;
2967
            }
2968
         }
2969
2970
         if (match_invalid_end<'[', Opts>(ctx, it, end)) {
2971
            return;
2972
         }
2973
         if constexpr (not Opts.null_terminated) {
2974
            ++ctx.indentation_level;
2975
         }
2976
         if (skip_ws<Opts>(ctx, it, end)) {
2977
            return;
2978
         }
2979
2980
         // TODO Use key parsing for compiletime known keys
2981
         if (match_invalid_end<'"', Opts>(ctx, it, end)) {
2982
            return;
2983
         }
2984
         auto start = it;
2985
         skip_string_view<Opts>(ctx, it, end);
2986
         if (bool(ctx.error)) [[unlikely]]
2987
            return;
2988
         sv type_id = {start, size_t(it - start)};
2989
         if (match<'"'>(ctx, it)) {
2990
            return;
2991
         }
2992
         if constexpr (not Opts.null_terminated) {
2993
            if (it == end) {
2994
               ctx.error = error_code::end_reached;
2995
               return;
2996
            }
2997
         }
2998
2999
         static constexpr auto id_map = make_variant_id_map<T>();
3000
         auto id_it = id_map.find(type_id);
3001
         if (id_it != id_map.end()) [[likely]] {
3002
            if (skip_ws<Opts>(ctx, it, end)) {
3003
               return;
3004
            }
3005
            if (match_invalid_end<',', Opts>(ctx, it, end)) {
3006
               return;
3007
            }
3008
            const auto type_index = id_it->second;
3009
            if (value.index() != type_index) value = runtime_variant_map<T>()[type_index];
3010
            std::visit([&](auto&& v) { parse<JSON>::op<Opts>(v, ctx, it, end); }, value);
3011
            if (bool(ctx.error)) [[unlikely]]
3012
               return;
3013
         }
3014
         else {
3015
            ctx.error = error_code::no_matching_variant_type;
3016
            return;
3017
         }
3018
3019
         if (skip_ws<Opts>(ctx, it, end)) {
3020
            return;
3021
         }
3022
         match<']'>(ctx, it);
3023
         if constexpr (not Opts.null_terminated) {
3024
            --ctx.indentation_level;
3025
         }
3026
      }
3027
   };
3028
3029
   template <is_expected T>
3030
   struct from<JSON, T>
3031
   {
3032
      template <auto Opts, class... Args>
3033
      static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end)
3034
      {
3035
         if constexpr (!check_ws_handled(Opts)) {
3036
            if (skip_ws<Opts>(ctx, it, end)) {
3037
               return;
3038
            }
3039
         }
3040
3041
         if (*it == '{') {
3042
            if constexpr (not Opts.null_terminated) {
3043
               ++ctx.indentation_level;
3044
            }
3045
            auto start = it;
3046
            ++it;
3047
            if constexpr (not Opts.null_terminated) {
3048
               if (it == end) [[unlikely]] {
3049
                  ctx.error = error_code::unexpected_end;
3050
                  return;
3051
               }
3052
            }
3053
            if (skip_ws<Opts>(ctx, it, end)) {
3054
               return;
3055
            }
3056
            if (*it == '}') {
3057
               it = start;
3058
               // empty object
3059
               if (value) {
3060
                  parse<JSON>::op<Opts>(*value, ctx, it, end);
3061
               }
3062
               else {
3063
                  value.emplace();
3064
                  parse<JSON>::op<Opts>(*value, ctx, it, end);
3065
               }
3066
            }
3067
            else {
3068
               // either we have an unexpected value or we are decoding an object
3069
               auto& key = string_buffer();
3070
               parse<JSON>::op<Opts>(key, ctx, it, end);
3071
               if (bool(ctx.error)) [[unlikely]]
3072
                  return;
3073
               if (key == "unexpected") {
3074
                  if (skip_ws<Opts>(ctx, it, end)) {
3075
                     return;
3076
                  }
3077
                  if (match_invalid_end<':', Opts>(ctx, it, end)) {
3078
                     return;
3079
                  }
3080
                  // read in unexpected value
3081
                  if (!value) {
3082
                     parse<JSON>::op<Opts>(value.error(), ctx, it, end);
3083
                     if (bool(ctx.error)) [[unlikely]]
3084
                        return;
3085
                  }
3086
                  else {
3087
                     // set value to unexpected
3088
                     using error_ctx = typename std::decay_t<decltype(value)>::error_type;
3089
                     std::decay_t<error_ctx> error{};
3090
                     parse<JSON>::op<Opts>(error, ctx, it, end);
3091
                     if (bool(ctx.error)) [[unlikely]]
3092
                        return;
3093
                     value = glz::unexpected(error);
3094
                  }
3095
                  if (skip_ws<Opts>(ctx, it, end)) {
3096
                     return;
3097
                  }
3098
                  match<'}'>(ctx, it);
3099
                  if constexpr (not Opts.null_terminated) {
3100
                     --ctx.indentation_level;
3101
                  }
3102
               }
3103
               else {
3104
                  it = start;
3105
                  if (value) {
3106
                     parse<JSON>::op<Opts>(*value, ctx, it, end);
3107
                  }
3108
                  else {
3109
                     value.emplace();
3110
                     parse<JSON>::op<Opts>(*value, ctx, it, end);
3111
                  }
3112
               }
3113
            }
3114
         }
3115
         else {
3116
            // this is not an object and therefore cannot be an unexpected value
3117
            if (value) {
3118
               parse<JSON>::op<Opts>(*value, ctx, it, end);
3119
            }
3120
            else {
3121
               value.emplace();
3122
               parse<JSON>::op<Opts>(*value, ctx, it, end);
3123
            }
3124
         }
3125
      }
3126
   };
3127
3128
   template <nullable_t T>
3129
      requires(std::is_array_v<T>)
3130
   struct from<JSON, T>
3131
   {
3132
      template <auto Opts, class V, size_t N>
3133
      GLZ_ALWAYS_INLINE static void op(V (&value)[N], is_context auto&& ctx, auto&& it, auto&& end) noexcept
3134
      {
3135
         parse<JSON>::op<Opts>(std::span{value, N}, ctx, it, end);
3136
      }
3137
   };
3138
3139
   template <class T>
3140
      requires((nullable_t<T> || nullable_value_t<T>) && not is_expected<T> && not std::is_array_v<T> &&
3141
               not custom_read<T>)
3142
   struct from<JSON, T>
3143
   {
3144
      template <auto Options>
3145
      static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end)
3146
      {
3147
         constexpr auto Opts = ws_handled_off<Options>();
3148
         if constexpr (!check_ws_handled(Options)) {
3149
            if (skip_ws<Opts>(ctx, it, end)) {
3150
               return;
3151
            }
3152
         }
3153
3154
         if (*it == 'n') {
3155
            ++it;
3156
            if constexpr (not Opts.null_terminated) {
3157
               if (it == end) [[unlikely]] {
3158
                  ctx.error = error_code::unexpected_end;
3159
                  return;
3160
               }
3161
            }
3162
            match<"ull", Opts>(ctx, it, end);
3163
            if (bool(ctx.error)) [[unlikely]]
3164
               return;
3165
            if constexpr (requires { value.reset(); }) {
3166
               value.reset();
3167
            }
3168
         }
3169
         else {
3170
            if constexpr (nullable_value_t<T>) {
3171
               if (not value.has_value()) {
3172
                  if constexpr (constructible<T>) {
3173
                     value = meta_construct_v<T>();
3174
                  }
3175
                  else if constexpr (requires { value.emplace(); }) {
3176
                     value.emplace();
3177
                  }
3178
                  else {
3179
                     static_assert(false_v<T>,
3180
                                   "Your nullable type must have `emplace()` or be glz::meta constructible, or "
3181
                                   "create a custom glz::from specialization");
3182
                  }
3183
               }
3184
               parse<JSON>::op<Opts>(value.value(), ctx, it, end);
3185
            }
3186
            else {
3187
               if (!value) {
3188
                  if constexpr (optional_like<T>) {
3189
                     if constexpr (requires { value.emplace(); }) {
3190
                        value.emplace();
3191
                     }
3192
                     else {
3193
                        value = typename T::value_type{};
3194
                     }
3195
                  }
3196
                  else if constexpr (is_specialization_v<T, std::unique_ptr>)
3197
                     value = std::make_unique<typename T::element_type>();
3198
                  else if constexpr (is_specialization_v<T, std::shared_ptr>)
3199
                     value = std::make_shared<typename T::element_type>();
3200
                  else if constexpr (constructible<T>) {
3201
                     value = meta_construct_v<T>();
3202
                  }
3203
                  else {
3204
                     // Cannot read into a null raw pointer
3205
                     ctx.error = error_code::invalid_nullable_read;
3206
                     return;
3207
                  }
3208
               }
3209
               parse<JSON>::op<Opts>(*value, ctx, it, end);
3210
            }
3211
         }
3212
      }
3213
   };
3214
3215
   template <filesystem_path T>
3216
   struct from<JSON, T>
3217
   {
3218
      template <auto Opts>
3219
      static void op(auto&& value, is_context auto&& ctx, auto&& it, auto&& end)
3220
      {
3221
         std::string& buffer = string_buffer();
3222
         parse<JSON>::op<Opts>(buffer, ctx, it, end);
3223
         if constexpr (Opts.null_terminated) {
3224
            if (bool(ctx.error)) [[unlikely]]
3225
               return;
3226
         }
3227
         else {
3228
            if (size_t(ctx.error) > size_t(error_code::end_reached)) [[unlikely]] {
3229
               return;
3230
            }
3231
         }
3232
         value = buffer;
3233
      }
3234
   };
3235
3236
   struct opts_validate : opts
3237
   {
3238
      bool validate_skipped = true;
3239
      bool validate_trailing_whitespace = true;
3240
   };
3241
3242
   template <is_buffer Buffer>
3243
   [[nodiscard]] error_ctx validate_json(Buffer&& buffer) noexcept
3244
   {
3245
      context ctx{};
3246
      glz::skip skip_value{};
3247
      return read<opts_validate{}>(skip_value, std::forward<Buffer>(buffer), ctx);
3248
   }
3249
3250
   template <is_buffer Buffer>
3251
   [[nodiscard]] error_ctx validate_jsonc(Buffer&& buffer) noexcept
3252
   {
3253
      context ctx{};
3254
      glz::skip skip_value{};
3255
      return read<opts_validate{{opts{.comments = true}}}>(skip_value, std::forward<Buffer>(buffer), ctx);
3256
   }
3257
3258
   template <read_supported<JSON> T, is_buffer Buffer>
3259
   [[nodiscard]] error_ctx read_json(T& value, Buffer&& buffer)
3260
   {
3261
      context ctx{};
3262
      return read<opts{}>(value, std::forward<Buffer>(buffer), ctx);
3263
   }
3264
3265
   template <read_supported<JSON> T, is_buffer Buffer>
3266
   [[nodiscard]] expected<T, error_ctx> read_json(Buffer&& buffer)
3267
4.57k
   {
3268
4.57k
      T value{};
3269
4.57k
      context ctx{};
3270
4.57k
      const error_ctx ec = read<opts{}>(value, std::forward<Buffer>(buffer), ctx);
3271
4.57k
      if (ec) {
3272
4.57k
         return unexpected<error_ctx>(ec);
3273
4.57k
      }
3274
3
      return value;
3275
4.57k
   }
3276
3277
   template <read_supported<JSON> T, is_buffer Buffer>
3278
   [[nodiscard]] error_ctx read_jsonc(T& value, Buffer&& buffer)
3279
   {
3280
      context ctx{};
3281
      return read<opts{.comments = true}>(value, std::forward<Buffer>(buffer), ctx);
3282
   }
3283
3284
   template <read_supported<JSON> T, is_buffer Buffer>
3285
   [[nodiscard]] expected<T, error_ctx> read_jsonc(Buffer&& buffer)
3286
   {
3287
      T value{};
3288
      context ctx{};
3289
      const error_ctx ec = read<opts{.comments = true}>(value, std::forward<Buffer>(buffer), ctx);
3290
      if (ec) {
3291
         return unexpected<error_ctx>(ec);
3292
      }
3293
      return value;
3294
   }
3295
3296
   template <auto Opts = opts{}, read_supported<JSON> T, is_buffer Buffer>
3297
   [[nodiscard]] error_ctx read_file_json(T& value, const sv file_name, Buffer&& buffer)
3298
   {
3299
      context ctx{};
3300
      ctx.current_file = file_name;
3301
3302
      const auto ec = file_to_buffer(buffer, ctx.current_file);
3303
3304
      if (bool(ec)) {
3305
         return {ec};
3306
      }
3307
3308
      return read<set_json<Opts>()>(value, buffer, ctx);
3309
   }
3310
3311
   template <auto Opts = opts{}, read_supported<JSON> T, is_buffer Buffer>
3312
   [[nodiscard]] error_ctx read_file_jsonc(T& value, const sv file_name, Buffer&& buffer)
3313
   {
3314
      context ctx{};
3315
      ctx.current_file = file_name;
3316
3317
      const auto ec = file_to_buffer(buffer, ctx.current_file);
3318
3319
      if (bool(ec)) {
3320
         return {ec};
3321
      }
3322
3323
      constexpr auto Options = opt_true<set_json<Opts>(), &opts::comments>;
3324
      return read<Options>(value, buffer, ctx);
3325
   }
3326
}
3327
3328
#ifdef _MSC_VER
3329
// restore disabled warnings
3330
#pragma warning(pop)
3331
#endif