join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
json.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_DATA_JSON_HPP
26#define JOIN_DATA_JSON_HPP
27
28// dconv.
29#include <dconv/probe.hpp>
30#include <dconv/atod.hpp>
31#include <dconv/dtoa.hpp>
32
33// libjoin.
35#include <join/value.hpp>
36#include <join/utf16.hpp>
37#include <join/utf8.hpp>
38#include <join/sax.hpp>
39
40// C++.
41#include <type_traits>
42#include <functional>
43#include <algorithm>
44#include <sstream>
45#include <fstream>
46#include <memory>
47#include <vector>
48
49// C.
50#include <cstring>
51#include <cstdint>
52
53namespace join
54{
55 namespace details
56 {
57 constexpr char digitPairs[201] = {
58 "00010203040506070809"
59 "10111213141516171819"
60 "20212223242526272829"
61 "30313233343536373839"
62 "40414243444546474849"
63 "50515253545556575859"
64 "60616263646566676869"
65 "70717273747576777879"
66 "80818283848586878889"
67 "90919293949596979899"};
68
70 {
71 uint8_t data[256];
72
73 constexpr UnescapedTable ()
74 : data{}
75 {
76 for (int i = 0; i < 32; ++i)
77 {
78 data[i] = 'u';
79 }
80 data[static_cast<unsigned char> ('\b')] = 'b';
81 data[static_cast<unsigned char> ('\t')] = 't';
82 data[static_cast<unsigned char> ('\n')] = 'n';
83 data[static_cast<unsigned char> ('\f')] = 'f';
84 data[static_cast<unsigned char> ('\r')] = 'r';
85 data[static_cast<unsigned char> ('"')] = '"';
86 data[static_cast<unsigned char> ('\\')] = '\\';
87 }
88 };
89
91
92 struct alignas (64) EscapedTable
93 {
94 uint8_t data[256];
95
96 constexpr EscapedTable ()
97 : data{}
98 {
99 for (unsigned i = 0; i < 0x20; ++i)
100 {
101 data[i] = 1;
102 }
103 data[static_cast<unsigned char> ('"')] = 1;
104 data[static_cast<unsigned char> ('\\')] = 1;
105 }
106 };
107
109
110 struct alignas (64) WhitespaceTable
111 {
112 uint8_t data[256];
113
114 constexpr WhitespaceTable ()
115 : data{}
116 {
117 data[static_cast<unsigned char> ('\t')] = 1;
118 data[static_cast<unsigned char> ('\n')] = 1;
119 data[static_cast<unsigned char> ('\r')] = 1;
120 data[static_cast<unsigned char> (' ')] = 1;
121 }
122 };
123
125
126 constexpr char hexDigits[17] = "0123456789abcdef";
127 }
128
145
149 class JsonCategory : public std::error_category
150 {
151 public:
156 virtual const char* name () const noexcept;
157
163 virtual std::string message (int code) const;
164 };
165
170 const std::error_category& jsonCategory () noexcept;
171
177 std::error_code make_error_code (JsonErrc code) noexcept;
178
184 std::error_condition make_error_condition (JsonErrc code) noexcept;
185
189 enum class JsonWriteMode
190 {
191 None,
192 Canonical,
193 };
194
198 template <JsonWriteMode WriteMode = JsonWriteMode::None>
200 {
201 public:
207 explicit BasicJsonWriter (std::ostream& document, size_t indentation = 0)
208 : _out (document.rdbuf ())
209 , _indentation ((WriteMode == JsonWriteMode::Canonical) ? 0 : indentation)
210 {
211 }
212
217 BasicJsonWriter (const BasicJsonWriter& other) = delete;
218
225
231
238
242 ~BasicJsonWriter () = default;
243
248 int setNull ()
249 {
250 array ();
251 append ("null", 4);
252 endValue ();
253 return 0;
254 }
255
261 int setBool (bool value)
262 {
263 array ();
264 if (value)
265 {
266 append ("true", 4);
267 }
268 else
269 {
270 append ("false", 5);
271 }
272 endValue ();
273 return 0;
274 }
275
281 int setInt (int32_t value)
282 {
283 array ();
284 writeInt (value);
285 endValue ();
286 return 0;
287 }
288
294 int setUint (uint32_t value)
295 {
296 array ();
297 writeUint (value);
298 endValue ();
299 return 0;
300 }
301
307 int setInt64 (int64_t value)
308 {
309 array ();
310 writeInt64 (value);
311 endValue ();
312 return 0;
313 }
314
320 int setUint64 (uint64_t value)
321 {
322 array ();
323 writeUint64 (value);
324 endValue ();
325 return 0;
326 }
327
333 template <JsonWriteMode Mode = WriteMode>
334 int setDouble (double value)
335 requires (Mode == JsonWriteMode::None)
336 {
337 array ();
338 uint64_t bits;
339 memcpy (&bits, &value, sizeof (bits));
340 const bool neg = (bits >> 63) != 0;
341 const uint64_t exp = (bits >> 52) & 0x7FFULL;
342 const uint64_t frac = bits & 0x000FFFFFFFFFFFFFULL;
343 if (exp != 0x7FFULL)
344 {
345 writeDouble (value);
346 }
347 else if (frac != 0)
348 {
349 if (neg)
350 {
351 append ("-NaN", 4);
352 }
353 else
354 {
355 append ("NaN", 3);
356 }
357 }
358 else
359 {
360 if (neg)
361 {
362 append ("-Inf", 4);
363 }
364 else
365 {
366 append ("Inf", 3);
367 }
368 }
369 endValue ();
370 return 0;
371 }
372
378 template <JsonWriteMode Mode = WriteMode>
379 int setDouble (double value)
380 requires (Mode == JsonWriteMode::Canonical)
381 {
382 array ();
383 if (std::isfinite (value))
384 {
385 if ((std::trunc (value) == value) && (value >= 0) &&
386 (value < static_cast<double> (std::numeric_limits<uint64_t>::max ())))
387 {
388 writeUint64 (static_cast<uint64_t> (value));
389 }
390 else if ((std::trunc (value) == value) &&
391 (value >= static_cast<double> (std::numeric_limits<int64_t>::min ())) &&
392 (value < static_cast<double> (std::numeric_limits<int64_t>::max ())))
393 {
394 writeInt64 (static_cast<int64_t> (value));
395 }
396 else
397 {
398 writeDouble (value);
399 }
400 }
401 else
402 {
403 append ("null", 4);
404 }
405 endValue ();
406 return 0;
407 }
408
414 int setString (std::string_view value)
415 {
416 if constexpr (WriteMode == JsonWriteMode::Canonical)
417 {
418 if (JOIN_UNLIKELY (utf8::validate (value.data (), value.data () + value.size ()) == -1))
419 {
421 reset ();
422 return -1;
423 }
424 }
425 array ();
426 append ('"');
427 writeEscaped (value);
428 append ('"');
429 endValue ();
430 return 0;
431 }
432
438 int startArray ([[maybe_unused]] uint32_t size = 0)
439 {
441 {
443 reset ();
444 return -1;
445 }
446 array ();
447 append ('[');
448 _arrays[_depth >> 6] |= 1ULL << (_depth & 63);
449 ++_depth;
450 _first = true;
451 return 0;
452 }
453
459 {
460 if (JOIN_UNLIKELY (_depth == 0))
461 {
463 reset ();
464 return -1;
465 }
466 --_depth;
467 if (!_first)
468 {
469 newLine ();
470 }
471 append (']');
472 endValue ();
473 return 0;
474 }
475
481 int startObject ([[maybe_unused]] uint32_t size = 0)
482 {
484 {
486 reset ();
487 return -1;
488 }
489 array ();
490 append ('{');
491 _arrays[_depth >> 6] &= ~(1ULL << (_depth & 63));
492 ++_depth;
493 _first = true;
494 return 0;
495 }
496
502 template <JsonWriteMode Mode = WriteMode>
503 const Object& members (const Object& object) const noexcept
504 requires (Mode == JsonWriteMode::None)
505 {
506 return object;
507 }
508
514 template <JsonWriteMode Mode = WriteMode>
515 std::vector<std::reference_wrapper<const Member>> members (const Object& object) const
516 requires (Mode == JsonWriteMode::Canonical)
517 {
518 std::vector<std::reference_wrapper<const Member>> sorted (object.begin (), object.end ());
519 std::sort (sorted.begin (), sorted.end (), [] (const Member& a, const Member& b) {
520 if (!a.first.isString () || !b.first.isString ())
521 {
522 return !a.first.isString () && b.first.isString ();
523 }
524 std::string_view sa = a.first.getString ();
525 std::string_view sb = b.first.getString ();
526 return utf8::compareUtf16Order (sa.data (), sa.data () + sa.size (), sb.data (),
527 sb.data () + sb.size ()) < 0;
528 });
529 return sorted;
530 }
531
537 int setKey ([[maybe_unused]] std::nullptr_t key)
538 {
540 reset ();
541 return -1;
542 }
543
549 int setKey ([[maybe_unused]] bool key)
550 {
552 reset ();
553 return -1;
554 }
555
561 int setKey ([[maybe_unused]] int32_t key)
562 {
564 reset ();
565 return -1;
566 }
567
573 int setKey ([[maybe_unused]] uint32_t key)
574 {
576 reset ();
577 return -1;
578 }
579
585 int setKey ([[maybe_unused]] int64_t key)
586 {
588 reset ();
589 return -1;
590 }
591
597 int setKey ([[maybe_unused]] uint64_t key)
598 {
600 reset ();
601 return -1;
602 }
603
609 int setKey ([[maybe_unused]] double key)
610 {
612 reset ();
613 return -1;
614 }
615
621 int setKey (std::string_view key)
622 {
623 if (JOIN_UNLIKELY (_depth == 0))
624 {
626 reset ();
627 return -1;
628 }
629 if constexpr (WriteMode == JsonWriteMode::Canonical)
630 {
631 if (JOIN_UNLIKELY (utf8::validate (key.data (), key.data () + key.size ()) == -1))
632 {
634 reset ();
635 return -1;
636 }
637 }
638 comma ();
639 newLine ();
640 append ('"');
641 writeEscaped (key);
642 append ('"');
643 append (':');
644 space ();
645 _first = true;
646 return 0;
647 }
648
654 int setKey (const char* key)
655 {
656 return setKey (std::string_view (key));
657 }
658
664 {
665 if (JOIN_UNLIKELY (_depth == 0))
666 {
668 reset ();
669 return -1;
670 }
671 --_depth;
672 if (!_first)
673 {
674 newLine ();
675 }
676 append ('}');
677 endValue ();
678 return 0;
679 }
680
684 void flush ()
685 {
686 if (_size)
687 {
688 _out->sputn (_buffer, _size);
689 _size = 0;
690 }
691 }
692
696 void reset () noexcept
697 {
698 _size = 0;
699 _depth = 0;
700 _first = true;
701 }
702
703 protected:
708 void writeInt (int32_t value)
709 {
710 if (value == std::numeric_limits<int32_t>::min ())
711 {
712 append ('-');
713 writeUint64 (static_cast<uint64_t> (std::numeric_limits<int32_t>::max ()) + 1);
714 return;
715 }
716
717 if (value < 0)
718 {
719 append ('-');
720 writeUint64 (static_cast<uint64_t> (-value));
721 return;
722 }
723
724 writeUint64 (static_cast<uint64_t> (value));
725 }
726
731 void writeUint (uint32_t value)
732 {
733 writeUint64 (static_cast<uint64_t> (value));
734 }
735
740 void writeInt64 (int64_t value)
741 {
742 if (value == std::numeric_limits<int64_t>::min ())
743 {
744 append ('-');
745 writeUint64 (static_cast<uint64_t> (std::numeric_limits<int64_t>::max ()) + 1);
746 return;
747 }
748
749 if (value < 0)
750 {
751 append ('-');
752 writeUint64 (static_cast<uint64_t> (-value));
753 return;
754 }
755
756 writeUint64 (static_cast<uint64_t> (value));
757 }
758
763 void writeUint64 (uint64_t value)
764 {
765 static constexpr uint64_t pow10[20] = {1ULL,
766 10ULL,
767 100ULL,
768 1000ULL,
769 10000ULL,
770 100000ULL,
771 1000000ULL,
772 10000000ULL,
773 100000000ULL,
774 1000000000ULL,
775 10000000000ULL,
776 100000000000ULL,
777 1000000000000ULL,
778 10000000000000ULL,
779 100000000000000ULL,
780 1000000000000000ULL,
781 10000000000000000ULL,
782 100000000000000000ULL,
783 1000000000000000000ULL,
784 10000000000000000000ULL};
785
786 uint64_t high = value / 100000000;
787 uint64_t top = high / 100000000;
788 uint32_t mid = static_cast<uint32_t> (high - top * 100000000);
789 uint32_t low = static_cast<uint32_t> (value - high * 100000000);
790
791 char buffer[40];
792 std::memcpy (buffer, &details::digitPairs[(top / 100) * 2], 2);
793 std::memcpy (buffer + 2, &details::digitPairs[(top % 100) * 2], 2);
794 std::memcpy (buffer + 4, &details::digitPairs[(mid / 1000000) * 2], 2);
795 std::memcpy (buffer + 6, &details::digitPairs[(mid / 10000 % 100) * 2], 2);
796 std::memcpy (buffer + 8, &details::digitPairs[(mid / 100 % 100) * 2], 2);
797 std::memcpy (buffer + 10, &details::digitPairs[(mid % 100) * 2], 2);
798 std::memcpy (buffer + 12, &details::digitPairs[(low / 1000000) * 2], 2);
799 std::memcpy (buffer + 14, &details::digitPairs[(low / 10000 % 100) * 2], 2);
800 std::memcpy (buffer + 16, &details::digitPairs[(low / 100 % 100) * 2], 2);
801 std::memcpy (buffer + 18, &details::digitPairs[(low % 100) * 2], 2);
802
803 size_t length = ((64 - __builtin_clzll (value | 1)) * 1233) >> 12;
804 length += (value >= pow10[length]) + (value == 0);
805
806 appendDigits (buffer + 20 - length, length);
807 }
808
813 void writeDouble (double value)
814 {
815 if constexpr (WriteMode == JsonWriteMode::Canonical)
816 {
817 char buf[25];
818 char* end = dconv::dtoa (buf, value);
819 for (char* pos = buf; pos < end; ++pos)
820 {
821 append (*pos);
822 if ((*pos == 'e') && (*(pos + 1) != '-'))
823 {
824 append ('+');
825 }
826 }
827 }
828 else
829 {
830 if (JOIN_UNLIKELY (sizeof (_buffer) - _size < 25))
831 {
832 flush ();
833 }
834 _size = dconv::dtoa (_buffer + _size, value) - _buffer;
835 }
836 }
837
842 void writeEscaped (std::string_view value)
843 {
844 const char* cur = value.data ();
845 const char* end = cur + value.size ();
846
847 while (cur != end)
848 {
849 const char* beg = cur;
850
851 while (end - cur >= 8)
852 {
853 uint64_t word, quote, backslash;
854 std::memcpy (&word, cur, 8);
855 quote = word ^ 0x2222222222222222ULL;
856 backslash = word ^ 0x5C5C5C5C5C5C5C5CULL;
857 uint64_t mask = (((quote - 0x0101010101010101ULL) & ~quote) |
858 ((backslash - 0x0101010101010101ULL) & ~backslash) |
859 ((word - 0x2020202020202020ULL) & ~word)) &
860 0x8080808080808080ULL;
861 if (mask)
862 {
863 cur += __builtin_ctzll (mask) >> 3;
864 break;
865 }
866 cur += 8;
867 }
868
869 while (cur != end && details::unescapedLookup.data[static_cast<uint8_t> (*cur)] == 0)
870 {
871 ++cur;
872 }
873
874 if (cur != beg)
875 {
876 append (beg, cur - beg);
877 }
878
879 if (cur == end)
880 {
881 break;
882 }
883
884 uint8_t ch = static_cast<uint8_t> (*cur);
885 uint8_t esc = details::unescapedLookup.data[ch];
886 if (esc == 'u')
887 {
888 char seq[6] = {'\\', 'u', '0', '0', details::hexDigits[ch >> 4], details::hexDigits[ch & 0xF]};
889 append (seq, 6);
890 }
891 else
892 {
893 char escapeSeq[2] = {'\\', static_cast<char> (esc)};
894 append (escapeSeq, 2);
895 }
896
897 ++cur;
898 }
899 }
900
905 inline void append (char data)
906 {
907 if (JOIN_UNLIKELY (_size == sizeof (_buffer)))
908 {
909 flush ();
910 }
911 _buffer[_size++] = data;
912 }
913
919 inline void append (const char* data, uint32_t size)
920 {
921 if (JOIN_UNLIKELY (size > sizeof (_buffer) - _size))
922 {
923 flush ();
924 if (size >= sizeof (_buffer))
925 {
926 _out->sputn (data, size);
927 return;
928 }
929 }
930 std::memcpy (_buffer + _size, data, size);
931 _size += size;
932 }
933
939 inline void appendDigits (const char* digits, size_t length)
940 {
941 if (JOIN_UNLIKELY (sizeof (_buffer) - _size < 20))
942 {
943 flush ();
944 }
945 std::memcpy (_buffer + _size, digits, 20);
946 _size += length;
947 }
948
952 inline void comma ()
953 {
954 if (_depth && !_first)
955 {
956 append (',');
957 }
958 }
959
963 inline void endLine ()
964 {
965 append ('\n');
966 }
967
971 inline void indent ()
972 {
973 static constexpr char spaces[] = " ";
974 size_t count = _depth * _indentation;
975 while (count)
976 {
977 size_t n = (count < sizeof (spaces) - 1) ? count : sizeof (spaces) - 1;
978 append (spaces, n);
979 count -= n;
980 }
981 }
982
986 inline void newLine ()
987 {
988 if (_indentation)
989 {
990 indentLine ();
991 }
992 }
993
997 __attribute__ ((noinline)) void indentLine ()
998 {
999 static constexpr char spaces[] = "\n ";
1000 size_t count = _depth * _indentation;
1001 if (JOIN_LIKELY (count < sizeof (spaces) - 1))
1002 {
1003 if (JOIN_UNLIKELY (sizeof (_buffer) - _size < sizeof (spaces) - 1))
1004 {
1005 flush ();
1006 }
1007 std::memcpy (_buffer + _size, spaces, sizeof (spaces) - 1);
1008 _size += count + 1;
1009 return;
1010 }
1011 endLine ();
1012 indent ();
1013 }
1014
1018 inline void space ()
1019 {
1020 if (_indentation)
1021 {
1022 append (' ');
1023 }
1024 }
1025
1029 inline void array ()
1030 {
1031 comma ();
1032 if (_depth && ((_arrays[(_depth - 1) >> 6] >> ((_depth - 1) & 63)) & 1))
1033 {
1034 newLine ();
1035 }
1036 }
1037
1041 inline void endValue ()
1042 {
1043 _first = false;
1044 if (_depth == 0)
1045 {
1046 flush ();
1047 }
1048 }
1049
1051 std::streambuf* _out;
1052
1054 char _buffer[1024] = {};
1055
1057 size_t _size = 0;
1058
1060 uint64_t _arrays[saxMaxDepth / 64] = {};
1061
1063 size_t _depth = 0;
1064
1067
1069 bool _first = true;
1070 };
1071
1074
1077
1082 {
1083 None = 0,
1084 ParseComments = 1L << 0,
1087 };
1088
1095 constexpr JsonReadMode operator& (JsonReadMode a, JsonReadMode b) noexcept
1096 {
1097 return JsonReadMode (static_cast<int> (a) & static_cast<int> (b));
1098 }
1099
1106 constexpr JsonReadMode operator| (JsonReadMode a, JsonReadMode b) noexcept
1107 {
1108 return JsonReadMode (static_cast<int> (a) | static_cast<int> (b));
1109 }
1110
1117 constexpr const JsonReadMode& operator&= (JsonReadMode& a, JsonReadMode b) noexcept
1118 {
1119 return a = a & b;
1120 }
1121
1128 constexpr const JsonReadMode& operator|= (JsonReadMode& a, JsonReadMode b) noexcept
1129 {
1130 return a = a | b;
1131 }
1132
1136 template <JsonReadMode ReadMode = JsonReadMode::None>
1138 {
1139 public:
1143 BasicJsonReader () = default;
1144
1149 BasicJsonReader (const BasicJsonReader& other) = delete;
1150
1156 BasicJsonReader& operator= (const BasicJsonReader& other) = delete;
1157
1163
1169 BasicJsonReader& operator= (BasicJsonReader&& other) = delete;
1170
1174 ~BasicJsonReader () = default;
1175
1183 template <typename Handler>
1184 int deserialize (const char* document, size_t length, Handler& handler)
1185 {
1186 dconv::StringProbe in (document, length);
1187 return read (in, handler);
1188 }
1189
1197 template <typename Handler>
1198 int deserialize (const char* first, const char* last, Handler& handler)
1199 {
1200 dconv::StringProbe in (first, last);
1201 return read (in, handler);
1202 }
1203
1210 template <typename Handler>
1211 int deserialize (std::string_view document, Handler& handler)
1212 {
1213 dconv::StringProbe in (document.data (), document.size ());
1214 return read (in, handler);
1215 }
1216
1223 template <typename Handler>
1224 int deserialize (std::stringstream& document, Handler& handler)
1225 {
1226 dconv::StreamProbe in (document);
1227 return read (in, handler);
1228 }
1229
1236 template <typename Handler>
1237 int deserialize (std::istringstream& document, Handler& handler)
1238 {
1239 dconv::StreamProbe in (document);
1240 return read (in, handler);
1241 }
1242
1249 template <typename Handler>
1250 int deserialize (std::fstream& document, Handler& handler)
1251 {
1252 dconv::StreamProbe in (document);
1253 return read (in, handler);
1254 }
1255
1262 template <typename Handler>
1263 int deserialize (std::ifstream& document, Handler& handler)
1264 {
1265 dconv::StreamProbe in (document);
1266 return read (in, handler);
1267 }
1268
1275 template <typename Handler>
1276 int deserialize (std::iostream& document, Handler& handler)
1277 {
1278 dconv::StreamProbe in (document);
1279 return read (in, handler);
1280 }
1281
1288 template <typename Handler>
1289 int deserialize (std::istream& document, Handler& handler)
1290 {
1291 dconv::StreamProbe in (document);
1292 return read (in, handler);
1293 }
1294
1295 protected:
1302 template <typename ProbeType>
1303 int read (ProbeType& document, Value& value)
1304 {
1305 return read (document, ValueBuilder (value));
1306 }
1307
1314 template <typename ProbeType, typename Handler>
1315 int read (ProbeType& document, Handler&& handler)
1316 {
1317 try
1318 {
1319 if (JOIN_LIKELY (readDocument (document, handler) == 0))
1320 {
1321 return 0;
1322 }
1323 }
1324 catch (...)
1325 {
1326 handler.reset ();
1327 throw;
1328 }
1329 handler.reset ();
1330 return -1;
1331 }
1332
1339 template <typename ProbeType, typename Handler>
1340 int readDocument (ProbeType& document, Handler& handler)
1341 {
1342 if (skipWhitespaces (document) != 0)
1343 {
1344 return -1;
1345 }
1346
1347 if (readValue (document, handler, 0) != 0)
1348 {
1349 return -1;
1350 }
1351
1352 if (ReadMode & JsonReadMode::StopParsingOnDone)
1353 {
1354 return 0;
1355 }
1356
1357 if (skipWhitespaces (document) != 0)
1358 {
1359 return -1;
1360 }
1361
1362 if (document.peek () != std::char_traits<char>::eof ())
1363 {
1364 join::lastError = make_error_code (SaxErrc::ExtraData);
1365 return -1;
1366 }
1367
1368 return 0;
1369 }
1370
1378 template <typename ProbeType, typename Handler>
1379 int readValue (ProbeType& document, Handler& handler, size_t depth)
1380 {
1381 int ch = document.peek ();
1382 switch (ch)
1383 {
1384 case '[':
1385 document.get ();
1386 return readArray (document, handler, depth);
1387 case '{':
1388 document.get ();
1389 return readObject (document, handler, depth);
1390 case '"':
1391 document.get ();
1392 return readString (document, handler);
1393 case 'n':
1394 document.get ();
1395 return readNull (document, handler);
1396 case 't':
1397 document.get ();
1398 return readTrue (document, handler);
1399 case 'f':
1400 document.get ();
1401 return readFalse (document, handler);
1402 default:
1403 return readNumber (document, handler);
1404 }
1405 }
1406
1413 template <typename ProbeType, typename Handler>
1414 int readNull (ProbeType& document, Handler& handler)
1415 {
1416 if (JOIN_UNLIKELY ((document.get () != 'u') || (document.get () != 'l') || (document.get () != 'l')))
1417 {
1418 join::lastError = make_error_code (SaxErrc::InvalidValue);
1419 return -1;
1420 }
1421
1422 return handler.setNull ();
1423 }
1424
1431 template <typename ProbeType, typename Handler>
1432 int readTrue (ProbeType& document, Handler& handler)
1433 {
1434 if (JOIN_UNLIKELY ((document.get () != 'r') || (document.get () != 'u') || (document.get () != 'e')))
1435 {
1436 join::lastError = make_error_code (SaxErrc::InvalidValue);
1437 return -1;
1438 }
1439
1440 return handler.setBool (true);
1441 }
1442
1449 template <typename ProbeType, typename Handler>
1450 int readFalse (ProbeType& document, Handler& handler)
1451 {
1452 if (JOIN_UNLIKELY ((document.get () != 'a') || (document.get () != 'l') || (document.get () != 's') ||
1453 (document.get () != 'e')))
1454 {
1455 join::lastError = make_error_code (SaxErrc::InvalidValue);
1456 return -1;
1457 }
1458
1459 return handler.setBool (false);
1460 }
1461
1468 template <typename ProbeType, typename Handler>
1469 int readNumber (ProbeType& document, Handler& handler)
1470 {
1471 double value = 0.0;
1472 uint64_t significand = 0;
1473 int64_t exponent = 0;
1474 bool negative = false;
1475 std::error_code ec;
1476
1477 if (JOIN_LIKELY (dconv::atod (document, value, significand, exponent, negative, ec) == 0))
1478 {
1479 return handler.setDouble (value);
1480 }
1481
1482 if (JOIN_UNLIKELY (ec != dconv::Errc::NotDouble))
1483 {
1484 join::lastError = make_error_code (SaxErrc::InvalidValue);
1485 return -1;
1486 }
1487
1488 if (!negative)
1489 {
1490 return handler.setUint64 (significand);
1491 }
1492
1493 if (significand <= static_cast<uint64_t> (std::numeric_limits<int64_t>::max ()) + 1)
1494 {
1495 return handler.setInt64 (static_cast<int64_t> (-significand));
1496 }
1497
1498 return handler.setDouble (-static_cast<double> (significand));
1499 }
1500
1507 template <typename ProbeType>
1508 inline int readHex (ProbeType& document, uint32_t& u)
1509 {
1510 for (int i = 0; i < 4; ++i)
1511 {
1512 char c = document.get ();
1513
1514 if (isDigit (c))
1515 {
1516 c -= '0';
1517 }
1518 else if (isUpperAlpha (c))
1519 {
1520 c = c - 'A' + 10;
1521 }
1522 else if (isLowerAlpha (c))
1523 {
1524 c = c - 'a' + 10;
1525 }
1526 else
1527 {
1528 join::lastError = make_error_code (JsonErrc::InvalidEncoding);
1529 return -1;
1530 }
1531
1532 u = (u << 4) + c;
1533 }
1534
1535 return 0;
1536 }
1537
1544 template <typename ProbeType>
1545 inline int readUnicode (ProbeType& document, std::string& output)
1546 {
1547 uint32_t u = 0;
1548
1549 if (readHex (document, u) == -1)
1550 {
1551 return -1;
1552 }
1553
1554 char16_t units[2] = {static_cast<char16_t> (u), 0};
1555 const char16_t* cur = units;
1556 const char16_t* end = units + 1;
1557
1558 if (utf16::isHighSurrogate (u))
1559 {
1560 if ((document.get () != '\\') || (document.get () != 'u'))
1561 {
1562 join::lastError = make_error_code (JsonErrc::InvalidEncoding);
1563 return -1;
1564 }
1565
1566 uint32_t v = 0;
1567
1568 if (readHex (document, v) == -1)
1569 {
1570 join::lastError = make_error_code (JsonErrc::InvalidEncoding);
1571 return -1;
1572 }
1573
1574 units[1] = static_cast<char16_t> (v);
1575 ++end;
1576 }
1577
1578 if (utf16::decode (cur, end, u) == -1)
1579 {
1580 join::lastError = make_error_code (JsonErrc::InvalidEncoding);
1581 return -1;
1582 }
1583
1584 char buf[4];
1585 output.append (buf, utf8::encode (u, buf));
1586
1587 return 0;
1588 }
1589
1596 template <typename ProbeType>
1597 inline int readEscaped (ProbeType& document, std::string& output)
1598 {
1599 int ch = document.get ();
1600 switch (ch)
1601 {
1602 case '"':
1603 output.push_back ('"');
1604 break;
1605 case '\\':
1606 output.push_back ('\\');
1607 break;
1608 case '/':
1609 output.push_back ('/');
1610 break;
1611 case 'b':
1612 output.push_back ('\b');
1613 break;
1614 case 'f':
1615 output.push_back ('\f');
1616 break;
1617 case 'n':
1618 output.push_back ('\n');
1619 break;
1620 case 'r':
1621 output.push_back ('\r');
1622 break;
1623 case 't':
1624 output.push_back ('\t');
1625 break;
1626 case 'u':
1627 return readUnicode (document, output);
1628 default:
1629 join::lastError = make_error_code (JsonErrc::InvalidEscaping);
1630 return -1;
1631 }
1632
1633 return 0;
1634 }
1635
1643 template <typename ProbeType, typename Handler>
1644 int readString (ProbeType& document, Handler& handler, bool isKey = false)
1645 {
1646 std::string_view chunk;
1647
1648 if constexpr (std::is_same_v<ProbeType, dconv::StringProbe>)
1649 {
1650 chunk = readUntilEscaped (document);
1651
1652 if (JOIN_UNLIKELY (validateChunk (chunk) == -1))
1653 {
1654 return -1;
1655 }
1656
1657 if (JOIN_LIKELY (document.peek () == '"'))
1658 {
1659 document.get ();
1660 return isKey ? handler.setKey (chunk) : handler.setString (chunk);
1661 }
1662 }
1663
1664 thread_local std::string cache;
1665 std::string output = std::move (cache);
1666 output.assign (chunk);
1667
1668 for (;;)
1669 {
1670 size_t pos = output.size ();
1671 readUntilEscaped (document, output);
1672
1673 if (JOIN_UNLIKELY (validateChunk (std::string_view (output).substr (pos)) == -1))
1674 {
1675 return -1;
1676 }
1677
1678 int ch = document.peek ();
1679
1680 if (ch == '"')
1681 {
1682 document.get ();
1683 break;
1684 }
1685
1686 if (ch == '\\')
1687 {
1688 document.get ();
1689 if (readEscaped (document, output) == -1)
1690 {
1691 return -1;
1692 }
1693 continue;
1694 }
1695
1696 if (ch < 0x20)
1697 {
1698 join::lastError = make_error_code (JsonErrc::IllegalCharacter);
1699 return -1;
1700 }
1701 }
1702
1703 int result = isKey ? handler.setKey (output) : handler.setString (output);
1704 cache = std::move (output);
1705 return result;
1706 }
1707
1715 template <typename ProbeType, typename Handler>
1716 JOIN_ALWAYS_INLINE int readArray (ProbeType& document, Handler& handler, size_t depth)
1717 {
1718 if (JOIN_UNLIKELY (depth == saxMaxDepth))
1719 {
1720 join::lastError = make_error_code (SaxErrc::StackOverflow);
1721 return -1;
1722 }
1723
1724 if (JOIN_UNLIKELY (handler.startArray () == -1))
1725 {
1726 return -1;
1727 }
1728
1729 if (JOIN_UNLIKELY (skipWhitespaces (document) == -1))
1730 {
1731 return -1;
1732 }
1733
1734 if (document.getIf (']'))
1735 {
1736 return handler.stopArray ();
1737 }
1738
1739 for (;;)
1740 {
1741 if (JOIN_UNLIKELY (readValue (document, handler, depth + 1) == -1))
1742 {
1743 return -1;
1744 }
1745
1746 int ch = document.get ();
1747
1748 if (JOIN_UNLIKELY (details::whitespaceLookup.data[static_cast<unsigned char> (ch)]))
1749 {
1750 if (JOIN_UNLIKELY (skipWhitespaces (document) == -1))
1751 {
1752 return -1;
1753 }
1754 ch = document.get ();
1755 }
1756
1757 if (JOIN_LIKELY (ch == ','))
1758 {
1759 if (JOIN_UNLIKELY (skipWhitespaces (document) == -1))
1760 {
1761 return -1;
1762 }
1763 continue;
1764 }
1765
1766 if (JOIN_LIKELY (ch == ']'))
1767 {
1768 break;
1769 }
1770
1771 join::lastError = make_error_code (JsonErrc::MissingComma);
1772 return -1;
1773 }
1774
1775 return handler.stopArray ();
1776 }
1777
1785 template <typename ProbeType, typename Handler>
1786 JOIN_ALWAYS_INLINE int readObject (ProbeType& document, Handler& handler, size_t depth)
1787 {
1788 if (JOIN_UNLIKELY (depth == saxMaxDepth))
1789 {
1790 join::lastError = make_error_code (SaxErrc::StackOverflow);
1791 return -1;
1792 }
1793
1794 if (JOIN_UNLIKELY (handler.startObject () == -1))
1795 {
1796 return -1;
1797 }
1798
1799 if (JOIN_UNLIKELY (skipWhitespaces (document) == -1))
1800 {
1801 return -1;
1802 }
1803
1804 if (document.getIf ('}'))
1805 {
1806 return handler.stopObject ();
1807 }
1808
1809 for (;;)
1810 {
1811 if (JOIN_UNLIKELY (document.get () != '"'))
1812 {
1813 join::lastError = make_error_code (JsonErrc::MissingQuote);
1814 return -1;
1815 }
1816
1817 if (JOIN_UNLIKELY (readString (document, handler, true) == -1))
1818 {
1819 return -1;
1820 }
1821
1822 if (document.peek () != ':')
1823 {
1824 if (JOIN_UNLIKELY (skipWhitespaces (document) == -1))
1825 {
1826 return -1;
1827 }
1828 }
1829
1830 if (JOIN_UNLIKELY (document.get () != ':'))
1831 {
1832 join::lastError = make_error_code (JsonErrc::MissingColon);
1833 return -1;
1834 }
1835
1836 if (JOIN_UNLIKELY (skipWhitespaces (document) == -1))
1837 {
1838 return -1;
1839 }
1840
1841 if (JOIN_UNLIKELY (readValue (document, handler, depth + 1) == -1))
1842 {
1843 return -1;
1844 }
1845
1846 int ch = document.get ();
1847
1848 if (JOIN_UNLIKELY (details::whitespaceLookup.data[static_cast<unsigned char> (ch)]))
1849 {
1850 if (JOIN_UNLIKELY (skipWhitespaces (document) == -1))
1851 {
1852 return -1;
1853 }
1854 ch = document.get ();
1855 }
1856
1857 if (JOIN_LIKELY (ch == ','))
1858 {
1859 if (JOIN_UNLIKELY (skipWhitespaces (document) == -1))
1860 {
1861 return -1;
1862 }
1863 continue;
1864 }
1865
1866 if (JOIN_LIKELY (ch == '}'))
1867 {
1868 break;
1869 }
1870
1871 join::lastError = make_error_code (JsonErrc::MissingComma);
1872 return -1;
1873 }
1874
1875 return handler.stopObject ();
1876 }
1877
1883 inline std::string_view readUntilEscaped (dconv::StringProbe& document) noexcept
1884 {
1885 const char* beg = document.tell ();
1886 const char* cur = beg;
1887 const char* end = document.end ();
1888
1889 while (end - cur >= 8)
1890 {
1891 uint64_t word, quote, backslash;
1892 std::memcpy (&word, cur, 8);
1893 quote = word ^ 0x2222222222222222ULL;
1894 backslash = word ^ 0x5C5C5C5C5C5C5C5CULL;
1895 uint64_t mask =
1896 (((quote - 0x0101010101010101ULL) & ~quote) | ((backslash - 0x0101010101010101ULL) & ~backslash) |
1897 ((word - 0x2020202020202020ULL) & ~word)) &
1898 0x8080808080808080ULL;
1899 if (mask)
1900 {
1901 cur += __builtin_ctzll (mask) >> 3;
1902 break;
1903 }
1904 cur += 8;
1905 }
1906
1907 while (cur < end && !details::escapedLookup.data[static_cast<unsigned char> (*cur)])
1908 {
1909 ++cur;
1910 }
1911
1912 document.seek (cur);
1913 return std::string_view (beg, static_cast<size_t> (cur - beg));
1914 }
1915
1921 inline void readUntilEscaped (dconv::StringProbe& document, std::string& out) noexcept
1922 {
1923 out.append (readUntilEscaped (document));
1924 }
1925
1931 inline void readUntilEscaped (dconv::StreamProbe& document, std::string& out) noexcept
1932 {
1933 int c;
1934 while ((c = document.peek ()) != std::char_traits<char>::eof () &&
1935 !details::escapedLookup.data[static_cast<unsigned char> (c)])
1936 {
1937 out.push_back (static_cast<char> (c));
1938 document.get ();
1939 }
1940 }
1941
1947 inline int skipWhitespaces (dconv::StringProbe& document) noexcept
1948 {
1949 if constexpr (ReadMode & JsonReadMode::ParseComments)
1950 {
1951 return skipWhitespacesAndComments (document);
1952 }
1953
1954 const char* cur = document.tell ();
1955 const char* end = document.end ();
1956
1957 while (cur < end && details::whitespaceLookup.data[static_cast<unsigned char> (*cur)])
1958 {
1959 ++cur;
1960
1961 while (end - cur >= 8)
1962 {
1963 uint64_t word;
1964 std::memcpy (&word, cur, 8);
1965 word ^= 0x2020202020202020ULL;
1966 if (word != 0)
1967 {
1968 cur += __builtin_ctzll (word) >> 3;
1969 break;
1970 }
1971 cur += 8;
1972 }
1973 }
1974
1975 document.seek (cur);
1976
1977 return 0;
1978 }
1979
1985 inline int skipWhitespaces (dconv::StreamProbe& document) noexcept
1986 {
1987 if constexpr (ReadMode & JsonReadMode::ParseComments)
1988 {
1989 return skipWhitespacesAndComments (document);
1990 }
1991
1992 int c;
1993 while ((c = document.peek ()) != std::char_traits<char>::eof () &&
1994 details::whitespaceLookup.data[static_cast<unsigned char> (c)])
1995 {
1996 document.get ();
1997 }
1998
1999 return 0;
2000 }
2001
2007 inline int skipWhitespacesAndComments (dconv::StringProbe& document) noexcept
2008 {
2009 const char* cur = document.tell ();
2010 const char* end = document.end ();
2011
2012 while (cur < end)
2013 {
2014 while (cur < end && details::whitespaceLookup.data[static_cast<unsigned char> (*cur)])
2015 {
2016 ++cur;
2017 }
2018
2019 if (cur >= end || *cur != '/')
2020 {
2021 break;
2022 }
2023
2024 if (++cur >= end)
2025 {
2026 return -1;
2027 }
2028
2029 if (*cur == '*')
2030 {
2031 ++cur;
2032 bool closed = false;
2033 while (cur < end)
2034 {
2035 if (*cur == '*' && (cur + 1 < end) && *(cur + 1) == '/')
2036 {
2037 cur += 2;
2038 closed = true;
2039 break;
2040 }
2041 ++cur;
2042 }
2043 if (!closed)
2044 {
2045 return -1;
2046 }
2047 }
2048 else if (*cur == '/')
2049 {
2050 ++cur;
2051 const char* p = static_cast<const char*> (std::memchr (cur, '\n', end - cur));
2052 cur = p ? p : end;
2053 }
2054 else
2055 {
2056 return -1;
2057 }
2058 }
2059
2060 document.seek (cur);
2061
2062 return 0;
2063 }
2064
2070 inline int skipWhitespacesAndComments (dconv::StreamProbe& document) noexcept
2071 {
2072 int c;
2073
2074 while ((c = document.peek ()) != std::char_traits<char>::eof ())
2075 {
2076 while ((c = document.peek ()) != std::char_traits<char>::eof () &&
2077 details::whitespaceLookup.data[static_cast<unsigned char> (c)])
2078 {
2079 document.get ();
2080 }
2081
2082 if (c != '/')
2083 {
2084 break;
2085 }
2086
2087 document.get ();
2088 c = document.peek ();
2089
2090 if (c == std::char_traits<char>::eof ())
2091 {
2092 return -1;
2093 }
2094
2095 if (c == '*')
2096 {
2097 document.get ();
2098 bool closed = false;
2099
2100 while ((c = document.get ()) != std::char_traits<char>::eof ())
2101 {
2102 if (c == '*' && document.peek () == '/')
2103 {
2104 document.get ();
2105 closed = true;
2106 break;
2107 }
2108 }
2109
2110 if (!closed)
2111 {
2112 return -1;
2113 }
2114 }
2115 else if (c == '/')
2116 {
2117 document.get ();
2118
2119 while ((c = document.get ()) != std::char_traits<char>::eof () && c != '\n')
2120 {
2121 }
2122 }
2123 else
2124 {
2125 return -1;
2126 }
2127 }
2128
2129 return 0;
2130 }
2131
2137 inline int validateChunk ([[maybe_unused]] std::string_view chunk) noexcept
2138 {
2139 if constexpr (ReadMode & JsonReadMode::ValidateEncoding)
2140 {
2141 if (JOIN_UNLIKELY (utf8::validate (chunk.data (), chunk.data () + chunk.size ()) == -1))
2142 {
2143 join::lastError = make_error_code (JsonErrc::InvalidEncoding);
2144 return -1;
2145 }
2146 }
2147 return 0;
2148 }
2149
2155 constexpr bool isUpperAlpha (char c) noexcept
2156 {
2157 return static_cast<unsigned char> (c - 'A') <= 5u;
2158 }
2159
2165 constexpr bool isLowerAlpha (char c) noexcept
2166 {
2167 return static_cast<unsigned char> (c - 'a') <= 5u;
2168 }
2169
2175 constexpr bool isDigit (char c) noexcept
2176 {
2177 return static_cast<unsigned char> (c - '0') <= 9u;
2178 }
2179 };
2180
2183}
2184
2185namespace std
2186{
2188 template <>
2189 struct is_error_condition_enum<join::JsonErrc> : public true_type
2190 {
2191 };
2192}
2193
2194#endif
JSON reader class.
Definition json.hpp:1138
int deserialize(const char *document, size_t length, Handler &handler)
deserialize a document.
Definition json.hpp:1184
constexpr bool isDigit(char c) noexcept
check if digit.
Definition json.hpp:2175
BasicJsonReader()=default
default constructor.
void readUntilEscaped(dconv::StringProbe &document, std::string &out) noexcept
read characters until escaped.
Definition json.hpp:1921
JOIN_ALWAYS_INLINE int readObject(ProbeType &document, Handler &handler, size_t depth)
parse an object value.
Definition json.hpp:1786
int deserialize(std::stringstream &document, Handler &handler)
deserialize a document.
Definition json.hpp:1224
int readFalse(ProbeType &document, Handler &handler)
parse a false value.
Definition json.hpp:1450
int deserialize(std::istringstream &document, Handler &handler)
deserialize a document.
Definition json.hpp:1237
JOIN_ALWAYS_INLINE int readArray(ProbeType &document, Handler &handler, size_t depth)
parse an array value.
Definition json.hpp:1716
int deserialize(std::fstream &document, Handler &handler)
deserialize a document.
Definition json.hpp:1250
int skipWhitespaces(dconv::StreamProbe &document) noexcept
skip whitespaces, and comments when comment parsing is enabled.
Definition json.hpp:1985
int readHex(ProbeType &document, uint32_t &u)
parse a 4-digit hexadecimal sequence..
Definition json.hpp:1508
constexpr bool isLowerAlpha(char c) noexcept
check if lower case alphanumeric character.
Definition json.hpp:2165
int skipWhitespacesAndComments(dconv::StreamProbe &document) noexcept
skip whitespaces and comments.
Definition json.hpp:2070
~BasicJsonReader()=default
destroy instance.
BasicJsonReader(const BasicJsonReader &other)=delete
copy constructor.
constexpr bool isUpperAlpha(char c) noexcept
check if upper case alphanumeric character.
Definition json.hpp:2155
int readNumber(ProbeType &document, Handler &handler)
parse a number value.
Definition json.hpp:1469
int readString(ProbeType &document, Handler &handler, bool isKey=false)
parse a string value.
Definition json.hpp:1644
int skipWhitespacesAndComments(dconv::StringProbe &document) noexcept
skip whitespaces and comments.
Definition json.hpp:2007
int readValue(ProbeType &document, Handler &handler, size_t depth)
parse a JSON value.
Definition json.hpp:1379
int readDocument(ProbeType &document, Handler &handler)
parse a document.
Definition json.hpp:1340
int deserialize(std::iostream &document, Handler &handler)
deserialize a document.
Definition json.hpp:1276
int readNull(ProbeType &document, Handler &handler)
parse a null value.
Definition json.hpp:1414
BasicJsonReader(BasicJsonReader &&other)=delete
move constructor.
std::string_view readUntilEscaped(dconv::StringProbe &document) noexcept
read characters until escaped.
Definition json.hpp:1883
void readUntilEscaped(dconv::StreamProbe &document, std::string &out) noexcept
read characters until escaped.
Definition json.hpp:1931
int readUnicode(ProbeType &document, std::string &output)
parse unicode.
Definition json.hpp:1545
int skipWhitespaces(dconv::StringProbe &document) noexcept
skip whitespaces, and comments when comment parsing is enabled.
Definition json.hpp:1947
int deserialize(std::string_view document, Handler &handler)
deserialize a document.
Definition json.hpp:1211
int readTrue(ProbeType &document, Handler &handler)
parse a true value.
Definition json.hpp:1432
int read(ProbeType &document, Value &value)
parse a document into a value.
Definition json.hpp:1303
int deserialize(std::istream &document, Handler &handler)
deserialize a document.
Definition json.hpp:1289
int deserialize(const char *first, const char *last, Handler &handler)
deserialize a document.
Definition json.hpp:1198
int readEscaped(ProbeType &document, std::string &output)
parse escaped sequence.
Definition json.hpp:1597
int deserialize(std::ifstream &document, Handler &handler)
deserialize a document.
Definition json.hpp:1263
int read(ProbeType &document, Handler &&handler)
parse a document, resetting the handler on failure.
Definition json.hpp:1315
int validateChunk(std::string_view chunk) noexcept
validate the encoding of the last chunk read, when encoding validation is enabled.
Definition json.hpp:2137
JSON writer class.
Definition json.hpp:200
int setKey(bool key)
set boolean key.
Definition json.hpp:549
void space()
write space.
Definition json.hpp:1018
BasicJsonWriter(const BasicJsonWriter &other)=delete
copy constructor.
uint64_t _arrays[saxMaxDepth/64]
array flags of the open containers, one bit per depth.
Definition json.hpp:1060
int setNull()
set null value.
Definition json.hpp:248
int setUint(uint32_t value)
set unsigned integer value.
Definition json.hpp:294
void appendDigits(const char *digits, size_t length)
append the digits of a number, read 20 bytes at a time.
Definition json.hpp:939
const Object & members(const Object &object) const noexcept
get object members in writing order.
Definition json.hpp:503
std::streambuf * _out
underlying output stream.
Definition json.hpp:1051
void endLine()
write end of line.
Definition json.hpp:963
BasicJsonWriter & operator=(const BasicJsonWriter &other)=delete
copy assignment.
void writeEscaped(std::string_view value)
escape string value.
Definition json.hpp:842
int setDouble(double value)
set real value in canonical form.
Definition json.hpp:379
void append(const char *data, uint32_t size)
append data to output stream in batch.
Definition json.hpp:919
~BasicJsonWriter()=default
destroy instance.
int startObject(uint32_t size=0)
start object.
Definition json.hpp:481
void writeDouble(double value)
write real value.
Definition json.hpp:813
int setKey(uint64_t key)
set unsigned 64 bits integer key.
Definition json.hpp:597
void indent()
write indentation.
Definition json.hpp:971
void reset() noexcept
reset the writer state, discarding buffered data.
Definition json.hpp:696
int setDouble(double value)
set real value.
Definition json.hpp:334
BasicJsonWriter(BasicJsonWriter &&other)=delete
move constructor.
int stopArray()
stop array.
Definition json.hpp:458
int setUint64(uint64_t value)
set unsigned 64 bits integer value.
Definition json.hpp:320
int stopObject()
stop object.
Definition json.hpp:663
int startArray(uint32_t size=0)
start array.
Definition json.hpp:438
void newLine()
write end of line and indentation.
Definition json.hpp:986
int setKey(int64_t key)
set 64 bits integer key.
Definition json.hpp:585
void writeUint64(uint64_t value)
write 64 bits unsigned integer value.
Definition json.hpp:763
int setKey(double key)
set real key.
Definition json.hpp:609
void writeUint(uint32_t value)
write unsigned integer value.
Definition json.hpp:731
void writeInt(int32_t value)
write integer value.
Definition json.hpp:708
void flush()
flush buffered data to output stream.
Definition json.hpp:684
int setString(std::string_view value)
set string value.
Definition json.hpp:414
int setKey(std::string_view key)
set string key.
Definition json.hpp:621
int setKey(uint32_t key)
set unsigned integer key.
Definition json.hpp:573
int setBool(bool value)
set boolean value.
Definition json.hpp:261
int setKey(const char *key)
set string key.
Definition json.hpp:654
size_t _depth
number of open containers.
Definition json.hpp:1063
void array()
add comma, go to line and indent if in array.
Definition json.hpp:1029
void comma()
write comma.
Definition json.hpp:952
void writeInt64(int64_t value)
write 64 bits integer value.
Definition json.hpp:740
__attribute__((noinline)) void indentLine()
write end of line and indentation, out of the compact writing path.
Definition json.hpp:997
std::vector< std::reference_wrapper< const Member > > members(const Object &object) const
get object members sorted by key in UTF-16 order.
Definition json.hpp:515
size_t _indentation
indentation.
Definition json.hpp:1066
int setInt64(int64_t value)
set 64 bits integer value.
Definition json.hpp:307
int setInt(int32_t value)
set integer value.
Definition json.hpp:281
void endValue()
mark the end of a value, flushing the document once complete.
Definition json.hpp:1041
int setKey(int32_t key)
set integer key.
Definition json.hpp:561
BasicJsonWriter(std::ostream &document, size_t indentation=0)
create instance.
Definition json.hpp:207
void append(char data)
append character to output stream in batch.
Definition json.hpp:905
bool _first
is first element.
Definition json.hpp:1069
int setKey(std::nullptr_t key)
set null key.
Definition json.hpp:537
JSON error category.
Definition json.hpp:150
virtual std::string message(int code) const
translate JSON error code to human readable error string.
Definition json.cpp:44
virtual const char * name() const noexcept
get JSON error category name.
Definition json.cpp:35
value builder class, filled by balanced SAX calls.
Definition value_builder.hpp:49
value class.
Definition value.hpp:92
const std::string key(65, 'a')
key.
constexpr UnescapedTable unescapedLookup
Definition json.hpp:90
constexpr char digitPairs[201]
Definition json.hpp:57
constexpr char hexDigits[17]
Definition json.hpp:126
constexpr WhitespaceTable whitespaceLookup
Definition json.hpp:124
constexpr EscapedTable escapedLookup
Definition json.hpp:108
int compareUtf16Order(const char *first1, const char *last1, const char *first2, const char *last2) noexcept
compare two UTF-8 inputs in UTF-16 code unit order.
Definition utf8.hpp:314
int validate(const char *first, const char *last) noexcept
validate UTF-8 input.
Definition utf8.hpp:276
Definition acceptor.hpp:32
JsonWriteMode
JSON serialization mode.
Definition json.hpp:190
const std::error_category & jsonCategory() noexcept
get error category.
Definition json.cpp:77
JsonReadMode
JSON deserialization mode.
Definition json.hpp:1082
@ StopParsingOnDone
Definition json.hpp:1086
@ ParseComments
Definition json.hpp:1084
@ ValidateEncoding
Definition json.hpp:1085
@ None
Definition json.hpp:1083
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
constexpr size_t saxMaxDepth
max number of nested containers.
Definition sax.hpp:42
thread_local std::error_code lastError
last error.
Definition error.cpp:32
std::vector< Member > Object
object.
Definition value.hpp:86
std::error_condition make_error_condition(join::Errc code) noexcept
Create an std::error_condition object.
Definition error.cpp:204
JsonErrc
JSON error codes.
Definition json.hpp:133
Definition error.hpp:144
member.
Definition value.hpp:60
Type first
member key.
Definition value.hpp:76
Definition json.hpp:93
uint8_t data[256]
Definition json.hpp:94
constexpr EscapedTable()
Definition json.hpp:96
Definition json.hpp:70
uint8_t data[256]
Definition json.hpp:71
constexpr UnescapedTable()
Definition json.hpp:73
Definition json.hpp:111
constexpr WhitespaceTable()
Definition json.hpp:114
uint8_t data[256]
Definition json.hpp:112
#define JOIN_LIKELY(x)
Definition utils.hpp:50
#define JOIN_ALWAYS_INLINE
Definition utils.hpp:48
#define JOIN_UNLIKELY(x)
Definition utils.hpp:51