cheatah
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 once
5// cheatah::parsers::json — Node: the dynamic JSON value. This is the single header for the Node
6// TYPE (the class). Forward declarations for the value model (the Node name, the ArrayStorage
7// 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 bare
10// variant alias) for ONE reason: to be forward-declarable, which lets Array be templated on its
11// 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::visit
13// 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"
27namespace cheatah::parsers::json {
29/**
30 * @brief The dynamic JSON value: a thin class wrapping a std::variant over the token types
31 * (Null, Boolean, Number, owning/viewing String, Array, Object). There is no runtime
32 * polymorphism — dispatch is compile-time std::visit over variant(); the class exists to
33 * be forward-declarable so Array/Object can be templated on their storage type.
34 */
35class Node {
36public:
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 itself
47 * 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.TokenClassesAndNodeVariant
53 */
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.TokenClassesAndNodeVariant
64 */
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.TokenClassesAndNodeVariant
72 */
73 [[nodiscard]] const variant_type& variant() const noexcept { return data_; }
75private:
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 */
86struct Member {
87 Node first; ///< the key — a string Node.
88 Node second; ///< the value Node.
89};
91} // namespace cheatah::parsers::json