Sourcemeta Core 0.0.0
Loading...
Searching...
No Matches
json_value.h
1#ifndef SOURCEMETA_CORE_JSON_VALUE_H_
2#define SOURCEMETA_CORE_JSON_VALUE_H_
3
4#ifndef SOURCEMETA_CORE_JSON_EXPORT
5#include <sourcemeta/core/json_export.h>
6#endif
7
8#include <sourcemeta/core/json_array.h>
9#include <sourcemeta/core/json_hash.h>
10#include <sourcemeta/core/json_object.h>
11
12#include <sourcemeta/core/numeric.h>
13#include <sourcemeta/core/preprocessor.h>
14
15#include <algorithm> // std::any_of
16#include <bitset> // std::bitset
17#include <cassert> // assert
18#include <cmath> // std::modf, std::trunc, std::isinf, std::isnan
19#include <concepts> // std::same_as
20#include <cstddef> // std::size_t
21#include <cstdint> // std::int64_t, std::uint8_t
22#include <functional> // std::less, std::reference_wrapper, std::function
23#include <initializer_list> // std::initializer_list
24#include <limits> // std::numeric_limits
25#include <memory> // std::allocator
26#include <set> // std::set
27#include <span> // std::span
28#include <sstream> // std::basic_istringstream
29#include <stdexcept> // std::out_of_range
30#include <string> // std::basic_string, std::char_traits
31#include <string_view> // std::basic_string_view
32#include <type_traits> // std::is_same_v, std::remove_cvref_t
33#include <utility> // std::pair
34
35namespace sourcemeta::core {
36
39class SOURCEMETA_CORE_JSON_EXPORT JSON {
40public:
42 using Char = char;
44 using CharTraits = std::char_traits<Char>;
46 using Integer = std::int64_t;
48 using Real = double;
50 template <typename T> using Allocator = std::allocator<T>;
52 using String = std::basic_string<Char, CharTraits, Allocator<Char>>;
54 using StringView = std::basic_string_view<Char, CharTraits>;
60 enum class ParsePhase : std::uint8_t {
62 Pre,
65 };
66
67 // The enumeration indexes must stay in sync with the internal variant
69 enum class Type : std::uint8_t {
71 Null = 0,
73 Boolean = 1,
77 Real = 3,
79 String = 4,
81 Array = 5,
83 Object = 6,
86 };
87
89 using TypeSet = std::bitset<8>;
90
92 enum class ParseContext : std::uint8_t {
94 Root,
96 Property,
99 };
100
103 using ParseCallback = std::function<void(
104 const ParsePhase phase, const Type type, const std::uint64_t line,
105 const std::uint64_t column, const ParseContext context,
106 const std::size_t index, const String &property)>;
107
110 using KeyComparison = std::function<bool(const String &, const String &)>;
111
112 /*
113 Constructors
114 */
115
124 explicit JSON(const std::int64_t value);
125
134 explicit JSON(const std::size_t value);
135
144 explicit JSON(const int value);
145
146 // On some systems, `std::int64_t` might be equal to `long`
148 template <typename T = std::int64_t>
149 explicit JSON(const long value)
150 requires(!std::is_same_v<T, std::int64_t>)
151 : current_type{Type::Integer} {
152 this->data_integer = value;
153 }
154
163 explicit JSON(const double value);
164
173 explicit JSON(const float value);
174
182 explicit JSON(const bool value);
183
191 explicit JSON(const std::nullptr_t);
192
200 explicit JSON(const String &value);
201
210 explicit JSON(String &&value);
211
219 explicit JSON(const std::basic_string_view<Char, CharTraits> &value);
220
228 explicit JSON(const Char *const value);
229
231 explicit JSON(const Array &value);
232
247 explicit JSON(std::initializer_list<typename Object::pair_value_type> values);
248
250 explicit JSON(const Object &value);
251
253 explicit JSON(const Decimal &value);
254
256 explicit JSON(Decimal &&value);
257
259 JSON(const JSON &);
261 JSON(JSON &&) noexcept;
262 auto operator=(const JSON &) -> JSON &;
263 auto operator=(JSON &&) noexcept -> JSON &;
264
267
282 static auto make_array() -> JSON;
283
304 static auto make_array(std::initializer_list<JSON> values) -> JSON;
305
320 static auto make_object() -> JSON;
321
332 static auto size(const String &value) noexcept -> std::size_t;
333
334 /*
335 * Operators
336 */
337
338 auto operator<(const JSON &other) const -> bool;
339 auto operator<=(const JSON &other) const -> bool;
340 auto operator>(const JSON &other) const -> bool;
341 auto operator>=(const JSON &other) const -> bool;
342
355 auto operator==(const JSON &other) const -> bool;
356 auto operator!=(const JSON &) const -> bool = default;
357
371 auto operator+(const JSON &other) const -> JSON;
372
386 auto operator-(const JSON &other) const -> JSON;
387
402 auto operator+=(const JSON &additive) -> JSON &;
403
418 auto operator-=(const JSON &substractive) -> JSON &;
419
420 /*
421 * Type checking
422 */
423
433 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_boolean() const noexcept
434 -> bool {
435 return this->current_type == Type::Boolean;
436 }
437
447 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_null() const noexcept
448 -> bool {
449 return this->current_type == Type::Null;
450 }
451
461 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_integer() const noexcept
462 -> bool {
463 return this->current_type == Type::Integer;
464 }
465
475 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_real() const noexcept
476 -> bool {
477 return this->current_type == Type::Real;
478 }
479
490 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_integral() const noexcept
491 -> bool {
492 switch (this->type()) {
493 case Type::Integer:
494 return true;
495 case Type::Real: {
496 Real integral_part = 0.0;
497 return std::modf(this->to_real(), &integral_part) == 0.0;
498 }
499 case Type::Decimal:
500 return this->to_decimal().is_integral();
501 default:
502 return false;
503 }
504 }
505
518 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_number() const noexcept
519 -> bool {
520 return this->is_integer() || this->is_real() || this->is_decimal();
521 }
522
535 [[nodiscard]] auto is_positive() const noexcept -> bool;
536
546 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_string() const noexcept
547 -> bool {
548 return this->current_type == Type::String;
549 }
550
561 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_array() const noexcept
562 -> bool {
563 return this->current_type == Type::Array;
564 }
565
576 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_object() const noexcept
577 -> bool {
578 return this->current_type == Type::Object;
579 }
580
592 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_decimal() const noexcept
593 -> bool {
594 return this->current_type == Type::Decimal;
595 }
596
606 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto type() const noexcept
607 -> Type {
608 return this->current_type;
609 }
610
611 /*
612 * Type conversion
613 */
614
626 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto to_boolean() const noexcept
627 -> bool {
628 assert(this->is_boolean());
629 return this->data_boolean;
630 }
631
644 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto to_integer() const noexcept
645 -> Integer {
646 assert(this->is_integer());
647 return this->data_integer;
648 }
649
662 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto to_real() const noexcept
663 -> Real {
664 assert(this->is_real());
665 assert(!std::isinf(this->data_real));
666 assert(!std::isnan(this->data_real));
667 return this->data_real;
668 }
669
682 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto to_decimal() const noexcept
683 -> const Decimal & {
684 assert(this->is_decimal());
685 assert(this->data_decimal.is_finite());
686 assert(!this->data_decimal.is_nan());
687 return this->data_decimal;
688 }
689
702 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto to_string() const noexcept
703 -> const String & {
704 assert(this->is_string());
705 return this->data_string;
706 }
707
721 [[nodiscard]] auto to_stringstream() const
722 -> std::basic_istringstream<Char, CharTraits, Allocator<Char>>;
723
742 // TODO: Merge const/non-const overloads of as_array, as_object, at, front,
743 // back using deducing this once Apple Clang supports it
744 // (__cpp_explicit_this_parameter)
745 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_array() const noexcept
746 -> const Array & {
747 assert(this->is_array());
748 return this->data_array;
749 }
750
763 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_array() noexcept
764 -> Array & {
765 assert(this->is_array());
766 return this->data_array;
767 }
768
791 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_object() noexcept
792 -> Object & {
793 assert(this->is_object());
794 return this->data_object;
795 }
796
815 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_object() const noexcept
816 -> const Object & {
817 assert(this->is_object());
818 return this->data_object;
819 }
820
833 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_real() const -> Real {
834 assert(this->is_number());
835 if (this->is_real()) {
836 return this->to_real();
837 } else if (this->is_integer()) {
838 return static_cast<Real>(this->to_integer());
839 } else {
840 return this->to_decimal().to_double();
841 }
842 }
843
856 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto as_integer() const
857 -> Integer {
858 assert(this->is_number());
859 if (this->is_integer()) {
860 return this->to_integer();
861 } else if (this->is_real()) {
862 const auto truncated{std::trunc(this->to_real())};
863 if (truncated < static_cast<Real>(std::numeric_limits<Integer>::min()) ||
864 truncated >= static_cast<Real>(std::numeric_limits<Integer>::max())) {
865 throw std::out_of_range{
866 "The real number does not fit in a 64-bit integer"};
867 }
868
869 return static_cast<Integer>(truncated);
870 } else {
871 const auto integral{this->to_decimal().to_integral()};
872 if (!integral.is_int64()) {
873 throw std::out_of_range{
874 "The decimal number does not fit in a 64-bit integer"};
875 }
876
877 return integral.to_int64();
878 }
879 }
880
881 /*
882 * Getters
883 */
884
903 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
904 at(const typename Array::size_type index) const -> const JSON & {
905 assert(this->is_array());
906 assert(index < this->size());
907 return this->data_array.data.at(index);
908 }
909
928 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
929 at(const typename Array::size_type index) -> JSON & {
930 assert(this->is_array());
931 assert(index < this->size());
932 return this->data_array.data.at(index);
933 }
934
947 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto at(const String &key) const
948 -> const JSON & {
949 assert(this->is_object());
950 assert(this->defines(key));
951 const auto &object{this->data_object};
952 return object.at(key, object.hash(key));
953 }
954
956 template <typename T>
957 requires std::same_as<std::remove_cvref_t<T>, StringView>
958 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto at(T key) const
959 -> const JSON & {
960 assert(this->is_object());
961 assert(this->defines(key));
962 const auto &object{this->data_object};
963 return object.at(key, object.hash(key));
964 }
965
980 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
981 at(const String &key, const typename Object::hash_type hash) const
982 -> const JSON & {
983 assert(this->is_object());
984 assert(this->defines(key));
985 return this->data_object.at(key, hash);
986 }
987
990 template <typename T>
991 requires std::same_as<std::remove_cvref_t<T>, StringView>
992 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
993 at(T key, const typename Object::hash_type hash) const -> const JSON & {
994 assert(this->is_object());
995 assert(this->defines(key));
996 return this->data_object.at(key, hash);
997 }
998
1011 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto at(const String &key)
1012 -> JSON & {
1013 assert(this->is_object());
1014 assert(this->defines(key));
1015 auto &object{this->data_object};
1016 return object.at(key, object.hash(key));
1017 }
1018
1020 template <typename T>
1021 requires std::same_as<std::remove_cvref_t<T>, StringView>
1022 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto at(T key) -> JSON & {
1023 assert(this->is_object());
1024 assert(this->defines(key));
1025 auto &object{this->data_object};
1026 return object.at(key, object.hash(key));
1027 }
1028
1043 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1044 at(const String &key, const typename Object::hash_type hash) -> JSON & {
1045 assert(this->is_object());
1046 assert(this->defines(key));
1047 return this->data_object.at(key, hash);
1048 }
1049
1052 template <typename T>
1053 requires std::same_as<std::remove_cvref_t<T>, StringView>
1054 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1055 at(T key, const typename Object::hash_type hash) -> JSON & {
1056 assert(this->is_object());
1057 assert(this->defines(key));
1058 return this->data_object.at(key, hash);
1059 }
1060
1075 [[nodiscard]] auto at_or(const String &key, const JSON &otherwise) const
1076 -> const JSON &;
1077
1080 [[nodiscard]] auto at_or(const String &key, JSON &&otherwise) const
1081 -> const JSON & = delete;
1082
1099 [[nodiscard]] auto at_or(const String &key,
1100 const typename Object::hash_type hash,
1101 const JSON &otherwise) const -> const JSON &;
1102
1105 [[nodiscard]] auto at_or(const String &key,
1106 const typename Object::hash_type hash,
1107 JSON &&otherwise) const -> const JSON & = delete;
1108
1121 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto front() -> JSON & {
1122 assert(this->is_array());
1123 assert(!this->empty());
1124 return this->data_array.data.front();
1125 }
1126
1139 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto front() const
1140 -> const JSON & {
1141 assert(this->is_array());
1142 assert(!this->empty());
1143 return this->data_array.data.front();
1144 }
1145
1158 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto back() -> JSON & {
1159 assert(this->is_array());
1160 assert(!this->empty());
1161 return this->data_array.data.back();
1162 }
1163
1176 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto back() const
1177 -> const JSON & {
1178 assert(this->is_array());
1179 assert(!this->empty());
1180 return this->data_array.data.back();
1181 }
1182
1183 /*
1184 * Read operations
1185 */
1186
1207 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto size() const -> std::size_t {
1208 if (this->is_object()) {
1209 return this->object_size();
1210 } else if (this->is_array()) {
1211 return this->array_size();
1212 } else {
1213 return this->string_size();
1214 }
1215 }
1216
1228 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto string_size() const
1229 -> std::size_t {
1230 assert(this->is_string());
1231 return JSON::size(this->data_string);
1232 }
1233
1246 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto array_size() const
1247 -> std::size_t {
1248 assert(this->is_array());
1249 return this->data_array.data.size();
1250 }
1251
1264 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto object_size() const
1265 -> std::size_t {
1266 assert(this->is_object());
1267 return this->data_object.size();
1268 }
1269
1282 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto byte_size() const
1283 -> std::size_t {
1284 assert(this->is_string());
1285 return this->data_string.size();
1286 }
1287
1302 [[nodiscard]] auto estimated_byte_size() const -> std::uint64_t;
1303
1319 [[nodiscard]] auto fast_hash() const -> std::uint64_t;
1320
1333 [[nodiscard]] auto divisible_by(const JSON &divisor) const -> bool;
1334
1354 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto empty() const -> bool {
1355 if (this->is_object()) {
1356 return this->data_object.empty();
1357 } else if (this->is_array()) {
1358 return this->data_array.data.empty();
1359 } else {
1360 return this->data_string.empty();
1361 }
1362 }
1363
1378 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1379 try_at(const String &key) const -> const JSON * {
1380 assert(this->is_object());
1381 const auto &object{this->data_object};
1382 return object.try_at(key, object.hash(key));
1383 }
1384
1386 template <typename T>
1387 requires std::same_as<std::remove_cvref_t<T>, StringView>
1388 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto try_at(T key) const
1389 -> const JSON * {
1390 assert(this->is_object());
1391 const auto &object{this->data_object};
1392 return object.try_at(key, object.hash(key));
1393 }
1394
1411 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1412 try_at(const String &key, const typename Object::hash_type hash) const
1413 -> const JSON * {
1414 assert(this->is_object());
1415 const auto &object{this->data_object};
1416 return object.try_at(key, hash);
1417 }
1418
1421 template <typename T>
1422 requires std::same_as<std::remove_cvref_t<T>, StringView>
1423 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1424 try_at(T key, const typename Object::hash_type hash) const -> const JSON * {
1425 assert(this->is_object());
1426 const auto &object{this->data_object};
1427 return object.try_at(key, hash);
1428 }
1429
1444 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto try_at(const String &key)
1445 -> JSON * {
1446 assert(this->is_object());
1447 auto &object{this->data_object};
1448 return object.try_at(key, object.hash(key));
1449 }
1450
1452 template <typename T>
1453 requires std::same_as<std::remove_cvref_t<T>, StringView>
1454 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto try_at(T key) -> JSON * {
1455 assert(this->is_object());
1456 auto &object{this->data_object};
1457 return object.try_at(key, object.hash(key));
1458 }
1459
1475 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1476 try_at(const String &key, const typename Object::hash_type hash) -> JSON * {
1477 assert(this->is_object());
1478 return this->data_object.try_at(key, hash);
1479 }
1480
1483 template <typename T>
1484 requires std::same_as<std::remove_cvref_t<T>, StringView>
1485 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1486 try_at(T key, const typename Object::hash_type hash) -> JSON * {
1487 assert(this->is_object());
1488 return this->data_object.try_at(key, hash);
1489 }
1490
1515 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1516 try_at(const String &key, const typename Object::hash_type hash,
1517 typename Object::size_type &start) const -> const JSON * {
1518 assert(this->is_object());
1519 const auto &object{this->data_object};
1520 return object.try_at(key, hash, start);
1521 }
1522
1525 template <typename T>
1526 requires std::same_as<std::remove_cvref_t<T>, StringView>
1527 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1528 try_at(T key, const typename Object::hash_type hash,
1529 typename Object::size_type &start) const -> const JSON * {
1530 assert(this->is_object());
1531 const auto &object{this->data_object};
1532 return object.try_at(key, hash, start);
1533 }
1534
1547 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1548 defines(const String &key) const -> bool {
1549 assert(this->is_object());
1550 const auto &object{this->data_object};
1551 return object.defines(key, object.hash(key));
1552 }
1553
1556 template <typename T>
1557 requires std::same_as<std::remove_cvref_t<T>, StringView>
1558 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto defines(T key) const
1559 -> bool {
1560 assert(this->is_object());
1561 const auto &object{this->data_object};
1562 return object.defines(key, object.hash(key));
1563 }
1564
1579 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1580 defines(const String &key, const typename Object::hash_type hash) const
1581 -> bool {
1582 assert(this->is_object());
1583 return this->data_object.defines(key, hash);
1584 }
1585
1588 template <typename T>
1589 requires std::same_as<std::remove_cvref_t<T>, StringView>
1590 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1591 defines(T key, const typename Object::hash_type hash) const -> bool {
1592 assert(this->is_object());
1593 return this->data_object.defines(key, hash);
1594 }
1595
1608 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1609 defines(const typename Array::size_type index) const -> bool {
1610 return this->defines(std::to_string(index));
1611 }
1612
1628 template <typename Iterator>
1629 [[nodiscard]] auto defines_any(Iterator begin, Iterator end) const -> bool {
1630 assert(this->is_object());
1631 return std::any_of(begin, end, [this](const auto &key) -> auto {
1632 return this->defines(key);
1633 });
1634 }
1635
1648 [[nodiscard]] auto defines_any(std::initializer_list<String> keys) const
1649 -> bool;
1650
1663 [[nodiscard]] auto contains(const JSON &element) const -> bool;
1664
1677 [[nodiscard]] auto contains(const StringView element) const -> bool;
1678
1692 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1694 const typename Object::hash_type hash,
1695 const StringView value) const -> bool {
1696 assert(this->is_object());
1697 const auto *member{this->try_at(key, hash)};
1698 return member != nullptr && member->is_array() && member->contains(value);
1699 }
1700
1712 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
1713 array_member_contains(const StringView key, const StringView value) const
1714 -> bool {
1715 return this->array_member_contains(key, Object::hash(key), value);
1716 }
1717
1729 [[nodiscard]] auto is_array_of_strings() const -> bool {
1730 if (!this->is_array()) {
1731 return false;
1732 }
1733
1734 for (const auto &element : this->as_array()) {
1735 if (!element.is_string()) {
1736 return false;
1737 }
1738 }
1739
1740 return true;
1741 }
1742
1754 [[nodiscard]] auto includes(const String &input) const -> bool;
1755
1767 [[nodiscard]] auto includes(const String::value_type input) const -> bool;
1768
1780 [[nodiscard]] auto unique() const -> bool;
1781
1793 [[nodiscard]] auto unique_keys() const -> bool;
1794
1795 /*
1796 * Write operations
1797 */
1798
1813 auto push_back(const JSON &value) -> void;
1814
1828 auto push_back(JSON &&value) -> void;
1829
1846 auto push_back_if_unique(const JSON &value)
1847 -> std::pair<std::reference_wrapper<const JSON>, bool>;
1848
1867 -> std::pair<std::reference_wrapper<const JSON>, bool>;
1868
1883 auto assign(const String &key, const JSON &value) -> void;
1884
1887 template <typename T>
1888 requires std::same_as<std::remove_cvref_t<T>, StringView>
1889 auto assign(T key, const JSON &value) -> void {
1890 assert(this->is_object());
1891 this->data_object.emplace(String{key}, value);
1892 }
1893
1907 auto assign(const String &key, JSON &&value) -> void;
1908
1911 template <typename T>
1912 requires std::same_as<std::remove_cvref_t<T>, StringView>
1913 auto assign(T key, JSON &&value) -> void {
1914 assert(this->is_object());
1915 this->data_object.emplace(String{key}, std::move(value));
1916 }
1917
1931 auto try_assign_before(const String &key, const JSON &value,
1932 const String &other) -> void;
1933
1954 auto assign_if_missing(const String &key, const JSON &value) -> void;
1955
1958 template <typename T>
1959 requires std::same_as<std::remove_cvref_t<T>, StringView>
1960 auto assign_if_missing(T key, const JSON &value) -> void {
1961 assert(this->is_object());
1962 if (!this->defines(key)) {
1963 this->assign(key, value);
1964 }
1965 }
1966
1984 auto assign_if_missing(const String &key, JSON &&value) -> void;
1985
1988 template <typename T>
1989 requires std::same_as<std::remove_cvref_t<T>, StringView>
1990 auto assign_if_missing(T key, JSON &&value) -> void {
1991 assert(this->is_object());
1992 if (!this->defines(key)) {
1993 this->assign(key, std::move(value));
1994 }
1995 }
1996
2011 auto assign_assume_new(const String &key, JSON &&value) -> void;
2012
2028 auto assign_assume_new(String &&key, JSON &&value) -> void;
2029
2032 auto assign_assume_new(String &&key, JSON &&value, Object::hash_type hash)
2033 -> JSON &;
2034
2048 SOURCEMETA_FORCEINLINE inline auto
2050 const typename Object::hash_type hash,
2051 const StringView value) -> void {
2052 if (!value.empty()) {
2053 this->assign_assume_new(String{key}, JSON{value}, hash);
2054 }
2055 }
2056
2069 SOURCEMETA_FORCEINLINE inline auto assign_if_nonempty(const StringView key,
2070 const StringView value)
2071 -> void {
2072 this->assign_if_nonempty(key, Object::hash(key), value);
2073 }
2074
2091 const typename Object::hash_type hash,
2092 const std::span<const StringView> values) -> void {
2093 if (values.empty()) {
2094 return;
2095 }
2096
2097 auto array{JSON::make_array()};
2098 for (const auto value : values) {
2099 array.push_back(JSON{value});
2100 }
2101
2102 this->assign_assume_new(String{key}, std::move(array), hash);
2103 }
2104
2120 const std::span<const StringView> values) -> void {
2121 this->assign_if_nonempty(key, Object::hash(key), values);
2122 }
2123
2135 auto erase(const String &key) -> typename Object::size_type;
2136
2138 template <typename T>
2139 requires std::same_as<std::remove_cvref_t<T>, StringView>
2140 auto erase(T key) -> typename Object::size_type {
2141 assert(this->is_object());
2142 return this->data_object.erase(key);
2143 }
2144
2166 template <typename Iterator>
2167 auto erase_keys(Iterator first, Iterator last) -> void {
2168 assert(this->is_object());
2169 for (auto iterator = first; iterator != last; ++iterator) {
2170 this->data_object.erase(*iterator);
2171 }
2172 }
2173
2192 auto erase_keys(std::initializer_list<String> keys) -> void;
2193
2208 auto erase(typename Array::const_iterator position) ->
2209 typename Array::iterator;
2210
2224 auto erase(typename Array::const_iterator first,
2225 typename Array::const_iterator last) -> typename Array::iterator;
2226
2242 auto erase_if(const std::function<bool(const JSON &)> &predicate) -> void;
2243
2260 auto clear() -> void;
2261
2284 template <typename Iterator>
2285 auto clear_except(Iterator first, Iterator last) -> void {
2286 assert(this->is_object());
2287 std::set<String, std::less<>, Allocator<String>> whitelist;
2288 for (auto iterator = first; iterator != last; ++iterator) {
2289 whitelist.insert(*iterator);
2290 }
2291
2292 std::set<String, std::less<>, Allocator<String>> blacklist;
2293 for (const auto &pair : this->as_object()) {
2294 if (!whitelist.contains(pair.first)) {
2295 blacklist.insert(pair.first);
2296 }
2297 }
2298
2299 this->erase_keys(blacklist.cbegin(), blacklist.cend());
2300 }
2301
2321 auto clear_except(std::initializer_list<String> keys) -> void;
2322
2349 auto merge(const JSON::Object &other) -> void;
2350
2360 [[nodiscard]] auto trim() const -> JSON::String;
2361
2372 auto trim() -> const JSON::String &;
2373
2386 [[nodiscard]] auto is_trimmed() const noexcept -> bool;
2387
2412 auto reorder(const KeyComparison &compare) -> void;
2413
2414 /*
2415 * Transform operations
2416 */
2417
2435 auto rename(const JSON::String &key, JSON::String &&to) -> void;
2436
2451 auto into(const JSON &other) -> void;
2452
2466 auto into(JSON &&other) noexcept -> void;
2467
2481 auto into_array() -> void;
2482
2496 auto into_object() -> void;
2497
2498private:
2499 Type current_type = Type::Null;
2500
2501// Exporting symbols that depends on the standard C++ library is considered
2502// safe.
2503// https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4275?view=msvc-170&redirectedfrom=MSDN
2504#if defined(_MSC_VER)
2505#pragma warning(disable : 4251)
2506#endif
2507 union {
2508 bool data_boolean;
2509 Integer data_integer;
2510 Real data_real;
2511 String data_string;
2512 Array data_array;
2513 Object data_object;
2514 Decimal data_decimal;
2515 };
2516
2517 // Storing the decimal inline must not grow the union beyond its existing
2518 // footprint
2519 static_assert(sizeof(Decimal) <= sizeof(String));
2520#if defined(_MSC_VER)
2521#pragma warning(default : 4251)
2522#endif
2523 auto maybe_destruct_union() -> void;
2524};
2525
2526} // namespace sourcemeta::core
2527
2528#endif
static constexpr auto hash(const String &key) noexcept -> hash_type
Definition json_object.h:181
SOURCEMETA_FORCEINLINE auto is_number() const noexcept -> bool
Definition json_value.h:518
SOURCEMETA_FORCEINLINE auto type() const noexcept -> Type
Definition json_value.h:606
SOURCEMETA_FORCEINLINE auto try_at(const String &key) -> JSON *
Definition json_value.h:1444
JSON(const Array &value)
A copy constructor for the array type.
SOURCEMETA_FORCEINLINE auto try_at(const String &key, const typename Object::hash_type hash, typename Object::size_type &start) const -> const JSON *
Definition json_value.h:1516
JSON(const std::nullptr_t)
double Real
The real type used by the JSON document.
Definition json_value.h:48
auto assign_assume_new(String &&key, JSON &&value, Object::hash_type hash) -> JSON &
char Char
The character type used by the JSON document.
Definition json_value.h:42
SOURCEMETA_FORCEINLINE auto try_at(T key) const -> const JSON *
This method tries to retrieve an object element by string view key.
Definition json_value.h:1388
SOURCEMETA_FORCEINLINE auto at(T key, const typename Object::hash_type hash) -> JSON &
Definition json_value.h:1055
auto assign_assume_new(const String &key, JSON &&value) -> void
SOURCEMETA_FORCEINLINE auto try_at(const String &key, const typename Object::hash_type hash) -> JSON *
Definition json_value.h:1476
JSON(std::initializer_list< typename Object::pair_value_type > values)
std::function< void( const ParsePhase phase, const Type type, const std::uint64_t line, const std::uint64_t column, const ParseContext context, const std::size_t index, const String &property)> ParseCallback
Definition json_value.h:103
auto rename(const JSON::String &key, JSON::String &&to) -> void
auto defines_any(std::initializer_list< String > keys) const -> bool
std::int64_t Integer
The integer type used by the JSON document.
Definition json_value.h:46
auto at_or(const String &key, const typename Object::hash_type hash, JSON &&otherwise) const -> const JSON &=delete
SOURCEMETA_FORCEINLINE auto try_at(const String &key, const typename Object::hash_type hash) const -> const JSON *
Definition json_value.h:1412
SOURCEMETA_FORCEINLINE auto to_decimal() const noexcept -> const Decimal &
Definition json_value.h:682
SOURCEMETA_FORCEINLINE auto as_array() const noexcept -> const Array &
Definition json_value.h:745
SOURCEMETA_FORCEINLINE auto defines(const String &key, const typename Object::hash_type hash) const -> bool
Definition json_value.h:1580
SOURCEMETA_FORCEINLINE auto at(T key) const -> const JSON &
This method retrieves an object element by string view key.
Definition json_value.h:958
SOURCEMETA_FORCEINLINE auto to_boolean() const noexcept -> bool
Definition json_value.h:626
SOURCEMETA_FORCEINLINE auto as_object() noexcept -> Object &
Definition json_value.h:791
SOURCEMETA_FORCEINLINE auto as_object() const noexcept -> const Object &
Definition json_value.h:815
std::char_traits< Char > CharTraits
The character traits used by the JSON document.
Definition json_value.h:44
auto unique_keys() const -> bool
auto erase(const String &key) -> typename Object::size_type
static auto make_array() -> JSON
SOURCEMETA_FORCEINLINE auto at(const String &key, const typename Object::hash_type hash) -> JSON &
Definition json_value.h:1044
SOURCEMETA_FORCEINLINE auto size() const -> std::size_t
Definition json_value.h:1207
auto erase_keys(Iterator first, Iterator last) -> void
Definition json_value.h:2167
auto reorder(const KeyComparison &compare) -> void
auto into_array() -> void
SOURCEMETA_FORCEINLINE auto try_at(T key, const typename Object::hash_type hash) -> JSON *
Definition json_value.h:1486
auto into(const JSON &other) -> void
std::basic_string< Char, CharTraits, Allocator< Char > > String
The string type used by the JSON document.
Definition json_value.h:52
auto contains(const StringView element) const -> bool
auto erase(T key) -> typename Object::size_type
This method deletes an object key by string view.
Definition json_value.h:2140
std::bitset< 8 > TypeSet
A set of types.
Definition json_value.h:89
auto is_positive() const noexcept -> bool
SOURCEMETA_FORCEINLINE auto to_real() const noexcept -> Real
Definition json_value.h:662
SOURCEMETA_FORCEINLINE auto as_real() const -> Real
Definition json_value.h:833
std::allocator< T > Allocator
The allocator used by the JSON document.
Definition json_value.h:50
SOURCEMETA_FORCEINLINE auto at(const typename Array::size_type index) -> JSON &
Definition json_value.h:929
SOURCEMETA_FORCEINLINE auto front() -> JSON &
Definition json_value.h:1121
SOURCEMETA_FORCEINLINE auto defines(const typename Array::size_type index) const -> bool
Definition json_value.h:1609
auto contains(const JSON &element) const -> bool
SOURCEMETA_FORCEINLINE auto try_at(T key, const typename Object::hash_type hash, typename Object::size_type &start) const -> const JSON *
Definition json_value.h:1528
SOURCEMETA_FORCEINLINE auto array_size() const -> std::size_t
Definition json_value.h:1246
SOURCEMETA_FORCEINLINE auto at(const String &key) const -> const JSON &
Definition json_value.h:947
SOURCEMETA_FORCEINLINE auto byte_size() const -> std::size_t
Definition json_value.h:1282
std::function< bool(const String &, const String &)> KeyComparison
Definition json_value.h:110
SOURCEMETA_FORCEINLINE auto is_decimal() const noexcept -> bool
Definition json_value.h:592
SOURCEMETA_FORCEINLINE auto assign_if_nonempty(const StringView key, const StringView value) -> void
Definition json_value.h:2069
SOURCEMETA_FORCEINLINE auto is_integral() const noexcept -> bool
Definition json_value.h:490
SOURCEMETA_FORCEINLINE auto at(const String &key, const typename Object::hash_type hash) const -> const JSON &
Definition json_value.h:981
auto try_assign_before(const String &key, const JSON &value, const String &other) -> void
auto assign_if_nonempty(const StringView key, const std::span< const StringView > values) -> void
Definition json_value.h:2119
SOURCEMETA_FORCEINLINE auto as_array() noexcept -> Array &
Definition json_value.h:763
SOURCEMETA_FORCEINLINE auto is_integer() const noexcept -> bool
Definition json_value.h:461
auto push_back(const JSON &value) -> void
auto assign_assume_new(String &&key, JSON &&value) -> void
auto at_or(const String &key, const JSON &otherwise) const -> const JSON &
auto clear_except(Iterator first, Iterator last) -> void
Definition json_value.h:2285
JSON(Decimal &&value)
A move constructor for the decimal type.
Type
The different types of a JSON instance.
Definition json_value.h:69
@ String
The JSON string type.
Definition json_value.h:79
@ Boolean
The JSON boolean type.
Definition json_value.h:73
@ Array
The JSON array type.
Definition json_value.h:81
@ Object
The JSON object type.
Definition json_value.h:83
@ Real
The JSON real number type.
Definition json_value.h:77
@ Decimal
The JSON decimal type.
Definition json_value.h:85
@ Integer
The JSON integer type.
Definition json_value.h:75
@ Null
The JSON null type.
Definition json_value.h:71
auto push_back_if_unique(const JSON &value) -> std::pair< std::reference_wrapper< const JSON >, bool >
auto assign_if_missing(T key, JSON &&value) -> void
Definition json_value.h:1990
auto is_trimmed() const noexcept -> bool
auto estimated_byte_size() const -> std::uint64_t
JSON(const JSON &)
Misc constructors.
JSON(const Char *const value)
SOURCEMETA_FORCEINLINE auto is_object() const noexcept -> bool
Definition json_value.h:576
auto assign(const String &key, JSON &&value) -> void
SOURCEMETA_FORCEINLINE auto front() const -> const JSON &
Definition json_value.h:1139
JSON(const long value)
This constructor creates a JSON document from an integer type.
Definition json_value.h:149
SOURCEMETA_FORCEINLINE auto as_integer() const -> Integer
Definition json_value.h:856
JSON(const std::size_t value)
auto fast_hash() const -> std::uint64_t
auto merge(const JSON::Object &other) -> void
SOURCEMETA_FORCEINLINE auto at(const String &key) -> JSON &
Definition json_value.h:1011
JSONArray< JSON > Array
The array type used by the JSON document.
Definition json_value.h:56
JSON(const bool value)
SOURCEMETA_FORCEINLINE auto is_real() const noexcept -> bool
Definition json_value.h:475
SOURCEMETA_FORCEINLINE auto back() const -> const JSON &
Definition json_value.h:1176
auto erase(typename Array::const_iterator first, typename Array::const_iterator last) -> typename Array::iterator
auto clear_except(std::initializer_list< String > keys) -> void
auto assign_if_nonempty(const StringView key, const typename Object::hash_type hash, const std::span< const StringView > values) -> void
Definition json_value.h:2090
JSONObject< String, JSON, PropertyHashJSON< JSON::String > > Object
The object type used by the JSON document.
Definition json_value.h:58
SOURCEMETA_FORCEINLINE auto at(T key) -> JSON &
This method retrieves an object element by string view key.
Definition json_value.h:1022
auto includes(const String &input) const -> bool
auto unique() const -> bool
static auto make_object() -> JSON
SOURCEMETA_FORCEINLINE auto try_at(const String &key) const -> const JSON *
Definition json_value.h:1379
SOURCEMETA_FORCEINLINE auto defines(const String &key) const -> bool
Definition json_value.h:1548
JSON(const String &value)
SOURCEMETA_FORCEINLINE auto array_member_contains(const StringView key, const StringView value) const -> bool
Definition json_value.h:1713
auto defines_any(Iterator begin, Iterator end) const -> bool
Definition json_value.h:1629
ParsePhase
The parsing phase of a JSON document.
Definition json_value.h:60
auto is_array_of_strings() const -> bool
Definition json_value.h:1729
auto clear() -> void
SOURCEMETA_FORCEINLINE auto is_boolean() const noexcept -> bool
Definition json_value.h:433
JSON(JSON &&) noexcept
A move constructor.
SOURCEMETA_FORCEINLINE auto to_integer() const noexcept -> Integer
Definition json_value.h:644
JSON(String &&value)
SOURCEMETA_FORCEINLINE auto empty() const -> bool
Definition json_value.h:1354
std::basic_string_view< Char, CharTraits > StringView
The string view type used by the JSON document.
Definition json_value.h:54
auto to_stringstream() const -> std::basic_istringstream< Char, CharTraits, Allocator< Char > >
auto at_or(const String &key, const typename Object::hash_type hash, const JSON &otherwise) const -> const JSON &
auto into_object() -> void
auto erase_if(const std::function< bool(const JSON &)> &predicate) -> void
JSON(const Object &value)
A copy constructor for the object type.
auto assign(const String &key, const JSON &value) -> void
SOURCEMETA_FORCEINLINE auto assign_if_nonempty(const StringView key, const typename Object::hash_type hash, const StringView value) -> void
Definition json_value.h:2049
SOURCEMETA_FORCEINLINE auto is_string() const noexcept -> bool
Definition json_value.h:546
auto includes(const String::value_type input) const -> bool
auto assign_if_missing(T key, const JSON &value) -> void
Definition json_value.h:1960
auto trim() const -> JSON::String
SOURCEMETA_FORCEINLINE auto object_size() const -> std::size_t
Definition json_value.h:1264
JSON(const double value)
SOURCEMETA_FORCEINLINE auto try_at(T key, const typename Object::hash_type hash) const -> const JSON *
Definition json_value.h:1424
auto erase_keys(std::initializer_list< String > keys) -> void
JSON(const std::int64_t value)
auto at_or(const String &key, JSON &&otherwise) const -> const JSON &=delete
SOURCEMETA_FORCEINLINE auto is_array() const noexcept -> bool
Definition json_value.h:561
JSON(const std::basic_string_view< Char, CharTraits > &value)
SOURCEMETA_FORCEINLINE auto string_size() const -> std::size_t
Definition json_value.h:1228
JSON(const int value)
SOURCEMETA_FORCEINLINE auto try_at(T key) -> JSON *
This method tries to retrieve a mutable object element by string view key.
Definition json_value.h:1454
ParseContext
The context type for parse callbacks.
Definition json_value.h:92
JSON(const Decimal &value)
A copy constructor for the decimal type.
auto assign(T key, JSON &&value) -> void
Definition json_value.h:1913
SOURCEMETA_FORCEINLINE auto defines(T key) const -> bool
Definition json_value.h:1558
SOURCEMETA_FORCEINLINE auto array_member_contains(const StringView key, const typename Object::hash_type hash, const StringView value) const -> bool
Definition json_value.h:1693
JSON(const float value)
SOURCEMETA_FORCEINLINE auto defines(T key, const typename Object::hash_type hash) const -> bool
Definition json_value.h:1591
SOURCEMETA_FORCEINLINE auto is_null() const noexcept -> bool
Definition json_value.h:447
SOURCEMETA_FORCEINLINE auto at(T key, const typename Object::hash_type hash) const -> const JSON &
Definition json_value.h:993
static auto size(const String &value) noexcept -> std::size_t
auto assign_if_missing(const String &key, JSON &&value) -> void
auto erase(typename Array::const_iterator position) -> typename Array::iterator
SOURCEMETA_FORCEINLINE auto at(const typename Array::size_type index) const -> const JSON &
Definition json_value.h:904
auto divisible_by(const JSON &divisor) const -> bool
auto assign_if_missing(const String &key, const JSON &value) -> void
SOURCEMETA_FORCEINLINE auto back() -> JSON &
Definition json_value.h:1158
SOURCEMETA_FORCEINLINE auto to_string() const noexcept -> const String &
Definition json_value.h:702
Definition json_array.h:11
Definition json_object.h:19
@ Index
A map of index labels carrying no RDF ranging over an object.
Definition jsonld_materialize.h:116
Definition numeric_decimal.h:21
@ Post
A client_secret in the request body (RFC 6749 Section 2.3.1).
Definition oauth_client_authentication.h:85