8#include <initializer_list>
13#include <unordered_map>
25 std::unordered_map<std::string, Value, detail::TransparentStringHash, std::equal_to<>>;
58 Object(
const std::initializer_list<value_type> il) : map_(il) {}
61 template <
class InputIt>
62 Object(InputIt first, InputIt last) : map_(first, last) {}
92 [[nodiscard]]
bool empty() const noexcept {
111 if (
const auto it = map_.find(key); it != map_.end()) {
114 return map_.emplace(std::string(key),
Value{}).first->second;
122 return map_[std::move(key)];
126 return (*
this)[std::string_view{key}];
131 if (
const auto it = map_.find(key); it != map_.end()) {
134 throw std::out_of_range(
"Object::at: key not found");
137 const Value&
at(
const std::string_view key)
const {
138 if (
const auto it = map_.find(key); it != map_.end()) {
141 throw std::out_of_range(
"Object::at: key not found");
146 return map_.find(key);
150 return map_.find(key);
155 return map_.count(key);
159 template <
class K,
class V>
161 return map_.insert_or_assign(std::forward<K>(k), std::forward<V>(v));
165 template <
class K,
class V>
166 std::pair<iterator, bool>
emplace(K&& k, V&& v) {
167 return map_.emplace(std::forward<K>(k), std::forward<V>(v));
172 return map_.insert(v);
176 return map_.insert(std::move(v));
181 if (
const auto it = map_.find(key); it != map_.end()) {
189 return map_.erase(pos);
195 [[nodiscard]]
bool contains(
const std::string_view key)
const {
196 return map_.contains(key);
201 if (
const auto it = map_.find(key); it != map_.end()) {
208 if (
const auto it = map_.find(key); it != map_.end()) {
216 if (
auto* p =
find_ptr(key); p !=
nullptr) {
219 throw missing_key_error(
"Object::require: missing key '" + std::string(key) +
"'");
223 if (
const auto* p =
find_ptr(key); p !=
nullptr) {
226 throw missing_key_error(
"Object::require: missing key '" + std::string(key) +
"'");
235 throw type_error(
"Object::require_string: '" + std::string(key) +
"' is not a string");
243 throw type_error(
"Object::require_string: '" + std::string(key) +
"' is not a string");
252 throw type_error(
"Object::require_array: '" + std::string(key) +
"' is not an array");
257 if (
const auto* p = v.
as_array_if(); p !=
nullptr) {
260 throw type_error(
"Object::require_array: '" + std::string(key) +
"' is not an array");
269 throw type_error(
"Object::require_object: '" + std::string(key) +
"' is not an object");
277 throw type_error(
"Object::require_object: '" + std::string(key) +
"' is not an object");
281 [[nodiscard]]
const std::string*
get_string_if(
const std::string_view key)
const {
282 if (
const auto* v =
find_ptr(key); v !=
nullptr) {
283 return v->as_string_if();
288 [[nodiscard]]
const Array*
get_array_if(
const std::string_view key)
const {
289 if (
const auto* v =
find_ptr(key); v !=
nullptr) {
290 return v->as_array_if();
296 if (
const auto* v =
find_ptr(key); v !=
nullptr) {
297 return v->as_object_if();
307 [[nodiscard]]
const Value*
find_path(std::string_view path)
const;
313 [[nodiscard]]
bool contains_path(std::string_view path)
const;
332 return a.map_ == b.map_;
344using Metadata = Object;
355 requires std::same_as<B, bool>
358template <detail::SignedIntLike T>
361template <detail::Un
signedIntLike T>
362inline Value::Value(T x) noexcept : v_(
static_cast<std::uint64_t
>(x)) {}
364template <detail::FloatLike T>
366 if constexpr (std::is_same_v<std::remove_cv_t<T>,
float>) {
369 v_ =
static_cast<double>(x);
381inline Value::Value(
const std::initializer_list<std::pair<const std::string, Value>> il)
387 v_ = std::move(other.v_);
394 using T = std::decay_t<
decltype(x)>;
395 if constexpr (std::is_same_v<T, std::unique_ptr<Object>>) {
396 v_ = std::make_unique<Object>(*x);
405 if (
this == &other) {
409 v_ = std::move(tmp.v_);
420 v_ = std::make_unique<Object>(
Object(il));
428 return std::holds_alternative<std::nullptr_t>(v_);
431 return std::holds_alternative<bool>(v_);
434 return std::holds_alternative<std::int64_t>(v_);
437 return std::holds_alternative<std::uint64_t>(v_);
440 return std::holds_alternative<float>(v_);
443 return std::holds_alternative<double>(v_);
449 return std::holds_alternative<std::string>(v_);
452 return std::holds_alternative<Array>(v_);
455 return std::holds_alternative<std::unique_ptr<Object>>(v_);
459 return std::get<bool>(v_);
462 return std::get<std::int64_t>(v_);
465 return std::get<std::uint64_t>(v_);
469 return std::get<float>(v_);
473 if (
const auto* p = std::get_if<double>(&v_); p !=
nullptr) {
476 if (
const auto* p = std::get_if<float>(&v_); p !=
nullptr) {
477 return static_cast<double>(*p);
479 if (
const auto* p = std::get_if<std::int64_t>(&v_); p !=
nullptr) {
480 return static_cast<double>(*p);
482 if (
const auto* p = std::get_if<std::uint64_t>(&v_); p !=
nullptr) {
483 return static_cast<double>(*p);
485 throw type_error(
"Value::as_double: value is not a number");
489 return std::get<std::string>(v_);
492 return std::get<std::string>(v_);
495 return std::get<Array>(v_);
498 return std::get<Array>(v_);
502 return *std::get<std::unique_ptr<Object>>(v_);
505 return *std::get<std::unique_ptr<Object>>(v_);
509 return std::get_if<bool>(&v_);
512 return std::get_if<bool>(&v_);
515 return std::get_if<std::int64_t>(&v_);
518 return std::get_if<std::int64_t>(&v_);
521 return std::get_if<std::uint64_t>(&v_);
524 return std::get_if<std::uint64_t>(&v_);
527 return std::get_if<float>(&v_);
530 return std::get_if<float>(&v_);
533 return std::get_if<double>(&v_);
536 return std::get_if<double>(&v_);
540 return std::get_if<std::string>(&v_);
543 return std::get_if<std::string>(&v_);
546 return std::get_if<Array>(&v_);
549 return std::get_if<Array>(&v_);
553 if (
const auto* p = std::get_if<std::unique_ptr<Object>>(&v_); p !=
nullptr) {
559 if (
const auto* p = std::get_if<std::unique_ptr<Object>>(&v_); p !=
nullptr) {
565inline bool operator==(
const Value& a,
const Value& b)
noexcept {
566 if (a.v_.index() != b.v_.index()) {
570 [&](
const auto& x) ->
bool {
571 using T = std::decay_t<
decltype(x)>;
572 if constexpr (std::is_same_v<T, std::unique_ptr<Object>>) {
573 const auto& y = std::get<std::unique_ptr<Object>>(b.v_);
576 const auto& y = std::get<T>(b.v_);
583inline bool operator!=(
const Value& a,
const Value& b)
noexcept {
589 return std::get_if<T>(&v_);
593 return std::get_if<T>(&v_);
598 if (
auto* p = std::get_if<T>(&v_)) {
617inline Value null() noexcept {
620inline Value boolean(
const bool b)
noexcept {
623inline Value string(std::string s) {
624 return Value{std::move(s)};
626inline Value string(
const std::string_view s) {
629inline Value string(
const char* s) {
636[[nodiscard]]
inline Object object() {
640[[nodiscard]]
inline Object object(
const std::initializer_list<Object::value_type> il) {
647 for (
const auto& [k, v] : source.map_) {
648 auto it = map_.find(k);
649 if (it == map_.end()) {
653 Object* dst_obj = it->second.as_object_if();
654 if (
const Object* src_obj = v.as_object_if(); dst_obj !=
nullptr && src_obj !=
nullptr) {
655 dst_obj->
merge(*src_obj);
Ordered-by-insertion-time-ish string-keyed map of Values, with transparent string-view lookup and JSO...
Definition object.hpp:21
map_type::reference reference
Reference to a stored value_type.
Definition object.hpp:42
const Value * find_ptr(const std::string_view key) const
Return a pointer to the value for key, or nullptr if absent.
Definition object.hpp:207
iterator begin() noexcept
Iterator to the first element.
Definition object.hpp:67
Value * find_path(std::string_view path)
Find a value by dotted path (e.g. "a.b[0].c"), or nullptr on miss.
Definition path.hpp:162
size_type count(const std::string_view key) const
Return 1 if key is present, otherwise 0.
Definition object.hpp:154
void merge(const Object &source)
Deep-merge source into this object; nested objects recurse, other alternatives are overwritten,...
Definition object.hpp:646
const Object * get_object_if(const std::string_view key) const
Pointer to the nested object at key, or nullptr if absent or wrong type.
Definition object.hpp:295
const Value & require(const std::string_view key) const
Return the value for key; throws missing_key_error if absent.
Definition object.hpp:222
iterator erase(const const_iterator pos)
Erase the entry at pos; returns the next iterator.
Definition object.hpp:188
map_type::key_type key_type
Key type (always std::string).
Definition object.hpp:28
iterator end() noexcept
Iterator past the last element.
Definition object.hpp:79
Value & operator[](std::string &&key)
Access (and default-insert if missing) the value for key.
Definition object.hpp:121
void clear() noexcept
Remove all entries.
Definition object.hpp:101
std::pair< iterator, bool > emplace(K &&k, V &&v)
Construct an entry in place; no effect if k already exists.
Definition object.hpp:166
Object()=default
Construct an empty Object.
map_type::pointer pointer
Pointer to a stored value_type.
Definition object.hpp:46
friend bool operator!=(const Object &a, const Object &b) noexcept
Negation of operator==.
Definition object.hpp:335
const_iterator cend() const noexcept
Const iterator past the last element.
Definition object.hpp:87
const std::string * get_string_if(const std::string_view key) const
Pointer to the string at key, or nullptr if absent or wrong type.
Definition object.hpp:281
const std::string & require_string(const std::string_view key) const
Return the string at key; throws on missing key or type mismatch.
Definition object.hpp:238
const map_type & raw() const noexcept
Access the underlying std::unordered_map.
Definition object.hpp:326
std::unordered_map< std::string, Value, detail::TransparentStringHash, std::equal_to<> > map_type
Underlying associative container type.
Definition object.hpp:25
bool contains_path(std::string_view path) const
True if path resolves to a value in the object.
Definition path.hpp:191
const_iterator begin() const noexcept
Const iterator to the first element.
Definition object.hpp:71
Array & require_array(const std::string_view key)
Return the array at key; throws on missing key or type mismatch.
Definition object.hpp:247
const_iterator cbegin() const noexcept
Const iterator to the first element.
Definition object.hpp:75
Object(InputIt first, InputIt last)
Construct from an iterator range of key/value pairs.
Definition object.hpp:62
const Value & at(const std::string_view key) const
Access the value for key; throws std::out_of_range if missing.
Definition object.hpp:137
map_type::key_equal key_equal
Key-equality functor type.
Definition object.hpp:40
size_type erase(const std::string_view key)
Erase the entry for key; returns 1 if removed, otherwise 0.
Definition object.hpp:180
map_type::difference_type difference_type
Signed difference type for iterators.
Definition object.hpp:36
std::string & require_string(const std::string_view key)
Return the string at key; throws on missing key or type mismatch.
Definition object.hpp:230
iterator find(const std::string_view key)
Find an entry by key, returning end() on miss.
Definition object.hpp:145
map_type::hasher hasher
Hash functor type.
Definition object.hpp:38
Value & require(const std::string_view key)
Return the value for key; throws missing_key_error if absent.
Definition object.hpp:215
Object & require_object(const std::string_view key)
Return the nested object at key; throws on missing key or type mismatch.
Definition object.hpp:264
bool empty() const noexcept
True if the object has no entries.
Definition object.hpp:92
size_type size() const noexcept
Number of entries.
Definition object.hpp:96
const Object & require_object(const std::string_view key) const
Return the nested object at key; throws on missing key or type mismatch.
Definition object.hpp:272
Value & operator[](const std::string_view key)
Access (and default-insert if missing) the value for key.
Definition object.hpp:110
std::pair< iterator, bool > insert(const value_type &v)
Insert an entry; no effect if the key already exists.
Definition object.hpp:171
Value & operator[](const std::string &key)
Access (and default-insert if missing) the value for key.
Definition object.hpp:117
Object(const std::initializer_list< value_type > il)
Construct from a braced list of key/value pairs.
Definition object.hpp:58
std::pair< iterator, bool > insert(value_type &&v)
Insert an entry; no effect if the key already exists.
Definition object.hpp:175
map_type::mapped_type mapped_type
Mapped value type (always Value).
Definition object.hpp:30
map_type::const_iterator const_iterator
Const iterator type.
Definition object.hpp:52
Value & at(const std::string_view key)
Access the value for key; throws std::out_of_range if missing.
Definition object.hpp:130
const Array & require_array(const std::string_view key) const
Return the array at key; throws on missing key or type mismatch.
Definition object.hpp:255
const Array * get_array_if(const std::string_view key) const
Pointer to the array at key, or nullptr if absent or wrong type.
Definition object.hpp:288
map_type::size_type size_type
Unsigned size type.
Definition object.hpp:34
const_iterator end() const noexcept
Const iterator past the last element.
Definition object.hpp:83
map_type::const_pointer const_pointer
Const pointer to a stored value_type.
Definition object.hpp:48
const Value & require_path(std::string_view path) const
Return the value at path; throws on miss or malformed path.
Definition path.hpp:167
void reserve(const size_type n)
Reserve storage for at least n entries.
Definition object.hpp:105
map_type::const_reference const_reference
Const reference to a stored value_type.
Definition object.hpp:44
std::pair< iterator, bool > insert_or_assign(K &&k, V &&v)
Insert or overwrite the entry for k.
Definition object.hpp:160
map_type & raw() noexcept
Access the underlying std::unordered_map.
Definition object.hpp:322
map_type::value_type value_type
std::pair<const key_type, mapped_type>.
Definition object.hpp:32
map_type::iterator iterator
Mutable iterator type.
Definition object.hpp:50
Value * find_ptr(const std::string_view key)
Return a pointer to the value for key, or nullptr if absent.
Definition object.hpp:200
friend bool operator==(const Object &a, const Object &b) noexcept
Deep value-equality compare two Objects.
Definition object.hpp:331
const_iterator find(const std::string_view key) const
Find an entry by key, returning end() on miss.
Definition object.hpp:149
bool contains(const std::string_view key) const
True if key is present in the object.
Definition object.hpp:195
Value & operator[](const char *key)
Access (and default-insert if missing) the value for key.
Definition object.hpp:125
Discriminated union holding one of the JSON-like alternatives (null, bool, signed/unsigned integer,...
Definition value.hpp:67
std::string * as_string_if() noexcept
Return a pointer to the string, or nullptr if not held.
Definition object.hpp:539
bool is_int() const noexcept
True if the value holds a signed integer (std::int64_t).
Definition object.hpp:433
bool is_bool() const noexcept
True if the value holds a bool.
Definition object.hpp:430
bool is_uint() const noexcept
True if the value holds an unsigned integer (std::uint64_t).
Definition object.hpp:436
bool is_object() const noexcept
True if the value holds a nested Object.
Definition object.hpp:454
std::string & as_string()
Access the string alternative; throws on type mismatch.
Definition object.hpp:488
bool is_null() const noexcept
True if the value holds nullptr.
Definition object.hpp:427
std::int64_t * as_int_if() noexcept
Return a pointer to the signed integer, or nullptr if not held.
Definition object.hpp:514
double as_double() const
Return as double, widening from int64/uint64/float as needed.
Definition object.hpp:472
Value & operator=(Value &&other) noexcept
Move-assign from another Value.
Definition object.hpp:386
Value() noexcept
Construct a null-valued Value.
Definition object.hpp:351
bool is_double() const noexcept
True if the value holds a double.
Definition object.hpp:442
std::int64_t as_int() const
Return the signed integer; throws on type mismatch.
Definition object.hpp:461
std::size_t index() const noexcept
Return the zero-based index of the active alternative.
Definition object.hpp:611
float as_float() const
Return the float; strict — throws if the value isn't a float.
Definition object.hpp:468
bool is_float() const noexcept
True if the value holds a float.
Definition object.hpp:439
T value_or(T fallback) const
Return the held T by value, or fallback if a different alternative is active.
Definition object.hpp:597
bool is_array() const noexcept
True if the value holds an Array.
Definition object.hpp:451
std::uint64_t as_uint() const
Return the unsigned integer; throws on type mismatch.
Definition object.hpp:464
Object * as_object_if() noexcept
Return a pointer to the nested object, or nullptr if not held.
Definition object.hpp:552
std::variant< std::nullptr_t, bool, std::int64_t, std::uint64_t, float, double, std::string, Array, std::unique_ptr< Object > > variant_type
Underlying std::variant type that stores the active alternative.
Definition value.hpp:82
T * get_if() noexcept
Return a pointer to the alternative of type T, or nullptr if not held.
Definition object.hpp:588
Array & as_array()
Access the array alternative; throws on type mismatch.
Definition object.hpp:494
std::uint64_t * as_uint_if() noexcept
Return a pointer to the unsigned integer, or nullptr if not held.
Definition object.hpp:520
variant_type & raw() noexcept
Return the underlying std::variant for advanced access.
Definition object.hpp:604
bool is_number() const noexcept
True if the value holds any numeric alternative.
Definition object.hpp:445
bool is_string() const noexcept
True if the value holds a std::string.
Definition object.hpp:448
bool as_bool() const
Return the bool; throws std::bad_variant_access on type mismatch.
Definition object.hpp:458
Array * as_array_if() noexcept
Return a pointer to the array, or nullptr if not held.
Definition object.hpp:545
bool * as_bool_if() noexcept
Return a pointer to the bool, or nullptr if the value isn't a bool.
Definition object.hpp:508
double * as_double_if() noexcept
Return a pointer to the double, or nullptr if not held.
Definition object.hpp:532
Object & as_object()
Access the nested object; throws on type mismatch.
Definition object.hpp:501
float * as_float_if() noexcept
Return a pointer to the float, or nullptr if not held.
Definition object.hpp:526
Thrown when a required key or path is not present in an Object.
Definition error.hpp:14
Thrown when a Value holds a different alternative than the caller demanded.
Definition error.hpp:19