summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--dev/BuildKit/IManifestBuilder.h6
-rw-r--r--dev/BuildKit/Imports.h4
-rw-r--r--dev/BuildKit/JSONManifestBuilder.h4
-rw-r--r--dev/BuildKit/TOMLManifestBuilder.h4
-rw-r--r--dev/cli/Tool.cc4
-rw-r--r--dev/src/JSONManifestBuilder.cc15
-rw-r--r--examples/example_02_libnebuild/libnebuild.cc2
-rw-r--r--vendor/toml++/impl/array.inl617
-rw-r--r--vendor/toml++/impl/at_path.inl472
-rw-r--r--vendor/toml++/impl/formatter.inl970
-rw-r--r--vendor/toml++/impl/json_formatter.inl187
-rw-r--r--vendor/toml++/impl/node.inl218
-rw-r--r--vendor/toml++/impl/parser.inl6938
-rw-r--r--vendor/toml++/impl/path.inl822
-rw-r--r--vendor/toml++/impl/print_to_stream.inl791
-rw-r--r--vendor/toml++/impl/std_string.inl116
-rw-r--r--vendor/toml++/impl/table.inl498
-rw-r--r--vendor/toml++/impl/toml_formatter.inl731
-rw-r--r--vendor/toml++/impl/unicode.inl70
-rw-r--r--vendor/toml++/impl/yaml_formatter.inl299
20 files changed, 5980 insertions, 6788 deletions
diff --git a/dev/BuildKit/IManifestBuilder.h b/dev/BuildKit/IManifestBuilder.h
index 1dd8bce..c1d45d0 100644
--- a/dev/BuildKit/IManifestBuilder.h
+++ b/dev/BuildKit/IManifestBuilder.h
@@ -14,7 +14,7 @@ namespace NeBuild {
/// @note This class is meant to be used as an interface.
class IManifestBuilder {
public:
- IManifestBuilder() = default;
+ IManifestBuilder() = default;
virtual ~IManifestBuilder() = default;
IManifestBuilder& operator=(const IManifestBuilder&) = default;
@@ -25,7 +25,7 @@ class IManifestBuilder {
/// @param arg_val filename path.
/// @retval true succeeded.
/// @retval false failed.
- virtual bool BuildTarget(const std::string& arg, const bool dry_run = false) = 0;
- virtual const char* BuildSystem() = 0;
+ virtual bool BuildTarget(const std::string& arg, const bool dry_run = false) = 0;
+ virtual const char* BuildSystem() = 0;
};
} // namespace NeBuild \ No newline at end of file
diff --git a/dev/BuildKit/Imports.h b/dev/BuildKit/Imports.h
index 9260c1e..c542737 100644
--- a/dev/BuildKit/Imports.h
+++ b/dev/BuildKit/Imports.h
@@ -6,6 +6,8 @@
#ifndef NEBUILD_INCLUDES_H
#define NEBUILD_INCLUDES_H
+#include <rang/rang.h>
+#include <cassert>
#include <cstddef>
#include <cstdio>
#include <fstream>
@@ -13,7 +15,5 @@
#include <sstream>
#include <string>
#include <thread>
-#include <cassert>
-#include <rang/rang.h>
#endif // NEBUILD_INCLUDES_H
diff --git a/dev/BuildKit/JSONManifestBuilder.h b/dev/BuildKit/JSONManifestBuilder.h
index b853ccf..63a67b7 100644
--- a/dev/BuildKit/JSONManifestBuilder.h
+++ b/dev/BuildKit/JSONManifestBuilder.h
@@ -15,7 +15,7 @@ namespace NeBuild {
/// @brief JSON builder
class JSONManifestBuilder final NEBUILD_MANIFEST_BUILDER {
public:
- JSONManifestBuilder() = default;
+ JSONManifestBuilder() = default;
~JSONManifestBuilder() override = default;
JSONManifestBuilder& operator=(const JSONManifestBuilder&) = default;
@@ -27,7 +27,7 @@ class JSONManifestBuilder final NEBUILD_MANIFEST_BUILDER {
/// @param arg_val filename path.
/// @retval true build succeeded.
/// @retval false failed to build.
- bool BuildTarget(const std::string& arg_val, const bool dry_run = false) override;
+ bool BuildTarget(const std::string& arg_val, const bool dry_run = false) override;
const char* BuildSystem() override;
};
} // namespace NeBuild \ No newline at end of file
diff --git a/dev/BuildKit/TOMLManifestBuilder.h b/dev/BuildKit/TOMLManifestBuilder.h
index e300ba6..10a8200 100644
--- a/dev/BuildKit/TOMLManifestBuilder.h
+++ b/dev/BuildKit/TOMLManifestBuilder.h
@@ -15,7 +15,7 @@ namespace NeBuild {
/// @brief TOML builder
class TOMLManifestBuilder final NEBUILD_MANIFEST_BUILDER {
public:
- TOMLManifestBuilder() = default;
+ TOMLManifestBuilder() = default;
~TOMLManifestBuilder() override = default;
TOMLManifestBuilder& operator=(const TOMLManifestBuilder&) = default;
@@ -27,7 +27,7 @@ class TOMLManifestBuilder final NEBUILD_MANIFEST_BUILDER {
/// @param arg_val filename path.
/// @retval true build succeeded.
/// @retval false failed to build.
- bool BuildTarget(int arg_sz, const char* arg_val, const bool dry_run = false) override;
+ bool BuildTarget(int arg_sz, const char* arg_val, const bool dry_run = false) override;
const char* BuildSystem() override;
};
} // namespace NeBuild \ No newline at end of file
diff --git a/dev/cli/Tool.cc b/dev/cli/Tool.cc
index 315f197..1d49c9f 100644
--- a/dev/cli/Tool.cc
+++ b/dev/cli/Tool.cc
@@ -52,8 +52,8 @@ int main(int argc, char** argv) {
return;
}
} else {
- NeBuild::Logger::info() << "error: file '" << index_path << "' is not a JSON file!"
- << std::endl;
+ NeBuild::Logger::info()
+ << "error: file '" << index_path << "' is not a JSON file!" << std::endl;
kFailed = true;
return;
}
diff --git a/dev/src/JSONManifestBuilder.cc b/dev/src/JSONManifestBuilder.cc
index 3b03bf8..33d7f62 100644
--- a/dev/src/JSONManifestBuilder.cc
+++ b/dev/src/JSONManifestBuilder.cc
@@ -5,7 +5,7 @@
#include <BuildKit/JSONManifestBuilder.h>
-using JSON = nlohmann::json;
+using JSON = nlohmann::json;
namespace FS = std::filesystem;
@@ -26,7 +26,8 @@ bool JSONManifestBuilder::BuildTarget(const std::string& argv_val, const bool dr
path = argv_val;
if (!FS::exists(path)) {
- NeBuild::Logger::info() << "nebuild: error: file '" << path << "' does not exist" << std::endl;
+ NeBuild::Logger::info() << "nebuild: error: file '" << path << "' does not exist"
+ << std::endl;
return false;
}
}
@@ -35,7 +36,8 @@ bool JSONManifestBuilder::BuildTarget(const std::string& argv_val, const bool dr
std::ifstream json(path);
if (!json.good()) {
- NeBuild::Logger::info() << "nebuild: error: file '" << path << "' is not a valid JSON" << std::endl;
+ NeBuild::Logger::info() << "nebuild: error: file '" << path << "' is not a valid JSON"
+ << std::endl;
return false;
}
@@ -90,15 +92,16 @@ bool JSONManifestBuilder::BuildTarget(const std::string& argv_val, const bool dr
auto ret_exec = std::system(command.c_str());
if (ret_exec > 0) {
- NeBuild::Logger::info() << "error: exit with message: " << std::strerror(ret_exec) << "" << std::endl;
+ NeBuild::Logger::info() << "error: exit with message: " << std::strerror(ret_exec) << ""
+ << std::endl;
return false;
}
try {
if (json_obj["run_after_build"].get<bool>()) {
if (target.ends_with(".so")) {
- NeBuild::Logger::info() << "error: can't open dynamic library, it mayn't have an entrypoint"
- << std::endl;
+ NeBuild::Logger::info()
+ << "error: can't open dynamic library, it mayn't have an entrypoint" << std::endl;
return true;
} else if (target.ends_with(".dylib") || target.ends_with(".dll")) {
diff --git a/examples/example_02_libnebuild/libnebuild.cc b/examples/example_02_libnebuild/libnebuild.cc
index 74cbe18..5540503 100644
--- a/examples/example_02_libnebuild/libnebuild.cc
+++ b/examples/example_02_libnebuild/libnebuild.cc
@@ -10,6 +10,6 @@ static auto kPath = ".\\win64.json";
int main(int argc, char** argv) {
auto builder = new NeBuild::JSONManifestBuilder();
if (!builder) return EXIT_FAILURE;
-
+
return builder->BuildTarget(kPath);
}
diff --git a/vendor/toml++/impl/array.inl b/vendor/toml++/impl/array.inl
index a3c6243..7ae8ee1 100644
--- a/vendor/toml++/impl/array.inl
+++ b/vendor/toml++/impl/array.inl
@@ -1,381 +1,306 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
-//# {{
+// # {{
#include "preprocessor.hpp"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
#include "array.hpp"
#include "header_start.hpp"
-TOML_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- array::array() noexcept
- {
+TOML_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ array::array() noexcept {
#if TOML_LIFETIME_HOOKS
- TOML_ARRAY_CREATED;
+ TOML_ARRAY_CREATED;
#endif
- }
+ }
- TOML_EXTERNAL_LINKAGE
- array::~array() noexcept
- {
+ TOML_EXTERNAL_LINKAGE
+ array::~array() noexcept {
#if TOML_LIFETIME_HOOKS
- TOML_ARRAY_DESTROYED;
+ TOML_ARRAY_DESTROYED;
#endif
- }
+ }
- TOML_EXTERNAL_LINKAGE
- array::array(const impl::array_init_elem* b, const impl::array_init_elem* e)
- {
+ TOML_EXTERNAL_LINKAGE
+ array::array(const impl::array_init_elem* b, const impl::array_init_elem* e) {
#if TOML_LIFETIME_HOOKS
- TOML_ARRAY_CREATED;
+ TOML_ARRAY_CREATED;
#endif
- TOML_ASSERT_ASSUME(b);
- TOML_ASSERT_ASSUME(e);
- TOML_ASSERT_ASSUME(b <= e);
-
- if TOML_UNLIKELY(b == e)
- return;
-
- size_t cap{};
- for (auto it = b; it != e; it++)
- {
- if (it->value)
- cap++;
- }
- if TOML_UNLIKELY(!cap)
- return;
-
- elems_.reserve(cap);
- for (; b != e; b++)
- {
- if (b->value)
- elems_.push_back(std::move(b->value));
- }
- }
-
- TOML_EXTERNAL_LINKAGE
- array::array(const array& other) //
- : node(other)
- {
- elems_.reserve(other.elems_.size());
- for (const auto& elem : other)
- elems_.emplace_back(impl::make_node(elem));
+ TOML_ASSERT_ASSUME(b);
+ TOML_ASSERT_ASSUME(e);
+ TOML_ASSERT_ASSUME(b <= e);
+
+ if TOML_UNLIKELY (b == e) return;
+
+ size_t cap{};
+ for (auto it = b; it != e; it++) {
+ if (it->value) cap++;
+ }
+ if TOML_UNLIKELY (!cap) return;
+
+ elems_.reserve(cap);
+ for (; b != e; b++) {
+ if (b->value) elems_.push_back(std::move(b->value));
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array::array(const array& other) //
+ : node(other) {
+ elems_.reserve(other.elems_.size());
+ for (const auto& elem : other) elems_.emplace_back(impl::make_node(elem));
#if TOML_LIFETIME_HOOKS
- TOML_ARRAY_CREATED;
+ TOML_ARRAY_CREATED;
#endif
- }
+ }
- TOML_EXTERNAL_LINKAGE
- array::array(array && other) noexcept //
- : node(std::move(other)),
- elems_(std::move(other.elems_))
- {
+ TOML_EXTERNAL_LINKAGE
+ array::array(array && other) noexcept //
+ : node(std::move(other)), elems_(std::move(other.elems_)) {
#if TOML_LIFETIME_HOOKS
- TOML_ARRAY_CREATED;
+ TOML_ARRAY_CREATED;
#endif
- }
-
- TOML_EXTERNAL_LINKAGE
- array& array::operator=(const array& rhs)
- {
- if (&rhs != this)
- {
- node::operator=(rhs);
- elems_.clear();
- elems_.reserve(rhs.elems_.size());
- for (const auto& elem : rhs)
- elems_.emplace_back(impl::make_node(elem));
- }
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- array& array::operator=(array&& rhs) noexcept
- {
- if (&rhs != this)
- {
- node::operator=(std::move(rhs));
- elems_ = std::move(rhs.elems_);
- }
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- void array::preinsertion_resize(size_t idx, size_t count)
- {
- TOML_ASSERT(idx <= elems_.size());
- TOML_ASSERT_ASSUME(count >= 1u);
- const auto old_size = elems_.size();
- const auto new_size = old_size + count;
- const auto inserting_at_end = idx == old_size;
- elems_.resize(new_size);
- if (!inserting_at_end)
- {
- for (size_t left = old_size, right = new_size - 1u; left-- > idx; right--)
- elems_[right] = std::move(elems_[left]);
- }
- }
-
- TOML_EXTERNAL_LINKAGE
- void array::insert_at_back(impl::node_ptr && elem)
- {
- TOML_ASSERT(elem);
- elems_.push_back(std::move(elem));
- }
-
- TOML_EXTERNAL_LINKAGE
- array::vector_iterator array::insert_at(const_vector_iterator pos, impl::node_ptr && elem)
- {
- return elems_.insert(pos, std::move(elem));
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- bool array::is_homogeneous(node_type ntype) const noexcept
- {
- if (elems_.empty())
- return false;
-
- if (ntype == node_type::none)
- ntype = elems_[0]->type();
-
- for (const auto& val : elems_)
- if (val->type() != ntype)
- return false;
-
- return true;
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- bool array::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
- {
- if (elems_.empty())
- {
- first_nonmatch = {};
- return false;
- }
- if (ntype == node_type::none)
- ntype = elems_[0]->type();
- for (const auto& val : elems_)
- {
- if (val->type() != ntype)
- {
- first_nonmatch = val.get();
- return false;
- }
- }
- return true;
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- bool array::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept
- {
- node* fnm = nullptr;
- const auto result = const_cast<array&>(*this).is_homogeneous(ntype, fnm);
- first_nonmatch = fnm;
- return result;
- }
-
- TOML_EXTERNAL_LINKAGE
- node& array::at(size_t index)
- {
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array& array::operator=(const array& rhs) {
+ if (&rhs != this) {
+ node::operator=(rhs);
+ elems_.clear();
+ elems_.reserve(rhs.elems_.size());
+ for (const auto& elem : rhs) elems_.emplace_back(impl::make_node(elem));
+ }
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array& array::operator=(array&& rhs) noexcept {
+ if (&rhs != this) {
+ node::operator=(std::move(rhs));
+ elems_ = std::move(rhs.elems_);
+ }
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::preinsertion_resize(size_t idx, size_t count) {
+ TOML_ASSERT(idx <= elems_.size());
+ TOML_ASSERT_ASSUME(count >= 1u);
+ const auto old_size = elems_.size();
+ const auto new_size = old_size + count;
+ const auto inserting_at_end = idx == old_size;
+ elems_.resize(new_size);
+ if (!inserting_at_end) {
+ for (size_t left = old_size, right = new_size - 1u; left-- > idx; right--)
+ elems_[right] = std::move(elems_[left]);
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::insert_at_back(impl::node_ptr && elem) {
+ TOML_ASSERT(elem);
+ elems_.push_back(std::move(elem));
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array::vector_iterator array::insert_at(const_vector_iterator pos, impl::node_ptr && elem) {
+ return elems_.insert(pos, std::move(elem));
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ bool array::is_homogeneous(node_type ntype) const noexcept {
+ if (elems_.empty()) return false;
+
+ if (ntype == node_type::none) ntype = elems_[0]->type();
+
+ for (const auto& val : elems_)
+ if (val->type() != ntype) return false;
+
+ return true;
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ bool array::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept {
+ if (elems_.empty()) {
+ first_nonmatch = {};
+ return false;
+ }
+ if (ntype == node_type::none) ntype = elems_[0]->type();
+ for (const auto& val : elems_) {
+ if (val->type() != ntype) {
+ first_nonmatch = val.get();
+ return false;
+ }
+ }
+ return true;
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ bool array::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept {
+ node* fnm = nullptr;
+ const auto result = const_cast<array&>(*this).is_homogeneous(ntype, fnm);
+ first_nonmatch = fnm;
+ return result;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node& array::at(size_t index) {
#if TOML_COMPILER_HAS_EXCEPTIONS
- return *elems_.at(index);
+ return *elems_.at(index);
#else
- auto n = get(index);
- TOML_ASSERT_ASSUME(n && "element index not found in array!");
- return *n;
+ auto n = get(index);
+ TOML_ASSERT_ASSUME(n && "element index not found in array!");
+ return *n;
#endif
- }
-
- TOML_EXTERNAL_LINKAGE
- void array::reserve(size_t new_capacity)
- {
- elems_.reserve(new_capacity);
- }
-
- TOML_EXTERNAL_LINKAGE
- void array::shrink_to_fit()
- {
- elems_.shrink_to_fit();
- }
-
- TOML_EXTERNAL_LINKAGE
- void array::truncate(size_t new_size)
- {
- if (new_size < elems_.size())
- elems_.resize(new_size);
- }
-
- TOML_EXTERNAL_LINKAGE
- array::iterator array::erase(const_iterator pos) noexcept
- {
- return iterator{ elems_.erase(const_vector_iterator{ pos }) };
- }
-
- TOML_EXTERNAL_LINKAGE
- array::iterator array::erase(const_iterator first, const_iterator last) noexcept
- {
- return iterator{ elems_.erase(const_vector_iterator{ first }, const_vector_iterator{ last }) };
- }
-
- TOML_EXTERNAL_LINKAGE
- size_t array::total_leaf_count() const noexcept
- {
- size_t leaves{};
- for (size_t i = 0, e = elems_.size(); i < e; i++)
- {
- auto arr = elems_[i]->as_array();
- leaves += arr ? arr->total_leaf_count() : size_t{ 1 };
- }
- return leaves;
- }
-
- TOML_EXTERNAL_LINKAGE
- void array::flatten_child(array && child, size_t & dest_index) noexcept
- {
- for (size_t i = 0, e = child.size(); i < e; i++)
- {
- auto type = child.elems_[i]->type();
- if (type == node_type::array)
- {
- array& arr = *reinterpret_cast<array*>(child.elems_[i].get());
- if (!arr.empty())
- flatten_child(std::move(arr), dest_index);
- }
- else
- elems_[dest_index++] = std::move(child.elems_[i]);
- }
- }
-
- TOML_EXTERNAL_LINKAGE
- array& array::flatten()&
- {
- if (elems_.empty())
- return *this;
-
- bool requires_flattening = false;
- size_t size_after_flattening = elems_.size();
- for (size_t i = elems_.size(); i-- > 0u;)
- {
- auto arr = elems_[i]->as_array();
- if (!arr)
- continue;
- size_after_flattening--; // discount the array itself
- const auto leaf_count = arr->total_leaf_count();
- if (leaf_count > 0u)
- {
- requires_flattening = true;
- size_after_flattening += leaf_count;
- }
- else
- elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
- }
-
- if (!requires_flattening)
- return *this;
-
- elems_.reserve(size_after_flattening);
-
- size_t i = 0;
- while (i < elems_.size())
- {
- auto arr = elems_[i]->as_array();
- if (!arr)
- {
- i++;
- continue;
- }
-
- impl::node_ptr arr_storage = std::move(elems_[i]);
- const auto leaf_count = arr->total_leaf_count();
- if (leaf_count > 1u)
- preinsertion_resize(i + 1u, leaf_count - 1u);
- flatten_child(std::move(*arr), i); // increments i
- }
-
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- array& array::prune(bool recursive)& noexcept
- {
- if (elems_.empty())
- return *this;
-
- for (size_t i = elems_.size(); i-- > 0u;)
- {
- if (auto arr = elems_[i]->as_array())
- {
- if (recursive)
- arr->prune(true);
- if (arr->empty())
- elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
- }
- else if (auto tbl = elems_[i]->as_table())
- {
- if (recursive)
- tbl->prune(true);
- if (tbl->empty())
- elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
- }
- }
-
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- void array::pop_back() noexcept
- {
- elems_.pop_back();
- }
-
- TOML_EXTERNAL_LINKAGE
- void array::clear() noexcept
- {
- elems_.clear();
- }
-
- TOML_EXTERNAL_LINKAGE
- bool TOML_CALLCONV array::equal(const array& lhs, const array& rhs) noexcept
- {
- if (&lhs == &rhs)
- return true;
- if (lhs.elems_.size() != rhs.elems_.size())
- return false;
- for (size_t i = 0, e = lhs.elems_.size(); i < e; i++)
- {
- const auto lhs_type = lhs.elems_[i]->type();
- const node& rhs_ = *rhs.elems_[i];
- const auto rhs_type = rhs_.type();
- if (lhs_type != rhs_type)
- return false;
-
- const bool equal = lhs.elems_[i]->visit(
- [&](const auto& lhs_) noexcept
- { return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
- if (!equal)
- return false;
- }
- return true;
- }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::reserve(size_t new_capacity) {
+ elems_.reserve(new_capacity);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::shrink_to_fit() {
+ elems_.shrink_to_fit();
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::truncate(size_t new_size) {
+ if (new_size < elems_.size()) elems_.resize(new_size);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array::iterator array::erase(const_iterator pos) noexcept {
+ return iterator{elems_.erase(const_vector_iterator{pos})};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array::iterator array::erase(const_iterator first, const_iterator last) noexcept {
+ return iterator{elems_.erase(const_vector_iterator{first}, const_vector_iterator{last})};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ size_t array::total_leaf_count() const noexcept {
+ size_t leaves{};
+ for (size_t i = 0, e = elems_.size(); i < e; i++) {
+ auto arr = elems_[i]->as_array();
+ leaves += arr ? arr->total_leaf_count() : size_t{1};
+ }
+ return leaves;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::flatten_child(array && child, size_t & dest_index) noexcept {
+ for (size_t i = 0, e = child.size(); i < e; i++) {
+ auto type = child.elems_[i]->type();
+ if (type == node_type::array) {
+ array& arr = *reinterpret_cast<array*>(child.elems_[i].get());
+ if (!arr.empty()) flatten_child(std::move(arr), dest_index);
+ } else
+ elems_[dest_index++] = std::move(child.elems_[i]);
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array& array::flatten()& {
+ if (elems_.empty()) return *this;
+
+ bool requires_flattening = false;
+ size_t size_after_flattening = elems_.size();
+ for (size_t i = elems_.size(); i-- > 0u;) {
+ auto arr = elems_[i]->as_array();
+ if (!arr) continue;
+ size_after_flattening--; // discount the array itself
+ const auto leaf_count = arr->total_leaf_count();
+ if (leaf_count > 0u) {
+ requires_flattening = true;
+ size_after_flattening += leaf_count;
+ } else
+ elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
+ }
+
+ if (!requires_flattening) return *this;
+
+ elems_.reserve(size_after_flattening);
+
+ size_t i = 0;
+ while (i < elems_.size()) {
+ auto arr = elems_[i]->as_array();
+ if (!arr) {
+ i++;
+ continue;
+ }
+
+ impl::node_ptr arr_storage = std::move(elems_[i]);
+ const auto leaf_count = arr->total_leaf_count();
+ if (leaf_count > 1u) preinsertion_resize(i + 1u, leaf_count - 1u);
+ flatten_child(std::move(*arr), i); // increments i
+ }
+
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ array& array::prune(bool recursive)& noexcept {
+ if (elems_.empty()) return *this;
+
+ for (size_t i = elems_.size(); i-- > 0u;) {
+ if (auto arr = elems_[i]->as_array()) {
+ if (recursive) arr->prune(true);
+ if (arr->empty()) elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
+ } else if (auto tbl = elems_[i]->as_table()) {
+ if (recursive) tbl->prune(true);
+ if (tbl->empty()) elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
+ }
+ }
+
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::pop_back() noexcept {
+ elems_.pop_back();
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void array::clear() noexcept {
+ elems_.clear();
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ bool TOML_CALLCONV array::equal(const array& lhs, const array& rhs) noexcept {
+ if (&lhs == &rhs) return true;
+ if (lhs.elems_.size() != rhs.elems_.size()) return false;
+ for (size_t i = 0, e = lhs.elems_.size(); i < e; i++) {
+ const auto lhs_type = lhs.elems_[i]->type();
+ const node& rhs_ = *rhs.elems_[i];
+ const auto rhs_type = rhs_.type();
+ if (lhs_type != rhs_type) return false;
+
+ const bool equal = lhs.elems_[i]->visit([&](const auto& lhs_) noexcept {
+ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_);
+ });
+ if (!equal) return false;
+ }
+ return true;
+ }
}
TOML_NAMESPACE_END;
diff --git a/vendor/toml++/impl/at_path.inl b/vendor/toml++/impl/at_path.inl
index 976c813..a90adea 100644
--- a/vendor/toml++/impl/at_path.inl
+++ b/vendor/toml++/impl/at_path.inl
@@ -1,18 +1,18 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
-//# {{
+// # {{
#include "preprocessor.hpp"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
-#include "at_path.hpp"
#include "array.hpp"
+#include "at_path.hpp"
#include "table.hpp"
TOML_DISABLE_WARNINGS;
#if TOML_INT_CHARCONV
@@ -23,267 +23,229 @@ TOML_DISABLE_WARNINGS;
TOML_ENABLE_WARNINGS;
#include "header_start.hpp"
-TOML_IMPL_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- bool TOML_CALLCONV parse_path(const std::string_view path,
- void* const data,
- const parse_path_callback<std::string_view> on_key,
- const parse_path_callback<size_t> on_index)
- {
- // a blank string is a valid path; it's just one component representing the "" key
- if (path.empty())
- return on_key(data, ""sv);
-
- size_t pos = 0;
- const auto end = path.length();
- bool prev_was_array_indexer = false;
- bool prev_was_dot = true; // invisible root 'dot'
-
- while (pos < end)
- {
- // start of an array indexer
- if (path[pos] == '[')
- {
- // find first digit in index
- size_t index_start = pos + 1u;
- while (true)
- {
- if TOML_UNLIKELY(index_start >= path.length())
- return false;
-
- const auto c = path[index_start];
- if TOML_LIKELY(c >= '0' && c <= '9')
- break;
- else if (c == ' ' || c == '\t')
- index_start++;
- else
- return false;
- }
- TOML_ASSERT(path[index_start] >= '0');
- TOML_ASSERT(path[index_start] <= '9');
-
- // find end of index (first non-digit character)
- size_t index_end = index_start + 1u;
- while (true)
- {
- // if an array indexer is missing the trailing ']' at the end of the string, permissively accept it
- if TOML_UNLIKELY(index_end >= path.length())
- break;
-
- const auto c = path[index_end];
- if (c >= '0' && c <= '9')
- index_end++;
- else if (c == ']' || c == ' ' || c == '\t' || c == '.' || c == '[')
- break;
- else
- return false;
- }
- TOML_ASSERT(path[index_end - 1u] >= '0');
- TOML_ASSERT(path[index_end - 1u] <= '9');
-
- // move pos to after indexer (char after closing ']' or permissively EOL/subkey '.'/next opening '[')
- pos = index_end;
- while (true)
- {
- if TOML_UNLIKELY(pos >= path.length())
- break;
-
- const auto c = path[pos];
- if (c == ']')
- {
- pos++;
- break;
- }
- else if TOML_UNLIKELY(c == '.' || c == '[')
- break;
- else if (c == '\t' || c == ' ')
- pos++;
- else
- return false;
- }
-
- // get array index substring
- auto index_str = path.substr(index_start, index_end - index_start);
-
- // parse the actual array index to an integer type
- size_t index;
- if (index_str.length() == 1u)
- index = static_cast<size_t>(index_str[0] - '0');
- else
- {
+TOML_IMPL_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ bool TOML_CALLCONV parse_path(const std::string_view path, void* const data,
+ const parse_path_callback<std::string_view> on_key,
+ const parse_path_callback<size_t> on_index) {
+ // a blank string is a valid path; it's just one component representing the "" key
+ if (path.empty()) return on_key(data, ""sv);
+
+ size_t pos = 0;
+ const auto end = path.length();
+ bool prev_was_array_indexer = false;
+ bool prev_was_dot = true; // invisible root 'dot'
+
+ while (pos < end) {
+ // start of an array indexer
+ if (path[pos] == '[') {
+ // find first digit in index
+ size_t index_start = pos + 1u;
+ while (true) {
+ if TOML_UNLIKELY (index_start >= path.length()) return false;
+
+ const auto c = path[index_start];
+ if TOML_LIKELY (c >= '0' && c <= '9')
+ break;
+ else if (c == ' ' || c == '\t')
+ index_start++;
+ else
+ return false;
+ }
+ TOML_ASSERT(path[index_start] >= '0');
+ TOML_ASSERT(path[index_start] <= '9');
+
+ // find end of index (first non-digit character)
+ size_t index_end = index_start + 1u;
+ while (true) {
+ // if an array indexer is missing the trailing ']' at the end of the string, permissively
+ // accept it
+ if TOML_UNLIKELY (index_end >= path.length()) break;
+
+ const auto c = path[index_end];
+ if (c >= '0' && c <= '9')
+ index_end++;
+ else if (c == ']' || c == ' ' || c == '\t' || c == '.' || c == '[')
+ break;
+ else
+ return false;
+ }
+ TOML_ASSERT(path[index_end - 1u] >= '0');
+ TOML_ASSERT(path[index_end - 1u] <= '9');
+
+ // move pos to after indexer (char after closing ']' or permissively EOL/subkey '.'/next
+ // opening '[')
+ pos = index_end;
+ while (true) {
+ if TOML_UNLIKELY (pos >= path.length()) break;
+
+ const auto c = path[pos];
+ if (c == ']') {
+ pos++;
+ break;
+ } else if TOML_UNLIKELY (c == '.' || c == '[')
+ break;
+ else if (c == '\t' || c == ' ')
+ pos++;
+ else
+ return false;
+ }
+
+ // get array index substring
+ auto index_str = path.substr(index_start, index_end - index_start);
+
+ // parse the actual array index to an integer type
+ size_t index;
+ if (index_str.length() == 1u)
+ index = static_cast<size_t>(index_str[0] - '0');
+ else {
#if TOML_INT_CHARCONV
- auto fc_result = std::from_chars(index_str.data(), index_str.data() + index_str.length(), index);
- if (fc_result.ec != std::errc{})
- return false;
+ auto fc_result =
+ std::from_chars(index_str.data(), index_str.data() + index_str.length(), index);
+ if (fc_result.ec != std::errc{}) return false;
#else
- std::stringstream ss;
- ss.imbue(std::locale::classic());
- ss.write(index_str.data(), static_cast<std::streamsize>(index_str.length()));
- if (!(ss >> index))
- return false;
+ std::stringstream ss;
+ ss.imbue(std::locale::classic());
+ ss.write(index_str.data(), static_cast<std::streamsize>(index_str.length()));
+ if (!(ss >> index)) return false;
#endif
- }
-
- prev_was_dot = false;
- prev_was_array_indexer = true;
-
- if (!on_index(data, index))
- return false;
- }
-
- // start of a new table child
- else if (path[pos] == '.')
- {
- // a dot immediately following another dot (or at the beginning of the string) is as if we'd asked
- // for an empty child in between, e.g.
- //
- // foo..bar
- //
- // is equivalent to
- //
- // "foo".""."bar"
- //
- if (prev_was_dot && !on_key(data, ""sv))
- return false;
-
- pos++;
- prev_was_dot = true;
- prev_was_array_indexer = false;
- }
-
- // an errant closing ']'
- else if TOML_UNLIKELY(path[pos] == ']')
- return false;
-
- // some regular subkey
- else
- {
- const auto subkey_start = pos;
- const auto subkey_len =
- impl::min(path.find_first_of(".[]"sv, subkey_start + 1u), path.length()) - subkey_start;
- const auto subkey = path.substr(subkey_start, subkey_len);
-
- // a regular subkey segment immediately after an array indexer is OK if it was all whitespace, e.g.:
- //
- // "foo[0] .bar"
- // ^^ skip this
- //
- // otherwise its an error (since it would have to be preceeded by a dot)
- if (prev_was_array_indexer)
- {
- auto non_ws = subkey.find_first_not_of(" \t");
- if (non_ws == std::string_view::npos)
- {
- pos += subkey_len;
- prev_was_dot = false;
- prev_was_array_indexer = false;
- continue;
- }
- else
- return false;
- }
-
- pos += subkey_len;
- prev_was_dot = false;
- prev_was_array_indexer = false;
-
- if (!on_key(data, subkey))
- return false;
- }
- }
-
- // Last character was a '.', which implies an empty string key at the end of the path
- if (prev_was_dot && !on_key(data, ""sv))
- return false;
-
- return true;
- }
+ }
+
+ prev_was_dot = false;
+ prev_was_array_indexer = true;
+
+ if (!on_index(data, index)) return false;
+ }
+
+ // start of a new table child
+ else if (path[pos] == '.') {
+ // a dot immediately following another dot (or at the beginning of the string) is as if we'd
+ // asked for an empty child in between, e.g.
+ //
+ // foo..bar
+ //
+ // is equivalent to
+ //
+ // "foo".""."bar"
+ //
+ if (prev_was_dot && !on_key(data, ""sv)) return false;
+
+ pos++;
+ prev_was_dot = true;
+ prev_was_array_indexer = false;
+ }
+
+ // an errant closing ']'
+ else if TOML_UNLIKELY (path[pos] == ']')
+ return false;
+
+ // some regular subkey
+ else {
+ const auto subkey_start = pos;
+ const auto subkey_len =
+ impl::min(path.find_first_of(".[]"sv, subkey_start + 1u), path.length()) - subkey_start;
+ const auto subkey = path.substr(subkey_start, subkey_len);
+
+ // a regular subkey segment immediately after an array indexer is OK if it was all
+ // whitespace, e.g.:
+ //
+ // "foo[0] .bar"
+ // ^^ skip this
+ //
+ // otherwise its an error (since it would have to be preceeded by a dot)
+ if (prev_was_array_indexer) {
+ auto non_ws = subkey.find_first_not_of(" \t");
+ if (non_ws == std::string_view::npos) {
+ pos += subkey_len;
+ prev_was_dot = false;
+ prev_was_array_indexer = false;
+ continue;
+ } else
+ return false;
+ }
+
+ pos += subkey_len;
+ prev_was_dot = false;
+ prev_was_array_indexer = false;
+
+ if (!on_key(data, subkey)) return false;
+ }
+ }
+
+ // Last character was a '.', which implies an empty string key at the end of the path
+ if (prev_was_dot && !on_key(data, ""sv)) return false;
+
+ return true;
+ }
}
TOML_IMPL_NAMESPACE_END;
-TOML_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- node_view<node> TOML_CALLCONV at_path(node & root, std::string_view path) noexcept
- {
- // early-exit sanity-checks
- if (root.is_value())
- return {};
- if (auto tbl = root.as_table(); tbl && tbl->empty())
- return {};
- if (auto arr = root.as_array(); arr && arr->empty())
- return {};
-
- node* current = &root;
-
- static constexpr auto on_key = [](void* data, std::string_view key) noexcept -> bool
- {
- auto& curr = *static_cast<node**>(data);
- TOML_ASSERT_ASSUME(curr);
-
- const auto current_table = curr->as<table>();
- if (!current_table)
- return false;
-
- curr = current_table->get(key);
- return curr != nullptr;
- };
-
- static constexpr auto on_index = [](void* data, size_t index) noexcept -> bool
- {
- auto& curr = *static_cast<node**>(data);
- TOML_ASSERT_ASSUME(curr);
-
- const auto current_array = curr->as<array>();
- if (!current_array)
- return false;
-
- curr = current_array->get(index);
- return curr != nullptr;
- };
-
- if (!impl::parse_path(path, &current, on_key, on_index))
- current = nullptr;
-
- return node_view{ current };
- }
-
- TOML_EXTERNAL_LINKAGE
- node_view<const node> TOML_CALLCONV at_path(const node& root, std::string_view path) noexcept
- {
- return node_view<const node>{ at_path(const_cast<node&>(root), path).node() };
- }
+TOML_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ node_view<node> TOML_CALLCONV at_path(node & root, std::string_view path) noexcept {
+ // early-exit sanity-checks
+ if (root.is_value()) return {};
+ if (auto tbl = root.as_table(); tbl && tbl->empty()) return {};
+ if (auto arr = root.as_array(); arr && arr->empty()) return {};
+
+ node* current = &root;
+
+ static constexpr auto on_key = [](void* data, std::string_view key) noexcept -> bool {
+ auto& curr = *static_cast<node**>(data);
+ TOML_ASSERT_ASSUME(curr);
+
+ const auto current_table = curr->as<table>();
+ if (!current_table) return false;
+
+ curr = current_table->get(key);
+ return curr != nullptr;
+ };
+
+ static constexpr auto on_index = [](void* data, size_t index) noexcept -> bool {
+ auto& curr = *static_cast<node**>(data);
+ TOML_ASSERT_ASSUME(curr);
+
+ const auto current_array = curr->as<array>();
+ if (!current_array) return false;
+
+ curr = current_array->get(index);
+ return curr != nullptr;
+ };
+
+ if (!impl::parse_path(path, &current, on_key, on_index)) current = nullptr;
+
+ return node_view{current};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<const node> TOML_CALLCONV at_path(const node& root, std::string_view path) noexcept {
+ return node_view<const node>{at_path(const_cast<node&>(root), path).node()};
+ }
#if TOML_ENABLE_WINDOWS_COMPAT
- TOML_EXTERNAL_LINKAGE
- node_view<node> TOML_CALLCONV at_path(node & root, std::wstring_view path)
- {
- // these are the same top-level checks from the narrow-string version;
- // they're hoisted up here to avoid doing the wide -> narrow conversion where it would not be necessary
- // (avoids an allocation)
- if (root.is_value())
- return {};
- if (auto tbl = root.as_table(); tbl && tbl->empty())
- return {};
- if (auto arr = root.as_array(); arr && arr->empty())
- return {};
-
- return at_path(root, impl::narrow(path));
- }
-
- TOML_EXTERNAL_LINKAGE
- node_view<const node> TOML_CALLCONV at_path(const node& root, std::wstring_view path)
- {
- return node_view<const node>{ at_path(const_cast<node&>(root), path).node() };
- }
-
-#endif // TOML_ENABLE_WINDOWS_COMPAT
+ TOML_EXTERNAL_LINKAGE
+ node_view<node> TOML_CALLCONV at_path(node & root, std::wstring_view path) {
+ // these are the same top-level checks from the narrow-string version;
+ // they're hoisted up here to avoid doing the wide -> narrow conversion where it would not be
+ // necessary (avoids an allocation)
+ if (root.is_value()) return {};
+ if (auto tbl = root.as_table(); tbl && tbl->empty()) return {};
+ if (auto arr = root.as_array(); arr && arr->empty()) return {};
+
+ return at_path(root, impl::narrow(path));
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<const node> TOML_CALLCONV at_path(const node& root, std::wstring_view path) {
+ return node_view<const node>{at_path(const_cast<node&>(root), path).node()};
+ }
+
+#endif // TOML_ENABLE_WINDOWS_COMPAT
}
TOML_NAMESPACE_END;
diff --git a/vendor/toml++/impl/formatter.inl b/vendor/toml++/impl/formatter.inl
index f429d32..937ba47 100644
--- a/vendor/toml++/impl/formatter.inl
+++ b/vendor/toml++/impl/formatter.inl
@@ -1,523 +1,503 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.hpp"
-//# {{
+// # {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
#if TOML_ENABLE_FORMATTERS
+#include "array.hpp"
#include "formatter.hpp"
+#include "header_start.hpp"
+#include "parse_result.hpp"
#include "print_to_stream.hpp"
-#include "value.hpp"
#include "table.hpp"
-#include "array.hpp"
#include "unicode.hpp"
-#include "parse_result.hpp"
-#include "header_start.hpp"
+#include "value.hpp"
-TOML_IMPL_NAMESPACE_START
-{
- enum class TOML_CLOSED_FLAGS_ENUM formatted_string_traits : unsigned
- {
- none,
- line_breaks = 1u << 0, // \n
- tabs = 1u << 1, // \t
- control_chars = 1u << 2, // also includes non-ascii vertical whitespace
- single_quotes = 1u << 3,
- non_bare = 1u << 4, // anything not satisfying "is bare key character"
- non_ascii = 1u << 5, // any codepoint >= 128
-
- all = (non_ascii << 1u) - 1u
- };
- TOML_MAKE_FLAGS(formatted_string_traits);
-
- TOML_EXTERNAL_LINKAGE
- formatter::formatter(const node* source_node,
- const parse_result* source_pr,
- const formatter_constants& constants,
- const formatter_config& config) noexcept //
+TOML_IMPL_NAMESPACE_START {
+ enum class TOML_CLOSED_FLAGS_ENUM formatted_string_traits : unsigned {
+ none,
+ line_breaks = 1u << 0, // \n
+ tabs = 1u << 1, // \t
+ control_chars = 1u << 2, // also includes non-ascii vertical whitespace
+ single_quotes = 1u << 3,
+ non_bare = 1u << 4, // anything not satisfying "is bare key character"
+ non_ascii = 1u << 5, // any codepoint >= 128
+
+ all = (non_ascii << 1u) - 1u
+ };
+ TOML_MAKE_FLAGS(formatted_string_traits);
+
+ TOML_EXTERNAL_LINKAGE
+ formatter::formatter(const node* source_node, const parse_result* source_pr,
+ const formatter_constants& constants,
+ const formatter_config& config) noexcept //
#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
- : source_{ source_pr && *source_pr ? &source_pr->table() : source_node },
- result_{ source_pr },
+ : source_{source_pr && *source_pr ? &source_pr->table() : source_node},
+ result_{source_pr},
#else
- : source_{ source_pr ? source_pr : source_node },
+ : source_{source_pr ? source_pr : source_node},
#endif
- constants_{ &constants },
- config_{ config }
- {
- TOML_ASSERT_ASSUME(source_);
-
- config_.flags = (config_.flags | constants_->mandatory_flags) & ~constants_->ignored_flags;
-
- indent_columns_ = {};
- for (auto c : config_.indent)
- indent_columns_ += c == '\t' ? 4u : 1u;
-
- int_format_mask_ = config_.flags
- & (format_flags::allow_binary_integers | format_flags::allow_octal_integers
- | format_flags::allow_hexadecimal_integers);
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::attach(std::ostream & stream) noexcept
- {
- indent_ = {};
- naked_newline_ = true;
- stream_ = &stream;
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::detach() noexcept
- {
- stream_ = nullptr;
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print_newline(bool force)
- {
- if (!naked_newline_ || force)
- {
- print_to_stream(*stream_, '\n');
- naked_newline_ = true;
- }
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print_indent()
- {
- for (int i = 0; i < indent_; i++)
- {
- print_to_stream(*stream_, config_.indent);
- naked_newline_ = false;
- }
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print_unformatted(char c)
- {
- print_to_stream(*stream_, c);
- naked_newline_ = false;
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print_unformatted(std::string_view str)
- {
- print_to_stream(*stream_, str);
- naked_newline_ = false;
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print_string(std::string_view str,
- bool allow_multi_line,
- bool allow_bare,
- bool allow_literal_whitespace)
- {
- if (str.empty())
- {
- print_unformatted(literal_strings_allowed() ? "''"sv : "\"\""sv);
- return;
- }
-
- // pre-scan the string to determine how we should output it
- formatted_string_traits traits = {};
-
- if (!allow_bare)
- traits |= formatted_string_traits::non_bare;
- bool unicode_allowed = unicode_strings_allowed();
-
- // ascii fast path
- if (is_ascii(str.data(), str.length()))
- {
- for (auto c : str)
- {
- switch (c)
- {
- case '\n': traits |= formatted_string_traits::line_breaks; break;
- case '\t': traits |= formatted_string_traits::tabs; break;
- case '\'': traits |= formatted_string_traits::single_quotes; break;
- default:
- {
- if TOML_UNLIKELY(is_control_character(c))
- traits |= formatted_string_traits::control_chars;
-
- if (!is_ascii_bare_key_character(static_cast<char32_t>(c)))
- traits |= formatted_string_traits::non_bare;
- break;
- }
- }
-
- static constexpr auto all_ascii_traits =
- formatted_string_traits::all & ~formatted_string_traits::non_ascii;
- if (traits == all_ascii_traits)
- break;
- }
- }
-
- // unicode slow path
- else
- {
- traits |= formatted_string_traits::non_ascii;
- utf8_decoder decoder;
-
- // if the unicode is malformed just treat the string as a single-line non-literal and
- // escape all non-ascii characters (to ensure round-tripping and help with diagnostics)
- const auto bad_unicode = [&]() noexcept
- {
- traits &= ~formatted_string_traits::line_breaks;
- traits |= formatted_string_traits::control_chars | formatted_string_traits::non_bare;
- unicode_allowed = false;
- };
-
- for (auto c : str)
- {
- decoder(c);
-
- if TOML_UNLIKELY(decoder.error())
- {
- bad_unicode();
- break;
- }
-
- if (!decoder.has_code_point())
- continue;
-
- switch (decoder.codepoint)
- {
- case U'\n': traits |= formatted_string_traits::line_breaks; break;
- case U'\t': traits |= formatted_string_traits::tabs; break;
- case U'\'': traits |= formatted_string_traits::single_quotes; break;
- default:
- {
- if TOML_UNLIKELY(is_control_character(decoder.codepoint)
- || is_non_ascii_vertical_whitespace(decoder.codepoint))
- traits |= formatted_string_traits::control_chars;
-
- if (!is_bare_key_character(decoder.codepoint))
- traits |= formatted_string_traits::non_bare;
- break;
- }
- }
- }
-
- if (decoder.needs_more_input())
- bad_unicode();
- }
-
- // strings with line breaks, tabs, and single-quotes can't be bare
- if (!!(traits
- & (formatted_string_traits::line_breaks | formatted_string_traits::tabs
- | formatted_string_traits::single_quotes)))
- traits |= formatted_string_traits::non_bare;
-
- // if the string meets the requirements of being 'bare' we can emit a bare string
- // (bare strings are composed of letters and numbers; no whitespace, control chars, quotes, etc)
- if (!(traits & formatted_string_traits::non_bare)
- && (!(traits & formatted_string_traits::non_ascii) || unicode_allowed))
- {
- print_unformatted(str);
- return;
- }
- const auto real_tabs_allowed = allow_literal_whitespace && real_tabs_in_strings_allowed();
-
- // determine if this should be a multi-line string (triple-quotes)
- const auto multi_line = allow_literal_whitespace //
- && allow_multi_line //
- && multi_line_strings_allowed() //
- && !!(traits & formatted_string_traits::line_breaks);
-
- // determine if this should be a literal string (single-quotes with no escaping)
- const auto literal = literal_strings_allowed() //
- && !(traits & formatted_string_traits::control_chars) //
- && (!(traits & formatted_string_traits::single_quotes) || multi_line) //
- && (!(traits & formatted_string_traits::tabs) || real_tabs_allowed) //
- && (!(traits & formatted_string_traits::line_breaks) || multi_line) //
- && (!(traits & formatted_string_traits::non_ascii) || unicode_allowed);
-
- // literal strings (single quotes, no escape codes)
- if (literal)
- {
- const auto quot = multi_line ? R"(''')"sv : R"(')"sv;
- print_unformatted(quot);
- print_unformatted(str);
- print_unformatted(quot);
- return;
- }
-
- // anything from here down is a non-literal string, so requires iteration and escaping.
- print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
-
- // ascii fast path
- if (!(traits & formatted_string_traits::non_ascii))
- {
- for (auto c : str)
- {
- switch (c)
- {
- case '"': print_to_stream(*stream_, R"(\")"sv); break;
- case '\\': print_to_stream(*stream_, R"(\\)"sv); break;
- case '\x7F': print_to_stream(*stream_, R"(\u007F)"sv); break;
- case '\t': print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv); break;
- case '\n': print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv); break;
- default:
- {
- // control characters from lookup table
- if TOML_UNLIKELY(c >= '\x00' && c <= '\x1F')
- print_to_stream(*stream_, control_char_escapes[c]);
-
- // regular characters
- else
- print_to_stream(*stream_, c);
- }
- }
- }
- }
-
- // unicode slow path
- else
- {
- utf8_decoder decoder;
- const char* cp_start = str.data();
- const char* cp_end = cp_start;
- for (auto c : str)
- {
- decoder(c);
- cp_end++;
-
- // if the decoder encounters malformed unicode just emit raw bytes and
- if (decoder.error())
- {
- while (cp_start != cp_end)
- {
- print_to_stream(*stream_, R"(\u00)"sv);
- print_to_stream(*stream_,
- static_cast<uint8_t>(*cp_start),
- value_flags::format_as_hexadecimal,
- 2);
- cp_start++;
- }
- decoder.reset();
- continue;
- }
-
- if (!decoder.has_code_point())
- continue;
-
- switch (decoder.codepoint)
- {
- case U'"': print_to_stream(*stream_, R"(\")"sv); break;
- case U'\\': print_to_stream(*stream_, R"(\\)"sv); break;
- case U'\x7F': print_to_stream(*stream_, R"(\u007F)"sv); break;
- case U'\t': print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv); break;
- case U'\n': print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv); break;
- default:
- {
- // control characters from lookup table
- if TOML_UNLIKELY(decoder.codepoint <= U'\x1F')
- print_to_stream(*stream_,
- control_char_escapes[static_cast<uint_least32_t>(decoder.codepoint)]);
-
- // escaped unicode characters
- else if (decoder.codepoint > U'\x7F'
- && (!unicode_allowed || is_non_ascii_vertical_whitespace(decoder.codepoint)))
- {
- if (static_cast<uint_least32_t>(decoder.codepoint) > 0xFFFFu)
- {
- print_to_stream(*stream_, R"(\U)"sv);
- print_to_stream(*stream_,
- static_cast<uint_least32_t>(decoder.codepoint),
- value_flags::format_as_hexadecimal,
- 8);
- }
- else
- {
- print_to_stream(*stream_, R"(\u)"sv);
- print_to_stream(*stream_,
- static_cast<uint_least32_t>(decoder.codepoint),
- value_flags::format_as_hexadecimal,
- 4);
- }
- }
-
- // regular characters
- else
- print_to_stream(*stream_, cp_start, static_cast<size_t>(cp_end - cp_start));
- }
- }
-
- cp_start = cp_end;
- }
- }
-
- print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print(const value<std::string>& val)
- {
- print_string(val.get());
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print(const value<int64_t>& val)
- {
- naked_newline_ = false;
-
- if (*val >= 0 && !!int_format_mask_)
- {
- static constexpr auto value_flags_mask =
- value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
-
- const auto fmt = val.flags() & value_flags_mask;
- switch (fmt)
- {
- case value_flags::format_as_binary:
- if (!!(int_format_mask_ & format_flags::allow_binary_integers))
- {
- print_to_stream(*stream_, "0b"sv);
- print_to_stream(*stream_, *val, fmt);
- return;
- }
- break;
-
- case value_flags::format_as_octal:
- if (!!(int_format_mask_ & format_flags::allow_octal_integers))
- {
- print_to_stream(*stream_, "0o"sv);
- print_to_stream(*stream_, *val, fmt);
- return;
- }
- break;
-
- case value_flags::format_as_hexadecimal:
- if (!!(int_format_mask_ & format_flags::allow_hexadecimal_integers))
- {
- print_to_stream(*stream_, "0x"sv);
- print_to_stream(*stream_, *val, fmt);
- return;
- }
- break;
-
- default: break;
- }
- }
-
- // fallback to decimal
- print_to_stream(*stream_, *val);
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print(const value<double>& val)
- {
- const std::string_view* inf_nan = nullptr;
- switch (fpclassify(*val))
- {
- case fp_class::neg_inf: inf_nan = &constants_->float_neg_inf; break;
- case fp_class::pos_inf: inf_nan = &constants_->float_pos_inf; break;
- case fp_class::nan: inf_nan = &constants_->float_nan; break;
- case fp_class::ok:
- print_to_stream(*stream_,
- *val,
- value_flags::none,
- !!(config_.flags & format_flags::relaxed_float_precision));
- break;
- default: TOML_UNREACHABLE;
- }
-
- if (inf_nan)
- {
- if (!!(config_.flags & format_flags::quote_infinities_and_nans))
- print_to_stream_bookended(*stream_, *inf_nan, '"');
- else
- print_to_stream(*stream_, *inf_nan);
- }
-
- naked_newline_ = false;
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print(const value<bool>& val)
- {
- print_unformatted(*val ? constants_->bool_true : constants_->bool_false);
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print(const value<date>& val)
- {
- if (!!(config_.flags & format_flags::quote_dates_and_times))
- print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
- else
- print_to_stream(*stream_, *val);
- naked_newline_ = false;
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print(const value<time>& val)
- {
- if (!!(config_.flags & format_flags::quote_dates_and_times))
- print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
- else
- print_to_stream(*stream_, *val);
- naked_newline_ = false;
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print(const value<date_time>& val)
- {
- if (!!(config_.flags & format_flags::quote_dates_and_times))
- print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
- else
- print_to_stream(*stream_, *val);
- naked_newline_ = false;
- }
-
- TOML_EXTERNAL_LINKAGE
- void formatter::print_value(const node& val_node, node_type type)
- {
- TOML_ASSUME(type > node_type::array);
- switch (type)
- {
- case node_type::string: print(*reinterpret_cast<const value<std::string>*>(&val_node)); break;
- case node_type::integer: print(*reinterpret_cast<const value<int64_t>*>(&val_node)); break;
- case node_type::floating_point: print(*reinterpret_cast<const value<double>*>(&val_node)); break;
- case node_type::boolean: print(*reinterpret_cast<const value<bool>*>(&val_node)); break;
- case node_type::date: print(*reinterpret_cast<const value<date>*>(&val_node)); break;
- case node_type::time: print(*reinterpret_cast<const value<time>*>(&val_node)); break;
- case node_type::date_time: print(*reinterpret_cast<const value<date_time>*>(&val_node)); break;
- default: TOML_UNREACHABLE;
- }
- }
+ constants_{&constants},
+ config_{config} {
+ TOML_ASSERT_ASSUME(source_);
+
+ config_.flags = (config_.flags | constants_->mandatory_flags) & ~constants_->ignored_flags;
+
+ indent_columns_ = {};
+ for (auto c : config_.indent) indent_columns_ += c == '\t' ? 4u : 1u;
+
+ int_format_mask_ =
+ config_.flags & (format_flags::allow_binary_integers | format_flags::allow_octal_integers |
+ format_flags::allow_hexadecimal_integers);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::attach(std::ostream & stream) noexcept {
+ indent_ = {};
+ naked_newline_ = true;
+ stream_ = &stream;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::detach() noexcept {
+ stream_ = nullptr;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print_newline(bool force) {
+ if (!naked_newline_ || force) {
+ print_to_stream(*stream_, '\n');
+ naked_newline_ = true;
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print_indent() {
+ for (int i = 0; i < indent_; i++) {
+ print_to_stream(*stream_, config_.indent);
+ naked_newline_ = false;
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print_unformatted(char c) {
+ print_to_stream(*stream_, c);
+ naked_newline_ = false;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print_unformatted(std::string_view str) {
+ print_to_stream(*stream_, str);
+ naked_newline_ = false;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print_string(std::string_view str, bool allow_multi_line, bool allow_bare,
+ bool allow_literal_whitespace) {
+ if (str.empty()) {
+ print_unformatted(literal_strings_allowed() ? "''"sv : "\"\""sv);
+ return;
+ }
+
+ // pre-scan the string to determine how we should output it
+ formatted_string_traits traits = {};
+
+ if (!allow_bare) traits |= formatted_string_traits::non_bare;
+ bool unicode_allowed = unicode_strings_allowed();
+
+ // ascii fast path
+ if (is_ascii(str.data(), str.length())) {
+ for (auto c : str) {
+ switch (c) {
+ case '\n':
+ traits |= formatted_string_traits::line_breaks;
+ break;
+ case '\t':
+ traits |= formatted_string_traits::tabs;
+ break;
+ case '\'':
+ traits |= formatted_string_traits::single_quotes;
+ break;
+ default: {
+ if TOML_UNLIKELY (is_control_character(c))
+ traits |= formatted_string_traits::control_chars;
+
+ if (!is_ascii_bare_key_character(static_cast<char32_t>(c)))
+ traits |= formatted_string_traits::non_bare;
+ break;
+ }
+ }
+
+ static constexpr auto all_ascii_traits =
+ formatted_string_traits::all & ~formatted_string_traits::non_ascii;
+ if (traits == all_ascii_traits) break;
+ }
+ }
+
+ // unicode slow path
+ else {
+ traits |= formatted_string_traits::non_ascii;
+ utf8_decoder decoder;
+
+ // if the unicode is malformed just treat the string as a single-line non-literal and
+ // escape all non-ascii characters (to ensure round-tripping and help with diagnostics)
+ const auto bad_unicode = [&]() noexcept {
+ traits &= ~formatted_string_traits::line_breaks;
+ traits |= formatted_string_traits::control_chars | formatted_string_traits::non_bare;
+ unicode_allowed = false;
+ };
+
+ for (auto c : str) {
+ decoder(c);
+
+ if TOML_UNLIKELY (decoder.error()) {
+ bad_unicode();
+ break;
+ }
+
+ if (!decoder.has_code_point()) continue;
+
+ switch (decoder.codepoint) {
+ case U'\n':
+ traits |= formatted_string_traits::line_breaks;
+ break;
+ case U'\t':
+ traits |= formatted_string_traits::tabs;
+ break;
+ case U'\'':
+ traits |= formatted_string_traits::single_quotes;
+ break;
+ default: {
+ if TOML_UNLIKELY (is_control_character(decoder.codepoint) ||
+ is_non_ascii_vertical_whitespace(decoder.codepoint))
+ traits |= formatted_string_traits::control_chars;
+
+ if (!is_bare_key_character(decoder.codepoint))
+ traits |= formatted_string_traits::non_bare;
+ break;
+ }
+ }
+ }
+
+ if (decoder.needs_more_input()) bad_unicode();
+ }
+
+ // strings with line breaks, tabs, and single-quotes can't be bare
+ if (!!(traits & (formatted_string_traits::line_breaks | formatted_string_traits::tabs |
+ formatted_string_traits::single_quotes)))
+ traits |= formatted_string_traits::non_bare;
+
+ // if the string meets the requirements of being 'bare' we can emit a bare string
+ // (bare strings are composed of letters and numbers; no whitespace, control chars, quotes, etc)
+ if (!(traits & formatted_string_traits::non_bare) &&
+ (!(traits & formatted_string_traits::non_ascii) || unicode_allowed)) {
+ print_unformatted(str);
+ return;
+ }
+ const auto real_tabs_allowed = allow_literal_whitespace && real_tabs_in_strings_allowed();
+
+ // determine if this should be a multi-line string (triple-quotes)
+ const auto multi_line = allow_literal_whitespace //
+ && allow_multi_line //
+ && multi_line_strings_allowed() //
+ && !!(traits & formatted_string_traits::line_breaks);
+
+ // determine if this should be a literal string (single-quotes with no escaping)
+ const auto literal = literal_strings_allowed() //
+ && !(traits & formatted_string_traits::control_chars) //
+ && (!(traits & formatted_string_traits::single_quotes) || multi_line) //
+ && (!(traits & formatted_string_traits::tabs) || real_tabs_allowed) //
+ && (!(traits & formatted_string_traits::line_breaks) || multi_line) //
+ && (!(traits & formatted_string_traits::non_ascii) || unicode_allowed);
+
+ // literal strings (single quotes, no escape codes)
+ if (literal) {
+ const auto quot = multi_line ? R"(''')"sv : R"(')"sv;
+ print_unformatted(quot);
+ print_unformatted(str);
+ print_unformatted(quot);
+ return;
+ }
+
+ // anything from here down is a non-literal string, so requires iteration and escaping.
+ print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
+
+ // ascii fast path
+ if (!(traits & formatted_string_traits::non_ascii)) {
+ for (auto c : str) {
+ switch (c) {
+ case '"':
+ print_to_stream(*stream_, R"(\")"sv);
+ break;
+ case '\\':
+ print_to_stream(*stream_, R"(\\)"sv);
+ break;
+ case '\x7F':
+ print_to_stream(*stream_, R"(\u007F)"sv);
+ break;
+ case '\t':
+ print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv);
+ break;
+ case '\n':
+ print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv);
+ break;
+ default: {
+ // control characters from lookup table
+ if TOML_UNLIKELY (c >= '\x00' && c <= '\x1F')
+ print_to_stream(*stream_, control_char_escapes[c]);
+
+ // regular characters
+ else
+ print_to_stream(*stream_, c);
+ }
+ }
+ }
+ }
+
+ // unicode slow path
+ else {
+ utf8_decoder decoder;
+ const char* cp_start = str.data();
+ const char* cp_end = cp_start;
+ for (auto c : str) {
+ decoder(c);
+ cp_end++;
+
+ // if the decoder encounters malformed unicode just emit raw bytes and
+ if (decoder.error()) {
+ while (cp_start != cp_end) {
+ print_to_stream(*stream_, R"(\u00)"sv);
+ print_to_stream(*stream_, static_cast<uint8_t>(*cp_start),
+ value_flags::format_as_hexadecimal, 2);
+ cp_start++;
+ }
+ decoder.reset();
+ continue;
+ }
+
+ if (!decoder.has_code_point()) continue;
+
+ switch (decoder.codepoint) {
+ case U'"':
+ print_to_stream(*stream_, R"(\")"sv);
+ break;
+ case U'\\':
+ print_to_stream(*stream_, R"(\\)"sv);
+ break;
+ case U'\x7F':
+ print_to_stream(*stream_, R"(\u007F)"sv);
+ break;
+ case U'\t':
+ print_to_stream(*stream_, real_tabs_allowed ? "\t"sv : R"(\t)"sv);
+ break;
+ case U'\n':
+ print_to_stream(*stream_, multi_line ? "\n"sv : R"(\n)"sv);
+ break;
+ default: {
+ // control characters from lookup table
+ if TOML_UNLIKELY (decoder.codepoint <= U'\x1F')
+ print_to_stream(*stream_,
+ control_char_escapes[static_cast<uint_least32_t>(decoder.codepoint)]);
+
+ // escaped unicode characters
+ else if (decoder.codepoint > U'\x7F' &&
+ (!unicode_allowed || is_non_ascii_vertical_whitespace(decoder.codepoint))) {
+ if (static_cast<uint_least32_t>(decoder.codepoint) > 0xFFFFu) {
+ print_to_stream(*stream_, R"(\U)"sv);
+ print_to_stream(*stream_, static_cast<uint_least32_t>(decoder.codepoint),
+ value_flags::format_as_hexadecimal, 8);
+ } else {
+ print_to_stream(*stream_, R"(\u)"sv);
+ print_to_stream(*stream_, static_cast<uint_least32_t>(decoder.codepoint),
+ value_flags::format_as_hexadecimal, 4);
+ }
+ }
+
+ // regular characters
+ else
+ print_to_stream(*stream_, cp_start, static_cast<size_t>(cp_end - cp_start));
+ }
+ }
+
+ cp_start = cp_end;
+ }
+ }
+
+ print_unformatted(multi_line ? R"(""")"sv : R"(")"sv);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print(const value<std::string>& val) {
+ print_string(val.get());
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print(const value<int64_t>& val) {
+ naked_newline_ = false;
+
+ if (*val >= 0 && !!int_format_mask_) {
+ static constexpr auto value_flags_mask = value_flags::format_as_binary |
+ value_flags::format_as_octal |
+ value_flags::format_as_hexadecimal;
+
+ const auto fmt = val.flags() & value_flags_mask;
+ switch (fmt) {
+ case value_flags::format_as_binary:
+ if (!!(int_format_mask_ & format_flags::allow_binary_integers)) {
+ print_to_stream(*stream_, "0b"sv);
+ print_to_stream(*stream_, *val, fmt);
+ return;
+ }
+ break;
+
+ case value_flags::format_as_octal:
+ if (!!(int_format_mask_ & format_flags::allow_octal_integers)) {
+ print_to_stream(*stream_, "0o"sv);
+ print_to_stream(*stream_, *val, fmt);
+ return;
+ }
+ break;
+
+ case value_flags::format_as_hexadecimal:
+ if (!!(int_format_mask_ & format_flags::allow_hexadecimal_integers)) {
+ print_to_stream(*stream_, "0x"sv);
+ print_to_stream(*stream_, *val, fmt);
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // fallback to decimal
+ print_to_stream(*stream_, *val);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print(const value<double>& val) {
+ const std::string_view* inf_nan = nullptr;
+ switch (fpclassify(*val)) {
+ case fp_class::neg_inf:
+ inf_nan = &constants_->float_neg_inf;
+ break;
+ case fp_class::pos_inf:
+ inf_nan = &constants_->float_pos_inf;
+ break;
+ case fp_class::nan:
+ inf_nan = &constants_->float_nan;
+ break;
+ case fp_class::ok:
+ print_to_stream(*stream_, *val, value_flags::none,
+ !!(config_.flags & format_flags::relaxed_float_precision));
+ break;
+ default:
+ TOML_UNREACHABLE;
+ }
+
+ if (inf_nan) {
+ if (!!(config_.flags & format_flags::quote_infinities_and_nans))
+ print_to_stream_bookended(*stream_, *inf_nan, '"');
+ else
+ print_to_stream(*stream_, *inf_nan);
+ }
+
+ naked_newline_ = false;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print(const value<bool>& val) {
+ print_unformatted(*val ? constants_->bool_true : constants_->bool_false);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print(const value<date>& val) {
+ if (!!(config_.flags & format_flags::quote_dates_and_times))
+ print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
+ else
+ print_to_stream(*stream_, *val);
+ naked_newline_ = false;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print(const value<time>& val) {
+ if (!!(config_.flags & format_flags::quote_dates_and_times))
+ print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
+ else
+ print_to_stream(*stream_, *val);
+ naked_newline_ = false;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print(const value<date_time>& val) {
+ if (!!(config_.flags & format_flags::quote_dates_and_times))
+ print_to_stream_bookended(*stream_, *val, literal_strings_allowed() ? '\'' : '"');
+ else
+ print_to_stream(*stream_, *val);
+ naked_newline_ = false;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void formatter::print_value(const node& val_node, node_type type) {
+ TOML_ASSUME(type > node_type::array);
+ switch (type) {
+ case node_type::string:
+ print(*reinterpret_cast<const value<std::string>*>(&val_node));
+ break;
+ case node_type::integer:
+ print(*reinterpret_cast<const value<int64_t>*>(&val_node));
+ break;
+ case node_type::floating_point:
+ print(*reinterpret_cast<const value<double>*>(&val_node));
+ break;
+ case node_type::boolean:
+ print(*reinterpret_cast<const value<bool>*>(&val_node));
+ break;
+ case node_type::date:
+ print(*reinterpret_cast<const value<date>*>(&val_node));
+ break;
+ case node_type::time:
+ print(*reinterpret_cast<const value<time>*>(&val_node));
+ break;
+ case node_type::date_time:
+ print(*reinterpret_cast<const value<date_time>*>(&val_node));
+ break;
+ default:
+ TOML_UNREACHABLE;
+ }
+ }
#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
- TOML_EXTERNAL_LINKAGE
- bool formatter::dump_failed_parse_result()
- {
- if (result_ && !(*result_))
- {
- stream() << result_->error();
- return true;
- }
- return false;
- }
+ TOML_EXTERNAL_LINKAGE
+ bool formatter::dump_failed_parse_result() {
+ if (result_ && !(*result_)) {
+ stream() << result_->error();
+ return true;
+ }
+ return false;
+ }
#else
- TOML_EXTERNAL_LINKAGE
- TOML_ATTR(const)
- bool formatter::dump_failed_parse_result()
- {
- return false;
- }
+ TOML_EXTERNAL_LINKAGE
+ TOML_ATTR(const)
+ bool formatter::dump_failed_parse_result() {
+ return false;
+ }
#endif
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.hpp"
-#endif // TOML_ENABLE_FORMATTERS
+#endif // TOML_ENABLE_FORMATTERS
diff --git a/vendor/toml++/impl/json_formatter.inl b/vendor/toml++/impl/json_formatter.inl
index ceffbd4..16bffc9 100644
--- a/vendor/toml++/impl/json_formatter.inl
+++ b/vendor/toml++/impl/json_formatter.inl
@@ -1,121 +1,118 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.hpp"
-//# {{
+// # {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
#if TOML_ENABLE_FORMATTERS
+#include "array.hpp"
+#include "header_start.hpp"
#include "json_formatter.hpp"
#include "print_to_stream.hpp"
#include "table.hpp"
-#include "array.hpp"
-#include "header_start.hpp"
-TOML_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- void json_formatter::print(const toml::table& tbl)
- {
- if (tbl.empty())
- {
- print_unformatted("{}"sv);
- return;
- }
+TOML_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ void json_formatter::print(const toml::table& tbl) {
+ if (tbl.empty()) {
+ print_unformatted("{}"sv);
+ return;
+ }
- print_unformatted('{');
+ print_unformatted('{');
- if (indent_sub_tables())
- increase_indent();
- bool first = false;
- for (auto&& [k, v] : tbl)
- {
- if (first)
- print_unformatted(',');
- first = true;
- print_newline(true);
- print_indent();
+ if (indent_sub_tables()) increase_indent();
+ bool first = false;
+ for (auto&& [k, v] : tbl) {
+ if (first) print_unformatted(',');
+ first = true;
+ print_newline(true);
+ print_indent();
- print_string(k.str(), false);
- if (terse_kvps())
- print_unformatted(":"sv);
- else
- print_unformatted(" : "sv);
+ print_string(k.str(), false);
+ if (terse_kvps())
+ print_unformatted(":"sv);
+ else
+ print_unformatted(" : "sv);
- const auto type = v.type();
- TOML_ASSUME(type != node_type::none);
- switch (type)
- {
- case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
- case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
- default: print_value(v, type);
- }
- }
- if (indent_sub_tables())
- decrease_indent();
- print_newline(true);
- print_indent();
+ const auto type = v.type();
+ TOML_ASSUME(type != node_type::none);
+ switch (type) {
+ case node_type::table:
+ print(*reinterpret_cast<const table*>(&v));
+ break;
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&v));
+ break;
+ default:
+ print_value(v, type);
+ }
+ }
+ if (indent_sub_tables()) decrease_indent();
+ print_newline(true);
+ print_indent();
- print_unformatted('}');
- }
+ print_unformatted('}');
+ }
- TOML_EXTERNAL_LINKAGE
- void json_formatter::print(const toml::array& arr)
- {
- if (arr.empty())
- {
- print_unformatted("[]"sv);
- return;
- }
+ TOML_EXTERNAL_LINKAGE
+ void json_formatter::print(const toml::array& arr) {
+ if (arr.empty()) {
+ print_unformatted("[]"sv);
+ return;
+ }
- print_unformatted('[');
- if (indent_array_elements())
- increase_indent();
- for (size_t i = 0; i < arr.size(); i++)
- {
- if (i > 0u)
- print_unformatted(',');
- print_newline(true);
- print_indent();
+ print_unformatted('[');
+ if (indent_array_elements()) increase_indent();
+ for (size_t i = 0; i < arr.size(); i++) {
+ if (i > 0u) print_unformatted(',');
+ print_newline(true);
+ print_indent();
- auto& v = arr[i];
- const auto type = v.type();
- TOML_ASSUME(type != node_type::none);
- switch (type)
- {
- case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
- case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
- default: print_value(v, type);
- }
- }
- if (indent_array_elements())
- decrease_indent();
- print_newline(true);
- print_indent();
- print_unformatted(']');
- }
+ auto& v = arr[i];
+ const auto type = v.type();
+ TOML_ASSUME(type != node_type::none);
+ switch (type) {
+ case node_type::table:
+ print(*reinterpret_cast<const table*>(&v));
+ break;
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&v));
+ break;
+ default:
+ print_value(v, type);
+ }
+ }
+ if (indent_array_elements()) decrease_indent();
+ print_newline(true);
+ print_indent();
+ print_unformatted(']');
+ }
- TOML_EXTERNAL_LINKAGE
- void json_formatter::print()
- {
- if (dump_failed_parse_result())
- return;
+ TOML_EXTERNAL_LINKAGE
+ void json_formatter::print() {
+ if (dump_failed_parse_result()) return;
- switch (auto source_type = source().type())
- {
- case node_type::table: print(*reinterpret_cast<const table*>(&source())); break;
- case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
- default: print_value(source(), source_type);
- }
- }
+ switch (auto source_type = source().type()) {
+ case node_type::table:
+ print(*reinterpret_cast<const table*>(&source()));
+ break;
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&source()));
+ break;
+ default:
+ print_value(source(), source_type);
+ }
+ }
}
TOML_NAMESPACE_END;
#include "header_end.hpp"
-#endif // TOML_ENABLE_FORMATTERS
+#endif // TOML_ENABLE_FORMATTERS
diff --git a/vendor/toml++/impl/node.inl b/vendor/toml++/impl/node.inl
index 171e05d..060832b 100644
--- a/vendor/toml++/impl/node.inl
+++ b/vendor/toml++/impl/node.inl
@@ -1,140 +1,120 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
-//# {{
+// # {{
#include "preprocessor.hpp"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
+#include "array.hpp"
+#include "at_path.hpp"
+#include "header_start.hpp"
#include "node.hpp"
#include "node_view.hpp"
-#include "at_path.hpp"
#include "table.hpp"
-#include "array.hpp"
#include "value.hpp"
-#include "header_start.hpp"
-TOML_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- node::node() noexcept = default;
-
- TOML_EXTERNAL_LINKAGE
- node::~node() noexcept = default;
-
- TOML_EXTERNAL_LINKAGE
- node::node(node && other) noexcept //
- : source_{ std::exchange(other.source_, {}) }
- {}
-
- TOML_EXTERNAL_LINKAGE
- node::node(const node& /*other*/) noexcept
- {
- // does not copy source information - this is not an error
- //
- // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
- }
-
- TOML_EXTERNAL_LINKAGE
- node& node::operator=(const node& /*rhs*/) noexcept
- {
- // does not copy source information - this is not an error
- //
- // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
-
- source_ = {};
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- node& node::operator=(node&& rhs) noexcept
- {
- if (&rhs != this)
- source_ = std::exchange(rhs.source_, {});
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- node_view<node> node::at_path(std::string_view path) noexcept
- {
- return toml::at_path(*this, path);
- }
-
- TOML_EXTERNAL_LINKAGE
- node_view<const node> node::at_path(std::string_view path) const noexcept
- {
- return toml::at_path(*this, path);
- }
-
- TOML_EXTERNAL_LINKAGE
- node_view<node> node::at_path(const path& p) noexcept
- {
- return toml::at_path(*this, p);
- }
-
- TOML_EXTERNAL_LINKAGE
- node_view<const node> node::at_path(const path& p) const noexcept
- {
- return toml::at_path(*this, p);
- }
+TOML_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ node::node() noexcept = default;
+
+ TOML_EXTERNAL_LINKAGE
+ node::~node() noexcept = default;
+
+ TOML_EXTERNAL_LINKAGE
+ node::node(node && other) noexcept //
+ : source_{std::exchange(other.source_, {})} {}
+
+ TOML_EXTERNAL_LINKAGE
+ node::node(const node& /*other*/) noexcept {
+ // does not copy source information - this is not an error
+ //
+ // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node& node::operator=(const node& /*rhs*/) noexcept {
+ // does not copy source information - this is not an error
+ //
+ // see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
+
+ source_ = {};
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node& node::operator=(node&& rhs) noexcept {
+ if (&rhs != this) source_ = std::exchange(rhs.source_, {});
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<node> node::at_path(std::string_view path) noexcept {
+ return toml::at_path(*this, path);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<const node> node::at_path(std::string_view path) const noexcept {
+ return toml::at_path(*this, path);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<node> node::at_path(const path& p) noexcept {
+ return toml::at_path(*this, p);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<const node> node::at_path(const path& p) const noexcept {
+ return toml::at_path(*this, p);
+ }
#if TOML_ENABLE_WINDOWS_COMPAT
- TOML_EXTERNAL_LINKAGE
- node_view<node> node::at_path(std::wstring_view path)
- {
- return toml::at_path(*this, path);
- }
-
- TOML_EXTERNAL_LINKAGE
- node_view<const node> node::at_path(std::wstring_view path) const
- {
- return toml::at_path(*this, path);
- }
-
-#endif // TOML_ENABLE_WINDOWS_COMPAT
-
- TOML_EXTERNAL_LINKAGE
- node_view<node> node::operator[](const path& p) noexcept
- {
- return toml::at_path(*this, p);
- }
-
- TOML_EXTERNAL_LINKAGE
- node_view<const node> node::operator[](const path& p) const noexcept
- {
- return toml::at_path(*this, p);
- }
+ TOML_EXTERNAL_LINKAGE
+ node_view<node> node::at_path(std::wstring_view path) {
+ return toml::at_path(*this, path);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<const node> node::at_path(std::wstring_view path) const {
+ return toml::at_path(*this, path);
+ }
+
+#endif // TOML_ENABLE_WINDOWS_COMPAT
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<node> node::operator[](const path& p) noexcept {
+ return toml::at_path(*this, p);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<const node> node::operator[](const path& p) const noexcept {
+ return toml::at_path(*this, p);
+ }
}
TOML_NAMESPACE_END;
-TOML_IMPL_NAMESPACE_START
-{
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- bool TOML_CALLCONV node_deep_equality(const node* lhs, const node* rhs) noexcept
- {
- // both same or both null
- if (lhs == rhs)
- return true;
-
- // lhs null != rhs null or different types
- if ((!lhs != !rhs) || lhs->type() != rhs->type())
- return false;
-
- return lhs->visit(
- [=](auto& l) noexcept
- {
- using concrete_type = remove_cvref<decltype(l)>;
-
- return l == *(rhs->as<concrete_type>());
- });
- }
+TOML_IMPL_NAMESPACE_START {
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ bool TOML_CALLCONV node_deep_equality(const node* lhs, const node* rhs) noexcept {
+ // both same or both null
+ if (lhs == rhs) return true;
+
+ // lhs null != rhs null or different types
+ if ((!lhs != !rhs) || lhs->type() != rhs->type()) return false;
+
+ return lhs->visit([=](auto& l) noexcept {
+ using concrete_type = remove_cvref<decltype(l)>;
+
+ return l == *(rhs->as<concrete_type>());
+ });
+ }
}
TOML_IMPL_NAMESPACE_END;
diff --git a/vendor/toml++/impl/parser.inl b/vendor/toml++/impl/parser.inl
index 6f0136f..1530e5a 100644
--- a/vendor/toml++/impl/parser.inl
+++ b/vendor/toml++/impl/parser.inl
@@ -1,29 +1,29 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.hpp"
-//# {{
+// # {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
#if TOML_ENABLE_PARSER
+#include "array.hpp"
+#include "date_time.hpp"
+#include "parse_error.hpp"
#include "parser.hpp"
-#include "std_optional.hpp"
#include "source_region.hpp"
-#include "parse_error.hpp"
-#include "date_time.hpp"
-#include "value.hpp"
-#include "array.hpp"
+#include "std_optional.hpp"
#include "table.hpp"
#include "unicode.hpp"
+#include "value.hpp"
TOML_DISABLE_WARNINGS;
-#include <istream>
#include <fstream>
+#include <istream>
#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
#include <charconv>
#endif
@@ -36,190 +36,153 @@ TOML_DISABLE_WARNINGS;
TOML_ENABLE_WARNINGS;
#include "header_start.hpp"
-//#---------------------------------------------------------------------------------------------------------------------
-//# UTF8 STREAMS
-//#---------------------------------------------------------------------------------------------------------------------
-
-TOML_ANON_NAMESPACE_START
-{
- template <typename T>
- class utf8_byte_stream;
-
- TOML_INTERNAL_LINKAGE
- constexpr auto utf8_byte_order_mark = "\xEF\xBB\xBF"sv;
-
- template <typename Char>
- class utf8_byte_stream<std::basic_string_view<Char>>
- {
- static_assert(sizeof(Char) == 1);
-
- private:
- std::basic_string_view<Char> source_;
- size_t position_ = {};
-
- public:
- TOML_NODISCARD_CTOR
- explicit constexpr utf8_byte_stream(std::basic_string_view<Char> sv) noexcept //
- : source_{ sv }
- {
- // skip bom
- if (source_.length() >= 3u && memcmp(utf8_byte_order_mark.data(), source_.data(), 3u) == 0)
- position_ += 3u;
- }
-
- TOML_CONST_INLINE_GETTER
- constexpr bool error() const noexcept
- {
- return false;
- }
-
- TOML_PURE_INLINE_GETTER
- constexpr bool eof() const noexcept
- {
- return position_ >= source_.length();
- }
-
- TOML_PURE_INLINE_GETTER
- explicit constexpr operator bool() const noexcept
- {
- return !eof();
- }
-
- TOML_PURE_INLINE_GETTER
- constexpr bool peek_eof() const noexcept
- {
- return eof();
- }
-
- TOML_NODISCARD
- TOML_ATTR(nonnull)
- size_t operator()(void* dest, size_t num) noexcept
- {
- TOML_ASSERT_ASSUME(!eof());
-
- num = impl::min(position_ + num, source_.length()) - position_;
- std::memcpy(dest, source_.data() + position_, num);
- position_ += num;
- return num;
- }
- };
-
- template <>
- class utf8_byte_stream<std::istream>
- {
- private:
- std::istream* source_;
-
- public:
- TOML_NODISCARD_CTOR
- explicit utf8_byte_stream(std::istream& stream) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) //
- : source_{ &stream }
- {
- if (!*this) // eof, bad
- return;
-
- const auto initial_pos = source_->tellg();
- char bom[3];
- source_->read(bom, 3);
- if (source_->bad() || (source_->gcount() == 3 && memcmp(utf8_byte_order_mark.data(), bom, 3u) == 0))
- return;
-
- source_->clear();
- source_->seekg(initial_pos, std::istream::beg);
- }
-
- TOML_PURE_INLINE_GETTER
- bool error() const noexcept
- {
- return !!(source_->rdstate() & std::istream::badbit);
- }
-
- TOML_PURE_INLINE_GETTER
- bool eof() const noexcept
- {
- return !!(source_->rdstate() & std::istream::eofbit);
- }
-
- TOML_PURE_INLINE_GETTER
- explicit operator bool() const noexcept
- {
- return !(source_->rdstate() & (std::istream::badbit | std::istream::eofbit));
- }
-
- TOML_NODISCARD
- bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
- {
- return eof() || source_->peek() == std::istream::traits_type::eof();
- }
-
- TOML_NODISCARD
- TOML_ATTR(nonnull)
- size_t operator()(void* dest, size_t num) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
- {
- TOML_ASSERT(*this);
-
- source_->read(static_cast<char*>(dest), static_cast<std::streamsize>(num));
- return static_cast<size_t>(source_->gcount());
- }
- };
-
- struct utf8_codepoint
- {
- char32_t value;
- char bytes[4];
- size_t count;
- source_position position;
-
- TOML_PURE_INLINE_GETTER
- constexpr operator const char32_t&() const noexcept
- {
- return value;
- }
-
- TOML_PURE_INLINE_GETTER
- constexpr const char32_t& operator*() const noexcept
- {
- return value;
- }
- };
- static_assert(std::is_trivial_v<utf8_codepoint>);
- static_assert(std::is_standard_layout_v<utf8_codepoint>);
-
- struct TOML_ABSTRACT_INTERFACE utf8_reader_interface
- {
- TOML_NODISCARD
- virtual const source_path_ptr& source_path() const noexcept = 0;
-
- TOML_NODISCARD
- virtual const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) = 0;
-
- TOML_NODISCARD
- virtual bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) = 0;
+// #---------------------------------------------------------------------------------------------------------------------
+// # UTF8 STREAMS
+// #---------------------------------------------------------------------------------------------------------------------
+
+TOML_ANON_NAMESPACE_START {
+ template <typename T>
+ class utf8_byte_stream;
+
+ TOML_INTERNAL_LINKAGE
+ constexpr auto utf8_byte_order_mark = "\xEF\xBB\xBF"sv;
+
+ template <typename Char>
+ class utf8_byte_stream<std::basic_string_view<Char>> {
+ static_assert(sizeof(Char) == 1);
+
+ private:
+ std::basic_string_view<Char> source_;
+ size_t position_ = {};
+
+ public:
+ TOML_NODISCARD_CTOR
+ explicit constexpr utf8_byte_stream(std::basic_string_view<Char> sv) noexcept //
+ : source_{sv} {
+ // skip bom
+ if (source_.length() >= 3u && memcmp(utf8_byte_order_mark.data(), source_.data(), 3u) == 0)
+ position_ += 3u;
+ }
+
+ TOML_CONST_INLINE_GETTER
+ constexpr bool error() const noexcept { return false; }
+
+ TOML_PURE_INLINE_GETTER
+ constexpr bool eof() const noexcept { return position_ >= source_.length(); }
+
+ TOML_PURE_INLINE_GETTER
+ explicit constexpr operator bool() const noexcept { return !eof(); }
+
+ TOML_PURE_INLINE_GETTER
+ constexpr bool peek_eof() const noexcept { return eof(); }
+
+ TOML_NODISCARD
+ TOML_ATTR(nonnull)
+ size_t operator()(void* dest, size_t num) noexcept {
+ TOML_ASSERT_ASSUME(!eof());
+
+ num = impl::min(position_ + num, source_.length()) - position_;
+ std::memcpy(dest, source_.data() + position_, num);
+ position_ += num;
+ return num;
+ }
+ };
+
+ template <>
+ class utf8_byte_stream<std::istream> {
+ private:
+ std::istream* source_;
+
+ public:
+ TOML_NODISCARD_CTOR
+ explicit utf8_byte_stream(std::istream& stream) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) //
+ : source_{&stream} {
+ if (!*this) // eof, bad
+ return;
+
+ const auto initial_pos = source_->tellg();
+ char bom[3];
+ source_->read(bom, 3);
+ if (source_->bad() ||
+ (source_->gcount() == 3 && memcmp(utf8_byte_order_mark.data(), bom, 3u) == 0))
+ return;
+
+ source_->clear();
+ source_->seekg(initial_pos, std::istream::beg);
+ }
+
+ TOML_PURE_INLINE_GETTER
+ bool error() const noexcept { return !!(source_->rdstate() & std::istream::badbit); }
+
+ TOML_PURE_INLINE_GETTER
+ bool eof() const noexcept { return !!(source_->rdstate() & std::istream::eofbit); }
+
+ TOML_PURE_INLINE_GETTER
+ explicit operator bool() const noexcept {
+ return !(source_->rdstate() & (std::istream::badbit | std::istream::eofbit));
+ }
+
+ TOML_NODISCARD
+ bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) {
+ return eof() || source_->peek() == std::istream::traits_type::eof();
+ }
+
+ TOML_NODISCARD
+ TOML_ATTR(nonnull)
+ size_t operator()(void* dest, size_t num) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) {
+ TOML_ASSERT(*this);
+
+ source_->read(static_cast<char*>(dest), static_cast<std::streamsize>(num));
+ return static_cast<size_t>(source_->gcount());
+ }
+ };
+
+ struct utf8_codepoint {
+ char32_t value;
+ char bytes[4];
+ size_t count;
+ source_position position;
+
+ TOML_PURE_INLINE_GETTER
+ constexpr operator const char32_t&() const noexcept { return value; }
+
+ TOML_PURE_INLINE_GETTER
+ constexpr const char32_t& operator*() const noexcept { return value; }
+ };
+ static_assert(std::is_trivial_v<utf8_codepoint>);
+ static_assert(std::is_standard_layout_v<utf8_codepoint>);
+
+ struct TOML_ABSTRACT_INTERFACE utf8_reader_interface {
+ TOML_NODISCARD
+ virtual const source_path_ptr& source_path() const noexcept = 0;
+
+ TOML_NODISCARD
+ virtual const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) = 0;
+
+ TOML_NODISCARD
+ virtual bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) = 0;
#if !TOML_EXCEPTIONS
- TOML_NODISCARD
- virtual optional<parse_error>&& error() noexcept = 0;
+ TOML_NODISCARD
+ virtual optional<parse_error>&& error() noexcept = 0;
#endif
- virtual ~utf8_reader_interface() noexcept = default;
- };
+ virtual ~utf8_reader_interface() noexcept = default;
+ };
#if TOML_EXCEPTIONS
-#define utf8_reader_error(...) throw parse_error(__VA_ARGS__)
+#define utf8_reader_error(...) throw parse_error(__VA_ARGS__)
#define utf8_reader_return_after_error(...) static_assert(true)
-#define utf8_reader_error_check(...) static_assert(true)
+#define utf8_reader_error_check(...) static_assert(true)
#else
-#define utf8_reader_error(...) err_.emplace(__VA_ARGS__)
+#define utf8_reader_error(...) err_.emplace(__VA_ARGS__)
#define utf8_reader_return_after_error(...) return __VA_ARGS__
-#define utf8_reader_error_check(...) \
- do \
- { \
- if TOML_UNLIKELY(err_) \
- return __VA_ARGS__; \
- } \
- while (false)
+#define utf8_reader_error_check(...) \
+ do { \
+ if TOML_UNLIKELY (err_) return __VA_ARGS__; \
+ } while (false)
#endif
@@ -229,373 +192,312 @@ TOML_ANON_NAMESPACE_START
#define TOML_OVERALIGNED alignas(32)
#endif
- template <typename T>
- class TOML_EMPTY_BASES utf8_reader final : public utf8_reader_interface
- {
- private:
- static constexpr size_t block_capacity = 32;
- utf8_byte_stream<T> stream_;
- source_position next_pos_ = { 1, 1 };
-
- impl::utf8_decoder decoder_;
- struct currently_decoding_t
- {
- char bytes[4];
- size_t count;
- } currently_decoding_;
-
- struct codepoints_t
- {
- TOML_OVERALIGNED utf8_codepoint buffer[block_capacity];
- size_t current;
- size_t count;
- } codepoints_;
-
- source_path_ptr source_path_;
+ template <typename T>
+ class TOML_EMPTY_BASES utf8_reader final : public utf8_reader_interface {
+ private:
+ static constexpr size_t block_capacity = 32;
+ utf8_byte_stream<T> stream_;
+ source_position next_pos_ = {1, 1};
+
+ impl::utf8_decoder decoder_;
+ struct currently_decoding_t {
+ char bytes[4];
+ size_t count;
+ } currently_decoding_;
+
+ struct codepoints_t {
+ TOML_OVERALIGNED utf8_codepoint buffer[block_capacity];
+ size_t current;
+ size_t count;
+ } codepoints_;
+
+ source_path_ptr source_path_;
#if !TOML_EXCEPTIONS
- optional<parse_error> err_;
+ optional<parse_error> err_;
#endif
- bool read_next_block() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
- {
- TOML_ASSERT(stream_);
+ bool read_next_block() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) {
+ TOML_ASSERT(stream_);
- TOML_OVERALIGNED char raw_bytes[block_capacity];
- size_t raw_bytes_read;
+ TOML_OVERALIGNED char raw_bytes[block_capacity];
+ size_t raw_bytes_read;
- // read the next raw (encoded) block in from the stream
- if constexpr (noexcept(stream_(raw_bytes, block_capacity)) || !TOML_EXCEPTIONS)
- {
- raw_bytes_read = stream_(raw_bytes, block_capacity);
- }
+ // read the next raw (encoded) block in from the stream
+ if constexpr (noexcept(stream_(raw_bytes, block_capacity)) || !TOML_EXCEPTIONS) {
+ raw_bytes_read = stream_(raw_bytes, block_capacity);
+ }
#if TOML_EXCEPTIONS
- else
- {
- try
- {
- raw_bytes_read = stream_(raw_bytes, block_capacity);
- }
- catch (const std::exception& exc)
- {
- throw parse_error{ exc.what(), next_pos_, source_path_ };
- }
- catch (...)
- {
- throw parse_error{ "An unspecified error occurred", next_pos_, source_path_ };
- }
- }
-#endif // TOML_EXCEPTIONS
-
- // handle a zero-byte read
- if TOML_UNLIKELY(!raw_bytes_read)
- {
- if (stream_.eof())
- {
- // EOF only sets the error state if the decoder wants more input, otherwise
- // a zero-byte read might have just caused the underlying stream to realize it's exhaused and set
- // the EOF flag, and that's totally fine
- if (decoder_.needs_more_input())
- utf8_reader_error("Encountered EOF during incomplete utf-8 code point sequence",
- next_pos_,
- source_path_);
- }
- else
- {
- utf8_reader_error("Reading from the underlying stream failed - zero bytes read",
- next_pos_,
- source_path_);
- }
- return false;
- }
-
- TOML_ASSERT_ASSUME(raw_bytes_read);
- std::memset(&codepoints_, 0, sizeof(codepoints_));
-
- // helper for calculating decoded codepoint line+cols
- const auto calc_positions = [&]() noexcept
- {
- for (size_t i = 0; i < codepoints_.count; i++)
- {
- auto& cp = codepoints_.buffer[i];
- cp.position = next_pos_;
-
- if (cp == U'\n')
- {
- next_pos_.line++;
- next_pos_.column = source_index{ 1 };
- }
- else
- next_pos_.column++;
- }
- };
-
- // decide whether we need to use the UTF-8 decoder or if we can treat this block as plain ASCII
- const auto ascii_fast_path = !decoder_.needs_more_input() && impl::is_ascii(raw_bytes, raw_bytes_read);
-
- // ASCII fast-path
- if (ascii_fast_path)
- {
- decoder_.reset();
- currently_decoding_.count = {};
-
- codepoints_.count = raw_bytes_read;
- for (size_t i = 0; i < codepoints_.count; i++)
- {
- auto& cp = codepoints_.buffer[i];
- cp.value = static_cast<char32_t>(raw_bytes[i]);
- cp.bytes[0] = raw_bytes[i];
- cp.count = 1u;
- }
- }
-
- // UTF-8 slow-path
- else
- {
- // helper for getting precise error location
- const auto error_pos = [&]() noexcept -> const source_position&
- { //
- return codepoints_.count ? codepoints_.buffer[codepoints_.count - 1u].position : next_pos_;
- };
-
- for (size_t i = 0; i < raw_bytes_read; i++)
- {
- decoder_(static_cast<uint8_t>(raw_bytes[i]));
- if TOML_UNLIKELY(decoder_.error())
- {
- calc_positions();
- utf8_reader_error("Encountered invalid utf-8 sequence", error_pos(), source_path_);
- utf8_reader_return_after_error(false);
- }
-
- currently_decoding_.bytes[currently_decoding_.count++] = raw_bytes[i];
-
- if (decoder_.has_code_point())
- {
- auto& cp = codepoints_.buffer[codepoints_.count++];
-
- cp.value = decoder_.codepoint;
- cp.count = currently_decoding_.count;
- std::memcpy(cp.bytes, currently_decoding_.bytes, currently_decoding_.count);
- currently_decoding_.count = {};
- }
- else if TOML_UNLIKELY(currently_decoding_.count == 4u)
- {
- calc_positions();
- utf8_reader_error("Encountered overlong utf-8 sequence", error_pos(), source_path_);
- utf8_reader_return_after_error(false);
- }
- }
- if TOML_UNLIKELY(decoder_.needs_more_input() && stream_.eof())
- {
- calc_positions();
- utf8_reader_error("Encountered EOF during incomplete utf-8 code point sequence",
- error_pos(),
- source_path_);
- utf8_reader_return_after_error(false);
- }
- }
-
- TOML_ASSERT_ASSUME(codepoints_.count);
- calc_positions();
-
- // handle general I/O errors
- // (down here so the next_pos_ benefits from calc_positions())
- if TOML_UNLIKELY(stream_.error())
- {
- utf8_reader_error("An I/O error occurred while reading from the underlying stream",
- next_pos_,
- source_path_);
- utf8_reader_return_after_error(false);
- }
-
- return true;
- }
-
- public:
- template <typename U, typename String = std::string_view>
- TOML_NODISCARD_CTOR
- explicit utf8_reader(U&& source, String&& source_path = {}) noexcept(
- std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
- : stream_{ static_cast<U&&>(source) }
- {
- currently_decoding_.count = {};
-
- codepoints_.current = {};
- codepoints_.count = {};
-
- if (!source_path.empty())
- source_path_ = std::make_shared<const std::string>(static_cast<String&&>(source_path));
- }
-
- TOML_PURE_INLINE_GETTER
- const source_path_ptr& source_path() const noexcept final
- {
- return source_path_;
- }
-
- TOML_NODISCARD
- const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
- {
- utf8_reader_error_check({});
-
- if (codepoints_.current == codepoints_.count)
- {
- if TOML_UNLIKELY(!stream_ || !read_next_block())
- return nullptr;
-
- TOML_ASSERT_ASSUME(!codepoints_.current);
- }
- TOML_ASSERT_ASSUME(codepoints_.count);
- TOML_ASSERT_ASSUME(codepoints_.count <= block_capacity);
- TOML_ASSERT_ASSUME(codepoints_.current < codepoints_.count);
-
- return &codepoints_.buffer[codepoints_.current++];
- }
-
- TOML_NODISCARD
- bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
- {
- return stream_.peek_eof();
- }
+ else {
+ try {
+ raw_bytes_read = stream_(raw_bytes, block_capacity);
+ } catch (const std::exception& exc) {
+ throw parse_error{exc.what(), next_pos_, source_path_};
+ } catch (...) {
+ throw parse_error{"An unspecified error occurred", next_pos_, source_path_};
+ }
+ }
+#endif // TOML_EXCEPTIONS
+
+ // handle a zero-byte read
+ if TOML_UNLIKELY (!raw_bytes_read) {
+ if (stream_.eof()) {
+ // EOF only sets the error state if the decoder wants more input, otherwise
+ // a zero-byte read might have just caused the underlying stream to realize it's exhaused
+ // and set the EOF flag, and that's totally fine
+ if (decoder_.needs_more_input())
+ utf8_reader_error("Encountered EOF during incomplete utf-8 code point sequence",
+ next_pos_, source_path_);
+ } else {
+ utf8_reader_error("Reading from the underlying stream failed - zero bytes read",
+ next_pos_, source_path_);
+ }
+ return false;
+ }
+
+ TOML_ASSERT_ASSUME(raw_bytes_read);
+ std::memset(&codepoints_, 0, sizeof(codepoints_));
+
+ // helper for calculating decoded codepoint line+cols
+ const auto calc_positions = [&]() noexcept {
+ for (size_t i = 0; i < codepoints_.count; i++) {
+ auto& cp = codepoints_.buffer[i];
+ cp.position = next_pos_;
+
+ if (cp == U'\n') {
+ next_pos_.line++;
+ next_pos_.column = source_index{1};
+ } else
+ next_pos_.column++;
+ }
+ };
+
+ // decide whether we need to use the UTF-8 decoder or if we can treat this block as plain
+ // ASCII
+ const auto ascii_fast_path =
+ !decoder_.needs_more_input() && impl::is_ascii(raw_bytes, raw_bytes_read);
+
+ // ASCII fast-path
+ if (ascii_fast_path) {
+ decoder_.reset();
+ currently_decoding_.count = {};
+
+ codepoints_.count = raw_bytes_read;
+ for (size_t i = 0; i < codepoints_.count; i++) {
+ auto& cp = codepoints_.buffer[i];
+ cp.value = static_cast<char32_t>(raw_bytes[i]);
+ cp.bytes[0] = raw_bytes[i];
+ cp.count = 1u;
+ }
+ }
+
+ // UTF-8 slow-path
+ else {
+ // helper for getting precise error location
+ const auto error_pos = [&]() noexcept -> const source_position& { //
+ return codepoints_.count ? codepoints_.buffer[codepoints_.count - 1u].position
+ : next_pos_;
+ };
+
+ for (size_t i = 0; i < raw_bytes_read; i++) {
+ decoder_(static_cast<uint8_t>(raw_bytes[i]));
+ if TOML_UNLIKELY (decoder_.error()) {
+ calc_positions();
+ utf8_reader_error("Encountered invalid utf-8 sequence", error_pos(), source_path_);
+ utf8_reader_return_after_error(false);
+ }
+
+ currently_decoding_.bytes[currently_decoding_.count++] = raw_bytes[i];
+
+ if (decoder_.has_code_point()) {
+ auto& cp = codepoints_.buffer[codepoints_.count++];
+
+ cp.value = decoder_.codepoint;
+ cp.count = currently_decoding_.count;
+ std::memcpy(cp.bytes, currently_decoding_.bytes, currently_decoding_.count);
+ currently_decoding_.count = {};
+ } else if TOML_UNLIKELY (currently_decoding_.count == 4u) {
+ calc_positions();
+ utf8_reader_error("Encountered overlong utf-8 sequence", error_pos(), source_path_);
+ utf8_reader_return_after_error(false);
+ }
+ }
+ if TOML_UNLIKELY (decoder_.needs_more_input() && stream_.eof()) {
+ calc_positions();
+ utf8_reader_error("Encountered EOF during incomplete utf-8 code point sequence",
+ error_pos(), source_path_);
+ utf8_reader_return_after_error(false);
+ }
+ }
+
+ TOML_ASSERT_ASSUME(codepoints_.count);
+ calc_positions();
+
+ // handle general I/O errors
+ // (down here so the next_pos_ benefits from calc_positions())
+ if TOML_UNLIKELY (stream_.error()) {
+ utf8_reader_error("An I/O error occurred while reading from the underlying stream",
+ next_pos_, source_path_);
+ utf8_reader_return_after_error(false);
+ }
+
+ return true;
+ }
+
+ public:
+ template <typename U, typename String = std::string_view>
+ TOML_NODISCARD_CTOR explicit utf8_reader(U&& source, String&& source_path = {}) noexcept(
+ std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
+ : stream_{static_cast<U&&>(source)} {
+ currently_decoding_.count = {};
+
+ codepoints_.current = {};
+ codepoints_.count = {};
+
+ if (!source_path.empty())
+ source_path_ = std::make_shared<const std::string>(static_cast<String&&>(source_path));
+ }
+
+ TOML_PURE_INLINE_GETTER
+ const source_path_ptr& source_path() const noexcept final { return source_path_; }
+
+ TOML_NODISCARD
+ const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final {
+ utf8_reader_error_check({});
+
+ if (codepoints_.current == codepoints_.count) {
+ if TOML_UNLIKELY (!stream_ || !read_next_block()) return nullptr;
+
+ TOML_ASSERT_ASSUME(!codepoints_.current);
+ }
+ TOML_ASSERT_ASSUME(codepoints_.count);
+ TOML_ASSERT_ASSUME(codepoints_.count <= block_capacity);
+ TOML_ASSERT_ASSUME(codepoints_.current < codepoints_.count);
+
+ return &codepoints_.buffer[codepoints_.current++];
+ }
+
+ TOML_NODISCARD
+ bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final {
+ return stream_.peek_eof();
+ }
#if !TOML_EXCEPTIONS
- TOML_NODISCARD
- optional<parse_error>&& error() noexcept final
- {
- return std::move(err_);
- }
+ TOML_NODISCARD
+ optional<parse_error>&& error() noexcept final { return std::move(err_); }
#endif
- };
-
- template <typename Char>
- utf8_reader(std::basic_string_view<Char>, std::string_view) -> utf8_reader<std::basic_string_view<Char>>;
- template <typename Char>
- utf8_reader(std::basic_string_view<Char>, std::string&&) -> utf8_reader<std::basic_string_view<Char>>;
- template <typename Char>
- utf8_reader(std::basic_istream<Char>&, std::string_view) -> utf8_reader<std::basic_istream<Char>>;
- template <typename Char>
- utf8_reader(std::basic_istream<Char>&, std::string&&) -> utf8_reader<std::basic_istream<Char>>;
+ };
+
+ template <typename Char>
+ utf8_reader(std::basic_string_view<Char>,
+ std::string_view) -> utf8_reader<std::basic_string_view<Char>>;
+ template <typename Char>
+ utf8_reader(std::basic_string_view<Char>,
+ std::string&&) -> utf8_reader<std::basic_string_view<Char>>;
+ template <typename Char>
+ utf8_reader(std::basic_istream<Char>&, std::string_view) -> utf8_reader<std::basic_istream<Char>>;
+ template <typename Char>
+ utf8_reader(std::basic_istream<Char>&, std::string&&) -> utf8_reader<std::basic_istream<Char>>;
#if TOML_EXCEPTIONS
#define utf8_buffered_reader_error_check(...) static_assert(true)
#else
-#define utf8_buffered_reader_error_check(...) \
- do \
- { \
- if TOML_UNLIKELY(reader_.error()) \
- return __VA_ARGS__; \
- } \
- while (false)
+#define utf8_buffered_reader_error_check(...) \
+ do { \
+ if TOML_UNLIKELY (reader_.error()) return __VA_ARGS__; \
+ } while (false)
#endif
- class TOML_EMPTY_BASES utf8_buffered_reader
- {
- public:
- static constexpr size_t max_history_length = 128;
-
- private:
- static constexpr size_t history_buffer_size = max_history_length - 1; //'head' is stored in the reader
- utf8_reader_interface& reader_;
- struct
- {
- utf8_codepoint buffer[history_buffer_size];
- size_t count, first;
- } history_ = {};
- const utf8_codepoint* head_ = {};
- size_t negative_offset_ = {};
-
- public:
- TOML_NODISCARD_CTOR
- explicit utf8_buffered_reader(utf8_reader_interface& reader) noexcept //
- : reader_{ reader }
- {}
-
- TOML_PURE_INLINE_GETTER
- const source_path_ptr& source_path() const noexcept
- {
- return reader_.source_path();
- }
-
- TOML_NODISCARD
- const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
- {
- utf8_buffered_reader_error_check({});
-
- if (negative_offset_)
- {
- negative_offset_--;
-
- // an entry negative offset of 1 just means "replay the current head"
- if (!negative_offset_)
- return head_;
-
- // otherwise step back into the history buffer
- else
- return history_.buffer
- + ((history_.first + history_.count - negative_offset_) % history_buffer_size);
- }
- else
- {
- // first character read from stream
- if TOML_UNLIKELY(!history_.count && !head_)
- head_ = reader_.read_next();
-
- // subsequent characters and not eof
- else if (head_)
- {
- if TOML_UNLIKELY(history_.count < history_buffer_size)
- history_.buffer[history_.count++] = *head_;
- else
- history_.buffer[(history_.first++ + history_buffer_size) % history_buffer_size] = *head_;
-
- head_ = reader_.read_next();
- }
-
- return head_;
- }
- }
-
- TOML_NODISCARD
- const utf8_codepoint* step_back(size_t count) noexcept
- {
- utf8_buffered_reader_error_check({});
-
- TOML_ASSERT_ASSUME(history_.count);
- TOML_ASSERT_ASSUME(negative_offset_ + count <= history_.count);
-
- negative_offset_ += count;
-
- return negative_offset_
- ? history_.buffer + ((history_.first + history_.count - negative_offset_) % history_buffer_size)
- : head_;
- }
-
- TOML_NODISCARD
- bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
- {
- return reader_.peek_eof();
- }
+ class TOML_EMPTY_BASES utf8_buffered_reader {
+ public:
+ static constexpr size_t max_history_length = 128;
+
+ private:
+ static constexpr size_t history_buffer_size =
+ max_history_length - 1; //'head' is stored in the reader
+ utf8_reader_interface& reader_;
+ struct {
+ utf8_codepoint buffer[history_buffer_size];
+ size_t count, first;
+ } history_ = {};
+ const utf8_codepoint* head_ = {};
+ size_t negative_offset_ = {};
+
+ public:
+ TOML_NODISCARD_CTOR
+ explicit utf8_buffered_reader(utf8_reader_interface& reader) noexcept //
+ : reader_{reader} {}
+
+ TOML_PURE_INLINE_GETTER
+ const source_path_ptr& source_path() const noexcept { return reader_.source_path(); }
+
+ TOML_NODISCARD
+ const utf8_codepoint* read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) {
+ utf8_buffered_reader_error_check({});
+
+ if (negative_offset_) {
+ negative_offset_--;
+
+ // an entry negative offset of 1 just means "replay the current head"
+ if (!negative_offset_) return head_;
+
+ // otherwise step back into the history buffer
+ else
+ return history_.buffer +
+ ((history_.first + history_.count - negative_offset_) % history_buffer_size);
+ } else {
+ // first character read from stream
+ if TOML_UNLIKELY (!history_.count && !head_) head_ = reader_.read_next();
+
+ // subsequent characters and not eof
+ else if (head_) {
+ if TOML_UNLIKELY (history_.count < history_buffer_size)
+ history_.buffer[history_.count++] = *head_;
+ else
+ history_.buffer[(history_.first++ + history_buffer_size) % history_buffer_size] =
+ *head_;
+
+ head_ = reader_.read_next();
+ }
+
+ return head_;
+ }
+ }
+
+ TOML_NODISCARD
+ const utf8_codepoint* step_back(size_t count) noexcept {
+ utf8_buffered_reader_error_check({});
+
+ TOML_ASSERT_ASSUME(history_.count);
+ TOML_ASSERT_ASSUME(negative_offset_ + count <= history_.count);
+
+ negative_offset_ += count;
+
+ return negative_offset_
+ ? history_.buffer +
+ ((history_.first + history_.count - negative_offset_) % history_buffer_size)
+ : head_;
+ }
+
+ TOML_NODISCARD
+ bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) { return reader_.peek_eof(); }
#if !TOML_EXCEPTIONS
- TOML_NODISCARD
- optional<parse_error>&& error() noexcept
- {
- return reader_.error();
- }
+ TOML_NODISCARD
+ optional<parse_error>&& error() noexcept { return reader_.error(); }
#endif
- };
+ };
}
TOML_ANON_NAMESPACE_END;
-//#---------------------------------------------------------------------------------------------------------------------
-//# PARSER INTERNAL IMPLEMENTATION
-//#---------------------------------------------------------------------------------------------------------------------
+// #---------------------------------------------------------------------------------------------------------------------
+// # PARSER INTERNAL IMPLEMENTATION
+// #---------------------------------------------------------------------------------------------------------------------
#if TOML_EXCEPTIONS
#define TOML_RETURNS_BY_THROWING [[noreturn]]
@@ -603,398 +505,331 @@ TOML_ANON_NAMESPACE_END;
#define TOML_RETURNS_BY_THROWING
#endif
-TOML_ANON_NAMESPACE_START
-{
- template <typename... T>
- TOML_CONST_GETTER
- TOML_INTERNAL_LINKAGE
- constexpr bool is_match(char32_t codepoint, T... vals) noexcept
- {
- static_assert((std::is_same_v<char32_t, T> && ...));
- return ((codepoint == vals) || ...);
- }
-
- template <uint64_t>
- struct parse_integer_traits;
- template <>
- struct parse_integer_traits<2>
- {
- static constexpr auto scope_qualifier = "binary integer"sv;
- static constexpr auto is_digit = impl::is_binary_digit;
- static constexpr auto is_signed = false;
- static constexpr auto max_digits = 63;
- static constexpr auto prefix_codepoint = U'b';
- static constexpr auto prefix = "b"sv;
- static constexpr auto full_prefix = "0b"sv;
- };
- template <>
- struct parse_integer_traits<8>
- {
- static constexpr auto scope_qualifier = "octal integer"sv;
- static constexpr auto is_digit = impl::is_octal_digit;
- static constexpr auto is_signed = false;
- static constexpr auto max_digits = 21; // strlen("777777777777777777777")
- static constexpr auto prefix_codepoint = U'o';
- static constexpr auto prefix = "o"sv;
- static constexpr auto full_prefix = "0o"sv;
- };
- template <>
- struct parse_integer_traits<10>
- {
- static constexpr auto scope_qualifier = "decimal integer"sv;
- static constexpr auto is_digit = impl::is_decimal_digit;
- static constexpr auto is_signed = true;
- static constexpr auto max_digits = 19; // strlen("9223372036854775807")
- static constexpr auto full_prefix = ""sv;
- };
- template <>
- struct parse_integer_traits<16>
- {
- static constexpr auto scope_qualifier = "hexadecimal integer"sv;
- static constexpr auto is_digit = impl::is_hexadecimal_digit;
- static constexpr auto is_signed = false;
- static constexpr auto max_digits = 16; // strlen("7FFFFFFFFFFFFFFF")
- static constexpr auto prefix_codepoint = U'x';
- static constexpr auto prefix = "x"sv;
- static constexpr auto full_prefix = "0x"sv;
- };
-
- TOML_PURE_GETTER
- TOML_INTERNAL_LINKAGE
- std::string_view to_sv(node_type val) noexcept
- {
- return impl::node_type_friendly_names[impl::unwrap_enum(val)];
- }
-
- TOML_PURE_GETTER
- TOML_INTERNAL_LINKAGE
- std::string_view to_sv(const std::string& str) noexcept
- {
- return std::string_view{ str };
- }
-
- TOML_CONST_GETTER
- TOML_INTERNAL_LINKAGE
- std::string_view to_sv(bool val) noexcept
- {
- using namespace std::string_view_literals;
-
- return val ? "true"sv : "false"sv;
- }
-
- TOML_PURE_GETTER
- TOML_INTERNAL_LINKAGE
- std::string_view to_sv(const utf8_codepoint& cp) noexcept
- {
- if (cp.value <= U'\x1F')
- return impl::control_char_escapes[cp.value];
- else if (cp.value == U'\x7F')
- return "\\u007F"sv;
- else
- return std::string_view{ cp.bytes, cp.count };
- }
-
- TOML_PURE_GETTER
- TOML_INTERNAL_LINKAGE
- std::string_view to_sv(const utf8_codepoint* cp) noexcept
- {
- if (cp)
- return to_sv(*cp);
- return ""sv;
- }
-
- struct escaped_codepoint
- {
- const utf8_codepoint& cp;
- };
-
- template <typename T>
- TOML_ATTR(nonnull)
- TOML_INTERNAL_LINKAGE
- void concatenate(char*& write_pos, char* const buf_end, const T& arg) noexcept
- {
- if TOML_UNLIKELY(write_pos >= buf_end)
- return;
-
- using arg_type = impl::remove_cvref<T>;
-
- // string views
- if constexpr (std::is_same_v<arg_type, std::string_view>)
- {
- const auto max_chars = static_cast<size_t>(buf_end - write_pos);
- const auto len = max_chars < arg.length() ? max_chars : arg.length();
- std::memcpy(write_pos, arg.data(), len);
- write_pos += len;
- }
-
- // doubles
- else if constexpr (std::is_same_v<arg_type, double>)
- {
+TOML_ANON_NAMESPACE_START {
+ template <typename... T>
+ TOML_CONST_GETTER TOML_INTERNAL_LINKAGE constexpr bool is_match(char32_t codepoint,
+ T... vals) noexcept {
+ static_assert((std::is_same_v<char32_t, T> && ...));
+ return ((codepoint == vals) || ...);
+ }
+
+ template <uint64_t>
+ struct parse_integer_traits;
+ template <>
+ struct parse_integer_traits<2> {
+ static constexpr auto scope_qualifier = "binary integer"sv;
+ static constexpr auto is_digit = impl::is_binary_digit;
+ static constexpr auto is_signed = false;
+ static constexpr auto max_digits = 63;
+ static constexpr auto prefix_codepoint = U'b';
+ static constexpr auto prefix = "b"sv;
+ static constexpr auto full_prefix = "0b"sv;
+ };
+ template <>
+ struct parse_integer_traits<8> {
+ static constexpr auto scope_qualifier = "octal integer"sv;
+ static constexpr auto is_digit = impl::is_octal_digit;
+ static constexpr auto is_signed = false;
+ static constexpr auto max_digits = 21; // strlen("777777777777777777777")
+ static constexpr auto prefix_codepoint = U'o';
+ static constexpr auto prefix = "o"sv;
+ static constexpr auto full_prefix = "0o"sv;
+ };
+ template <>
+ struct parse_integer_traits<10> {
+ static constexpr auto scope_qualifier = "decimal integer"sv;
+ static constexpr auto is_digit = impl::is_decimal_digit;
+ static constexpr auto is_signed = true;
+ static constexpr auto max_digits = 19; // strlen("9223372036854775807")
+ static constexpr auto full_prefix = ""sv;
+ };
+ template <>
+ struct parse_integer_traits<16> {
+ static constexpr auto scope_qualifier = "hexadecimal integer"sv;
+ static constexpr auto is_digit = impl::is_hexadecimal_digit;
+ static constexpr auto is_signed = false;
+ static constexpr auto max_digits = 16; // strlen("7FFFFFFFFFFFFFFF")
+ static constexpr auto prefix_codepoint = U'x';
+ static constexpr auto prefix = "x"sv;
+ static constexpr auto full_prefix = "0x"sv;
+ };
+
+ TOML_PURE_GETTER
+ TOML_INTERNAL_LINKAGE
+ std::string_view to_sv(node_type val) noexcept {
+ return impl::node_type_friendly_names[impl::unwrap_enum(val)];
+ }
+
+ TOML_PURE_GETTER
+ TOML_INTERNAL_LINKAGE
+ std::string_view to_sv(const std::string& str) noexcept {
+ return std::string_view{str};
+ }
+
+ TOML_CONST_GETTER
+ TOML_INTERNAL_LINKAGE
+ std::string_view to_sv(bool val) noexcept {
+ using namespace std::string_view_literals;
+
+ return val ? "true"sv : "false"sv;
+ }
+
+ TOML_PURE_GETTER
+ TOML_INTERNAL_LINKAGE
+ std::string_view to_sv(const utf8_codepoint& cp) noexcept {
+ if (cp.value <= U'\x1F')
+ return impl::control_char_escapes[cp.value];
+ else if (cp.value == U'\x7F')
+ return "\\u007F"sv;
+ else
+ return std::string_view{cp.bytes, cp.count};
+ }
+
+ TOML_PURE_GETTER
+ TOML_INTERNAL_LINKAGE
+ std::string_view to_sv(const utf8_codepoint* cp) noexcept {
+ if (cp) return to_sv(*cp);
+ return ""sv;
+ }
+
+ struct escaped_codepoint {
+ const utf8_codepoint& cp;
+ };
+
+ template <typename T>
+ TOML_ATTR(nonnull)
+ TOML_INTERNAL_LINKAGE void concatenate(char*& write_pos, char* const buf_end,
+ const T& arg) noexcept {
+ if TOML_UNLIKELY (write_pos >= buf_end) return;
+
+ using arg_type = impl::remove_cvref<T>;
+
+ // string views
+ if constexpr (std::is_same_v<arg_type, std::string_view>) {
+ const auto max_chars = static_cast<size_t>(buf_end - write_pos);
+ const auto len = max_chars < arg.length() ? max_chars : arg.length();
+ std::memcpy(write_pos, arg.data(), len);
+ write_pos += len;
+ }
+
+ // doubles
+ else if constexpr (std::is_same_v<arg_type, double>) {
#if TOML_FLOAT_CHARCONV
- const auto result = std::to_chars(write_pos, buf_end, arg);
- write_pos = result.ptr;
+ const auto result = std::to_chars(write_pos, buf_end, arg);
+ write_pos = result.ptr;
#else
- std::ostringstream ss;
- ss.imbue(std::locale::classic());
- ss.precision(std::numeric_limits<arg_type>::max_digits10);
- ss << arg;
- concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
+ std::ostringstream ss;
+ ss.imbue(std::locale::classic());
+ ss.precision(std::numeric_limits<arg_type>::max_digits10);
+ ss << arg;
+ concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
#endif
- }
+ }
- // 64-bit integers
- else if constexpr (impl::is_one_of<arg_type, int64_t, uint64_t>)
- {
+ // 64-bit integers
+ else if constexpr (impl::is_one_of<arg_type, int64_t, uint64_t>) {
#if TOML_INT_CHARCONV
- const auto result = std::to_chars(write_pos, buf_end, arg);
- write_pos = result.ptr;
+ const auto result = std::to_chars(write_pos, buf_end, arg);
+ write_pos = result.ptr;
#else
- std::ostringstream ss;
- ss.imbue(std::locale::classic());
- using cast_type = std::conditional_t<std::is_signed_v<arg_type>, int64_t, uint64_t>;
- ss << static_cast<cast_type>(arg);
- concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
+ std::ostringstream ss;
+ ss.imbue(std::locale::classic());
+ using cast_type = std::conditional_t<std::is_signed_v<arg_type>, int64_t, uint64_t>;
+ ss << static_cast<cast_type>(arg);
+ concatenate(write_pos, buf_end, to_sv(std::move(ss).str()));
#endif
- }
-
- // escaped_codepoint
- else if constexpr (std::is_same_v<arg_type, escaped_codepoint>)
- {
- if (arg.cp.value <= U'\x7F')
- concatenate(write_pos, buf_end, to_sv(arg.cp));
- else
- {
- auto val = static_cast<uint_least32_t>(arg.cp.value);
- const auto digits = val > 0xFFFFu ? 8u : 4u;
- constexpr auto mask = uint_least32_t{ 0xFu };
- char buf[10] = { '\\', digits > 4 ? 'U' : 'u' };
- for (auto i = 2u + digits; i-- > 2u;)
- {
- const auto hexdig = val & mask;
- buf[i] = static_cast<char>(hexdig >= 0xAu ? ('A' + (hexdig - 0xAu)) : ('0' + hexdig));
- val >>= 4;
- }
- concatenate(write_pos, buf_end, std::string_view{ buf, digits + 2u });
- }
- }
-
- // all other floats (fallback - coerce to double)
- else if constexpr (std::is_floating_point_v<arg_type>)
- concatenate(write_pos, buf_end, static_cast<double>(arg));
-
- // all other integers (fallback - coerce to (u)int64_t)
- else if constexpr (std::is_arithmetic_v<arg_type> && std::is_integral_v<arg_type>)
- {
- using cast_type = std::conditional_t<std::is_unsigned_v<arg_type>, uint64_t, int64_t>;
- concatenate(write_pos, buf_end, static_cast<cast_type>(arg));
- }
-
- else
- {
- static_assert(
- impl::always_false<T>,
- "concatenate() inputs are limited to std::string_views, integers, floats, and escaped_codepoint");
- }
- }
-
- struct error_builder
- {
- static constexpr std::size_t buf_size = 512;
- char buf[buf_size];
- char* write_pos = buf;
- char* const max_write_pos = buf + (buf_size - std::size_t{ 1 }); // allow for null terminator
-
- TOML_NODISCARD_CTOR
- error_builder(std::string_view scope) noexcept
- {
- concatenate(write_pos, max_write_pos, "Error while parsing "sv);
- concatenate(write_pos, max_write_pos, scope);
- concatenate(write_pos, max_write_pos, ": "sv);
- }
-
- template <typename T>
- void append(const T& arg) noexcept
- {
- concatenate(write_pos, max_write_pos, arg);
- }
-
- TOML_RETURNS_BY_THROWING
- auto finish(const source_position& pos, const source_path_ptr& source_path) const
- {
- *write_pos = '\0';
+ }
+
+ // escaped_codepoint
+ else if constexpr (std::is_same_v<arg_type, escaped_codepoint>) {
+ if (arg.cp.value <= U'\x7F')
+ concatenate(write_pos, buf_end, to_sv(arg.cp));
+ else {
+ auto val = static_cast<uint_least32_t>(arg.cp.value);
+ const auto digits = val > 0xFFFFu ? 8u : 4u;
+ constexpr auto mask = uint_least32_t{0xFu};
+ char buf[10] = {'\\', digits > 4 ? 'U' : 'u'};
+ for (auto i = 2u + digits; i-- > 2u;) {
+ const auto hexdig = val & mask;
+ buf[i] = static_cast<char>(hexdig >= 0xAu ? ('A' + (hexdig - 0xAu)) : ('0' + hexdig));
+ val >>= 4;
+ }
+ concatenate(write_pos, buf_end, std::string_view{buf, digits + 2u});
+ }
+ }
+
+ // all other floats (fallback - coerce to double)
+ else if constexpr (std::is_floating_point_v<arg_type>)
+ concatenate(write_pos, buf_end, static_cast<double>(arg));
+
+ // all other integers (fallback - coerce to (u)int64_t)
+ else if constexpr (std::is_arithmetic_v<arg_type> && std::is_integral_v<arg_type>) {
+ using cast_type = std::conditional_t<std::is_unsigned_v<arg_type>, uint64_t, int64_t>;
+ concatenate(write_pos, buf_end, static_cast<cast_type>(arg));
+ }
+
+ else {
+ static_assert(impl::always_false<T>,
+ "concatenate() inputs are limited to std::string_views, integers, floats, and "
+ "escaped_codepoint");
+ }
+ }
+
+ struct error_builder {
+ static constexpr std::size_t buf_size = 512;
+ char buf[buf_size];
+ char* write_pos = buf;
+ char* const max_write_pos = buf + (buf_size - std::size_t{1}); // allow for null terminator
+
+ TOML_NODISCARD_CTOR
+ error_builder(std::string_view scope) noexcept {
+ concatenate(write_pos, max_write_pos, "Error while parsing "sv);
+ concatenate(write_pos, max_write_pos, scope);
+ concatenate(write_pos, max_write_pos, ": "sv);
+ }
+
+ template <typename T>
+ void append(const T& arg) noexcept {
+ concatenate(write_pos, max_write_pos, arg);
+ }
+
+ TOML_RETURNS_BY_THROWING
+ auto finish(const source_position& pos, const source_path_ptr& source_path) const {
+ *write_pos = '\0';
#if TOML_EXCEPTIONS
- throw parse_error{ buf, pos, source_path };
+ throw parse_error{buf, pos, source_path};
#else
- return parse_error{ std::string(buf, static_cast<size_t>(write_pos - buf)), pos, source_path };
+ return parse_error{std::string(buf, static_cast<size_t>(write_pos - buf)), pos, source_path};
#endif
- }
-
- TOML_DELETE_DEFAULTS(error_builder);
- };
-
- struct parse_scope
- {
- std::string_view& storage_;
- std::string_view parent_;
-
- TOML_NODISCARD_CTOR
- explicit parse_scope(std::string_view& current_scope, std::string_view new_scope) noexcept
- : storage_{ current_scope },
- parent_{ current_scope }
- {
- storage_ = new_scope;
- }
-
- ~parse_scope() noexcept
- {
- storage_ = parent_;
- }
-
- TOML_DELETE_DEFAULTS(parse_scope);
- };
+ }
+
+ TOML_DELETE_DEFAULTS(error_builder);
+ };
+
+ struct parse_scope {
+ std::string_view& storage_;
+ std::string_view parent_;
+
+ TOML_NODISCARD_CTOR
+ explicit parse_scope(std::string_view& current_scope, std::string_view new_scope) noexcept
+ : storage_{current_scope}, parent_{current_scope} {
+ storage_ = new_scope;
+ }
+
+ ~parse_scope() noexcept { storage_ = parent_; }
+
+ TOML_DELETE_DEFAULTS(parse_scope);
+ };
#define push_parse_scope_2(scope, line) parse_scope ps_##line(current_scope, scope)
#define push_parse_scope_1(scope, line) push_parse_scope_2(scope, line)
-#define push_parse_scope(scope) push_parse_scope_1(scope, __LINE__)
-
- struct parse_key_buffer
- {
- std::string buffer;
- std::vector<std::pair<size_t, size_t>> segments;
- std::vector<source_position> starts;
- std::vector<source_position> ends;
-
- void clear() noexcept
- {
- buffer.clear();
- segments.clear();
- starts.clear();
- ends.clear();
- }
-
- void push_back(std::string_view segment, source_position b, source_position e)
- {
- segments.push_back({ buffer.length(), segment.length() });
- buffer.append(segment);
- starts.push_back(b);
- ends.push_back(e);
- }
-
- TOML_PURE_INLINE_GETTER
- std::string_view operator[](size_t i) const noexcept
- {
- return std::string_view{ buffer.c_str() + segments[i].first, segments[i].second };
- }
-
- TOML_PURE_INLINE_GETTER
- std::string_view back() const noexcept
- {
- return (*this)[segments.size() - 1u];
- }
-
- TOML_PURE_INLINE_GETTER
- bool empty() const noexcept
- {
- return segments.empty();
- }
-
- TOML_PURE_INLINE_GETTER
- size_t size() const noexcept
- {
- return segments.size();
- }
- };
-
- struct depth_counter_scope
- {
- size_t& depth_;
-
- TOML_NODISCARD_CTOR
- explicit depth_counter_scope(size_t& depth) noexcept //
- : depth_{ depth }
- {
- depth_++;
- }
-
- ~depth_counter_scope() noexcept
- {
- depth_--;
- }
-
- TOML_DELETE_DEFAULTS(depth_counter_scope);
- };
-
- struct parsed_string
- {
- std::string_view value;
- bool was_multi_line;
- };
-
- struct table_vector_scope
- {
- std::vector<table*>& tables;
-
- TOML_NODISCARD_CTOR
- explicit table_vector_scope(std::vector<table*>& tables_, table& tbl) //
- : tables{ tables_ }
- {
- tables.push_back(&tbl);
- }
-
- ~table_vector_scope() noexcept
- {
- tables.pop_back();
- }
-
- TOML_DELETE_DEFAULTS(table_vector_scope);
- };
+#define push_parse_scope(scope) push_parse_scope_1(scope, __LINE__)
+
+ struct parse_key_buffer {
+ std::string buffer;
+ std::vector<std::pair<size_t, size_t>> segments;
+ std::vector<source_position> starts;
+ std::vector<source_position> ends;
+
+ void clear() noexcept {
+ buffer.clear();
+ segments.clear();
+ starts.clear();
+ ends.clear();
+ }
+
+ void push_back(std::string_view segment, source_position b, source_position e) {
+ segments.push_back({buffer.length(), segment.length()});
+ buffer.append(segment);
+ starts.push_back(b);
+ ends.push_back(e);
+ }
+
+ TOML_PURE_INLINE_GETTER
+ std::string_view operator[](size_t i) const noexcept {
+ return std::string_view{buffer.c_str() + segments[i].first, segments[i].second};
+ }
+
+ TOML_PURE_INLINE_GETTER
+ std::string_view back() const noexcept { return (*this)[segments.size() - 1u]; }
+
+ TOML_PURE_INLINE_GETTER
+ bool empty() const noexcept { return segments.empty(); }
+
+ TOML_PURE_INLINE_GETTER
+ size_t size() const noexcept { return segments.size(); }
+ };
+
+ struct depth_counter_scope {
+ size_t& depth_;
+
+ TOML_NODISCARD_CTOR
+ explicit depth_counter_scope(size_t& depth) noexcept //
+ : depth_{depth} {
+ depth_++;
+ }
+
+ ~depth_counter_scope() noexcept { depth_--; }
+
+ TOML_DELETE_DEFAULTS(depth_counter_scope);
+ };
+
+ struct parsed_string {
+ std::string_view value;
+ bool was_multi_line;
+ };
+
+ struct table_vector_scope {
+ std::vector<table*>& tables;
+
+ TOML_NODISCARD_CTOR
+ explicit table_vector_scope(std::vector<table*>& tables_, table& tbl) //
+ : tables{tables_} {
+ tables.push_back(&tbl);
+ }
+
+ ~table_vector_scope() noexcept { tables.pop_back(); }
+
+ TOML_DELETE_DEFAULTS(table_vector_scope);
+ };
}
TOML_ANON_NAMESPACE_END;
-#if 1 // parser helper macros
+#if 1 // parser helper macros
// Q: "what the fuck is this? MACROS????"
// A: The parser needs to work in exceptionless mode (returning error objects directly)
-// and exception mode (reporting parse failures by throwing). Two totally different control flows.
-// These macros encapsulate the differences between the two modes so I can write code code
+// and exception mode (reporting parse failures by throwing). Two totally different control
+// flows. These macros encapsulate the differences between the two modes so I can write code code
// as though I was only targeting one mode and not want yeet myself into the sun.
-// They're all #undef'd at the bottom of the parser's implementation so they should be harmless outside
-// of toml++.
+// They're all #undef'd at the bottom of the parser's implementation so they should be harmless
+// outside of toml++.
-#define is_eof() !cp
+#define is_eof() !cp
#define assert_not_eof() TOML_ASSERT_ASSUME(cp != nullptr)
-#define return_if_eof(...) \
- do \
- { \
- if TOML_UNLIKELY(is_eof()) \
- return __VA_ARGS__; \
- } \
- while (false)
+#define return_if_eof(...) \
+ do { \
+ if TOML_UNLIKELY (is_eof()) return __VA_ARGS__; \
+ } while (false)
#if TOML_EXCEPTIONS
-#define is_error() false
-#define return_after_error(...) TOML_UNREACHABLE
-#define assert_not_error() static_assert(true)
-#define return_if_error(...) static_assert(true)
+#define is_error() false
+#define return_after_error(...) TOML_UNREACHABLE
+#define assert_not_error() static_assert(true)
+#define return_if_error(...) static_assert(true)
#define return_if_error_or_eof(...) return_if_eof(__VA_ARGS__)
#else
-#define is_error() !!err
+#define is_error() !!err
#define return_after_error(...) return __VA_ARGS__
-#define assert_not_error() TOML_ASSERT(!is_error())
-#define return_if_error(...) \
- do \
- { \
- if TOML_UNLIKELY(is_error()) \
- return __VA_ARGS__; \
- } \
- while (false)
-#define return_if_error_or_eof(...) \
- do \
- { \
- if TOML_UNLIKELY(is_eof() || is_error()) \
- return __VA_ARGS__; \
- } \
- while (false)
+#define assert_not_error() TOML_ASSERT(!is_error())
+#define return_if_error(...) \
+ do { \
+ if TOML_UNLIKELY (is_error()) return __VA_ARGS__; \
+ } while (false)
+#define return_if_error_or_eof(...) \
+ do { \
+ if TOML_UNLIKELY (is_eof() || is_error()) return __VA_ARGS__; \
+ } while (false)
#endif
#if defined(TOML_BREAK_AT_PARSE_ERRORS) && TOML_BREAK_AT_PARSE_ERRORS
@@ -1016,2711 +851,2483 @@ TOML_ANON_NAMESPACE_END;
#define parse_error_break() static_assert(true)
#endif
-#define set_error_and_return(ret, ...) \
- do \
- { \
- if (!is_error()) \
- set_error(__VA_ARGS__); \
- return_after_error(ret); \
- } \
- while (false)
+#define set_error_and_return(ret, ...) \
+ do { \
+ if (!is_error()) set_error(__VA_ARGS__); \
+ return_after_error(ret); \
+ } while (false)
#define set_error_and_return_default(...) set_error_and_return({}, __VA_ARGS__)
-#define set_error_and_return_if_eof(...) \
- do \
- { \
- if TOML_UNLIKELY(is_eof()) \
- set_error_and_return(__VA_ARGS__, "encountered end-of-file"sv); \
- } \
- while (false)
-
-#define advance_and_return_if_error(...) \
- do \
- { \
- assert_not_eof(); \
- advance(); \
- return_if_error(__VA_ARGS__); \
- } \
- while (false)
-
-#define advance_and_return_if_error_or_eof(...) \
- do \
- { \
- assert_not_eof(); \
- advance(); \
- return_if_error(__VA_ARGS__); \
- set_error_and_return_if_eof(__VA_ARGS__); \
- } \
- while (false)
-
-#endif // parser helper macros
-
-TOML_IMPL_NAMESPACE_START
-{
- TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex);
-
- class parser
- {
- private:
- static constexpr size_t max_nested_values = TOML_MAX_NESTED_VALUES;
-
- utf8_buffered_reader reader;
- table root;
- source_position prev_pos = { 1, 1 };
- const utf8_codepoint* cp = {};
- std::vector<table*> implicit_tables;
- std::vector<table*> dotted_key_tables;
- std::vector<table*> open_inline_tables;
- std::vector<array*> table_arrays;
- parse_key_buffer key_buffer;
- std::string string_buffer;
- std::string recording_buffer; // for diagnostics
- bool recording = false, recording_whitespace = true;
- std::string_view current_scope;
- size_t nested_values = {};
+#define set_error_and_return_if_eof(...) \
+ do { \
+ if TOML_UNLIKELY (is_eof()) set_error_and_return(__VA_ARGS__, "encountered end-of-file"sv); \
+ } while (false)
+
+#define advance_and_return_if_error(...) \
+ do { \
+ assert_not_eof(); \
+ advance(); \
+ return_if_error(__VA_ARGS__); \
+ } while (false)
+
+#define advance_and_return_if_error_or_eof(...) \
+ do { \
+ assert_not_eof(); \
+ advance(); \
+ return_if_error(__VA_ARGS__); \
+ set_error_and_return_if_eof(__VA_ARGS__); \
+ } while (false)
+
+#endif // parser helper macros
+
+TOML_IMPL_NAMESPACE_START {
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex);
+
+ class parser {
+ private:
+ static constexpr size_t max_nested_values = TOML_MAX_NESTED_VALUES;
+
+ utf8_buffered_reader reader;
+ table root;
+ source_position prev_pos = {1, 1};
+ const utf8_codepoint* cp = {};
+ std::vector<table*> implicit_tables;
+ std::vector<table*> dotted_key_tables;
+ std::vector<table*> open_inline_tables;
+ std::vector<array*> table_arrays;
+ parse_key_buffer key_buffer;
+ std::string string_buffer;
+ std::string recording_buffer; // for diagnostics
+ bool recording = false, recording_whitespace = true;
+ std::string_view current_scope;
+ size_t nested_values = {};
#if !TOML_EXCEPTIONS
- mutable optional<parse_error> err;
+ mutable optional<parse_error> err;
#endif
- TOML_NODISCARD
- source_position current_position(source_index fallback_offset = 0) const noexcept
- {
- if (!is_eof())
- return cp->position;
- return { prev_pos.line, static_cast<source_index>(prev_pos.column + fallback_offset) };
- }
+ TOML_NODISCARD
+ source_position current_position(source_index fallback_offset = 0) const noexcept {
+ if (!is_eof()) return cp->position;
+ return {prev_pos.line, static_cast<source_index>(prev_pos.column + fallback_offset)};
+ }
- template <typename... T>
- TOML_RETURNS_BY_THROWING
- TOML_NEVER_INLINE
- void set_error_at(source_position pos, const T&... reason) const
- {
- static_assert(sizeof...(T) > 0);
- return_if_error();
+ template <typename... T>
+ TOML_RETURNS_BY_THROWING TOML_NEVER_INLINE void set_error_at(source_position pos,
+ const T&... reason) const {
+ static_assert(sizeof...(T) > 0);
+ return_if_error();
- error_builder builder{ current_scope };
- (builder.append(reason), ...);
+ error_builder builder{current_scope};
+ (builder.append(reason), ...);
- parse_error_break();
+ parse_error_break();
#if TOML_EXCEPTIONS
- builder.finish(pos, reader.source_path());
+ builder.finish(pos, reader.source_path());
#else
- err.emplace(builder.finish(pos, reader.source_path()));
+ err.emplace(builder.finish(pos, reader.source_path()));
#endif
- }
+ }
- template <typename... T>
- TOML_RETURNS_BY_THROWING
- void set_error(const T&... reason) const
- {
- set_error_at(current_position(1), reason...);
- }
+ template <typename... T>
+ TOML_RETURNS_BY_THROWING void set_error(const T&... reason) const {
+ set_error_at(current_position(1), reason...);
+ }
- void go_back(size_t count = 1) noexcept
- {
- return_if_error();
- TOML_ASSERT_ASSUME(count);
+ void go_back(size_t count = 1) noexcept {
+ return_if_error();
+ TOML_ASSERT_ASSUME(count);
- cp = reader.step_back(count);
- prev_pos = cp->position;
- }
+ cp = reader.step_back(count);
+ prev_pos = cp->position;
+ }
- void advance()
- {
- return_if_error();
- assert_not_eof();
+ void advance() {
+ return_if_error();
+ assert_not_eof();
- prev_pos = cp->position;
- cp = reader.read_next();
+ prev_pos = cp->position;
+ cp = reader.read_next();
#if !TOML_EXCEPTIONS
- if (reader.error())
- {
- err = std::move(reader.error());
- return;
- }
+ if (reader.error()) {
+ err = std::move(reader.error());
+ return;
+ }
#endif
- if (recording && !is_eof())
- {
- if (recording_whitespace || !is_whitespace(*cp))
- recording_buffer.append(cp->bytes, cp->count);
- }
- }
-
- void start_recording(bool include_current = true) noexcept
- {
- return_if_error();
-
- recording = true;
- recording_whitespace = true;
- recording_buffer.clear();
- if (include_current && !is_eof())
- recording_buffer.append(cp->bytes, cp->count);
- }
-
- void stop_recording(size_t pop_bytes = 0) noexcept
- {
- return_if_error();
-
- recording = false;
- if (pop_bytes)
- {
- if (pop_bytes >= recording_buffer.length())
- recording_buffer.clear();
- else if (pop_bytes == 1u)
- recording_buffer.pop_back();
- else
- recording_buffer.erase(recording_buffer.begin()
- + static_cast<ptrdiff_t>(recording_buffer.length() - pop_bytes),
- recording_buffer.end());
- }
- }
-
- bool consume_leading_whitespace()
- {
- return_if_error_or_eof({});
-
- bool consumed = false;
- while (!is_eof() && is_horizontal_whitespace(*cp))
- {
- if TOML_UNLIKELY(!is_ascii_horizontal_whitespace(*cp))
- set_error_and_return_default("expected space or tab, saw '"sv, escaped_codepoint{ *cp }, "'"sv);
-
- consumed = true;
- advance_and_return_if_error({});
- }
- return consumed;
- }
-
- bool consume_line_break()
- {
- return_if_error_or_eof({});
-
- if TOML_UNLIKELY(is_match(*cp, U'\v', U'\f'))
- set_error_and_return_default(
- R"(vertical tabs '\v' and form-feeds '\f' are not legal line breaks in TOML)"sv);
-
- if (*cp == U'\r')
- {
- advance_and_return_if_error({}); // skip \r
-
- if TOML_UNLIKELY(is_eof())
- set_error_and_return_default("expected '\\n' after '\\r', saw EOF"sv);
-
- if TOML_UNLIKELY(*cp != U'\n')
- set_error_and_return_default("expected '\\n' after '\\r', saw '"sv,
- escaped_codepoint{ *cp },
- "'"sv);
- }
- else if (*cp != U'\n')
- return false;
-
- advance_and_return_if_error({}); // skip \n
- return true;
- }
-
- bool consume_rest_of_line()
- {
- return_if_error_or_eof({});
-
- do
- {
- if (is_ascii_vertical_whitespace(*cp))
- return consume_line_break();
- else
- advance();
- return_if_error({});
- }
- while (!is_eof());
-
- return true;
- }
-
- bool consume_comment()
- {
- return_if_error_or_eof({});
-
- if (*cp != U'#')
- return false;
-
- push_parse_scope("comment"sv);
-
- advance_and_return_if_error({}); // skip the '#'
-
- while (!is_eof())
- {
- if (consume_line_break())
- return true;
- return_if_error({});
+ if (recording && !is_eof()) {
+ if (recording_whitespace || !is_whitespace(*cp))
+ recording_buffer.append(cp->bytes, cp->count);
+ }
+ }
+
+ void start_recording(bool include_current = true) noexcept {
+ return_if_error();
+
+ recording = true;
+ recording_whitespace = true;
+ recording_buffer.clear();
+ if (include_current && !is_eof()) recording_buffer.append(cp->bytes, cp->count);
+ }
+
+ void stop_recording(size_t pop_bytes = 0) noexcept {
+ return_if_error();
+
+ recording = false;
+ if (pop_bytes) {
+ if (pop_bytes >= recording_buffer.length())
+ recording_buffer.clear();
+ else if (pop_bytes == 1u)
+ recording_buffer.pop_back();
+ else
+ recording_buffer.erase(recording_buffer.begin() +
+ static_cast<ptrdiff_t>(recording_buffer.length() - pop_bytes),
+ recording_buffer.end());
+ }
+ }
+
+ bool consume_leading_whitespace() {
+ return_if_error_or_eof({});
+
+ bool consumed = false;
+ while (!is_eof() && is_horizontal_whitespace(*cp)) {
+ if TOML_UNLIKELY (!is_ascii_horizontal_whitespace(*cp))
+ set_error_and_return_default("expected space or tab, saw '"sv, escaped_codepoint{*cp},
+ "'"sv);
+
+ consumed = true;
+ advance_and_return_if_error({});
+ }
+ return consumed;
+ }
+
+ bool consume_line_break() {
+ return_if_error_or_eof({});
+
+ if TOML_UNLIKELY (is_match(*cp, U'\v', U'\f'))
+ set_error_and_return_default(
+ R"(vertical tabs '\v' and form-feeds '\f' are not legal line breaks in TOML)"sv);
+
+ if (*cp == U'\r') {
+ advance_and_return_if_error({}); // skip \r
+
+ if TOML_UNLIKELY (is_eof())
+ set_error_and_return_default("expected '\\n' after '\\r', saw EOF"sv);
+
+ if TOML_UNLIKELY (*cp != U'\n')
+ set_error_and_return_default("expected '\\n' after '\\r', saw '"sv,
+ escaped_codepoint{*cp}, "'"sv);
+ } else if (*cp != U'\n')
+ return false;
+
+ advance_and_return_if_error({}); // skip \n
+ return true;
+ }
+
+ bool consume_rest_of_line() {
+ return_if_error_or_eof({});
+
+ do {
+ if (is_ascii_vertical_whitespace(*cp))
+ return consume_line_break();
+ else
+ advance();
+ return_if_error({});
+ } while (!is_eof());
+
+ return true;
+ }
+
+ bool consume_comment() {
+ return_if_error_or_eof({});
+
+ if (*cp != U'#') return false;
+
+ push_parse_scope("comment"sv);
+
+ advance_and_return_if_error({}); // skip the '#'
+
+ while (!is_eof()) {
+ if (consume_line_break()) return true;
+ return_if_error({});
#if TOML_LANG_AT_LEAST(1, 0, 0)
- // toml/issues/567 (disallow non-TAB control characters in comments)
- if TOML_UNLIKELY(is_nontab_control_character(*cp))
- set_error_and_return_default(
- "control characters other than TAB (U+0009) are explicitly prohibited in comments"sv);
+ // toml/issues/567 (disallow non-TAB control characters in comments)
+ if TOML_UNLIKELY (is_nontab_control_character(*cp))
+ set_error_and_return_default(
+ "control characters other than TAB (U+0009) are explicitly prohibited in comments"sv);
- // toml/pull/720 (disallow surrogates in comments)
- else if TOML_UNLIKELY(is_unicode_surrogate(*cp))
- set_error_and_return_default(
- "unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited in comments"sv);
+ // toml/pull/720 (disallow surrogates in comments)
+ else if TOML_UNLIKELY (is_unicode_surrogate(*cp))
+ set_error_and_return_default(
+ "unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited in comments"sv);
#endif
- advance_and_return_if_error({});
- }
-
- return true;
- }
-
- TOML_NODISCARD
- bool consume_expected_sequence(std::u32string_view seq)
- {
- return_if_error({});
- TOML_ASSERT(!seq.empty());
-
- for (auto c : seq)
- {
- set_error_and_return_if_eof({});
- if (*cp != c)
- return false;
- advance_and_return_if_error({});
- }
- return true;
- }
-
- template <typename T>
- TOML_NODISCARD
- bool consume_digit_sequence(T* digits, size_t len)
- {
- return_if_error({});
- TOML_ASSERT_ASSUME(digits);
- TOML_ASSERT_ASSUME(len);
-
- for (size_t i = 0; i < len; i++)
- {
- set_error_and_return_if_eof({});
- if (!is_decimal_digit(*cp))
- return false;
-
- digits[i] = static_cast<T>(*cp - U'0');
- advance_and_return_if_error({});
- }
- return true;
- }
-
- template <typename T>
- TOML_NODISCARD
- size_t consume_variable_length_digit_sequence(T* buffer, size_t max_len)
- {
- return_if_error({});
- TOML_ASSERT_ASSUME(buffer);
- TOML_ASSERT_ASSUME(max_len);
-
- size_t i = {};
- for (; i < max_len; i++)
- {
- if (is_eof() || !is_decimal_digit(*cp))
- break;
-
- buffer[i] = static_cast<T>(*cp - U'0');
- advance_and_return_if_error({});
- }
- return i;
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- std::string_view parse_basic_string(bool multi_line)
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(*cp == U'"');
- push_parse_scope("string"sv);
-
- // skip the '"'
- advance_and_return_if_error_or_eof({});
-
- // multi-line strings ignore a single line ending right at the beginning
- if (multi_line)
- {
- consume_line_break();
- return_if_error({});
- set_error_and_return_if_eof({});
- }
-
- auto& str = string_buffer;
- str.clear();
- bool escaped = false;
- bool skipping_whitespace = false;
- do
- {
- if (escaped)
- {
- escaped = false;
-
- // handle 'line ending slashes' in multi-line mode
- if (multi_line && is_whitespace(*cp))
- {
- consume_leading_whitespace();
-
- if TOML_UNLIKELY(!consume_line_break())
- set_error_and_return_default(
- "line-ending backslashes must be the last non-whitespace character on the line"sv);
-
- skipping_whitespace = true;
- return_if_error({});
- continue;
- }
-
- bool skip_escaped_codepoint = true;
- assert_not_eof();
- switch (const auto escaped_codepoint = *cp)
- {
- // 'regular' escape codes
- case U'b': str += '\b'; break;
- case U'f': str += '\f'; break;
- case U'n': str += '\n'; break;
- case U'r': str += '\r'; break;
- case U't': str += '\t'; break;
- case U'"': str += '"'; break;
- case U'\\': str += '\\'; break;
-
-#if TOML_LANG_UNRELEASED // toml/pull/790 (\e shorthand for \x1B)
- case U'e': str += '\x1B'; break;
+ advance_and_return_if_error({});
+ }
+
+ return true;
+ }
+
+ TOML_NODISCARD
+ bool consume_expected_sequence(std::u32string_view seq) {
+ return_if_error({});
+ TOML_ASSERT(!seq.empty());
+
+ for (auto c : seq) {
+ set_error_and_return_if_eof({});
+ if (*cp != c) return false;
+ advance_and_return_if_error({});
+ }
+ return true;
+ }
+
+ template <typename T>
+ TOML_NODISCARD bool consume_digit_sequence(T* digits, size_t len) {
+ return_if_error({});
+ TOML_ASSERT_ASSUME(digits);
+ TOML_ASSERT_ASSUME(len);
+
+ for (size_t i = 0; i < len; i++) {
+ set_error_and_return_if_eof({});
+ if (!is_decimal_digit(*cp)) return false;
+
+ digits[i] = static_cast<T>(*cp - U'0');
+ advance_and_return_if_error({});
+ }
+ return true;
+ }
+
+ template <typename T>
+ TOML_NODISCARD size_t consume_variable_length_digit_sequence(T* buffer, size_t max_len) {
+ return_if_error({});
+ TOML_ASSERT_ASSUME(buffer);
+ TOML_ASSERT_ASSUME(max_len);
+
+ size_t i = {};
+ for (; i < max_len; i++) {
+ if (is_eof() || !is_decimal_digit(*cp)) break;
+
+ buffer[i] = static_cast<T>(*cp - U'0');
+ advance_and_return_if_error({});
+ }
+ return i;
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ std::string_view parse_basic_string(bool multi_line) {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(*cp == U'"');
+ push_parse_scope("string"sv);
+
+ // skip the '"'
+ advance_and_return_if_error_or_eof({});
+
+ // multi-line strings ignore a single line ending right at the beginning
+ if (multi_line) {
+ consume_line_break();
+ return_if_error({});
+ set_error_and_return_if_eof({});
+ }
+
+ auto& str = string_buffer;
+ str.clear();
+ bool escaped = false;
+ bool skipping_whitespace = false;
+ do {
+ if (escaped) {
+ escaped = false;
+
+ // handle 'line ending slashes' in multi-line mode
+ if (multi_line && is_whitespace(*cp)) {
+ consume_leading_whitespace();
+
+ if TOML_UNLIKELY (!consume_line_break())
+ set_error_and_return_default(
+ "line-ending backslashes must be the last non-whitespace character on the line"sv);
+
+ skipping_whitespace = true;
+ return_if_error({});
+ continue;
+ }
+
+ bool skip_escaped_codepoint = true;
+ assert_not_eof();
+ switch (const auto escaped_codepoint = *cp) {
+ // 'regular' escape codes
+ case U'b':
+ str += '\b';
+ break;
+ case U'f':
+ str += '\f';
+ break;
+ case U'n':
+ str += '\n';
+ break;
+ case U'r':
+ str += '\r';
+ break;
+ case U't':
+ str += '\t';
+ break;
+ case U'"':
+ str += '"';
+ break;
+ case U'\\':
+ str += '\\';
+ break;
+
+#if TOML_LANG_UNRELEASED // toml/pull/790 (\e shorthand for \x1B)
+ case U'e':
+ str += '\x1B';
+ break;
#else
- case U'e':
- set_error_and_return_default(
- "escape sequence '\\e' is not supported in TOML 1.0.0 and earlier"sv);
+ case U'e':
+ set_error_and_return_default(
+ "escape sequence '\\e' is not supported in TOML 1.0.0 and earlier"sv);
#endif
-#if TOML_LANG_UNRELEASED // toml/pull/796 (\xHH unicode scalar sequences)
- case U'x': [[fallthrough]];
+#if TOML_LANG_UNRELEASED // toml/pull/796 (\xHH unicode scalar sequences)
+ case U'x':
+ [[fallthrough]];
#else
- case U'x':
- set_error_and_return_default(
- "escape sequence '\\x' is not supported in TOML 1.0.0 and earlier"sv);
+ case U'x':
+ set_error_and_return_default(
+ "escape sequence '\\x' is not supported in TOML 1.0.0 and earlier"sv);
#endif
- // unicode scalar sequences
- case U'u': [[fallthrough]];
- case U'U':
- {
- push_parse_scope("unicode scalar sequence"sv);
- advance_and_return_if_error_or_eof({});
- skip_escaped_codepoint = false;
-
- uint32_t place_value =
- escaped_codepoint == U'U' ? 0x10000000u : (escaped_codepoint == U'u' ? 0x1000u : 0x10u);
- uint32_t sequence_value{};
- while (place_value)
- {
- set_error_and_return_if_eof({});
-
- if TOML_UNLIKELY(!is_hexadecimal_digit(*cp))
- set_error_and_return_default("expected hex digit, saw '"sv, to_sv(*cp), "'"sv);
-
- sequence_value += place_value * hex_to_dec(*cp);
- place_value /= 16u;
- advance_and_return_if_error({});
- }
-
- if TOML_UNLIKELY(is_unicode_surrogate(sequence_value))
- set_error_and_return_default(
- "unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
- else if TOML_UNLIKELY(sequence_value > 0x10FFFFu)
- set_error_and_return_default("values greater than U+10FFFF are invalid"sv);
-
- if (sequence_value < 0x80)
- {
- str += static_cast<char>(sequence_value);
- }
- else if (sequence_value < 0x800u)
- {
- str += static_cast<char>((sequence_value >> 6) | 0xC0u);
- str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
- }
- else if (sequence_value < 0x10000u)
- {
- str += static_cast<char>((sequence_value >> 12) | 0xE0u);
- str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
- str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
- }
- else if (sequence_value < 0x110000u)
- {
- str += static_cast<char>((sequence_value >> 18) | 0xF0u);
- str += static_cast<char>(((sequence_value >> 12) & 0x3Fu) | 0x80u);
- str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
- str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
- }
- break;
- }
-
- // ???
- TOML_UNLIKELY_CASE
- default: set_error_and_return_default("unknown escape sequence '\\"sv, to_sv(*cp), "'"sv);
- }
-
- if (skip_escaped_codepoint)
- advance_and_return_if_error_or_eof({});
- }
- else
- {
- // handle closing delimiters
- if (*cp == U'"')
- {
- if (multi_line)
- {
- size_t lookaheads = {};
- size_t consecutive_delimiters = 1;
- do
- {
- advance_and_return_if_error({});
- lookaheads++;
- if (!is_eof() && *cp == U'"')
- consecutive_delimiters++;
- else
- break;
- }
- while (lookaheads < 4u);
-
- switch (consecutive_delimiters)
- {
- // """ " (one quote somewhere in a ML string)
- case 1:
- str += '"';
- skipping_whitespace = false;
- continue;
-
- // """ "" (two quotes somewhere in a ML string)
- case 2:
- str.append("\"\""sv);
- skipping_whitespace = false;
- continue;
-
- // """ """ (the end of the string)
- case 3: return str;
-
- // """ """" (one at the end of the string)
- case 4: str += '"'; return str;
-
- // """ """"" (two quotes at the end of the string)
- case 5:
- str.append("\"\""sv);
- advance_and_return_if_error({}); // skip the last '"'
- return str;
-
- default: TOML_UNREACHABLE;
- }
- }
- else
- {
- advance_and_return_if_error({}); // skip the closing delimiter
- return str;
- }
- }
-
- // handle escapes
- else if (*cp == U'\\')
- {
- advance_and_return_if_error_or_eof({}); // skip the '\'
- skipping_whitespace = false;
- escaped = true;
- continue;
- }
-
- // handle line endings in multi-line mode
- if (multi_line && is_ascii_vertical_whitespace(*cp))
- {
- consume_line_break();
- return_if_error({});
- if (!skipping_whitespace)
- str += '\n';
- continue;
- }
-
- // handle control characters
- if TOML_UNLIKELY(is_nontab_control_character(*cp))
- set_error_and_return_default(
- "unescaped control characters other than TAB (U+0009) are explicitly prohibited"sv);
+ // unicode scalar sequences
+ case U'u':
+ [[fallthrough]];
+ case U'U': {
+ push_parse_scope("unicode scalar sequence"sv);
+ advance_and_return_if_error_or_eof({});
+ skip_escaped_codepoint = false;
+
+ uint32_t place_value = escaped_codepoint == U'U'
+ ? 0x10000000u
+ : (escaped_codepoint == U'u' ? 0x1000u : 0x10u);
+ uint32_t sequence_value{};
+ while (place_value) {
+ set_error_and_return_if_eof({});
+
+ if TOML_UNLIKELY (!is_hexadecimal_digit(*cp))
+ set_error_and_return_default("expected hex digit, saw '"sv, to_sv(*cp), "'"sv);
+
+ sequence_value += place_value * hex_to_dec(*cp);
+ place_value /= 16u;
+ advance_and_return_if_error({});
+ }
+
+ if TOML_UNLIKELY (is_unicode_surrogate(sequence_value))
+ set_error_and_return_default(
+ "unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
+ else if TOML_UNLIKELY (sequence_value > 0x10FFFFu)
+ set_error_and_return_default("values greater than U+10FFFF are invalid"sv);
+
+ if (sequence_value < 0x80) {
+ str += static_cast<char>(sequence_value);
+ } else if (sequence_value < 0x800u) {
+ str += static_cast<char>((sequence_value >> 6) | 0xC0u);
+ str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
+ } else if (sequence_value < 0x10000u) {
+ str += static_cast<char>((sequence_value >> 12) | 0xE0u);
+ str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
+ str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
+ } else if (sequence_value < 0x110000u) {
+ str += static_cast<char>((sequence_value >> 18) | 0xF0u);
+ str += static_cast<char>(((sequence_value >> 12) & 0x3Fu) | 0x80u);
+ str += static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
+ str += static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
+ }
+ break;
+ }
+
+ // ???
+ TOML_UNLIKELY_CASE
+ default:
+ set_error_and_return_default("unknown escape sequence '\\"sv, to_sv(*cp), "'"sv);
+ }
+
+ if (skip_escaped_codepoint) advance_and_return_if_error_or_eof({});
+ } else {
+ // handle closing delimiters
+ if (*cp == U'"') {
+ if (multi_line) {
+ size_t lookaheads = {};
+ size_t consecutive_delimiters = 1;
+ do {
+ advance_and_return_if_error({});
+ lookaheads++;
+ if (!is_eof() && *cp == U'"')
+ consecutive_delimiters++;
+ else
+ break;
+ } while (lookaheads < 4u);
+
+ switch (consecutive_delimiters) {
+ // """ " (one quote somewhere in a ML string)
+ case 1:
+ str += '"';
+ skipping_whitespace = false;
+ continue;
+
+ // """ "" (two quotes somewhere in a ML string)
+ case 2:
+ str.append("\"\""sv);
+ skipping_whitespace = false;
+ continue;
+
+ // """ """ (the end of the string)
+ case 3:
+ return str;
+
+ // """ """" (one at the end of the string)
+ case 4:
+ str += '"';
+ return str;
+
+ // """ """"" (two quotes at the end of the string)
+ case 5:
+ str.append("\"\""sv);
+ advance_and_return_if_error({}); // skip the last '"'
+ return str;
+
+ default:
+ TOML_UNREACHABLE;
+ }
+ } else {
+ advance_and_return_if_error({}); // skip the closing delimiter
+ return str;
+ }
+ }
+
+ // handle escapes
+ else if (*cp == U'\\') {
+ advance_and_return_if_error_or_eof({}); // skip the '\'
+ skipping_whitespace = false;
+ escaped = true;
+ continue;
+ }
+
+ // handle line endings in multi-line mode
+ if (multi_line && is_ascii_vertical_whitespace(*cp)) {
+ consume_line_break();
+ return_if_error({});
+ if (!skipping_whitespace) str += '\n';
+ continue;
+ }
+
+ // handle control characters
+ if TOML_UNLIKELY (is_nontab_control_character(*cp))
+ set_error_and_return_default(
+ "unescaped control characters other than TAB (U+0009) are explicitly prohibited"sv);
#if TOML_LANG_AT_LEAST(1, 0, 0)
- // handle surrogates in strings
- if TOML_UNLIKELY(is_unicode_surrogate(*cp))
- set_error_and_return_default(
- "unescaped unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited"sv);
+ // handle surrogates in strings
+ if TOML_UNLIKELY (is_unicode_surrogate(*cp))
+ set_error_and_return_default(
+ "unescaped unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited"sv);
#endif
- if (multi_line)
- {
- if (!skipping_whitespace || !is_horizontal_whitespace(*cp))
- {
- skipping_whitespace = false;
- str.append(cp->bytes, cp->count);
- }
- }
- else
- str.append(cp->bytes, cp->count);
-
- advance_and_return_if_error({});
- }
- }
- while (!is_eof());
-
- set_error_and_return_default("encountered end-of-file"sv);
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- std::string_view parse_literal_string(bool multi_line)
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(*cp == U'\'');
- push_parse_scope("literal string"sv);
-
- // skip the delimiter
- advance_and_return_if_error_or_eof({});
-
- // multi-line strings ignore a single line ending right at the beginning
- if (multi_line)
- {
- consume_line_break();
- return_if_error({});
- set_error_and_return_if_eof({});
- }
-
- auto& str = string_buffer;
- str.clear();
- do
- {
- return_if_error({});
-
- // handle closing delimiters
- if (*cp == U'\'')
- {
- if (multi_line)
- {
- size_t lookaheads = {};
- size_t consecutive_delimiters = 1;
- do
- {
- advance_and_return_if_error({});
- lookaheads++;
- if (!is_eof() && *cp == U'\'')
- consecutive_delimiters++;
- else
- break;
- }
- while (lookaheads < 4u);
-
- switch (consecutive_delimiters)
- {
- // ''' ' (one quote somewhere in a ML string)
- case 1: str += '\''; continue;
-
- // ''' '' (two quotes somewhere in a ML string)
- case 2: str.append("''"sv); continue;
-
- // ''' ''' (the end of the string)
- case 3: return str;
-
- // ''' '''' (one at the end of the string)
- case 4: str += '\''; return str;
-
- // ''' ''''' (two quotes at the end of the string)
- case 5:
- str.append("''"sv);
- advance_and_return_if_error({}); // skip the last '
- return str;
-
- default: TOML_UNREACHABLE;
- }
- }
- else
- {
- advance_and_return_if_error({}); // skip the closing delimiter
- return str;
- }
- }
-
- // handle line endings in multi-line mode
- if (multi_line && is_ascii_vertical_whitespace(*cp))
- {
- consume_line_break();
- return_if_error({});
- str += '\n';
- continue;
- }
-
- // handle control characters
- if TOML_UNLIKELY(is_nontab_control_character(*cp))
- set_error_and_return_default(
- "control characters other than TAB (U+0009) are explicitly prohibited"sv);
+ if (multi_line) {
+ if (!skipping_whitespace || !is_horizontal_whitespace(*cp)) {
+ skipping_whitespace = false;
+ str.append(cp->bytes, cp->count);
+ }
+ } else
+ str.append(cp->bytes, cp->count);
+
+ advance_and_return_if_error({});
+ }
+ } while (!is_eof());
+
+ set_error_and_return_default("encountered end-of-file"sv);
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ std::string_view parse_literal_string(bool multi_line) {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(*cp == U'\'');
+ push_parse_scope("literal string"sv);
+
+ // skip the delimiter
+ advance_and_return_if_error_or_eof({});
+
+ // multi-line strings ignore a single line ending right at the beginning
+ if (multi_line) {
+ consume_line_break();
+ return_if_error({});
+ set_error_and_return_if_eof({});
+ }
+
+ auto& str = string_buffer;
+ str.clear();
+ do {
+ return_if_error({});
+
+ // handle closing delimiters
+ if (*cp == U'\'') {
+ if (multi_line) {
+ size_t lookaheads = {};
+ size_t consecutive_delimiters = 1;
+ do {
+ advance_and_return_if_error({});
+ lookaheads++;
+ if (!is_eof() && *cp == U'\'')
+ consecutive_delimiters++;
+ else
+ break;
+ } while (lookaheads < 4u);
+
+ switch (consecutive_delimiters) {
+ // ''' ' (one quote somewhere in a ML string)
+ case 1:
+ str += '\'';
+ continue;
+
+ // ''' '' (two quotes somewhere in a ML string)
+ case 2:
+ str.append("''"sv);
+ continue;
+
+ // ''' ''' (the end of the string)
+ case 3:
+ return str;
+
+ // ''' '''' (one at the end of the string)
+ case 4:
+ str += '\'';
+ return str;
+
+ // ''' ''''' (two quotes at the end of the string)
+ case 5:
+ str.append("''"sv);
+ advance_and_return_if_error({}); // skip the last '
+ return str;
+
+ default:
+ TOML_UNREACHABLE;
+ }
+ } else {
+ advance_and_return_if_error({}); // skip the closing delimiter
+ return str;
+ }
+ }
+
+ // handle line endings in multi-line mode
+ if (multi_line && is_ascii_vertical_whitespace(*cp)) {
+ consume_line_break();
+ return_if_error({});
+ str += '\n';
+ continue;
+ }
+
+ // handle control characters
+ if TOML_UNLIKELY (is_nontab_control_character(*cp))
+ set_error_and_return_default(
+ "control characters other than TAB (U+0009) are explicitly prohibited"sv);
#if TOML_LANG_AT_LEAST(1, 0, 0)
- // handle surrogates in strings
- if TOML_UNLIKELY(is_unicode_surrogate(*cp))
- set_error_and_return_default("unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
+ // handle surrogates in strings
+ if TOML_UNLIKELY (is_unicode_surrogate(*cp))
+ set_error_and_return_default(
+ "unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
#endif
- str.append(cp->bytes, cp->count);
- advance_and_return_if_error({});
- }
- while (!is_eof());
-
- set_error_and_return_default("encountered end-of-file"sv);
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- parsed_string parse_string()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(is_string_delimiter(*cp));
- push_parse_scope("string"sv);
-
- // get the first three characters to determine the string type
- const auto first = cp->value;
- advance_and_return_if_error_or_eof({});
- const auto second = cp->value;
- advance_and_return_if_error({});
- const auto third = cp ? cp->value : U'\0';
-
- // if we were eof at the third character then first and second need to be
- // the same string character (otherwise it's an unterminated string)
- if (is_eof())
- {
- if (second == first)
- return {};
-
- set_error_and_return_default("encountered end-of-file"sv);
- }
-
- // if the first three characters are all the same string delimiter then
- // it's a multi-line string.
- else if (first == second && first == third)
- {
- return { first == U'\'' ? parse_literal_string(true) : parse_basic_string(true), true };
- }
-
- // otherwise it's just a regular string.
- else
- {
- // step back two characters so that the current
- // character is the string delimiter
- go_back(2u);
-
- return { first == U'\'' ? parse_literal_string(false) : parse_basic_string(false), false };
- }
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- std::string_view parse_bare_key_segment()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(is_bare_key_character(*cp));
-
- string_buffer.clear();
-
- while (!is_eof())
- {
- if (!is_bare_key_character(*cp))
- break;
-
- string_buffer.append(cp->bytes, cp->count);
- advance_and_return_if_error({});
- }
-
- return string_buffer;
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- bool parse_boolean()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(is_match(*cp, U't', U'f', U'T', U'F'));
- push_parse_scope("boolean"sv);
-
- start_recording(true);
- auto result = is_match(*cp, U't', U'T');
- if (!consume_expected_sequence(result ? U"true"sv : U"false"sv))
- set_error_and_return_default("expected '"sv,
- to_sv(result),
- "', saw '"sv,
- to_sv(recording_buffer),
- "'"sv);
- stop_recording();
-
- if (cp && !is_value_terminator(*cp))
- set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
-
- return result;
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- double parse_inf_or_nan()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(is_match(*cp, U'i', U'n', U'I', U'N', U'+', U'-'));
- push_parse_scope("floating-point"sv);
-
- start_recording(true);
- const bool negative = *cp == U'-';
- if (negative || *cp == U'+')
- advance_and_return_if_error_or_eof({});
-
- const bool inf = is_match(*cp, U'i', U'I');
- if (!consume_expected_sequence(inf ? U"inf"sv : U"nan"sv))
- set_error_and_return_default("expected '"sv,
- inf ? "inf"sv : "nan"sv,
- "', saw '"sv,
- to_sv(recording_buffer),
- "'"sv);
- stop_recording();
-
- if (cp && !is_value_terminator(*cp))
- set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
-
- return inf ? (negative ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity())
- : std::numeric_limits<double>::quiet_NaN();
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- double parse_float()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(is_match(*cp, U'+', U'-', U'.') || is_decimal_digit(*cp));
- push_parse_scope("floating-point"sv);
-
- // sign
- const int sign = *cp == U'-' ? -1 : 1;
- if (is_match(*cp, U'+', U'-'))
- advance_and_return_if_error_or_eof({});
-
- // consume value chars
- char chars[utf8_buffered_reader::max_history_length];
- size_t length = {};
- const utf8_codepoint* prev = {};
- bool seen_decimal = false, seen_exponent = false;
- char first_integer_part = '\0';
- while (!is_eof() && !is_value_terminator(*cp))
- {
- if (*cp == U'_')
- {
- if (!prev || !is_decimal_digit(*prev))
- set_error_and_return_default("underscores may only follow digits"sv);
-
- prev = cp;
- advance_and_return_if_error_or_eof({});
- continue;
- }
- else if TOML_UNLIKELY(prev && *prev == U'_' && !is_decimal_digit(*cp))
- set_error_and_return_default("underscores must be followed by digits"sv);
- else if TOML_UNLIKELY(length == sizeof(chars))
- set_error_and_return_default("exceeds length limit of "sv,
- sizeof(chars),
- " digits"sv,
- (seen_exponent ? ""sv : " (consider using exponent notation)"sv));
- else if (*cp == U'.')
- {
- // .1
- // -.1
- // +.1 (no integer part)
- if (!first_integer_part)
- set_error_and_return_default("expected decimal digit, saw '.'"sv);
-
- // 1.0e+.10 (exponent cannot have '.')
- else if (seen_exponent)
- set_error_and_return_default("expected exponent decimal digit or sign, saw '.'"sv);
-
- // 1.0.e+.10
- // 1..0
- // (multiple '.')
- else if (seen_decimal)
- set_error_and_return_default("expected decimal digit or exponent, saw '.'"sv);
-
- seen_decimal = true;
- }
- else if (is_match(*cp, U'e', U'E'))
- {
- if (prev && !is_decimal_digit(*prev))
- set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
-
- // 1.0ee+10 (multiple 'e')
- else if (seen_exponent)
- set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
-
- seen_decimal = true; // implied
- seen_exponent = true;
- }
- else if (is_match(*cp, U'+', U'-'))
- {
- // 1.-0 (sign in mantissa)
- if (!seen_exponent)
- set_error_and_return_default("expected decimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
-
- // 1.0e1-0 (misplaced exponent sign)
- else if (!is_match(*prev, U'e', U'E'))
- set_error_and_return_default("expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
- }
- else if (is_decimal_digit(*cp))
- {
- if (!seen_decimal)
- {
- if (!first_integer_part)
- first_integer_part = static_cast<char>(cp->bytes[0]);
- else if (first_integer_part == '0')
- set_error_and_return_default("leading zeroes are prohibited"sv);
- }
- }
- else
- set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
-
- chars[length++] = static_cast<char>(cp->bytes[0]);
- prev = cp;
- advance_and_return_if_error({});
- }
-
- // sanity-check ending state
- if (prev)
- {
- if (*prev == U'_')
- {
- set_error_and_return_if_eof({});
- set_error_and_return_default("underscores must be followed by digits"sv);
- }
- else if (is_match(*prev, U'e', U'E', U'+', U'-', U'.'))
- {
- set_error_and_return_if_eof({});
- set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
- }
- }
-
- // convert to double
- double result;
+ str.append(cp->bytes, cp->count);
+ advance_and_return_if_error({});
+ } while (!is_eof());
+
+ set_error_and_return_default("encountered end-of-file"sv);
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ parsed_string parse_string() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(is_string_delimiter(*cp));
+ push_parse_scope("string"sv);
+
+ // get the first three characters to determine the string type
+ const auto first = cp->value;
+ advance_and_return_if_error_or_eof({});
+ const auto second = cp->value;
+ advance_and_return_if_error({});
+ const auto third = cp ? cp->value : U'\0';
+
+ // if we were eof at the third character then first and second need to be
+ // the same string character (otherwise it's an unterminated string)
+ if (is_eof()) {
+ if (second == first) return {};
+
+ set_error_and_return_default("encountered end-of-file"sv);
+ }
+
+ // if the first three characters are all the same string delimiter then
+ // it's a multi-line string.
+ else if (first == second && first == third) {
+ return {first == U'\'' ? parse_literal_string(true) : parse_basic_string(true), true};
+ }
+
+ // otherwise it's just a regular string.
+ else {
+ // step back two characters so that the current
+ // character is the string delimiter
+ go_back(2u);
+
+ return {first == U'\'' ? parse_literal_string(false) : parse_basic_string(false), false};
+ }
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ std::string_view parse_bare_key_segment() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(is_bare_key_character(*cp));
+
+ string_buffer.clear();
+
+ while (!is_eof()) {
+ if (!is_bare_key_character(*cp)) break;
+
+ string_buffer.append(cp->bytes, cp->count);
+ advance_and_return_if_error({});
+ }
+
+ return string_buffer;
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ bool parse_boolean() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(is_match(*cp, U't', U'f', U'T', U'F'));
+ push_parse_scope("boolean"sv);
+
+ start_recording(true);
+ auto result = is_match(*cp, U't', U'T');
+ if (!consume_expected_sequence(result ? U"true"sv : U"false"sv))
+ set_error_and_return_default("expected '"sv, to_sv(result), "', saw '"sv,
+ to_sv(recording_buffer), "'"sv);
+ stop_recording();
+
+ if (cp && !is_value_terminator(*cp))
+ set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
+
+ return result;
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ double parse_inf_or_nan() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(is_match(*cp, U'i', U'n', U'I', U'N', U'+', U'-'));
+ push_parse_scope("floating-point"sv);
+
+ start_recording(true);
+ const bool negative = *cp == U'-';
+ if (negative || *cp == U'+') advance_and_return_if_error_or_eof({});
+
+ const bool inf = is_match(*cp, U'i', U'I');
+ if (!consume_expected_sequence(inf ? U"inf"sv : U"nan"sv))
+ set_error_and_return_default("expected '"sv, inf ? "inf"sv : "nan"sv, "', saw '"sv,
+ to_sv(recording_buffer), "'"sv);
+ stop_recording();
+
+ if (cp && !is_value_terminator(*cp))
+ set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
+
+ return inf ? (negative ? -std::numeric_limits<double>::infinity()
+ : std::numeric_limits<double>::infinity())
+ : std::numeric_limits<double>::quiet_NaN();
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ double parse_float() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(is_match(*cp, U'+', U'-', U'.') || is_decimal_digit(*cp));
+ push_parse_scope("floating-point"sv);
+
+ // sign
+ const int sign = *cp == U'-' ? -1 : 1;
+ if (is_match(*cp, U'+', U'-')) advance_and_return_if_error_or_eof({});
+
+ // consume value chars
+ char chars[utf8_buffered_reader::max_history_length];
+ size_t length = {};
+ const utf8_codepoint* prev = {};
+ bool seen_decimal = false, seen_exponent = false;
+ char first_integer_part = '\0';
+ while (!is_eof() && !is_value_terminator(*cp)) {
+ if (*cp == U'_') {
+ if (!prev || !is_decimal_digit(*prev))
+ set_error_and_return_default("underscores may only follow digits"sv);
+
+ prev = cp;
+ advance_and_return_if_error_or_eof({});
+ continue;
+ } else if TOML_UNLIKELY (prev && *prev == U'_' && !is_decimal_digit(*cp))
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ else if TOML_UNLIKELY (length == sizeof(chars))
+ set_error_and_return_default(
+ "exceeds length limit of "sv, sizeof(chars), " digits"sv,
+ (seen_exponent ? ""sv : " (consider using exponent notation)"sv));
+ else if (*cp == U'.') {
+ // .1
+ // -.1
+ // +.1 (no integer part)
+ if (!first_integer_part)
+ set_error_and_return_default("expected decimal digit, saw '.'"sv);
+
+ // 1.0e+.10 (exponent cannot have '.')
+ else if (seen_exponent)
+ set_error_and_return_default("expected exponent decimal digit or sign, saw '.'"sv);
+
+ // 1.0.e+.10
+ // 1..0
+ // (multiple '.')
+ else if (seen_decimal)
+ set_error_and_return_default("expected decimal digit or exponent, saw '.'"sv);
+
+ seen_decimal = true;
+ } else if (is_match(*cp, U'e', U'E')) {
+ if (prev && !is_decimal_digit(*prev))
+ set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
+
+ // 1.0ee+10 (multiple 'e')
+ else if (seen_exponent)
+ set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
+
+ seen_decimal = true; // implied
+ seen_exponent = true;
+ } else if (is_match(*cp, U'+', U'-')) {
+ // 1.-0 (sign in mantissa)
+ if (!seen_exponent)
+ set_error_and_return_default("expected decimal digit or '.', saw '"sv, to_sv(*cp),
+ "'"sv);
+
+ // 1.0e1-0 (misplaced exponent sign)
+ else if (!is_match(*prev, U'e', U'E'))
+ set_error_and_return_default("expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
+ } else if (is_decimal_digit(*cp)) {
+ if (!seen_decimal) {
+ if (!first_integer_part)
+ first_integer_part = static_cast<char>(cp->bytes[0]);
+ else if (first_integer_part == '0')
+ set_error_and_return_default("leading zeroes are prohibited"sv);
+ }
+ } else
+ set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
+
+ chars[length++] = static_cast<char>(cp->bytes[0]);
+ prev = cp;
+ advance_and_return_if_error({});
+ }
+
+ // sanity-check ending state
+ if (prev) {
+ if (*prev == U'_') {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ } else if (is_match(*prev, U'e', U'E', U'+', U'-', U'.')) {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("expected decimal digit, saw '"sv, to_sv(*cp), "'"sv);
+ }
+ }
+
+ // convert to double
+ double result;
#if TOML_FLOAT_CHARCONV
- {
- auto fc_result = std::from_chars(chars, chars + length, result);
- switch (fc_result.ec)
- {
- TOML_LIKELY_CASE
- case std::errc{}: // ok
- return result * sign;
-
- case std::errc::invalid_argument:
- set_error_and_return_default("'"sv,
- std::string_view{ chars, length },
- "' could not be interpreted as a value"sv);
- break;
-
- case std::errc::result_out_of_range:
- set_error_and_return_default("'"sv,
- std::string_view{ chars, length },
- "' is not representable in 64 bits"sv);
- break;
-
- default: //??
- set_error_and_return_default("an unspecified error occurred while trying to interpret '"sv,
- std::string_view{ chars, length },
- "' as a value"sv);
- }
- }
+ {
+ auto fc_result = std::from_chars(chars, chars + length, result);
+ switch (fc_result.ec) {
+ TOML_LIKELY_CASE
+ case std::errc{}: // ok
+ return result * sign;
+
+ case std::errc::invalid_argument:
+ set_error_and_return_default("'"sv, std::string_view{chars, length},
+ "' could not be interpreted as a value"sv);
+ break;
+
+ case std::errc::result_out_of_range:
+ set_error_and_return_default("'"sv, std::string_view{chars, length},
+ "' is not representable in 64 bits"sv);
+ break;
+
+ default: //??
+ set_error_and_return_default(
+ "an unspecified error occurred while trying to interpret '"sv,
+ std::string_view{chars, length}, "' as a value"sv);
+ }
+ }
#else
- {
- std::stringstream ss;
- ss.imbue(std::locale::classic());
- ss.write(chars, static_cast<std::streamsize>(length));
- if ((ss >> result))
- return result * sign;
- else
- set_error_and_return_default("'"sv,
- std::string_view{ chars, length },
- "' could not be interpreted as a value"sv);
- }
+ {
+ std::stringstream ss;
+ ss.imbue(std::locale::classic());
+ ss.write(chars, static_cast<std::streamsize>(length));
+ if ((ss >> result))
+ return result * sign;
+ else
+ set_error_and_return_default("'"sv, std::string_view{chars, length},
+ "' could not be interpreted as a value"sv);
+ }
#endif
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- double parse_hex_float()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(is_match(*cp, U'0', U'+', U'-'));
- push_parse_scope("hexadecimal floating-point"sv);
-
-#if TOML_LANG_UNRELEASED // toml/issues/562 (hexfloats)
-
- // sign
- const int sign = *cp == U'-' ? -1 : 1;
- if (is_match(*cp, U'+', U'-'))
- advance_and_return_if_error_or_eof({});
-
- // '0'
- if (*cp != U'0')
- set_error_and_return_default(" expected '0', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- // 'x' or 'X'
- if (!is_match(*cp, U'x', U'X'))
- set_error_and_return_default("expected 'x' or 'X', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- // <HEX DIGITS> ([.]<HEX DIGITS>)? [pP] [+-]? <DEC DIGITS>
-
- // consume value fragments
- struct fragment
- {
- char chars[24];
- size_t length;
- double value;
- };
- fragment fragments[] = {
- {}, // mantissa, whole part
- {}, // mantissa, fractional part
- {} // exponent
- };
- fragment* current_fragment = fragments;
- const utf8_codepoint* prev = {};
- int exponent_sign = 1;
- while (!is_eof() && !is_value_terminator(*cp))
- {
- if (*cp == U'_')
- {
- if (!prev || !is_hexadecimal_digit(*prev))
- set_error_and_return_default("underscores may only follow digits"sv);
-
- prev = cp;
- advance_and_return_if_error_or_eof({});
- continue;
- }
- else if (prev && *prev == U'_' && !is_hexadecimal_digit(*cp))
- set_error_and_return_default("underscores must be followed by digits"sv);
- else if (*cp == U'.')
- {
- // 0x10.0p-.0 (exponent cannot have '.')
- if (current_fragment == fragments + 2)
- set_error_and_return_default("expected exponent digit or sign, saw '.'"sv);
-
- // 0x10.0.p-0 (multiple '.')
- else if (current_fragment == fragments + 1)
- set_error_and_return_default("expected hexadecimal digit or exponent, saw '.'"sv);
-
- else
- current_fragment++;
- }
- else if (is_match(*cp, U'p', U'P'))
- {
- // 0x10.0pp-0 (multiple 'p')
- if (current_fragment == fragments + 2)
- set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
-
- // 0x.p-0 (mantissa is just '.')
- else if (fragments[0].length == 0u && fragments[1].length == 0u)
- set_error_and_return_default("expected hexadecimal digit, saw '"sv, to_sv(*cp), "'"sv);
-
- else
- current_fragment = fragments + 2;
- }
- else if (is_match(*cp, U'+', U'-'))
- {
- // 0x-10.0p-0 (sign in mantissa)
- if (current_fragment != fragments + 2)
- set_error_and_return_default("expected hexadecimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
-
- // 0x10.0p0- (misplaced exponent sign)
- else if (!is_match(*prev, U'p', U'P'))
- set_error_and_return_default("expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
-
- else
- exponent_sign = *cp == U'-' ? -1 : 1;
- }
- else if (current_fragment < fragments + 2 && !is_hexadecimal_digit(*cp))
- set_error_and_return_default("expected hexadecimal digit or '.', saw '"sv, to_sv(*cp), "'"sv);
- else if (current_fragment == fragments + 2 && !is_decimal_digit(*cp))
- set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp), "'"sv);
- else if (current_fragment->length == sizeof(fragment::chars))
- set_error_and_return_default("fragment exceeeds maximum length of "sv,
- sizeof(fragment::chars),
- " characters"sv);
- else
- current_fragment->chars[current_fragment->length++] = static_cast<char>(cp->bytes[0]);
-
- prev = cp;
- advance_and_return_if_error({});
- }
-
- // sanity-check ending state
- if (current_fragment != fragments + 2 || current_fragment->length == 0u)
- {
- set_error_and_return_if_eof({});
- set_error_and_return_default("missing exponent"sv);
- }
- else if (prev && *prev == U'_')
- {
- set_error_and_return_if_eof({});
- set_error_and_return_default("underscores must be followed by digits"sv);
- }
-
- // calculate values for the three fragments
- for (int fragment_idx = 0; fragment_idx < 3; fragment_idx++)
- {
- auto& f = fragments[fragment_idx];
- const uint32_t base = fragment_idx == 2 ? 10u : 16u;
-
- // left-trim zeroes
- const char* c = f.chars;
- size_t sig = {};
- while (f.length && *c == '0')
- {
- f.length--;
- c++;
- sig++;
- }
- if (!f.length)
- continue;
-
- // calculate value
- auto place = 1u;
- for (size_t i = 0; i < f.length - 1u; i++)
- place *= base;
- uint32_t val{};
- while (place)
- {
- if (base == 16)
- val += place * hex_to_dec(*c);
- else
- val += place * static_cast<uint32_t>(*c - '0');
- if (fragment_idx == 1)
- sig++;
- c++;
- place /= base;
- }
- f.value = static_cast<double>(val);
-
- // shift the fractional part
- if (fragment_idx == 1)
- {
- while (sig--)
- f.value /= base;
- }
- }
-
- return (fragments[0].value + fragments[1].value) * pow(2.0, fragments[2].value * exponent_sign) * sign;
-
-#else // !TOML_LANG_UNRELEASED
-
- set_error_and_return_default("hexadecimal floating-point values are not supported "
- "in TOML 1.0.0 and earlier"sv);
-
-#endif // !TOML_LANG_UNRELEASED
- }
-
- template <uint64_t base>
- TOML_NODISCARD
- TOML_NEVER_INLINE
- int64_t parse_integer()
- {
- return_if_error({});
- assert_not_eof();
- using traits = parse_integer_traits<base>;
- push_parse_scope(traits::scope_qualifier);
-
- [[maybe_unused]] int64_t sign = 1;
- if constexpr (traits::is_signed)
- {
- sign = *cp == U'-' ? -1 : 1;
- if (is_match(*cp, U'+', U'-'))
- advance_and_return_if_error_or_eof({});
- }
-
- if constexpr (base == 10)
- {
- if (!traits::is_digit(*cp))
- set_error_and_return_default("expected expected digit or sign, saw '"sv, to_sv(*cp), "'"sv);
- }
- else
- {
- // '0'
- if (*cp != U'0')
- set_error_and_return_default("expected '0', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- // 'b', 'o', 'x'
- if (*cp != traits::prefix_codepoint)
- set_error_and_return_default("expected '"sv, traits::prefix, "', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- if (!traits::is_digit(*cp))
- set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
- }
-
- // consume digits
- char digits[utf8_buffered_reader::max_history_length];
- size_t length = {};
- const utf8_codepoint* prev = {};
- while (!is_eof() && !is_value_terminator(*cp))
- {
- if (*cp == U'_')
- {
- if (!prev || !traits::is_digit(*prev))
- set_error_and_return_default("underscores may only follow digits"sv);
-
- prev = cp;
- advance_and_return_if_error_or_eof({});
- continue;
- }
- else if TOML_UNLIKELY(prev && *prev == U'_' && !traits::is_digit(*cp))
- set_error_and_return_default("underscores must be followed by digits"sv);
- else if TOML_UNLIKELY(!traits::is_digit(*cp))
- set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
- else if TOML_UNLIKELY(length == sizeof(digits))
- set_error_and_return_default("exceeds length limit of "sv, sizeof(digits), " digits"sv);
- else
- digits[length++] = static_cast<char>(cp->bytes[0]);
-
- prev = cp;
- advance_and_return_if_error({});
- }
-
- // sanity check ending state
- if (prev && *prev == U'_')
- {
- set_error_and_return_if_eof({});
- set_error_and_return_default("underscores must be followed by digits"sv);
- }
-
- // single digits can be converted trivially
- if (length == 1u)
- {
- int64_t result;
-
- if constexpr (base == 16)
- result = static_cast<int64_t>(hex_to_dec(digits[0]));
- else
- result = static_cast<int64_t>(digits[0] - '0');
-
- if constexpr (traits::is_signed)
- result *= sign;
-
- return result;
- }
-
- // bin, oct and hex allow leading zeroes so trim them first
- const char* end = digits + length;
- const char* msd = digits;
- if constexpr (base != 10)
- {
- while (msd < end && *msd == '0')
- msd++;
- if (msd == end)
- return 0ll;
- }
-
- // decimal integers do not allow leading zeroes
- else
- {
- if TOML_UNLIKELY(digits[0] == '0')
- set_error_and_return_default("leading zeroes are prohibited"sv);
- }
-
- // range check
- if TOML_UNLIKELY(static_cast<size_t>(end - msd) > traits::max_digits)
- set_error_and_return_default("'"sv,
- traits::full_prefix,
- std::string_view{ digits, length },
- "' is not representable in 64 bits"sv);
-
- // do the thing
- {
- uint64_t result = {};
- {
- uint64_t power = 1;
- while (--end >= msd)
- {
- if constexpr (base == 16)
- result += power * hex_to_dec(*end);
- else
- result += power * static_cast<uint64_t>(*end - '0');
-
- power *= base;
- }
- }
-
- // range check
- static constexpr auto i64_max = static_cast<uint64_t>((std::numeric_limits<int64_t>::max)());
- if TOML_UNLIKELY(result > i64_max + (sign < 0 ? 1u : 0u))
- set_error_and_return_default("'"sv,
- traits::full_prefix,
- std::string_view{ digits, length },
- "' is not representable in 64 bits"sv);
-
- if constexpr (traits::is_signed)
- {
- // avoid signed multiply UB when parsing INT64_MIN
- if TOML_UNLIKELY(sign < 0 && result == i64_max + 1u)
- return (std::numeric_limits<int64_t>::min)();
-
- return static_cast<int64_t>(result) * sign;
- }
- else
- return static_cast<int64_t>(result);
- }
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- date parse_date(bool part_of_datetime = false)
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
- push_parse_scope("date"sv);
-
- // "YYYY"
- uint32_t digits[4];
- if (!consume_digit_sequence(digits, 4u))
- set_error_and_return_default("expected 4-digit year, saw '"sv, to_sv(cp), "'"sv);
- const auto year = digits[3] + digits[2] * 10u + digits[1] * 100u + digits[0] * 1000u;
- const auto is_leap_year = (year % 4u == 0u) && ((year % 100u != 0u) || (year % 400u == 0u));
- set_error_and_return_if_eof({});
-
- // '-'
- if (*cp != U'-')
- set_error_and_return_default("expected '-', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- // "MM"
- if (!consume_digit_sequence(digits, 2u))
- set_error_and_return_default("expected 2-digit month, saw '"sv, to_sv(cp), "'"sv);
- const auto month = digits[1] + digits[0] * 10u;
- if (month == 0u || month > 12u)
- set_error_and_return_default("expected month between 1 and 12 (inclusive), saw "sv, month);
- const auto max_days_in_month = month == 2u
- ? (is_leap_year ? 29u : 28u)
- : (month == 4u || month == 6u || month == 9u || month == 11u ? 30u : 31u);
- set_error_and_return_if_eof({});
-
- // '-'
- if (*cp != U'-')
- set_error_and_return_default("expected '-', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- // "DD"
- if (!consume_digit_sequence(digits, 2u))
- set_error_and_return_default("expected 2-digit day, saw '"sv, to_sv(cp), "'"sv);
- const auto day = digits[1] + digits[0] * 10u;
- if (day == 0u || day > max_days_in_month)
- set_error_and_return_default("expected day between 1 and "sv,
- max_days_in_month,
- " (inclusive), saw "sv,
- day);
-
- if (!part_of_datetime && !is_eof() && !is_value_terminator(*cp))
- set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
-
- return { year, month, day };
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- time parse_time(bool part_of_datetime = false)
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
- push_parse_scope("time"sv);
-
- static constexpr size_t max_digits = 64; // far more than necessary but needed to allow fractional
- // millisecond truncation per the spec
- uint32_t digits[max_digits];
-
- // "HH"
- if (!consume_digit_sequence(digits, 2u))
- set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
- const auto hour = digits[1] + digits[0] * 10u;
- if (hour > 23u)
- set_error_and_return_default("expected hour between 0 to 59 (inclusive), saw "sv, hour);
- set_error_and_return_if_eof({});
-
- // ':'
- if (*cp != U':')
- set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- // "MM"
- if (!consume_digit_sequence(digits, 2u))
- set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
- const auto minute = digits[1] + digits[0] * 10u;
- if (minute > 59u)
- set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv, minute);
- auto time = toml::time{ hour, minute };
-
- // ':'
- if constexpr (TOML_LANG_UNRELEASED) // toml/issues/671 (allow omission of seconds)
- {
- if (is_eof() || is_value_terminator(*cp) || (part_of_datetime && is_match(*cp, U'+', U'-', U'Z', U'z')))
- return time;
- }
- else
- set_error_and_return_if_eof({});
- if (*cp != U':')
- set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- // "SS"
- if (!consume_digit_sequence(digits, 2u))
- set_error_and_return_default("expected 2-digit second, saw '"sv, to_sv(cp), "'"sv);
- const auto second = digits[1] + digits[0] * 10u;
- if (second > 59u)
- set_error_and_return_default("expected second between 0 and 59 (inclusive), saw "sv, second);
- time.second = static_cast<decltype(time.second)>(second);
-
- // '.' (early-exiting is allowed; fractional is optional)
- if (is_eof() || is_value_terminator(*cp) || (part_of_datetime && is_match(*cp, U'+', U'-', U'Z', U'z')))
- return time;
- if (*cp != U'.')
- set_error_and_return_default("expected '.', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- // "FFFFFFFFF"
- size_t digit_count = consume_variable_length_digit_sequence(digits, max_digits);
- if (!digit_count)
- {
- set_error_and_return_if_eof({});
- set_error_and_return_default("expected fractional digits, saw '"sv, to_sv(*cp), "'"sv);
- }
- else if (!is_eof())
- {
- if (digit_count == max_digits && is_decimal_digit(*cp))
- set_error_and_return_default("fractional component exceeds maximum precision of "sv, max_digits);
- else if (!part_of_datetime && !is_value_terminator(*cp))
- set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
- }
- uint32_t value = 0u;
- uint32_t place = 1u;
- for (auto i = impl::min<size_t>(digit_count, 9u); i-- > 0u;)
- {
- value += digits[i] * place;
- place *= 10u;
- }
- for (auto i = digit_count; i < 9u; i++) // implicit zeros
- value *= 10u;
- time.nanosecond = value;
- return time;
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- date_time parse_date_time()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
- push_parse_scope("date-time"sv);
-
- // "YYYY-MM-DD"
- auto date = parse_date(true);
- set_error_and_return_if_eof({});
-
- // ' ', 'T' or 't'
- if (!is_match(*cp, U' ', U'T', U't'))
- set_error_and_return_default("expected space, 'T' or 't', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- // "HH:MM:SS.FFFFFFFFF"
- auto time = parse_time(true);
- return_if_error({});
-
- // no offset
- if (is_eof() || is_value_terminator(*cp))
- return { date, time };
-
- // zero offset ('Z' or 'z')
- time_offset offset{};
- if (is_match(*cp, U'Z', U'z'))
- advance_and_return_if_error({});
-
- // explicit offset ("+/-HH:MM")
- else if (is_match(*cp, U'+', U'-'))
- {
- push_parse_scope("date-time offset"sv);
-
- // sign
- int sign = *cp == U'-' ? -1 : 1;
- advance_and_return_if_error_or_eof({});
-
- // "HH"
- int digits[2];
- if (!consume_digit_sequence(digits, 2u))
- set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
- const auto hour = digits[1] + digits[0] * 10;
- if (hour > 23)
- set_error_and_return_default("expected hour between 0 and 23 (inclusive), saw "sv, hour);
- set_error_and_return_if_eof({});
-
- // ':'
- if (*cp != U':')
- set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- // "MM"
- if (!consume_digit_sequence(digits, 2u))
- set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
- const auto minute = digits[1] + digits[0] * 10;
- if (minute > 59)
- set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv, minute);
- offset.minutes = static_cast<decltype(offset.minutes)>((hour * 60 + minute) * sign);
- }
-
- if (!is_eof() && !is_value_terminator(*cp))
- set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
-
- return { date, time, offset };
- }
-
- TOML_NODISCARD
- node_ptr parse_array();
-
- TOML_NODISCARD
- node_ptr parse_inline_table();
-
- TOML_NODISCARD
- node_ptr parse_value_known_prefixes()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(!is_control_character(*cp));
- TOML_ASSERT_ASSUME(*cp != U'_');
-
- switch (cp->value)
- {
- // arrays
- case U'[': return parse_array();
-
- // inline tables
- case U'{': return parse_inline_table();
-
- // floats beginning with '.'
- case U'.': return node_ptr{ new value{ parse_float() } };
-
- // strings
- case U'"': [[fallthrough]];
- case U'\'': return node_ptr{ new value{ parse_string().value } };
-
- default:
- {
- const auto cp_upper = static_cast<uint_least32_t>(cp->value) & ~0x20u;
-
- // bools
- if (cp_upper == 70u || cp_upper == 84u) // F or T
- return node_ptr{ new value{ parse_boolean() } };
-
- // inf/nan
- else if (cp_upper == 73u || cp_upper == 78u) // I or N
- return node_ptr{ new value{ parse_inf_or_nan() } };
-
- else
- return nullptr;
- }
- }
- TOML_UNREACHABLE;
- }
-
- TOML_NODISCARD
- node_ptr parse_value()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
- push_parse_scope("value"sv);
-
- const depth_counter_scope depth_counter{ nested_values };
- if TOML_UNLIKELY(nested_values > max_nested_values)
- set_error_and_return_default("exceeded maximum nested value depth of "sv,
- max_nested_values,
- " (TOML_MAX_NESTED_VALUES)"sv);
-
- // check if it begins with some control character
- // (note that this will also fail for whitespace but we're assuming we've
- // called consume_leading_whitespace() before calling parse_value())
- if TOML_UNLIKELY(is_control_character(*cp))
- set_error_and_return_default("unexpected control character"sv);
-
- // underscores at the beginning
- else if (*cp == U'_')
- set_error_and_return_default("values may not begin with underscores"sv);
-
- const auto begin_pos = cp->position;
- node_ptr val;
-
- do
- {
- TOML_ASSERT_ASSUME(!is_control_character(*cp));
- TOML_ASSERT_ASSUME(*cp != U'_');
-
- // detect the value type and parse accordingly,
- // starting with value types that can be detected
- // unambiguously from just one character.
-
- val = parse_value_known_prefixes();
- return_if_error({});
- if (val)
- break;
-
- // value types from here down require more than one character to unambiguously identify
- // so scan ahead and collect a set of value 'traits'.
- enum TOML_CLOSED_FLAGS_ENUM value_traits : int
- {
- has_nothing = 0,
- has_digits = 1,
- has_b = 1 << 1, // as second char only (0b)
- has_e = 1 << 2, // only float exponents
- has_o = 1 << 3, // as second char only (0o)
- has_p = 1 << 4, // only hexfloat exponents
- has_t = 1 << 5,
- has_x = 1 << 6, // as second or third char only (0x, -0x, +0x)
- has_z = 1 << 7,
- has_colon = 1 << 8,
- has_plus = 1 << 9,
- has_minus = 1 << 10,
- has_dot = 1 << 11,
- begins_sign = 1 << 12,
- begins_digit = 1 << 13,
- begins_zero = 1 << 14,
-
- signs_msk = has_plus | has_minus,
- bdigit_msk = has_digits | begins_digit,
- bzero_msk = bdigit_msk | begins_zero,
- };
- value_traits traits = has_nothing;
- const auto has_any = [&](auto t) noexcept { return (traits & t) != has_nothing; };
- const auto has_none = [&](auto t) noexcept { return (traits & t) == has_nothing; };
- const auto add_trait = [&](auto t) noexcept { traits = static_cast<value_traits>(traits | t); };
-
- // examine the first character to get the 'begins with' traits
- // (good fail-fast opportunity; all the remaining types begin with numeric digits or signs)
- if (is_decimal_digit(*cp))
- {
- add_trait(begins_digit);
- if (*cp == U'0')
- add_trait(begins_zero);
- }
- else if (is_match(*cp, U'+', U'-'))
- add_trait(begins_sign);
- else
- break;
-
- // scan the rest of the value to determine the remaining traits
- char32_t chars[utf8_buffered_reader::max_history_length];
- size_t char_count = {}, advance_count = {};
- bool eof_while_scanning = false;
- const auto scan = [&]() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
- {
- if (is_eof())
- return;
- TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
-
- do
- {
- if (const auto c = **cp; c != U'_')
- {
- chars[char_count++] = c;
-
- if (is_decimal_digit(c))
- add_trait(has_digits);
- else if (is_ascii_letter(c))
- {
- TOML_ASSERT_ASSUME((c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z'));
- switch (static_cast<char32_t>(c | 32u))
- {
- case U'b':
- if (char_count == 2u && has_any(begins_zero))
- add_trait(has_b);
- break;
-
- case U'e':
- if (char_count > 1u
- && has_none(has_b | has_o | has_p | has_t | has_x | has_z | has_colon)
- && (has_none(has_plus | has_minus) || has_any(begins_sign)))
- add_trait(has_e);
- break;
-
- case U'o':
- if (char_count == 2u && has_any(begins_zero))
- add_trait(has_o);
- break;
-
- case U'p':
- if (has_any(has_x))
- add_trait(has_p);
- break;
-
- case U'x':
- if ((char_count == 2u && has_any(begins_zero))
- || (char_count == 3u && has_any(begins_sign) && chars[1] == U'0'))
- add_trait(has_x);
- break;
-
- case U't': add_trait(has_t); break;
- case U'z': add_trait(has_z); break;
- }
- }
- else if (c <= U':')
- {
- TOML_ASSERT_ASSUME(c < U'0' || c > U'9');
- switch (c)
- {
- case U'+': add_trait(has_plus); break;
- case U'-': add_trait(has_minus); break;
- case U'.': add_trait(has_dot); break;
- case U':': add_trait(has_colon); break;
- }
- }
- }
-
- advance_and_return_if_error();
- advance_count++;
- eof_while_scanning = is_eof();
- }
- while (advance_count < (utf8_buffered_reader::max_history_length - 1u) && !is_eof()
- && !is_value_terminator(*cp));
- };
- scan();
- return_if_error({});
-
- // force further scanning if this could have been a date-time with a space instead of a T
- if (char_count == 10u //
- && (traits | begins_zero) == (bzero_msk | has_minus) //
- && chars[4] == U'-' //
- && chars[7] == U'-' //
- && !is_eof() //
- && *cp == U' ')
- {
- const auto pre_advance_count = advance_count;
- const auto pre_scan_traits = traits;
- chars[char_count++] = *cp;
- add_trait(has_t);
-
- const auto backpedal = [&]() noexcept
- {
- go_back(advance_count - pre_advance_count);
- advance_count = pre_advance_count;
- traits = pre_scan_traits;
- char_count = 10u;
- };
-
- advance_and_return_if_error({});
- advance_count++;
-
- if (is_eof() || !is_decimal_digit(*cp))
- backpedal();
- else
- {
- chars[char_count++] = *cp;
-
- advance_and_return_if_error({});
- advance_count++;
-
- scan();
- return_if_error({});
-
- if (char_count == 12u)
- backpedal();
- }
- }
-
- // set the reader back to where we started
- go_back(advance_count);
-
- // if after scanning ahead we still only have one value character,
- // the only valid value type is an integer.
- if (char_count == 1u)
- {
- if (has_any(begins_digit))
- {
- val.reset(new value{ static_cast<int64_t>(chars[0] - U'0') });
- advance(); // skip the digit
- break;
- }
-
- // anything else would be ambiguous.
- else
- set_error_and_return_default(eof_while_scanning ? "encountered end-of-file"sv
- : "could not determine value type"sv);
- }
-
- // now things that can be identified from two or more characters
- return_if_error({});
- TOML_ASSERT_ASSUME(char_count >= 2u);
-
- // do some 'fuzzy matching' where there's no ambiguity, since that allows the specific
- // typed parse functions to take over and show better diagnostics if there's an issue
- // (as opposed to the fallback "could not determine type" message)
- if (has_any(has_p))
- val.reset(new value{ parse_hex_float() });
- else if (has_any(has_x | has_o | has_b))
- {
- int64_t i;
- value_flags flags;
- if (has_any(has_x))
- {
- i = parse_integer<16>();
- flags = value_flags::format_as_hexadecimal;
- }
- else if (has_any(has_o))
- {
- i = parse_integer<8>();
- flags = value_flags::format_as_octal;
- }
- else // has_b
- {
- i = parse_integer<2>();
- flags = value_flags::format_as_binary;
- }
- return_if_error({});
-
- val.reset(new value{ i });
- val->ref_cast<int64_t>().flags(flags);
- }
- else if (has_any(has_e) || (has_any(begins_digit) && chars[1] == U'.'))
- val.reset(new value{ parse_float() });
- else if (has_any(begins_sign))
- {
- // single-digit signed integers
- if (char_count == 2u && has_any(has_digits))
- {
- val.reset(new value{ static_cast<int64_t>(chars[1] - U'0') * (chars[0] == U'-' ? -1LL : 1LL) });
- advance(); // skip the sign
- advance(); // skip the digit
- break;
- }
-
- // simple signed floats (e.g. +1.0)
- if (is_decimal_digit(chars[1]) && chars[2] == U'.')
- val.reset(new value{ parse_float() });
-
- // signed infinity or nan
- else if (is_match(chars[1], U'i', U'n', U'I', U'N'))
- val.reset(new value{ parse_inf_or_nan() });
- }
-
- return_if_error({});
- if (val)
- break;
-
- // match trait masks against what they can match exclusively.
- // all correct value parses will come out of this list, so doing this as a switch is likely to
- // be a better friend to the optimizer on the success path (failure path can be slow but that
- // doesn't matter much).
- switch (unwrap_enum(traits))
- {
- // binary integers
- // 0b10
- case bzero_msk | has_b:
- val.reset(new value{ parse_integer<2>() });
- val->ref_cast<int64_t>().flags(value_flags::format_as_binary);
- break;
-
- // octal integers
- // 0o10
- case bzero_msk | has_o:
- val.reset(new value{ parse_integer<8>() });
- val->ref_cast<int64_t>().flags(value_flags::format_as_octal);
- break;
-
- // decimal integers
- // 00
- // 10
- // +10
- // -10
- case bzero_msk: [[fallthrough]];
- case bdigit_msk: [[fallthrough]];
- case begins_sign | has_digits | has_minus: [[fallthrough]];
- case begins_sign | has_digits | has_plus:
- {
- // if the value was so long we exhausted the history buffer it's reasonable to assume
- // there was more and the value's actual type is impossible to identify without making the
- // buffer bigger (since it could have actually been a float), so emit an error.
- //
- // (this will likely only come up during fuzzing and similar scenarios)
- static constexpr size_t max_numeric_value_length =
- utf8_buffered_reader::max_history_length - 2u;
- if TOML_UNLIKELY(!eof_while_scanning && advance_count > max_numeric_value_length)
- set_error_and_return_default("numeric value too long to identify type - cannot exceed "sv,
- max_numeric_value_length,
- " characters"sv);
-
- val.reset(new value{ parse_integer<10>() });
- break;
- }
-
- // hexadecimal integers
- // 0x10
- case bzero_msk | has_x:
- val.reset(new value{ parse_integer<16>() });
- val->ref_cast<int64_t>().flags(value_flags::format_as_hexadecimal);
- break;
-
- // decimal floats
- // 0e1
- // 0e-1
- // 0e+1
- // 0.0
- // 0.0e1
- // 0.0e-1
- // 0.0e+1
- case bzero_msk | has_e: [[fallthrough]];
- case bzero_msk | has_e | has_minus: [[fallthrough]];
- case bzero_msk | has_e | has_plus: [[fallthrough]];
- case bzero_msk | has_dot: [[fallthrough]];
- case bzero_msk | has_dot | has_e: [[fallthrough]];
- case bzero_msk | has_dot | has_e | has_minus: [[fallthrough]];
- case bzero_msk | has_dot | has_e | has_plus: [[fallthrough]];
- // 1e1
- // 1e-1
- // 1e+1
- // 1.0
- // 1.0e1
- // 1.0e-1
- // 1.0e+1
- case bdigit_msk | has_e: [[fallthrough]];
- case bdigit_msk | has_e | has_minus: [[fallthrough]];
- case bdigit_msk | has_e | has_plus: [[fallthrough]];
- case bdigit_msk | has_dot: [[fallthrough]];
- case bdigit_msk | has_dot | has_e: [[fallthrough]];
- case bdigit_msk | has_dot | has_e | has_minus: [[fallthrough]];
- case bdigit_msk | has_dot | has_e | has_plus: [[fallthrough]];
- // +1e1
- // +1.0
- // +1.0e1
- // +1.0e+1
- // +1.0e-1
- // -1.0e+1
- case begins_sign | has_digits | has_e | has_plus: [[fallthrough]];
- case begins_sign | has_digits | has_dot | has_plus: [[fallthrough]];
- case begins_sign | has_digits | has_dot | has_e | has_plus: [[fallthrough]];
- case begins_sign | has_digits | has_dot | has_e | signs_msk: [[fallthrough]];
- // -1e1
- // -1e+1
- // +1e-1
- // -1.0
- // -1.0e1
- // -1.0e-1
- case begins_sign | has_digits | has_e | has_minus: [[fallthrough]];
- case begins_sign | has_digits | has_e | signs_msk: [[fallthrough]];
- case begins_sign | has_digits | has_dot | has_minus: [[fallthrough]];
- case begins_sign | has_digits | has_dot | has_e | has_minus:
- val.reset(new value{ parse_float() });
- break;
-
- // hexadecimal floats
- // 0x10p0
- // 0x10p-0
- // 0x10p+0
- case bzero_msk | has_x | has_p: [[fallthrough]];
- case bzero_msk | has_x | has_p | has_minus: [[fallthrough]];
- case bzero_msk | has_x | has_p | has_plus: [[fallthrough]];
- // -0x10p0
- // -0x10p-0
- // +0x10p0
- // +0x10p+0
- // -0x10p+0
- // +0x10p-0
- case begins_sign | has_digits | has_x | has_p | has_minus: [[fallthrough]];
- case begins_sign | has_digits | has_x | has_p | has_plus: [[fallthrough]];
- case begins_sign | has_digits | has_x | has_p | signs_msk: [[fallthrough]];
- // 0x10.1p0
- // 0x10.1p-0
- // 0x10.1p+0
- case bzero_msk | has_x | has_dot | has_p: [[fallthrough]];
- case bzero_msk | has_x | has_dot | has_p | has_minus: [[fallthrough]];
- case bzero_msk | has_x | has_dot | has_p | has_plus: [[fallthrough]];
- // -0x10.1p0
- // -0x10.1p-0
- // +0x10.1p0
- // +0x10.1p+0
- // -0x10.1p+0
- // +0x10.1p-0
- case begins_sign | has_digits | has_x | has_dot | has_p | has_minus: [[fallthrough]];
- case begins_sign | has_digits | has_x | has_dot | has_p | has_plus: [[fallthrough]];
- case begins_sign | has_digits | has_x | has_dot | has_p | signs_msk:
- val.reset(new value{ parse_hex_float() });
- break;
-
- // times
- // HH:MM
- // HH:MM:SS
- // HH:MM:SS.FFFFFF
- case bzero_msk | has_colon: [[fallthrough]];
- case bzero_msk | has_colon | has_dot: [[fallthrough]];
- case bdigit_msk | has_colon: [[fallthrough]];
- case bdigit_msk | has_colon | has_dot: val.reset(new value{ parse_time() }); break;
-
- // local dates
- // YYYY-MM-DD
- case bzero_msk | has_minus: [[fallthrough]];
- case bdigit_msk | has_minus: val.reset(new value{ parse_date() }); break;
-
- // date-times
- // YYYY-MM-DDTHH:MM
- // YYYY-MM-DDTHH:MM-HH:MM
- // YYYY-MM-DDTHH:MM+HH:MM
- // YYYY-MM-DD HH:MM
- // YYYY-MM-DD HH:MM-HH:MM
- // YYYY-MM-DD HH:MM+HH:MM
- // YYYY-MM-DDTHH:MM:SS
- // YYYY-MM-DDTHH:MM:SS-HH:MM
- // YYYY-MM-DDTHH:MM:SS+HH:MM
- // YYYY-MM-DD HH:MM:SS
- // YYYY-MM-DD HH:MM:SS-HH:MM
- // YYYY-MM-DD HH:MM:SS+HH:MM
- case bzero_msk | has_minus | has_colon | has_t: [[fallthrough]];
- case bzero_msk | signs_msk | has_colon | has_t: [[fallthrough]];
- case bdigit_msk | has_minus | has_colon | has_t: [[fallthrough]];
- case bdigit_msk | signs_msk | has_colon | has_t: [[fallthrough]];
- // YYYY-MM-DDTHH:MM:SS.FFFFFF
- // YYYY-MM-DDTHH:MM:SS.FFFFFF-HH:MM
- // YYYY-MM-DDTHH:MM:SS.FFFFFF+HH:MM
- // YYYY-MM-DD HH:MM:SS.FFFFFF
- // YYYY-MM-DD HH:MM:SS.FFFFFF-HH:MM
- // YYYY-MM-DD HH:MM:SS.FFFFFF+HH:MM
- case bzero_msk | has_minus | has_colon | has_dot | has_t: [[fallthrough]];
- case bzero_msk | signs_msk | has_colon | has_dot | has_t: [[fallthrough]];
- case bdigit_msk | has_minus | has_colon | has_dot | has_t: [[fallthrough]];
- case bdigit_msk | signs_msk | has_colon | has_dot | has_t: [[fallthrough]];
- // YYYY-MM-DDTHH:MMZ
- // YYYY-MM-DD HH:MMZ
- // YYYY-MM-DDTHH:MM:SSZ
- // YYYY-MM-DD HH:MM:SSZ
- // YYYY-MM-DDTHH:MM:SS.FFFFFFZ
- // YYYY-MM-DD HH:MM:SS.FFFFFFZ
- case bzero_msk | has_minus | has_colon | has_z | has_t: [[fallthrough]];
- case bzero_msk | has_minus | has_colon | has_dot | has_z | has_t: [[fallthrough]];
- case bdigit_msk | has_minus | has_colon | has_z | has_t: [[fallthrough]];
- case bdigit_msk | has_minus | has_colon | has_dot | has_z | has_t:
- val.reset(new value{ parse_date_time() });
- break;
- }
- }
- while (false);
-
- if (!val)
- {
- set_error_at(begin_pos, "could not determine value type"sv);
- return_after_error({});
- }
-
- val->source_ = { begin_pos, current_position(1), reader.source_path() };
- return val;
- }
-
- TOML_NEVER_INLINE
- bool parse_key()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(is_bare_key_character(*cp) || is_string_delimiter(*cp));
- push_parse_scope("key"sv);
-
- key_buffer.clear();
- recording_whitespace = false;
-
- while (!is_error())
- {
- std::string_view key_segment;
- const auto key_begin = current_position();
-
- // bare_key_segment
- if (is_bare_key_character(*cp))
- key_segment = parse_bare_key_segment();
-
- // "quoted key segment"
- else if (is_string_delimiter(*cp))
- {
- const auto begin_pos = cp->position;
-
- recording_whitespace = true;
- parsed_string str = parse_string();
- recording_whitespace = false;
- return_if_error({});
-
- if (str.was_multi_line)
- {
- set_error_at(begin_pos,
- "multi-line strings are prohibited in "sv,
- key_buffer.empty() ? ""sv : "dotted "sv,
- "keys"sv);
- return_after_error({});
- }
- else
- key_segment = str.value;
- }
-
- // ???
- else
- set_error_and_return_default("expected bare key starting character or string delimiter, saw '"sv,
- to_sv(*cp),
- "'"sv);
-
- const auto key_end = current_position();
-
- // whitespace following the key segment
- consume_leading_whitespace();
-
- // store segment
- key_buffer.push_back(key_segment, key_begin, key_end);
-
- // eof or no more key to come
- if (is_eof() || *cp != U'.')
- break;
-
- // was a dotted key - go around again
- advance_and_return_if_error_or_eof({});
- consume_leading_whitespace();
- set_error_and_return_if_eof({});
- }
- return_if_error({});
-
- return true;
- }
-
- TOML_NODISCARD
- key make_key(size_t segment_index) const
- {
- TOML_ASSERT(key_buffer.size() > segment_index);
-
- return key{
- key_buffer[segment_index],
- source_region{ key_buffer.starts[segment_index], key_buffer.ends[segment_index], root.source().path }
- };
- }
-
- TOML_NODISCARD
- TOML_NEVER_INLINE
- table* parse_table_header()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(*cp == U'[');
- push_parse_scope("table header"sv);
-
- const source_position header_begin_pos = cp->position;
- source_position header_end_pos;
- bool is_arr = false;
-
- // parse header
- {
- // skip first '['
- advance_and_return_if_error_or_eof({});
-
- // skip past any whitespace that followed the '['
- const bool had_leading_whitespace = consume_leading_whitespace();
- set_error_and_return_if_eof({});
-
- // skip second '[' (if present)
- if (*cp == U'[')
- {
- if (had_leading_whitespace)
- set_error_and_return_default(
- "[[array-of-table]] brackets must be contiguous (i.e. [ [ this ] ] is prohibited)"sv);
-
- is_arr = true;
- advance_and_return_if_error_or_eof({});
-
- // skip past any whitespace that followed the '['
- consume_leading_whitespace();
- set_error_and_return_if_eof({});
- }
-
- // check for a premature closing ']'
- if (*cp == U']')
- set_error_and_return_default("tables with blank bare keys are explicitly prohibited"sv);
-
- // get the actual key
- start_recording();
- parse_key();
- stop_recording(1u);
- return_if_error({});
-
- // skip past any whitespace that followed the key
- consume_leading_whitespace();
- return_if_error({});
- set_error_and_return_if_eof({});
-
- // consume the closing ']'
- if (*cp != U']')
- set_error_and_return_default("expected ']', saw '"sv, to_sv(*cp), "'"sv);
- if (is_arr)
- {
- advance_and_return_if_error_or_eof({});
- if (*cp != U']')
- set_error_and_return_default("expected ']', saw '"sv, to_sv(*cp), "'"sv);
- }
- advance_and_return_if_error({});
- header_end_pos = current_position(1);
-
- // handle the rest of the line after the header
- consume_leading_whitespace();
- if (!is_eof() && !consume_comment() && !consume_line_break())
- set_error_and_return_default("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
- }
- TOML_ASSERT(!key_buffer.empty());
-
- // check if each parent is a table/table array, or can be created implicitly as a table.
- table* parent = &root;
- for (size_t i = 0, e = key_buffer.size() - 1u; i < e; i++)
- {
- const std::string_view segment = key_buffer[i];
- auto pit = parent->lower_bound(segment);
-
- // parent already existed
- if (pit != parent->end() && pit->first == segment)
- {
- node& p = pit->second;
-
- if (auto tbl = p.as_table())
- {
- // adding to closed inline tables is illegal
- if (tbl->is_inline() && !impl::find(open_inline_tables.begin(), open_inline_tables.end(), tbl))
- set_error_and_return_default("cannot insert '"sv,
- to_sv(recording_buffer),
- "' into existing inline table"sv);
-
- parent = tbl;
- }
- else if (auto arr = p.as_array(); arr && impl::find(table_arrays.begin(), table_arrays.end(), arr))
- {
- // table arrays are a special case;
- // the spec dictates we select the most recently declared element in the array.
- TOML_ASSERT(!arr->empty());
- TOML_ASSERT(arr->back().is_table());
- parent = &arr->back().ref_cast<table>();
- }
- else
- {
- if (!is_arr && p.type() == node_type::table)
- set_error_and_return_default("cannot redefine existing table '"sv,
- to_sv(recording_buffer),
- "'"sv);
- else
- set_error_and_return_default("cannot redefine existing "sv,
- to_sv(p.type()),
- " '"sv,
- to_sv(recording_buffer),
- "' as "sv,
- is_arr ? "array-of-tables"sv : "table"sv);
- }
- }
-
- // need to create a new implicit table
- else
- {
- pit = parent->emplace_hint<table>(pit, make_key(i));
- table& p = pit->second.ref_cast<table>();
- p.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
-
- implicit_tables.push_back(&p);
- parent = &p;
- }
- }
-
- const auto last_segment = key_buffer.back();
- auto it = parent->lower_bound(last_segment);
-
- // if there was already a matching node some sanity checking is necessary;
- // this is ok if we're making an array and the existing element is already an array (new element)
- // or if we're making a table and the existing element is an implicitly-created table (promote it),
- // otherwise this is a redefinition error.
- if (it != parent->end() && it->first == last_segment)
- {
- node& matching_node = it->second;
- if (auto arr = matching_node.as_array();
- is_arr && arr && impl::find(table_arrays.begin(), table_arrays.end(), arr))
- {
- table& tbl = arr->emplace_back<table>();
- tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
- return &tbl;
- }
-
- else if (auto tbl = matching_node.as_table(); !is_arr && tbl && !implicit_tables.empty())
- {
- if (auto found = impl::find(implicit_tables.begin(), implicit_tables.end(), tbl); found)
- {
- bool ok = true;
- if (!tbl->empty())
- {
- for (auto& [_, child] : *tbl)
- {
- if (!child.is_table() && !child.is_array_of_tables())
- {
- ok = false;
- break;
- }
- }
- }
-
- if (ok)
- {
- implicit_tables.erase(implicit_tables.cbegin() + (found - implicit_tables.data()));
- tbl->source_.begin = header_begin_pos;
- tbl->source_.end = header_end_pos;
- return tbl;
- }
- }
- }
-
- // if we get here it's a redefinition error.
- if (!is_arr && matching_node.type() == node_type::table)
- {
- set_error_at(header_begin_pos,
- "cannot redefine existing table '"sv,
- to_sv(recording_buffer),
- "'"sv);
- return_after_error({});
- }
- else
- {
- set_error_at(header_begin_pos,
- "cannot redefine existing "sv,
- to_sv(matching_node.type()),
- " '"sv,
- to_sv(recording_buffer),
- "' as "sv,
- is_arr ? "array-of-tables"sv : "table"sv);
- return_after_error({});
- }
- }
-
- // there was no matching node, sweet - we can freely instantiate a new table/table array.
- else
- {
- auto last_key = make_key(key_buffer.size() - 1u);
-
- // if it's an array we need to make the array and it's first table element,
- // set the starting regions, and return the table element
- if (is_arr)
- {
- it = parent->emplace_hint<array>(it, std::move(last_key));
- array& tbl_arr = it->second.ref_cast<array>();
- table_arrays.push_back(&tbl_arr);
- tbl_arr.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
-
- table& tbl = tbl_arr.emplace_back<table>();
- tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
- return &tbl;
- }
-
- // otherwise we're just making a table
- else
- {
- it = parent->emplace_hint<table>(it, std::move(last_key));
- table& tbl = it->second.ref_cast<table>();
- tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() };
- return &tbl;
- }
- }
- }
-
- TOML_NEVER_INLINE
- bool parse_key_value_pair_and_insert(table* tbl)
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(is_string_delimiter(*cp) || is_bare_key_character(*cp));
- push_parse_scope("key-value pair"sv);
-
- // read the key into the key buffer
- start_recording();
- parse_key();
- stop_recording(1u);
- return_if_error({});
- TOML_ASSERT(key_buffer.size() >= 1u);
-
- // skip past any whitespace that followed the key
- consume_leading_whitespace();
- set_error_and_return_if_eof({});
-
- // '='
- if (*cp != U'=')
- set_error_and_return_default("expected '=', saw '"sv, to_sv(*cp), "'"sv);
- advance_and_return_if_error_or_eof({});
-
- // skip past any whitespace that followed the '='
- consume_leading_whitespace();
- return_if_error({});
- set_error_and_return_if_eof({});
-
- // check that the next character could actually be a value
- if (is_value_terminator(*cp))
- set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv);
-
- // if it's a dotted kvp we need to spawn the parent sub-tables if necessary,
- // and set the target table to the second-to-last one in the chain
- if (key_buffer.size() > 1u)
- {
- for (size_t i = 0; i < key_buffer.size() - 1u; i++)
- {
- const std::string_view segment = key_buffer[i];
- auto pit = tbl->lower_bound(segment);
-
- // parent already existed
- if (pit != tbl->end() && pit->first == segment)
- {
- table* p = pit->second.as_table();
-
- // redefinition
- if TOML_UNLIKELY(!p
- || !(impl::find(dotted_key_tables.begin(), dotted_key_tables.end(), p)
- || impl::find(implicit_tables.begin(), implicit_tables.end(), p)))
- {
- set_error_at(key_buffer.starts[i],
- "cannot redefine existing "sv,
- to_sv(pit->second.type()),
- " as dotted key-value pair"sv);
- return_after_error({});
- }
-
- tbl = p;
- }
-
- // need to create a new implicit table
- else
- {
- pit = tbl->emplace_hint<table>(pit, make_key(i));
- table& p = pit->second.ref_cast<table>();
- p.source_ = pit->first.source();
-
- dotted_key_tables.push_back(&p);
- tbl = &p;
- }
- }
- }
-
- // ensure this isn't a redefinition
- const std::string_view last_segment = key_buffer.back();
- auto it = tbl->lower_bound(last_segment);
- if (it != tbl->end() && it->first == last_segment)
- {
- set_error("cannot redefine existing "sv,
- to_sv(it->second.type()),
- " '"sv,
- to_sv(recording_buffer),
- "'"sv);
- return_after_error({});
- }
-
- // create the key first since the key buffer will likely get overwritten during value parsing (inline
- // tables)
- auto last_key = make_key(key_buffer.size() - 1u);
-
- // now we can actually parse the value
- node_ptr val = parse_value();
- return_if_error({});
-
- tbl->emplace_hint<node_ptr>(it, std::move(last_key), std::move(val));
- return true;
- }
-
- void parse_document()
- {
- assert_not_error();
- assert_not_eof();
- push_parse_scope("root table"sv);
-
- table* current_table = &root;
-
- do
- {
- return_if_error();
-
- // leading whitespace, line endings, comments
- if (consume_leading_whitespace() || consume_line_break() || consume_comment())
- continue;
- return_if_error();
-
- // [tables]
- // [[table array]]
- if (*cp == U'[')
- current_table = parse_table_header();
-
- // bare_keys
- // dotted.keys
- // "quoted keys"
- else if (is_bare_key_character(*cp) || is_string_delimiter(*cp))
- {
- push_parse_scope("key-value pair"sv);
-
- parse_key_value_pair_and_insert(current_table);
-
- // handle the rest of the line after the kvp
- // (this is not done in parse_key_value_pair() because that is also used for inline tables)
- consume_leading_whitespace();
- return_if_error();
- if (!is_eof() && !consume_comment() && !consume_line_break())
- set_error("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
- }
-
- else // ??
- set_error("expected keys, tables, whitespace or comments, saw '"sv, to_sv(cp), "'"sv);
- }
- while (!is_eof());
-
- auto eof_pos = current_position(1);
- root.source_.end = eof_pos;
- if (current_table && current_table != &root && current_table->source_.end <= current_table->source_.begin)
- current_table->source_.end = eof_pos;
- }
-
- static void update_region_ends(node& nde) noexcept
- {
- const auto type = nde.type();
- if (type > node_type::array)
- return;
-
- if (type == node_type::table)
- {
- auto& tbl = nde.ref_cast<table>();
- if (tbl.is_inline()) // inline tables (and all their inline descendants) are already correctly
- // terminated
- return;
-
- auto end = nde.source_.end;
- for (auto&& [k, v] : tbl)
- {
- TOML_UNUSED(k);
- update_region_ends(v);
- if (end < v.source_.end)
- end = v.source_.end;
- }
- }
- else // arrays
- {
- auto& arr = nde.ref_cast<array>();
- auto end = nde.source_.end;
- for (auto&& v : arr)
- {
- update_region_ends(v);
- if (end < v.source_.end)
- end = v.source_.end;
- }
- nde.source_.end = end;
- }
- }
-
- public:
- parser(utf8_reader_interface&& reader_) //
- : reader{ reader_ }
- {
- root.source_ = { prev_pos, prev_pos, reader.source_path() };
-
- if (!reader.peek_eof())
- {
- cp = reader.read_next();
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ double parse_hex_float() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(is_match(*cp, U'0', U'+', U'-'));
+ push_parse_scope("hexadecimal floating-point"sv);
+
+#if TOML_LANG_UNRELEASED // toml/issues/562 (hexfloats)
+
+ // sign
+ const int sign = *cp == U'-' ? -1 : 1;
+ if (is_match(*cp, U'+', U'-')) advance_and_return_if_error_or_eof({});
+
+ // '0'
+ if (*cp != U'0') set_error_and_return_default(" expected '0', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // 'x' or 'X'
+ if (!is_match(*cp, U'x', U'X'))
+ set_error_and_return_default("expected 'x' or 'X', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // <HEX DIGITS> ([.]<HEX DIGITS>)? [pP] [+-]? <DEC DIGITS>
+
+ // consume value fragments
+ struct fragment {
+ char chars[24];
+ size_t length;
+ double value;
+ };
+ fragment fragments[] = {
+ {}, // mantissa, whole part
+ {}, // mantissa, fractional part
+ {} // exponent
+ };
+ fragment* current_fragment = fragments;
+ const utf8_codepoint* prev = {};
+ int exponent_sign = 1;
+ while (!is_eof() && !is_value_terminator(*cp)) {
+ if (*cp == U'_') {
+ if (!prev || !is_hexadecimal_digit(*prev))
+ set_error_and_return_default("underscores may only follow digits"sv);
+
+ prev = cp;
+ advance_and_return_if_error_or_eof({});
+ continue;
+ } else if (prev && *prev == U'_' && !is_hexadecimal_digit(*cp))
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ else if (*cp == U'.') {
+ // 0x10.0p-.0 (exponent cannot have '.')
+ if (current_fragment == fragments + 2)
+ set_error_and_return_default("expected exponent digit or sign, saw '.'"sv);
+
+ // 0x10.0.p-0 (multiple '.')
+ else if (current_fragment == fragments + 1)
+ set_error_and_return_default("expected hexadecimal digit or exponent, saw '.'"sv);
+
+ else
+ current_fragment++;
+ } else if (is_match(*cp, U'p', U'P')) {
+ // 0x10.0pp-0 (multiple 'p')
+ if (current_fragment == fragments + 2)
+ set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp),
+ "'"sv);
+
+ // 0x.p-0 (mantissa is just '.')
+ else if (fragments[0].length == 0u && fragments[1].length == 0u)
+ set_error_and_return_default("expected hexadecimal digit, saw '"sv, to_sv(*cp), "'"sv);
+
+ else
+ current_fragment = fragments + 2;
+ } else if (is_match(*cp, U'+', U'-')) {
+ // 0x-10.0p-0 (sign in mantissa)
+ if (current_fragment != fragments + 2)
+ set_error_and_return_default("expected hexadecimal digit or '.', saw '"sv, to_sv(*cp),
+ "'"sv);
+
+ // 0x10.0p0- (misplaced exponent sign)
+ else if (!is_match(*prev, U'p', U'P'))
+ set_error_and_return_default("expected exponent digit, saw '"sv, to_sv(*cp), "'"sv);
+
+ else
+ exponent_sign = *cp == U'-' ? -1 : 1;
+ } else if (current_fragment < fragments + 2 && !is_hexadecimal_digit(*cp))
+ set_error_and_return_default("expected hexadecimal digit or '.', saw '"sv, to_sv(*cp),
+ "'"sv);
+ else if (current_fragment == fragments + 2 && !is_decimal_digit(*cp))
+ set_error_and_return_default("expected exponent digit or sign, saw '"sv, to_sv(*cp),
+ "'"sv);
+ else if (current_fragment->length == sizeof(fragment::chars))
+ set_error_and_return_default("fragment exceeeds maximum length of "sv,
+ sizeof(fragment::chars), " characters"sv);
+ else
+ current_fragment->chars[current_fragment->length++] = static_cast<char>(cp->bytes[0]);
+
+ prev = cp;
+ advance_and_return_if_error({});
+ }
+
+ // sanity-check ending state
+ if (current_fragment != fragments + 2 || current_fragment->length == 0u) {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("missing exponent"sv);
+ } else if (prev && *prev == U'_') {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ }
+
+ // calculate values for the three fragments
+ for (int fragment_idx = 0; fragment_idx < 3; fragment_idx++) {
+ auto& f = fragments[fragment_idx];
+ const uint32_t base = fragment_idx == 2 ? 10u : 16u;
+
+ // left-trim zeroes
+ const char* c = f.chars;
+ size_t sig = {};
+ while (f.length && *c == '0') {
+ f.length--;
+ c++;
+ sig++;
+ }
+ if (!f.length) continue;
+
+ // calculate value
+ auto place = 1u;
+ for (size_t i = 0; i < f.length - 1u; i++) place *= base;
+ uint32_t val{};
+ while (place) {
+ if (base == 16)
+ val += place * hex_to_dec(*c);
+ else
+ val += place * static_cast<uint32_t>(*c - '0');
+ if (fragment_idx == 1) sig++;
+ c++;
+ place /= base;
+ }
+ f.value = static_cast<double>(val);
+
+ // shift the fractional part
+ if (fragment_idx == 1) {
+ while (sig--) f.value /= base;
+ }
+ }
+
+ return (fragments[0].value + fragments[1].value) *
+ pow(2.0, fragments[2].value * exponent_sign) * sign;
+
+#else // !TOML_LANG_UNRELEASED
+
+ set_error_and_return_default(
+ "hexadecimal floating-point values are not supported "
+ "in TOML 1.0.0 and earlier"sv);
+
+#endif // !TOML_LANG_UNRELEASED
+ }
+
+ template <uint64_t base>
+ TOML_NODISCARD TOML_NEVER_INLINE int64_t parse_integer() {
+ return_if_error({});
+ assert_not_eof();
+ using traits = parse_integer_traits<base>;
+ push_parse_scope(traits::scope_qualifier);
+
+ [[maybe_unused]] int64_t sign = 1;
+ if constexpr (traits::is_signed) {
+ sign = *cp == U'-' ? -1 : 1;
+ if (is_match(*cp, U'+', U'-')) advance_and_return_if_error_or_eof({});
+ }
+
+ if constexpr (base == 10) {
+ if (!traits::is_digit(*cp))
+ set_error_and_return_default("expected expected digit or sign, saw '"sv, to_sv(*cp),
+ "'"sv);
+ } else {
+ // '0'
+ if (*cp != U'0') set_error_and_return_default("expected '0', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // 'b', 'o', 'x'
+ if (*cp != traits::prefix_codepoint)
+ set_error_and_return_default("expected '"sv, traits::prefix, "', saw '"sv, to_sv(*cp),
+ "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ if (!traits::is_digit(*cp))
+ set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
+ }
+
+ // consume digits
+ char digits[utf8_buffered_reader::max_history_length];
+ size_t length = {};
+ const utf8_codepoint* prev = {};
+ while (!is_eof() && !is_value_terminator(*cp)) {
+ if (*cp == U'_') {
+ if (!prev || !traits::is_digit(*prev))
+ set_error_and_return_default("underscores may only follow digits"sv);
+
+ prev = cp;
+ advance_and_return_if_error_or_eof({});
+ continue;
+ } else if TOML_UNLIKELY (prev && *prev == U'_' && !traits::is_digit(*cp))
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ else if TOML_UNLIKELY (!traits::is_digit(*cp))
+ set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
+ else if TOML_UNLIKELY (length == sizeof(digits))
+ set_error_and_return_default("exceeds length limit of "sv, sizeof(digits), " digits"sv);
+ else
+ digits[length++] = static_cast<char>(cp->bytes[0]);
+
+ prev = cp;
+ advance_and_return_if_error({});
+ }
+
+ // sanity check ending state
+ if (prev && *prev == U'_') {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("underscores must be followed by digits"sv);
+ }
+
+ // single digits can be converted trivially
+ if (length == 1u) {
+ int64_t result;
+
+ if constexpr (base == 16)
+ result = static_cast<int64_t>(hex_to_dec(digits[0]));
+ else
+ result = static_cast<int64_t>(digits[0] - '0');
+
+ if constexpr (traits::is_signed) result *= sign;
+
+ return result;
+ }
+
+ // bin, oct and hex allow leading zeroes so trim them first
+ const char* end = digits + length;
+ const char* msd = digits;
+ if constexpr (base != 10) {
+ while (msd < end && *msd == '0') msd++;
+ if (msd == end) return 0ll;
+ }
+
+ // decimal integers do not allow leading zeroes
+ else {
+ if TOML_UNLIKELY (digits[0] == '0')
+ set_error_and_return_default("leading zeroes are prohibited"sv);
+ }
+
+ // range check
+ if TOML_UNLIKELY (static_cast<size_t>(end - msd) > traits::max_digits)
+ set_error_and_return_default("'"sv, traits::full_prefix, std::string_view{digits, length},
+ "' is not representable in 64 bits"sv);
+
+ // do the thing
+ {
+ uint64_t result = {};
+ {
+ uint64_t power = 1;
+ while (--end >= msd) {
+ if constexpr (base == 16)
+ result += power * hex_to_dec(*end);
+ else
+ result += power * static_cast<uint64_t>(*end - '0');
+
+ power *= base;
+ }
+ }
+
+ // range check
+ static constexpr auto i64_max =
+ static_cast<uint64_t>((std::numeric_limits<int64_t>::max)());
+ if TOML_UNLIKELY (result > i64_max + (sign < 0 ? 1u : 0u))
+ set_error_and_return_default("'"sv, traits::full_prefix, std::string_view{digits, length},
+ "' is not representable in 64 bits"sv);
+
+ if constexpr (traits::is_signed) {
+ // avoid signed multiply UB when parsing INT64_MIN
+ if TOML_UNLIKELY (sign < 0 && result == i64_max + 1u)
+ return (std::numeric_limits<int64_t>::min)();
+
+ return static_cast<int64_t>(result) * sign;
+ } else
+ return static_cast<int64_t>(result);
+ }
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ date parse_date(bool part_of_datetime = false) {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
+ push_parse_scope("date"sv);
+
+ // "YYYY"
+ uint32_t digits[4];
+ if (!consume_digit_sequence(digits, 4u))
+ set_error_and_return_default("expected 4-digit year, saw '"sv, to_sv(cp), "'"sv);
+ const auto year = digits[3] + digits[2] * 10u + digits[1] * 100u + digits[0] * 1000u;
+ const auto is_leap_year = (year % 4u == 0u) && ((year % 100u != 0u) || (year % 400u == 0u));
+ set_error_and_return_if_eof({});
+
+ // '-'
+ if (*cp != U'-') set_error_and_return_default("expected '-', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "MM"
+ if (!consume_digit_sequence(digits, 2u))
+ set_error_and_return_default("expected 2-digit month, saw '"sv, to_sv(cp), "'"sv);
+ const auto month = digits[1] + digits[0] * 10u;
+ if (month == 0u || month > 12u)
+ set_error_and_return_default("expected month between 1 and 12 (inclusive), saw "sv, month);
+ const auto max_days_in_month =
+ month == 2u ? (is_leap_year ? 29u : 28u)
+ : (month == 4u || month == 6u || month == 9u || month == 11u ? 30u : 31u);
+ set_error_and_return_if_eof({});
+
+ // '-'
+ if (*cp != U'-') set_error_and_return_default("expected '-', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "DD"
+ if (!consume_digit_sequence(digits, 2u))
+ set_error_and_return_default("expected 2-digit day, saw '"sv, to_sv(cp), "'"sv);
+ const auto day = digits[1] + digits[0] * 10u;
+ if (day == 0u || day > max_days_in_month)
+ set_error_and_return_default("expected day between 1 and "sv, max_days_in_month,
+ " (inclusive), saw "sv, day);
+
+ if (!part_of_datetime && !is_eof() && !is_value_terminator(*cp))
+ set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
+
+ return {year, month, day};
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ time parse_time(bool part_of_datetime = false) {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
+ push_parse_scope("time"sv);
+
+ static constexpr size_t max_digits = 64; // far more than necessary but needed to allow
+ // fractional millisecond truncation per the spec
+ uint32_t digits[max_digits];
+
+ // "HH"
+ if (!consume_digit_sequence(digits, 2u))
+ set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
+ const auto hour = digits[1] + digits[0] * 10u;
+ if (hour > 23u)
+ set_error_and_return_default("expected hour between 0 to 59 (inclusive), saw "sv, hour);
+ set_error_and_return_if_eof({});
+
+ // ':'
+ if (*cp != U':') set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "MM"
+ if (!consume_digit_sequence(digits, 2u))
+ set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
+ const auto minute = digits[1] + digits[0] * 10u;
+ if (minute > 59u)
+ set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv,
+ minute);
+ auto time = toml::time{hour, minute};
+
+ // ':'
+ if constexpr (TOML_LANG_UNRELEASED) // toml/issues/671 (allow omission of seconds)
+ {
+ if (is_eof() || is_value_terminator(*cp) ||
+ (part_of_datetime && is_match(*cp, U'+', U'-', U'Z', U'z')))
+ return time;
+ } else
+ set_error_and_return_if_eof({});
+ if (*cp != U':') set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "SS"
+ if (!consume_digit_sequence(digits, 2u))
+ set_error_and_return_default("expected 2-digit second, saw '"sv, to_sv(cp), "'"sv);
+ const auto second = digits[1] + digits[0] * 10u;
+ if (second > 59u)
+ set_error_and_return_default("expected second between 0 and 59 (inclusive), saw "sv,
+ second);
+ time.second = static_cast<decltype(time.second)>(second);
+
+ // '.' (early-exiting is allowed; fractional is optional)
+ if (is_eof() || is_value_terminator(*cp) ||
+ (part_of_datetime && is_match(*cp, U'+', U'-', U'Z', U'z')))
+ return time;
+ if (*cp != U'.') set_error_and_return_default("expected '.', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "FFFFFFFFF"
+ size_t digit_count = consume_variable_length_digit_sequence(digits, max_digits);
+ if (!digit_count) {
+ set_error_and_return_if_eof({});
+ set_error_and_return_default("expected fractional digits, saw '"sv, to_sv(*cp), "'"sv);
+ } else if (!is_eof()) {
+ if (digit_count == max_digits && is_decimal_digit(*cp))
+ set_error_and_return_default("fractional component exceeds maximum precision of "sv,
+ max_digits);
+ else if (!part_of_datetime && !is_value_terminator(*cp))
+ set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
+ }
+ uint32_t value = 0u;
+ uint32_t place = 1u;
+ for (auto i = impl::min<size_t>(digit_count, 9u); i-- > 0u;) {
+ value += digits[i] * place;
+ place *= 10u;
+ }
+ for (auto i = digit_count; i < 9u; i++) // implicit zeros
+ value *= 10u;
+ time.nanosecond = value;
+ return time;
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ date_time parse_date_time() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
+ push_parse_scope("date-time"sv);
+
+ // "YYYY-MM-DD"
+ auto date = parse_date(true);
+ set_error_and_return_if_eof({});
+
+ // ' ', 'T' or 't'
+ if (!is_match(*cp, U' ', U'T', U't'))
+ set_error_and_return_default("expected space, 'T' or 't', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "HH:MM:SS.FFFFFFFFF"
+ auto time = parse_time(true);
+ return_if_error({});
+
+ // no offset
+ if (is_eof() || is_value_terminator(*cp)) return {date, time};
+
+ // zero offset ('Z' or 'z')
+ time_offset offset{};
+ if (is_match(*cp, U'Z', U'z')) advance_and_return_if_error({});
+
+ // explicit offset ("+/-HH:MM")
+ else if (is_match(*cp, U'+', U'-')) {
+ push_parse_scope("date-time offset"sv);
+
+ // sign
+ int sign = *cp == U'-' ? -1 : 1;
+ advance_and_return_if_error_or_eof({});
+
+ // "HH"
+ int digits[2];
+ if (!consume_digit_sequence(digits, 2u))
+ set_error_and_return_default("expected 2-digit hour, saw '"sv, to_sv(cp), "'"sv);
+ const auto hour = digits[1] + digits[0] * 10;
+ if (hour > 23)
+ set_error_and_return_default("expected hour between 0 and 23 (inclusive), saw "sv, hour);
+ set_error_and_return_if_eof({});
+
+ // ':'
+ if (*cp != U':') set_error_and_return_default("expected ':', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // "MM"
+ if (!consume_digit_sequence(digits, 2u))
+ set_error_and_return_default("expected 2-digit minute, saw '"sv, to_sv(cp), "'"sv);
+ const auto minute = digits[1] + digits[0] * 10;
+ if (minute > 59)
+ set_error_and_return_default("expected minute between 0 and 59 (inclusive), saw "sv,
+ minute);
+ offset.minutes = static_cast<decltype(offset.minutes)>((hour * 60 + minute) * sign);
+ }
+
+ if (!is_eof() && !is_value_terminator(*cp))
+ set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
+
+ return {date, time, offset};
+ }
+
+ TOML_NODISCARD
+ node_ptr parse_array();
+
+ TOML_NODISCARD
+ node_ptr parse_inline_table();
+
+ TOML_NODISCARD
+ node_ptr parse_value_known_prefixes() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(!is_control_character(*cp));
+ TOML_ASSERT_ASSUME(*cp != U'_');
+
+ switch (cp->value) {
+ // arrays
+ case U'[':
+ return parse_array();
+
+ // inline tables
+ case U'{':
+ return parse_inline_table();
+
+ // floats beginning with '.'
+ case U'.':
+ return node_ptr{new value{parse_float()}};
+
+ // strings
+ case U'"':
+ [[fallthrough]];
+ case U'\'':
+ return node_ptr{new value{parse_string().value}};
+
+ default: {
+ const auto cp_upper = static_cast<uint_least32_t>(cp->value) & ~0x20u;
+
+ // bools
+ if (cp_upper == 70u || cp_upper == 84u) // F or T
+ return node_ptr{new value{parse_boolean()}};
+
+ // inf/nan
+ else if (cp_upper == 73u || cp_upper == 78u) // I or N
+ return node_ptr{new value{parse_inf_or_nan()}};
+
+ else
+ return nullptr;
+ }
+ }
+ TOML_UNREACHABLE;
+ }
+
+ TOML_NODISCARD
+ node_ptr parse_value() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
+ push_parse_scope("value"sv);
+
+ const depth_counter_scope depth_counter{nested_values};
+ if TOML_UNLIKELY (nested_values > max_nested_values)
+ set_error_and_return_default("exceeded maximum nested value depth of "sv, max_nested_values,
+ " (TOML_MAX_NESTED_VALUES)"sv);
+
+ // check if it begins with some control character
+ // (note that this will also fail for whitespace but we're assuming we've
+ // called consume_leading_whitespace() before calling parse_value())
+ if TOML_UNLIKELY (is_control_character(*cp))
+ set_error_and_return_default("unexpected control character"sv);
+
+ // underscores at the beginning
+ else if (*cp == U'_')
+ set_error_and_return_default("values may not begin with underscores"sv);
+
+ const auto begin_pos = cp->position;
+ node_ptr val;
+
+ do {
+ TOML_ASSERT_ASSUME(!is_control_character(*cp));
+ TOML_ASSERT_ASSUME(*cp != U'_');
+
+ // detect the value type and parse accordingly,
+ // starting with value types that can be detected
+ // unambiguously from just one character.
+
+ val = parse_value_known_prefixes();
+ return_if_error({});
+ if (val) break;
+
+ // value types from here down require more than one character to unambiguously identify
+ // so scan ahead and collect a set of value 'traits'.
+ enum TOML_CLOSED_FLAGS_ENUM value_traits : int {
+ has_nothing = 0,
+ has_digits = 1,
+ has_b = 1 << 1, // as second char only (0b)
+ has_e = 1 << 2, // only float exponents
+ has_o = 1 << 3, // as second char only (0o)
+ has_p = 1 << 4, // only hexfloat exponents
+ has_t = 1 << 5,
+ has_x = 1 << 6, // as second or third char only (0x, -0x, +0x)
+ has_z = 1 << 7,
+ has_colon = 1 << 8,
+ has_plus = 1 << 9,
+ has_minus = 1 << 10,
+ has_dot = 1 << 11,
+ begins_sign = 1 << 12,
+ begins_digit = 1 << 13,
+ begins_zero = 1 << 14,
+
+ signs_msk = has_plus | has_minus,
+ bdigit_msk = has_digits | begins_digit,
+ bzero_msk = bdigit_msk | begins_zero,
+ };
+ value_traits traits = has_nothing;
+ const auto has_any = [&](auto t) noexcept { return (traits & t) != has_nothing; };
+ const auto has_none = [&](auto t) noexcept { return (traits & t) == has_nothing; };
+ const auto add_trait = [&](auto t) noexcept {
+ traits = static_cast<value_traits>(traits | t);
+ };
+
+ // examine the first character to get the 'begins with' traits
+ // (good fail-fast opportunity; all the remaining types begin with numeric digits or signs)
+ if (is_decimal_digit(*cp)) {
+ add_trait(begins_digit);
+ if (*cp == U'0') add_trait(begins_zero);
+ } else if (is_match(*cp, U'+', U'-'))
+ add_trait(begins_sign);
+ else
+ break;
+
+ // scan the rest of the value to determine the remaining traits
+ char32_t chars[utf8_buffered_reader::max_history_length];
+ size_t char_count = {}, advance_count = {};
+ bool eof_while_scanning = false;
+ const auto scan = [&]() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) {
+ if (is_eof()) return;
+ TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
+
+ do {
+ if (const auto c = **cp; c != U'_') {
+ chars[char_count++] = c;
+
+ if (is_decimal_digit(c))
+ add_trait(has_digits);
+ else if (is_ascii_letter(c)) {
+ TOML_ASSERT_ASSUME((c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z'));
+ switch (static_cast<char32_t>(c | 32u)) {
+ case U'b':
+ if (char_count == 2u && has_any(begins_zero)) add_trait(has_b);
+ break;
+
+ case U'e':
+ if (char_count > 1u &&
+ has_none(has_b | has_o | has_p | has_t | has_x | has_z | has_colon) &&
+ (has_none(has_plus | has_minus) || has_any(begins_sign)))
+ add_trait(has_e);
+ break;
+
+ case U'o':
+ if (char_count == 2u && has_any(begins_zero)) add_trait(has_o);
+ break;
+
+ case U'p':
+ if (has_any(has_x)) add_trait(has_p);
+ break;
+
+ case U'x':
+ if ((char_count == 2u && has_any(begins_zero)) ||
+ (char_count == 3u && has_any(begins_sign) && chars[1] == U'0'))
+ add_trait(has_x);
+ break;
+
+ case U't':
+ add_trait(has_t);
+ break;
+ case U'z':
+ add_trait(has_z);
+ break;
+ }
+ } else if (c <= U':') {
+ TOML_ASSERT_ASSUME(c < U'0' || c > U'9');
+ switch (c) {
+ case U'+':
+ add_trait(has_plus);
+ break;
+ case U'-':
+ add_trait(has_minus);
+ break;
+ case U'.':
+ add_trait(has_dot);
+ break;
+ case U':':
+ add_trait(has_colon);
+ break;
+ }
+ }
+ }
+
+ advance_and_return_if_error();
+ advance_count++;
+ eof_while_scanning = is_eof();
+ } while (advance_count < (utf8_buffered_reader::max_history_length - 1u) && !is_eof() &&
+ !is_value_terminator(*cp));
+ };
+ scan();
+ return_if_error({});
+
+ // force further scanning if this could have been a date-time with a space instead of a T
+ if (char_count == 10u //
+ && (traits | begins_zero) == (bzero_msk | has_minus) //
+ && chars[4] == U'-' //
+ && chars[7] == U'-' //
+ && !is_eof() //
+ && *cp == U' ') {
+ const auto pre_advance_count = advance_count;
+ const auto pre_scan_traits = traits;
+ chars[char_count++] = *cp;
+ add_trait(has_t);
+
+ const auto backpedal = [&]() noexcept {
+ go_back(advance_count - pre_advance_count);
+ advance_count = pre_advance_count;
+ traits = pre_scan_traits;
+ char_count = 10u;
+ };
+
+ advance_and_return_if_error({});
+ advance_count++;
+
+ if (is_eof() || !is_decimal_digit(*cp))
+ backpedal();
+ else {
+ chars[char_count++] = *cp;
+
+ advance_and_return_if_error({});
+ advance_count++;
+
+ scan();
+ return_if_error({});
+
+ if (char_count == 12u) backpedal();
+ }
+ }
+
+ // set the reader back to where we started
+ go_back(advance_count);
+
+ // if after scanning ahead we still only have one value character,
+ // the only valid value type is an integer.
+ if (char_count == 1u) {
+ if (has_any(begins_digit)) {
+ val.reset(new value{static_cast<int64_t>(chars[0] - U'0')});
+ advance(); // skip the digit
+ break;
+ }
+
+ // anything else would be ambiguous.
+ else
+ set_error_and_return_default(eof_while_scanning ? "encountered end-of-file"sv
+ : "could not determine value type"sv);
+ }
+
+ // now things that can be identified from two or more characters
+ return_if_error({});
+ TOML_ASSERT_ASSUME(char_count >= 2u);
+
+ // do some 'fuzzy matching' where there's no ambiguity, since that allows the specific
+ // typed parse functions to take over and show better diagnostics if there's an issue
+ // (as opposed to the fallback "could not determine type" message)
+ if (has_any(has_p))
+ val.reset(new value{parse_hex_float()});
+ else if (has_any(has_x | has_o | has_b)) {
+ int64_t i;
+ value_flags flags;
+ if (has_any(has_x)) {
+ i = parse_integer<16>();
+ flags = value_flags::format_as_hexadecimal;
+ } else if (has_any(has_o)) {
+ i = parse_integer<8>();
+ flags = value_flags::format_as_octal;
+ } else // has_b
+ {
+ i = parse_integer<2>();
+ flags = value_flags::format_as_binary;
+ }
+ return_if_error({});
+
+ val.reset(new value{i});
+ val->ref_cast<int64_t>().flags(flags);
+ } else if (has_any(has_e) || (has_any(begins_digit) && chars[1] == U'.'))
+ val.reset(new value{parse_float()});
+ else if (has_any(begins_sign)) {
+ // single-digit signed integers
+ if (char_count == 2u && has_any(has_digits)) {
+ val.reset(
+ new value{static_cast<int64_t>(chars[1] - U'0') * (chars[0] == U'-' ? -1LL : 1LL)});
+ advance(); // skip the sign
+ advance(); // skip the digit
+ break;
+ }
+
+ // simple signed floats (e.g. +1.0)
+ if (is_decimal_digit(chars[1]) && chars[2] == U'.') val.reset(new value{parse_float()});
+
+ // signed infinity or nan
+ else if (is_match(chars[1], U'i', U'n', U'I', U'N'))
+ val.reset(new value{parse_inf_or_nan()});
+ }
+
+ return_if_error({});
+ if (val) break;
+
+ // match trait masks against what they can match exclusively.
+ // all correct value parses will come out of this list, so doing this as a switch is likely
+ // to be a better friend to the optimizer on the success path (failure path can be slow but
+ // that doesn't matter much).
+ switch (unwrap_enum(traits)) {
+ // binary integers
+ // 0b10
+ case bzero_msk | has_b:
+ val.reset(new value{parse_integer<2>()});
+ val->ref_cast<int64_t>().flags(value_flags::format_as_binary);
+ break;
+
+ // octal integers
+ // 0o10
+ case bzero_msk | has_o:
+ val.reset(new value{parse_integer<8>()});
+ val->ref_cast<int64_t>().flags(value_flags::format_as_octal);
+ break;
+
+ // decimal integers
+ // 00
+ // 10
+ // +10
+ // -10
+ case bzero_msk:
+ [[fallthrough]];
+ case bdigit_msk:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_minus:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_plus: {
+ // if the value was so long we exhausted the history buffer it's reasonable to assume
+ // there was more and the value's actual type is impossible to identify without making
+ // the buffer bigger (since it could have actually been a float), so emit an error.
+ //
+ // (this will likely only come up during fuzzing and similar scenarios)
+ static constexpr size_t max_numeric_value_length =
+ utf8_buffered_reader::max_history_length - 2u;
+ if TOML_UNLIKELY (!eof_while_scanning && advance_count > max_numeric_value_length)
+ set_error_and_return_default(
+ "numeric value too long to identify type - cannot exceed "sv,
+ max_numeric_value_length, " characters"sv);
+
+ val.reset(new value{parse_integer<10>()});
+ break;
+ }
+
+ // hexadecimal integers
+ // 0x10
+ case bzero_msk | has_x:
+ val.reset(new value{parse_integer<16>()});
+ val->ref_cast<int64_t>().flags(value_flags::format_as_hexadecimal);
+ break;
+
+ // decimal floats
+ // 0e1
+ // 0e-1
+ // 0e+1
+ // 0.0
+ // 0.0e1
+ // 0.0e-1
+ // 0.0e+1
+ case bzero_msk | has_e:
+ [[fallthrough]];
+ case bzero_msk | has_e | has_minus:
+ [[fallthrough]];
+ case bzero_msk | has_e | has_plus:
+ [[fallthrough]];
+ case bzero_msk | has_dot:
+ [[fallthrough]];
+ case bzero_msk | has_dot | has_e:
+ [[fallthrough]];
+ case bzero_msk | has_dot | has_e | has_minus:
+ [[fallthrough]];
+ case bzero_msk | has_dot | has_e | has_plus:
+ [[fallthrough]];
+ // 1e1
+ // 1e-1
+ // 1e+1
+ // 1.0
+ // 1.0e1
+ // 1.0e-1
+ // 1.0e+1
+ case bdigit_msk | has_e:
+ [[fallthrough]];
+ case bdigit_msk | has_e | has_minus:
+ [[fallthrough]];
+ case bdigit_msk | has_e | has_plus:
+ [[fallthrough]];
+ case bdigit_msk | has_dot:
+ [[fallthrough]];
+ case bdigit_msk | has_dot | has_e:
+ [[fallthrough]];
+ case bdigit_msk | has_dot | has_e | has_minus:
+ [[fallthrough]];
+ case bdigit_msk | has_dot | has_e | has_plus:
+ [[fallthrough]];
+ // +1e1
+ // +1.0
+ // +1.0e1
+ // +1.0e+1
+ // +1.0e-1
+ // -1.0e+1
+ case begins_sign | has_digits | has_e | has_plus:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_dot | has_plus:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_dot | has_e | has_plus:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_dot | has_e | signs_msk:
+ [[fallthrough]];
+ // -1e1
+ // -1e+1
+ // +1e-1
+ // -1.0
+ // -1.0e1
+ // -1.0e-1
+ case begins_sign | has_digits | has_e | has_minus:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_e | signs_msk:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_dot | has_minus:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_dot | has_e | has_minus:
+ val.reset(new value{parse_float()});
+ break;
+
+ // hexadecimal floats
+ // 0x10p0
+ // 0x10p-0
+ // 0x10p+0
+ case bzero_msk | has_x | has_p:
+ [[fallthrough]];
+ case bzero_msk | has_x | has_p | has_minus:
+ [[fallthrough]];
+ case bzero_msk | has_x | has_p | has_plus:
+ [[fallthrough]];
+ // -0x10p0
+ // -0x10p-0
+ // +0x10p0
+ // +0x10p+0
+ // -0x10p+0
+ // +0x10p-0
+ case begins_sign | has_digits | has_x | has_p | has_minus:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_x | has_p | has_plus:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_x | has_p | signs_msk:
+ [[fallthrough]];
+ // 0x10.1p0
+ // 0x10.1p-0
+ // 0x10.1p+0
+ case bzero_msk | has_x | has_dot | has_p:
+ [[fallthrough]];
+ case bzero_msk | has_x | has_dot | has_p | has_minus:
+ [[fallthrough]];
+ case bzero_msk | has_x | has_dot | has_p | has_plus:
+ [[fallthrough]];
+ // -0x10.1p0
+ // -0x10.1p-0
+ // +0x10.1p0
+ // +0x10.1p+0
+ // -0x10.1p+0
+ // +0x10.1p-0
+ case begins_sign | has_digits | has_x | has_dot | has_p | has_minus:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_x | has_dot | has_p | has_plus:
+ [[fallthrough]];
+ case begins_sign | has_digits | has_x | has_dot | has_p | signs_msk:
+ val.reset(new value{parse_hex_float()});
+ break;
+
+ // times
+ // HH:MM
+ // HH:MM:SS
+ // HH:MM:SS.FFFFFF
+ case bzero_msk | has_colon:
+ [[fallthrough]];
+ case bzero_msk | has_colon | has_dot:
+ [[fallthrough]];
+ case bdigit_msk | has_colon:
+ [[fallthrough]];
+ case bdigit_msk | has_colon | has_dot:
+ val.reset(new value{parse_time()});
+ break;
+
+ // local dates
+ // YYYY-MM-DD
+ case bzero_msk | has_minus:
+ [[fallthrough]];
+ case bdigit_msk | has_minus:
+ val.reset(new value{parse_date()});
+ break;
+
+ // date-times
+ // YYYY-MM-DDTHH:MM
+ // YYYY-MM-DDTHH:MM-HH:MM
+ // YYYY-MM-DDTHH:MM+HH:MM
+ // YYYY-MM-DD HH:MM
+ // YYYY-MM-DD HH:MM-HH:MM
+ // YYYY-MM-DD HH:MM+HH:MM
+ // YYYY-MM-DDTHH:MM:SS
+ // YYYY-MM-DDTHH:MM:SS-HH:MM
+ // YYYY-MM-DDTHH:MM:SS+HH:MM
+ // YYYY-MM-DD HH:MM:SS
+ // YYYY-MM-DD HH:MM:SS-HH:MM
+ // YYYY-MM-DD HH:MM:SS+HH:MM
+ case bzero_msk | has_minus | has_colon | has_t:
+ [[fallthrough]];
+ case bzero_msk | signs_msk | has_colon | has_t:
+ [[fallthrough]];
+ case bdigit_msk | has_minus | has_colon | has_t:
+ [[fallthrough]];
+ case bdigit_msk | signs_msk | has_colon | has_t:
+ [[fallthrough]];
+ // YYYY-MM-DDTHH:MM:SS.FFFFFF
+ // YYYY-MM-DDTHH:MM:SS.FFFFFF-HH:MM
+ // YYYY-MM-DDTHH:MM:SS.FFFFFF+HH:MM
+ // YYYY-MM-DD HH:MM:SS.FFFFFF
+ // YYYY-MM-DD HH:MM:SS.FFFFFF-HH:MM
+ // YYYY-MM-DD HH:MM:SS.FFFFFF+HH:MM
+ case bzero_msk | has_minus | has_colon | has_dot | has_t:
+ [[fallthrough]];
+ case bzero_msk | signs_msk | has_colon | has_dot | has_t:
+ [[fallthrough]];
+ case bdigit_msk | has_minus | has_colon | has_dot | has_t:
+ [[fallthrough]];
+ case bdigit_msk | signs_msk | has_colon | has_dot | has_t:
+ [[fallthrough]];
+ // YYYY-MM-DDTHH:MMZ
+ // YYYY-MM-DD HH:MMZ
+ // YYYY-MM-DDTHH:MM:SSZ
+ // YYYY-MM-DD HH:MM:SSZ
+ // YYYY-MM-DDTHH:MM:SS.FFFFFFZ
+ // YYYY-MM-DD HH:MM:SS.FFFFFFZ
+ case bzero_msk | has_minus | has_colon | has_z | has_t:
+ [[fallthrough]];
+ case bzero_msk | has_minus | has_colon | has_dot | has_z | has_t:
+ [[fallthrough]];
+ case bdigit_msk | has_minus | has_colon | has_z | has_t:
+ [[fallthrough]];
+ case bdigit_msk | has_minus | has_colon | has_dot | has_z | has_t:
+ val.reset(new value{parse_date_time()});
+ break;
+ }
+ } while (false);
+
+ if (!val) {
+ set_error_at(begin_pos, "could not determine value type"sv);
+ return_after_error({});
+ }
+
+ val->source_ = {begin_pos, current_position(1), reader.source_path()};
+ return val;
+ }
+
+ TOML_NEVER_INLINE
+ bool parse_key() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(is_bare_key_character(*cp) || is_string_delimiter(*cp));
+ push_parse_scope("key"sv);
+
+ key_buffer.clear();
+ recording_whitespace = false;
+
+ while (!is_error()) {
+ std::string_view key_segment;
+ const auto key_begin = current_position();
+
+ // bare_key_segment
+ if (is_bare_key_character(*cp)) key_segment = parse_bare_key_segment();
+
+ // "quoted key segment"
+ else if (is_string_delimiter(*cp)) {
+ const auto begin_pos = cp->position;
+
+ recording_whitespace = true;
+ parsed_string str = parse_string();
+ recording_whitespace = false;
+ return_if_error({});
+
+ if (str.was_multi_line) {
+ set_error_at(begin_pos, "multi-line strings are prohibited in "sv,
+ key_buffer.empty() ? ""sv : "dotted "sv, "keys"sv);
+ return_after_error({});
+ } else
+ key_segment = str.value;
+ }
+
+ // ???
+ else
+ set_error_and_return_default(
+ "expected bare key starting character or string delimiter, saw '"sv, to_sv(*cp),
+ "'"sv);
+
+ const auto key_end = current_position();
+
+ // whitespace following the key segment
+ consume_leading_whitespace();
+
+ // store segment
+ key_buffer.push_back(key_segment, key_begin, key_end);
+
+ // eof or no more key to come
+ if (is_eof() || *cp != U'.') break;
+
+ // was a dotted key - go around again
+ advance_and_return_if_error_or_eof({});
+ consume_leading_whitespace();
+ set_error_and_return_if_eof({});
+ }
+ return_if_error({});
+
+ return true;
+ }
+
+ TOML_NODISCARD
+ key make_key(size_t segment_index) const {
+ TOML_ASSERT(key_buffer.size() > segment_index);
+
+ return key{key_buffer[segment_index],
+ source_region{key_buffer.starts[segment_index], key_buffer.ends[segment_index],
+ root.source().path}};
+ }
+
+ TOML_NODISCARD
+ TOML_NEVER_INLINE
+ table* parse_table_header() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(*cp == U'[');
+ push_parse_scope("table header"sv);
+
+ const source_position header_begin_pos = cp->position;
+ source_position header_end_pos;
+ bool is_arr = false;
+
+ // parse header
+ {
+ // skip first '['
+ advance_and_return_if_error_or_eof({});
+
+ // skip past any whitespace that followed the '['
+ const bool had_leading_whitespace = consume_leading_whitespace();
+ set_error_and_return_if_eof({});
+
+ // skip second '[' (if present)
+ if (*cp == U'[') {
+ if (had_leading_whitespace)
+ set_error_and_return_default(
+ "[[array-of-table]] brackets must be contiguous (i.e. [ [ this ] ] is prohibited)"sv);
+
+ is_arr = true;
+ advance_and_return_if_error_or_eof({});
+
+ // skip past any whitespace that followed the '['
+ consume_leading_whitespace();
+ set_error_and_return_if_eof({});
+ }
+
+ // check for a premature closing ']'
+ if (*cp == U']')
+ set_error_and_return_default("tables with blank bare keys are explicitly prohibited"sv);
+
+ // get the actual key
+ start_recording();
+ parse_key();
+ stop_recording(1u);
+ return_if_error({});
+
+ // skip past any whitespace that followed the key
+ consume_leading_whitespace();
+ return_if_error({});
+ set_error_and_return_if_eof({});
+
+ // consume the closing ']'
+ if (*cp != U']') set_error_and_return_default("expected ']', saw '"sv, to_sv(*cp), "'"sv);
+ if (is_arr) {
+ advance_and_return_if_error_or_eof({});
+ if (*cp != U']') set_error_and_return_default("expected ']', saw '"sv, to_sv(*cp), "'"sv);
+ }
+ advance_and_return_if_error({});
+ header_end_pos = current_position(1);
+
+ // handle the rest of the line after the header
+ consume_leading_whitespace();
+ if (!is_eof() && !consume_comment() && !consume_line_break())
+ set_error_and_return_default("expected a comment or whitespace, saw '"sv, to_sv(cp),
+ "'"sv);
+ }
+ TOML_ASSERT(!key_buffer.empty());
+
+ // check if each parent is a table/table array, or can be created implicitly as a table.
+ table* parent = &root;
+ for (size_t i = 0, e = key_buffer.size() - 1u; i < e; i++) {
+ const std::string_view segment = key_buffer[i];
+ auto pit = parent->lower_bound(segment);
+
+ // parent already existed
+ if (pit != parent->end() && pit->first == segment) {
+ node& p = pit->second;
+
+ if (auto tbl = p.as_table()) {
+ // adding to closed inline tables is illegal
+ if (tbl->is_inline() &&
+ !impl::find(open_inline_tables.begin(), open_inline_tables.end(), tbl))
+ set_error_and_return_default("cannot insert '"sv, to_sv(recording_buffer),
+ "' into existing inline table"sv);
+
+ parent = tbl;
+ } else if (auto arr = p.as_array();
+ arr && impl::find(table_arrays.begin(), table_arrays.end(), arr)) {
+ // table arrays are a special case;
+ // the spec dictates we select the most recently declared element in the array.
+ TOML_ASSERT(!arr->empty());
+ TOML_ASSERT(arr->back().is_table());
+ parent = &arr->back().ref_cast<table>();
+ } else {
+ if (!is_arr && p.type() == node_type::table)
+ set_error_and_return_default("cannot redefine existing table '"sv,
+ to_sv(recording_buffer), "'"sv);
+ else
+ set_error_and_return_default("cannot redefine existing "sv, to_sv(p.type()), " '"sv,
+ to_sv(recording_buffer), "' as "sv,
+ is_arr ? "array-of-tables"sv : "table"sv);
+ }
+ }
+
+ // need to create a new implicit table
+ else {
+ pit = parent->emplace_hint<table>(pit, make_key(i));
+ table& p = pit->second.ref_cast<table>();
+ p.source_ = {header_begin_pos, header_end_pos, reader.source_path()};
+
+ implicit_tables.push_back(&p);
+ parent = &p;
+ }
+ }
+
+ const auto last_segment = key_buffer.back();
+ auto it = parent->lower_bound(last_segment);
+
+ // if there was already a matching node some sanity checking is necessary;
+ // this is ok if we're making an array and the existing element is already an array (new
+ // element) or if we're making a table and the existing element is an implicitly-created table
+ // (promote it), otherwise this is a redefinition error.
+ if (it != parent->end() && it->first == last_segment) {
+ node& matching_node = it->second;
+ if (auto arr = matching_node.as_array();
+ is_arr && arr && impl::find(table_arrays.begin(), table_arrays.end(), arr)) {
+ table& tbl = arr->emplace_back<table>();
+ tbl.source_ = {header_begin_pos, header_end_pos, reader.source_path()};
+ return &tbl;
+ }
+
+ else if (auto tbl = matching_node.as_table(); !is_arr && tbl && !implicit_tables.empty()) {
+ if (auto found = impl::find(implicit_tables.begin(), implicit_tables.end(), tbl); found) {
+ bool ok = true;
+ if (!tbl->empty()) {
+ for (auto& [_, child] : *tbl) {
+ if (!child.is_table() && !child.is_array_of_tables()) {
+ ok = false;
+ break;
+ }
+ }
+ }
+
+ if (ok) {
+ implicit_tables.erase(implicit_tables.cbegin() + (found - implicit_tables.data()));
+ tbl->source_.begin = header_begin_pos;
+ tbl->source_.end = header_end_pos;
+ return tbl;
+ }
+ }
+ }
+
+ // if we get here it's a redefinition error.
+ if (!is_arr && matching_node.type() == node_type::table) {
+ set_error_at(header_begin_pos, "cannot redefine existing table '"sv,
+ to_sv(recording_buffer), "'"sv);
+ return_after_error({});
+ } else {
+ set_error_at(header_begin_pos, "cannot redefine existing "sv, to_sv(matching_node.type()),
+ " '"sv, to_sv(recording_buffer), "' as "sv,
+ is_arr ? "array-of-tables"sv : "table"sv);
+ return_after_error({});
+ }
+ }
+
+ // there was no matching node, sweet - we can freely instantiate a new table/table array.
+ else {
+ auto last_key = make_key(key_buffer.size() - 1u);
+
+ // if it's an array we need to make the array and it's first table element,
+ // set the starting regions, and return the table element
+ if (is_arr) {
+ it = parent->emplace_hint<array>(it, std::move(last_key));
+ array& tbl_arr = it->second.ref_cast<array>();
+ table_arrays.push_back(&tbl_arr);
+ tbl_arr.source_ = {header_begin_pos, header_end_pos, reader.source_path()};
+
+ table& tbl = tbl_arr.emplace_back<table>();
+ tbl.source_ = {header_begin_pos, header_end_pos, reader.source_path()};
+ return &tbl;
+ }
+
+ // otherwise we're just making a table
+ else {
+ it = parent->emplace_hint<table>(it, std::move(last_key));
+ table& tbl = it->second.ref_cast<table>();
+ tbl.source_ = {header_begin_pos, header_end_pos, reader.source_path()};
+ return &tbl;
+ }
+ }
+ }
+
+ TOML_NEVER_INLINE
+ bool parse_key_value_pair_and_insert(table* tbl) {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(is_string_delimiter(*cp) || is_bare_key_character(*cp));
+ push_parse_scope("key-value pair"sv);
+
+ // read the key into the key buffer
+ start_recording();
+ parse_key();
+ stop_recording(1u);
+ return_if_error({});
+ TOML_ASSERT(key_buffer.size() >= 1u);
+
+ // skip past any whitespace that followed the key
+ consume_leading_whitespace();
+ set_error_and_return_if_eof({});
+
+ // '='
+ if (*cp != U'=') set_error_and_return_default("expected '=', saw '"sv, to_sv(*cp), "'"sv);
+ advance_and_return_if_error_or_eof({});
+
+ // skip past any whitespace that followed the '='
+ consume_leading_whitespace();
+ return_if_error({});
+ set_error_and_return_if_eof({});
+
+ // check that the next character could actually be a value
+ if (is_value_terminator(*cp))
+ set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv);
+
+ // if it's a dotted kvp we need to spawn the parent sub-tables if necessary,
+ // and set the target table to the second-to-last one in the chain
+ if (key_buffer.size() > 1u) {
+ for (size_t i = 0; i < key_buffer.size() - 1u; i++) {
+ const std::string_view segment = key_buffer[i];
+ auto pit = tbl->lower_bound(segment);
+
+ // parent already existed
+ if (pit != tbl->end() && pit->first == segment) {
+ table* p = pit->second.as_table();
+
+ // redefinition
+ if TOML_UNLIKELY (!p ||
+ !(impl::find(dotted_key_tables.begin(), dotted_key_tables.end(), p) ||
+ impl::find(implicit_tables.begin(), implicit_tables.end(), p))) {
+ set_error_at(key_buffer.starts[i], "cannot redefine existing "sv,
+ to_sv(pit->second.type()), " as dotted key-value pair"sv);
+ return_after_error({});
+ }
+
+ tbl = p;
+ }
+
+ // need to create a new implicit table
+ else {
+ pit = tbl->emplace_hint<table>(pit, make_key(i));
+ table& p = pit->second.ref_cast<table>();
+ p.source_ = pit->first.source();
+
+ dotted_key_tables.push_back(&p);
+ tbl = &p;
+ }
+ }
+ }
+
+ // ensure this isn't a redefinition
+ const std::string_view last_segment = key_buffer.back();
+ auto it = tbl->lower_bound(last_segment);
+ if (it != tbl->end() && it->first == last_segment) {
+ set_error("cannot redefine existing "sv, to_sv(it->second.type()), " '"sv,
+ to_sv(recording_buffer), "'"sv);
+ return_after_error({});
+ }
+
+ // create the key first since the key buffer will likely get overwritten during value parsing
+ // (inline tables)
+ auto last_key = make_key(key_buffer.size() - 1u);
+
+ // now we can actually parse the value
+ node_ptr val = parse_value();
+ return_if_error({});
+
+ tbl->emplace_hint<node_ptr>(it, std::move(last_key), std::move(val));
+ return true;
+ }
+
+ void parse_document() {
+ assert_not_error();
+ assert_not_eof();
+ push_parse_scope("root table"sv);
+
+ table* current_table = &root;
+
+ do {
+ return_if_error();
+
+ // leading whitespace, line endings, comments
+ if (consume_leading_whitespace() || consume_line_break() || consume_comment()) continue;
+ return_if_error();
+
+ // [tables]
+ // [[table array]]
+ if (*cp == U'[') current_table = parse_table_header();
+
+ // bare_keys
+ // dotted.keys
+ // "quoted keys"
+ else if (is_bare_key_character(*cp) || is_string_delimiter(*cp)) {
+ push_parse_scope("key-value pair"sv);
+
+ parse_key_value_pair_and_insert(current_table);
+
+ // handle the rest of the line after the kvp
+ // (this is not done in parse_key_value_pair() because that is also used for inline
+ // tables)
+ consume_leading_whitespace();
+ return_if_error();
+ if (!is_eof() && !consume_comment() && !consume_line_break())
+ set_error("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv);
+ }
+
+ else // ??
+ set_error("expected keys, tables, whitespace or comments, saw '"sv, to_sv(cp), "'"sv);
+ } while (!is_eof());
+
+ auto eof_pos = current_position(1);
+ root.source_.end = eof_pos;
+ if (current_table && current_table != &root &&
+ current_table->source_.end <= current_table->source_.begin)
+ current_table->source_.end = eof_pos;
+ }
+
+ static void update_region_ends(node& nde) noexcept {
+ const auto type = nde.type();
+ if (type > node_type::array) return;
+
+ if (type == node_type::table) {
+ auto& tbl = nde.ref_cast<table>();
+ if (tbl.is_inline()) // inline tables (and all their inline descendants) are already
+ // correctly terminated
+ return;
+
+ auto end = nde.source_.end;
+ for (auto&& [k, v] : tbl) {
+ TOML_UNUSED(k);
+ update_region_ends(v);
+ if (end < v.source_.end) end = v.source_.end;
+ }
+ } else // arrays
+ {
+ auto& arr = nde.ref_cast<array>();
+ auto end = nde.source_.end;
+ for (auto&& v : arr) {
+ update_region_ends(v);
+ if (end < v.source_.end) end = v.source_.end;
+ }
+ nde.source_.end = end;
+ }
+ }
+
+ public:
+ parser(utf8_reader_interface&& reader_) //
+ : reader{reader_} {
+ root.source_ = {prev_pos, prev_pos, reader.source_path()};
+
+ if (!reader.peek_eof()) {
+ cp = reader.read_next();
#if !TOML_EXCEPTIONS
- if (reader.error())
- {
- err = std::move(reader.error());
- return;
- }
+ if (reader.error()) {
+ err = std::move(reader.error());
+ return;
+ }
#endif
- if (cp)
- parse_document();
- }
+ if (cp) parse_document();
+ }
- update_region_ends(root);
- }
+ update_region_ends(root);
+ }
- TOML_NODISCARD
- operator parse_result() && noexcept
- {
+ TOML_NODISCARD
+ operator parse_result() && noexcept {
#if TOML_EXCEPTIONS
- return { std::move(root) };
+ return {std::move(root)};
#else
- if (err)
- return parse_result{ *std::move(err) };
- else
- return parse_result{ std::move(root) };
+ if (err)
+ return parse_result{*std::move(err)};
+ else
+ return parse_result{std::move(root)};
#endif
- }
- };
-
- TOML_EXTERNAL_LINKAGE
- node_ptr parser::parse_array()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(*cp == U'[');
- push_parse_scope("array"sv);
-
- // skip opening '['
- advance_and_return_if_error_or_eof({});
-
- node_ptr arr_ptr{ new array{} };
- array& arr = arr_ptr->ref_cast<array>();
- enum class TOML_CLOSED_ENUM parse_type : int
- {
- none,
- comma,
- val
- };
- parse_type prev = parse_type::none;
-
- while (!is_error())
- {
- while (consume_leading_whitespace() || consume_line_break() || consume_comment())
- continue;
- set_error_and_return_if_eof({});
-
- // commas - only legal after a value
- if (*cp == U',')
- {
- if (prev == parse_type::val)
- {
- prev = parse_type::comma;
- advance_and_return_if_error_or_eof({});
- continue;
- }
- set_error_and_return_default("expected value or closing ']', saw comma"sv);
- }
-
- // closing ']'
- else if (*cp == U']')
- {
- advance_and_return_if_error({});
- break;
- }
-
- // must be a value
- else
- {
- if (prev == parse_type::val)
- {
- set_error_and_return_default("expected comma or closing ']', saw '"sv, to_sv(*cp), "'"sv);
- continue;
- }
- prev = parse_type::val;
-
- auto val = parse_value();
- return_if_error({});
-
- if (!arr.capacity())
- arr.reserve(4u);
- arr.emplace_back<node_ptr>(std::move(val));
- }
- }
-
- return_if_error({});
- return arr_ptr;
- }
-
- TOML_EXTERNAL_LINKAGE
- node_ptr parser::parse_inline_table()
- {
- return_if_error({});
- assert_not_eof();
- TOML_ASSERT_ASSUME(*cp == U'{');
- push_parse_scope("inline table"sv);
-
- // skip opening '{'
- advance_and_return_if_error_or_eof({});
-
- node_ptr tbl_ptr{ new table{} };
- table& tbl = tbl_ptr->ref_cast<table>();
- tbl.is_inline(true);
- table_vector_scope table_scope{ open_inline_tables, tbl };
-
- enum class TOML_CLOSED_ENUM parse_type : int
- {
- none,
- comma,
- kvp
- };
- parse_type prev = parse_type::none;
- while (!is_error())
- {
- if constexpr (TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
- {
- while (consume_leading_whitespace() || consume_line_break() || consume_comment())
- continue;
- }
- else
- {
- while (consume_leading_whitespace())
- continue;
- }
- return_if_error({});
- set_error_and_return_if_eof({});
-
- // commas - only legal after a key-value pair
- if (*cp == U',')
- {
- if (prev == parse_type::kvp)
- {
- prev = parse_type::comma;
- advance_and_return_if_error_or_eof({});
- }
- else
- set_error_and_return_default("expected key-value pair or closing '}', saw comma"sv);
- }
-
- // closing '}'
- else if (*cp == U'}')
- {
- if constexpr (!TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
- {
- if (prev == parse_type::comma)
- {
- set_error_and_return_default("expected key-value pair, saw closing '}' (dangling comma)"sv);
- continue;
- }
- }
- advance_and_return_if_error({});
- break;
- }
-
- // key-value pair
- else if (is_string_delimiter(*cp) || is_bare_key_character(*cp))
- {
- if (prev == parse_type::kvp)
- set_error_and_return_default("expected comma or closing '}', saw '"sv, to_sv(*cp), "'"sv);
- else
- {
- prev = parse_type::kvp;
- parse_key_value_pair_and_insert(&tbl);
- }
- }
-
- /// ???
- else
- set_error_and_return_default("expected key or closing '}', saw '"sv, to_sv(*cp), "'"sv);
- }
-
- return_if_error({});
- return tbl_ptr;
- }
-
- TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
+ }
+ };
+
+ TOML_EXTERNAL_LINKAGE
+ node_ptr parser::parse_array() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(*cp == U'[');
+ push_parse_scope("array"sv);
+
+ // skip opening '['
+ advance_and_return_if_error_or_eof({});
+
+ node_ptr arr_ptr{new array{}};
+ array& arr = arr_ptr->ref_cast<array>();
+ enum class TOML_CLOSED_ENUM parse_type : int { none, comma, val };
+ parse_type prev = parse_type::none;
+
+ while (!is_error()) {
+ while (consume_leading_whitespace() || consume_line_break() || consume_comment()) continue;
+ set_error_and_return_if_eof({});
+
+ // commas - only legal after a value
+ if (*cp == U',') {
+ if (prev == parse_type::val) {
+ prev = parse_type::comma;
+ advance_and_return_if_error_or_eof({});
+ continue;
+ }
+ set_error_and_return_default("expected value or closing ']', saw comma"sv);
+ }
+
+ // closing ']'
+ else if (*cp == U']') {
+ advance_and_return_if_error({});
+ break;
+ }
+
+ // must be a value
+ else {
+ if (prev == parse_type::val) {
+ set_error_and_return_default("expected comma or closing ']', saw '"sv, to_sv(*cp), "'"sv);
+ continue;
+ }
+ prev = parse_type::val;
+
+ auto val = parse_value();
+ return_if_error({});
+
+ if (!arr.capacity()) arr.reserve(4u);
+ arr.emplace_back<node_ptr>(std::move(val));
+ }
+ }
+
+ return_if_error({});
+ return arr_ptr;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node_ptr parser::parse_inline_table() {
+ return_if_error({});
+ assert_not_eof();
+ TOML_ASSERT_ASSUME(*cp == U'{');
+ push_parse_scope("inline table"sv);
+
+ // skip opening '{'
+ advance_and_return_if_error_or_eof({});
+
+ node_ptr tbl_ptr{new table{}};
+ table& tbl = tbl_ptr->ref_cast<table>();
+ tbl.is_inline(true);
+ table_vector_scope table_scope{open_inline_tables, tbl};
+
+ enum class TOML_CLOSED_ENUM parse_type : int { none, comma, kvp };
+ parse_type prev = parse_type::none;
+ while (!is_error()) {
+ if constexpr (TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline
+ // tables)
+ {
+ while (consume_leading_whitespace() || consume_line_break() || consume_comment()) continue;
+ } else {
+ while (consume_leading_whitespace()) continue;
+ }
+ return_if_error({});
+ set_error_and_return_if_eof({});
+
+ // commas - only legal after a key-value pair
+ if (*cp == U',') {
+ if (prev == parse_type::kvp) {
+ prev = parse_type::comma;
+ advance_and_return_if_error_or_eof({});
+ } else
+ set_error_and_return_default("expected key-value pair or closing '}', saw comma"sv);
+ }
+
+ // closing '}'
+ else if (*cp == U'}') {
+ if constexpr (!TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline
+ // tables)
+ {
+ if (prev == parse_type::comma) {
+ set_error_and_return_default(
+ "expected key-value pair, saw closing '}' (dangling comma)"sv);
+ continue;
+ }
+ }
+ advance_and_return_if_error({});
+ break;
+ }
+
+ // key-value pair
+ else if (is_string_delimiter(*cp) || is_bare_key_character(*cp)) {
+ if (prev == parse_type::kvp)
+ set_error_and_return_default("expected comma or closing '}', saw '"sv, to_sv(*cp), "'"sv);
+ else {
+ prev = parse_type::kvp;
+ parse_key_value_pair_and_insert(&tbl);
+ }
+ }
+
+ /// ???
+ else
+ set_error_and_return_default("expected key or closing '}', saw '"sv, to_sv(*cp), "'"sv);
+ }
+
+ return_if_error({});
+ return tbl_ptr;
+ }
+
+ TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
}
TOML_IMPL_NAMESPACE_END;
@@ -3747,171 +3354,160 @@ TOML_IMPL_NAMESPACE_END;
#undef utf8_reader_error_check
#undef utf8_reader_return_after_error
-//#---------------------------------------------------------------------------------------------------------------------
-//# PARSER PUBLIC IMPLEMENTATION
-//#---------------------------------------------------------------------------------------------------------------------
-
-TOML_ANON_NAMESPACE_START
-{
- TOML_NODISCARD
- TOML_INTERNAL_LINKAGE
- parse_result do_parse(utf8_reader_interface && reader)
- {
- return impl::parser{ std::move(reader) };
- }
-
- TOML_NODISCARD
- TOML_INTERNAL_LINKAGE
- parse_result do_parse_file(std::string_view file_path)
- {
+// #---------------------------------------------------------------------------------------------------------------------
+// # PARSER PUBLIC IMPLEMENTATION
+// #---------------------------------------------------------------------------------------------------------------------
+
+TOML_ANON_NAMESPACE_START {
+ TOML_NODISCARD
+ TOML_INTERNAL_LINKAGE
+ parse_result do_parse(utf8_reader_interface && reader) {
+ return impl::parser{std::move(reader)};
+ }
+
+ TOML_NODISCARD
+ TOML_INTERNAL_LINKAGE
+ parse_result do_parse_file(std::string_view file_path) {
#if TOML_EXCEPTIONS
-#define TOML_PARSE_FILE_ERROR(msg, path) \
- throw parse_error{ msg, source_position{}, std::make_shared<const std::string>(std::move(path)) }
+#define TOML_PARSE_FILE_ERROR(msg, path) \
+ throw parse_error { \
+ msg, source_position{}, std::make_shared<const std::string>(std::move(path)) \
+ }
#else
-#define TOML_PARSE_FILE_ERROR(msg, path) \
- return parse_result \
- { \
- parse_error \
- { \
- msg, source_position{}, std::make_shared<const std::string>(std::move(path)) \
- } \
- }
+#define TOML_PARSE_FILE_ERROR(msg, path) \
+ return parse_result { \
+ parse_error { \
+ msg, source_position{}, std::make_shared<const std::string>(std::move(path)) \
+ } \
+ }
#endif
- std::string file_path_str(file_path);
+ std::string file_path_str(file_path);
- // open file with a custom-sized stack buffer
- std::ifstream file;
- TOML_OVERALIGNED char file_buffer[sizeof(void*) * 1024u];
- file.rdbuf()->pubsetbuf(file_buffer, sizeof(file_buffer));
+ // open file with a custom-sized stack buffer
+ std::ifstream file;
+ TOML_OVERALIGNED char file_buffer[sizeof(void*) * 1024u];
+ file.rdbuf()->pubsetbuf(file_buffer, sizeof(file_buffer));
#if TOML_WINDOWS
- file.open(impl::widen(file_path_str).c_str(), std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
+ file.open(impl::widen(file_path_str).c_str(),
+ std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
#else
- file.open(file_path_str, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
+ file.open(file_path_str, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
#endif
- if (!file.is_open())
- TOML_PARSE_FILE_ERROR("File could not be opened for reading", file_path_str);
-
- // get size
- const auto file_size = file.tellg();
- if (file_size == -1)
- TOML_PARSE_FILE_ERROR("Could not determine file size", file_path_str);
- file.seekg(0, std::ifstream::beg);
-
- // read the whole file into memory first if the file isn't too large
- constexpr auto large_file_threshold = 1024 * 1024 * 2; // 2 MB
- if (file_size <= large_file_threshold)
- {
- std::vector<char> file_data;
- file_data.resize(static_cast<size_t>(file_size));
- file.read(file_data.data(), static_cast<std::streamsize>(file_size));
- return parse(std::string_view{ file_data.data(), file_data.size() }, std::move(file_path_str));
- }
-
- // otherwise parse it using the streams
- else
- return parse(file, std::move(file_path_str));
+ if (!file.is_open())
+ TOML_PARSE_FILE_ERROR("File could not be opened for reading", file_path_str);
+
+ // get size
+ const auto file_size = file.tellg();
+ if (file_size == -1) TOML_PARSE_FILE_ERROR("Could not determine file size", file_path_str);
+ file.seekg(0, std::ifstream::beg);
+
+ // read the whole file into memory first if the file isn't too large
+ constexpr auto large_file_threshold = 1024 * 1024 * 2; // 2 MB
+ if (file_size <= large_file_threshold) {
+ std::vector<char> file_data;
+ file_data.resize(static_cast<size_t>(file_size));
+ file.read(file_data.data(), static_cast<std::streamsize>(file_size));
+ return parse(std::string_view{file_data.data(), file_data.size()}, std::move(file_path_str));
+ }
+
+ // otherwise parse it using the streams
+ else
+ return parse(file, std::move(file_path_str));
#undef TOML_PARSE_FILE_ERROR
- }
+ }
}
TOML_ANON_NAMESPACE_END;
-TOML_NAMESPACE_START
-{
- TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
-
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path)
- {
- return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, source_path });
- }
-
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse(std::string_view doc, std::string && source_path)
- {
- return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, std::move(source_path) });
- }
-
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse(std::istream & doc, std::string_view source_path)
- {
- return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, source_path });
- }
-
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse(std::istream & doc, std::string && source_path)
- {
- return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, std::move(source_path) });
- }
-
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse_file(std::string_view file_path)
- {
- return TOML_ANON_NAMESPACE::do_parse_file(file_path);
- }
+TOML_NAMESPACE_START {
+ TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
+
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path) {
+ return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse(std::string_view doc, std::string && source_path) {
+ return TOML_ANON_NAMESPACE::do_parse(
+ TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse(std::istream & doc, std::string_view source_path) {
+ return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse(std::istream & doc, std::string && source_path) {
+ return TOML_ANON_NAMESPACE::do_parse(
+ TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse_file(std::string_view file_path) {
+ return TOML_ANON_NAMESPACE::do_parse_file(file_path);
+ }
#if TOML_HAS_CHAR8
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string_view source_path)
- {
- return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, source_path });
- }
-
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string && source_path)
- {
- return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, std::move(source_path) });
- }
-
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse_file(std::u8string_view file_path)
- {
- std::string file_path_str;
- file_path_str.resize(file_path.length());
- memcpy(file_path_str.data(), file_path.data(), file_path.length());
- return TOML_ANON_NAMESPACE::do_parse_file(file_path_str);
- }
-
-#endif // TOML_HAS_CHAR8
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string_view source_path) {
+ return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string && source_path) {
+ return TOML_ANON_NAMESPACE::do_parse(
+ TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse_file(std::u8string_view file_path) {
+ std::string file_path_str;
+ file_path_str.resize(file_path.length());
+ memcpy(file_path_str.data(), file_path.data(), file_path.length());
+ return TOML_ANON_NAMESPACE::do_parse_file(file_path_str);
+ }
+
+#endif // TOML_HAS_CHAR8
#if TOML_ENABLE_WINDOWS_COMPAT
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse(std::string_view doc, std::wstring_view source_path)
- {
- return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, impl::narrow(source_path) });
- }
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse(std::string_view doc, std::wstring_view source_path) {
+ return TOML_ANON_NAMESPACE::do_parse(
+ TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
+ }
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse(std::istream & doc, std::wstring_view source_path)
- {
- return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, impl::narrow(source_path) });
- }
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse(std::istream & doc, std::wstring_view source_path) {
+ return TOML_ANON_NAMESPACE::do_parse(
+ TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
+ }
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse_file(std::wstring_view file_path)
- {
- return TOML_ANON_NAMESPACE::do_parse_file(impl::narrow(file_path));
- }
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse_file(std::wstring_view file_path) {
+ return TOML_ANON_NAMESPACE::do_parse_file(impl::narrow(file_path));
+ }
-#endif // TOML_ENABLE_WINDOWS_COMPAT
+#endif // TOML_ENABLE_WINDOWS_COMPAT
#if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
- TOML_EXTERNAL_LINKAGE
- parse_result TOML_CALLCONV parse(std::u8string_view doc, std::wstring_view source_path)
- {
- return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, impl::narrow(source_path) });
- }
+ TOML_EXTERNAL_LINKAGE
+ parse_result TOML_CALLCONV parse(std::u8string_view doc, std::wstring_view source_path) {
+ return TOML_ANON_NAMESPACE::do_parse(
+ TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
+ }
-#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
+#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
- TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
+ TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
}
TOML_NAMESPACE_END;
#undef TOML_OVERALIGNED
#include "header_end.hpp"
-#endif // TOML_ENABLE_PARSER
+#endif // TOML_ENABLE_PARSER
diff --git a/vendor/toml++/impl/path.inl b/vendor/toml++/impl/path.inl
index 999d651..c33632f 100644
--- a/vendor/toml++/impl/path.inl
+++ b/vendor/toml++/impl/path.inl
@@ -1,18 +1,18 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
-//# {{
+// # {{
#include "preprocessor.hpp"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
-#include "path.hpp"
#include "at_path.hpp"
+#include "path.hpp"
#include "print_to_stream.hpp"
TOML_DISABLE_WARNINGS;
#if TOML_INT_CHARCONV
@@ -22,501 +22,427 @@ TOML_DISABLE_WARNINGS;
TOML_ENABLE_WARNINGS;
#include "header_start.hpp"
-//#=====================================================================================================================
-//# toml::path_component
-//#=====================================================================================================================
-
-TOML_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- path_component::path_component() //
- : type_{ path_component_type::key }
- {
- store_key("", value_storage_);
- }
-
- TOML_EXTERNAL_LINKAGE
- path_component::path_component(size_t index) noexcept //
- : type_(path_component_type::array_index)
- {
- store_index(index, value_storage_);
- }
-
- TOML_EXTERNAL_LINKAGE
- path_component::path_component(std::string_view key) //
- : type_(path_component_type::key)
- {
- store_key(key, value_storage_);
- }
+// #=====================================================================================================================
+// # toml::path_component
+// #=====================================================================================================================
+
+TOML_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ path_component::path_component() //
+ : type_{path_component_type::key} {
+ store_key("", value_storage_);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path_component::path_component(size_t index) noexcept //
+ : type_(path_component_type::array_index) {
+ store_index(index, value_storage_);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path_component::path_component(std::string_view key) //
+ : type_(path_component_type::key) {
+ store_key(key, value_storage_);
+ }
#if TOML_ENABLE_WINDOWS_COMPAT
- TOML_EXTERNAL_LINKAGE
- path_component::path_component(std::wstring_view key) //
- : path_component(impl::narrow(key))
- {}
+ TOML_EXTERNAL_LINKAGE
+ path_component::path_component(std::wstring_view key) //
+ : path_component(impl::narrow(key)) {}
#endif
- TOML_EXTERNAL_LINKAGE
- path_component::path_component(const path_component& pc) //
- : type_{ pc.type_ }
- {
- if (type_ == path_component_type::array_index)
- store_index(pc.index(), value_storage_);
- else
- store_key(pc.key(), value_storage_);
- }
-
- TOML_EXTERNAL_LINKAGE
- path_component::path_component(path_component && pc) noexcept //
- : type_{ pc.type_ }
- {
- if (type_ == path_component_type::array_index)
- store_index(pc.index_ref(), value_storage_);
- else
- store_key(std::move(pc.key_ref()), value_storage_);
- }
-
- TOML_EXTERNAL_LINKAGE
- path_component& path_component::operator=(const path_component& rhs)
- {
- if (type_ != rhs.type_)
- {
- destroy();
-
- type_ = rhs.type_;
- if (type_ == path_component_type::array_index)
- store_index(rhs.index(), value_storage_);
- else
- store_key(rhs.key(), value_storage_);
- }
- else
- {
- if (type_ == path_component_type::array_index)
- index_ref() = rhs.index();
- else
- key_ref() = rhs.key();
- }
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- path_component& path_component::operator=(path_component&& rhs) noexcept
- {
- if (type_ != rhs.type_)
- {
- destroy();
-
- type_ = rhs.type_;
- if (type_ == path_component_type::array_index)
- store_index(rhs.index(), value_storage_);
- else
- store_key(std::move(rhs.key_ref()), value_storage_);
- }
- else
- {
- if (type_ == path_component_type::array_index)
- index_ref() = rhs.index();
- else
- key_ref() = std::move(rhs.key_ref());
- }
- return *this;
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- bool TOML_CALLCONV path_component::equal(const path_component& lhs, const path_component& rhs) noexcept
- {
- // Different comparison depending on contents
- if (lhs.type_ != rhs.type_)
- return false;
-
- if (lhs.type_ == path_component_type::array_index)
- return lhs.index() == rhs.index();
- else // path_component_type::key
- return lhs.key() == rhs.key();
- }
-
- TOML_EXTERNAL_LINKAGE
- path_component& path_component::operator=(size_t new_index) noexcept
- {
- // If currently a key, string will need to be destroyed regardless
- destroy();
-
- type_ = path_component_type::array_index;
- store_index(new_index, value_storage_);
-
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- path_component& path_component::operator=(std::string_view new_key)
- {
- if (type_ == path_component_type::key)
- key_ref() = new_key;
- else
- {
- type_ = path_component_type::key;
- store_key(new_key, value_storage_);
- }
-
- return *this;
- }
+ TOML_EXTERNAL_LINKAGE
+ path_component::path_component(const path_component& pc) //
+ : type_{pc.type_} {
+ if (type_ == path_component_type::array_index)
+ store_index(pc.index(), value_storage_);
+ else
+ store_key(pc.key(), value_storage_);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path_component::path_component(path_component && pc) noexcept //
+ : type_{pc.type_} {
+ if (type_ == path_component_type::array_index)
+ store_index(pc.index_ref(), value_storage_);
+ else
+ store_key(std::move(pc.key_ref()), value_storage_);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path_component& path_component::operator=(const path_component& rhs) {
+ if (type_ != rhs.type_) {
+ destroy();
+
+ type_ = rhs.type_;
+ if (type_ == path_component_type::array_index)
+ store_index(rhs.index(), value_storage_);
+ else
+ store_key(rhs.key(), value_storage_);
+ } else {
+ if (type_ == path_component_type::array_index)
+ index_ref() = rhs.index();
+ else
+ key_ref() = rhs.key();
+ }
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path_component& path_component::operator=(path_component&& rhs) noexcept {
+ if (type_ != rhs.type_) {
+ destroy();
+
+ type_ = rhs.type_;
+ if (type_ == path_component_type::array_index)
+ store_index(rhs.index(), value_storage_);
+ else
+ store_key(std::move(rhs.key_ref()), value_storage_);
+ } else {
+ if (type_ == path_component_type::array_index)
+ index_ref() = rhs.index();
+ else
+ key_ref() = std::move(rhs.key_ref());
+ }
+ return *this;
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ bool TOML_CALLCONV path_component::equal(const path_component& lhs,
+ const path_component& rhs) noexcept {
+ // Different comparison depending on contents
+ if (lhs.type_ != rhs.type_) return false;
+
+ if (lhs.type_ == path_component_type::array_index)
+ return lhs.index() == rhs.index();
+ else // path_component_type::key
+ return lhs.key() == rhs.key();
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path_component& path_component::operator=(size_t new_index) noexcept {
+ // If currently a key, string will need to be destroyed regardless
+ destroy();
+
+ type_ = path_component_type::array_index;
+ store_index(new_index, value_storage_);
+
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path_component& path_component::operator=(std::string_view new_key) {
+ if (type_ == path_component_type::key)
+ key_ref() = new_key;
+ else {
+ type_ = path_component_type::key;
+ store_key(new_key, value_storage_);
+ }
+
+ return *this;
+ }
#if TOML_ENABLE_WINDOWS_COMPAT
- TOML_EXTERNAL_LINKAGE
- path_component& path_component::operator=(std::wstring_view new_key)
- {
- if (type_ == path_component_type::key)
- key_ref() = impl::narrow(new_key);
- else
- {
- type_ = path_component_type::key;
- store_key(impl::narrow(new_key), value_storage_);
- }
+ TOML_EXTERNAL_LINKAGE
+ path_component& path_component::operator=(std::wstring_view new_key) {
+ if (type_ == path_component_type::key)
+ key_ref() = impl::narrow(new_key);
+ else {
+ type_ = path_component_type::key;
+ store_key(impl::narrow(new_key), value_storage_);
+ }
- return *this;
- }
+ return *this;
+ }
#endif
}
TOML_NAMESPACE_END;
-//#=====================================================================================================================
-//# toml::path
-//#=====================================================================================================================
-
-TOML_ANON_NAMESPACE_START
-{
- TOML_INTERNAL_LINKAGE
- bool parse_path_into(std::string_view path_str, std::vector<path_component> & components)
- {
- using components_type = std::remove_reference_t<decltype(components)>;
-
- const auto original_size = components.size();
-
- static constexpr auto on_key = [](void* data, std::string_view key) -> bool
- {
- auto& comps = *static_cast<components_type*>(data);
- comps.emplace_back(key);
- return true;
- };
-
- static constexpr auto on_index = [](void* data, size_t index) -> bool
- {
- auto& comps = *static_cast<components_type*>(data);
- comps.emplace_back(index);
- return true;
- };
-
- if (!impl::parse_path(path_str, &components, on_key, on_index))
- {
- components.resize(original_size);
- return false;
- }
-
- return true;
- }
+// #=====================================================================================================================
+// # toml::path
+// #=====================================================================================================================
+
+TOML_ANON_NAMESPACE_START {
+ TOML_INTERNAL_LINKAGE
+ bool parse_path_into(std::string_view path_str, std::vector<path_component> & components) {
+ using components_type = std::remove_reference_t<decltype(components)>;
+
+ const auto original_size = components.size();
+
+ static constexpr auto on_key = [](void* data, std::string_view key) -> bool {
+ auto& comps = *static_cast<components_type*>(data);
+ comps.emplace_back(key);
+ return true;
+ };
+
+ static constexpr auto on_index = [](void* data, size_t index) -> bool {
+ auto& comps = *static_cast<components_type*>(data);
+ comps.emplace_back(index);
+ return true;
+ };
+
+ if (!impl::parse_path(path_str, &components, on_key, on_index)) {
+ components.resize(original_size);
+ return false;
+ }
+
+ return true;
+ }
}
TOML_ANON_NAMESPACE_END;
-TOML_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- void path::print_to(std::ostream & os) const
- {
- bool root = true;
- for (const auto& component : components_)
- {
- if (component.type() == path_component_type::key) // key
- {
- if (!root)
- impl::print_to_stream(os, '.');
- impl::print_to_stream(os, component.key());
- }
- else if (component.type() == path_component_type::array_index) // array
- {
- impl::print_to_stream(os, '[');
- impl::print_to_stream(os, component.index());
- impl::print_to_stream(os, ']');
- }
- root = false;
- }
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- bool TOML_CALLCONV path::equal(const path& lhs, const path& rhs) noexcept
- {
- return lhs.components_ == rhs.components_;
- }
-
- //#=== constructors =================================================
-
- TOML_EXTERNAL_LINKAGE
- path::path(std::string_view str) //
- {
- TOML_ANON_NAMESPACE::parse_path_into(str, components_);
- }
+TOML_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ void path::print_to(std::ostream & os) const {
+ bool root = true;
+ for (const auto& component : components_) {
+ if (component.type() == path_component_type::key) // key
+ {
+ if (!root) impl::print_to_stream(os, '.');
+ impl::print_to_stream(os, component.key());
+ } else if (component.type() == path_component_type::array_index) // array
+ {
+ impl::print_to_stream(os, '[');
+ impl::print_to_stream(os, component.index());
+ impl::print_to_stream(os, ']');
+ }
+ root = false;
+ }
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ bool TOML_CALLCONV path::equal(const path& lhs, const path& rhs) noexcept {
+ return lhs.components_ == rhs.components_;
+ }
+
+ // #=== constructors =================================================
+
+ TOML_EXTERNAL_LINKAGE
+ path::path(std::string_view str) //
+ {
+ TOML_ANON_NAMESPACE::parse_path_into(str, components_);
+ }
#if TOML_ENABLE_WINDOWS_COMPAT
- TOML_EXTERNAL_LINKAGE
- path::path(std::wstring_view str) //
- : path(impl::narrow(str))
- {}
+ TOML_EXTERNAL_LINKAGE
+ path::path(std::wstring_view str) //
+ : path(impl::narrow(str)) {}
#endif
- //#=== assignment =================================================
+ // #=== assignment =================================================
- TOML_EXTERNAL_LINKAGE
- path& path::operator=(std::string_view rhs)
- {
- components_.clear();
- TOML_ANON_NAMESPACE::parse_path_into(rhs, components_);
- return *this;
- }
+ TOML_EXTERNAL_LINKAGE
+ path& path::operator=(std::string_view rhs) {
+ components_.clear();
+ TOML_ANON_NAMESPACE::parse_path_into(rhs, components_);
+ return *this;
+ }
#if TOML_ENABLE_WINDOWS_COMPAT
- TOML_EXTERNAL_LINKAGE
- path& path::operator=(std::wstring_view rhs)
- {
- return assign(impl::narrow(rhs));
- }
+ TOML_EXTERNAL_LINKAGE
+ path& path::operator=(std::wstring_view rhs) {
+ return assign(impl::narrow(rhs));
+ }
#endif
- //#=== appending =================================================
-
- TOML_EXTERNAL_LINKAGE
- path& path::operator+=(const path& rhs)
- {
- components_.insert(components_.cend(), rhs.begin(), rhs.end());
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- path& path::operator+=(path&& rhs)
- {
- components_.insert(components_.end(),
- std::make_move_iterator(rhs.components_.begin()),
- std::make_move_iterator(rhs.components_.end()));
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- path& path::operator+=(std::string_view str)
- {
- TOML_ANON_NAMESPACE::parse_path_into(str, components_);
- return *this;
- }
+ // #=== appending =================================================
+
+ TOML_EXTERNAL_LINKAGE
+ path& path::operator+=(const path& rhs) {
+ components_.insert(components_.cend(), rhs.begin(), rhs.end());
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path& path::operator+=(path&& rhs) {
+ components_.insert(components_.end(), std::make_move_iterator(rhs.components_.begin()),
+ std::make_move_iterator(rhs.components_.end()));
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path& path::operator+=(std::string_view str) {
+ TOML_ANON_NAMESPACE::parse_path_into(str, components_);
+ return *this;
+ }
#if TOML_ENABLE_WINDOWS_COMPAT
- TOML_EXTERNAL_LINKAGE
- path& path::operator+=(std::wstring_view str)
- {
- return *this += impl::narrow(str);
- }
+ TOML_EXTERNAL_LINKAGE
+ path& path::operator+=(std::wstring_view str) {
+ return *this += impl::narrow(str);
+ }
#endif
- //#=== prepending =================================================
-
- TOML_EXTERNAL_LINKAGE
- path& path::prepend(const path& source)
- {
- components_.insert(components_.begin(), source.components_.begin(), source.components_.end());
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- path& path::prepend(path && source)
- {
- components_.insert(components_.begin(),
- std::make_move_iterator(source.components_.begin()),
- std::make_move_iterator(source.components_.end()));
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- path& path::prepend(std::string_view source)
- {
- return prepend(path{ source });
- }
+ // #=== prepending =================================================
+
+ TOML_EXTERNAL_LINKAGE
+ path& path::prepend(const path& source) {
+ components_.insert(components_.begin(), source.components_.begin(), source.components_.end());
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path& path::prepend(path && source) {
+ components_.insert(components_.begin(), std::make_move_iterator(source.components_.begin()),
+ std::make_move_iterator(source.components_.end()));
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path& path::prepend(std::string_view source) {
+ return prepend(path{source});
+ }
#if TOML_ENABLE_WINDOWS_COMPAT
- TOML_EXTERNAL_LINKAGE
- path& path::prepend(std::wstring_view source)
- {
- return prepend(impl::narrow(source));
- }
+ TOML_EXTERNAL_LINKAGE
+ path& path::prepend(std::wstring_view source) {
+ return prepend(impl::narrow(source));
+ }
#endif
- //#=== string conversion =================================================
+ // #=== string conversion =================================================
- TOML_EXTERNAL_LINKAGE
- std::string path::str() const
- {
- if (empty())
- return "";
+ TOML_EXTERNAL_LINKAGE
+ std::string path::str() const {
+ if (empty()) return "";
- std::ostringstream ss;
- print_to(ss);
- return std::move(ss).str();
- }
+ std::ostringstream ss;
+ print_to(ss);
+ return std::move(ss).str();
+ }
#if TOML_ENABLE_WINDOWS_COMPAT
- TOML_EXTERNAL_LINKAGE
- std::wstring path::wide_str() const
- {
- return impl::widen(str());
- }
+ TOML_EXTERNAL_LINKAGE
+ std::wstring path::wide_str() const {
+ return impl::widen(str());
+ }
#endif
- //#=== equality and comparison =================================================
-
- TOML_EXTERNAL_LINKAGE
- void path::clear() noexcept
- {
- components_.clear();
- }
-
- TOML_EXTERNAL_LINKAGE
- path& path::truncate(size_t n)
- {
- n = n > components_.size() ? components_.size() : n;
-
- auto it_end = components_.end();
- components_.erase(it_end - static_cast<int>(n), it_end);
-
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- path path::truncated(size_t n) const
- {
- path truncated_path{};
-
- n = n > components_.size() ? components_.size() : n;
-
- // Copy all components except one
- // Need at least two path components to have a parent, since if there is
- // only one path component, the parent is the root/null path ""
- truncated_path.components_.insert(truncated_path.components_.begin(),
- components_.begin(),
- components_.end() - static_cast<int>(n));
-
- return truncated_path;
- }
-
- TOML_EXTERNAL_LINKAGE
- path path::parent() const
- {
- return truncated(1);
- }
-
- TOML_EXTERNAL_LINKAGE
- path path::leaf(size_t n) const
- {
- path leaf_path{};
-
- n = n > components_.size() ? components_.size() : n;
-
- if (n > 0)
- {
- leaf_path.components_.insert(leaf_path.components_.begin(),
- components_.end() - static_cast<int>(n),
- components_.end());
- }
-
- return leaf_path;
- }
-
- TOML_EXTERNAL_LINKAGE
- path path::subpath(std::vector<path_component>::const_iterator start,
- std::vector<path_component>::const_iterator end) const
- {
- if (start >= end)
- return {};
-
- path subpath;
- subpath.components_.insert(subpath.components_.begin(), start, end);
- return subpath;
- }
-
- TOML_EXTERNAL_LINKAGE
- path path::subpath(size_t start, size_t length) const
- {
- return subpath(begin() + static_cast<int>(start), begin() + static_cast<int>(start + length));
- }
+ // #=== equality and comparison =================================================
+
+ TOML_EXTERNAL_LINKAGE
+ void path::clear() noexcept {
+ components_.clear();
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path& path::truncate(size_t n) {
+ n = n > components_.size() ? components_.size() : n;
+
+ auto it_end = components_.end();
+ components_.erase(it_end - static_cast<int>(n), it_end);
+
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path path::truncated(size_t n) const {
+ path truncated_path{};
+
+ n = n > components_.size() ? components_.size() : n;
+
+ // Copy all components except one
+ // Need at least two path components to have a parent, since if there is
+ // only one path component, the parent is the root/null path ""
+ truncated_path.components_.insert(truncated_path.components_.begin(), components_.begin(),
+ components_.end() - static_cast<int>(n));
+
+ return truncated_path;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path path::parent() const {
+ return truncated(1);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path path::leaf(size_t n) const {
+ path leaf_path{};
+
+ n = n > components_.size() ? components_.size() : n;
+
+ if (n > 0) {
+ leaf_path.components_.insert(leaf_path.components_.begin(),
+ components_.end() - static_cast<int>(n), components_.end());
+ }
+
+ return leaf_path;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path path::subpath(std::vector<path_component>::const_iterator start,
+ std::vector<path_component>::const_iterator end) const {
+ if (start >= end) return {};
+
+ path subpath;
+ subpath.components_.insert(subpath.components_.begin(), start, end);
+ return subpath;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ path path::subpath(size_t start, size_t length) const {
+ return subpath(begin() + static_cast<int>(start), begin() + static_cast<int>(start + length));
+ }
}
TOML_NAMESPACE_END;
-//#=====================================================================================================================
-//# at_path() overloads for toml::path
-//#=====================================================================================================================
-
-TOML_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- node_view<node> TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept
- {
- // early-exit sanity-checks
- if (root.is_value())
- return {};
- if (auto tbl = root.as_table(); tbl && tbl->empty())
- return {};
- if (auto arr = root.as_array(); arr && arr->empty())
- return {};
-
- node* current = &root;
-
- for (const auto& component : path)
- {
- auto type = component.type();
- if (type == path_component_type::array_index)
- {
- const auto current_array = current->as<array>();
- if (!current_array)
- return {}; // not an array, using array index doesn't work
-
- current = current_array->get(component.index());
- }
- else if (type == path_component_type::key)
- {
- const auto current_table = current->as<table>();
- if (!current_table)
- return {};
-
- current = current_table->get(component.key());
- }
- else
- {
- // Error: invalid component
- return {};
- }
-
- if (!current)
- return {}; // not found
- }
-
- return node_view{ current };
- }
-
- TOML_EXTERNAL_LINKAGE
- node_view<const node> TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept
- {
- return node_view<const node>{ at_path(const_cast<node&>(root), path).node() };
- }
+// #=====================================================================================================================
+// # at_path() overloads for toml::path
+// #=====================================================================================================================
+
+TOML_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ node_view<node> TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept {
+ // early-exit sanity-checks
+ if (root.is_value()) return {};
+ if (auto tbl = root.as_table(); tbl && tbl->empty()) return {};
+ if (auto arr = root.as_array(); arr && arr->empty()) return {};
+
+ node* current = &root;
+
+ for (const auto& component : path) {
+ auto type = component.type();
+ if (type == path_component_type::array_index) {
+ const auto current_array = current->as<array>();
+ if (!current_array) return {}; // not an array, using array index doesn't work
+
+ current = current_array->get(component.index());
+ } else if (type == path_component_type::key) {
+ const auto current_table = current->as<table>();
+ if (!current_table) return {};
+
+ current = current_table->get(component.key());
+ } else {
+ // Error: invalid component
+ return {};
+ }
+
+ if (!current) return {}; // not found
+ }
+
+ return node_view{current};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node_view<const node> TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept {
+ return node_view<const node>{at_path(const_cast<node&>(root), path).node()};
+ }
}
TOML_NAMESPACE_END;
diff --git a/vendor/toml++/impl/print_to_stream.inl b/vendor/toml++/impl/print_to_stream.inl
index 57dbf76..aaeac16 100644
--- a/vendor/toml++/impl/print_to_stream.inl
+++ b/vendor/toml++/impl/print_to_stream.inl
@@ -1,23 +1,23 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
-//# {{
+// # {{
#include "preprocessor.hpp"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
+#include "array.hpp"
+#include "date_time.hpp"
#include "print_to_stream.hpp"
#include "source_region.hpp"
-#include "date_time.hpp"
+#include "table.hpp"
#include "toml_formatter.hpp"
#include "value.hpp"
-#include "array.hpp"
-#include "table.hpp"
TOML_DISABLE_WARNINGS;
#include <ostream>
#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
@@ -32,456 +32,405 @@ TOML_DISABLE_WARNINGS;
TOML_ENABLE_WARNINGS;
#include "header_start.hpp"
-TOML_ANON_NAMESPACE_START
-{
- template <typename T>
- inline constexpr size_t charconv_buffer_length = 0;
+TOML_ANON_NAMESPACE_START {
+ template <typename T>
+ inline constexpr size_t charconv_buffer_length = 0;
- template <>
- inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
+ template <>
+ inline constexpr size_t charconv_buffer_length<int8_t> = 4; // strlen("-128")
- template <>
- inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")
+ template <>
+ inline constexpr size_t charconv_buffer_length<int16_t> = 6; // strlen("-32768")
- template <>
- inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")
+ template <>
+ inline constexpr size_t charconv_buffer_length<int32_t> = 11; // strlen("-2147483648")
- template <>
- inline constexpr size_t charconv_buffer_length<int64_t> = 20; // strlen("-9223372036854775808")
+ template <>
+ inline constexpr size_t charconv_buffer_length<int64_t> = 20; // strlen("-9223372036854775808")
- template <>
- inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
+ template <>
+ inline constexpr size_t charconv_buffer_length<uint8_t> = 3; // strlen("255")
- template <>
- inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")
+ template <>
+ inline constexpr size_t charconv_buffer_length<uint16_t> = 5; // strlen("65535")
- template <>
- inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")
+ template <>
+ inline constexpr size_t charconv_buffer_length<uint32_t> = 10; // strlen("4294967295")
- template <>
- inline constexpr size_t charconv_buffer_length<uint64_t> = 20; // strlen("18446744073709551615")
+ template <>
+ inline constexpr size_t charconv_buffer_length<uint64_t> = 20; // strlen("18446744073709551615")
- template <>
- inline constexpr size_t charconv_buffer_length<float> = 64;
+ template <>
+ inline constexpr size_t charconv_buffer_length<float> = 64;
- template <>
- inline constexpr size_t charconv_buffer_length<double> = 64;
+ template <>
+ inline constexpr size_t charconv_buffer_length<double> = 64;
- template <typename T>
- TOML_INTERNAL_LINKAGE
- void print_integer_to_stream(std::ostream & stream, T val, value_flags format = {}, size_t min_digits = 0)
- {
- if (!val)
- {
- if (!min_digits)
- min_digits = 1;
+ template <typename T>
+ TOML_INTERNAL_LINKAGE void print_integer_to_stream(
+ std::ostream & stream, T val, value_flags format = {}, size_t min_digits = 0) {
+ if (!val) {
+ if (!min_digits) min_digits = 1;
- for (size_t i = 0; i < min_digits; i++)
- stream.put('0');
+ for (size_t i = 0; i < min_digits; i++) stream.put('0');
- return;
- }
+ return;
+ }
- static constexpr auto value_flags_mask =
- value_flags::format_as_binary | value_flags::format_as_octal | value_flags::format_as_hexadecimal;
- format &= value_flags_mask;
+ static constexpr auto value_flags_mask = value_flags::format_as_binary |
+ value_flags::format_as_octal |
+ value_flags::format_as_hexadecimal;
+ format &= value_flags_mask;
- int base = 10;
- if (format != value_flags::none && val > T{})
- {
- switch (format)
- {
- case value_flags::format_as_binary: base = 2; break;
- case value_flags::format_as_octal: base = 8; break;
- case value_flags::format_as_hexadecimal: base = 16; break;
- default: break;
- }
- }
+ int base = 10;
+ if (format != value_flags::none && val > T{}) {
+ switch (format) {
+ case value_flags::format_as_binary:
+ base = 2;
+ break;
+ case value_flags::format_as_octal:
+ base = 8;
+ break;
+ case value_flags::format_as_hexadecimal:
+ base = 16;
+ break;
+ default:
+ break;
+ }
+ }
#if TOML_INT_CHARCONV
- char buf[(sizeof(T) * CHAR_BIT)];
- const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
- const auto len = static_cast<size_t>(res.ptr - buf);
- for (size_t i = len; i < min_digits; i++)
- stream.put('0');
- if (base == 16)
- {
- for (size_t i = 0; i < len; i++)
- if (buf[i] >= 'a')
- buf[i] -= 32;
- }
- impl::print_to_stream(stream, buf, len);
+ char buf[(sizeof(T) * CHAR_BIT)];
+ const auto res = std::to_chars(buf, buf + sizeof(buf), val, base);
+ const auto len = static_cast<size_t>(res.ptr - buf);
+ for (size_t i = len; i < min_digits; i++) stream.put('0');
+ if (base == 16) {
+ for (size_t i = 0; i < len; i++)
+ if (buf[i] >= 'a') buf[i] -= 32;
+ }
+ impl::print_to_stream(stream, buf, len);
#else
- using unsigned_type = std::conditional_t<(sizeof(T) > sizeof(unsigned)), std::make_unsigned_t<T>, unsigned>;
- using cast_type = std::conditional_t<std::is_signed_v<T>, std::make_signed_t<unsigned_type>, unsigned_type>;
-
- if (base == 2)
- {
- const auto len = sizeof(T) * CHAR_BIT;
- for (size_t i = len; i < min_digits; i++)
- stream.put('0');
-
- bool found_one = false;
- const auto v = static_cast<unsigned_type>(val);
- unsigned_type mask = unsigned_type{ 1 } << (len - 1u);
- for (size_t i = 0; i < len; i++)
- {
- if ((v & mask))
- {
- stream.put('1');
- found_one = true;
- }
- else if (found_one)
- stream.put('0');
- mask >>= 1;
- }
- }
- else
- {
- std::ostringstream ss;
- ss.imbue(std::locale::classic());
- ss << std::uppercase << std::setbase(base);
- if (min_digits)
- ss << std::setfill('0') << std::setw(static_cast<int>(min_digits));
- ss << static_cast<cast_type>(val);
- const auto str = std::move(ss).str();
- impl::print_to_stream(stream, str);
- }
+ using unsigned_type =
+ std::conditional_t<(sizeof(T) > sizeof(unsigned)), std::make_unsigned_t<T>, unsigned>;
+ using cast_type =
+ std::conditional_t<std::is_signed_v<T>, std::make_signed_t<unsigned_type>, unsigned_type>;
+
+ if (base == 2) {
+ const auto len = sizeof(T) * CHAR_BIT;
+ for (size_t i = len; i < min_digits; i++) stream.put('0');
+
+ bool found_one = false;
+ const auto v = static_cast<unsigned_type>(val);
+ unsigned_type mask = unsigned_type{1} << (len - 1u);
+ for (size_t i = 0; i < len; i++) {
+ if ((v & mask)) {
+ stream.put('1');
+ found_one = true;
+ } else if (found_one)
+ stream.put('0');
+ mask >>= 1;
+ }
+ } else {
+ std::ostringstream ss;
+ ss.imbue(std::locale::classic());
+ ss << std::uppercase << std::setbase(base);
+ if (min_digits) ss << std::setfill('0') << std::setw(static_cast<int>(min_digits));
+ ss << static_cast<cast_type>(val);
+ const auto str = std::move(ss).str();
+ impl::print_to_stream(stream, str);
+ }
#endif
- }
-
- template <typename T>
- TOML_INTERNAL_LINKAGE
- void print_floating_point_to_stream(std::ostream & stream,
- T val,
- value_flags format,
- [[maybe_unused]] bool relaxed_precision)
- {
- switch (impl::fpclassify(val))
- {
- case impl::fp_class::neg_inf: impl::print_to_stream(stream, "-inf"sv); break;
-
- case impl::fp_class::pos_inf: impl::print_to_stream(stream, "inf"sv); break;
-
- case impl::fp_class::nan: impl::print_to_stream(stream, "nan"sv); break;
-
- case impl::fp_class::ok:
- {
- static constexpr auto needs_decimal_point = [](auto&& s) noexcept
- {
- for (auto c : s)
- if (c == '.' || c == 'E' || c == 'e')
- return false;
- return true;
- };
+ }
+
+ template <typename T>
+ TOML_INTERNAL_LINKAGE void print_floating_point_to_stream(
+ std::ostream & stream, T val, value_flags format, [[maybe_unused]] bool relaxed_precision) {
+ switch (impl::fpclassify(val)) {
+ case impl::fp_class::neg_inf:
+ impl::print_to_stream(stream, "-inf"sv);
+ break;
+
+ case impl::fp_class::pos_inf:
+ impl::print_to_stream(stream, "inf"sv);
+ break;
+
+ case impl::fp_class::nan:
+ impl::print_to_stream(stream, "nan"sv);
+ break;
+
+ case impl::fp_class::ok: {
+ static constexpr auto needs_decimal_point = [](auto&& s) noexcept {
+ for (auto c : s)
+ if (c == '.' || c == 'E' || c == 'e') return false;
+ return true;
+ };
#if TOML_FLOAT_CHARCONV
- const auto hex = !!(format & value_flags::format_as_hexadecimal);
- char buf[charconv_buffer_length<T>];
- auto res = hex ? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
- : std::to_chars(buf, buf + sizeof(buf), val);
- auto str = std::string_view{ buf, static_cast<size_t>(res.ptr - buf) };
-
- char buf2[charconv_buffer_length<T>];
- if (!hex && relaxed_precision)
- {
- res = std::to_chars(buf2, buf2 + sizeof(buf2), val, std::chars_format::general, 6);
- const auto str2 = std::string_view{ buf2, static_cast<size_t>(res.ptr - buf2) };
- if (str2.length() < str.length())
- str = str2;
- }
-
- impl::print_to_stream(stream, str);
- if (!hex && needs_decimal_point(str))
- toml::impl::print_to_stream(stream, ".0"sv);
+ const auto hex = !!(format & value_flags::format_as_hexadecimal);
+ char buf[charconv_buffer_length<T>];
+ auto res = hex ? std::to_chars(buf, buf + sizeof(buf), val, std::chars_format::hex)
+ : std::to_chars(buf, buf + sizeof(buf), val);
+ auto str = std::string_view{buf, static_cast<size_t>(res.ptr - buf)};
+
+ char buf2[charconv_buffer_length<T>];
+ if (!hex && relaxed_precision) {
+ res = std::to_chars(buf2, buf2 + sizeof(buf2), val, std::chars_format::general, 6);
+ const auto str2 = std::string_view{buf2, static_cast<size_t>(res.ptr - buf2)};
+ if (str2.length() < str.length()) str = str2;
+ }
+
+ impl::print_to_stream(stream, str);
+ if (!hex && needs_decimal_point(str)) toml::impl::print_to_stream(stream, ".0"sv);
#else
- std::ostringstream ss;
- ss.imbue(std::locale::classic());
- if (!relaxed_precision)
- ss.precision(std::numeric_limits<T>::max_digits10);
- if (!!(format & value_flags::format_as_hexadecimal))
- ss << std::hexfloat;
- ss << val;
- const auto str = std::move(ss).str();
- impl::print_to_stream(stream, str);
- if (!(format & value_flags::format_as_hexadecimal) && needs_decimal_point(str))
- impl::print_to_stream(stream, ".0"sv);
+ std::ostringstream ss;
+ ss.imbue(std::locale::classic());
+ if (!relaxed_precision) ss.precision(std::numeric_limits<T>::max_digits10);
+ if (!!(format & value_flags::format_as_hexadecimal)) ss << std::hexfloat;
+ ss << val;
+ const auto str = std::move(ss).str();
+ impl::print_to_stream(stream, str);
+ if (!(format & value_flags::format_as_hexadecimal) && needs_decimal_point(str))
+ impl::print_to_stream(stream, ".0"sv);
#endif
- }
- break;
+ } break;
- default: TOML_UNREACHABLE;
- }
- }
+ default:
+ TOML_UNREACHABLE;
+ }
+ }
}
TOML_ANON_NAMESPACE_END;
-TOML_IMPL_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- TOML_ATTR(nonnull)
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const char* val, size_t len)
- {
- stream.write(val, static_cast<std::streamsize>(len));
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, std::string_view val)
- {
- stream.write(val.data(), static_cast<std::streamsize>(val.length()));
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const std::string& val)
- {
- stream.write(val.data(), static_cast<std::streamsize>(val.length()));
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, char val)
- {
- stream.put(val);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, signed char val, value_flags format, size_t min_digits)
- {
- TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, signed short val, value_flags format, size_t min_digits)
- {
- TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, signed int val, value_flags format, size_t min_digits)
- {
- TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, signed long val, value_flags format, size_t min_digits)
- {
- TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream,
- signed long long val,
- value_flags format,
- size_t min_digits)
- {
- TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned char val, value_flags format, size_t min_digits)
- {
- TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned short val, value_flags format, size_t min_digits)
- {
- TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned int val, value_flags format, size_t min_digits)
- {
- TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned long val, value_flags format, size_t min_digits)
- {
- TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream,
- unsigned long long val,
- value_flags format,
- size_t min_digits)
- {
- TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, float val, value_flags format, bool relaxed_precision)
- {
- TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, double val, value_flags format, bool relaxed_precision)
- {
- TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, bool val)
- {
- print_to_stream(stream, val ? "true"sv : "false"sv);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date& val)
- {
- print_to_stream(stream, val.year, {}, 4);
- stream.put('-');
- print_to_stream(stream, val.month, {}, 2);
- stream.put('-');
- print_to_stream(stream, val.day, {}, 2);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time& val)
- {
- print_to_stream(stream, val.hour, {}, 2);
- stream.put(':');
- print_to_stream(stream, val.minute, {}, 2);
- stream.put(':');
- print_to_stream(stream, val.second, {}, 2);
- if (val.nanosecond && val.nanosecond <= 999999999u)
- {
- stream.put('.');
- auto ns = val.nanosecond;
- size_t digits = 9u;
- while (ns % 10u == 0u)
- {
- ns /= 10u;
- digits--;
- }
- print_to_stream(stream, ns, {}, digits);
- }
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time_offset& val)
- {
- if (!val.minutes)
- {
- stream.put('Z');
- return;
- }
-
- auto mins = static_cast<int>(val.minutes);
- if (mins < 0)
- {
- stream.put('-');
- mins = -mins;
- }
- else
- stream.put('+');
- const auto hours = mins / 60;
- if (hours)
- {
- print_to_stream(stream, static_cast<unsigned int>(hours), {}, 2);
- mins -= hours * 60;
- }
- else
- print_to_stream(stream, "00"sv);
- stream.put(':');
- print_to_stream(stream, static_cast<unsigned int>(mins), {}, 2);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date_time& val)
- {
- print_to_stream(stream, val.date);
- stream.put('T');
- print_to_stream(stream, val.time);
- if (val.offset)
- print_to_stream(stream, *val.offset);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_position& val)
- {
- print_to_stream(stream, "line "sv);
- print_to_stream(stream, val.line);
- print_to_stream(stream, ", column "sv);
- print_to_stream(stream, val.column);
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_region& val)
- {
- print_to_stream(stream, val.begin);
- if (val.path)
- {
- print_to_stream(stream, " of '"sv);
- print_to_stream(stream, *val.path);
- stream.put('\'');
- }
- }
+TOML_IMPL_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ TOML_ATTR(nonnull)
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const char* val, size_t len) {
+ stream.write(val, static_cast<std::streamsize>(len));
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, std::string_view val) {
+ stream.write(val.data(), static_cast<std::streamsize>(val.length()));
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const std::string& val) {
+ stream.write(val.data(), static_cast<std::streamsize>(val.length()));
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, char val) {
+ stream.put(val);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, signed char val, value_flags format,
+ size_t min_digits) {
+ TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, signed short val, value_flags format,
+ size_t min_digits) {
+ TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, signed int val, value_flags format,
+ size_t min_digits) {
+ TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, signed long val, value_flags format,
+ size_t min_digits) {
+ TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, signed long long val,
+ value_flags format, size_t min_digits) {
+ TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned char val, value_flags format,
+ size_t min_digits) {
+ TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned short val, value_flags format,
+ size_t min_digits) {
+ TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned int val, value_flags format,
+ size_t min_digits) {
+ TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned long val, value_flags format,
+ size_t min_digits) {
+ TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, unsigned long long val,
+ value_flags format, size_t min_digits) {
+ TOML_ANON_NAMESPACE::print_integer_to_stream(stream, val, format, min_digits);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, float val, value_flags format,
+ bool relaxed_precision) {
+ TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, double val, value_flags format,
+ bool relaxed_precision) {
+ TOML_ANON_NAMESPACE::print_floating_point_to_stream(stream, val, format, relaxed_precision);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, bool val) {
+ print_to_stream(stream, val ? "true"sv : "false"sv);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date& val) {
+ print_to_stream(stream, val.year, {}, 4);
+ stream.put('-');
+ print_to_stream(stream, val.month, {}, 2);
+ stream.put('-');
+ print_to_stream(stream, val.day, {}, 2);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time& val) {
+ print_to_stream(stream, val.hour, {}, 2);
+ stream.put(':');
+ print_to_stream(stream, val.minute, {}, 2);
+ stream.put(':');
+ print_to_stream(stream, val.second, {}, 2);
+ if (val.nanosecond && val.nanosecond <= 999999999u) {
+ stream.put('.');
+ auto ns = val.nanosecond;
+ size_t digits = 9u;
+ while (ns % 10u == 0u) {
+ ns /= 10u;
+ digits--;
+ }
+ print_to_stream(stream, ns, {}, digits);
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::time_offset& val) {
+ if (!val.minutes) {
+ stream.put('Z');
+ return;
+ }
+
+ auto mins = static_cast<int>(val.minutes);
+ if (mins < 0) {
+ stream.put('-');
+ mins = -mins;
+ } else
+ stream.put('+');
+ const auto hours = mins / 60;
+ if (hours) {
+ print_to_stream(stream, static_cast<unsigned int>(hours), {}, 2);
+ mins -= hours * 60;
+ } else
+ print_to_stream(stream, "00"sv);
+ stream.put(':');
+ print_to_stream(stream, static_cast<unsigned int>(mins), {}, 2);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const toml::date_time& val) {
+ print_to_stream(stream, val.date);
+ stream.put('T');
+ print_to_stream(stream, val.time);
+ if (val.offset) print_to_stream(stream, *val.offset);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_position& val) {
+ print_to_stream(stream, "line "sv);
+ print_to_stream(stream, val.line);
+ print_to_stream(stream, ", column "sv);
+ print_to_stream(stream, val.column);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const source_region& val) {
+ print_to_stream(stream, val.begin);
+ if (val.path) {
+ print_to_stream(stream, " of '"sv);
+ print_to_stream(stream, *val.path);
+ stream.put('\'');
+ }
+ }
#if TOML_ENABLE_FORMATTERS
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const array& arr)
- {
- stream << toml_formatter{ arr };
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const table& tbl)
- {
- stream << toml_formatter{ tbl };
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<std::string>& val)
- {
- stream << toml_formatter{ val };
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<int64_t>& val)
- {
- stream << toml_formatter{ val };
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<double>& val)
- {
- stream << toml_formatter{ val };
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<bool>& val)
- {
- stream << toml_formatter{ val };
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date>& val)
- {
- stream << toml_formatter{ val };
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<time>& val)
- {
- stream << toml_formatter{ val };
- }
-
- TOML_EXTERNAL_LINKAGE
- void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date_time>& val)
- {
- stream << toml_formatter{ val };
- }
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const array& arr) {
+ stream << toml_formatter{arr};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const table& tbl) {
+ stream << toml_formatter{tbl};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<std::string>& val) {
+ stream << toml_formatter{val};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<int64_t>& val) {
+ stream << toml_formatter{val};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<double>& val) {
+ stream << toml_formatter{val};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<bool>& val) {
+ stream << toml_formatter{val};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date>& val) {
+ stream << toml_formatter{val};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<time>& val) {
+ stream << toml_formatter{val};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void TOML_CALLCONV print_to_stream(std::ostream & stream, const value<date_time>& val) {
+ stream << toml_formatter{val};
+ }
#endif
}
diff --git a/vendor/toml++/impl/std_string.inl b/vendor/toml++/impl/std_string.inl
index a20d662..9cbf989 100644
--- a/vendor/toml++/impl/std_string.inl
+++ b/vendor/toml++/impl/std_string.inl
@@ -1,15 +1,15 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
-//# {{
+// # {{
#include "preprocessor.hpp"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
#if TOML_WINDOWS
#include "std_string.hpp"
@@ -18,82 +18,60 @@
#include <Windows.h>
#else
-extern "C" __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int CodePage,
- unsigned long dwFlags,
- const wchar_t* lpWideCharStr,
- int cchWideChar,
- char* lpMultiByteStr,
- int cbMultiByte,
- const char* lpDefaultChar,
- int* lpUsedDefaultChar);
+extern "C" __declspec(dllimport) int __stdcall WideCharToMultiByte(
+ unsigned int CodePage, unsigned long dwFlags, const wchar_t* lpWideCharStr, int cchWideChar,
+ char* lpMultiByteStr, int cbMultiByte, const char* lpDefaultChar, int* lpUsedDefaultChar);
-extern "C" __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage,
- unsigned long dwFlags,
- const char* lpMultiByteStr,
- int cbMultiByte,
- wchar_t* lpWideCharStr,
- int cchWideChar);
+extern "C" __declspec(dllimport) int __stdcall MultiByteToWideChar(
+ unsigned int CodePage, unsigned long dwFlags, const char* lpMultiByteStr, int cbMultiByte,
+ wchar_t* lpWideCharStr, int cchWideChar);
-#endif // TOML_INCLUDE_WINDOWS_H
-#endif // _WINDOWS_
+#endif // TOML_INCLUDE_WINDOWS_H
+#endif // _WINDOWS_
#include "header_start.hpp"
-TOML_IMPL_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- std::string narrow(std::wstring_view str)
- {
- if (str.empty())
- return {};
+TOML_IMPL_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ std::string narrow(std::wstring_view str) {
+ if (str.empty()) return {};
- std::string s;
- const auto len =
- ::WideCharToMultiByte(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr);
- if (len)
- {
- s.resize(static_cast<size_t>(len));
- ::WideCharToMultiByte(65001,
- 0,
- str.data(),
- static_cast<int>(str.length()),
- s.data(),
- len,
- nullptr,
- nullptr);
- }
- return s;
- }
+ std::string s;
+ const auto len = ::WideCharToMultiByte(65001, 0, str.data(), static_cast<int>(str.length()),
+ nullptr, 0, nullptr, nullptr);
+ if (len) {
+ s.resize(static_cast<size_t>(len));
+ ::WideCharToMultiByte(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len,
+ nullptr, nullptr);
+ }
+ return s;
+ }
- TOML_EXTERNAL_LINKAGE
- std::wstring widen(std::string_view str)
- {
- if (str.empty())
- return {};
+ TOML_EXTERNAL_LINKAGE
+ std::wstring widen(std::string_view str) {
+ if (str.empty()) return {};
- std::wstring s;
- const auto len = ::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
- if (len)
- {
- s.resize(static_cast<size_t>(len));
- ::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len);
- }
- return s;
- }
+ std::wstring s;
+ const auto len =
+ ::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
+ if (len) {
+ s.resize(static_cast<size_t>(len));
+ ::MultiByteToWideChar(65001, 0, str.data(), static_cast<int>(str.length()), s.data(), len);
+ }
+ return s;
+ }
#if TOML_HAS_CHAR8
- TOML_EXTERNAL_LINKAGE
- std::wstring widen(std::u8string_view str)
- {
- if (str.empty())
- return {};
+ TOML_EXTERNAL_LINKAGE
+ std::wstring widen(std::u8string_view str) {
+ if (str.empty()) return {};
- return widen(std::string_view{ reinterpret_cast<const char*>(str.data()), str.length() });
- }
+ return widen(std::string_view{reinterpret_cast<const char*>(str.data()), str.length()});
+ }
-#endif // TOML_HAS_CHAR8
+#endif // TOML_HAS_CHAR8
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.hpp"
-#endif // TOML_WINDOWS
+#endif // TOML_WINDOWS
diff --git a/vendor/toml++/impl/table.inl b/vendor/toml++/impl/table.inl
index 01cba01..ca7473e 100644
--- a/vendor/toml++/impl/table.inl
+++ b/vendor/toml++/impl/table.inl
@@ -1,317 +1,259 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
-//# {{
+// # {{
#include "preprocessor.hpp"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
-#include "table.hpp"
-#include "node_view.hpp"
#include "header_start.hpp"
+#include "node_view.hpp"
+#include "table.hpp"
-TOML_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- table::table() noexcept
- {
+TOML_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ table::table() noexcept {
#if TOML_LIFETIME_HOOKS
- TOML_TABLE_CREATED;
+ TOML_TABLE_CREATED;
#endif
- }
+ }
- TOML_EXTERNAL_LINKAGE
- table::~table() noexcept
- {
+ TOML_EXTERNAL_LINKAGE
+ table::~table() noexcept {
#if TOML_LIFETIME_HOOKS
- TOML_TABLE_DESTROYED;
+ TOML_TABLE_DESTROYED;
#endif
- }
+ }
- TOML_EXTERNAL_LINKAGE
- table::table(const impl::table_init_pair* b, const impl::table_init_pair* e)
- {
+ TOML_EXTERNAL_LINKAGE
+ table::table(const impl::table_init_pair* b, const impl::table_init_pair* e) {
#if TOML_LIFETIME_HOOKS
- TOML_TABLE_CREATED;
+ TOML_TABLE_CREATED;
#endif
- TOML_ASSERT_ASSUME(b);
- TOML_ASSERT_ASSUME(e);
- TOML_ASSERT_ASSUME(b <= e);
+ TOML_ASSERT_ASSUME(b);
+ TOML_ASSERT_ASSUME(e);
+ TOML_ASSERT_ASSUME(b <= e);
- if TOML_UNLIKELY(b == e)
- return;
+ if TOML_UNLIKELY (b == e) return;
- for (; b != e; b++)
- {
- if (!b->value) // empty node_views
- continue;
+ for (; b != e; b++) {
+ if (!b->value) // empty node_views
+ continue;
- map_.insert_or_assign(std::move(b->key), std::move(b->value));
- }
- }
+ map_.insert_or_assign(std::move(b->key), std::move(b->value));
+ }
+ }
- TOML_EXTERNAL_LINKAGE
- table::table(const table& other) //
- : node(other),
- inline_{ other.inline_ }
- {
- for (auto&& [k, v] : other.map_)
- map_.emplace_hint(map_.end(), k, impl::make_node(*v));
+ TOML_EXTERNAL_LINKAGE
+ table::table(const table& other) //
+ : node(other), inline_{other.inline_} {
+ for (auto&& [k, v] : other.map_) map_.emplace_hint(map_.end(), k, impl::make_node(*v));
#if TOML_LIFETIME_HOOKS
- TOML_TABLE_CREATED;
+ TOML_TABLE_CREATED;
#endif
- }
-
- TOML_EXTERNAL_LINKAGE
- table::table(table && other) noexcept //
- : node(std::move(other)),
- map_{ std::move(other.map_) },
- inline_{ other.inline_ }
- {
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::table(table && other) noexcept //
+ : node(std::move(other)), map_{std::move(other.map_)}, inline_{other.inline_} {
#if TOML_LIFETIME_HOOKS
- TOML_TABLE_CREATED;
+ TOML_TABLE_CREATED;
#endif
- }
-
- TOML_EXTERNAL_LINKAGE
- table& table::operator=(const table& rhs)
- {
- if (&rhs != this)
- {
- node::operator=(rhs);
- map_.clear();
- for (auto&& [k, v] : rhs.map_)
- map_.emplace_hint(map_.end(), k, impl::make_node(*v));
- inline_ = rhs.inline_;
- }
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- table& table::operator=(table&& rhs) noexcept
- {
- if (&rhs != this)
- {
- node::operator=(std::move(rhs));
- map_ = std::move(rhs.map_);
- inline_ = rhs.inline_;
- }
- return *this;
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- bool table::is_homogeneous(node_type ntype) const noexcept
- {
- if (map_.empty())
- return false;
-
- if (ntype == node_type::none)
- ntype = map_.cbegin()->second->type();
-
- for (auto&& [k, v] : map_)
- {
- TOML_UNUSED(k);
- if (v->type() != ntype)
- return false;
- }
-
- return true;
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- bool table::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
- {
- if (map_.empty())
- {
- first_nonmatch = {};
- return false;
- }
- if (ntype == node_type::none)
- ntype = map_.cbegin()->second->type();
- for (const auto& [k, v] : map_)
- {
- TOML_UNUSED(k);
- if (v->type() != ntype)
- {
- first_nonmatch = v.get();
- return false;
- }
- }
- return true;
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- bool table::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept
- {
- node* fnm = nullptr;
- const auto result = const_cast<table&>(*this).is_homogeneous(ntype, fnm);
- first_nonmatch = fnm;
- return result;
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- node* table::get(std::string_view key) noexcept
- {
- if (auto it = map_.find(key); it != map_.end())
- return it->second.get();
- return nullptr;
- }
-
- TOML_EXTERNAL_LINKAGE
- node& table::at(std::string_view key)
- {
- auto n = get(key);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table& table::operator=(const table& rhs) {
+ if (&rhs != this) {
+ node::operator=(rhs);
+ map_.clear();
+ for (auto&& [k, v] : rhs.map_) map_.emplace_hint(map_.end(), k, impl::make_node(*v));
+ inline_ = rhs.inline_;
+ }
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table& table::operator=(table&& rhs) noexcept {
+ if (&rhs != this) {
+ node::operator=(std::move(rhs));
+ map_ = std::move(rhs.map_);
+ inline_ = rhs.inline_;
+ }
+ return *this;
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ bool table::is_homogeneous(node_type ntype) const noexcept {
+ if (map_.empty()) return false;
+
+ if (ntype == node_type::none) ntype = map_.cbegin()->second->type();
+
+ for (auto&& [k, v] : map_) {
+ TOML_UNUSED(k);
+ if (v->type() != ntype) return false;
+ }
+
+ return true;
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ bool table::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept {
+ if (map_.empty()) {
+ first_nonmatch = {};
+ return false;
+ }
+ if (ntype == node_type::none) ntype = map_.cbegin()->second->type();
+ for (const auto& [k, v] : map_) {
+ TOML_UNUSED(k);
+ if (v->type() != ntype) {
+ first_nonmatch = v.get();
+ return false;
+ }
+ }
+ return true;
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ bool table::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept {
+ node* fnm = nullptr;
+ const auto result = const_cast<table&>(*this).is_homogeneous(ntype, fnm);
+ first_nonmatch = fnm;
+ return result;
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ node* table::get(std::string_view key) noexcept {
+ if (auto it = map_.find(key); it != map_.end()) return it->second.get();
+ return nullptr;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ node& table::at(std::string_view key) {
+ auto n = get(key);
#if TOML_COMPILER_HAS_EXCEPTIONS
- if (!n)
- {
- auto err = "key '"s;
- err.append(key);
- err.append("' not found in table"sv);
- throw std::out_of_range{ err };
- }
+ if (!n) {
+ auto err = "key '"s;
+ err.append(key);
+ err.append("' not found in table"sv);
+ throw std::out_of_range{err};
+ }
#else
- TOML_ASSERT_ASSUME(n && "key not found in table!");
+ TOML_ASSERT_ASSUME(n && "key not found in table!");
#endif
- return *n;
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- table::map_iterator table::get_lower_bound(std::string_view key) noexcept
- {
- return map_.lower_bound(key);
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- table::iterator table::find(std::string_view key) noexcept
- {
- return iterator{ map_.find(key) };
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- table::const_iterator table::find(std::string_view key) const noexcept
- {
- return const_iterator{ map_.find(key) };
- }
-
- TOML_EXTERNAL_LINKAGE
- table::map_iterator table::erase(const_map_iterator pos) noexcept
- {
- return map_.erase(pos);
- }
-
- TOML_EXTERNAL_LINKAGE
- table::map_iterator table::erase(const_map_iterator begin, const_map_iterator end) noexcept
- {
- return map_.erase(begin, end);
- }
-
- TOML_EXTERNAL_LINKAGE
- size_t table::erase(std::string_view key) noexcept
- {
- if (auto it = map_.find(key); it != map_.end())
- {
- map_.erase(it);
- return size_t{ 1 };
- }
- return size_t{};
- }
-
- TOML_EXTERNAL_LINKAGE
- table& table::prune(bool recursive)& noexcept
- {
- if (map_.empty())
- return *this;
-
- for (auto it = map_.begin(); it != map_.end();)
- {
- if (auto arr = it->second->as_array())
- {
- if (recursive)
- arr->prune(true);
-
- if (arr->empty())
- {
- it = map_.erase(it);
- continue;
- }
- }
- else if (auto tbl = it->second->as_table())
- {
- if (recursive)
- tbl->prune(true);
-
- if (tbl->empty())
- {
- it = map_.erase(it);
- continue;
- }
- }
- it++;
- }
-
- return *this;
- }
-
- TOML_EXTERNAL_LINKAGE
- void table::clear() noexcept
- {
- map_.clear();
- }
-
- TOML_EXTERNAL_LINKAGE
- table::map_iterator table::insert_with_hint(const_iterator hint, key && k, impl::node_ptr && v)
- {
- return map_.emplace_hint(const_map_iterator{ hint }, std::move(k), std::move(v));
- }
-
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- bool TOML_CALLCONV table::equal(const table& lhs, const table& rhs) noexcept
- {
- if (&lhs == &rhs)
- return true;
- if (lhs.map_.size() != rhs.map_.size())
- return false;
-
- for (auto l = lhs.map_.begin(), r = rhs.map_.begin(), e = lhs.map_.end(); l != e; l++, r++)
- {
- if (l->first != r->first)
- return false;
-
- const auto lhs_type = l->second->type();
- const node& rhs_ = *r->second;
- const auto rhs_type = rhs_.type();
- if (lhs_type != rhs_type)
- return false;
-
- const bool equal = l->second->visit(
- [&](const auto& lhs_) noexcept
- { return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
- if (!equal)
- return false;
- }
- return true;
- }
+ return *n;
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ table::map_iterator table::get_lower_bound(std::string_view key) noexcept {
+ return map_.lower_bound(key);
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ table::iterator table::find(std::string_view key) noexcept {
+ return iterator{map_.find(key)};
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ table::const_iterator table::find(std::string_view key) const noexcept {
+ return const_iterator{map_.find(key)};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::map_iterator table::erase(const_map_iterator pos) noexcept {
+ return map_.erase(pos);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::map_iterator table::erase(const_map_iterator begin, const_map_iterator end) noexcept {
+ return map_.erase(begin, end);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ size_t table::erase(std::string_view key) noexcept {
+ if (auto it = map_.find(key); it != map_.end()) {
+ map_.erase(it);
+ return size_t{1};
+ }
+ return size_t{};
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table& table::prune(bool recursive)& noexcept {
+ if (map_.empty()) return *this;
+
+ for (auto it = map_.begin(); it != map_.end();) {
+ if (auto arr = it->second->as_array()) {
+ if (recursive) arr->prune(true);
+
+ if (arr->empty()) {
+ it = map_.erase(it);
+ continue;
+ }
+ } else if (auto tbl = it->second->as_table()) {
+ if (recursive) tbl->prune(true);
+
+ if (tbl->empty()) {
+ it = map_.erase(it);
+ continue;
+ }
+ }
+ it++;
+ }
+
+ return *this;
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void table::clear() noexcept {
+ map_.clear();
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ table::map_iterator table::insert_with_hint(const_iterator hint, key && k, impl::node_ptr && v) {
+ return map_.emplace_hint(const_map_iterator{hint}, std::move(k), std::move(v));
+ }
+
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ bool TOML_CALLCONV table::equal(const table& lhs, const table& rhs) noexcept {
+ if (&lhs == &rhs) return true;
+ if (lhs.map_.size() != rhs.map_.size()) return false;
+
+ for (auto l = lhs.map_.begin(), r = rhs.map_.begin(), e = lhs.map_.end(); l != e; l++, r++) {
+ if (l->first != r->first) return false;
+
+ const auto lhs_type = l->second->type();
+ const node& rhs_ = *r->second;
+ const auto rhs_type = rhs_.type();
+ if (lhs_type != rhs_type) return false;
+
+ const bool equal = l->second->visit([&](const auto& lhs_) noexcept {
+ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_);
+ });
+ if (!equal) return false;
+ }
+ return true;
+ }
}
TOML_NAMESPACE_END;
diff --git a/vendor/toml++/impl/toml_formatter.inl b/vendor/toml++/impl/toml_formatter.inl
index e764448..02c6d0b 100644
--- a/vendor/toml++/impl/toml_formatter.inl
+++ b/vendor/toml++/impl/toml_formatter.inl
@@ -1,405 +1,366 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.hpp"
-//# {{
+// # {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
#if TOML_ENABLE_FORMATTERS
-#include "toml_formatter.hpp"
+#include "array.hpp"
+#include "header_start.hpp"
#include "print_to_stream.hpp"
-#include "value.hpp"
#include "table.hpp"
-#include "array.hpp"
+#include "toml_formatter.hpp"
#include "unicode.hpp"
-#include "header_start.hpp"
+#include "value.hpp"
TOML_DISABLE_ARITHMETIC_WARNINGS;
-TOML_ANON_NAMESPACE_START
-{
- TOML_INTERNAL_LINKAGE
- size_t toml_formatter_count_inline_columns(const node& node, size_t line_wrap_cols) noexcept
- {
- switch (node.type())
- {
- case node_type::table:
- {
- auto& tbl = *reinterpret_cast<const table*>(&node);
- if (tbl.empty())
- return 2u; // "{}"
- size_t weight = 3u; // "{ }"
- for (auto&& [k, v] : tbl)
- {
- weight += k.length() + toml_formatter_count_inline_columns(v, line_wrap_cols) + 2u; // + ", "
- if (weight >= line_wrap_cols)
- break;
- }
- return weight;
- }
-
- case node_type::array:
- {
- auto& arr = *reinterpret_cast<const array*>(&node);
- if (arr.empty())
- return 2u; // "[]"
- size_t weight = 3u; // "[ ]"
- for (auto& elem : arr)
- {
- weight += toml_formatter_count_inline_columns(elem, line_wrap_cols) + 2u; // + ", "
- if (weight >= line_wrap_cols)
- break;
- }
- return weight;
- }
-
- case node_type::string:
- {
- // todo: proper utf8 decoding?
- // todo: tab awareness?
- auto& str = (*reinterpret_cast<const value<std::string>*>(&node)).get();
- return str.length() + 2u; // + ""
- }
-
- case node_type::integer:
- {
- auto val = (*reinterpret_cast<const value<int64_t>*>(&node)).get();
- if (!val)
- return 1u;
- size_t weight = {};
- if (val < 0)
- {
- weight += 1u;
- val *= -1;
- }
- return weight + static_cast<size_t>(log10(static_cast<double>(val))) + 1u;
- }
-
- case node_type::floating_point:
- {
- auto val = (*reinterpret_cast<const value<double>*>(&node)).get();
- if (val == 0.0)
- return 3u; // "0.0"
- size_t weight = 2u; // ".0"
- if (val < 0.0)
- {
- weight += 1u;
- val *= -1.0;
- }
- return weight + static_cast<size_t>(log10(val)) + 1u;
- break;
- }
-
- case node_type::boolean: return 5u;
- case node_type::date: [[fallthrough]];
- case node_type::time: return 10u;
- case node_type::date_time: return 30u;
- case node_type::none: TOML_UNREACHABLE;
- default: TOML_UNREACHABLE;
- }
-
- TOML_UNREACHABLE;
- }
-
- TOML_INTERNAL_LINKAGE
- bool toml_formatter_forces_multiline(const node& node, size_t line_wrap_cols, size_t starting_column_bias) noexcept
- {
- return (toml_formatter_count_inline_columns(node, line_wrap_cols) + starting_column_bias) >= line_wrap_cols;
- }
+TOML_ANON_NAMESPACE_START {
+ TOML_INTERNAL_LINKAGE
+ size_t toml_formatter_count_inline_columns(const node& node, size_t line_wrap_cols) noexcept {
+ switch (node.type()) {
+ case node_type::table: {
+ auto& tbl = *reinterpret_cast<const table*>(&node);
+ if (tbl.empty()) return 2u; // "{}"
+ size_t weight = 3u; // "{ }"
+ for (auto&& [k, v] : tbl) {
+ weight +=
+ k.length() + toml_formatter_count_inline_columns(v, line_wrap_cols) + 2u; // + ", "
+ if (weight >= line_wrap_cols) break;
+ }
+ return weight;
+ }
+
+ case node_type::array: {
+ auto& arr = *reinterpret_cast<const array*>(&node);
+ if (arr.empty()) return 2u; // "[]"
+ size_t weight = 3u; // "[ ]"
+ for (auto& elem : arr) {
+ weight += toml_formatter_count_inline_columns(elem, line_wrap_cols) + 2u; // + ", "
+ if (weight >= line_wrap_cols) break;
+ }
+ return weight;
+ }
+
+ case node_type::string: {
+ // todo: proper utf8 decoding?
+ // todo: tab awareness?
+ auto& str = (*reinterpret_cast<const value<std::string>*>(&node)).get();
+ return str.length() + 2u; // + ""
+ }
+
+ case node_type::integer: {
+ auto val = (*reinterpret_cast<const value<int64_t>*>(&node)).get();
+ if (!val) return 1u;
+ size_t weight = {};
+ if (val < 0) {
+ weight += 1u;
+ val *= -1;
+ }
+ return weight + static_cast<size_t>(log10(static_cast<double>(val))) + 1u;
+ }
+
+ case node_type::floating_point: {
+ auto val = (*reinterpret_cast<const value<double>*>(&node)).get();
+ if (val == 0.0) return 3u; // "0.0"
+ size_t weight = 2u; // ".0"
+ if (val < 0.0) {
+ weight += 1u;
+ val *= -1.0;
+ }
+ return weight + static_cast<size_t>(log10(val)) + 1u;
+ break;
+ }
+
+ case node_type::boolean:
+ return 5u;
+ case node_type::date:
+ [[fallthrough]];
+ case node_type::time:
+ return 10u;
+ case node_type::date_time:
+ return 30u;
+ case node_type::none:
+ TOML_UNREACHABLE;
+ default:
+ TOML_UNREACHABLE;
+ }
+
+ TOML_UNREACHABLE;
+ }
+
+ TOML_INTERNAL_LINKAGE
+ bool toml_formatter_forces_multiline(const node& node, size_t line_wrap_cols,
+ size_t starting_column_bias) noexcept {
+ return (toml_formatter_count_inline_columns(node, line_wrap_cols) + starting_column_bias) >=
+ line_wrap_cols;
+ }
}
TOML_ANON_NAMESPACE_END;
-TOML_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- void toml_formatter::print_pending_table_separator()
- {
- if (pending_table_separator_)
- {
- print_newline(true);
- print_newline(true);
- pending_table_separator_ = false;
- }
- }
-
- TOML_EXTERNAL_LINKAGE
- void toml_formatter::print(const key& k)
- {
- print_string(k.str(), false, true, false);
- }
-
- TOML_EXTERNAL_LINKAGE
- void toml_formatter::print_inline(const table& tbl)
- {
- if (tbl.empty())
- {
- print_unformatted("{}"sv);
- return;
- }
-
- print_unformatted("{ "sv);
-
- bool first = false;
- for (auto&& [k, v] : tbl)
- {
- if (first)
- print_unformatted(", "sv);
- first = true;
-
- print(k);
- if (terse_kvps())
- print_unformatted("="sv);
- else
- print_unformatted(" = "sv);
-
- const auto type = v.type();
- TOML_ASSUME(type != node_type::none);
- switch (type)
- {
- case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
- case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
- default: print_value(v, type);
- }
- }
-
- print_unformatted(" }"sv);
- }
-
- TOML_EXTERNAL_LINKAGE
- void toml_formatter::print(const array& arr)
- {
- if (arr.empty())
- {
- print_unformatted("[]"sv);
- return;
- }
-
- const auto original_indent = indent();
- const auto multiline = TOML_ANON_NAMESPACE::toml_formatter_forces_multiline(
- arr,
- 120u,
- indent_columns() * static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
-
- print_unformatted("["sv);
-
- if (multiline)
- {
- if (original_indent < 0)
- indent(0);
- if (indent_array_elements())
- increase_indent();
- }
- else
- print_unformatted(' ');
-
- for (size_t i = 0; i < arr.size(); i++)
- {
- if (i > 0u)
- {
- print_unformatted(',');
- if (!multiline)
- print_unformatted(' ');
- }
-
- if (multiline)
- {
- print_newline(true);
- print_indent();
- }
-
- auto& v = arr[i];
- const auto type = v.type();
- TOML_ASSUME(type != node_type::none);
- switch (type)
- {
- case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
- case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
- default: print_value(v, type);
- }
- }
- if (multiline)
- {
- indent(original_indent);
- print_newline(true);
- print_indent();
- }
- else
- print_unformatted(' ');
-
- print_unformatted("]"sv);
- }
-
- TOML_EXTERNAL_LINKAGE
- void toml_formatter::print(const table& tbl)
- {
- static constexpr auto is_non_inline_array_of_tables = [](const node& n) noexcept
- {
- const auto arr = n.as_array();
- if (!arr || !arr->is_array_of_tables())
- return false;
-
- return !reinterpret_cast<const table*>(&(*arr)[0])->is_inline();
- };
-
- // values, arrays, and inline tables/table arrays
- for (auto&& [k, v] : tbl)
- {
- const auto type = v.type();
- if ((type == node_type::table && !reinterpret_cast<const table*>(&v)->is_inline())
- || (type == node_type::array && is_non_inline_array_of_tables(v)))
- continue;
-
- pending_table_separator_ = true;
- print_newline();
- print_indent();
- print(k);
- if (terse_kvps())
- print_unformatted("="sv);
- else
- print_unformatted(" = "sv);
- TOML_ASSUME(type != node_type::none);
- switch (type)
- {
- case node_type::table: print_inline(*reinterpret_cast<const table*>(&v)); break;
- case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
- default: print_value(v, type);
- }
- }
-
- const auto print_key_path = [&]()
- {
- size_t i{};
- for (const auto k : key_path_)
- {
- if (i++)
- print_unformatted('.');
- print(*k);
- }
- };
-
- // non-inline tables
- for (auto&& [k, v] : tbl)
- {
- const auto type = v.type();
- if (type != node_type::table || reinterpret_cast<const table*>(&v)->is_inline())
- continue;
- auto& child_tbl = *reinterpret_cast<const table*>(&v);
-
- // we can skip indenting and emitting the headers for tables that only contain other tables
- // (so we don't over-nest)
- size_t child_value_count{}; // includes inline tables and non-table arrays
- size_t child_table_count{};
- size_t child_table_array_count{};
- for (auto&& [child_k, child_v] : child_tbl)
- {
- TOML_UNUSED(child_k);
- const auto child_type = child_v.type();
- TOML_ASSUME(child_type != node_type::none);
- switch (child_type)
- {
- case node_type::table:
- if (reinterpret_cast<const table*>(&child_v)->is_inline())
- child_value_count++;
- else
- child_table_count++;
- break;
-
- case node_type::array:
- if (is_non_inline_array_of_tables(child_v))
- child_table_array_count++;
- else
- child_value_count++;
- break;
-
- default: child_value_count++;
- }
- }
- bool skip_self = false;
- if (child_value_count == 0u && (child_table_count > 0u || child_table_array_count > 0u))
- skip_self = true;
-
- key_path_.push_back(&k);
-
- if (!skip_self)
- {
- print_pending_table_separator();
- if (indent_sub_tables())
- increase_indent();
- print_indent();
- print_unformatted("["sv);
- print_key_path();
- print_unformatted("]"sv);
- pending_table_separator_ = true;
- }
-
- print(child_tbl);
-
- key_path_.pop_back();
- if (!skip_self && indent_sub_tables())
- decrease_indent();
- }
-
- // table arrays
- for (auto&& [k, v] : tbl)
- {
- if (!is_non_inline_array_of_tables(v))
- continue;
- auto& arr = *reinterpret_cast<const array*>(&v);
-
- if (indent_sub_tables())
- increase_indent();
- key_path_.push_back(&k);
-
- for (size_t i = 0; i < arr.size(); i++)
- {
- print_pending_table_separator();
- print_indent();
- print_unformatted("[["sv);
- print_key_path();
- print_unformatted("]]"sv);
- pending_table_separator_ = true;
- print(*reinterpret_cast<const table*>(&arr[i]));
- }
-
- key_path_.pop_back();
- if (indent_sub_tables())
- decrease_indent();
- }
- }
-
- TOML_EXTERNAL_LINKAGE
- void toml_formatter::print()
- {
- if (dump_failed_parse_result())
- return;
-
- switch (auto source_type = source().type())
- {
- case node_type::table:
- {
- auto& tbl = *reinterpret_cast<const table*>(&source());
- if (tbl.is_inline())
- print_inline(tbl);
- else
- {
- decrease_indent(); // so root kvps and tables have the same indent
- print(tbl);
- }
- break;
- }
-
- case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
-
- default: print_value(source(), source_type);
- }
- }
+TOML_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ void toml_formatter::print_pending_table_separator() {
+ if (pending_table_separator_) {
+ print_newline(true);
+ print_newline(true);
+ pending_table_separator_ = false;
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void toml_formatter::print(const key& k) {
+ print_string(k.str(), false, true, false);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void toml_formatter::print_inline(const table& tbl) {
+ if (tbl.empty()) {
+ print_unformatted("{}"sv);
+ return;
+ }
+
+ print_unformatted("{ "sv);
+
+ bool first = false;
+ for (auto&& [k, v] : tbl) {
+ if (first) print_unformatted(", "sv);
+ first = true;
+
+ print(k);
+ if (terse_kvps())
+ print_unformatted("="sv);
+ else
+ print_unformatted(" = "sv);
+
+ const auto type = v.type();
+ TOML_ASSUME(type != node_type::none);
+ switch (type) {
+ case node_type::table:
+ print_inline(*reinterpret_cast<const table*>(&v));
+ break;
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&v));
+ break;
+ default:
+ print_value(v, type);
+ }
+ }
+
+ print_unformatted(" }"sv);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void toml_formatter::print(const array& arr) {
+ if (arr.empty()) {
+ print_unformatted("[]"sv);
+ return;
+ }
+
+ const auto original_indent = indent();
+ const auto multiline = TOML_ANON_NAMESPACE::toml_formatter_forces_multiline(
+ arr, 120u,
+ indent_columns() * static_cast<size_t>(original_indent < 0 ? 0 : original_indent));
+
+ print_unformatted("["sv);
+
+ if (multiline) {
+ if (original_indent < 0) indent(0);
+ if (indent_array_elements()) increase_indent();
+ } else
+ print_unformatted(' ');
+
+ for (size_t i = 0; i < arr.size(); i++) {
+ if (i > 0u) {
+ print_unformatted(',');
+ if (!multiline) print_unformatted(' ');
+ }
+
+ if (multiline) {
+ print_newline(true);
+ print_indent();
+ }
+
+ auto& v = arr[i];
+ const auto type = v.type();
+ TOML_ASSUME(type != node_type::none);
+ switch (type) {
+ case node_type::table:
+ print_inline(*reinterpret_cast<const table*>(&v));
+ break;
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&v));
+ break;
+ default:
+ print_value(v, type);
+ }
+ }
+ if (multiline) {
+ indent(original_indent);
+ print_newline(true);
+ print_indent();
+ } else
+ print_unformatted(' ');
+
+ print_unformatted("]"sv);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void toml_formatter::print(const table& tbl) {
+ static constexpr auto is_non_inline_array_of_tables = [](const node& n) noexcept {
+ const auto arr = n.as_array();
+ if (!arr || !arr->is_array_of_tables()) return false;
+
+ return !reinterpret_cast<const table*>(&(*arr)[0])->is_inline();
+ };
+
+ // values, arrays, and inline tables/table arrays
+ for (auto&& [k, v] : tbl) {
+ const auto type = v.type();
+ if ((type == node_type::table && !reinterpret_cast<const table*>(&v)->is_inline()) ||
+ (type == node_type::array && is_non_inline_array_of_tables(v)))
+ continue;
+
+ pending_table_separator_ = true;
+ print_newline();
+ print_indent();
+ print(k);
+ if (terse_kvps())
+ print_unformatted("="sv);
+ else
+ print_unformatted(" = "sv);
+ TOML_ASSUME(type != node_type::none);
+ switch (type) {
+ case node_type::table:
+ print_inline(*reinterpret_cast<const table*>(&v));
+ break;
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&v));
+ break;
+ default:
+ print_value(v, type);
+ }
+ }
+
+ const auto print_key_path = [&]() {
+ size_t i{};
+ for (const auto k : key_path_) {
+ if (i++) print_unformatted('.');
+ print(*k);
+ }
+ };
+
+ // non-inline tables
+ for (auto&& [k, v] : tbl) {
+ const auto type = v.type();
+ if (type != node_type::table || reinterpret_cast<const table*>(&v)->is_inline()) continue;
+ auto& child_tbl = *reinterpret_cast<const table*>(&v);
+
+ // we can skip indenting and emitting the headers for tables that only contain other tables
+ // (so we don't over-nest)
+ size_t child_value_count{}; // includes inline tables and non-table arrays
+ size_t child_table_count{};
+ size_t child_table_array_count{};
+ for (auto&& [child_k, child_v] : child_tbl) {
+ TOML_UNUSED(child_k);
+ const auto child_type = child_v.type();
+ TOML_ASSUME(child_type != node_type::none);
+ switch (child_type) {
+ case node_type::table:
+ if (reinterpret_cast<const table*>(&child_v)->is_inline())
+ child_value_count++;
+ else
+ child_table_count++;
+ break;
+
+ case node_type::array:
+ if (is_non_inline_array_of_tables(child_v))
+ child_table_array_count++;
+ else
+ child_value_count++;
+ break;
+
+ default:
+ child_value_count++;
+ }
+ }
+ bool skip_self = false;
+ if (child_value_count == 0u && (child_table_count > 0u || child_table_array_count > 0u))
+ skip_self = true;
+
+ key_path_.push_back(&k);
+
+ if (!skip_self) {
+ print_pending_table_separator();
+ if (indent_sub_tables()) increase_indent();
+ print_indent();
+ print_unformatted("["sv);
+ print_key_path();
+ print_unformatted("]"sv);
+ pending_table_separator_ = true;
+ }
+
+ print(child_tbl);
+
+ key_path_.pop_back();
+ if (!skip_self && indent_sub_tables()) decrease_indent();
+ }
+
+ // table arrays
+ for (auto&& [k, v] : tbl) {
+ if (!is_non_inline_array_of_tables(v)) continue;
+ auto& arr = *reinterpret_cast<const array*>(&v);
+
+ if (indent_sub_tables()) increase_indent();
+ key_path_.push_back(&k);
+
+ for (size_t i = 0; i < arr.size(); i++) {
+ print_pending_table_separator();
+ print_indent();
+ print_unformatted("[["sv);
+ print_key_path();
+ print_unformatted("]]"sv);
+ pending_table_separator_ = true;
+ print(*reinterpret_cast<const table*>(&arr[i]));
+ }
+
+ key_path_.pop_back();
+ if (indent_sub_tables()) decrease_indent();
+ }
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void toml_formatter::print() {
+ if (dump_failed_parse_result()) return;
+
+ switch (auto source_type = source().type()) {
+ case node_type::table: {
+ auto& tbl = *reinterpret_cast<const table*>(&source());
+ if (tbl.is_inline())
+ print_inline(tbl);
+ else {
+ decrease_indent(); // so root kvps and tables have the same indent
+ print(tbl);
+ }
+ break;
+ }
+
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&source()));
+ break;
+
+ default:
+ print_value(source(), source_type);
+ }
+ }
}
TOML_NAMESPACE_END;
#include "header_end.hpp"
-#endif // TOML_ENABLE_FORMATTERS
+#endif // TOML_ENABLE_FORMATTERS
diff --git a/vendor/toml++/impl/unicode.inl b/vendor/toml++/impl/unicode.inl
index 4064c58..93a7d52 100644
--- a/vendor/toml++/impl/unicode.inl
+++ b/vendor/toml++/impl/unicode.inl
@@ -1,59 +1,53 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
-//# {{
+// # {{
#include "preprocessor.hpp"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
-#include "unicode.hpp"
-#include "simd.hpp"
#include "header_start.hpp"
+#include "simd.hpp"
+#include "unicode.hpp"
-TOML_IMPL_NAMESPACE_START
-{
- TOML_PURE_GETTER
- TOML_EXTERNAL_LINKAGE
- bool is_ascii(const char* str, size_t len) noexcept
- {
- const char* const end = str + len;
+TOML_IMPL_NAMESPACE_START {
+ TOML_PURE_GETTER
+ TOML_EXTERNAL_LINKAGE
+ bool is_ascii(const char* str, size_t len) noexcept {
+ const char* const end = str + len;
#if TOML_HAS_SSE2 && (128 % CHAR_BIT) == 0
- {
- constexpr size_t chars_per_vector = 128u / CHAR_BIT;
-
- if (const size_t simdable = len - (len % chars_per_vector))
- {
- __m128i mask = _mm_setzero_si128();
- for (const char* const e = str + simdable; str < e; str += chars_per_vector)
- {
- const __m128i current_bytes = _mm_loadu_si128(reinterpret_cast<const __m128i*>(str));
- mask = _mm_or_si128(mask, current_bytes);
- }
- const __m128i has_error = _mm_cmpgt_epi8(_mm_setzero_si128(), mask);
+ {
+ constexpr size_t chars_per_vector = 128u / CHAR_BIT;
+
+ if (const size_t simdable = len - (len % chars_per_vector)) {
+ __m128i mask = _mm_setzero_si128();
+ for (const char* const e = str + simdable; str < e; str += chars_per_vector) {
+ const __m128i current_bytes = _mm_loadu_si128(reinterpret_cast<const __m128i*>(str));
+ mask = _mm_or_si128(mask, current_bytes);
+ }
+ const __m128i has_error = _mm_cmpgt_epi8(_mm_setzero_si128(), mask);
#if TOML_HAS_SSE4_1
- if (!_mm_testz_si128(has_error, has_error))
- return false;
+ if (!_mm_testz_si128(has_error, has_error)) return false;
#else
- if (_mm_movemask_epi8(_mm_cmpeq_epi8(has_error, _mm_setzero_si128())) != 0xFFFF)
- return false;
+ if (_mm_movemask_epi8(_mm_cmpeq_epi8(has_error, _mm_setzero_si128())) != 0xFFFF)
+ return false;
#endif
- }
- }
+ }
+ }
#endif
- for (; str < end; str++)
- if (static_cast<unsigned char>(*str) > 127u)
- return false;
+ for (; str < end; str++)
+ if (static_cast<unsigned char>(*str) > 127u) return false;
- return true;
- }
+ return true;
+ }
}
TOML_IMPL_NAMESPACE_END;
diff --git a/vendor/toml++/impl/yaml_formatter.inl b/vendor/toml++/impl/yaml_formatter.inl
index 95cb08d..7bf4c5f 100644
--- a/vendor/toml++/impl/yaml_formatter.inl
+++ b/vendor/toml++/impl/yaml_formatter.inl
@@ -1,165 +1,164 @@
-//# This file is a part of toml++ and is subject to the the terms of the MIT license.
-//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
-//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
-// SPDX-License-Identifier: MIT
+// # This file is a part of toml++ and is subject to the the terms of the MIT license.
+// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
+// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
+// SPDX-License-Identifier: MIT
#pragma once
#include "preprocessor.hpp"
-//# {{
+// # {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
-//# }}
+// # }}
#if TOML_ENABLE_FORMATTERS
-#include "yaml_formatter.hpp"
-#include "print_to_stream.hpp"
-#include "table.hpp"
#include "array.hpp"
#include "header_start.hpp"
+#include "print_to_stream.hpp"
+#include "table.hpp"
+#include "yaml_formatter.hpp"
-TOML_NAMESPACE_START
-{
- TOML_EXTERNAL_LINKAGE
- void yaml_formatter::print_yaml_string(const value<std::string>& str)
- {
- if (str->empty())
- {
- base::print(str);
- return;
- }
-
- bool contains_newline = false;
- for (auto c = str->c_str(), e = str->c_str() + str->length(); c < e && !contains_newline; c++)
- contains_newline = *c == '\n';
-
- if (contains_newline)
- {
- print_unformatted("|-"sv);
-
- increase_indent();
-
- auto line_end = str->c_str() - 1u;
- const auto end = str->c_str() + str->length();
- while (line_end != end)
- {
- auto line_start = line_end + 1u;
- line_end = line_start;
- for (; line_end != end && *line_end != '\n'; line_end++)
- ;
-
- if TOML_LIKELY(line_start != line_end || line_end != end)
- {
- print_newline();
- print_indent();
- print_unformatted(std::string_view{ line_start, static_cast<size_t>(line_end - line_start) });
- }
- }
-
- decrease_indent();
- }
- else
- print_string(*str, false, true);
- }
-
- TOML_EXTERNAL_LINKAGE
- void yaml_formatter::print(const toml::table& tbl, bool parent_is_array)
- {
- if (tbl.empty())
- {
- print_unformatted("{}"sv);
- return;
- }
-
- increase_indent();
-
- for (auto&& [k, v] : tbl)
- {
- if (!parent_is_array)
- {
- print_newline();
- print_indent();
- }
- parent_is_array = false;
-
- print_string(k.str(), false, true);
- if (terse_kvps())
- print_unformatted(":"sv);
- else
- print_unformatted(": "sv);
-
- const auto type = v.type();
- TOML_ASSUME(type != node_type::none);
- switch (type)
- {
- case node_type::table: print(*reinterpret_cast<const table*>(&v)); break;
- case node_type::array: print(*reinterpret_cast<const array*>(&v)); break;
- case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v)); break;
- default: print_value(v, type);
- }
- }
-
- decrease_indent();
- }
-
- TOML_EXTERNAL_LINKAGE
- void yaml_formatter::print(const toml::array& arr, bool parent_is_array)
- {
- if (arr.empty())
- {
- print_unformatted("[]"sv);
- return;
- }
-
- increase_indent();
-
- for (auto&& v : arr)
- {
- if (!parent_is_array)
- {
- print_newline();
- print_indent();
- }
- parent_is_array = false;
-
- print_unformatted("- "sv);
-
- const auto type = v.type();
- TOML_ASSUME(type != node_type::none);
- switch (type)
- {
- case node_type::table: print(*reinterpret_cast<const table*>(&v), true); break;
- case node_type::array: print(*reinterpret_cast<const array*>(&v), true); break;
- case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v)); break;
- default: print_value(v, type);
- }
- }
-
- decrease_indent();
- }
-
- TOML_EXTERNAL_LINKAGE
- void yaml_formatter::print()
- {
- if (dump_failed_parse_result())
- return;
-
- switch (auto source_type = source().type())
- {
- case node_type::table:
- decrease_indent(); // so root kvps and tables have the same indent
- print(*reinterpret_cast<const table*>(&source()));
- break;
-
- case node_type::array: print(*reinterpret_cast<const array*>(&source())); break;
-
- case node_type::string: print_yaml_string(*reinterpret_cast<const value<std::string>*>(&source())); break;
-
- default: print_value(source(), source_type);
- }
- }
+TOML_NAMESPACE_START {
+ TOML_EXTERNAL_LINKAGE
+ void yaml_formatter::print_yaml_string(const value<std::string>& str) {
+ if (str->empty()) {
+ base::print(str);
+ return;
+ }
+
+ bool contains_newline = false;
+ for (auto c = str->c_str(), e = str->c_str() + str->length(); c < e && !contains_newline; c++)
+ contains_newline = *c == '\n';
+
+ if (contains_newline) {
+ print_unformatted("|-"sv);
+
+ increase_indent();
+
+ auto line_end = str->c_str() - 1u;
+ const auto end = str->c_str() + str->length();
+ while (line_end != end) {
+ auto line_start = line_end + 1u;
+ line_end = line_start;
+ for (; line_end != end && *line_end != '\n'; line_end++);
+
+ if TOML_LIKELY (line_start != line_end || line_end != end) {
+ print_newline();
+ print_indent();
+ print_unformatted(
+ std::string_view{line_start, static_cast<size_t>(line_end - line_start)});
+ }
+ }
+
+ decrease_indent();
+ } else
+ print_string(*str, false, true);
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void yaml_formatter::print(const toml::table& tbl, bool parent_is_array) {
+ if (tbl.empty()) {
+ print_unformatted("{}"sv);
+ return;
+ }
+
+ increase_indent();
+
+ for (auto&& [k, v] : tbl) {
+ if (!parent_is_array) {
+ print_newline();
+ print_indent();
+ }
+ parent_is_array = false;
+
+ print_string(k.str(), false, true);
+ if (terse_kvps())
+ print_unformatted(":"sv);
+ else
+ print_unformatted(": "sv);
+
+ const auto type = v.type();
+ TOML_ASSUME(type != node_type::none);
+ switch (type) {
+ case node_type::table:
+ print(*reinterpret_cast<const table*>(&v));
+ break;
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&v));
+ break;
+ case node_type::string:
+ print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v));
+ break;
+ default:
+ print_value(v, type);
+ }
+ }
+
+ decrease_indent();
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void yaml_formatter::print(const toml::array& arr, bool parent_is_array) {
+ if (arr.empty()) {
+ print_unformatted("[]"sv);
+ return;
+ }
+
+ increase_indent();
+
+ for (auto&& v : arr) {
+ if (!parent_is_array) {
+ print_newline();
+ print_indent();
+ }
+ parent_is_array = false;
+
+ print_unformatted("- "sv);
+
+ const auto type = v.type();
+ TOML_ASSUME(type != node_type::none);
+ switch (type) {
+ case node_type::table:
+ print(*reinterpret_cast<const table*>(&v), true);
+ break;
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&v), true);
+ break;
+ case node_type::string:
+ print_yaml_string(*reinterpret_cast<const value<std::string>*>(&v));
+ break;
+ default:
+ print_value(v, type);
+ }
+ }
+
+ decrease_indent();
+ }
+
+ TOML_EXTERNAL_LINKAGE
+ void yaml_formatter::print() {
+ if (dump_failed_parse_result()) return;
+
+ switch (auto source_type = source().type()) {
+ case node_type::table:
+ decrease_indent(); // so root kvps and tables have the same indent
+ print(*reinterpret_cast<const table*>(&source()));
+ break;
+
+ case node_type::array:
+ print(*reinterpret_cast<const array*>(&source()));
+ break;
+
+ case node_type::string:
+ print_yaml_string(*reinterpret_cast<const value<std::string>*>(&source()));
+ break;
+
+ default:
+ print_value(source(), source_type);
+ }
+ }
}
TOML_NAMESPACE_END;
#include "header_end.hpp"
-#endif // TOML_ENABLE_FORMATTERS
+#endif // TOML_ENABLE_FORMATTERS