libdonut 2.3.6
Application framework for cross-platform game development in C++20
Loading...
Searching...
No Matches
json.hpp
Go to the documentation of this file.
1#ifndef DONUT_JSON_HPP
2#define DONUT_JSON_HPP
3
4#include <donut/Variant.hpp>
6#include <donut/unicode.hpp>
7
8#include <algorithm> // std::sort, std::equal_range, std::lower_bound, std::upper_bound
9#include <array> // std::array
10#include <charconv> // std::from_chars_result, std::from_chars
11#include <cmath> // std::isnan, std::isinf, std::signbit
12#include <compare> // std::partial_ordering, std::compare_partial_order_fallback
13#include <cstddef> // std::size_t, std::nullptr_t
14#include <cstdint> // std::uint8_t, std::uint32_t
15#include <cstdlib> // std::strtoull, std::strtod
16#include <cstring> // std::memcpy
17#include <fmt/format.h> // fmt::format_to
18#include <initializer_list> // std::initializer_list
19#include <istream> // std::istream
20#include <iterator> // std::begin, std::end, std::istreambuf_iterator, std::ostreambuf_iterator
21#include <limits> // std::numeric_limits
22#include <numeric> // std::accumulate
23#include <optional> // std::optional
24#include <ostream> // std::ostream
25#include <span> // std::span, std::as_bytes
26#include <sstream> // std::istringstream, std::ostringstream
27#include <stdexcept> // std::runtime_error, std::out_of_range
28#include <string> // std::...string
29#include <string_view> // std::...string_view
30#include <system_error> // std::errc
31#include <tuple> // std::forward_as_tuple
32#include <type_traits> // std::is_same_v, std::is_arithmetic_v, std::is_pointer_v, std::is_aggregate_v, std::is_constructible_v, std::remove_cvref_t
33#include <utility> // std::pair, std::move, std::forward, std::piecewise_construct
34#include <vector> // std::vector, std::erase(std::vector), std::erase_if(std::vector)
35
36namespace donut::json {
37
38namespace detail {
39
40template <typename T>
41concept number = std::is_arithmetic_v<T> && !std::is_same_v<T, bool> && !std::is_same_v<T, char> && !std::is_same_v<T, char8_t> && !std::is_same_v<T, char16_t> &&
42 !std::is_same_v<T, char32_t> && !std::is_same_v<T, wchar_t>;
43
44// clang-format off
45struct AlwaysTrue { constexpr bool operator()(const auto&...) const noexcept { return true; } };
46struct Get { constexpr const auto& operator()(const auto& value) const noexcept { return value; } };
47struct GetFirst { constexpr const auto& operator()(const auto& kv) const noexcept { return kv.first; } };
48struct GetSecond { constexpr const auto& operator()(const auto& kv) const noexcept { return kv.second; } };
49// clang-format on
50
51} // namespace detail
52
61 std::size_t lineNumber;
62
67 std::size_t columnNumber;
68
76 [[nodiscard]] constexpr bool operator==(const SourceLocation& other) const = default;
77};
78
82struct Error : std::runtime_error {
88
89 Error(const std::string& message, const SourceLocation& source)
90 : std::runtime_error(message)
91 , source(source) {}
92
93 Error(const char* message, const SourceLocation& source)
94 : std::runtime_error(message)
95 , source(source) {}
96};
97
106 std::size_t indentation = 0;
107
112 std::size_t relativeIndentation = 4;
113
118
127 bool prettyPrint = true;
128
142
156
165 const char* newlineString = "\r\n";
166};
167
172
173// Forward declaration of the definition below, so that Object and Array can contain objects of type Value through indirection, despite Value being defined in terms of them.
174class Value;
175
180
184using Boolean = bool;
185
189using String = std::string;
190
194using Number = double;
195
199class Object {
200public:
203 using value_type = std::pair<String, Value>;
204 using size_type = typename std::vector<value_type>::size_type;
205 using difference_type = typename std::vector<value_type>::difference_type;
206 using reference = typename std::vector<value_type>::reference;
207 using const_reference = typename std::vector<value_type>::const_reference;
208 using pointer = typename std::vector<value_type>::pointer;
209 using const_pointer = typename std::vector<value_type>::const_pointer;
210 using iterator = typename std::vector<value_type>::iterator;
211 using const_iterator = typename std::vector<value_type>::const_iterator;
212 using reverse_iterator = typename std::vector<value_type>::reverse_iterator;
213 using const_reverse_iterator = typename std::vector<value_type>::const_reverse_iterator;
214
215 Object() noexcept;
217
218 template <typename InputIt>
219 Object(InputIt first, InputIt last);
220 Object(std::initializer_list<value_type> ilist);
221
222 Object(const Object& other);
223 Object(Object&& other) noexcept;
224 Object& operator=(const Object& other);
225 Object& operator=(Object&& other) noexcept;
226
227 Object& operator=(std::initializer_list<value_type> ilist);
228
229 [[nodiscard]] Value& at(std::string_view name);
230 [[nodiscard]] const Value& at(std::string_view name) const;
231 [[nodiscard]] Value& operator[](const String& k);
232 [[nodiscard]] Value& operator[](String&& k);
233
234 [[nodiscard]] iterator begin() noexcept;
235 [[nodiscard]] const_iterator begin() const noexcept;
236 [[nodiscard]] const_iterator cbegin() const noexcept;
237 [[nodiscard]] iterator end() noexcept;
238 [[nodiscard]] const_iterator end() const noexcept;
239 [[nodiscard]] const_iterator cend() const noexcept;
240 [[nodiscard]] reverse_iterator rbegin() noexcept;
241 [[nodiscard]] const_reverse_iterator rbegin() const noexcept;
242 [[nodiscard]] const_reverse_iterator crbegin() const noexcept;
243 [[nodiscard]] reverse_iterator rend() noexcept;
244 [[nodiscard]] const_reverse_iterator rend() const noexcept;
245 [[nodiscard]] const_reverse_iterator crend() const noexcept;
246
247 [[nodiscard]] bool empty() const noexcept;
248 [[nodiscard]] size_type size() const noexcept;
249 [[nodiscard]] size_type max_size() const noexcept;
250
251 void clear() noexcept;
252
253 template <typename P>
254 std::pair<iterator, bool> insert(P&& value);
255
256 template <typename P>
257 iterator insert(const_iterator pos, P&& value);
258
259 template <typename InputIt>
260 void insert(InputIt first, InputIt last);
261 void insert(std::initializer_list<value_type> ilist);
262
263 template <typename... Args>
264 std::pair<iterator, bool> emplace(Args&&... args);
265
266 template <typename... Args>
267 iterator emplace_hint(const_iterator hint, Args&&... args);
268
269 template <typename... Args>
270 std::pair<iterator, bool> try_emplace(const String& k, Args&&... args);
271
272 template <typename... Args>
273 std::pair<iterator, bool> try_emplace(String&& k, Args&&... args);
274
275 template <typename... Args>
276 iterator try_emplace(const_iterator, const String& k, Args&&... args);
277
278 template <typename... Args>
279 iterator try_emplace(const_iterator, String&& k, Args&&... args);
280
282 size_type erase(std::string_view name);
283
284 void swap(Object& other) noexcept;
285 friend void swap(Object& a, Object& b) noexcept;
286
287 [[nodiscard]] size_type count(std::string_view name) const noexcept;
288 [[nodiscard]] bool contains(std::string_view name) const noexcept;
289 [[nodiscard]] iterator find(std::string_view name) noexcept;
290 [[nodiscard]] const_iterator find(std::string_view name) const noexcept;
291 [[nodiscard]] std::pair<iterator, iterator> equal_range(std::string_view name) noexcept;
292 [[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(std::string_view name) const noexcept;
293 [[nodiscard]] iterator lower_bound(std::string_view name) noexcept;
294 [[nodiscard]] const_iterator lower_bound(std::string_view name) const noexcept;
295 [[nodiscard]] iterator upper_bound(std::string_view name) noexcept;
296 [[nodiscard]] const_iterator upper_bound(std::string_view name) const noexcept;
297
298 [[nodiscard]] bool operator==(const Object& other) const noexcept;
299 [[nodiscard]] std::partial_ordering operator<=>(const Object& other) const noexcept;
300
301 template <typename Predicate>
302 friend size_type erase_if(Object& container, Predicate predicate);
303
304private:
305 struct Compare {
306 [[nodiscard]] bool operator()(const value_type& a, const value_type& b) const noexcept;
307 [[nodiscard]] bool operator()(const value_type& a, std::string_view b) const noexcept;
308 [[nodiscard]] bool operator()(std::string_view a, const value_type& b) const noexcept;
309 [[nodiscard]] bool operator()(std::string_view a, std::string_view b) const noexcept;
310 };
311
312 std::vector<value_type> membersSortedByName;
313};
314
318class Array {
319public:
321 using size_type = typename std::vector<value_type>::size_type;
322 using difference_type = typename std::vector<value_type>::difference_type;
323 using reference = typename std::vector<value_type>::reference;
324 using const_reference = typename std::vector<value_type>::const_reference;
325 using pointer = typename std::vector<value_type>::pointer;
326 using const_pointer = typename std::vector<value_type>::const_pointer;
327 using iterator = typename std::vector<value_type>::iterator;
328 using const_iterator = typename std::vector<value_type>::const_iterator;
329 using reverse_iterator = typename std::vector<value_type>::reverse_iterator;
330 using const_reverse_iterator = typename std::vector<value_type>::const_reverse_iterator;
331
332 Array() noexcept;
334
335 template <typename InputIt>
336 Array(InputIt first, InputIt last);
337 Array(size_type count, const Value& value);
338 Array(std::initializer_list<value_type> ilist);
339
340 Array(const Array& other);
341 Array(Array&& other) noexcept;
342 Array& operator=(const Array& other);
343 Array& operator=(Array&& other) noexcept;
344
345 Array& operator=(std::initializer_list<value_type> ilist);
346
347 void swap(Array& other) noexcept;
348 friend void swap(Array& a, Array& b) noexcept;
349
350 [[nodiscard]] pointer data() noexcept;
351 [[nodiscard]] const_pointer data() const noexcept;
352 [[nodiscard]] size_type size() const noexcept;
353 [[nodiscard]] size_type max_size() const noexcept;
354 [[nodiscard]] size_type capacity() const noexcept;
355 [[nodiscard]] bool empty() const noexcept;
356
357 [[nodiscard]] iterator begin() noexcept;
358 [[nodiscard]] const_iterator begin() const noexcept;
359 [[nodiscard]] const_iterator cbegin() const noexcept;
360 [[nodiscard]] iterator end() noexcept;
361 [[nodiscard]] const_iterator end() const noexcept;
362 [[nodiscard]] const_iterator cend() const noexcept;
363 [[nodiscard]] reverse_iterator rbegin() noexcept;
364 [[nodiscard]] const_reverse_iterator rbegin() const noexcept;
365 [[nodiscard]] const_reverse_iterator crbegin() const noexcept;
366 [[nodiscard]] reverse_iterator rend() noexcept;
367 [[nodiscard]] const_reverse_iterator rend() const noexcept;
368 [[nodiscard]] const_reverse_iterator crend() const noexcept;
369
370 [[nodiscard]] reference front();
371 [[nodiscard]] const_reference front() const;
372 [[nodiscard]] reference back();
373 [[nodiscard]] const_reference back() const;
374 [[nodiscard]] reference at(size_type pos);
375 [[nodiscard]] const_reference at(size_type pos) const;
376 [[nodiscard]] reference operator[](size_type pos);
377 [[nodiscard]] const_reference operator[](size_type pos) const;
378
379 [[nodiscard]] bool operator==(const Array& other) const;
380 [[nodiscard]] std::partial_ordering operator<=>(const Array& other) const noexcept;
381
382 template <typename U>
383 friend size_type erase(Array& container, const U& value);
384
385 template <typename Predicate>
386 friend size_type erase_if(Array& container, Predicate predicate);
387
388 void clear() noexcept;
389 void reserve(size_type newCap);
390 void shrink_to_fit();
391
392 iterator insert(const_iterator pos, const Value& value);
393 iterator insert(const_iterator pos, Value&& value);
394 iterator insert(const_iterator pos, size_type count, const Value& value);
395
396 template <typename InputIt>
397 iterator insert(const_iterator pos, InputIt first, InputIt last);
398 iterator insert(const_iterator pos, std::initializer_list<value_type> ilist);
399
400 template <typename... Args>
401 iterator emplace(const_iterator pos, Args&&... args);
402
405
406 void push_back(const Value& value);
407 void push_back(Value&& value);
408
409 template <typename... Args>
410 reference emplace_back(Args&&... args);
411
412 void pop_back();
413
414 void resize(size_type count);
415 void resize(size_type count, const Value& value);
416
417private:
418 std::vector<value_type> values;
419};
420
433public:
448 [[nodiscard]] static Value parse(std::u8string_view jsonString);
449
465 [[nodiscard]] static Value parse(std::string_view jsonString);
466
470 Value() noexcept = default;
471
475 Value(Null) noexcept {}
476
480 Value(std::nullptr_t) noexcept {}
481
487 Value(Boolean value) noexcept
488 : Variant(value) {}
489
497 Value(const String& value)
498 : Variant(value) {}
499
505 Value(String&& value) noexcept
506 : Variant(std::move(value)) {}
507
516 Value(const char* value)
517 : Variant(String{value}) {}
518
526 Value(std::string_view value)
527 : Variant(String{value}) {}
528
537 Value(const char8_t* value)
538 : Variant(String{reinterpret_cast<const char*>(value)}) {
539 static_assert(sizeof(char) == sizeof(char8_t));
540 static_assert(alignof(char) == alignof(char8_t));
541 }
542
551 Value(std::u8string_view value)
552 : Variant(String{value.begin(), value.end()}) {}
553
560 Value(detail::number auto value) noexcept
561 : Variant(static_cast<Number>(value)) {}
562
570 Value(const Object& value)
571 : Variant(value) {}
572
578 Value(Object&& value) noexcept
579 : Variant(std::move(value)) {}
580
588 Value(const Array& value)
589 : Variant(value) {}
590
596 Value(Array&& value) noexcept
597 : Variant(std::move(value)) {}
598
611 [[nodiscard]] std::string toString(const SerializationOptions& options = {}) const;
612
620 [[nodiscard]] bool operator==(const Value& other) const {
621 return static_cast<const Variant&>(*this) == static_cast<const Variant&>(other);
622 }
623
631 [[nodiscard]] std::partial_ordering operator<=>(const Value& other) const {
632 return std::compare_partial_order_fallback(static_cast<const Variant&>(*this), static_cast<const Variant&>(other));
633 }
634};
635
643[[nodiscard]] constexpr bool isWhitespaceCharacter(char32_t codePoint) noexcept {
644 return codePoint == '\t' || codePoint == '\n' || codePoint == '\v' || codePoint == '\f' || codePoint == '\r' || codePoint == ' ' || codePoint == 0x00A0 ||
645 codePoint == 0x1680 || (codePoint >= 0x2000 && codePoint <= 0x200A) || codePoint == 0x2028 || codePoint == 0x2029 || codePoint == 0x202F || codePoint == 0x205F ||
646 codePoint == 0x3000 || codePoint == 0xFEFF;
647}
648
656[[nodiscard]] constexpr bool isPunctuationCharacter(char32_t codePoint) noexcept {
657 return codePoint == ',' || codePoint == ':' || codePoint == '[' || codePoint == ']' || codePoint == '{' || codePoint == '}';
658}
659
669[[nodiscard]] constexpr bool isLineTerminatorCharacter(char32_t codePoint) noexcept {
670 return codePoint == '\n' || codePoint == '\r' || codePoint == 0x2028 || codePoint == 0x2029;
671}
672
698
707
714template <typename It>
715class Lexer {
716public:
728 : it(std::move(it))
729 , end(end)
730 , source(source) {}
731
744 skipWhitespace();
745 if (hasReachedEnd()) {
746 return {.string{}, .source = source, .type = TokenType::END_OF_FILE};
747 }
748 switch (peek()) {
749 case '{': [[fallthrough]];
750 case '}': [[fallthrough]];
751 case '[': [[fallthrough]];
752 case ']': [[fallthrough]];
753 case ':': [[fallthrough]];
754 case ',': return scanPunctuator();
755 case '\"': [[fallthrough]];
756 case '\'': return scanString();
757 case '0': [[fallthrough]];
758 case '1': [[fallthrough]];
759 case '2': [[fallthrough]];
760 case '3': [[fallthrough]];
761 case '4': [[fallthrough]];
762 case '5': [[fallthrough]];
763 case '6': [[fallthrough]];
764 case '7': [[fallthrough]];
765 case '8': [[fallthrough]];
766 case '9': [[fallthrough]];
767 case '+': [[fallthrough]];
768 case '-': [[fallthrough]];
769 case '.': return scanNumber();
770 default: return scanIdentifier();
771 }
772 }
773
774private:
775 void skipWhitespace() {
776 while (!hasReachedEnd()) {
777 if (isWhitespaceCharacter(peek())) {
778 if (isLineTerminatorCharacter(peek())) {
779 skipLineTerminatorSequence();
780 } else {
781 advance();
782 }
783 } else if (peek() == '/') {
784 advance();
785 if (hasReachedEnd()) {
786 throw Error{"Invalid token.", source};
787 }
788 if (peek() == '/') {
789 advance();
790 while (!hasReachedEnd()) {
791 if (isLineTerminatorCharacter(peek())) {
792 skipLineTerminatorSequence();
793 break;
794 }
795 advance();
796 }
797 } else if (peek() == '*') {
798 advance();
799 while (!hasReachedEnd()) {
800 if (isLineTerminatorCharacter(peek())) {
801 skipLineTerminatorSequence();
802 } else if (peek() == '*') {
803 advance();
804 if (!hasReachedEnd() && peek() == '/') {
805 advance();
806 break;
807 }
808 } else {
809 advance();
810 }
811 }
812 } else {
813 throw Error{"Invalid token.", source};
814 }
815 } else {
816 break;
817 }
818 }
819 }
820
821 void skipLineTerminatorSequence() {
822 if (peek() == '\r') {
823 advance();
824 if (!hasReachedEnd() && peek() == '\n') {
825 advance();
826 }
827 } else {
828 advance();
829 }
830 ++source.lineNumber;
831 source.columnNumber = 1;
832 }
833
834 void advance() {
835 if (!currentCodePoint) {
836 ++it;
837 }
838 currentCodePoint.reset();
839 ++source.columnNumber;
840 }
841
842 [[nodiscard]] bool hasReachedEnd() const noexcept {
843 return it == end && !currentCodePoint;
844 }
845
846 [[nodiscard]] char32_t peek() const {
847 if (!currentCodePoint) {
848 currentCodePoint = *it++;
849 }
850 return *currentCodePoint;
851 }
852
853 [[nodiscard]] std::optional<char32_t> lookahead() const {
854 if (!currentCodePoint) {
855 currentCodePoint = *it++;
856 }
857 if (it != end) {
858 return *it;
859 }
860 return {};
861 }
862
863 [[nodiscard]] Token scanPunctuator() {
864 String string{static_cast<char>(peek())};
865 const SourceLocation punctuatorSource = source;
866 TokenType type{};
867 switch (peek()) {
868 case ',': type = TokenType::PUNCTUATOR_COMMA; break;
869 case ':': type = TokenType::PUNCTUATOR_COLON; break;
870 case '[': type = TokenType::PUNCTUATOR_OPEN_SQUARE_BRACKET; break;
871 case ']': type = TokenType::PUNCTUATOR_CLOSE_SQUARE_BRACKET; break;
872 case '{': type = TokenType::PUNCTUATOR_OPEN_CURLY_BRACE; break;
873 case '}': type = TokenType::PUNCTUATOR_CLOSE_CURLY_BRACE; break;
874 default: break;
875 }
876 advance();
877 return {.string = std::move(string), .source = punctuatorSource, .type = type};
878 }
879
880 [[nodiscard]] Token scanString() {
881 const char32_t quoteCharacter = peek();
882 String string{};
883 const SourceLocation stringSource = source;
884 advance();
885 while (!hasReachedEnd()) {
886 if (!unicode::isValidCodePoint(peek())) {
887 throw Error{"Invalid UTF-8.", source};
888 }
889 if (peek() == quoteCharacter) {
890 advance();
891 return {.string = std::move(string), .source = stringSource, .type = TokenType::STRING};
892 }
893 if (isLineTerminatorCharacter(peek())) {
894 throw Error{"Unexpected line terminator in string.", source};
895 }
896 if (peek() != '\\') {
898 string.append(std::string_view{reinterpret_cast<const char*>(codePointUTF8.codeUnits.data()), codePointUTF8.size});
899 advance();
900 continue;
901 }
902 advance();
903 if (hasReachedEnd()) {
904 throw Error{"Empty escape sequence.", source};
905 }
906 if (isLineTerminatorCharacter(peek())) {
907 skipLineTerminatorSequence();
908 continue;
909 }
910 switch (peek()) {
911 case '\"': string.push_back('\"'); break;
912 case '\'': string.push_back('\''); break;
913 case '\\': string.push_back('\\'); break;
914 case 'b': string.push_back('\b'); break;
915 case 'f': string.push_back('\f'); break;
916 case 'n': string.push_back('\n'); break;
917 case 'r': string.push_back('\r'); break;
918 case 't': string.push_back('\t'); break;
919 case 'v': string.push_back('\v'); break;
920 case '0': [[fallthrough]];
921 case '1': [[fallthrough]];
922 case '2': [[fallthrough]];
923 case '3': [[fallthrough]];
924 case '4': [[fallthrough]];
925 case '5': [[fallthrough]];
926 case '6': [[fallthrough]];
927 case '7': [[fallthrough]];
928 case '8': [[fallthrough]];
929 case '9': scanNumericEscapeSequence(string, 1, 3, 8, [](char32_t codePoint) noexcept -> bool { return (codePoint >= '0' && codePoint <= '7'); }); continue;
930 case 'x':
931 scanNumericEscapeSequence(string, 2, 2, 16, [](char32_t codePoint) noexcept -> bool {
932 return (codePoint >= '0' && codePoint <= '9') || (codePoint >= 'a' && codePoint <= 'f') || (codePoint >= 'A' && codePoint <= 'F');
933 });
934 continue;
935 case 'u':
936 scanNumericEscapeSequence(string, 4, 4, 16, [](char32_t codePoint) noexcept -> bool {
937 return (codePoint >= '0' && codePoint <= '9') || (codePoint >= 'a' && codePoint <= 'f') || (codePoint >= 'A' && codePoint <= 'F');
938 });
939 continue;
940 case 'U':
941 scanNumericEscapeSequence(string, 8, 8, 16, [](char32_t codePoint) noexcept -> bool {
942 return (codePoint >= '0' && codePoint <= '9') || (codePoint >= 'a' && codePoint <= 'f') || (codePoint >= 'A' && codePoint <= 'F');
943 });
944 continue;
945 default: {
947 string.append(std::string_view{reinterpret_cast<const char*>(codePointUTF8.codeUnits.data()), codePointUTF8.size});
948 break;
949 }
950 }
951 advance();
952 }
953 throw Error{"Missing end of string quote character.", source};
954 }
955
956 [[nodiscard]] Token scanNumber() {
957 String string{};
958 const SourceLocation numberSource = source;
959 bool negative = false;
960 if (peek() == '+') {
961 advance();
962 } else if (peek() == '-') {
963 string.push_back('-');
964 advance();
965 negative = true;
966 }
967 if (hasReachedEnd()) {
968 throw Error{"Missing number.", source};
969 }
970 if (peek() == 'I') {
971 if (scanIdentifier().type == TokenType::NUMBER_POSITIVE_INFINITY) {
972 return {.string{}, .source = numberSource, .type = (negative) ? TokenType::NUMBER_NEGATIVE_INFINITY : TokenType::NUMBER_POSITIVE_INFINITY};
973 }
974 throw Error{"Invalid number.", numberSource};
975 }
976 if (peek() == 'N') {
977 if (scanIdentifier().type == TokenType::NUMBER_POSITIVE_NAN) {
978 return {.string{}, .source = numberSource, .type = (negative) ? TokenType::NUMBER_NEGATIVE_NAN : TokenType::NUMBER_POSITIVE_NAN};
979 }
980 throw Error{"Invalid number.", numberSource};
981 }
982 TokenType type = TokenType::NUMBER_DECIMAL;
983 if (!hasReachedEnd() && peek() == '0') {
984 string.push_back('0');
985 advance();
986 if (!hasReachedEnd() && (peek() == 'b' || peek() == 'B')) {
987 string.push_back('b');
988 advance();
989 type = TokenType::NUMBER_BINARY;
990 } else if (!hasReachedEnd() && (peek() == 'x' || peek() == 'X')) {
991 string.push_back('x');
992 advance();
993 type = TokenType::NUMBER_HEXADECIMAL;
994 } else if (hasReachedEnd() || peek() != '.') {
995 type = TokenType::NUMBER_OCTAL;
996 }
997 }
998 bool eNotation = false;
999 bool fraction = false;
1000 while (!hasReachedEnd()) {
1001 if (peek() == '.') {
1002 if (lookahead() == '.') {
1003 break;
1004 }
1005 if (type != TokenType::NUMBER_DECIMAL) {
1006 break;
1007 }
1008 if (eNotation) {
1009 throw Error{"Decimal point in E notation exponent.", source};
1010 }
1011 if (fraction) {
1012 throw Error{"Multiple decimal points in number.", source};
1013 }
1014 string.push_back('.');
1015 advance();
1016 fraction = true;
1017 } else if ((peek() == 'e' || peek() == 'E') && type != TokenType::NUMBER_HEXADECIMAL) {
1018 if (type != TokenType::NUMBER_DECIMAL) {
1019 break;
1020 }
1021 if (eNotation) {
1022 throw Error{"Multiple exponent symbols in E notation.", source};
1023 }
1024 string.push_back('e');
1025 advance();
1026 eNotation = true;
1027 fraction = true;
1028 if (hasReachedEnd()) {
1029 throw Error{"Missing exponent in E notation.", source};
1030 }
1031 if (peek() >= '0' && peek() <= '9') {
1032 string.push_back(static_cast<char>(peek()));
1033 advance();
1034 } else if ((peek() == '+' || peek() == '-')) {
1035 string.push_back(static_cast<char>(peek()));
1036 advance();
1037 if (!hasReachedEnd() && peek() >= '0' && peek() <= '9') {
1038 string.push_back(static_cast<char>(peek()));
1039 advance();
1040 } else {
1041 throw Error{"Missing exponent in E notation.", source};
1042 }
1043 }
1044 } else if ( //
1045 (type == TokenType::NUMBER_BINARY && (peek() == '0' || peek() == '1')) || //
1046 (type == TokenType::NUMBER_OCTAL && (peek() >= '0' && peek() <= '7')) || //
1047 (type == TokenType::NUMBER_DECIMAL && (peek() >= '0' && peek() <= '9')) || //
1048 (type == TokenType::NUMBER_HEXADECIMAL && ((peek() >= '0' && peek() <= '9') || (peek() >= 'a' && peek() <= 'f') || (peek() >= 'A' && peek() <= 'F')))) {
1049 string.push_back(static_cast<char>(peek()));
1050 advance();
1051 } else if (peek() == '_') {
1052 advance();
1053 } else {
1054 break;
1055 }
1056 }
1057 if (!hasReachedEnd()) {
1058 if (!isWhitespaceCharacter(peek()) && !isPunctuationCharacter(peek()) && peek() != '\"' && peek() != '\'' && peek() != '/') {
1059 throw Error{"Invalid character after number.", source};
1060 }
1061 }
1062 return {.string = std::move(string), .source = numberSource, .type = type};
1063 }
1064
1065 [[nodiscard]] Token scanIdentifier() {
1066 String string{};
1067 const SourceLocation identifierSource = source;
1068 do {
1069 if (!unicode::isValidCodePoint(peek())) {
1070 throw Error{"Invalid UTF-8.", source};
1071 }
1073 string.append(std::string_view{reinterpret_cast<const char*>(codePointUTF8.codeUnits.data()), codePointUTF8.size});
1074 advance();
1075 } while (!hasReachedEnd() && !isWhitespaceCharacter(peek()) && !isPunctuationCharacter(peek()) && peek() != '\"' && peek() != '\'' && peek() != '/');
1076 TokenType type = TokenType::IDENTIFIER_NAME;
1077 if (string == "null") {
1078 string = {};
1079 type = TokenType::IDENTIFIER_NULL;
1080 } else if (string == "false") {
1081 string = {};
1082 type = TokenType::IDENTIFIER_FALSE;
1083 } else if (string == "true") {
1084 string = {};
1085 type = TokenType::IDENTIFIER_TRUE;
1086 } else if (string == "Infinity") {
1087 string = {};
1088 type = TokenType::NUMBER_POSITIVE_INFINITY;
1089 } else if (string == "NaN") {
1090 string = {};
1091 type = TokenType::NUMBER_POSITIVE_NAN;
1092 }
1093 return {.string = std::move(string), .source = identifierSource, .type = type};
1094 }
1095
1096 void scanNumericEscapeSequence(String& output, std::size_t minDigitCount, std::size_t maxDigitCount, int radix, bool (*isDigit)(char32_t) noexcept) {
1097 const SourceLocation escapeSequenceSource = source;
1098 std::string digits{};
1099 digits.reserve(maxDigitCount);
1100 while (digits.size() < maxDigitCount && !hasReachedEnd() && isDigit(peek())) {
1101 digits.push_back(static_cast<char>(peek()));
1102 advance();
1103 }
1104 if (digits.size() < minDigitCount) {
1105 throw Error{"Invalid escape sequence length.", escapeSequenceSource};
1106 }
1107 const char* const digitsBegin = digits.data();
1108 const char* const digitsEnd = digitsBegin + digits.size();
1109 std::uint32_t codePointValue = 0;
1110 if (const std::from_chars_result parseResult = std::from_chars(digitsBegin, digitsEnd, codePointValue, radix);
1111 parseResult.ec != std::errc{} || parseResult.ptr != digitsEnd || !unicode::isValidCodePoint(static_cast<char32_t>(codePointValue))) {
1112 throw Error{"Invalid code point value.", escapeSequenceSource};
1113 }
1114 const unicode::EncodeUTF8FromCodePointResult codePointUTF8 = unicode::encodeUTF8FromCodePoint(static_cast<char32_t>(codePointValue));
1115 output.append(std::string_view{reinterpret_cast<const char*>(codePointUTF8.codeUnits.data()), codePointUTF8.size});
1116 }
1117
1118 mutable unicode::UTF8Iterator<It> it;
1120 SourceLocation source;
1121 mutable std::optional<char32_t> currentCodePoint{};
1122};
1123
1131template <typename It>
1132class Parser {
1133public:
1138 public:
1148 virtual void visitNull(const SourceLocation& source, Null value) {
1149 (void)value;
1150 throw Error{"Unexpected null.", source};
1151 }
1152
1162 virtual void visitBoolean(const SourceLocation& source, Boolean value) {
1163 (void)value;
1164 throw Error{"Unexpected boolean.", source};
1165 }
1166
1176 virtual void visitString(const SourceLocation& source, String&& value) {
1177 (void)std::move(value);
1178 throw Error{"Unexpected string.", source};
1179 }
1180
1190 virtual void visitNumber(const SourceLocation& source, Number value) {
1191 (void)value;
1192 throw Error{"Unexpected number.", source};
1193 }
1194
1209 virtual void visitObject(const SourceLocation& source, Parser& parser) {
1210 (void)parser;
1211 throw Error{"Unexpected object.", source};
1212 }
1213
1228 virtual void visitArray(const SourceLocation& source, Parser& parser) {
1229 (void)parser;
1230 throw Error{"Unexpected array.", source};
1231 }
1232
1233 protected:
1234 ~ValueVisitor() = default;
1235 };
1236
1243 template <typename Visitor>
1245 Visitor visitor;
1246
1247 ConcreteValueVisitor(Visitor visitor)
1248 : visitor(std::move(visitor)) {}
1249
1250 void visitNull(const SourceLocation& source, Null value) override {
1251 if constexpr (requires { visitor.visitNull(source, value); }) {
1252 visitor.visitNull(source, value);
1253 } else {
1254 ValueVisitor::visitNull(source, value);
1255 }
1256 }
1257
1258 void visitBoolean(const SourceLocation& source, Boolean value) override {
1259 if constexpr (requires { visitor.visitBoolean(source, value); }) {
1260 visitor.visitBoolean(source, value);
1261 } else {
1262 ValueVisitor::visitBoolean(source, value);
1263 }
1264 }
1265
1266 void visitString(const SourceLocation& source, String&& value) override {
1267 if constexpr (requires { visitor.visitString(source, std::move(value)); }) {
1268 visitor.visitString(source, std::move(value));
1269 } else {
1270 ValueVisitor::visitString(source, std::move(value));
1271 }
1272 }
1273
1274 void visitNumber(const SourceLocation& source, Number value) override {
1275 if constexpr (requires { visitor.visitNumber(source, value); }) {
1276 visitor.visitNumber(source, value);
1277 } else {
1278 ValueVisitor::visitNumber(source, value);
1279 }
1280 }
1281
1282 void visitObject(const SourceLocation& source, Parser& parser) override {
1283 if constexpr (requires { visitor.visitObject(source, parser); }) {
1284 visitor.visitObject(source, parser);
1285 } else {
1286 ValueVisitor::visitObject(source, parser);
1287 }
1288 }
1289
1290 void visitArray(const SourceLocation& source, Parser& parser) override {
1291 if constexpr (requires { visitor.visitArray(source, parser); }) {
1292 visitor.visitArray(source, parser);
1293 } else {
1294 ValueVisitor::visitArray(source, parser);
1295 }
1296 }
1297 };
1298
1304 public:
1321 virtual void visitProperty(const SourceLocation& source, String&& key, Parser& parser) = 0;
1322
1323 protected:
1324 ~PropertyVisitor() = default;
1325 };
1326
1333 template <typename Visitor>
1335 Visitor visitor;
1336
1338 : visitor(std::move(visitor)) {}
1339
1340 void visitProperty(const SourceLocation& source, String&& key, Parser& parser) override {
1341 if constexpr (requires { visitor.visitProperty(source, std::move(key), parser); }) {
1342 visitor.visitProperty(source, std::move(key), parser);
1343 }
1344 }
1345 };
1346
1352 // clang-format off
1353 void visitNull(const SourceLocation& source, Null value) override { (void)source; (void)value; }
1354 void visitBoolean(const SourceLocation& source, Boolean value) override { (void)source; (void)value; }
1355 void visitString(const SourceLocation& source, String&& value) override { (void)source; (void)std::move(value); }
1356 void visitNumber(const SourceLocation& source, Number value) override { (void)source; (void)value; }
1357 void visitObject(const SourceLocation& source, Parser& parser) override { (void)source; parser.parseObject(SkipPropertyVisitor{}); }
1358 void visitArray(const SourceLocation& source, Parser& parser) override { (void)source; parser.parseValue(SkipValueVisitor{}); }
1359 // clang-format on
1360 };
1361
1367 // clang-format off
1368 void visitProperty(const SourceLocation& source, String&& key, Parser& parser) override { (void)source; (void)std::move(key); parser.parseValue(SkipValueVisitor{}); }
1369 // clang-format on
1370 };
1371
1377 explicit Parser(Lexer<It> lexer)
1378 : lexer(std::move(lexer)) {}
1379
1386 explicit Parser(unicode::UTF8View codePoints) requires(std::is_same_v<It, const char8_t*>)
1387 : Parser(Lexer<It>{codePoints.begin(), codePoints.end(), SourceLocation{.lineNumber = 1, .columnNumber = 1}}) {}
1388
1395 explicit Parser(std::u8string_view jsonString) requires(std::is_same_v<It, const char8_t*>)
1396 : Parser(unicode::UTF8View{jsonString}) {}
1397
1405 explicit Parser(std::string_view jsonString) requires(std::is_same_v<It, const char8_t*>)
1406 : Parser(unicode::UTF8View{jsonString}) {}
1407
1413 explicit Parser(std::istream& stream) requires(std::is_same_v<It, std::istreambuf_iterator<char>>)
1414 : Parser(Lexer<It>{unicode::UTF8Iterator<It>{It{stream}, It{}}, unicode::UTF8Sentinel{}, SourceLocation{.lineNumber = 1, .columnNumber = 1}}) {}
1415
1421 explicit Parser(std::streambuf* streambuf) requires(std::is_same_v<It, std::istreambuf_iterator<char>>)
1422 : Parser(Lexer<It>{unicode::UTF8Iterator<It>{It{streambuf}, It{}}, unicode::UTF8Sentinel{}, SourceLocation{.lineNumber = 1, .columnNumber = 1}}) {}
1423
1444 void parseFile(ValueVisitor& visitor) {
1445 parseValue(visitor);
1446 if (const Token& token = peek(); token.type != TokenType::END_OF_FILE) {
1447 throw Error{"Multiple top-level values.", token.source};
1448 }
1449 }
1450
1470 void parseValue(ValueVisitor& visitor) {
1471 switch (const Token& token = peek(); token.type) {
1472 case TokenType::END_OF_FILE: throw Error{"Expected a value.", token.source};
1473 case TokenType::IDENTIFIER_NULL:
1474 advance();
1475 visitor.visitNull(token.source, Null{});
1476 break;
1477 case TokenType::IDENTIFIER_FALSE:
1478 advance();
1479 visitor.visitBoolean(token.source, Boolean{false});
1480 break;
1481 case TokenType::IDENTIFIER_TRUE:
1482 advance();
1483 visitor.visitBoolean(token.source, Boolean{true});
1484 break;
1485 case TokenType::IDENTIFIER_NAME: throw Error{"Unexpected name identifier.", token.source};
1486 case TokenType::PUNCTUATOR_COMMA: throw Error{"Unexpected comma.", token.source};
1487 case TokenType::PUNCTUATOR_COLON: throw Error{"Unexpected colon.", token.source};
1488 case TokenType::PUNCTUATOR_OPEN_SQUARE_BRACKET: {
1489 const SourceLocation source = token.source;
1490 visitor.visitArray(source, *this);
1491 break;
1492 }
1493 case TokenType::PUNCTUATOR_CLOSE_SQUARE_BRACKET: throw Error{"Unexpected closing bracket.", token.source};
1494 case TokenType::PUNCTUATOR_OPEN_CURLY_BRACE: {
1495 const SourceLocation source = token.source;
1496 visitor.visitObject(source, *this);
1497 break;
1498 }
1499 case TokenType::PUNCTUATOR_CLOSE_CURLY_BRACE: throw Error{"Unexpected closing brace.", token.source};
1500 case TokenType::STRING: visitor.visitString(token.source, std::move(eat().string)); break;
1501 case TokenType::NUMBER_BINARY: visitor.visitNumber(token.source, parseNumberContents(eat(), 2)); break;
1502 case TokenType::NUMBER_OCTAL: visitor.visitNumber(token.source, parseNumberContents(eat(), 8)); break;
1503 case TokenType::NUMBER_DECIMAL: visitor.visitNumber(token.source, parseNumberContents(eat(), 10)); break;
1504 case TokenType::NUMBER_HEXADECIMAL: visitor.visitNumber(token.source, parseNumberContents(eat(), 16)); break;
1505 case TokenType::NUMBER_POSITIVE_INFINITY:
1506 advance();
1507 visitor.visitNumber(token.source, Number{std::numeric_limits<Number>::infinity()});
1508 break;
1509 case TokenType::NUMBER_NEGATIVE_INFINITY:
1510 advance();
1511 visitor.visitNumber(token.source, Number{-std::numeric_limits<Number>::infinity()});
1512 break;
1513 case TokenType::NUMBER_POSITIVE_NAN:
1514 advance();
1515 visitor.visitNumber(token.source, Number{std::numeric_limits<Number>::quiet_NaN()});
1516 break;
1517 case TokenType::NUMBER_NEGATIVE_NAN:
1518 advance();
1519 visitor.visitNumber(token.source, Number{-std::numeric_limits<Number>::quiet_NaN()});
1520 break;
1521 }
1522 }
1523
1539 if (const Token& token = peek(); token.type != TokenType::PUNCTUATOR_OPEN_CURLY_BRACE) {
1540 throw Error{"Expected an object.", token.source};
1541 }
1542 advance();
1543 while (true) {
1544 String key{};
1545 switch (const Token& token = peek(); token.type) {
1546 case TokenType::END_OF_FILE: throw Error{"Missing end of object.", token.source};
1547 case TokenType::IDENTIFIER_NULL: throw Error{"Unexpected null.", token.source};
1548 case TokenType::IDENTIFIER_FALSE: throw Error{"Unexpected false.", token.source};
1549 case TokenType::IDENTIFIER_TRUE: throw Error{"Unexpected true.", token.source};
1550 case TokenType::IDENTIFIER_NAME: [[fallthrough]];
1551 case TokenType::STRING: key = std::move(eat().string); break;
1552 case TokenType::PUNCTUATOR_COMMA: [[fallthrough]];
1553 case TokenType::PUNCTUATOR_COLON: [[fallthrough]];
1554 case TokenType::PUNCTUATOR_OPEN_SQUARE_BRACKET: [[fallthrough]];
1555 case TokenType::PUNCTUATOR_CLOSE_SQUARE_BRACKET: [[fallthrough]];
1556 case TokenType::PUNCTUATOR_OPEN_CURLY_BRACE: throw Error{"Unexpected punctuator.", token.source};
1557 case TokenType::PUNCTUATOR_CLOSE_CURLY_BRACE: advance(); return;
1558 case TokenType::NUMBER_BINARY: [[fallthrough]];
1559 case TokenType::NUMBER_OCTAL: [[fallthrough]];
1560 case TokenType::NUMBER_DECIMAL: [[fallthrough]];
1561 case TokenType::NUMBER_HEXADECIMAL: [[fallthrough]];
1562 case TokenType::NUMBER_POSITIVE_INFINITY: [[fallthrough]];
1563 case TokenType::NUMBER_NEGATIVE_INFINITY: [[fallthrough]];
1564 case TokenType::NUMBER_POSITIVE_NAN: [[fallthrough]];
1565 case TokenType::NUMBER_NEGATIVE_NAN: throw Error{"Unexpected number.", token.source};
1566 }
1567 if (const Token token = eat(); token.type != TokenType::PUNCTUATOR_COLON) {
1568 throw Error{"Expected a colon.", token.source};
1569 }
1570 const SourceLocation source = peek().source;
1571 visitor.visitProperty(source, std::move(key), *this);
1572 if (peek().source == source) {
1573 struct SkipValue final : ValueVisitor {
1574 // clang-format off
1575 void visitNull(const SourceLocation& source, Null value) override { (void)source; (void)value; }
1576 void visitBoolean(const SourceLocation& source, Boolean value) override { (void)source; (void)value; }
1577 void visitString(const SourceLocation& source, String&& value) override { (void)source; (void)std::move(value); }
1578 void visitNumber(const SourceLocation& source, Number value) override { (void)source; (void)value; }
1579 void visitObject(const SourceLocation& source, Parser& parser) override { (void)source; (void)parser; }
1580 void visitArray(const SourceLocation& source, Parser& parser) override { (void)source; (void)parser; }
1581 // clang-format on
1582 };
1583 parseValue(SkipValue{});
1584 }
1585 if (const Token& token = peek(); token.type == TokenType::PUNCTUATOR_COMMA) {
1586 advance();
1587 } else if (token.type == TokenType::PUNCTUATOR_CLOSE_CURLY_BRACE) {
1588 advance();
1589 break;
1590 } else {
1591 throw Error{"Expected a comma or closing brace.", token.source};
1592 }
1593 }
1594 }
1595
1614 void parseArray(ValueVisitor& visitor) {
1615 if (const Token& token = peek(); token.type != TokenType::PUNCTUATOR_OPEN_SQUARE_BRACKET) {
1616 throw Error{"Expected an array.", token.source};
1617 }
1618 advance();
1619 while (true) {
1620 if (peek().type == TokenType::PUNCTUATOR_CLOSE_SQUARE_BRACKET) {
1621 advance();
1622 return;
1623 }
1624 parseValue(visitor);
1625 if (const Token& token = peek(); token.type == TokenType::PUNCTUATOR_COMMA) {
1626 advance();
1627 } else if (token.type == TokenType::PUNCTUATOR_CLOSE_SQUARE_BRACKET) {
1628 advance();
1629 break;
1630 } else {
1631 throw Error{"Expected a comma or closing bracket.", token.source};
1632 }
1633 }
1634 }
1635
1639 void parseFile(ValueVisitor&& visitor) { // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
1640 parseFile(visitor);
1641 }
1642
1646 void parseValue(ValueVisitor&& visitor) { // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
1647 parseValue(visitor);
1648 }
1649
1653 void parseObject(PropertyVisitor&& visitor) { // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
1654 parseObject(visitor);
1655 }
1656
1660 void parseArray(ValueVisitor&& visitor) { // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
1661 parseArray(visitor);
1662 }
1663
1667 template <typename Visitor>
1668 void parseFile(Visitor visitor) {
1669 parseFile(static_cast<ValueVisitor&&>(ConcreteValueVisitor<Visitor>{std::move(visitor)}));
1670 }
1671
1675 template <typename Visitor>
1676 void parseValue(Visitor visitor) {
1677 parseValue(static_cast<ValueVisitor&&>(ConcreteValueVisitor<Visitor>{std::move(visitor)}));
1678 }
1679
1683 template <typename Visitor>
1684 void parseObject(Visitor visitor) {
1685 parseObject(static_cast<PropertyVisitor&&>(ConcretePropertyVisitor<Visitor>{std::move(visitor)}));
1686 }
1687
1691 template <typename Visitor>
1692 void parseArray(Visitor visitor) {
1693 parseArray(static_cast<ValueVisitor&&>(ConcreteValueVisitor<Visitor>{std::move(visitor)}));
1694 }
1695
1707 void skipFile() {
1708 parseFile(SkipValueVisitor{});
1709 }
1710
1721 void skipValue() {
1722 parseValue(SkipValueVisitor{});
1723 }
1724
1740 Value result = parseValue();
1741 if (const Token& token = peek(); token.type != TokenType::END_OF_FILE) {
1742 throw Error{"Multiple top-level values.", token.source};
1743 }
1744 return result;
1745 }
1746
1767 struct Visitor final : ValueVisitor {
1768 Value& result;
1769
1770 explicit Visitor(Value& result) noexcept
1771 : result(result) {}
1772
1773 // clang-format off
1774 void visitNull(const SourceLocation&, Null value) override { result = value; }
1775 void visitBoolean(const SourceLocation&, Boolean value) override { result = value; }
1776 void visitString(const SourceLocation&, String&& value) override { result = std::move(value); }
1777 void visitNumber(const SourceLocation&, Number value) override { result = value; }
1778 void visitObject(const SourceLocation&, Parser& parser) override { result = parser.parseObject(); }
1779 void visitArray(const SourceLocation&, Parser& parser) override { result = parser.parseArray(); }
1780 // clang-format on
1781 };
1782 Value result{};
1783 parseValue(Visitor{result});
1784 return result;
1785 }
1786
1799 const Token token = eat();
1800 switch (token.type) {
1801 case TokenType::IDENTIFIER_NULL: return Null{};
1802 default: break;
1803 }
1804 throw Error{"Expected a null.", token.source};
1805 }
1806
1819 const Token token = eat();
1820 switch (token.type) {
1821 case TokenType::IDENTIFIER_FALSE: return Boolean{false};
1822 case TokenType::IDENTIFIER_TRUE: return Boolean{true};
1823 default: break;
1824 }
1825 throw Error{"Expected a boolean.", token.source};
1826 }
1827
1840 Token token = eat();
1841 switch (token.type) {
1842 case TokenType::STRING: return std::move(token.string);
1843 default: break;
1844 }
1845 throw Error{"Expected a string.", token.source};
1846 }
1847
1860 Token token = eat();
1861 switch (token.type) {
1862 case TokenType::NUMBER_BINARY: return parseNumberContents(std::move(token), 2);
1863 case TokenType::NUMBER_OCTAL: return parseNumberContents(std::move(token), 8);
1864 case TokenType::NUMBER_DECIMAL: return parseNumberContents(std::move(token), 10);
1865 case TokenType::NUMBER_HEXADECIMAL: return parseNumberContents(std::move(token), 16);
1866 case TokenType::NUMBER_POSITIVE_INFINITY: return std::numeric_limits<Number>::infinity();
1867 case TokenType::NUMBER_NEGATIVE_INFINITY: return -std::numeric_limits<Number>::infinity();
1868 case TokenType::NUMBER_POSITIVE_NAN: return std::numeric_limits<Number>::quiet_NaN();
1869 case TokenType::NUMBER_NEGATIVE_NAN: return -std::numeric_limits<Number>::quiet_NaN();
1870 default: break;
1871 }
1872 throw Error{"Expected a number.", token.source};
1873 }
1874
1888 const Token& token = peek();
1889 switch (token.type) {
1890 case TokenType::PUNCTUATOR_OPEN_CURLY_BRACE: {
1891 struct Visitor final : PropertyVisitor {
1892 Object& result;
1893
1894 explicit Visitor(Object& result) noexcept
1895 : result(result) {}
1896
1897 void visitProperty(const SourceLocation&, String&& key, Parser& parser) override {
1898 result.emplace(std::move(key), std::move(parser.parseValue()));
1899 }
1900 };
1901 Object result{};
1902 parseObject(Visitor{result});
1903 return result;
1904 }
1905 default: break;
1906 }
1907 throw Error{"Expected an object.", token.source};
1908 }
1909
1923 const Token& token = peek();
1924 switch (token.type) {
1925 case TokenType::PUNCTUATOR_OPEN_SQUARE_BRACKET: {
1926 Array result{};
1927 struct Visitor final : ValueVisitor {
1928 Array& result;
1929
1930 explicit Visitor(Array& result) noexcept
1931 : result(result) {}
1932
1933 // clang-format off
1934 void visitNull(const SourceLocation&, Null value) override { result.emplace_back(value); }
1935 void visitBoolean(const SourceLocation&, Boolean value) override { result.emplace_back(value); }
1936 void visitString(const SourceLocation&, String&& value) override { result.emplace_back(std::move(value)); }
1937 void visitNumber(const SourceLocation&, Number value) override { result.emplace_back(value); }
1938 void visitObject(const SourceLocation&, Parser& parser) override { result.emplace_back(parser.parseObject()); }
1939 void visitArray(const SourceLocation&, Parser& parser) override { result.emplace_back(parser.parseArray()); }
1940 // clang-format on
1941 };
1942 parseArray(Visitor{result});
1943 return result;
1944 }
1945 default: break;
1946 }
1947 throw Error{"Expected an array.", token.source};
1948 }
1949
1957 void advance() {
1958 if (!currentToken) {
1959 lexer.scan();
1960 }
1961 currentToken.reset();
1962 }
1963
1980 [[nodiscard]] const Token& peek() const {
1981 if (!currentToken) {
1982 currentToken = lexer.scan();
1983 }
1984 return *currentToken;
1985 }
1986
1998 [[nodiscard]] Token eat() {
1999 if (!currentToken) {
2000 currentToken = lexer.scan();
2001 }
2002 Token result = std::move(*currentToken);
2003 currentToken.reset();
2004 return result;
2005 }
2006
2007private:
2008 [[nodiscard]] static Number parseNumberContents(Token token, int radix) {
2009 const char* numberStringBegin = token.string.c_str();
2010 char* const numberStringEnd = token.string.data() + token.string.size();
2011 char* endPointer = numberStringEnd;
2012 if (radix == 10) {
2013 const double number_value = std::strtod(numberStringBegin, &endPointer);
2014 if (endPointer != numberStringEnd) {
2015 throw Error{"Invalid number.", token.source};
2016 }
2017 return Number{number_value};
2018 }
2019 bool negative = false;
2020 if (!token.string.empty() && token.string.front() == '-') {
2021 negative = true;
2022 ++numberStringBegin;
2023 }
2024 const unsigned long long integerNumberValue = std::strtoull(numberStringBegin, &endPointer, radix);
2025 if (endPointer != numberStringEnd) {
2026 throw Error{"Invalid number.", token.source};
2027 }
2028 const double numberValue = static_cast<double>(integerNumberValue);
2029 return Number{(negative) ? -numberValue : numberValue};
2030 }
2031
2032 mutable Lexer<It> lexer;
2033 mutable std::optional<Token> currentToken{};
2034};
2035
2040
2045
2046namespace detail {
2047
2048template <typename T, typename ObjectPropertyFilter = detail::AlwaysTrue, typename ArrayItemFilter = detail::AlwaysTrue>
2049[[nodiscard]] std::size_t getRecursiveSize(const T& value, ObjectPropertyFilter objectPropertyFilter, ArrayItemFilter arrayItemFilter);
2050
2051} // namespace detail
2052
2069template <typename T>
2070struct Serializer;
2071
2087template <typename T>
2088struct Deserializer;
2089
2106template <typename T>
2107void serialize(std::ostream& stream, const T& value, const SerializationOptions& options = {});
2108
2126template <typename T>
2127void deserialize(std::istream& stream, T& value, const DeserializationOptions& options = {});
2128
2142inline std::ostream& operator<<(std::ostream& stream, const Value& value) {
2143 json::serialize(stream, value);
2144 return stream;
2145}
2146
2163inline std::istream& operator>>(std::istream& stream, Value& value) {
2164 try {
2165 json::deserialize(stream, value);
2166 } catch (const Error&) {
2167 stream.setstate(std::istream::failbit);
2168 }
2169 return stream;
2170}
2171
2175struct Writer {
2176private:
2177 std::ostream& stream;
2178
2179public:
2184
2191 explicit Writer(std::ostream& stream, const SerializationOptions& options = {})
2192 : stream(stream)
2193 , options(options) {}
2194
2202 void write(char byte) {
2203 stream << byte;
2204 }
2205
2213 void write(std::string_view bytes) {
2214 stream << bytes;
2215 }
2216
2229 for (std::size_t i = 0; i < options.indentation; ++i) {
2230 write(options.indentationCharacter);
2231 }
2232 }
2233
2240 stream << options.newlineString;
2241 }
2242
2248 void writeNull() {
2249 write("null");
2250 }
2251
2259 void writeBoolean(Boolean value) {
2260 write((value) ? "true" : "false");
2261 }
2262
2271 void writeString(std::string_view bytes) {
2272 constexpr std::array<char, 16> HEXADECIMAL_DIGITS{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
2273 write('\"');
2274 for (const char byte : bytes) {
2275 if (byte >= ' ' && byte <= '~' && byte != '\"' && byte != '\\') {
2276 write(byte);
2277 } else {
2278 write('\\');
2279 switch (byte) {
2280 case '\"': write('\"'); break;
2281 case '\\': write('\\'); break;
2282 case '\b': write('b'); break;
2283 case '\f': write('f'); break;
2284 case '\n': write('n'); break;
2285 case '\r': write('r'); break;
2286 case '\t': write('t'); break;
2287 case '\v': write('v'); break;
2288 case '\0': write('0'); break;
2289 default:
2290 write('x');
2291 write(HEXADECIMAL_DIGITS[(byte >> 4) & 0x0F]);
2292 write(HEXADECIMAL_DIGITS[(byte & 0x0F)]);
2293 break;
2294 }
2295 }
2296 }
2297 write('\"');
2298 }
2299
2308 template <typename CharT, typename Traits>
2309 void writeString(std::basic_string_view<CharT, Traits> value) requires(!std::is_same_v<CharT, char> || !std::is_same_v<Traits, std::char_traits<char>>) {
2310 const std::span<const std::byte> bytes = std::as_bytes(std::span{value.data(), value.size()});
2311 writeString(std::string_view{reinterpret_cast<const char*>(bytes.data()), bytes.size()});
2312 }
2313
2324 void writeString(const auto& value) {
2325 if constexpr (requires { std::string_view{value}; }) {
2326 writeString(std::string_view{value});
2327 } else if constexpr (requires { std::u8string_view{value}; }) {
2328 writeString(std::u8string_view{value});
2329 } else if constexpr (requires { std::u16string_view{value}; }) {
2330 writeString(std::u16string_view{value});
2331 } else if constexpr (requires { std::u32string_view{value}; }) {
2332 writeString(std::u32string_view{value});
2333 } else if constexpr (requires { std::wstring_view{value}; }) {
2334 writeString(std::wstring_view{value});
2335 } else {
2336 std::ostringstream stringStream{};
2337 json::serialize(stringStream, value, {.prettyPrint = false});
2338 writeString(std::move(stringStream).str());
2339 }
2340 }
2341
2349 void writeNumber(Number value) {
2350 if (std::isnan(value)) {
2351 if (std::signbit(value)) {
2352 stream << "-NaN";
2353 } else {
2354 stream << "NaN";
2355 }
2356 } else if (std::isinf(value)) {
2357 if (std::signbit(value)) {
2358 stream << "-Infinity";
2359 } else {
2360 stream << "Infinity";
2361 }
2362 } else {
2363 [[likely]] fmt::format_to(std::ostreambuf_iterator{stream}, "{}", value);
2364 }
2365 }
2366
2384 template <typename PropertyFilter = detail::AlwaysTrue, typename GetKey = detail::GetFirst, typename GetValue = detail::GetSecond>
2385 void writeObject(const auto& value, PropertyFilter propertyFilter = {}, GetKey getKey = {}, GetValue getValue = {}) {
2386 auto it = std::begin(value);
2387 const auto end = std::end(value);
2388 while (it != end && !propertyFilter(*it)) {
2389 ++it;
2390 }
2391 if (options.prettyPrint) {
2392 if (it == end) {
2393 write("{}");
2394 } else if (detail::getRecursiveSize(value, propertyFilter, {}) - 1 <= options.prettyPrintMaxSingleLineObjectPropertyCount) {
2395 write("{ ");
2396 writeString(getKey(*it));
2397 write(": ");
2398 serialize(getValue(*it));
2399 for (++it; it != end; ++it) {
2400 if (propertyFilter(*it)) {
2401 write(", ");
2402 writeString(getKey(*it));
2403 write(": ");
2404 serialize(getValue(*it));
2405 }
2406 }
2407 write(" }");
2408 } else {
2409 write('{');
2410 writeNewline();
2411 options.indentation += options.relativeIndentation;
2412 writeIndentation();
2413 writeString(getKey(*it));
2414 write(": ");
2415 serialize(getValue(*it));
2416 for (++it; it != end; ++it) {
2417 if (propertyFilter(*it)) {
2418 write(',');
2419 writeNewline();
2420 writeIndentation();
2421 writeString(getKey(*it));
2422 write(": ");
2423 serialize(getValue(*it));
2424 }
2425 }
2426 writeNewline();
2427 options.indentation -= options.relativeIndentation;
2428 writeIndentation();
2429 write('}');
2430 }
2431 } else {
2432 write('{');
2433 if (it != end) {
2434 writeString(getKey(*it));
2435 write(':');
2436 serialize(getValue(*it));
2437 for (++it; it != end; ++it) {
2438 if (propertyFilter(*it)) {
2439 write(',');
2440 writeString(getKey(*it));
2441 write(':');
2442 serialize(getValue(*it));
2443 }
2444 }
2445 }
2446 write('}');
2447 }
2448 }
2449
2464 template <typename ItemFilter = detail::AlwaysTrue, typename GetValue = detail::Get>
2465 void writeArray(const auto& value, ItemFilter itemFilter = {}, GetValue getValue = {}) {
2466 auto it = std::begin(value);
2467 const auto end = std::end(value);
2468 while (it != end && !itemFilter(*it)) {
2469 ++it;
2470 }
2471 if (options.prettyPrint) {
2472 if (it == end) {
2473 write("[]");
2474 } else if (detail::getRecursiveSize(value, {}, itemFilter) - 1 <= options.prettyPrintMaxSingleLineArrayItemCount) {
2475 write('[');
2476 serialize(getValue(*it));
2477 for (++it; it != end; ++it) {
2478 if (itemFilter(*it)) {
2479 write(", ");
2480 serialize(getValue(*it));
2481 }
2482 }
2483 write(']');
2484 } else {
2485 write('[');
2486 writeNewline();
2487 options.indentation += options.relativeIndentation;
2488 writeIndentation();
2489 serialize(getValue(*it));
2490 for (++it; it != end; ++it) {
2491 if (itemFilter(*it)) {
2492 write(',');
2493 writeNewline();
2494 writeIndentation();
2495 serialize(getValue(*it));
2496 }
2497 }
2498 writeNewline();
2499 options.indentation -= options.relativeIndentation;
2500 writeIndentation();
2501 write(']');
2502 }
2503 } else {
2504 write('[');
2505 if (it != end) {
2506 serialize(getValue(*it));
2507 for (++it; it != end; ++it) {
2508 if (itemFilter(*it)) {
2509 write(',');
2510 serialize(getValue(*it));
2511 }
2512 }
2513 }
2514 write(']');
2515 }
2516 }
2517
2531 void writeOptional(const auto& value) {
2532 if (value) {
2533 serialize(*value);
2534 } else {
2535 writeNull();
2536 }
2537 }
2538
2548 template <typename T>
2549 void writeAggregate(const T& value) {
2550 if constexpr (reflection::aggregate_size_v<T> == 0) {
2551 write("[]");
2552 } else if constexpr (reflection::aggregate_size_v<T> == 1) {
2553 const auto& [v] = value;
2554 serialize(v);
2555 } else if (options.prettyPrint) {
2556 if (detail::getRecursiveSize(value, {}, {}) - 1 <= options.prettyPrintMaxSingleLineArrayItemCount) {
2557 write('[');
2558 bool successor = false;
2559 reflection::forEach(reflection::fields(value), [&](const auto& v) {
2560 if (successor) {
2561 write(", ");
2562 }
2563 successor = true;
2564 serialize(v);
2565 });
2566 write(']');
2567 } else {
2568 write('[');
2569 writeNewline();
2570 options.indentation += options.relativeIndentation;
2571 bool successor = false;
2572 reflection::forEach(reflection::fields(value), [&](const auto& v) {
2573 if (successor) {
2574 write(',');
2575 writeNewline();
2576 }
2577 successor = true;
2578 writeIndentation();
2579 serialize(v);
2580 });
2581 writeNewline();
2582 options.indentation -= options.relativeIndentation;
2583 writeIndentation();
2584 write(']');
2585 }
2586 } else {
2587 write('[');
2588 bool successor = false;
2589 reflection::forEach(reflection::fields(value), [&](const auto& v) {
2590 if (successor) {
2591 write(',');
2592 }
2593 successor = true;
2594 serialize(v);
2595 });
2596 write(']');
2597 }
2598 }
2599
2609 template <typename T>
2610 void serialize(const T& value) {
2612 }
2613};
2614
2618struct Reader {
2619private:
2620 using It = std::istreambuf_iterator<char>;
2621
2622 Parser<It> parser;
2623
2624public:
2629
2636 explicit Reader(std::istream& stream, const DeserializationOptions& options = {})
2637 : parser(stream)
2638 , options(options) {}
2639
2653 const SourceLocation source = parser.peek().source;
2654 parser.parseNull();
2655 return source;
2656 }
2657
2674 const SourceLocation source = parser.peek().source;
2675 value = parser.parseBoolean();
2676 return source;
2677 }
2678
2695 const SourceLocation source = parser.peek().source;
2696 value = parser.parseString();
2697 return source;
2698 }
2699
2715 String string{};
2716 const SourceLocation source = readString(string);
2717 if constexpr (requires { value = std::move(string); }) {
2718 value = std::move(string);
2719 } else if constexpr (requires { value = std::string{}; }) {
2720 value = std::string{std::move(string)};
2721 } else if constexpr (requires { value = std::u8string{}; }) {
2722 value = std::u8string{string.begin(), string.end()};
2723 } else if constexpr (requires { value = std::u16string{}; }) {
2724 if (string.size() % sizeof(char16_t) != 0) {
2725 throw Error{"Expected a sequence of complete UTF-16 code units.", source};
2726 }
2727 std::u16string temporaryString = std::u16string(string.size() / sizeof(char16_t), char16_t{});
2728 std::memcpy(temporaryString.data(), string.data(), string.size());
2729 value = std::move(temporaryString);
2730 } else if constexpr (requires { value = std::u32string{}; }) {
2731 if (string.size() % sizeof(char32_t) != 0) {
2732 throw Error{"Expected a sequence of complete UTF-32 code units.", source};
2733 }
2734 std::u32string temporaryString = std::u32string(string.size() / sizeof(char32_t), char32_t{});
2735 std::memcpy(temporaryString.data(), string.data(), string.size());
2736 value = std::move(temporaryString);
2737 } else if constexpr (requires { value = std::wstring{}; }) {
2738 if (string.size() % sizeof(wchar_t) != 0) {
2739 throw Error{"Expected a sequence of complete wide characters.", source};
2740 }
2741 std::wstring temporaryString = std::wstring(string.size() / sizeof(wchar_t), wchar_t{});
2742 std::memcpy(temporaryString.data(), string.data(), string.size());
2743 value = std::move(temporaryString);
2744 } else {
2745 std::istringstream stringStream{std::move(string)}; // NOLINT(performance-move-const-arg)
2746 json::deserialize(stringStream, value);
2747 }
2748 return source;
2749 }
2750
2767 const SourceLocation source = parser.peek().source;
2768 value = parser.parseNumber();
2769 return source;
2770 }
2771
2786 template <typename T>
2788 Number number{};
2789 const SourceLocation source = readNumber(number);
2790 value = static_cast<T>(number);
2791 return source;
2792 }
2793
2810 const SourceLocation source = parser.peek().source;
2811 value = parser.parseObject();
2812 return source;
2813 }
2814
2841 const SourceLocation source = parser.peek().source;
2842 if (const Token token = parser.eat(); token.type != TokenType::PUNCTUATOR_OPEN_CURLY_BRACE) {
2843 throw Error{"Expected an object.", token.source};
2844 }
2845 value.clear();
2846 if (parser.peek().type != TokenType::PUNCTUATOR_CLOSE_CURLY_BRACE) {
2847 while (true) {
2848 std::remove_cvref_t<decltype(std::begin(value)->first)> propertyKey{};
2849 std::remove_cvref_t<decltype(std::begin(value)->second)> propertyValue{};
2850 readString(propertyKey);
2851 if (const Token token = parser.eat(); token.type != TokenType::PUNCTUATOR_COLON) {
2852 throw Error{"Expected a colon.", token.source};
2853 }
2854 deserialize(propertyValue);
2855 value.emplace(std::move(propertyKey), std::move(propertyValue));
2856 const Token token = parser.eat();
2857 if (token.type == TokenType::PUNCTUATOR_CLOSE_CURLY_BRACE) {
2858 break;
2859 }
2860 if (token.type == TokenType::PUNCTUATOR_COMMA) {
2861 if (parser.peek().type == TokenType::PUNCTUATOR_CLOSE_CURLY_BRACE) {
2862 parser.advance();
2863 break;
2864 }
2865 } else {
2866 throw Error{"Expected a comma or closing brace.", token.source};
2867 }
2868 }
2869 }
2870 return source;
2871 }
2872
2889 const SourceLocation source = parser.peek().source;
2890 value = parser.parseArray();
2891 return source;
2892 }
2893
2918 const SourceLocation source = parser.peek().source;
2919 if (const Token token = parser.eat(); token.type != TokenType::PUNCTUATOR_OPEN_SQUARE_BRACKET) {
2920 throw Error{"Expected an array.", token.source};
2921 }
2922 value.clear();
2923 if (parser.peek().type != TokenType::PUNCTUATOR_CLOSE_SQUARE_BRACKET) {
2924 while (true) {
2925 std::remove_cvref_t<decltype(*std::begin(value))> item{};
2926 deserialize(item);
2927 value.push_back(std::move(item));
2928 const Token token = parser.eat();
2929 if (token.type == TokenType::PUNCTUATOR_CLOSE_SQUARE_BRACKET) {
2930 break;
2931 }
2932 if (token.type == TokenType::PUNCTUATOR_COMMA) {
2933 if (parser.peek().type == TokenType::PUNCTUATOR_CLOSE_SQUARE_BRACKET) {
2934 parser.advance();
2935 break;
2936 }
2937 } else {
2938 throw Error{"Expected a comma or closing bracket.", token.source};
2939 }
2940 }
2941 }
2942 return source;
2943 }
2944
2961 const SourceLocation source = parser.peek().source;
2962 value = parser.parseValue();
2963 return source;
2964 }
2965
2989 template <typename T>
2991 const SourceLocation source = parser.peek().source;
2992 if (parser.peek().type == TokenType::IDENTIFIER_NULL) {
2993 parser.advance();
2994 value = T{};
2995 } else {
2996 std::remove_cvref_t<decltype(*value)> result{};
2997 deserialize(result);
2998 value = std::move(result);
2999 }
3000 return source;
3001 }
3002
3022 template <typename T>
3024 const SourceLocation source = parser.peek().source;
3025 if constexpr (reflection::aggregate_size_v<T> == 1) {
3026 auto& [v] = value;
3027 deserialize(v);
3028 } else {
3029 if (const Token token = parser.eat(); token.type != TokenType::PUNCTUATOR_OPEN_SQUARE_BRACKET) {
3030 throw Error{"Expected an array.", token.source};
3031 }
3032 bool successor = false;
3033 reflection::forEach(reflection::fields(value), [&](auto& v) -> void {
3034 if (successor) {
3035 if (const Token token = parser.eat(); token.type != TokenType::PUNCTUATOR_COMMA) {
3036 throw Error{"Expected a comma.", token.source};
3037 }
3038 }
3039 successor = true;
3040 deserialize(v);
3041 });
3042 Token token = parser.eat();
3043 if (token.type == TokenType::PUNCTUATOR_COMMA) {
3044 token = parser.eat();
3045 }
3046 if (token.type != TokenType::PUNCTUATOR_CLOSE_SQUARE_BRACKET) {
3047 throw Error{"Missing end of array.", token.source};
3048 }
3049 }
3050 return source;
3051 }
3052
3062 template <typename T>
3063 void deserialize(T& value) {
3065 }
3066};
3067
3081template <typename T>
3082inline void serialize(std::ostream& stream, const T& value, const SerializationOptions& options) {
3083 Writer{stream, options}.serialize(value);
3084}
3085
3099template <typename T>
3100inline void deserialize(std::istream& stream, T& value, const DeserializationOptions& options) {
3101 Reader{stream, options}.deserialize(value);
3102}
3103
3104namespace detail {
3105
3106struct NoVisitor {};
3107
3108template <typename Base, typename Callback>
3109struct VisitNull : Base {
3110 [[no_unique_address]] Callback callback;
3111
3112 VisitNull(Callback callback)
3113 : callback(std::move(callback)) {}
3114
3115 VisitNull(Base base, Callback callback)
3116 : Base(std::move(base))
3117 , callback(std::move(callback)) {}
3118
3119 void visitNull(const SourceLocation& source, Null value) {
3120 callback(source, value);
3121 }
3122
3123 template <typename NewBase>
3124 [[nodiscard]] auto operator|(NewBase other) && {
3125 return VisitNull<NewBase, Callback>{std::move(other), std::move(callback)};
3126 }
3127};
3128
3129template <typename Base, typename Callback>
3130struct VisitBoolean : Base {
3131 [[no_unique_address]] Callback callback;
3132
3133 VisitBoolean(Callback callback)
3134 : callback(std::move(callback)) {}
3135
3136 VisitBoolean(Base base, Callback callback)
3137 : Base(std::move(base))
3138 , callback(std::move(callback)) {}
3139
3140 void visitBoolean(const SourceLocation& source, Boolean value) {
3141 callback(source, value);
3142 }
3143
3144 template <typename NewBase>
3145 [[nodiscard]] auto operator|(NewBase other) && {
3146 return VisitBoolean<NewBase, Callback>{std::move(other), std::move(callback)};
3147 }
3148};
3149
3150template <typename Base, typename Callback>
3151struct VisitString : Base {
3152 [[no_unique_address]] Callback callback;
3153
3154 VisitString(Callback callback)
3155 : callback(std::move(callback)) {}
3156
3157 VisitString(Base base, Callback callback)
3158 : Base(std::move(base))
3159 , callback(std::move(callback)) {}
3160
3161 void visitString(const SourceLocation& source, String&& value) {
3162 callback(source, std::move(value));
3163 }
3164
3165 template <typename NewBase>
3166 [[nodiscard]] auto operator|(NewBase other) && {
3167 return VisitString<NewBase, Callback>{std::move(other), std::move(callback)};
3168 }
3169};
3170
3171template <typename Base, typename Callback>
3172struct VisitNumber : Base {
3173 [[no_unique_address]] Callback callback;
3174
3175 VisitNumber(Callback callback)
3176 : callback(std::move(callback)) {}
3177
3178 VisitNumber(Base base, Callback callback)
3179 : Base(std::move(base))
3180 , callback(std::move(callback)) {}
3181
3182 void visitNumber(const SourceLocation& source, Number value) {
3183 callback(source, value);
3184 }
3185
3186 template <typename NewBase>
3187 [[nodiscard]] auto operator|(NewBase other) && {
3188 return VisitNumber<NewBase, Callback>{std::move(other), std::move(callback)};
3189 }
3190};
3191
3192template <typename Base, typename Callback>
3193struct VisitObject : Base {
3194 [[no_unique_address]] Callback callback;
3195
3196 VisitObject(Callback callback)
3197 : callback(std::move(callback)) {}
3198
3199 VisitObject(Base base, Callback callback)
3200 : Base(std::move(base))
3201 , callback(std::move(callback)) {}
3202
3203 void visitObject(const SourceLocation& source, auto& parser) {
3204 callback(source, parser);
3205 }
3206
3207 template <typename NewBase>
3208 [[nodiscard]] auto operator|(NewBase other) && {
3209 return VisitObject<NewBase, Callback>{std::move(other), std::move(callback)};
3210 }
3211};
3212
3213template <typename Base, typename Callback>
3214struct VisitArray : Base {
3215 [[no_unique_address]] Callback callback;
3216
3217 VisitArray(Callback callback)
3218 : callback(std::move(callback)) {}
3219
3220 VisitArray(Base base, Callback callback)
3221 : Base(std::move(base))
3222 , callback(std::move(callback)) {}
3223
3224 void visitArray(const SourceLocation& source, auto& parser) {
3225 callback(source, parser);
3226 }
3227
3228 template <typename NewBase>
3229 [[nodiscard]] auto operator|(NewBase other) && {
3230 return VisitArray<NewBase, Callback>{std::move(other), std::move(callback)};
3231 }
3232};
3233
3234template <typename Base, typename Callback>
3235struct VisitProperty : Base {
3236 [[no_unique_address]] Callback callback;
3237
3238 VisitProperty(Callback callback)
3239 : callback(std::move(callback)) {}
3240
3241 VisitProperty(Base base, Callback callback)
3242 : Base(std::move(base))
3243 , callback(std::move(callback)) {}
3244
3245 void visitProperty(const SourceLocation& source, String&& key, auto& parser) {
3246 callback(source, std::move(key), parser);
3247 }
3248
3249 template <typename NewBase>
3250 [[nodiscard]] auto operator|(NewBase other) && {
3251 return VisitProperty<NewBase, Callback>{std::move(other), std::move(callback)};
3252 }
3253};
3254
3255} // namespace detail
3256
3279template <typename Callback>
3280[[nodiscard]] inline auto onNull(Callback callback) {
3281 return detail::VisitNull<detail::NoVisitor, Callback>{std::move(callback)};
3282}
3283
3306template <typename Callback>
3307[[nodiscard]] inline auto onBoolean(Callback callback) {
3308 return detail::VisitBoolean<detail::NoVisitor, Callback>{std::move(callback)};
3309}
3310
3333template <typename Callback>
3334[[nodiscard]] inline auto onString(Callback callback) {
3335 return detail::VisitString<detail::NoVisitor, Callback>{std::move(callback)};
3336}
3337
3360template <typename Callback>
3361[[nodiscard]] inline auto onNumber(Callback callback) {
3362 return detail::VisitNumber<detail::NoVisitor, Callback>{std::move(callback)};
3363}
3364
3387template <typename Callback>
3388[[nodiscard]] inline auto onObject(Callback callback) {
3389 return detail::VisitObject<detail::NoVisitor, Callback>{std::move(callback)};
3390}
3391
3414template <typename Callback>
3415[[nodiscard]] inline auto onArray(Callback callback) {
3416 return detail::VisitArray<detail::NoVisitor, Callback>{std::move(callback)};
3417}
3418
3434template <typename Callback>
3435[[nodiscard]] inline auto onProperty(Callback callback) {
3436 return detail::VisitProperty<detail::NoVisitor, Callback>{std::move(callback)};
3437}
3438
3439namespace detail {
3440
3441template <typename T>
3442concept nullable = //
3443 !std::is_arithmetic_v<T> && //
3444 requires(const T& value) {
3445 static_cast<bool>(value);
3446 static_cast<bool>(!value);
3447 T{};
3448 };
3449
3450template <typename T>
3451concept serializable_as_string = //
3452 std::is_same_v<T, String> || //
3453 requires(const T& value) { std::string_view{value}; } || //
3454 requires(const T& value) { std::u8string_view{value}; } || //
3455 requires(const T& value) { std::u16string_view{value}; } || //
3456 requires(const T& value) { std::u32string_view{value}; } || //
3457 requires(const T& value) { std::wstring_view{value}; };
3458
3459template <typename T>
3460concept deserializable_as_string = //
3461 std::is_same_v<T, String> || //
3462 requires(T& value) { value = std::string{}; } || //
3463 requires(T& value) { value = std::u8string{}; } || //
3464 requires(T& value) { value = std::u16string{}; } || //
3465 requires(T& value) { value = std::u32string{}; } || //
3466 requires(T& value) { value = std::wstring{}; };
3467
3468template <typename T>
3469concept serializable_as_object = //
3470 std::is_same_v<T, Object> || //
3471 requires(Writer& writer, const T& value) {
3472 writer.writeString(std::begin(value)->first);
3473 writer.serialize(std::begin(value)->second);
3474 };
3475
3476template <typename T>
3477concept deserializable_as_object = //
3478 std::is_same_v<T, Object> || //
3479 requires(Reader& reader, T& value) {
3480 value.clear();
3481 std::remove_cvref_t<decltype(std::begin(value)->first)>{};
3482 std::remove_cvref_t<decltype(std::begin(value)->second)>{};
3483 reader.readString(std::begin(value)->first);
3484 reader.deserialize(std::begin(value)->second);
3485 value.emplace(std::remove_cvref_t<decltype(std::begin(value)->first)>{}, std::remove_cvref_t<decltype(std::begin(value)->second)>{});
3486 };
3487
3488template <typename T>
3489concept serializable_as_array = //
3490 std::is_same_v<T, Array> || //
3491 requires(Writer& writer, const T& value) { writer.serialize(*std::begin(value)); };
3492
3493template <typename T>
3494concept deserializable_as_array = //
3495 std::is_same_v<T, Array> || //
3496 requires(Reader& reader, T& value) {
3497 value.clear();
3498 std::remove_cvref_t<decltype(*std::begin(value))>{};
3499 reader.deserialize(*std::begin(value));
3500 value.push_back(std::remove_cvref_t<decltype(*std::begin(value))>{});
3501 };
3502
3503template <typename T>
3504concept serializable_as_optional = //
3505 !std::is_pointer_v<T> && //
3506 requires(Writer& writer, const T& value) {
3507 static_cast<bool>(value);
3508 writer.serialize(*value);
3509 };
3510
3511template <typename T>
3512concept deserializable_as_optional = //
3513 !std::is_pointer_v<T> && //
3514 requires(Reader& reader, T& value, std::remove_cvref_t<decltype(*value)> result) {
3515 value = T{};
3516 std::remove_cvref_t<decltype(*value)>{};
3517 reader.deserialize(result);
3518 value = std::move(result);
3519 };
3520
3521template <typename T>
3522inline constexpr bool always_false_v = false;
3523
3524template <typename T, typename ObjectPropertyFilter, typename ArrayItemFilter>
3525inline std::size_t getRecursiveSize(const T& value, ObjectPropertyFilter objectPropertyFilter, ArrayItemFilter arrayItemFilter) {
3526 if constexpr (std::is_same_v<T, Value>) {
3527 return match(value)([&](const auto& v) -> std::size_t { return getRecursiveSize(v, objectPropertyFilter, arrayItemFilter); });
3528 } else if constexpr (serializable_as_string<T>) {
3529 return 1;
3530 } else if constexpr (serializable_as_object<T>) {
3531 if constexpr (nullable<T>) {
3532 if (!value) {
3533 return 1;
3534 }
3535 }
3536 return std::accumulate(std::begin(value), std::end(value), std::size_t{1}, [&](std::size_t count, const auto& kv) -> std::size_t {
3537 if (objectPropertyFilter(kv)) {
3538 count += getRecursiveSize(kv.second, {}, {});
3539 }
3540 return count;
3541 });
3542 } else if constexpr (serializable_as_array<T>) {
3543 if constexpr (nullable<T>) {
3544 if (!value) {
3545 return 1;
3546 }
3547 }
3548 return std::accumulate(std::begin(value), std::end(value), std::size_t{1}, [&](std::size_t count, const auto& v) -> std::size_t {
3549 if (arrayItemFilter(v)) {
3550 count += getRecursiveSize(v, {}, {});
3551 }
3552 return count;
3553 });
3554 } else if constexpr (serializable_as_optional<T>) {
3555 return 1;
3556 } else if constexpr (std::is_aggregate_v<T>) {
3557 if constexpr (nullable<T>) {
3558 if (!value) {
3559 return 1;
3560 }
3561 }
3562 std::size_t result = 1;
3563 reflection::forEach(reflection::fields(value), [&](const auto& v) -> void { result += getRecursiveSize(v, {}, {}); });
3564 return result;
3565 } else {
3566 return 1;
3567 }
3568}
3569
3570} // namespace detail
3571
3572template <typename T>
3574 void serialize(Writer& writer, const T& value) {
3575 if constexpr (detail::nullable<T>) {
3576 if (!value) {
3577 writer.writeNull();
3578 return;
3579 }
3580 }
3581 if constexpr (detail::serializable_as_string<T>) {
3582 writer.writeString(value);
3583 } else if constexpr (detail::serializable_as_object<T>) {
3584 writer.writeObject(value);
3585 } else if constexpr (detail::serializable_as_array<T>) {
3586 writer.writeArray(value);
3587 } else if constexpr (detail::serializable_as_optional<T>) {
3588 writer.writeOptional(value);
3589 } else if constexpr (std::is_aggregate_v<T>) {
3590 writer.writeAggregate(value);
3591 } else {
3592 static_assert(detail::always_false_v<T>, "JSON serialization is not implemented for the given type.");
3593 }
3594 }
3595};
3596
3597template <typename T>
3599 void deserialize(Reader& reader, T& value) {
3600 if constexpr (detail::serializable_as_string<T>) {
3601 reader.readString(value);
3602 } else if constexpr (detail::serializable_as_object<T>) {
3603 reader.readObject(value);
3604 } else if constexpr (detail::serializable_as_array<T>) {
3605 reader.readArray(value);
3606 } else if constexpr (detail::serializable_as_optional<T>) {
3607 reader.readOptional(value);
3608 } else if constexpr (std::is_aggregate_v<T>) {
3609 reader.readAggregate(value);
3610 } else {
3611 static_assert(detail::always_false_v<T>, "JSON deserialization is not implemented for the given type.");
3612 }
3613 }
3614};
3615
3617template <>
3618struct Serializer<Null> {
3619 void serialize(Writer& writer, Null) {
3620 writer.writeNull();
3621 }
3622};
3623
3624template <>
3625struct Serializer<std::nullptr_t> {
3626 void serialize(Writer& writer, std::nullptr_t) {
3627 writer.writeNull();
3628 }
3629};
3630
3631template <>
3632struct Serializer<Boolean> {
3633 void serialize(Writer& writer, Boolean value) {
3634 writer.writeBoolean(value);
3635 }
3636};
3637
3638template <detail::number Num>
3639struct Serializer<Num> {
3640 void serialize(Writer& writer, Num value) {
3641 writer.writeNumber(static_cast<Number>(value));
3642 }
3643};
3644
3645template <>
3646struct Serializer<char> {
3647 void serialize(Writer& writer, char value) {
3648 writer.writeString(std::string_view{&value, 1});
3649 }
3650};
3651
3652template <>
3653struct Serializer<char8_t> {
3654 void serialize(Writer& writer, char8_t value) {
3655 writer.writeString(std::u8string_view{&value, 1});
3656 }
3657};
3658
3659template <>
3660struct Serializer<char16_t> {
3661 void serialize(Writer& writer, char16_t value) {
3662 writer.writeString(std::u16string_view{&value, 1});
3663 }
3664};
3665
3666template <>
3667struct Serializer<char32_t> {
3668 void serialize(Writer& writer, char32_t value) {
3669 writer.writeString(std::u32string_view{&value, 1});
3670 }
3671};
3672
3673template <>
3674struct Serializer<wchar_t> {
3675 void serialize(Writer& writer, wchar_t value) {
3676 writer.writeString(std::wstring_view{&value, 1});
3677 }
3678};
3679
3680template <>
3681struct Serializer<Value> {
3682 void serialize(Writer& writer, const Value& value) {
3683 match(value)([&](const auto& v) -> void { writer.serialize(v); });
3684 }
3685};
3687
3689template <>
3690struct Deserializer<Null> {
3691 void deserialize(Reader& reader, Null&) {
3692 reader.readNull();
3693 }
3694};
3695
3696template <>
3697struct Deserializer<std::nullptr_t> {
3698 void deserialize(Reader& reader, std::nullptr_t&) {
3699 reader.readNull();
3700 }
3701};
3702
3703template <>
3704struct Deserializer<Boolean> {
3705 void deserialize(Reader& reader, Boolean& value) {
3706 reader.readBoolean(value);
3707 }
3708};
3709
3710template <detail::number Num>
3711struct Deserializer<Num> {
3712 void deserialize(Reader& reader, Num& value) {
3713 reader.readNumber(value);
3714 }
3715};
3716
3717template <>
3718struct Deserializer<char> {
3719 void deserialize(Reader& reader, char& value) {
3720 String string{};
3721 const SourceLocation source = reader.readString(string);
3722 if (string.size() != 1) {
3723 throw Error{"Expected only a single character.", source};
3724 }
3725 value = string.front();
3726 }
3727};
3728
3729template <>
3730struct Deserializer<char8_t> {
3731 void deserialize(Reader& reader, char8_t& value) {
3732 String string{};
3733 const SourceLocation source = reader.readString(string);
3734 if (string.size() != sizeof(char8_t)) {
3735 throw Error{"Expected only a single UTF-8 code unit.", source};
3736 }
3737 std::memcpy(&value, string.data(), sizeof(char8_t));
3738 }
3739};
3740
3741template <>
3742struct Deserializer<char16_t> {
3743 void deserialize(Reader& reader, char16_t& value) {
3744 String string{};
3745 const SourceLocation source = reader.readString(string);
3746 if (string.size() != sizeof(char16_t)) {
3747 throw Error{"Expected only a single UTF-16 code unit.", source};
3748 }
3749 std::memcpy(&value, string.data(), sizeof(char16_t));
3750 }
3751};
3752
3753template <>
3754struct Deserializer<char32_t> {
3755 void deserialize(Reader& reader, char32_t& value) {
3756 String string{};
3757 const SourceLocation source = reader.readString(string);
3758 if (string.size() != sizeof(char32_t)) {
3759 throw Error{"Expected only a single UTF-32 code unit.", source};
3760 }
3761 std::memcpy(&value, string.data(), sizeof(char32_t));
3762 }
3763};
3764
3765template <>
3766struct Deserializer<wchar_t> {
3767 void deserialize(Reader& reader, wchar_t& value) {
3768 String string{};
3769 const SourceLocation source = reader.readString(string);
3770 if (string.size() != sizeof(wchar_t)) {
3771 throw Error{"Expected only a single wide character.", source};
3772 }
3773 std::memcpy(&value, string.data(), sizeof(wchar_t));
3774 }
3775};
3776
3777template <>
3778struct Deserializer<Value> {
3779 void deserialize(Reader& reader, Value& value) {
3780 reader.readValue(value);
3781 }
3782};
3784
3785inline Object::Object() noexcept = default;
3786
3787inline Object::~Object() = default;
3788
3789inline Object::Object(const Object& other) = default;
3790
3791inline Object::Object(Object&& other) noexcept = default;
3792
3793inline Object& Object::operator=(const Object& other) = default;
3794
3795inline Object& Object::operator=(Object&& other) noexcept = default;
3796
3797template <typename InputIt>
3798inline Object::Object(InputIt first, InputIt last)
3799 : membersSortedByName(first, last) {
3800 std::sort(membersSortedByName.begin(), membersSortedByName.end(), Compare{});
3801}
3802
3803inline Object::Object(std::initializer_list<value_type> ilist)
3804 : Object(ilist.begin(), ilist.end()) {}
3805
3806inline Object& Object::operator=(std::initializer_list<value_type> ilist) {
3807 membersSortedByName = ilist;
3808 std::sort(membersSortedByName.begin(), membersSortedByName.end(), Compare{});
3809 return *this;
3810}
3811
3812inline Value& Object::at(std::string_view name) {
3813 if (const auto it = find(name); it != end()) {
3814 return it->second;
3815 }
3816 throw std::out_of_range{"JSON object does not contain a member with the given name."};
3817}
3818
3819inline const Value& Object::at(std::string_view name) const {
3820 if (const auto it = find(name); it != end()) {
3821 return it->second;
3822 }
3823 throw std::out_of_range{"JSON object does not contain a member with the given name."};
3824}
3825
3827 return try_emplace(k).first->second;
3828}
3829
3831 return try_emplace(std::move(k)).first->second;
3832}
3833
3835 return membersSortedByName.begin();
3836}
3837
3838inline Object::const_iterator Object::begin() const noexcept {
3839 return membersSortedByName.begin();
3840}
3841
3843 return membersSortedByName.cbegin();
3844}
3845
3847 return membersSortedByName.end();
3848}
3849
3850inline Object::const_iterator Object::end() const noexcept {
3851 return membersSortedByName.end();
3852}
3853
3854inline Object::const_iterator Object::cend() const noexcept {
3855 return membersSortedByName.cend();
3856}
3857
3859 return membersSortedByName.rbegin();
3860}
3861
3863 return membersSortedByName.rbegin();
3864}
3865
3867 return membersSortedByName.crbegin();
3868}
3869
3871 return membersSortedByName.rend();
3872}
3873
3875 return membersSortedByName.rend();
3876}
3877
3879 return membersSortedByName.crend();
3880}
3881
3882inline bool Object::empty() const noexcept {
3883 return membersSortedByName.empty();
3884}
3885
3886inline Object::size_type Object::size() const noexcept {
3887 return membersSortedByName.size();
3888}
3889
3890inline Object::size_type Object::max_size() const noexcept {
3891 return membersSortedByName.max_size();
3892}
3893
3894inline void Object::clear() noexcept {
3895 membersSortedByName.clear();
3896}
3897
3898template <typename P>
3899inline std::pair<Object::iterator, bool> Object::insert(P&& value) {
3900 return emplace(std::forward<P>(value));
3901}
3902
3903template <typename P>
3905 return emplace_hint(pos, std::forward<P>(value));
3906}
3907
3908template <typename InputIt>
3909inline void Object::insert(InputIt first, InputIt last) {
3910 while (first != last) {
3911 insert(*first++);
3912 }
3913}
3914
3915inline void Object::insert(std::initializer_list<Object::value_type> ilist) {
3916 insert(ilist.begin(), ilist.end());
3917}
3918
3919template <typename... Args>
3920inline std::pair<Object::iterator, bool> Object::emplace(Args&&... args) {
3921 value_type value{std::forward<Args>(args)...};
3922 const auto [first, last] = equal_range(value.first);
3923 if (first != last) {
3924 return {first, false};
3925 }
3926 const auto it = membersSortedByName.insert(last, std::move(value));
3927 return {it, true};
3928}
3929
3930template <typename... Args>
3932 return emplace(std::forward<Args>(args)...);
3933}
3934
3935template <typename... Args>
3936inline std::pair<Object::iterator, bool> Object::try_emplace(const String& k, Args&&... args) {
3937 const auto [first, last] = equal_range(k);
3938 if (first != last) {
3939 return {first, false};
3940 }
3941 const auto it = membersSortedByName.emplace(last, std::piecewise_construct, std::forward_as_tuple(k), std::forward_as_tuple(std::forward<Args>(args)...));
3942 return {it, true};
3943}
3944
3945template <typename... Args>
3946inline std::pair<Object::iterator, bool> Object::try_emplace(String&& k, Args&&... args) {
3947 const auto [first, last] = equal_range(k);
3948 if (first != last) {
3949 return {first, false};
3950 }
3951 const auto it = membersSortedByName.emplace(last, std::piecewise_construct, std::forward_as_tuple(std::move(k)), std::forward_as_tuple(std::forward<Args>(args)...));
3952 return {it, true};
3953}
3954
3955template <typename... Args>
3957 return try_emplace(k, std::forward<Args>(args)...);
3958}
3959
3960template <typename... Args>
3962 return try_emplace(std::move(k), std::forward<Args>(args)...);
3963}
3964
3966 return membersSortedByName.erase(pos);
3967}
3968
3969inline Object::size_type Object::erase(std::string_view name) {
3970 const auto [first, last] = equal_range(name);
3971 const size_type count = static_cast<size_type>(last - first);
3972 membersSortedByName.erase(first, last);
3973 return count;
3974}
3975
3976inline void Object::swap(Object& other) noexcept {
3977 membersSortedByName.swap(other.membersSortedByName);
3978}
3979
3980inline void swap(Object& a, Object& b) noexcept {
3981 a.swap(b);
3982}
3983
3984inline Object::size_type Object::count(std::string_view name) const noexcept {
3985 const auto [first, last] = equal_range(name);
3986 return static_cast<size_type>(last - first);
3987}
3988
3989inline bool Object::contains(std::string_view name) const noexcept {
3990 return count(name) > 0;
3991}
3992
3993inline Object::iterator Object::find(std::string_view name) noexcept {
3994 if (const auto [first, last] = equal_range(name); first != last) {
3995 return first;
3996 }
3997 return end();
3998}
3999
4000inline Object::const_iterator Object::find(std::string_view name) const noexcept {
4001 if (const auto [first, last] = equal_range(name); first != last) {
4002 return first;
4003 }
4004 return end();
4005}
4006
4007inline std::pair<Object::iterator, Object::iterator> Object::equal_range(std::string_view name) noexcept {
4008 return std::equal_range(membersSortedByName.begin(), membersSortedByName.end(), name, Compare{});
4009}
4010
4011inline std::pair<Object::const_iterator, Object::const_iterator> Object::equal_range(std::string_view name) const noexcept {
4012 return std::equal_range(membersSortedByName.begin(), membersSortedByName.end(), name, Compare{});
4013}
4014
4015inline Object::iterator Object::lower_bound(std::string_view name) noexcept {
4016 return std::lower_bound(membersSortedByName.begin(), membersSortedByName.end(), name, Compare{});
4017}
4018
4019inline Object::const_iterator Object::lower_bound(std::string_view name) const noexcept {
4020 return std::lower_bound(membersSortedByName.begin(), membersSortedByName.end(), name, Compare{});
4021}
4022
4023inline Object::iterator Object::upper_bound(std::string_view name) noexcept {
4024 return std::upper_bound(membersSortedByName.begin(), membersSortedByName.end(), name, Compare{});
4025}
4026
4027inline Object::const_iterator Object::upper_bound(std::string_view name) const noexcept {
4028 return std::upper_bound(membersSortedByName.begin(), membersSortedByName.end(), name, Compare{});
4029}
4030
4031inline bool Object::operator==(const Object& other) const noexcept {
4032 return membersSortedByName == other.membersSortedByName;
4033}
4034
4035inline std::partial_ordering Object::operator<=>(const Object& other) const noexcept {
4036 return std::compare_partial_order_fallback(membersSortedByName, other.membersSortedByName);
4037}
4038
4039template <typename Predicate>
4040inline Object::size_type erase_if(Object& container, Predicate predicate) {
4041 return std::erase_if(container.membersSortedByName, predicate);
4042}
4043
4044inline bool Object::Compare::operator()(const value_type& a, const value_type& b) const noexcept {
4045 return a.first < b.first;
4046}
4047
4048inline bool Object::Compare::operator()(const value_type& a, std::string_view b) const noexcept {
4049 return a.first < b;
4050}
4051
4052inline bool Object::Compare::operator()(std::string_view a, const value_type& b) const noexcept {
4053 return a < b.first;
4054}
4055
4056inline bool Object::Compare::operator()(std::string_view a, std::string_view b) const noexcept {
4057 return a < b;
4058}
4059
4060inline Array::Array() noexcept = default;
4061
4062inline Array::~Array() = default;
4063
4064inline Array::Array(const Array& other) = default;
4065
4066inline Array::Array(Array&& other) noexcept = default;
4067
4068inline Array& Array::operator=(const Array& other) = default;
4069
4070inline Array& Array::operator=(Array&& other) noexcept = default;
4071
4072template <typename InputIt>
4073inline Array::Array(InputIt first, InputIt last)
4074 : values(first, last) {}
4075
4076inline Array::Array(size_type count, const Value& value)
4077 : values(count, value) {}
4078
4079inline Array::Array(std::initializer_list<value_type> ilist)
4080 : values(ilist) {}
4081
4082inline Array& Array::operator=(std::initializer_list<value_type> ilist) {
4083 values = ilist;
4084 return *this;
4085}
4086
4087inline void Array::swap(Array& other) noexcept {
4088 values.swap(other.values);
4089}
4090
4091inline void swap(Array& a, Array& b) noexcept {
4092 a.swap(b);
4093}
4094
4095inline Array::pointer Array::data() noexcept {
4096 return values.data();
4097}
4098
4099inline Array::const_pointer Array::data() const noexcept {
4100 return values.data();
4101}
4102
4103inline Array::size_type Array::size() const noexcept {
4104 return values.size();
4105}
4106
4107inline Array::size_type Array::max_size() const noexcept {
4108 return values.max_size();
4109}
4110
4111inline Array::size_type Array::capacity() const noexcept {
4112 return values.capacity();
4113}
4114
4115inline bool Array::empty() const noexcept {
4116 return values.empty();
4117}
4118
4120 return values.begin();
4121}
4122
4123inline Array::const_iterator Array::begin() const noexcept {
4124 return values.begin();
4125}
4126
4127inline Array::const_iterator Array::cbegin() const noexcept {
4128 return values.cbegin();
4129}
4130
4131inline Array::iterator Array::end() noexcept {
4132 return values.end();
4133}
4134
4135inline Array::const_iterator Array::end() const noexcept {
4136 return values.end();
4137}
4138
4139inline Array::const_iterator Array::cend() const noexcept {
4140 return values.cend();
4141}
4142
4144 return values.rbegin();
4145}
4146
4148 return values.rbegin();
4149}
4150
4152 return values.crbegin();
4153}
4154
4156 return values.rend();
4157}
4158
4160 return values.rend();
4161}
4162
4164 return values.crend();
4165}
4166
4168 return values.front();
4169}
4170
4172 return values.front();
4173}
4174
4176 return values.back();
4177}
4178
4180 return values.back();
4181}
4182
4184 return values.at(pos);
4185}
4186
4188 return values.at(pos);
4189}
4190
4192 return values[pos];
4193}
4194
4196 return values[pos];
4197}
4198
4199inline bool Array::operator==(const Array& other) const {
4200 return values == other.values;
4201}
4202
4203inline std::partial_ordering Array::operator<=>(const Array& other) const noexcept {
4204 return std::compare_partial_order_fallback(values, other.values);
4205}
4206
4207template <typename U>
4208inline Array::size_type erase(Array& container, const U& value) {
4209 return std::erase(container.values, value);
4210}
4211
4212template <typename Predicate>
4213inline Array::size_type erase_if(Array& container, Predicate predicate) {
4214 return std::erase_if(container.values, predicate);
4215}
4216
4217inline void Array::clear() noexcept {
4218 values.clear();
4219}
4220
4221inline void Array::reserve(size_type newCap) {
4222 values.reserve(newCap);
4223}
4224
4226 values.shrink_to_fit();
4227}
4228
4230 return values.insert(pos, value);
4231}
4232
4234 return values.insert(pos, std::move(value));
4235}
4236
4238 return values.insert(pos, count, value);
4239}
4240
4241template <typename InputIt>
4242inline Array::iterator Array::insert(const_iterator pos, InputIt first, InputIt last) {
4243 return values.insert(pos, first, last);
4244}
4245
4246inline Array::iterator Array::insert(const_iterator pos, std::initializer_list<value_type> ilist) {
4247 return values.insert(pos, ilist);
4248}
4249
4250template <typename... Args>
4251inline Array::iterator Array::emplace(const_iterator pos, Args&&... args) {
4252 return values.emplace(pos, std::forward<Args>(args)...);
4253}
4254
4256 return values.erase(pos);
4257}
4258
4260 return values.erase(first, last);
4261}
4262
4263inline void Array::push_back(const Value& value) {
4264 values.push_back(value);
4265}
4266
4267inline void Array::push_back(Value&& value) {
4268 values.push_back(std::move(value));
4269}
4270
4271template <typename... Args>
4273 return values.emplace_back(std::forward<Args>(args)...);
4274}
4275
4276inline void Array::pop_back() {
4277 values.pop_back();
4278}
4279
4280inline void Array::resize(size_type count) {
4281 values.resize(count);
4282}
4283
4284inline void Array::resize(size_type count, const Value& value) {
4285 values.resize(count, value);
4286}
4287
4288inline Value Value::parse(std::u8string_view jsonString) {
4289 unicode::UTF8View codePoints{jsonString};
4290 return Parser<const char8_t*>{{codePoints.begin(), codePoints.end(), {.lineNumber = 1, .columnNumber = 1}}}.parseFile();
4291}
4292
4293inline Value Value::parse(std::string_view jsonString) {
4294 static_assert(sizeof(char) == sizeof(char8_t));
4295 static_assert(alignof(char) == alignof(char8_t));
4296 return parse(std::u8string_view{reinterpret_cast<const char8_t*>(jsonString.data()), jsonString.size()});
4297}
4298
4299inline std::string Value::toString(const SerializationOptions& options) const {
4300 std::ostringstream stream{};
4301 json::serialize(stream, *this, options);
4302 return std::move(stream).str();
4303}
4304
4305} // namespace donut::json
4306
4307#endif
Tagged union value type that holds a value of one of the given types.
Definition Variant.hpp:290
JSON array type whose API mimics that of std::vector<Value>.
Definition json.hpp:318
void push_back(const Value &value)
Definition json.hpp:4263
void resize(size_type count)
Definition json.hpp:4280
void pop_back()
Definition json.hpp:4276
const_reverse_iterator crend() const noexcept
Definition json.hpp:4163
reverse_iterator rend() noexcept
Definition json.hpp:4155
size_type capacity() const noexcept
Definition json.hpp:4111
reference back()
Definition json.hpp:4175
iterator begin() noexcept
Definition json.hpp:4119
reference at(size_type pos)
Definition json.hpp:4183
void reserve(size_type newCap)
Definition json.hpp:4221
size_type size() const noexcept
Definition json.hpp:4103
typename std::vector< value_type >::size_type size_type
Definition json.hpp:321
size_type max_size() const noexcept
Definition json.hpp:4107
void swap(Array &other) noexcept
Definition json.hpp:4087
iterator insert(const_iterator pos, const Value &value)
Definition json.hpp:4229
void shrink_to_fit()
Definition json.hpp:4225
typename std::vector< value_type >::const_reference const_reference
Definition json.hpp:324
typename std::vector< value_type >::reverse_iterator reverse_iterator
Definition json.hpp:329
reference operator[](size_type pos)
Definition json.hpp:4191
typename std::vector< value_type >::const_pointer const_pointer
Definition json.hpp:326
reference front()
Definition json.hpp:4167
typename std::vector< value_type >::difference_type difference_type
Definition json.hpp:322
const_iterator cbegin() const noexcept
Definition json.hpp:4127
const_reverse_iterator crbegin() const noexcept
Definition json.hpp:4151
pointer data() noexcept
Definition json.hpp:4095
Array & operator=(const Array &other)
void clear() noexcept
Definition json.hpp:4217
typename std::vector< value_type >::const_iterator const_iterator
Definition json.hpp:328
std::partial_ordering operator<=>(const Array &other) const noexcept
Definition json.hpp:4203
iterator end() noexcept
Definition json.hpp:4131
typename std::vector< value_type >::reference reference
Definition json.hpp:323
bool empty() const noexcept
Definition json.hpp:4115
iterator emplace(const_iterator pos, Args &&... args)
Definition json.hpp:4251
bool operator==(const Array &other) const
Definition json.hpp:4199
typename std::vector< value_type >::iterator iterator
Definition json.hpp:327
reverse_iterator rbegin() noexcept
Definition json.hpp:4143
friend size_type erase_if(Array &container, Predicate predicate)
Definition json.hpp:4213
typename std::vector< value_type >::pointer pointer
Definition json.hpp:325
reference emplace_back(Args &&... args)
Definition json.hpp:4272
friend size_type erase(Array &container, const U &value)
Definition json.hpp:4208
typename std::vector< value_type >::const_reverse_iterator const_reverse_iterator
Definition json.hpp:330
friend void swap(Array &a, Array &b) noexcept
Definition json.hpp:4091
const_iterator cend() const noexcept
Definition json.hpp:4139
Lexical analyzer for scanning and tokenizing input in the JSON5 format.
Definition json.hpp:715
Token scan()
Scan and consume the next token from the input.
Definition json.hpp:743
Lexer(unicode::UTF8Iterator< It > it, unicode::UTF8Sentinel end, const SourceLocation &source)
Construct a lexer with a Unicode iterator pair as input.
Definition json.hpp:727
JSON object type whose API mimics that of std::multimap<String, Value>.
Definition json.hpp:199
std::pair< iterator, iterator > equal_range(std::string_view name) noexcept
Definition json.hpp:4007
iterator erase(const_iterator pos)
Definition json.hpp:3965
const_iterator cbegin() const noexcept
Definition json.hpp:3842
std::pair< iterator, bool > insert(P &&value)
Definition json.hpp:3899
std::pair< iterator, bool > emplace(Args &&... args)
Definition json.hpp:3920
typename std::vector< value_type >::pointer pointer
Definition json.hpp:208
reverse_iterator rbegin() noexcept
Definition json.hpp:3858
iterator upper_bound(std::string_view name) noexcept
Definition json.hpp:4023
typename std::vector< value_type >::const_reference const_reference
Definition json.hpp:207
std::pair< String, Value > value_type
Definition json.hpp:203
typename std::vector< value_type >::iterator iterator
Definition json.hpp:210
size_type size() const noexcept
Definition json.hpp:3886
typename std::vector< value_type >::const_iterator const_iterator
Definition json.hpp:211
const_reverse_iterator crend() const noexcept
Definition json.hpp:3878
std::pair< iterator, bool > try_emplace(const String &k, Args &&... args)
Definition json.hpp:3936
typename std::vector< value_type >::difference_type difference_type
Definition json.hpp:205
const_reverse_iterator crbegin() const noexcept
Definition json.hpp:3866
iterator emplace_hint(const_iterator hint, Args &&... args)
Definition json.hpp:3931
void clear() noexcept
Definition json.hpp:3894
Object & operator=(const Object &other)
iterator lower_bound(std::string_view name) noexcept
Definition json.hpp:4015
iterator begin() noexcept
Definition json.hpp:3834
iterator find(std::string_view name) noexcept
Definition json.hpp:3993
Value & at(std::string_view name)
Definition json.hpp:3812
String key_type
Definition json.hpp:201
typename std::vector< value_type >::const_reverse_iterator const_reverse_iterator
Definition json.hpp:213
Value & operator[](const String &k)
Definition json.hpp:3826
typename std::vector< value_type >::reverse_iterator reverse_iterator
Definition json.hpp:212
size_type max_size() const noexcept
Definition json.hpp:3890
const_iterator cend() const noexcept
Definition json.hpp:3854
bool contains(std::string_view name) const noexcept
Definition json.hpp:3989
friend void swap(Object &a, Object &b) noexcept
Definition json.hpp:3980
typename std::vector< value_type >::reference reference
Definition json.hpp:206
bool operator==(const Object &other) const noexcept
Definition json.hpp:4031
friend size_type erase_if(Object &container, Predicate predicate)
Definition json.hpp:4040
std::partial_ordering operator<=>(const Object &other) const noexcept
Definition json.hpp:4035
size_type count(std::string_view name) const noexcept
Definition json.hpp:3984
reverse_iterator rend() noexcept
Definition json.hpp:3870
iterator end() noexcept
Definition json.hpp:3846
typename std::vector< value_type >::size_type size_type
Definition json.hpp:204
typename std::vector< value_type >::const_pointer const_pointer
Definition json.hpp:209
bool empty() const noexcept
Definition json.hpp:3882
Polymorphic interface for visitation-based parsing of JSON object properties.
Definition json.hpp:1303
virtual void visitProperty(const SourceLocation &source, String &&key, Parser &parser)=0
Callback for each object property.
Polymorphic interface for visitation-based parsing of JSON values.
Definition json.hpp:1137
virtual void visitString(const SourceLocation &source, String &&value)
Callback for values of type String.
Definition json.hpp:1176
virtual void visitObject(const SourceLocation &source, Parser &parser)
Callback for objects.
Definition json.hpp:1209
virtual void visitBoolean(const SourceLocation &source, Boolean value)
Callback for values of type Boolean.
Definition json.hpp:1162
virtual void visitNumber(const SourceLocation &source, Number value)
Callback for values of type Number.
Definition json.hpp:1190
virtual void visitArray(const SourceLocation &source, Parser &parser)
Callback for arrays.
Definition json.hpp:1228
virtual void visitNull(const SourceLocation &source, Null value)
Callback for values of type Null.
Definition json.hpp:1148
Syntactic analyzer for parsing input in the JSON5 format obtained from a json::Lexer.
Definition json.hpp:1132
void skipFile()
Parse a single JSON value from the input and discard the result, then make sure the rest of the input...
Definition json.hpp:1707
Parser(unicode::UTF8View codePoints)
Construct a parser with a contiguous UTF-8 view as input.
Definition json.hpp:1386
Value parseValue()
Read a single JSON value from the input.
Definition json.hpp:1766
void parseObject(PropertyVisitor &visitor)
Read a single JSON object from the input and visit each of its properties.
Definition json.hpp:1538
void parseFile(ValueVisitor &visitor)
Read a single JSON value from the input and visit it, then make sure the rest of the input only consi...
Definition json.hpp:1444
void parseObject(Visitor visitor)
Definition json.hpp:1684
void parseFile(Visitor visitor)
Definition json.hpp:1668
Object parseObject()
Read a single JSON value of type Object from the input.
Definition json.hpp:1887
const Token & peek() const
Peek the next token without advancing the internal state of the underlying lexer.
Definition json.hpp:1980
Parser(std::u8string_view jsonString)
Construct a parser with a contiguous UTF-8 string as input.
Definition json.hpp:1395
Value parseFile()
Read a single JSON value from the input and make sure the rest of the input only consists of whitespa...
Definition json.hpp:1739
void parseValue(ValueVisitor &visitor)
Read a single JSON value from the input and visit it.
Definition json.hpp:1470
Parser(std::streambuf *streambuf)
Construct a parser with an input stream buffer as input.
Definition json.hpp:1421
void skipValue()
Parse a single JSON value from the input and discard the result.
Definition json.hpp:1721
Null parseNull()
Read a single JSON value of type Null from the input.
Definition json.hpp:1798
void parseFile(ValueVisitor &&visitor)
Definition json.hpp:1639
void parseArray(ValueVisitor &&visitor)
Definition json.hpp:1660
Token eat()
Scan and consume the next token from the input.
Definition json.hpp:1998
void parseArray(ValueVisitor &visitor)
Read a single JSON array from the input and visit each of its values.
Definition json.hpp:1614
Array parseArray()
Read a single JSON value of type Array from the input.
Definition json.hpp:1922
String parseString()
Read a single JSON value of type String from the input.
Definition json.hpp:1839
Boolean parseBoolean()
Read a single JSON value of type Boolean from the input.
Definition json.hpp:1818
void parseValue(ValueVisitor &&visitor)
Definition json.hpp:1646
Parser(std::istream &stream)
Construct a parser with an input stream as input.
Definition json.hpp:1413
Parser(Lexer< It > lexer)
Construct a parser with an existing lexer as input.
Definition json.hpp:1377
void parseArray(Visitor visitor)
Definition json.hpp:1692
void parseObject(PropertyVisitor &&visitor)
Definition json.hpp:1653
void parseValue(Visitor visitor)
Definition json.hpp:1676
Number parseNumber()
Read a single JSON value of type Number from the input.
Definition json.hpp:1859
void advance()
Advance the internal state of the underlying lexer by one token.
Definition json.hpp:1957
Parser(std::string_view jsonString)
Construct a parser with a contiguous string of bytes, interpreted as UTF-8, as input.
Definition json.hpp:1405
JSON value type.
Definition json.hpp:432
Value(detail::number auto value) noexcept
Construct a Number value with the given underlying value.
Definition json.hpp:560
std::string toString(const SerializationOptions &options={}) const
Get a JSON string representation of the value.
Definition json.hpp:4299
Value(std::string_view value)
Construct a String value with the given underlying value.
Definition json.hpp:526
Value(const Array &value)
Construct an Array value with the given underlying value.
Definition json.hpp:588
Value() noexcept=default
Construct a Null value.
Value(String &&value) noexcept
Construct a String value from the given underlying value.
Definition json.hpp:505
Value(const Object &value)
Construct an Object value with the given underlying value.
Definition json.hpp:570
Value(Object &&value) noexcept
Construct an Object value from the given underlying value.
Definition json.hpp:578
Value(Boolean value) noexcept
Construct a Boolean value with the given underlying value.
Definition json.hpp:487
static Value parse(std::u8string_view jsonString)
Parse a value of any JSON type from a UTF-8 JSON string.
Definition json.hpp:4288
bool operator==(const Value &other) const
Compare this value to another for equality.
Definition json.hpp:620
Value(Array &&value) noexcept
Construct an Array value from the given underlying value.
Definition json.hpp:596
Value(const char *value)
Construct a String value with the given underlying value.
Definition json.hpp:516
std::partial_ordering operator<=>(const Value &other) const
Compare this value to another.
Definition json.hpp:631
Value(const char8_t *value)
Construct a String value with the given underlying value.
Definition json.hpp:537
Value(const String &value)
Construct a String value with the given underlying value.
Definition json.hpp:497
Value(std::u8string_view value)
Construct a String value with the given underlying value.
Definition json.hpp:551
Value(std::nullptr_t) noexcept
Construct a Null value.
Definition json.hpp:480
Iterator type for decoding Unicode code points from a UTF-8 string, wrapping an existing iterator for...
Definition unicode.hpp:193
Non-owning view type for decoding Unicode code points from a contiguous UTF-8 string.
Definition unicode.hpp:331
Definition json.hpp:36
std::string String
JSON string type.
Definition json.hpp:189
Array::size_type erase(Array &container, const U &value)
Definition json.hpp:4208
std::istream & operator>>(std::istream &stream, Value &value)
Read a JSON value from an input stream using the default deserialization options.
Definition json.hpp:2163
bool Boolean
JSON boolean type.
Definition json.hpp:184
auto onNull(Callback callback)
Build a Parser::ValueVisitor that handles Null values with a given callback function.
Definition json.hpp:3280
TokenType
Type of a scanned JSON5 token.
Definition json.hpp:676
@ PUNCTUATOR_OPEN_CURLY_BRACE
Open curly brace '{' symbol.
@ NUMBER_OCTAL
Octal number literal, e.g. 0777.
@ IDENTIFIER_FALSE
Keyword false.
@ PUNCTUATOR_CLOSE_CURLY_BRACE
Closing curly brace '}' symbol.
@ NUMBER_BINARY
Binary number literal, e.g. 0b0000000111111111.
@ PUNCTUATOR_COLON
Colon ':' symbol.
@ NUMBER_NEGATIVE_INFINITY
Keyword -Infinity.
@ END_OF_FILE
End-of-file marker.
@ PUNCTUATOR_CLOSE_SQUARE_BRACKET
Closing square bracket ']' symbol.
@ STRING
Quoted string literal, e.g. "abc".
@ NUMBER_POSITIVE_NAN
Keyword NaN.
@ IDENTIFIER_NAME
Unquoted identifier, e.g. abc.
@ NUMBER_DECIMAL
Decimal number literal, e.g. 511.
@ IDENTIFIER_NULL
Keyword null.
@ NUMBER_POSITIVE_INFINITY
Keyword Infinity.
@ IDENTIFIER_TRUE
Keyword true.
@ NUMBER_NEGATIVE_NAN
Keyword -NaN.
@ NUMBER_HEXADECIMAL
Hexadecimal number literal, e.g. 0x01FF.
@ PUNCTUATOR_OPEN_SQUARE_BRACKET
Open square bracket '[' symbol.
@ PUNCTUATOR_COMMA
Comma ',' symbol.
Monostate Null
JSON null type.
Definition json.hpp:179
std::ostream & operator<<(std::ostream &stream, const Value &value)
Write a JSON value to an output stream using the default serialization options.
Definition json.hpp:2142
void serialize(std::ostream &stream, const T &value, const SerializationOptions &options={})
Serialize a value of any JSON-serializable type to an output stream.
Definition json.hpp:3082
Object::size_type erase_if(Object &container, Predicate predicate)
Definition json.hpp:4040
constexpr bool isPunctuationCharacter(char32_t codePoint) noexcept
Check if a Unicode code point is considered to be punctuation in JSON5.
Definition json.hpp:656
void deserialize(std::istream &stream, T &value, const DeserializationOptions &options={})
Deserialize a value of any JSON-serializable type from an input stream.
Definition json.hpp:3100
constexpr bool isWhitespaceCharacter(char32_t codePoint) noexcept
Check if a Unicode code point is considered to be whitespace in JSON5.
Definition json.hpp:643
auto onArray(Callback callback)
Build a Parser::ValueVisitor that handles arrays with a given callback function.
Definition json.hpp:3415
void swap(Object &a, Object &b) noexcept
Definition json.hpp:3980
auto onString(Callback callback)
Build a Parser::ValueVisitor that handles String values with a given callback function.
Definition json.hpp:3334
constexpr bool isLineTerminatorCharacter(char32_t codePoint) noexcept
Check if a Unicode code point marks the beginning of a line terminator sequence in JSON5.
Definition json.hpp:669
double Number
JSON number type.
Definition json.hpp:194
auto onProperty(Callback callback)
Build a Parser::PropertyVisitor that handles object properties with a given callback function.
Definition json.hpp:3435
auto onObject(Callback callback)
Build a Parser::ValueVisitor that handles objects with a given callback function.
Definition json.hpp:3388
auto onNumber(Callback callback)
Build a Parser::ValueVisitor that handles Number values with a given callback function.
Definition json.hpp:3361
auto onBoolean(Callback callback)
Build a Parser::ValueVisitor that handles Boolean values with a given callback function.
Definition json.hpp:3307
constexpr auto fields(auto &&aggregate) noexcept
Get a tuple of references to each of the fields of an aggregate.
Definition reflection.hpp:86
constexpr void forEach(auto &&tuple, auto fn)
Execute a function once for each element in a given tuple, sequentially.
Definition reflection.hpp:207
Definition utilities.hpp:165
constexpr bool isValidCodePoint(char32_t codePoint) noexcept
Check if a 32-bit unsigned integer value falls within the valid ranges for a Unicode code point.
Definition unicode.hpp:22
constexpr EncodeUTF8FromCodePointResult encodeUTF8FromCodePoint(char32_t codePoint) noexcept
Encode a Unicode code point into a sequence of UTF-8 code units.
Definition unicode.hpp:141
constexpr detail::Matcher< V > match(V &&variant)
Choose a function overload to execute based on the active alternative of a variant.
Definition Variant.hpp:1736
Unit type for representing an empty alternative in Variant.
Definition Variant.hpp:235
Options for JSON deserialization.
Definition json.hpp:171
Base template to specialize in order to implement JSON deserialization for a specific type.
Definition json.hpp:3598
void deserialize(Reader &reader, T &value)
Definition json.hpp:3599
Exception type for errors originating from the JSON API.
Definition json.hpp:82
Error(const char *message, const SourceLocation &source)
Definition json.hpp:93
SourceLocation source
Location in the JSON source string that the error originated from, or (0, 0) if the error did not ori...
Definition json.hpp:87
Error(const std::string &message, const SourceLocation &source)
Definition json.hpp:89
Implementation of PropertyVisitor for freestanding classes that implement all or parts of its interfa...
Definition json.hpp:1334
ConcretePropertyVisitor(Visitor visitor)
Definition json.hpp:1337
Visitor visitor
Definition json.hpp:1335
void visitProperty(const SourceLocation &source, String &&key, Parser &parser) override
Callback for each object property.
Definition json.hpp:1340
Implementation of ValueVisitor for freestanding classes that implement all or parts of its interface ...
Definition json.hpp:1244
void visitNull(const SourceLocation &source, Null value) override
Callback for values of type Null.
Definition json.hpp:1250
void visitBoolean(const SourceLocation &source, Boolean value) override
Callback for values of type Boolean.
Definition json.hpp:1258
ConcreteValueVisitor(Visitor visitor)
Definition json.hpp:1247
Visitor visitor
Definition json.hpp:1245
void visitObject(const SourceLocation &source, Parser &parser) override
Callback for objects.
Definition json.hpp:1282
void visitNumber(const SourceLocation &source, Number value) override
Callback for values of type Number.
Definition json.hpp:1274
void visitString(const SourceLocation &source, String &&value) override
Callback for values of type String.
Definition json.hpp:1266
void visitArray(const SourceLocation &source, Parser &parser) override
Callback for arrays.
Definition json.hpp:1290
Implementation of PropertyVisitor that skips over the parsed property and discards the result.
Definition json.hpp:1366
void visitProperty(const SourceLocation &source, String &&key, Parser &parser) override
Callback for each object property.
Definition json.hpp:1368
Implementation of ValueVisitor that skips over the parsed value and discards the result.
Definition json.hpp:1351
void visitArray(const SourceLocation &source, Parser &parser) override
Callback for arrays.
Definition json.hpp:1358
void visitObject(const SourceLocation &source, Parser &parser) override
Callback for objects.
Definition json.hpp:1357
void visitBoolean(const SourceLocation &source, Boolean value) override
Callback for values of type Boolean.
Definition json.hpp:1354
void visitNull(const SourceLocation &source, Null value) override
Callback for values of type Null.
Definition json.hpp:1353
void visitNumber(const SourceLocation &source, Number value) override
Callback for values of type Number.
Definition json.hpp:1356
void visitString(const SourceLocation &source, String &&value) override
Callback for values of type String.
Definition json.hpp:1355
Stateful wrapper object of an input stream for JSON deserialization.
Definition json.hpp:2618
SourceLocation readBoolean(Boolean &value)
Read a single JSON value of type Boolean from the input.
Definition json.hpp:2673
Reader(std::istream &stream, const DeserializationOptions &options={})
Construct a reader with an input stream as input.
Definition json.hpp:2636
SourceLocation readNull()
Read a single JSON value of type Null from the input.
Definition json.hpp:2652
SourceLocation readString(auto &value)
Read a single JSON value of type String from the input into any value that can be assigned from a sta...
Definition json.hpp:2714
SourceLocation readString(String &value)
Read a single JSON value of type String from the input.
Definition json.hpp:2694
SourceLocation readArray(Array &value)
Read a single JSON value of type Array from the input.
Definition json.hpp:2888
SourceLocation readAggregate(T &value)
Read a single JSON value from the input into any value of aggregate type whose fields are deserializa...
Definition json.hpp:3023
SourceLocation readOptional(T &value)
Read a single nullable JSON value from the input into any value that is default-constructible,...
Definition json.hpp:2990
SourceLocation readObject(auto &value)
Read a single JSON object from the input into any container of key-value pairs where the key and valu...
Definition json.hpp:2840
SourceLocation readArray(auto &value)
Read a single JSON array from the input into any container of elements that are default-constructible...
Definition json.hpp:2917
SourceLocation readObject(Object &value)
Read a single JSON value of type Object from the input.
Definition json.hpp:2809
DeserializationOptions options
The current options of the deserialization process.
Definition json.hpp:2628
SourceLocation readNumber(T &value)
Read a single JSON value of type Number from the input into any value that Number can be explicitly c...
Definition json.hpp:2787
void deserialize(T &value)
Read a JSON value from the input into any value that is deserializable from JSON using its correspond...
Definition json.hpp:3063
SourceLocation readNumber(Number &value)
Read a single JSON value of type Number from the input.
Definition json.hpp:2766
SourceLocation readValue(Value &value)
Read a single JSON value from the input.
Definition json.hpp:2960
Options for JSON serialization.
Definition json.hpp:101
bool prettyPrint
Format the output in a way that is nicely human-readable.
Definition json.hpp:127
std::size_t indentation
The starting indentation level, expressed as the number of indentation characters.
Definition json.hpp:106
std::size_t prettyPrintMaxSingleLineArrayItemCount
Maximum size of an array before it is split into multiple lines when pretty printing.
Definition json.hpp:155
char indentationCharacter
The character to use when performing indentation.
Definition json.hpp:117
const char * newlineString
Non-owning pointer to a null-terminated ASCII string representing the newline sequence to use when pe...
Definition json.hpp:165
std::size_t prettyPrintMaxSingleLineObjectPropertyCount
Maximum size of an object before it is split into multiple lines when pretty printing.
Definition json.hpp:141
std::size_t relativeIndentation
The number of indentation characters that each new level of indentation will add.
Definition json.hpp:112
Base template to specialize in order to implement JSON serialization for a specific type.
Definition json.hpp:3573
void serialize(Writer &writer, const T &value)
Definition json.hpp:3574
Line and column numbers of a location in a JSON source string.
Definition json.hpp:56
std::size_t lineNumber
Line number, starting at 1 for the first line.
Definition json.hpp:61
std::size_t columnNumber
Column number, starting at 1 for the first column.
Definition json.hpp:67
constexpr bool operator==(const SourceLocation &other) const =default
Compare this source location to another for equality.
Token data scanned from JSON.
Definition json.hpp:702
SourceLocation source
Location of the scanned string in the JSON source string.
Definition json.hpp:704
TokenType type
Scanned token type.
Definition json.hpp:705
String string
Scanned string.
Definition json.hpp:703
Stateful wrapper object of an output stream for JSON serialization.
Definition json.hpp:2175
void writeString(const auto &value)
Write a single JSON value of type String to the output from any string-view-like or JSON-serializable...
Definition json.hpp:2324
void write(std::string_view bytes)
Write a raw sequence of bytes to the output without any extra formatting.
Definition json.hpp:2213
SerializationOptions options
The current options of the serialization process.
Definition json.hpp:2183
void writeNewline()
Write a newline sequence to the output.
Definition json.hpp:2239
void writeBoolean(Boolean value)
Write a single JSON value of type Boolean to the output.
Definition json.hpp:2259
void writeIndentation()
Write a sequence of indentation characters to the output.
Definition json.hpp:2228
void writeArray(const auto &value, ItemFilter itemFilter={}, GetValue getValue={})
Write a single JSON array to the output from any range of JSON-serializable values.
Definition json.hpp:2465
void writeOptional(const auto &value)
Write a single JSON value to the output from any value that supports conversion to bool and the deref...
Definition json.hpp:2531
void writeString(std::basic_string_view< CharT, Traits > value)
Write a single JSON value of type String to the output from a raw string, interpreted as raw bytes.
Definition json.hpp:2309
void writeObject(const auto &value, PropertyFilter propertyFilter={}, GetKey getKey={}, GetValue getValue={})
Write a single JSON object to the output from any range of JSON-serializable key-value pairs.
Definition json.hpp:2385
void write(char byte)
Write a single raw byte to the output without any extra formatting.
Definition json.hpp:2202
void writeString(std::string_view bytes)
Write a single JSON value of type String to the output from a raw byte string.
Definition json.hpp:2271
void serialize(const T &value)
Write any JSON-serializable value to the output using its corresponding implementation of Serializer.
Definition json.hpp:2610
void writeAggregate(const T &value)
Write a single JSON value to the output from any value of aggregate type.
Definition json.hpp:2549
void writeNull()
Write a single JSON value of type Null to the output.
Definition json.hpp:2248
Writer(std::ostream &stream, const SerializationOptions &options={})
Construct a writer with an output stream as output.
Definition json.hpp:2191
void writeNumber(Number value)
Write a single JSON value of type Number to the output.
Definition json.hpp:2349
Result of the encodeUTF8FromCodePoint() function.
Definition unicode.hpp:123
std::size_t size
The length of the encoded code unit sequence stored in the codeUnits array.
Definition unicode.hpp:125
std::array< char8_t, 4 > codeUnits
Array of UTF-8 code units that encode the given code point.
Definition unicode.hpp:124
Sentinel type for UTF8Iterator.
Definition unicode.hpp:183