Source
stdlib/parsers/json/node.hpp
1
// Copyright (c) 2026 BigBrain LLC. MIT-licensed (see LICENSE).2
// Original work; see ACKNOWLEDGMENTS.md for the open-source ideas we build upon.3
#pragma once5
// cheatah::parsers::json — Node: the dynamic JSON value. This is the single header for the Node6
// TYPE (the class). Forward declarations for the value model (the Node name, the ArrayStorage7
// concept, Array/Object/Member) live in fwd.hpp, so the token headers can compile standalone.8
//9
// Node is a thin CLASS wrapping a std::variant over the token types. It is a class (not a bare10
// variant alias) for ONE reason: to be forward-declarable, which lets Array be templated on its11
// storage TYPE with a real ArrayStorage concept — exactly symmetric with String / StringStorage.12
// There is NO runtime polymorphism: no virtual functions, no base classes; dispatch is std::visit13
// over the variant, resolved at compile time. The wrapper just exposes the variant via variant().15
#include <type_traits>16
#include <utility>17
#include <variant>19
#include "fwd.hpp"20
#include "array.hpp"21
#include "boolean.hpp"22
#include "null.hpp"23
#include "number.hpp"24
#include "object.hpp"25
#include "string.hpp"27
namespace cheatah::parsers::json {29
/**30
* @brief The dynamic JSON value: a thin class wrapping a std::variant over the token types31
* (Null, Boolean, Number, owning/viewing String, Array, Object). There is no runtime32
* polymorphism — dispatch is compile-time std::visit over variant(); the class exists to33
* be forward-declarable so Array/Object can be templated on their storage type.34
*/35
class Node {36
public:37
/// The set of JSON value alternatives this Node may hold (null is the first, default state).38
using variant_type = std::variant<Null, Boolean, Number,39
String<std::string_view>, String<std::string>,40
ArrayView, OwnedArray,41
ObjectView, OwnedObject>;43
Node() = default; // JSON null (the variant's first alternative)45
/**46
* Construct from any one of the token alternatives (e.g. Number{3.5}); excludes Node itself47
* so the copy/move constructors are not hidden.48
* @tparam T one of the variant alternative types.49
* @param value the token value to store (forwarded into the variant).50
* @complexity O(1) — one move/copy of the token into the variant.51
* @alloc none of its own (whatever the moved-in token owns comes along).52
* @test CheatahParsersJson.TokenClassesAndNodeVariant53
*/54
template <class T>55
requires(!std::is_same_v<std::remove_cvref_t<T>, Node>)56
Node(T&& value) : data_(std::forward<T>(value)) {}58
/**59
* The underlying variant, for dispatch with std::visit / std::get / std::get_if / emplace.60
* @return a mutable reference to the wrapped variant.61
* @complexity O(1).62
* @alloc none.63
* @test CheatahParsersJson.TokenClassesAndNodeVariant64
*/65
[[nodiscard]] variant_type& variant() noexcept { return data_; }66
/**67
* The underlying variant (const overload).68
* @return a const reference to the wrapped variant.69
* @complexity O(1).70
* @alloc none.71
* @test CheatahParsersJson.TokenClassesAndNodeVariant72
*/73
[[nodiscard]] const variant_type& variant() const noexcept { return data_; }75
private:76
variant_type data_;77
};79
// Member holds two Nodes BY VALUE (key + value), so it is defined here — after Node is complete.80
// It is forward-declared in fwd.hpp so Object / ObjectStorage can name vector<Member> /81
// span<const Member> while Node is still being defined.82
/**83
* @brief One key/value entry of a JSON object, holding both the key and value Nodes by value.84
* Defined here (after Node is complete) and forward-declared in fwd.hpp.85
*/86
struct Member {87
Node first; ///< the key — a string Node.88
Node second; ///< the value Node.89
};91
} // namespace cheatah::parsers::json