8#include <BufferStream.h>
17 || std::same_as<V, bool>
18 || std::same_as<V, int32_t>
19 || std::same_as<V, int64_t>
20 || std::same_as<V, float>;
22template<
typename S,
typename K>
23requires std::convertible_to<S, std::string_view>
27 [[nodiscard]] std::string_view
getKey()
const {
32 [[nodiscard]] std::string_view
getValue()
const {
37 template<KV1ValueType V>
39 if constexpr (std::convertible_to<V, std::string_view>) {
41 }
else if constexpr (std::same_as<V, bool>) {
42 return static_cast<bool>(this->getValue<int32_t>());
43 }
else if constexpr (std::same_as<V, int32_t>) {
45 return std::stoi(std::string{this->
value.substr(2)},
nullptr, 16);
47 return std::stoi(std::string{this->
value});
48 }
else if constexpr (std::same_as<V, int64_t>) {
50 return std::stoll(std::string{this->
value.substr(2)},
nullptr, 16);
52 return std::stoll(std::string{this->
value});
53 }
else if constexpr (std::same_as<V, float>) {
54 return std::stof(std::string{this->
value});
65 [[nodiscard]]
bool hasChild(std::string_view childKey)
const {
102 for (
const auto& element : this->
children) {
112 unsigned int count = 0;
113 for (
const auto& element : this->
children) {
141 parser::text::eatWhitespaceAndSingleLineComments(stream);
142 if (stream.peek<
char>() ==
'}') {
148 auto childKey = parser::text::readStringToBuffer(stream, backing, parser::text::DEFAULT_STRING_START, parser::text::DEFAULT_STRING_END, escapeSequences);
149 elements.push_back(K{});
150 elements.back().key = childKey;
151 parser::text::eatWhitespaceAndSingleLineComments(stream);
154 if (stream.peek<
char>() !=
'{') {
155 elements.back().value = parser::text::readStringToBuffer(stream, backing, parser::text::DEFAULT_STRING_START, parser::text::DEFAULT_STRING_END, escapeSequences);
156 parser::text::eatWhitespaceAndSingleLineComments(stream);
159 if (stream.peek<
char>() ==
'[') {
160 elements.back().conditional = parser::text::readStringToBuffer(stream, backing,
"[",
"]", escapeSequences);
161 parser::text::eatWhitespaceAndSingleLineComments(stream);
164 if (stream.peek<
char>() ==
'{') {
166 parser::text::eatWhitespaceAndSingleLineComments(stream);
167 if (stream.peek<
char>() !=
'}') {
191 explicit KV1(std::string_view kv1Data,
bool useEscapeSequences_ =
false);
199 bool useEscapeSequences;
202template<
typename S = std::
string>
203requires std::convertible_to<S, std::string_view>
209 void setKey(std::string_view key_) {
214 template<KV1ValueType V>
216 if constexpr (std::convertible_to<V, std::string_view>) {
217 this->value = std::string_view{value_};
219 this->setValue(std::to_string(value_));
224 template<KV1ValueType V>
226 this->setValue(value_);
232 this->conditional = conditional_;
235 template<KV1ValueType V = std::
string_view>
241 this->children.push_back(elem);
242 return this->children.back();
247 return this->children.at(n);
252 return this->operator()(childKey);
257 for (
auto& element : this->children) {
262 return this->addChild(childKey);
267 unsigned int count = 0;
268 for (
auto& element: this->children) {
276 return this->addChild(childKey);
281 unsigned int count = 0;
282 for (
auto element = this->children.begin(); element != this->children.end(); ++element) {
284 if (n < 0 || count == n) {
285 element = this->children.erase(element);
300 constexpr auto writeIndentation = [](BufferStream& stream_,
unsigned short indentLevel_) {
301 for (
unsigned short i = 0; i < indentLevel_; i++) {
305 constexpr auto writeQuotedString = [](BufferStream& stream_, std::string_view str,
const parser::text::EscapeSequenceMap& escapeSequences_,
char quoteStart =
'\"',
char quoteEnd =
'\"') {
306 stream_.write(quoteStart);
308 stream_.write(parser::text::convertSpecialCharsToEscapes(str, escapeSequences_),
false);
310 stream_.write(quoteEnd);
313 for (
auto& elem : elements) {
314 writeIndentation(stream, indentLevel);
315 writeQuotedString(stream, elem.
key, escapeSequences);
318 writeQuotedString(stream, elem.
value, escapeSequences);
322 writeQuotedString(stream, elem.
conditional, escapeSequences,
'[',
']');
326 writeIndentation(stream, indentLevel);
327 stream <<
'{' <<
'\n';
328 write(stream, elem.
children, indentLevel + 1, escapeSequences);
329 writeIndentation(stream, indentLevel);
330 stream <<
'}' <<
'\n';
336template<
typename S = std::
string>
337requires std::convertible_to<S, std::string_view>
340 explicit KV1Writer(std::string_view kv1Data =
"",
bool useEscapeSequences_ =
false)
342 , useEscapeSequences(useEscapeSequences_) {
343 if (kv1Data.empty()) {
346 BufferStreamReadOnly stream{kv1Data.data(), kv1Data.size()};
350 std::string backingData(kv1Data.size() * 2,
'\0');
351 BufferStream backing{backingData,
false};
354 }
catch (
const std::overflow_error&) {}
357 [[nodiscard]] std::string
bake() {
359 BufferStream stream{buffer};
361 buffer.resize(stream.size());
365 void bake(
const std::string& kv1Path) {
std::string_view getKey() const
Get the key associated with the element.
uint64_t getChildCount() const
Get the number of child elements.
static const KV1ElementBase & getInvalid()
static void read(BufferStreamReadOnly &stream, BufferStream &backing, std::vector< K > &elements, const sourcepp::parser::text::EscapeSequenceMap &escapeSequences)
std::string_view getConditional() const
Get the conditional associated with the element.
V getValue() const
Get the value associated with the element as the given type.
bool isInvalid() const
Check if the given element is invalid.
const KV1ElementBase & operator[](std::string_view childKey) const
Get the first child element of the element with the given key.
std::string_view getValue() const
Get the value associated with the element.
const std::vector< K > & getChildren() const
Get the child elements of the element.
uint64_t getChildCount(std::string_view childKey) const
Get the number of child elements with the given key.
const KV1ElementBase & operator()(std::string_view childKey) const
Get the first child element of the element with the given key.
const KV1ElementBase & operator[](unsigned int n) const
Get the child element of the element at the given index.
const KV1ElementBase & operator()(std::string_view childKey, unsigned int n) const
Get the nth child element of the element with the given key.
std::vector< K > children
bool hasChild(std::string_view childKey) const
Check if the element has one or more children with the given name.
void setKey(std::string_view key_)
Set the key associated with the element.
void removeChild(std::string_view childKey, int n=-1)
Remove a child element from the element. -1 means all children with the given key.
KV1ElementWritable()=default
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...
KV1ElementWritable & addChild(std::string_view key_, V value_={}, std::string_view conditional_="")
void setValue(V value_)
Set the value associated with the element.
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 ...
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 ...
static void write(BufferStream &stream, std::vector< KV1ElementWritable > &elements, unsigned short indentLevel, const sourcepp::parser::text::EscapeSequenceMap &escapeSequences)
void bake(const std::string &kv1Path)
KV1Writer(std::string_view kv1Data="", bool useEscapeSequences_=false)
bool writeFileText(const std::string &filepath, const std::string &text)
const EscapeSequenceMap NO_ESCAPE_SEQUENCES
std::unordered_map< char, char > EscapeSequenceMap
const EscapeSequenceMap DEFAULT_ESCAPE_SEQUENCES
bool isNumber(char c)
If a char is a numerical character (0-9).
bool iequals(std::string_view s1, std::string_view s2)