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 {
90 using iterator =
typename std::vector<K>::iterator;
130 for (
const auto& element : this->
children) {
140 unsigned int count = 0;
141 for (
const auto& element : this->
children) {
169 parser::text::eatWhitespaceAndSingleLineComments(stream);
170 if (stream.peek<
char>() ==
'}') {
176 auto childKey = parser::text::readStringToBuffer(stream, backing, parser::text::DEFAULT_STRING_START, parser::text::DEFAULT_STRING_END, escapeSequences);
177 elements.push_back(K{});
178 elements.back().key = childKey;
179 parser::text::eatWhitespaceAndSingleLineComments(stream);
182 if (stream.peek<
char>() !=
'{') {
183 elements.back().value = parser::text::readStringToBuffer(stream, backing, parser::text::DEFAULT_STRING_START, parser::text::DEFAULT_STRING_END, escapeSequences);
184 parser::text::eatWhitespaceAndSingleLineComments(stream);
187 if (stream.peek<
char>() ==
'[') {
188 elements.back().conditional = parser::text::readStringToBuffer(stream, backing,
"[",
"]", escapeSequences);
189 parser::text::eatWhitespaceAndSingleLineComments(stream);
192 if (stream.peek<
char>() ==
'{') {
194 parser::text::eatWhitespaceAndSingleLineComments(stream);
195 if (stream.peek<
char>() !=
'}') {
210template<
typename S = std::
string_view>
211requires std::convertible_to<S, std::string_view>
219template<
typename S = std::
string_view>
220requires std::convertible_to<S, std::string_view>
223 explicit KV1(std::string_view kv1Data,
bool useEscapeSequences_ =
false)
226 if (kv1Data.empty()) {
229 BufferStreamReadOnly stream{kv1Data.data(), kv1Data.size()};
236 }
catch (
const std::overflow_error&) {}
248template<
typename S = std::
string>
249requires std::convertible_to<S, std::string_view>
260 template<KV1ValueType V>
262 if constexpr (std::convertible_to<V, std::string_view>) {
263 this->
value = std::string_view{value_};
265 this->
setValue(std::to_string(value_));
270 template<KV1ValueType V>
281 template<KV1ValueType V = std::
string_view>
303 for (
auto& element : this->
children) {
313 unsigned int count = 0;
314 for (
auto& element: this->
children) {
334 unsigned int count = 0;
335 for (
auto element = this->
children.begin(); element != this->children.end(); ++element) {
337 if (n < 0 || count == n) {
338 element = this->
children.erase(element);
353 constexpr auto writeIndentation = [](BufferStream& stream_,
unsigned short indentLevel_) {
354 for (
unsigned short i = 0; i < indentLevel_; i++) {
358 constexpr auto writeQuotedString = [](BufferStream& stream_, std::string_view str,
const parser::text::EscapeSequenceMap& escapeSequences_,
char quoteStart =
'\"',
char quoteEnd =
'\"') {
359 stream_.write(quoteStart);
361 stream_.write(parser::text::convertSpecialCharsToEscapes(str, escapeSequences_),
false);
363 stream_.write(quoteEnd);
366 for (
auto& elem : elements) {
367 writeIndentation(stream, indentLevel);
368 writeQuotedString(stream, elem.
key, escapeSequences);
371 writeQuotedString(stream, elem.
value, escapeSequences);
375 writeQuotedString(stream, elem.
conditional, escapeSequences,
'[',
']');
379 writeIndentation(stream, indentLevel);
380 stream <<
'{' <<
'\n';
381 write(stream, elem.
children, indentLevel + 1, escapeSequences);
382 writeIndentation(stream, indentLevel);
383 stream <<
'}' <<
'\n';
389template<
typename S = std::
string>
390requires std::convertible_to<S, std::string_view>
393 explicit KV1Writer(std::string_view kv1Data =
"",
bool useEscapeSequences_ =
false)
396 if (kv1Data.empty()) {
399 BufferStreamReadOnly stream{kv1Data.data(), kv1Data.size()};
403 std::string backingData(kv1Data.size() * 2,
'\0');
404 BufferStream backing{backingData,
false};
407 }
catch (
const std::overflow_error&) {}
410 [[nodiscard]] std::string
bake()
const {
412 BufferStream stream{buffer};
414 buffer.resize(stream.size());
418 void bake(
const std::string& kv1Path)
const {
423 using KV1ElementWritable<S>
::getKey;
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()
typename std::vector< K >::iterator iterator
static void read(BufferStreamReadOnly &stream, BufferStream &backing, std::vector< K > &elements, const sourcepp::parser::text::EscapeSequenceMap &escapeSequences)
constexpr const_iterator end() const
constexpr const_iterator begin() const
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.
constexpr const_iterator cend() const
bool isInvalid() const
Check if the given element is invalid.
constexpr iterator begin()
const KV1ElementBase & operator[](std::string_view childKey) const
Get the first child element of the element with the given key.
constexpr const_iterator cbegin() const
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.
typename std::vector< K >::const_iterator const_iterator
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.
KV1ElementReadable()=default
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
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)
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 ...
void bake(const std::string &kv1Path) const
KV1Writer(std::string_view kv1Data="", bool useEscapeSequences_=false)
KV1(std::string_view kv1Data, bool useEscapeSequences_=false)
bool writeFileText(const std::string &filepath, const std::string &text)
std::unordered_map< char, char > EscapeSequenceMap
const EscapeSequenceMap & getDefaultEscapeSequencesOrNone(bool useEscapes)
bool isNumber(char c)
If a char is a numerical character (0-9).
bool iequals(std::string_view s1, std::string_view s2)