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 once5
// 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>12
namespace cheatah::parsers::json {14
// String holds its characters one of two ways, chosen by the storage type S, which is DEDUCED15
// 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 the19
// String; string literals live in the binary for the whole program, so String{"x"} can20
// 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 a24
// 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).26
template <typename S>27
concept 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 owned31
* (String<std::string>) or as a zero-copy view (String<std::string_view>), chosen by32
* 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
*/35
template <StringStorage S>36
class String {37
private:38
S value_;40
public:41
/**42
* Construct from the backing storage. Owning S=std::string moves the rvalue in; viewing43
* 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.ContainerTokenLifecycle48
*/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.ContainerTokenLifecycle58
*/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 a64
* std::string_view become VIEWS (never a std::string); an rvalue std::string is OWNED. These65
* user-defined guides are preferred over the implicit one, so String{"lit"} deduces66
* 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.ContainerTokenLifecycle70
*/71
String(const char*) -> String<std::string_view>;72
/** @copydoc String(const char*) */73
String(std::string_view) -> String<std::string_view>;74
/** @copydoc String(const char*) */75
String(std::string) -> String<std::string>;77
} // namespace cheatah::parsers::json