cheatah
Source

stdlib/parsers/json/string.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 — the JSON string token (decoded, un-escaped). See json.hpp.
7#include <string>
8#include <string_view>
9#include <type_traits>
10#include <utility>
12namespace cheatah::parsers::json {
14// String holds its characters one of two ways, chosen by the storage type S, which is DEDUCED
15// from the constructor argument (see the deduction guides below):
16//
17// - String<std::string_view> — a non-owning VIEW. Zero-copy. This is what a const char* /
18// string literal or an existing buffer becomes. The viewed characters must outlive the
19// String; string literals live in the binary for the whole program, so String{"x"} can
20// refer to that const data as its own value, safely, forever.
21// - String<std::string> — OWNS its characters (an rvalue std::string moved in).
22//
23// A const char* is ALWAYS wrapped in a std::string_view and is NEVER silently copied into a
24// std::string. S is constrained to exactly those two storage types.
25// Valid backing storage for a String: either owning (std::string) or non-owning (std::string_view).
26template <typename S>
27concept StringStorage = std::is_same_v<S, std::string> || std::is_same_v<S, std::string_view>;
29/**
30 * @brief A decoded (un-escaped) JSON string token, storing its characters either owned
31 * (String<std::string>) or as a zero-copy view (String<std::string_view>), chosen by
32 * the storage type @p S via the deduction guides below.
33 * @tparam S the backing storage: std::string (owning) or std::string_view (viewing).
34 */
35template <StringStorage S>
36class String {
37private:
38 S value_;
40public:
41 /**
42 * Construct from the backing storage. Owning S=std::string moves the rvalue in; viewing
43 * S=std::string_view just stores the (cheap) view — the characters are never copied here.
44 * @param value the string storage (moved in).
45 * @complexity O(1) — a std::string move or a std::string_view copy; characters are never copied.
46 * @alloc none.
47 * @test CheatahParsersJson.ContainerTokenLifecycle
48 */
49 String(S value) : value_(std::move(value)) {}
50 ~String() = default;
52 /**
53 * Read the characters uniformly as a view, whether owning or viewing (no setter).
54 * @return a std::string_view over the stored characters.
55 * @complexity O(1).
56 * @alloc none.
57 * @test CheatahParsersJson.ContainerTokenLifecycle
58 */
59 [[nodiscard]] std::string_view value() const noexcept { return value_; }
60};
62/**
63 * Deduction guides — route each argument to the right storage. A const char* and a
64 * std::string_view become VIEWS (never a std::string); an rvalue std::string is OWNED. These
65 * user-defined guides are preferred over the implicit one, so String{"lit"} deduces
66 * String<std::string_view>, not String<const char*>.
67 * @complexity O(1) — deduction is compile-time; the chosen constructor moves or views.
68 * @alloc none.
69 * @test CheatahParsersJson.ContainerTokenLifecycle
70 */
71String(const char*) -> String<std::string_view>;
72/** @copydoc String(const char*) */
73String(std::string_view) -> String<std::string_view>;
74/** @copydoc String(const char*) */
75String(std::string) -> String<std::string>;
77} // namespace cheatah::parsers::json