simdjson 4.0.7
Ridiculously Fast JSON
Loading...
Searching...
No Matches
std_deserialize.h
1#if SIMDJSON_SUPPORTS_CONCEPTS
2
3#ifndef SIMDJSON_ONDEMAND_DESERIALIZE_H
4#ifndef SIMDJSON_CONDITIONAL_INCLUDE
5#define SIMDJSON_ONDEMAND_DESERIALIZE_H
6#include "simdjson/generic/ondemand/object.h"
7#include "simdjson/generic/ondemand/array.h"
8#include "simdjson/generic/ondemand/base.h"
9#endif // SIMDJSON_CONDITIONAL_INCLUDE
10
11#include <concepts>
12#include <limits>
13#if SIMDJSON_STATIC_REFLECTION
14#include <meta>
15// #include <static_reflection> // for std::define_static_string - header not available yet
16#endif
17
18namespace simdjson {
19
21// Number deserialization
23
24template <std::unsigned_integral T>
25error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
26 using limits = std::numeric_limits<T>;
27
28 uint64_t x;
29 SIMDJSON_TRY(val.get_uint64().get(x));
30 if (x > (limits::max)()) {
32 }
33 out = static_cast<T>(x);
34 return SUCCESS;
35}
36
37template <std::floating_point T>
38error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
39 double x;
40 SIMDJSON_TRY(val.get_double().get(x));
41 out = static_cast<T>(x);
42 return SUCCESS;
43}
44
45template <std::signed_integral T>
46error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept {
47 using limits = std::numeric_limits<T>;
48
49 int64_t x;
50 SIMDJSON_TRY(val.get_int64().get(x));
51 if (x > (limits::max)() || x < (limits::min)()) {
53 }
54 out = static_cast<T>(x);
55 return SUCCESS;
56}
57
59// String deserialization
61
62// just a character!
63error_code tag_invoke(deserialize_tag, auto &val, char &out) noexcept {
64 std::string_view x;
65 SIMDJSON_TRY(val.get_string().get(x));
66 if(x.size() != 1) {
67 return INCORRECT_TYPE;
68 }
69 out = x[0];
70 return SUCCESS;
71}
72
73// any string-like type (can be constructed from std::string_view)
74template <concepts::constructible_from_string_view T, typename ValT>
75error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(std::is_nothrow_constructible_v<T, std::string_view>) {
76 std::string_view str;
77 SIMDJSON_TRY(val.get_string().get(str));
78 out = T{str};
79 return SUCCESS;
80}
81
82
90template <concepts::appendable_containers T, typename ValT>
91error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
92 using value_type = typename std::remove_cvref_t<T>::value_type;
93 static_assert(
94 deserializable<value_type, ValT>,
95 "The specified type inside the container must itself be deserializable");
96 static_assert(
97 std::is_default_constructible_v<value_type>,
98 "The specified type inside the container must default constructible.");
99 SIMDJSON_IMPLEMENTATION::ondemand::array arr;
100 if constexpr (std::is_same_v<std::remove_cvref_t<ValT>, SIMDJSON_IMPLEMENTATION::ondemand::array>) {
101 arr = val;
102 } else {
103 SIMDJSON_TRY(val.get_array().get(arr));
104 }
105
106 for (auto v : arr) {
107 if constexpr (concepts::returns_reference<T>) {
108 if (auto const err = v.get<value_type>().get(concepts::emplace_one(out));
109 err) {
110 // If an error occurs, the empty element that we just inserted gets
111 // removed. We're not using a temp variable because if T is a heavy
112 // type, we want the valid path to be the fast path and the slow path be
113 // the path that has errors in it.
114 if constexpr (requires { out.pop_back(); }) {
115 static_cast<void>(out.pop_back());
116 }
117 return err;
118 }
119 } else {
120 value_type temp;
121 if (auto const err = v.get<value_type>().get(temp); err) {
122 return err;
123 }
124 concepts::emplace_one(out, std::move(temp));
125 }
126 }
127 return SUCCESS;
128}
129
130
135 template <concepts::string_view_keyed_map T, typename ValT>
136error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(false) {
137 using value_type = typename std::remove_cvref_t<T>::mapped_type;
138 static_assert(
139 deserializable<value_type, ValT>,
140 "The specified value type inside the container must itself be deserializable");
141 static_assert(
142 std::is_default_constructible_v<value_type>,
143 "The specified value type inside the container must default constructible.");
144 SIMDJSON_IMPLEMENTATION::ondemand::object obj;
145 SIMDJSON_TRY(val.get_object().get(obj));
146 for (auto field : obj) {
147 std::string_view key;
148 SIMDJSON_TRY(field.unescaped_key().get(key));
149 value_type this_value;
150 SIMDJSON_TRY(field.value().get<value_type>().get(this_value));
151 [[maybe_unused]] std::pair<typename T::iterator, bool> result = out.emplace(key, this_value);
152 // unclear what to do if the key already exists
153 // if (result.second == false) {
154 // // key already exists
155 // }
156 }
157 (void)out;
158 return SUCCESS;
159}
160
161template <concepts::string_view_keyed_map T>
162error_code tag_invoke(deserialize_tag, SIMDJSON_IMPLEMENTATION::ondemand::object &obj, T &out) noexcept {
163 using value_type = typename std::remove_cvref_t<T>::mapped_type;
164
165 out.clear();
166 for (auto field : obj) {
167 std::string_view key;
168 SIMDJSON_TRY(field.unescaped_key().get(key));
169
170 SIMDJSON_IMPLEMENTATION::ondemand::value value_obj;
171 SIMDJSON_TRY(field.value().get(value_obj));
172
173 value_type this_value;
174 SIMDJSON_TRY(value_obj.get(this_value));
175 out.emplace(typename T::key_type(key), std::move(this_value));
176 }
177 return SUCCESS;
178}
179
180template <concepts::string_view_keyed_map T>
181error_code tag_invoke(deserialize_tag, SIMDJSON_IMPLEMENTATION::ondemand::value &val, T &out) noexcept {
182 SIMDJSON_IMPLEMENTATION::ondemand::object obj;
183 SIMDJSON_TRY(val.get_object().get(obj));
184 return simdjson::deserialize(obj, out);
185}
186
187template <concepts::string_view_keyed_map T>
188error_code tag_invoke(deserialize_tag, SIMDJSON_IMPLEMENTATION::ondemand::document &doc, T &out) noexcept {
189 SIMDJSON_IMPLEMENTATION::ondemand::object obj;
190 SIMDJSON_TRY(doc.get_object().get(obj));
191 return simdjson::deserialize(obj, out);
192}
193
194template <concepts::string_view_keyed_map T>
195error_code tag_invoke(deserialize_tag, SIMDJSON_IMPLEMENTATION::ondemand::document_reference &doc, T &out) noexcept {
196 SIMDJSON_IMPLEMENTATION::ondemand::object obj;
197 SIMDJSON_TRY(doc.get_object().get(obj));
198 return simdjson::deserialize(obj, out);
199}
200
201
216template <concepts::smart_pointer T, typename ValT>
217error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::element_type, ValT>) {
218 using element_type = typename std::remove_cvref_t<T>::element_type;
219
220 // For better error messages, don't use these as constraints on
221 // the tag_invoke CPO.
222 static_assert(
223 deserializable<element_type, ValT>,
224 "The specified type inside the unique_ptr must itself be deserializable");
225 static_assert(
226 std::is_default_constructible_v<element_type>,
227 "The specified type inside the unique_ptr must default constructible.");
228
229 auto ptr = new (std::nothrow) element_type();
230 if (ptr == nullptr) {
231 return MEMALLOC;
232 }
233 SIMDJSON_TRY(val.template get<element_type>(*ptr));
234 out.reset(ptr);
235 return SUCCESS;
236}
237
241template <concepts::optional_type T>
242error_code tag_invoke(deserialize_tag, auto &val, T &out) noexcept(nothrow_deserializable<typename std::remove_cvref_t<T>::value_type, decltype(val)>) {
243 using value_type = typename std::remove_cvref_t<T>::value_type;
244
245 // Check if the value is null
246 bool is_null_value;
247 SIMDJSON_TRY( val.is_null().get(is_null_value) );
248 if (is_null_value) {
249 out.reset(); // Set to nullopt
250 return SUCCESS;
251 }
252
253 if (!out) {
254 out.emplace();
255 }
256 SIMDJSON_TRY(val.template get<value_type>(out.value()));
257 return SUCCESS;
258}
259
260
261#if SIMDJSON_STATIC_REFLECTION
262
263
264template <typename T>
265constexpr bool user_defined_type = (std::is_class_v<T>
266&& !std::is_same_v<T, std::string> && !std::is_same_v<T, std::string_view> && !concepts::optional_type<T> &&
267!concepts::appendable_containers<T>);
268
269
270template <typename T, typename ValT>
271 requires(user_defined_type<T> && std::is_class_v<T>)
272error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept {
273 SIMDJSON_IMPLEMENTATION::ondemand::object obj;
274 if constexpr (std::is_same_v<std::remove_cvref_t<ValT>, SIMDJSON_IMPLEMENTATION::ondemand::object>) {
275 obj = val;
276 } else {
277 SIMDJSON_TRY(val.get_object().get(obj));
278 }
279 template for (constexpr auto mem : std::define_static_array(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::unchecked()))) {
280 if constexpr (!std::meta::is_const(mem) && std::meta::is_public(mem)) {
281 constexpr std::string_view key = std::define_static_string(std::meta::identifier_of(mem));
282 if constexpr (concepts::optional_type<decltype(out.[:mem:])>) {
283 // for optional members, it's ok if the key is missing
284 auto error = obj[key].get(out.[:mem:]);
285 if (error && error != NO_SUCH_FIELD) {
286 if(error == NO_SUCH_FIELD) {
287 out.[:mem:].reset();
288 continue;
289 }
290 return error;
291 }
292 } else {
293 // for non-optional members, the key must be present
294 SIMDJSON_TRY(obj[key].get(out.[:mem:]));
295 }
296 }
297 };
298 return simdjson::SUCCESS;
299}
300
301// Support for enum deserialization - deserialize from string representation using expand approach from P2996R12
302template <typename T, typename ValT>
303 requires(std::is_enum_v<T>)
304error_code tag_invoke(deserialize_tag, ValT &val, T &out) noexcept {
305#if SIMDJSON_STATIC_REFLECTION
306 std::string_view str;
307 SIMDJSON_TRY(val.get_string().get(str));
308 constexpr auto enumerators = std::define_static_array(std::meta::enumerators_of(^^T));
309 template for (constexpr auto enum_val : enumerators) {
310 if (str == std::meta::identifier_of(enum_val)) {
311 out = [:enum_val:];
312 return SUCCESS;
313 }
314 };
315
316 return INCORRECT_TYPE;
317#else
318 // Fallback: deserialize as integer if reflection not available
319 std::underlying_type_t<T> int_val;
320 SIMDJSON_TRY(val.get(int_val));
321 out = static_cast<T>(int_val);
322 return SUCCESS;
323#endif
324}
325
326template <typename simdjson_value, typename T>
327 requires(user_defined_type<std::remove_cvref_t<T>>)
328error_code tag_invoke(deserialize_tag, simdjson_value &val, std::unique_ptr<T> &out) noexcept {
329 if (!out) {
330 out = std::make_unique<T>();
331 if (!out) {
332 return MEMALLOC;
333 }
334 }
335 if (auto err = val.get(*out)) {
336 out.reset();
337 return err;
338 }
339 return SUCCESS;
340}
341
342template <typename simdjson_value, typename T>
343 requires(user_defined_type<std::remove_cvref_t<T>>)
344error_code tag_invoke(deserialize_tag, simdjson_value &val, std::shared_ptr<T> &out) noexcept {
345 if (!out) {
346 out = std::make_shared<T>();
347 if (!out) {
348 return MEMALLOC;
349 }
350 }
351 if (auto err = val.get(*out)) {
352 out.reset();
353 return err;
354 }
355 return SUCCESS;
356}
357
358#endif // SIMDJSON_STATIC_REFLECTION
359
361// Unique pointers
363error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<bool> &out) noexcept {
364 bool is_null_value;
365 SIMDJSON_TRY( val.is_null().get(is_null_value) );
366 if (is_null_value) {
367 out.reset();
368 return SUCCESS;
369 }
370 if (!out) {
371 out = std::make_unique<bool>();
372 if (!out) { return MEMALLOC; }
373 }
374 SIMDJSON_TRY(val.get_bool().get(*out));
375 return SUCCESS;
376}
377
378error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<int64_t> &out) noexcept {
379 bool is_null_value;
380 SIMDJSON_TRY( val.is_null().get(is_null_value) );
381 if (is_null_value) {
382 out.reset();
383 return SUCCESS;
384 }
385 if (!out) {
386 out = std::make_unique<int64_t>();
387 if (!out) { return MEMALLOC; }
388 }
389 SIMDJSON_TRY(val.get_int64().get(*out));
390 return SUCCESS;
391}
392
393error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<uint64_t> &out) noexcept {
394 bool is_null_value;
395 SIMDJSON_TRY( val.is_null().get(is_null_value) );
396 if (is_null_value) {
397 out.reset();
398 return SUCCESS;
399 }
400 if (!out) {
401 out = std::make_unique<uint64_t>();
402 if (!out) { return MEMALLOC; }
403 }
404 SIMDJSON_TRY(val.get_uint64().get(*out));
405 return SUCCESS;
406}
407
408error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<double> &out) noexcept {
409 bool is_null_value;
410 SIMDJSON_TRY( val.is_null().get(is_null_value) );
411 if (is_null_value) {
412 out.reset();
413 return SUCCESS;
414 }
415 if (!out) {
416 out = std::make_unique<double>();
417 if (!out) { return MEMALLOC; }
418 }
419 SIMDJSON_TRY(val.get_double().get(*out));
420 return SUCCESS;
421}
422
423error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string_view> &out) noexcept {
424 bool is_null_value;
425 SIMDJSON_TRY( val.is_null().get(is_null_value) );
426 if (is_null_value) {
427 out.reset();
428 return SUCCESS;
429 }
430 if (!out) {
431 out = std::make_unique<std::string_view>();
432 if (!out) { return MEMALLOC; }
433 }
434 SIMDJSON_TRY(val.get_string().get(*out));
435 return SUCCESS;
436}
437
438
440// Shared pointers
442error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<bool> &out) noexcept {
443 bool is_null_value;
444 SIMDJSON_TRY( val.is_null().get(is_null_value) );
445 if (is_null_value) {
446 out.reset();
447 return SUCCESS;
448 }
449 if (!out) {
450 out = std::make_shared<bool>();
451 if (!out) { return MEMALLOC; }
452 }
453 SIMDJSON_TRY(val.get_bool().get(*out));
454 return SUCCESS;
455}
456
457error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<int64_t> &out) noexcept {
458 bool is_null_value;
459 SIMDJSON_TRY( val.is_null().get(is_null_value) );
460 if (is_null_value) {
461 out.reset();
462 return SUCCESS;
463 }
464 if (!out) {
465 out = std::make_shared<int64_t>();
466 if (!out) { return MEMALLOC; }
467 }
468 SIMDJSON_TRY(val.get_int64().get(*out));
469 return SUCCESS;
470}
471
472error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<uint64_t> &out) noexcept {
473 bool is_null_value;
474 SIMDJSON_TRY( val.is_null().get(is_null_value) );
475 if (is_null_value) {
476 out.reset();
477 return SUCCESS;
478 }
479 if (!out) {
480 out = std::make_shared<uint64_t>();
481 if (!out) { return MEMALLOC; }
482 }
483 SIMDJSON_TRY(val.get_uint64().get(*out));
484 return SUCCESS;
485}
486
487error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<double> &out) noexcept {
488 bool is_null_value;
489 SIMDJSON_TRY( val.is_null().get(is_null_value) );
490 if (is_null_value) {
491 out.reset();
492 return SUCCESS;
493 }
494 if (!out) {
495 out = std::make_shared<double>();
496 if (!out) { return MEMALLOC; }
497 }
498 SIMDJSON_TRY(val.get_double().get(*out));
499 return SUCCESS;
500}
501
502error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string_view> &out) noexcept {
503 bool is_null_value;
504 SIMDJSON_TRY( val.is_null().get(is_null_value) );
505 if (is_null_value) {
506 out.reset();
507 return SUCCESS;
508 }
509 if (!out) {
510 out = std::make_shared<std::string_view>();
511 if (!out) { return MEMALLOC; }
512 }
513 SIMDJSON_TRY(val.get_string().get(*out));
514 return SUCCESS;
515}
516
517
519// Explicit optional specializations
521
523// Explicit smart pointer specializations for string and int types
525error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<std::string> &out) noexcept {
526 // Check if the value is null
527 bool is_null_value;
528 SIMDJSON_TRY( val.is_null().get(is_null_value) );
529 if (is_null_value) {
530 out.reset(); // Set to nullptr
531 return SUCCESS;
532 }
533
534 if (!out) {
535 out = std::make_unique<std::string>();
536 }
537 std::string_view str;
538 SIMDJSON_TRY(val.get_string().get(str));
539 *out = std::string{str};
540 return SUCCESS;
541}
542
543error_code tag_invoke(deserialize_tag, auto &val, std::shared_ptr<std::string> &out) noexcept {
544 // Check if the value is null
545 bool is_null_value;
546 SIMDJSON_TRY( val.is_null().get(is_null_value) );
547 if (is_null_value) {
548 out.reset(); // Set to nullptr
549 return SUCCESS;
550 }
551
552 if (!out) {
553 out = std::make_shared<std::string>();
554 }
555 std::string_view str;
556 SIMDJSON_TRY(val.get_string().get(str));
557 *out = std::string{str};
558 return SUCCESS;
559}
560
561error_code tag_invoke(deserialize_tag, auto &val, std::unique_ptr<int> &out) noexcept {
562 // Check if the value is null
563 bool is_null_value;
564 SIMDJSON_TRY( val.is_null().get(is_null_value) );
565 if (is_null_value) {
566 out.reset(); // Set to nullptr
567 return SUCCESS;
568 }
569
570 if (!out) {
571 out = std::make_unique<int>();
572 }
573 int64_t temp;
574 SIMDJSON_TRY(val.get_int64().get(temp));
575 *out = static_cast<int>(temp);
576 return SUCCESS;
577}
578
579} // namespace simdjson
580
581#endif // SIMDJSON_ONDEMAND_DESERIALIZE_H
582#endif // SIMDJSON_SUPPORTS_CONCEPTS
element_type
The actual concrete type of a JSON element This is the type it is most easily cast to with get<>.
Definition element.h:16
The top level simdjson namespace, containing everything the library provides.
Definition base.h:8
error_code
All possible errors returned by simdjson.
Definition error.h:19
@ INCORRECT_TYPE
JSON element has a different type than user expected.
Definition error.h:37
@ NO_SUCH_FIELD
JSON field not found in object.
Definition error.h:40
@ NUMBER_OUT_OF_RANGE
JSON number does not fit in 64 bits.
Definition error.h:38
@ MEMALLOC
Error allocating memory, most likely out of memory.
Definition error.h:22
@ SUCCESS
No error.
Definition error.h:20