11template<
typename S = std::
string>
12requires std::convertible_to<S, std::string>
16 [[nodiscard]] std::string_view
getKey()
const {
26 [[nodiscard]] std::string_view
getValue()
const {
31 template<KV1ValueType V>
33 if constexpr (std::convertible_to<V, std::string_view>) {
35 }
else if constexpr (std::same_as<V, bool>) {
37 }
else if constexpr (std::same_as<V, int32_t> || std::same_as<V, int64_t>) {
45 }
else if constexpr (std::same_as<V, float>) {
54 template<KV1ValueType V>
56 if constexpr (std::convertible_to<V, std::string_view>) {
57 this->
value = std::string_view{value_};
58 }
else if constexpr (std::same_as<V, bool>) {
59 this->
setValue(std::format(
"{:b}", value_));
61 this->
setValue(std::format(
"{}", value_));
66 template<KV1ValueType V>
83 [[nodiscard]]
bool hasChild(std::string_view childKey)
const {
88 template<KV1ValueType V = std::
string_view>
106 for (
const auto& element : this->
children) {
115 [[nodiscard]]
const std::vector<KV1ElementWritable>&
getChildren()
const {
124 using iterator = std::vector<KV1ElementWritable>::iterator;
174 for (
const auto& element : this->
children) {
184 for (
auto& element : this->
children) {
194 unsigned int count = 0;
195 for (
const auto& element : this->
children) {
210 unsigned int count = 0;
211 for (
auto& element: this->
children) {
233 unsigned int count = 0;
234 for (
auto element = this->
children.begin(); element != this->children.end(); ++element) {
236 if (n < 0 || count == n) {
237 element = this->
children.erase(element);
257 [[nodiscard]]
explicit operator bool()
const {
269 if (stream.peek<
char>() ==
'}') {
280 if (stream.peek<
char>() !=
'{') {
285 if (stream.peek<
char>() ==
'[') {
290 if (stream.peek<
char>() ==
'{') {
293 if (stream.peek<
char>() !=
'}') {
304 constexpr auto writeIndentation = [](BufferStream& stream_,
unsigned short indentLevel_) {
305 for (
unsigned short i = 0; i < indentLevel_; i++) {
309 constexpr auto writeQuotedString = [](BufferStream& stream_, std::string_view str,
const parser::text::EscapeSequenceMap& escapeSequences_,
char quoteStart =
'\"',
char quoteEnd =
'\"') {
310 stream_.write(quoteStart);
314 stream_.write(quoteEnd);
317 for (
const auto& e : elements) {
318 writeIndentation(stream, indentLevel);
319 writeQuotedString(stream, e.key, escapeSequences);
320 if (!e.value.empty() || e.children.empty()) {
322 writeQuotedString(stream, e.value, escapeSequences);
324 if (!e.conditional.empty()) {
326 writeQuotedString(stream, e.conditional, escapeSequences,
'[',
']');
329 if (!e.children.empty()) {
330 writeIndentation(stream, indentLevel);
331 stream <<
'{' <<
'\n';
332 write(stream, e.children, indentLevel + 1, escapeSequences);
333 writeIndentation(stream, indentLevel);
334 stream <<
'}' <<
'\n';
345template<
typename S = std::
string>
346requires std::convertible_to<S, std::string_view>
349 explicit KV1Writer(std::string_view kv1Data =
"",
bool useEscapeSequences_ =
false)
352 if (kv1Data.empty()) {
355 BufferStreamReadOnly stream{kv1Data};
357 KV1ElementWritable<S>::read(stream, this->children, sourcepp::parser::text::getDefaultEscapeSequencesOrNone(this->useEscapeSequences));
358 } catch (
const std::overflow_error&) {}
361 [[nodiscard]] std::string
bake()
const {
363 BufferStream stream{buffer};
365 buffer.resize(stream.size());
369 void bake(
const std::filesystem::path& kv1Path)
const {
387inline KV1Writer<> operator""_kv1w(
const char* str,
const std::size_t len) {
388 return KV1Writer{std::string_view{str, len}};
std::vector< KV1ElementWritable > & getChildren()
Get the child elements of the element.
constexpr const_iterator end() const
void setKey(std::string_view key_)
Set the key associated with the element.
std::string_view getConditional() const
Get the conditional associated with the element.
bool isInvalid() const
Check if the given element is invalid.
constexpr const_iterator begin() const
const std::vector< KV1ElementWritable > & getChildren() const
Get the child elements of the element.
void removeChild(std::string_view childKey, int n=-1)
Remove a child element from the element with the given key. -1 means all children with the given key.
const KV1ElementWritable & operator()(std::string_view childKey) const
Get the first child element of the element with the given key.
KV1ElementWritable()=default
void removeChild(unsigned int n)
Remove a child element from the element.
static void write(BufferStream &stream, const std::vector< KV1ElementWritable > &elements, unsigned short indentLevel, const sourcepp::parser::text::EscapeSequenceMap &escapeSequences)
constexpr iterator begin()
KV1ElementWritable & operator=(V value_)
Set the value associated with the element.
void setConditional(std::string_view conditional_)
Set the conditional associated with the element.
KV1ElementWritable & operator()(std::string_view childKey, unsigned int n)
Get the nth child element of the element with the given key, or create a new element if it doesn't ex...
std::vector< KV1ElementWritable > children
KV1ElementWritable & addChild(std::string_view key_, V value_={}, std::string_view conditional_="")
void setValue(V value_)
Set the value associated with the element.
constexpr const_iterator cend() const
std::vector< KV1ElementWritable >::iterator iterator
KV1ElementWritable & operator[](unsigned int n)
Get the child element of the element at the given index.
KV1ElementWritable & operator()(std::string_view childKey)
Get the first child element of the element with the given key, or create a new element if it doesn't ...
std::vector< KV1ElementWritable >::const_iterator const_iterator
const KV1ElementWritable & operator[](unsigned int n) const
Get the child element of the element at the given index.
uint64_t getChildCount(std::string_view childKey) const
Get the number of child elements with the given key.
static void read(BufferStreamReadOnly &stream, std::vector< KV1ElementWritable > &elements, const sourcepp::parser::text::EscapeSequenceMap &escapeSequences)
std::string_view getValue() const
Get the value associated with the element.
bool hasChild(std::string_view childKey) const
Check if the element has one or more children with the given key.
KV1ElementWritable & operator[](std::string_view childKey)
Get the first child element of the element with the given key, or create a new element if it doesn't ...
const KV1ElementWritable & operator()(std::string_view childKey, unsigned int n) const
Get the nth child element of the element with the given key.
constexpr const_iterator cbegin() const
static const KV1ElementWritable & getInvalid()
uint64_t getChildCount() const
Get the number of child elements.
std::string_view getKey() const
Get the key associated with the element.
const KV1ElementWritable & operator[](std::string_view childKey) const
Get the first child element of the element with the given key.
V getValue() const
Get the value associated with the element as the given type.
void bake(const std::filesystem::path &kv1Path) const
KV1Writer(std::string_view kv1Data="", bool useEscapeSequences_=false)
bool writeFileText(const std::filesystem::path &filepath, std::string_view text)
std::string convertSpecialCharsToEscapes(std::string_view str, const EscapeSequenceMap &escapeSequences)
Convert special characters like \n to escaped special characters like \\n.
std::unordered_map< char, char > EscapeSequenceMap
void eatWhitespaceAndSingleLineComments(BufferStream &stream, std::string_view singleLineCommentStart=DEFAULT_SINGLE_LINE_COMMENT_START)
Eat all whitespace and single line comments after the current stream position.
std::string readString(BufferStream &stream, std::string_view start=DEFAULT_STRING_START, std::string_view end=DEFAULT_STRING_END, const EscapeSequenceMap &escapeSequences=getDefaultEscapeSequences())
Read a string starting at the current stream position.
constexpr std::string_view DEFAULT_STRING_END
constexpr std::string_view DEFAULT_STRING_START
const EscapeSequenceMap & getDefaultEscapeSequencesOrNone(bool useEscapes)
bool isNumber(char c)
If a char is a numerical character (0-9).
std::from_chars_result toFloat(std::string_view number, std::floating_point auto &out)
std::from_chars_result toInt(std::string_view number, std::integral auto &out, int base=10)
bool iequals(std::string_view s1, std::string_view s2)