add toml configure file | and setup-routine

This commit is contained in:
lucaspalomodevelop 2023-06-28 12:11:51 +02:00
parent d150ee9b7c
commit 3b2f277b18
56 changed files with 21570 additions and 22 deletions

1727
lib/toml++/impl/array.h Normal file

File diff suppressed because it is too large Load Diff

382
lib/toml++/impl/array.inl Normal file
View File

@ -0,0 +1,382 @@
//# 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.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "array.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
array::array() noexcept
{
#if TOML_LIFETIME_HOOKS
TOML_ARRAY_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
array::~array() noexcept
{
#if TOML_LIFETIME_HOOKS
TOML_ARRAY_DESTROYED;
#endif
}
TOML_EXTERNAL_LINKAGE
array::array(const impl::array_init_elem* b, const impl::array_init_elem* e)
{
#if TOML_LIFETIME_HOOKS
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));
#if TOML_LIFETIME_HOOKS
TOML_ARRAY_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
array::array(array && other) noexcept //
: node(std::move(other)),
elems_(std::move(other.elems_))
{
#if TOML_LIFETIME_HOOKS
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)
{
#if TOML_COMPILER_HAS_EXCEPTIONS
return *elems_.at(index);
#else
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_NAMESPACE_END;
#include "header_end.h"

97
lib/toml++/impl/at_path.h Normal file
View File

@ -0,0 +1,97 @@
//# 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 "forward_declarations.h"
/// \cond
TOML_IMPL_NAMESPACE_START
{
template <typename T>
using parse_path_callback = bool(TOML_CALLCONV*)(void*, T);
TOML_NODISCARD
bool TOML_CALLCONV parse_path(std::string_view,
void*,
parse_path_callback<std::string_view>,
parse_path_callback<size_t>);
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
TOML_NAMESPACE_START
{
/// \brief Returns a view of the node matching a fully-qualified "TOML path".
///
/// \detail \cpp
/// auto config = toml::parse(R"(
///
/// [foo]
/// bar = [ 0, 1, 2, [ 3 ], { kek = 4 } ]
///
/// )"sv);
///
/// std::cout << toml::at_path(config, "foo.bar[2]") << "\n";
/// std::cout << toml::at_path(config, "foo.bar[3][0]") << "\n";
/// std::cout << toml::at_path(config, "foo.bar[4].kek") << "\n";
/// \ecpp
///
/// \out
/// 2
/// 3
/// 4
/// \eout
///
///
/// \note Keys in paths are interpreted literally, so whitespace (or lack thereof) matters:
/// \cpp
/// toml::at_path(config, "foo.bar") // same as config["foo"]["bar"]
/// toml::at_path(config, "foo. bar") // same as config["foo"][" bar"]
/// toml::at_path(config, "foo..bar") // same as config["foo"][""]["bar"]
/// toml::at_path(config, ".foo.bar") // same as config[""]["foo"]["bar"]
/// \ecpp
/// <br>
/// Additionally, TOML allows '.' (period) characters to appear in keys if they are quoted strings.
/// This function makes no allowance for this, instead treating all period characters as sub-table delimiters.
/// If you have periods in your table keys, first consider:
/// 1. Not doing that
/// 2. Using node_view::operator[] instead.
///
/// \param root The root node from which the path will be traversed.
/// \param path The "TOML path" to traverse.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
node_view<node> TOML_CALLCONV at_path(node & root, std::string_view path) noexcept;
/// \brief Returns a const view of the node matching a fully-qualified "TOML path".
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
node_view<const node> TOML_CALLCONV at_path(const node& root, std::string_view path) noexcept;
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Returns a view of the node matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
node_view<node> TOML_CALLCONV at_path(node & root, std::wstring_view path);
/// \brief Returns a const view of the node matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::at_path(node&, std::string_view)
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
node_view<const node> TOML_CALLCONV at_path(const node& root, std::wstring_view path);
#endif
}
TOML_NAMESPACE_END;

290
lib/toml++/impl/at_path.inl Normal file
View File

@ -0,0 +1,290 @@
//# 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.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "at_path.h"
#include "array.h"
#include "table.h"
TOML_DISABLE_WARNINGS;
#if TOML_INT_CHARCONV
#include <charconv>
#else
#include <sstream>
#endif
TOML_ENABLE_WARNINGS;
#include "header_start.h"
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;
#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;
#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;
}
}
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() };
}
#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_NAMESPACE_END;
#include "header_end.h"

468
lib/toml++/impl/date_time.h Normal file
View File

@ -0,0 +1,468 @@
//# 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 "forward_declarations.h"
#include "print_to_stream.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief A local date.
struct TOML_TRIVIAL_ABI date
{
/// \brief The year component.
uint16_t year;
/// \brief The month component, from 1 - 12.
uint8_t month;
/// \brief The day component, from 1 - 31.
uint8_t day;
/// \brief Default constructor. Does not initialize the members.
TOML_NODISCARD_CTOR
date() noexcept = default;
/// \brief Constructs a date from individual date component values.
TOML_CONSTRAINED_TEMPLATE((impl::all_integral<Y, M, D>), typename Y, typename M, typename D)
TOML_NODISCARD_CTOR
constexpr date(Y y, M m, D d) noexcept //
: year{ static_cast<uint16_t>(y) },
month{ static_cast<uint8_t>(m) },
day{ static_cast<uint8_t>(d) }
{}
/// \brief Equality operator.
TOML_PURE_GETTER
friend constexpr bool operator==(const date& lhs, const date& rhs) noexcept
{
return lhs.year == rhs.year //
&& lhs.month == rhs.month //
&& lhs.day == rhs.day;
}
/// \brief Inequality operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator!=(const date& lhs, const date& rhs) noexcept
{
return !(lhs == rhs);
}
private:
/// \cond
TOML_PURE_GETTER
static constexpr uint32_t pack(const date& d) noexcept
{
return (static_cast<uint32_t>(d.year) << 16) | (static_cast<uint32_t>(d.month) << 8)
| static_cast<uint32_t>(d.day);
}
/// \endcond
public:
/// \brief Less-than operator.
TOML_PURE_GETTER
friend constexpr bool operator<(const date& lhs, const date& rhs) noexcept
{
return pack(lhs) < pack(rhs);
}
/// \brief Less-than-or-equal-to operator.
TOML_PURE_GETTER
friend constexpr bool operator<=(const date& lhs, const date& rhs) noexcept
{
return pack(lhs) <= pack(rhs);
}
/// \brief Greater-than operator.
TOML_PURE_GETTER
friend constexpr bool operator>(const date& lhs, const date& rhs) noexcept
{
return pack(lhs) > pack(rhs);
}
/// \brief Greater-than-or-equal-to operator.
TOML_PURE_GETTER
friend constexpr bool operator>=(const date& lhs, const date& rhs) noexcept
{
return pack(lhs) >= pack(rhs);
}
/// \brief Prints a date out to a stream as `YYYY-MM-DD` (per RFC 3339).
///
/// \detail \cpp
/// std::cout << toml::date{ 1987, 3, 16 } << "\n";
/// \ecpp
///
/// \out
/// 1987-03-16
/// \eout
friend std::ostream& operator<<(std::ostream& lhs, const date& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
/// \brief A local time-of-day.
struct TOML_TRIVIAL_ABI time
{
/// \brief The hour component, from 0 - 23.
uint8_t hour;
/// \brief The minute component, from 0 - 59.
uint8_t minute;
/// \brief The second component, from 0 - 59.
uint8_t second;
/// \brief The fractional nanoseconds component, from 0 - 999999999.
uint32_t nanosecond;
/// \brief Default constructor. Does not initialize the members.
TOML_NODISCARD_CTOR
time() noexcept = default;
/// \brief Constructs a time from individual time component values.
TOML_CONSTRAINED_TEMPLATE((impl::all_integral<H, M, S, NS>),
typename H,
typename M,
typename S = uint8_t,
typename NS = uint32_t)
TOML_NODISCARD_CTOR
constexpr time(H h, M m, S s = S{}, NS ns = NS{}) noexcept //
: hour{ static_cast<uint8_t>(h) },
minute{ static_cast<uint8_t>(m) },
second{ static_cast<uint8_t>(s) },
nanosecond{ static_cast<uint32_t>(ns) }
{}
/// \brief Equality operator.
TOML_PURE_GETTER
friend constexpr bool operator==(const time& lhs, const time& rhs) noexcept
{
return lhs.hour == rhs.hour //
&& lhs.minute == rhs.minute //
&& lhs.second == rhs.second //
&& lhs.nanosecond == rhs.nanosecond;
}
/// \brief Inequality operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator!=(const time& lhs, const time& rhs) noexcept
{
return !(lhs == rhs);
}
private:
/// \cond
TOML_PURE_GETTER
static constexpr uint64_t pack(const time& t) noexcept
{
return static_cast<uint64_t>(t.hour) << 48 | static_cast<uint64_t>(t.minute) << 40
| static_cast<uint64_t>(t.second) << 32 | static_cast<uint64_t>(t.nanosecond);
}
/// \endcond
public:
/// \brief Less-than operator.
TOML_PURE_GETTER
friend constexpr bool operator<(const time& lhs, const time& rhs) noexcept
{
return pack(lhs) < pack(rhs);
}
/// \brief Less-than-or-equal-to operator.
TOML_PURE_GETTER
friend constexpr bool operator<=(const time& lhs, const time& rhs) noexcept
{
return pack(lhs) <= pack(rhs);
}
/// \brief Greater-than operator.
TOML_PURE_GETTER
friend constexpr bool operator>(const time& lhs, const time& rhs) noexcept
{
return pack(lhs) > pack(rhs);
}
/// \brief Greater-than-or-equal-to operator.
TOML_PURE_GETTER
friend constexpr bool operator>=(const time& lhs, const time& rhs) noexcept
{
return pack(lhs) >= pack(rhs);
}
/// \brief Prints a time out to a stream as `HH:MM:SS.FFFFFF` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::time{ 10, 20, 34 } << "\n";
/// std::cout << toml::time{ 10, 20, 34, 500000000 } << "\n";
/// \ecpp
///
/// \out
/// 10:20:34
/// 10:20:34.5
/// \eout
friend std::ostream& operator<<(std::ostream& lhs, const time& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
/// \brief A timezone offset.
struct TOML_TRIVIAL_ABI time_offset
{
/// \brief Offset from UTC+0, in minutes.
int16_t minutes;
/// \brief Default constructor. Does not initialize the members.
TOML_NODISCARD_CTOR
time_offset() noexcept = default;
/// \brief Constructs a timezone offset from individual hour and minute totals.
///
/// \detail \cpp
/// std::cout << toml::time_offset{ 2, 30 } << "\n";
/// std::cout << toml::time_offset{ -2, 30 } << "\n";
/// std::cout << toml::time_offset{ -2, -30 } << "\n";
/// std::cout << toml::time_offset{ 0, 0 } << "\n";
/// \ecpp
///
/// \out
/// +02:30
/// -01:30
/// -02:30
/// Z
/// \eout
///
/// \tparam H An integral type.
/// \tparam M An integral type.
///
/// \param h The total hours.
/// \param m The total minutes.
TOML_CONSTRAINED_TEMPLATE((impl::all_integral<H, M>), typename H, typename M)
TOML_NODISCARD_CTOR
constexpr time_offset(H h, M m) noexcept //
: minutes{ static_cast<int16_t>(static_cast<impl::common_signed_type<H, M>>(h)
* impl::common_signed_type<H, M>{ 60 }
+ static_cast<impl::common_signed_type<H, M>>(m)) }
{}
/// \brief Equality operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator==(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes == rhs.minutes;
}
/// \brief Inequality operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator!=(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes != rhs.minutes;
}
/// \brief Less-than operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator<(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes < rhs.minutes;
}
/// \brief Less-than-or-equal-to operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator<=(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes <= rhs.minutes;
}
/// \brief Greater-than operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator>(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes > rhs.minutes;
}
/// \brief Greater-than-or-equal-to operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator>=(time_offset lhs, time_offset rhs) noexcept
{
return lhs.minutes >= rhs.minutes;
}
/// \brief Prints a time_offset out to a stream as `+-HH:MM or Z` (per RFC 3339).
/// \detail \cpp
/// std::cout << toml::time_offset{ 2, 30 } << "\n";
/// std::cout << toml::time_offset{ 2, -30 } << "\n";
/// std::cout << toml::time_offset{} << "\n";
/// std::cout << toml::time_offset{ -2, 30 } << "\n";
/// std::cout << toml::time_offset{ -2, -30 } << "\n";
/// \ecpp
///
/// \out
/// +02:30
/// +01:30
/// Z
/// -01:30
/// -02:30
/// \eout
friend std::ostream& operator<<(std::ostream& lhs, const time_offset& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt);
/// \brief A date-time.
struct date_time
{
/// \brief The date component.
toml::date date;
/// \brief The time component.
toml::time time;
/// \brief The timezone offset component.
///
/// \remarks The date_time is said to be 'local' if the offset is empty.
optional<toml::time_offset> offset;
/// \brief Default constructor. Does not initialize the members.
TOML_NODISCARD_CTOR
date_time() noexcept = default;
/// \brief Constructs a local date-time.
///
/// \param d The date component.
/// \param t The time component.
TOML_NODISCARD_CTOR
constexpr date_time(const toml::date& d, const toml::time& t) noexcept //
: date{ d },
time{ t },
offset{} // TINAE - icc bugfix
{}
/// \brief Constructs a local date-time.
///
/// \param d The date component.
TOML_NODISCARD_CTOR
explicit constexpr date_time(const toml::date& d) noexcept //
: date{ d },
time{},
offset{} // TINAE - icc bugfix
{}
/// \brief Constructs a local date-time.
///
/// \param t The time component.
TOML_NODISCARD_CTOR
explicit constexpr date_time(const toml::time& t) noexcept //
: date{},
time{ t },
offset{} // TINAE - icc bugfix
{}
/// \brief Constructs an offset date-time.
///
/// \param d The date component.
/// \param t The time component.
/// \param off The timezone offset.
TOML_NODISCARD_CTOR
constexpr date_time(const toml::date& d, const toml::time& t, const toml::time_offset& off) noexcept
: date{ d },
time{ t },
offset{ off }
{}
/// \brief Returns true if this date_time does not contain timezone offset information.
TOML_PURE_INLINE_GETTER
constexpr bool is_local() const noexcept
{
return !offset.has_value();
}
/// \brief Equality operator.
TOML_PURE_GETTER
friend constexpr bool operator==(const date_time& lhs, const date_time& rhs) noexcept
{
return lhs.date == rhs.date //
&& lhs.time == rhs.time //
&& lhs.offset == rhs.offset;
}
/// \brief Inequality operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator!=(const date_time& lhs, const date_time& rhs) noexcept
{
return !(lhs == rhs);
}
/// \brief Less-than operator.
TOML_PURE_GETTER
friend constexpr bool operator<(const date_time& lhs, const date_time& rhs) noexcept
{
if (lhs.date != rhs.date)
return lhs.date < rhs.date;
if (lhs.time != rhs.time)
return lhs.time < rhs.time;
return lhs.offset < rhs.offset;
}
/// \brief Less-than-or-equal-to operator.
TOML_PURE_GETTER
friend constexpr bool operator<=(const date_time& lhs, const date_time& rhs) noexcept
{
if (lhs.date != rhs.date)
return lhs.date < rhs.date;
if (lhs.time != rhs.time)
return lhs.time < rhs.time;
return lhs.offset <= rhs.offset;
}
/// \brief Greater-than operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator>(const date_time& lhs, const date_time& rhs) noexcept
{
return !(lhs <= rhs);
}
/// \brief Greater-than-or-equal-to operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator>=(const date_time& lhs, const date_time& rhs) noexcept
{
return !(lhs < rhs);
}
/// \brief Prints a date_time out to a stream in RFC 3339 format.
/// \detail \cpp
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 } } << "\n";
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, { -2, -30 } } << "\n";
/// std::cout << toml::date_time{ { 1987, 3, 16 }, { 10, 20, 34 }, {} } << "\n";
/// \ecpp
///
/// \out
/// 1987-03-16T10:20:34
/// 1987-03-16T10:20:34-02:30
/// 1987-03-16T10:20:34Z
/// \eout
friend std::ostream& operator<<(std::ostream& lhs, const date_time& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
TOML_ABI_NAMESPACE_END; // TOML_HAS_CUSTOM_OPTIONAL_TYPE
}
TOML_NAMESPACE_END;
#include "header_end.h"

191
lib/toml++/impl/formatter.h Normal file
View File

@ -0,0 +1,191 @@
//# 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.h"
#if TOML_ENABLE_FORMATTERS
#include "forward_declarations.h"
#include "print_to_stream.h"
#include "header_start.h"
/// \cond
TOML_IMPL_NAMESPACE_START
{
struct formatter_constants
{
format_flags mandatory_flags;
format_flags ignored_flags;
std::string_view float_pos_inf;
std::string_view float_neg_inf;
std::string_view float_nan;
std::string_view bool_true;
std::string_view bool_false;
};
struct formatter_config
{
format_flags flags;
std::string_view indent;
};
class TOML_EXPORTED_CLASS formatter
{
private:
const node* source_;
#if TOML_ENABLE_PARSER && !TOML_EXCEPTIONS
const parse_result* result_;
#endif
const formatter_constants* constants_;
formatter_config config_;
size_t indent_columns_;
format_flags int_format_mask_;
std::ostream* stream_; //
int indent_; // these are set in attach()
bool naked_newline_; //
protected:
TOML_PURE_INLINE_GETTER
const node& source() const noexcept
{
return *source_;
}
TOML_PURE_INLINE_GETTER
std::ostream& stream() const noexcept
{
return *stream_;
}
TOML_PURE_INLINE_GETTER
int indent() const noexcept
{
return indent_;
}
void indent(int level) noexcept
{
indent_ = level;
}
void increase_indent() noexcept
{
indent_++;
}
void decrease_indent() noexcept
{
indent_--;
}
TOML_PURE_INLINE_GETTER
size_t indent_columns() const noexcept
{
return indent_columns_;
}
TOML_PURE_INLINE_GETTER
bool indent_array_elements() const noexcept
{
return !!(config_.flags & format_flags::indent_array_elements);
}
TOML_PURE_INLINE_GETTER
bool indent_sub_tables() const noexcept
{
return !!(config_.flags & format_flags::indent_sub_tables);
}
TOML_PURE_INLINE_GETTER
bool literal_strings_allowed() const noexcept
{
return !!(config_.flags & format_flags::allow_literal_strings);
}
TOML_PURE_INLINE_GETTER
bool multi_line_strings_allowed() const noexcept
{
return !!(config_.flags & format_flags::allow_multi_line_strings);
}
TOML_PURE_INLINE_GETTER
bool real_tabs_in_strings_allowed() const noexcept
{
return !!(config_.flags & format_flags::allow_real_tabs_in_strings);
}
TOML_PURE_INLINE_GETTER
bool unicode_strings_allowed() const noexcept
{
return !!(config_.flags & format_flags::allow_unicode_strings);
}
TOML_PURE_INLINE_GETTER
bool terse_kvps() const noexcept
{
return !!(config_.flags & format_flags::terse_key_value_pairs);
}
TOML_EXPORTED_MEMBER_FUNCTION
void attach(std::ostream& stream) noexcept;
TOML_EXPORTED_MEMBER_FUNCTION
void detach() noexcept;
TOML_EXPORTED_MEMBER_FUNCTION
void print_newline(bool force = false);
TOML_EXPORTED_MEMBER_FUNCTION
void print_indent();
TOML_EXPORTED_MEMBER_FUNCTION
void print_unformatted(char);
TOML_EXPORTED_MEMBER_FUNCTION
void print_unformatted(std::string_view);
TOML_EXPORTED_MEMBER_FUNCTION
void print_string(std::string_view str, bool allow_multi_line = true, bool allow_bare = false);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const value<std::string>&);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const value<int64_t>&);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const value<double>&);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const value<bool>&);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const value<date>&);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const value<time>&);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const value<date_time>&);
TOML_EXPORTED_MEMBER_FUNCTION
void print_value(const node&, node_type);
TOML_NODISCARD
TOML_EXPORTED_MEMBER_FUNCTION
bool dump_failed_parse_result();
TOML_NODISCARD_CTOR
TOML_EXPORTED_MEMBER_FUNCTION
formatter(const node*, const parse_result*, const formatter_constants&, const formatter_config&) noexcept;
};
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -0,0 +1,513 @@
//# 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.h"
//# {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_FORMATTERS
#include "formatter.h"
#include "print_to_stream.h"
#include "value.h"
#include "table.h"
#include "array.h"
#include "unicode.h"
#include "parse_result.h"
#include "header_start.h"
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 },
#else
: 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)
{
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();
}
// 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;
}
// determine if this should be a multi-line string (triple-quotes)
const auto multi_line = 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_in_strings_allowed()) //
&& (!(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);
const auto real_tabs_allowed = real_tabs_in_strings_allowed();
// 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;
}
#else
TOML_EXTERNAL_LINKAGE
TOML_ATTR(const)
bool formatter::dump_failed_parse_result()
{
return false;
}
#endif
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
//# {{
#ifdef __INTELLISENSE__
#include "preprocessor.h"
#endif
//# }}
#ifdef _MSC_VER
#pragma pop_macro("min")
#pragma pop_macro("max")
#ifndef __clang__
#pragma inline_recursion(off)
#endif
#endif
TOML_POP_WARNINGS;

View File

@ -0,0 +1,15 @@
//# {{
#ifdef __INTELLISENSE__
#include "preprocessor.h"
#endif
//# }}
TOML_PUSH_WARNINGS;
#ifdef _MSC_VER
#ifndef __clang__
#pragma inline_recursion(on)
#endif
#pragma push_macro("min")
#pragma push_macro("max")
#undef min
#undef max
#endif

View File

@ -0,0 +1,142 @@
//# 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.h"
#if TOML_ENABLE_FORMATTERS
#include "formatter.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted JSON.
///
/// \availability This class is only available when #TOML_ENABLE_FORMATTERS is enabled.
///
/// \detail \cpp
/// auto some_toml = toml::parse(R"(
/// [fruit]
/// apple.color = "red"
/// apple.taste.sweet = true
///
/// [fruit.apple.texture]
/// smooth = true
/// )"sv);
/// std::cout << toml::json_formatter{ some_toml } << "\n";
/// \ecpp
///
/// \out
/// {
/// "fruit" : {
/// "apple" : {
/// "color" : "red",
/// "taste" : {
/// "sweet" : true
/// },
/// "texture" : {
/// "smooth" : true
/// }
/// }
/// }
/// }
/// \eout
class TOML_EXPORTED_CLASS json_formatter : impl::formatter
{
private:
/// \cond
using base = impl::formatter;
TOML_EXPORTED_MEMBER_FUNCTION
void print(const toml::table&);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const toml::array&);
TOML_EXPORTED_MEMBER_FUNCTION
void print();
static constexpr impl::formatter_constants constants = {
format_flags::quote_dates_and_times, // mandatory
format_flags::allow_literal_strings | format_flags::allow_multi_line_strings, // ignored
"Infinity"sv,
"-Infinity"sv,
"NaN"sv,
"true"sv,
"false"sv
};
/// \endcond
public:
/// \brief The default flags for a json_formatter.
static constexpr format_flags default_flags = constants.mandatory_flags //
| format_flags::quote_infinities_and_nans //
| format_flags::allow_unicode_strings //
| format_flags::indentation;
/// \brief Constructs a JSON formatter and binds it to a TOML object.
///
/// \param source The source TOML object.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit json_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ &source, nullptr, constants, { flags, " "sv } }
{}
#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
/// \brief Constructs a JSON formatter and binds it to a toml::parse_result.
///
/// \availability This constructor is only available when exceptions are disabled.
///
/// \attention Formatting a failed parse result will simply dump the error message out as-is.
/// This will not be valid JSON, but at least gives you something to log or show up in diagnostics:
/// \cpp
/// std::cout << toml::json_formatter{ toml::parse("a = 'b'"sv) } // ok
/// << "\n\n"
/// << toml::json_formatter{ toml::parse("a = "sv) } // malformed
/// << "\n";
/// \ecpp
/// \out
/// {
/// "a" : "b"
/// }
///
/// Error while parsing key-value pair: encountered end-of-file
/// (error occurred at line 1, column 5)
/// \eout
/// Use the library with exceptions if you want to avoid this scenario.
///
/// \param result The parse result.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit json_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ nullptr, &result, constants, { flags, " "sv } }
{}
#endif
/// \brief Prints the bound TOML object out to the stream as JSON.
friend std::ostream& operator<<(std::ostream& lhs, json_formatter& rhs)
{
rhs.attach(lhs);
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as JSON (rvalue overload).
friend std::ostream& operator<<(std::ostream& lhs, json_formatter&& rhs)
{
return lhs << rhs; // as lvalue
}
};
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -0,0 +1,121 @@
//# 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.h"
//# {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_FORMATTERS
#include "json_formatter.h"
#include "print_to_stream.h"
#include "table.h"
#include "array.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
void json_formatter::print(const toml::table& tbl)
{
if (tbl.empty())
{
print_unformatted("{}"sv);
return;
}
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();
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();
print_unformatted('}');
}
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();
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;
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.h"
#endif // TOML_ENABLE_FORMATTERS

335
lib/toml++/impl/key.h Normal file
View File

@ -0,0 +1,335 @@
//# 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 "source_region.h"
#include "std_utility.h"
#include "print_to_stream.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief A key parsed from a TOML document.
///
/// \detail These are used as the internal keys for a toml::table: \cpp
/// const toml::table tbl = R"(
/// a = 1
/// b = 2
/// c = 3
/// )"_toml;
///
/// for (auto&& [k, v] : tbl)
/// std::cout << "key '"sv << k << "' defined at "sv << k.source() << "\n";
/// \ecpp
/// \out
/// key 'a' defined at line 2, column 5
/// key 'b' defined at line 3, column 7
/// key 'c' defined at line 4, column 9
/// \eout
class key
{
private:
std::string key_;
source_region source_;
public:
/// \brief Default constructor.
TOML_NODISCARD_CTOR
key() noexcept = default;
/// \brief Constructs a key from a string view and source region.
TOML_NODISCARD_CTOR
explicit key(std::string_view k, source_region&& src = {}) //
: key_{ k },
source_{ std::move(src) }
{}
/// \brief Constructs a key from a string view and source region.
TOML_NODISCARD_CTOR
explicit key(std::string_view k, const source_region& src) //
: key_{ k },
source_{ src }
{}
/// \brief Constructs a key from a string and source region.
TOML_NODISCARD_CTOR
explicit key(std::string&& k, source_region&& src = {}) noexcept //
: key_{ std::move(k) },
source_{ std::move(src) }
{}
/// \brief Constructs a key from a string and source region.
TOML_NODISCARD_CTOR
explicit key(std::string&& k, const source_region& src) noexcept //
: key_{ std::move(k) },
source_{ src }
{}
/// \brief Constructs a key from a c-string and source region.
TOML_NODISCARD_CTOR
explicit key(const char* k, source_region&& src = {}) //
: key_{ k },
source_{ std::move(src) }
{}
/// \brief Constructs a key from a c-string view and source region.
TOML_NODISCARD_CTOR
explicit key(const char* k, const source_region& src) //
: key_{ k },
source_{ src }
{}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Constructs a key from a wide string view and source region.
///
/// \availability This constructor is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD_CTOR
explicit key(std::wstring_view k, source_region&& src = {}) //
: key_{ impl::narrow(k) },
source_{ std::move(src) }
{}
/// \brief Constructs a key from a wide string and source region.
///
/// \availability This constructor is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD_CTOR
explicit key(std::wstring_view k, const source_region& src) //
: key_{ impl::narrow(k) },
source_{ src }
{}
#endif
/// \name String operations
/// @{
/// \brief Returns a view of the key's underlying string.
TOML_PURE_INLINE_GETTER
std::string_view str() const noexcept
{
return std::string_view{ key_ };
}
/// \brief Returns a view of the key's underlying string.
TOML_PURE_INLINE_GETTER
/*implicit*/ operator std::string_view() const noexcept
{
return str();
}
/// \brief Returns true if the key's underlying string is empty.
TOML_PURE_INLINE_GETTER
bool empty() const noexcept
{
return key_.empty();
}
/// \brief Returns a pointer to the start of the key's underlying string.
TOML_PURE_INLINE_GETTER
const char* data() const noexcept
{
return key_.data();
}
/// \brief Returns the length of the key's underlying string.
TOML_PURE_INLINE_GETTER
size_t length() const noexcept
{
return key_.length();
}
/// @}
/// \name Metadata
/// @{
/// \brief Returns the source region responsible for specifying this key during parsing.
TOML_PURE_INLINE_GETTER
const source_region& source() const noexcept
{
return source_;
}
/// @}
/// \name Equality and Comparison
/// \attention These operations only compare the underlying strings; source regions are ignored for the purposes of all comparison!
/// @{
/// \brief Returns true if `lhs.str() == rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator==(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ == rhs.key_;
}
/// \brief Returns true if `lhs.str() != rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator!=(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ != rhs.key_;
}
/// \brief Returns true if `lhs.str() < rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator<(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ < rhs.key_;
}
/// \brief Returns true if `lhs.str() <= rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator<=(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ <= rhs.key_;
}
/// \brief Returns true if `lhs.str() > rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator>(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ > rhs.key_;
}
/// \brief Returns true if `lhs.str() >= rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator>=(const key& lhs, const key& rhs) noexcept
{
return lhs.key_ >= rhs.key_;
}
/// \brief Returns true if `lhs.str() == rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator==(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ == rhs;
}
/// \brief Returns true if `lhs.str() != rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator!=(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ != rhs;
}
/// \brief Returns true if `lhs.str() < rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator<(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ < rhs;
}
/// \brief Returns true if `lhs.str() <= rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator<=(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ <= rhs;
}
/// \brief Returns true if `lhs.str() > rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator>(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ > rhs;
}
/// \brief Returns true if `lhs.str() >= rhs`.
TOML_PURE_INLINE_GETTER
friend bool operator>=(const key& lhs, std::string_view rhs) noexcept
{
return lhs.key_ >= rhs;
}
/// \brief Returns true if `lhs == rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator==(std::string_view lhs, const key& rhs) noexcept
{
return lhs == rhs.key_;
}
/// \brief Returns true if `lhs != rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator!=(std::string_view lhs, const key& rhs) noexcept
{
return lhs != rhs.key_;
}
/// \brief Returns true if `lhs < rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator<(std::string_view lhs, const key& rhs) noexcept
{
return lhs < rhs.key_;
}
/// \brief Returns true if `lhs <= rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator<=(std::string_view lhs, const key& rhs) noexcept
{
return lhs <= rhs.key_;
}
/// \brief Returns true if `lhs > rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator>(std::string_view lhs, const key& rhs) noexcept
{
return lhs > rhs.key_;
}
/// \brief Returns true if `lhs >= rhs.str()`.
TOML_PURE_INLINE_GETTER
friend bool operator>=(std::string_view lhs, const key& rhs) noexcept
{
return lhs >= rhs.key_;
}
/// @}
/// \name Iteration
/// @{
/// \brief A const iterator for iterating over the characters in the key.
using const_iterator = const char*;
/// \brief A const iterator for iterating over the characters in the key.
using iterator = const_iterator;
/// \brief Returns an iterator to the first character in the key's backing string.
TOML_PURE_INLINE_GETTER
const_iterator begin() const noexcept
{
return key_.data();
}
/// \brief Returns an iterator to one-past-the-last character in the key's backing string.
TOML_PURE_INLINE_GETTER
const_iterator end() const noexcept
{
return key_.data() + key_.length();
}
/// @}
/// \brief Prints the key's underlying string out to the stream.
friend std::ostream& operator<<(std::ostream& lhs, const key& rhs)
{
impl::print_to_stream(lhs, rhs.key_);
return lhs;
}
};
/// \brief Metafunction for determining if a type is, or is a reference to, a toml::key.
template <typename T>
inline constexpr bool is_key = std::is_same_v<impl::remove_cvref<T>, toml::key>;
/// \brief Metafunction for determining if a type is, or is a reference to, a toml::key,
/// or is implicitly or explicitly convertible to one.
template <typename T>
inline constexpr bool is_key_or_convertible = is_key<T> //
|| impl::is_constructible_or_convertible<toml::key, T>;
}
TOML_NAMESPACE_END;
#include "header_end.h"

182
lib/toml++/impl/make_node.h Normal file
View File

@ -0,0 +1,182 @@
//# 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 "forward_declarations.h"
#include "header_start.h"
/// \cond
TOML_IMPL_NAMESPACE_START
{
template <typename T>
TOML_NODISCARD
TOML_ATTR(returns_nonnull)
auto* make_node_impl_specialized(T && val, [[maybe_unused]] value_flags flags)
{
using unwrapped_type = unwrap_node<remove_cvref<T>>;
static_assert(!std::is_same_v<unwrapped_type, node>);
static_assert(!is_node_view<unwrapped_type>);
// arrays + tables - invoke copy/move ctor
if constexpr (is_one_of<unwrapped_type, array, table>)
{
return new unwrapped_type(static_cast<T&&>(val));
}
// values
else
{
using native_type = native_type_of<unwrapped_type>;
using value_type = value<native_type>;
value_type* out;
// copy/move ctor
if constexpr (std::is_same_v<remove_cvref<T>, value_type>)
{
out = new value_type{ static_cast<T&&>(val), flags };
}
// creating from raw value
else
{
static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
"Instantiating values from wide-character strings is only "
"supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
if constexpr (!is_losslessly_convertible_to_native<unwrapped_type>)
{
if constexpr (std::is_same_v<native_type, int64_t>)
static_assert(dependent_false<T>,
"Integral value initializers must be losslessly convertible to int64_t");
else if constexpr (std::is_same_v<native_type, double>)
static_assert(dependent_false<T>,
"Floating-point value initializers must be losslessly convertible to double");
else
static_assert(
dependent_false<T>,
"Value initializers must be losslessly convertible to one of the TOML value types");
}
if constexpr (is_wide_string<T>)
{
#if TOML_ENABLE_WINDOWS_COMPAT
out = new value_type{ narrow(static_cast<T&&>(val)) };
#else
static_assert(dependent_false<T>, "Evaluated unreachable branch!");
#endif
}
else
out = new value_type{ static_cast<T&&>(val) };
if (flags != preserve_source_value_flags)
out->flags(flags);
}
return out;
}
}
template <typename T>
TOML_NODISCARD
auto* make_node_impl(T && val, value_flags flags = preserve_source_value_flags)
{
using unwrapped_type = unwrap_node<remove_cvref<T>>;
if constexpr (std::is_same_v<unwrapped_type, node> || is_node_view<unwrapped_type>)
{
if constexpr (is_node_view<unwrapped_type>)
{
if (!val)
return static_cast<toml::node*>(nullptr);
}
return static_cast<T&&>(val).visit(
[flags](auto&& concrete) {
return static_cast<toml::node*>(
make_node_impl_specialized(static_cast<decltype(concrete)&&>(concrete), flags));
});
}
else
return make_node_impl_specialized(static_cast<T&&>(val), flags);
}
template <typename T>
TOML_NODISCARD
auto* make_node_impl(inserter<T> && val, value_flags flags = preserve_source_value_flags)
{
return make_node_impl(static_cast<T&&>(val.value), flags);
}
template <typename T, bool = (is_node<T> || is_node_view<T> || is_value<T> || can_partially_represent_native<T>)>
struct inserted_type_of_
{
using type = std::remove_pointer_t<decltype(make_node_impl(std::declval<T>()))>;
};
template <typename T>
struct inserted_type_of_<inserter<T>, false>
{
using type = typename inserted_type_of_<remove_cvref<T>>::type;
};
template <typename T>
struct inserted_type_of_<T, false>
{
using type = void;
};
template <typename T>
TOML_NODISCARD
node_ptr make_node(T && val, value_flags flags = preserve_source_value_flags)
{
return node_ptr{ make_node_impl(static_cast<T&&>(val), flags) };
}
template <typename... T>
struct emplaced_type_of_
{
using type = void;
};
template <typename T>
struct emplaced_type_of_<T>
{
using type = std::conditional_t<is_one_of<T, node, node_view<node>, node_view<const node>>,
void,
typename inserted_type_of_<T>::type>;
};
template <typename T>
struct emplaced_type_of_<inserter<T>>
{
using type = typename emplaced_type_of_<remove_cvref<T>>::type;
};
template <typename... T>
using emplaced_type_of = typename emplaced_type_of_<remove_cvref<T>...>::type;
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
TOML_NAMESPACE_START
{
/// \brief Metafunction for determining which node type would be constructed
/// if an object of this type was inserted into a toml::table or toml::array.
///
/// \detail \cpp
/// static_assert(std::is_same_v<toml::inserted_type_of<const char*>, toml::value<std::string>);
/// static_assert(std::is_same_v<toml::inserted_type_of<int>, toml::value<int64_t>);
/// static_assert(std::is_same_v<toml::inserted_type_of<float>, toml::value<double>);
/// static_assert(std::is_same_v<toml::inserted_type_of<bool>, toml::value<bool>);
/// \ecpp
///
/// \note This will return toml::node for nodes and node_views, even though a more specific node subclass
/// would actually be inserted. There is no way around this in a compile-time metafunction.
template <typename T>
using inserted_type_of = POXY_IMPLEMENTATION_DETAIL(typename impl::inserted_type_of_<impl::remove_cvref<T>>::type);
}
TOML_NAMESPACE_END;
#include "header_end.h"

1115
lib/toml++/impl/node.h Normal file

File diff suppressed because it is too large Load Diff

141
lib/toml++/impl/node.inl Normal file
View File

@ -0,0 +1,141 @@
//# 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.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "node.h"
#include "node_view.h"
#include "at_path.h"
#include "table.h"
#include "array.h"
#include "value.h"
#include "header_start.h"
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_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_END;
#include "header_end.h"

839
lib/toml++/impl/node_view.h Normal file
View File

@ -0,0 +1,839 @@
//# 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 "std_vector.h"
#include "std_initializer_list.h"
#include "print_to_stream.h"
#include "node.h"
#include "header_start.h"
TOML_DISABLE_ARITHMETIC_WARNINGS;
TOML_NAMESPACE_START
{
/// \brief A view of a node.
///
/// \detail A node_view is like a std::optional<toml::node&> (if such a construct were legal), with lots of
/// toml-specific stuff built-in. It _may_ represent a node, and allows you to do many of the
/// same operations that you'd do on nodes directly, as well as easily traversing the node tree by creating
/// subviews (via node_view::operator[]). \cpp
///
/// auto tbl = toml::parse(R"(
///
/// title = "my hardware store"
///
/// [[products]]
/// name = "Hammer"
/// sku = 738594937
/// keywords = [ "hammer", "construction", "build" ]
///
/// [[products]]
/// name = "Nail"
/// sku = 284758393
/// color = "gray"
///
/// )"sv);
///
/// std::cout << tbl["title"] << "\n";
/// std::cout << tbl["products"][0]["name"] << "\n";
/// std::cout << tbl["products"][0]["keywords"] << "\n";
/// std::cout << tbl["products"][0]["keywords"][2] << "\n";
///
/// tbl["products"][0]["keywords"].as_array()->push_back("heavy");
/// std::cout << tbl["products"][0]["keywords"] << "\n";
/// std::cout << "has product[2]: "sv << !!tbl["products"][2] << "\n";
/// std::cout << "product[2]: "sv << tbl["products"][2] << "\n";
/// \ecpp
///
/// \out
/// "my hardware store"
/// "Hammer"
/// [ "hammer", "construction", "build" ]
/// "build"
/// [ "hammer", "construction", "build", "heavy" ]
/// has product[2]: false
/// product[2]:
/// \eout
template <typename ViewedType>
class TOML_TRIVIAL_ABI node_view
{
static_assert(impl::is_one_of<ViewedType, toml::node, const toml::node>,
"A toml::node_view<> must wrap toml::node or const toml::node.");
public:
/// \brief The node type being viewed - either `node` or `const node`.
using viewed_type = ViewedType;
private:
template <typename T>
friend class node_view;
mutable viewed_type* node_ = nullptr;
public:
/// \brief Constructs an empty node view.
TOML_NODISCARD_CTOR
node_view() noexcept = default;
/// \brief Constructs node_view of a specific node.
TOML_NODISCARD_CTOR
explicit node_view(viewed_type* node) noexcept //
: node_{ node }
{}
/// \brief Constructs node_view of a specific node.
TOML_NODISCARD_CTOR
explicit node_view(viewed_type& node) noexcept //
: node_{ &node }
{}
/// \brief Copy constructor.
TOML_NODISCARD_CTOR
node_view(const node_view&) noexcept = default;
/// \brief Move constructor.
TOML_NODISCARD_CTOR
node_view(node_view&&) noexcept = default;
/// \brief Copy-assignment operator.
node_view& operator=(const node_view&) & noexcept = default;
/// \brief Move-assignment operator.
node_view& operator=(node_view&&) & noexcept = default;
/// \brief Returns true if the view references a node.
TOML_PURE_INLINE_GETTER
explicit operator bool() const noexcept
{
return node_ != nullptr;
}
/// \brief Returns the node that's being referenced by the view.
TOML_PURE_INLINE_GETTER
viewed_type* node() const noexcept
{
return node_;
}
/// \name Type checks
/// @{
/// \brief Returns the type identifier for the viewed node.
TOML_PURE_GETTER
node_type type() const noexcept
{
return node_ ? node_->type() : node_type::none;
}
/// \brief Returns true if the viewed node is a toml::table.
TOML_PURE_GETTER
bool is_table() const noexcept
{
return node_ && node_->is_table();
}
/// \brief Returns true if the viewed node is a toml::array.
TOML_PURE_GETTER
bool is_array() const noexcept
{
return node_ && node_->is_array();
}
/// \brief Returns true if the viewed node is a toml::value<>.
TOML_PURE_GETTER
bool is_value() const noexcept
{
return node_ && node_->is_value();
}
/// \brief Returns true if the viewed node is a toml::value<string>.
TOML_PURE_GETTER
bool is_string() const noexcept
{
return node_ && node_->is_string();
}
/// \brief Returns true if the viewed node is a toml::value<int64_t>.
TOML_PURE_GETTER
bool is_integer() const noexcept
{
return node_ && node_->is_integer();
}
/// \brief Returns true if the viewed node is a toml::value<double>.
TOML_PURE_GETTER
bool is_floating_point() const noexcept
{
return node_ && node_->is_floating_point();
}
/// \brief Returns true if the viewed node is a toml::value<int64_t> or toml::value<double>.
TOML_PURE_GETTER
bool is_number() const noexcept
{
return node_ && node_->is_number();
}
/// \brief Returns true if the viewed node is a toml::value<bool>.
TOML_PURE_GETTER
bool is_boolean() const noexcept
{
return node_ && node_->is_boolean();
}
/// \brief Returns true if the viewed node is a toml::value<date>.
TOML_PURE_GETTER
bool is_date() const noexcept
{
return node_ && node_->is_date();
}
/// \brief Returns true if the viewed node is a toml::value<time>.
TOML_PURE_GETTER
bool is_time() const noexcept
{
return node_ && node_->is_time();
}
/// \brief Returns true if the viewed node is a toml::value<date_time>.
TOML_PURE_GETTER
bool is_date_time() const noexcept
{
return node_ && node_->is_date_time();
}
/// \brief Returns true if the viewed node is a toml::array that contains only tables.
TOML_PURE_GETTER
bool is_array_of_tables() const noexcept
{
return node_ && node_->is_array_of_tables();
}
/// \brief Checks if this view references a node of a specific type.
///
/// \tparam T A TOML node or value type.
///
/// \returns Returns true if the viewed node is an instance of the specified type.
///
/// \see toml::node::is()
template <typename T>
TOML_PURE_GETTER
bool is() const noexcept
{
return node_ ? node_->template is<impl::unwrap_node<impl::remove_cvref<T>>>() : false;
}
/// \brief Checks if the viewed node contains values/elements of only one type.
///
/// \detail \cpp
/// auto cfg = toml::parse("arr = [ 1, 2, 3, 4.0 ]");
///
/// toml::node* nonmatch{};
/// if (cfg["arr"].is_homogeneous(toml::node_type::integer, nonmatch))
/// std::cout << "array was homogeneous"sv << "\n";
/// else
/// std::cout << "array was not homogeneous!\n"
/// << "first non-match was a "sv << nonmatch->type() << " at " << nonmatch->source() << "\n";
/// \ecpp
///
/// \out
/// array was not homogeneous!
/// first non-match was a floating-point at line 1, column 18
/// \eout
///
/// \param ntype A TOML node type. <br>
/// \conditional_return{toml::node_type::none} "is every element the same type?"
/// \conditional_return{Anything else} "is every element one of these?"
///
/// \param first_nonmatch Reference to a pointer in which the address of the first non-matching element
/// will be stored if the return value is false.
///
/// \returns True if the viewed node was homogeneous.
///
/// \remarks Always returns `false` if the view does not reference a node, or if the viewed node is
/// an empty table or array.
TOML_NODISCARD
bool is_homogeneous(node_type ntype, viewed_type*& first_nonmatch) const noexcept
{
if (!node_)
{
first_nonmatch = {};
return false;
}
return node_->is_homogeneous(ntype, first_nonmatch);
}
/// \brief Checks if the viewed node contains values/elements of only one type.
///
/// \detail \cpp
/// auto cfg = toml::parse("arr = [ 1, 2, 3 ]");
/// std::cout << "homogenous: "sv << cfg["arr"].is_homogeneous(toml::node_type::none) << "\n";
/// std::cout << "all floats: "sv << cfg["arr"].is_homogeneous(toml::node_type::floating_point) << "\n";
/// std::cout << "all arrays: "sv << cfg["arr"].is_homogeneous(toml::node_type::array) << "\n";
/// std::cout << "all ints: "sv << cfg["arr"].is_homogeneous(toml::node_type::integer) << "\n";
/// \ecpp
///
/// \out
/// homogeneous: true
/// all floats: false
/// all arrays: false
/// all ints: true
/// \eout
///
/// \param ntype A TOML node type. <br>
/// \conditional_return{toml::node_type::none} "is every element the same type?"
/// \conditional_return{Anything else} "is every element one of these?"
///
/// \returns True if the viewed node was homogeneous.
///
/// \remarks Always returns `false` if the view does not reference a node, or if the viewed node is
/// an empty table or array.
TOML_NODISCARD
bool is_homogeneous(node_type ntype) const noexcept
{
return node_ ? node_->is_homogeneous(ntype) : false;
}
/// \brief Checks if the viewed node contains values/elements of only one type.
///
/// \detail \cpp
/// auto cfg = toml::parse("arr = [ 1, 2, 3 ]");
/// std::cout << "homogenous: "sv << cfg["arr"].is_homogeneous() << "\n";
/// std::cout << "all doubles: "sv << cfg["arr"].is_homogeneous<double>() << "\n";
/// std::cout << "all arrays: "sv << cfg["arr"].is_homogeneous<toml::array>() << "\n";
/// std::cout << "all integers: "sv << cfg["arr"].is_homogeneous<int64_t>() << "\n";
/// \ecpp
///
/// \out
/// homogeneous: true
/// all floats: false
/// all arrays: false
/// all ints: true
/// \eout
///
/// \tparam ElemType A TOML node or value type. <br>
/// \conditional_return{Left as `void`} "is every element the same type?" <br>
/// \conditional_return{Explicitly specified} "is every element a T?"
///
/// \returns True if the viewed node was homogeneous.
///
/// \remarks Always returns `false` if the view does not reference a node, or if the viewed node is
/// an empty table or array.
template <typename ElemType = void>
TOML_PURE_GETTER
bool is_homogeneous() const noexcept
{
return node_ ? node_->template is_homogeneous<impl::unwrap_node<impl::remove_cvref<ElemType>>>() : false;
}
/// @}
/// \name Type casts
/// @{
/// \brief Gets a pointer to the viewed node as a more specific node type.
///
/// \tparam T The node type or TOML value type to cast to.
///
/// \returns A pointer to the node as the given type, or nullptr if it was a different type.
///
/// \see toml::node::as()
template <typename T>
TOML_PURE_GETTER
auto* as() const noexcept
{
return node_ ? node_->template as<T>() : nullptr;
}
/// \brief Returns a pointer to the viewed node as a toml::table, if it is one.
TOML_PURE_GETTER
auto* as_table() const noexcept
{
return as<table>();
}
/// \brief Returns a pointer to the viewed node as a toml::array, if it is one.
TOML_PURE_GETTER
auto* as_array() const noexcept
{
return as<array>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<string>, if it is one.
TOML_PURE_GETTER
auto* as_string() const noexcept
{
return as<std::string>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<int64_t>, if it is one.
TOML_PURE_GETTER
auto* as_integer() const noexcept
{
return as<int64_t>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<double>, if it is one.
TOML_PURE_GETTER
auto* as_floating_point() const noexcept
{
return as<double>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<bool>, if it is one.
TOML_PURE_GETTER
auto* as_boolean() const noexcept
{
return as<bool>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<date>, if it is one.
TOML_PURE_GETTER
auto* as_date() const noexcept
{
return as<date>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<time>, if it is one.
TOML_PURE_GETTER
auto* as_time() const noexcept
{
return as<time>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<date_time>, if it is one.
TOML_PURE_GETTER
auto* as_date_time() const noexcept
{
return as<date_time>();
}
/// @}
/// \name Value retrieval
/// @{
/// \brief Gets the value contained by the referenced node.
///
/// \detail This function has 'exact' retrieval semantics; the only return value types allowed are the
/// TOML native value types, or types that can losslessly represent a native value type (e.g.
/// std::wstring on Windows).
///
/// \tparam T One of the native TOML value types, or a type capable of losslessly representing one.
///
/// \returns The underlying value if the node was a value of the
/// matching type (or losslessly convertible to it), or an empty optional.
///
/// \see node_view::value()
template <typename T>
TOML_NODISCARD
optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>)
{
if (node_)
return node_->template value_exact<T>();
return {};
}
/// \brief Gets the value contained by the referenced node.
///
/// \detail This function has 'permissive' retrieval semantics; some value types are allowed
/// to convert to others (e.g. retrieving a boolean as an integer), and the specified return value
/// type can be any type where a reasonable conversion from a native TOML value exists
/// (e.g. std::wstring on Windows). If the source value cannot be represented by
/// the destination type, an empty optional is returned. See node::value() for examples.
///
/// \tparam T One of the native TOML value types, or a type capable of convertible to one.
///
/// \returns The underlying value if the node was a value of the matching type (or convertible to it)
/// and within the range of the output type, or an empty optional.
///
/// \note If you want strict value retrieval semantics that do not allow for any type conversions,
/// use node_view::value_exact() instead.
///
/// \see
/// - node_view::value()
/// - node_view::value_exact()
template <typename T>
TOML_NODISCARD
optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>)
{
if (node_)
return node_->template value<T>();
return {};
}
/// \brief Gets the raw value contained by the referenced node, or a default.
///
/// \tparam T Default value type. Must be one of the native TOML value types,
/// or convertible to it.
/// \param default_value The default value to return if the node wasn't a value, wasn't the
/// correct type, or no conversion was possible.
///
/// \returns The underlying value if the node was a value of the matching type (or convertible to it)
/// and within the range of the output type, or the provided default.
///
/// \note This function has the same permissive retrieval semantics as node::value(). If you want strict
/// value retrieval semantics that do not allow for any type conversions, use node_view::value_exact()
/// instead.
///
/// \see
/// - node_view::value()
/// - node_view::value_exact()
template <typename T>
TOML_NODISCARD
auto value_or(T&& default_value) const noexcept(impl::value_retrieval_is_nothrow<T>)
{
using namespace ::toml::impl;
static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
"Retrieving values as wide-character strings is only "
"supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
if constexpr (is_wide_string<T>)
{
#if TOML_ENABLE_WINDOWS_COMPAT
if (node_)
return node_->value_or(static_cast<T&&>(default_value));
return std::wstring{ static_cast<T&&>(default_value) };
#else
static_assert(impl::dependent_false<T>, "Evaluated unreachable branch!");
#endif
}
else
{
using value_type =
std::conditional_t<std::is_pointer_v<std::decay_t<T>>,
std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>,
std::decay_t<T>>;
if (node_)
return node_->value_or(static_cast<T&&>(default_value));
if constexpr (std::is_pointer_v<value_type>)
return value_type{ default_value };
else
return static_cast<T&&>(default_value);
}
}
/// \brief Gets a raw reference to the viewed node's underlying data.
///
/// \warning This function is dangerous if used carelessly and **WILL** break your code if the
/// node_view didn't reference a node, or the chosen value type doesn't match the node's
/// actual type. In debug builds an assertion will fire when invalid accesses are attempted: \cpp
///
/// auto tbl = toml::parse(R"(
/// min = 32
/// max = 45
/// )"sv);
///
/// int64_t& min_ref = tbl["min"].ref<int64_t>(); // matching type
/// double& max_ref = tbl["max"].ref<double>(); // mismatched type, hits assert()
/// int64_t& foo_ref = tbl["foo"].ref<int64_t>(); // nonexistent key, hits assert()
/// \ecpp
///
/// \note Specifying explicit ref qualifiers acts as an explicit ref-category cast,
/// whereas specifying explicit cv-ref qualifiers merges them with whatever
/// the cv qualification of the viewed node is (to ensure cv-correctness is propagated), e.g.:
/// | node_view | T | return type |
/// |-----------------------|------------------------|------------------------------|
/// | node_view<node> | std::string | std::string& |
/// | node_view<node> | std::string&& | std::string&& |
/// | node_view<const node> | volatile std::string | const volatile std::string& |
/// | node_view<const node> | volatile std::string&& | const volatile std::string&& |
///
///
/// \tparam T One of the TOML value types.
///
/// \returns A reference to the underlying data.
template <typename T>
TOML_PURE_INLINE_GETTER
decltype(auto) ref() const noexcept
{
TOML_ASSERT_ASSUME(node_ && "toml::node_view::ref() called on a node_view that did not reference a node");
return node_->template ref<T>();
}
/// @}
/// \name Visitation
/// @{
private:
/// \cond
template <typename Func>
static constexpr bool visit_is_nothrow = noexcept(std::declval<viewed_type*>()->visit(std::declval<Func>()));
/// \endcond
public:
/// \brief Invokes a visitor on the viewed node based on its concrete type.
///
/// \remarks Has no effect if the view does not reference a node.
///
/// \see node::visit()
template <typename Func>
decltype(auto) visit(Func&& visitor) const noexcept(visit_is_nothrow<Func&&>)
{
using return_type = decltype(node_->visit(static_cast<Func&&>(visitor)));
if (node_)
return node_->visit(static_cast<Func&&>(visitor));
if constexpr (!std::is_void_v<return_type>)
return return_type{};
}
/// @}
/// \name Equality
/// @{
public:
/// \brief Returns true if the two views refer to nodes of the same type and value.
template <typename T>
TOML_PURE_GETTER
friend bool operator==(const node_view& lhs, const node_view<T>& rhs) noexcept
{
return impl::node_deep_equality(lhs.node_, rhs.node_);
}
/// \brief Returns true if the two views do not refer to nodes of the same type and value.
template <typename T>
TOML_PURE_GETTER
friend bool operator!=(const node_view& lhs, const node_view<T>& rhs) noexcept
{
return !impl::node_deep_equality(lhs.node_, rhs.node_);
}
/// \brief Returns true if the viewed node is a table with the same contents as RHS.
TOML_NODISCARD
friend bool operator==(const node_view& lhs, const table& rhs) noexcept
{
if (lhs.node_ == &rhs)
return true;
const auto tbl = lhs.as<table>();
return tbl && *tbl == rhs;
}
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const table&, );
/// \brief Returns true if the viewed node is an array with the same contents as RHS.
TOML_NODISCARD
friend bool operator==(const node_view& lhs, const array& rhs) noexcept
{
if (lhs.node_ == &rhs)
return true;
const auto arr = lhs.as<array>();
return arr && *arr == rhs;
}
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const array&, );
/// \brief Returns true if the viewed node is a value with the same value as RHS.
template <typename T>
TOML_NODISCARD
friend bool operator==(const node_view& lhs, const toml::value<T>& rhs) noexcept
{
if (lhs.node_ == &rhs)
return true;
const auto val = lhs.as<T>();
return val && *val == rhs;
}
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const toml::value<T>&, template <typename T>);
/// \brief Returns true if the viewed node is a value with the same value as RHS.
TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>, typename T)
TOML_NODISCARD
friend bool operator==(const node_view& lhs, const T& rhs) noexcept(!impl::is_wide_string<T>)
{
static_assert(!impl::is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT,
"Comparison with wide-character strings is only "
"supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled.");
if constexpr (impl::is_wide_string<T>)
{
#if TOML_ENABLE_WINDOWS_COMPAT
return lhs == impl::narrow(rhs);
#else
static_assert(impl::dependent_false<T>, "Evaluated unreachable branch!");
#endif
}
else
{
const auto val = lhs.as<impl::native_type_of<T>>();
return val && *val == rhs;
}
}
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&,
const T&,
TOML_CONSTRAINED_TEMPLATE(impl::is_losslessly_convertible_to_native<T>,
typename T));
/// \brief Returns true if the viewed node is an array with the same contents as the RHS initializer list.
template <typename T>
TOML_NODISCARD
friend bool operator==(const node_view& lhs,
const std::initializer_list<T>& rhs) noexcept(!impl::is_wide_string<T>)
{
const auto arr = lhs.as<array>();
return arr && *arr == rhs;
}
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::initializer_list<T>&, template <typename T>);
/// \brief Returns true if the viewed node is an array with the same contents as the RHS vector.
template <typename T>
TOML_NODISCARD
friend bool operator==(const node_view& lhs, const std::vector<T>& rhs) noexcept(!impl::is_wide_string<T>)
{
const auto arr = lhs.as<array>();
return arr && *arr == rhs;
}
TOML_ASYMMETRICAL_EQUALITY_OPS(const node_view&, const std::vector<T>&, template <typename T>);
/// @}
/// \name Subviews
/// @{
/// \brief Returns a view of the selected subnode.
///
/// \param key The key of the node to retrieve
///
/// \returns A view of the selected node if this node represented a table and it contained a
/// value at the given key, or an empty view.
TOML_NODISCARD
node_view operator[](std::string_view key) const noexcept
{
if (auto tbl = this->as_table())
return node_view{ tbl->get(key) };
return {};
}
/// \brief Returns a view of the selected subnode.
///
/// \param path A "TOML path" to the desired subnode
///
/// \returns A view of the selected node if this node represented a table and it contained a
/// value at the given key, or an empty view.
TOML_NODISCARD
node_view operator[](const toml::path& path) const noexcept
{
return node_ ? node_->at_path(path) : node_view{};
}
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::node::at_path(std::string_view)
TOML_NODISCARD
node_view at_path(std::string_view path) const noexcept
{
return node_ ? node_->at_path(path) : node_view{};
}
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::node::at_path(const toml::path&)
TOML_NODISCARD
node_view at_path(const toml::path& path) const noexcept
{
return node_ ? node_->at_path(path) : node_view{};
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Returns a view of the selected subnode.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \param key The key of the node to retrieve
///
/// \returns A view of the selected node if this node represented a table and it contained a
/// value at the given key, or an empty view.
TOML_NODISCARD
node_view operator[](std::wstring_view key) const
{
if (auto tbl = this->as_table())
return node_view{ tbl->get(key) };
return {};
}
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::node::at_path(std::string_view)
TOML_NODISCARD
node_view at_path(std::wstring_view path) const
{
return node_ ? node_->at_path(path) : node_view{};
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
/// \brief Returns a view of the selected subnode.
///
/// \param index The index of the node to retrieve
///
/// \returns A view of the selected node if this node represented an array and it contained a
/// value at the given index, or an empty view.
TOML_NODISCARD
node_view operator[](size_t index) const noexcept
{
if (auto arr = this->as_array())
return node_view{ arr->get(index) };
return {};
}
/// @}
#if TOML_ENABLE_FORMATTERS
/// \brief Prints the viewed node out to a stream.
///
/// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
friend std::ostream& operator<<(std::ostream& os, const node_view& nv)
{
if (nv.node_)
nv.node_->visit([&os](const auto& n) { os << n; });
return os;
}
#endif
};
/// \cond
template <typename T>
node_view(const T&) -> node_view<const node>;
template <typename T>
node_view(const T*) -> node_view<const node>;
template <typename T>
node_view(T&) -> node_view<node>;
template <typename T>
node_view(T*) -> node_view<node>;
/// \endcond
}
TOML_NAMESPACE_END;
/// \cond
TOML_NAMESPACE_START
{
inline node::operator node_view<node>() noexcept
{
return node_view<node>{ this };
}
inline node::operator node_view<const node>() const noexcept
{
return node_view<const node>{ this };
}
}
TOML_NAMESPACE_END;
/// \endcond
#include "header_end.h"

View File

@ -0,0 +1,139 @@
//# 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.h"
#if TOML_ENABLE_PARSER
#include "std_except.h"
#include "source_region.h"
#include "print_to_stream.h"
#include "header_start.h"
#if TOML_DOXYGEN || !TOML_EXCEPTIONS
#define TOML_PARSE_ERROR_BASE
#else
#define TOML_PARSE_ERROR_BASE : public std::runtime_error
#endif
TOML_NAMESPACE_START
{
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
/// \brief An error generated when parsing fails.
///
/// \remarks This class inherits from std::runtime_error when exceptions are enabled.
/// The public interface is the same regardless of exception mode.
class parse_error TOML_PARSE_ERROR_BASE
{
private:
#if !TOML_EXCEPTIONS
std::string description_;
#endif
source_region source_;
public:
#if TOML_EXCEPTIONS
TOML_NODISCARD_CTOR
TOML_ATTR(nonnull)
parse_error(const char* desc, source_region&& src) noexcept //
: std::runtime_error{ desc },
source_{ std::move(src) }
{}
TOML_NODISCARD_CTOR
TOML_ATTR(nonnull)
parse_error(const char* desc, const source_region& src) noexcept //
: parse_error{ desc, source_region{ src } }
{}
TOML_NODISCARD_CTOR
TOML_ATTR(nonnull)
parse_error(const char* desc, const source_position& position, const source_path_ptr& path = {}) noexcept
: parse_error{ desc, source_region{ position, position, path } }
{}
#else
TOML_NODISCARD_CTOR
parse_error(std::string&& desc, source_region&& src) noexcept //
: description_{ std::move(desc) },
source_{ std::move(src) }
{}
TOML_NODISCARD_CTOR
parse_error(std::string&& desc, const source_region& src) noexcept //
: parse_error{ std::move(desc), source_region{ src } }
{}
TOML_NODISCARD_CTOR
parse_error(std::string&& desc, const source_position& position, const source_path_ptr& path = {}) noexcept
: parse_error{ std::move(desc), source_region{ position, position, path } }
{}
#endif
/// \brief Returns a textual description of the error.
/// \remark The backing string is guaranteed to be null-terminated.
TOML_NODISCARD
std::string_view description() const noexcept
{
#if TOML_EXCEPTIONS
return std::string_view{ what() };
#else
return description_;
#endif
}
/// \brief Returns the region of the source document responsible for the error.
TOML_NODISCARD
const source_region& source() const noexcept
{
return source_;
}
/// \brief Prints a parse_error to a stream.
///
/// \detail \cpp
/// try
/// {
/// auto tbl = toml::parse("enabled = trUe"sv);
/// }
/// catch (const toml::parse_error & err)
/// {
/// std::cerr << "Parsing failed:\n"sv << err << "\n";
/// }
/// \ecpp
///
/// \out
/// Parsing failed:
/// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU'
/// (error occurred at line 1, column 13)
/// \eout
///
/// \tparam Char The output stream's underlying character type. Must be 1 byte in size.
/// \param lhs The stream.
/// \param rhs The parse_error.
///
/// \returns The input stream.
friend std::ostream& operator<<(std::ostream& lhs, const parse_error& rhs)
{
impl::print_to_stream(lhs, rhs.description());
impl::print_to_stream(lhs, "\n\t(error occurred at "sv);
impl::print_to_stream(lhs, rhs.source());
impl::print_to_stream(lhs, ")"sv);
return lhs;
}
};
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
}
TOML_NAMESPACE_END;
#undef TOML_PARSE_ERROR_BASE
#include "header_end.h"
#endif // TOML_ENABLE_PARSER

View File

@ -0,0 +1,499 @@
//# 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.h"
#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
#include "table.h"
#include "parse_error.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
TOML_ABI_NAMESPACE_START(noex);
/// \brief The result of a parsing operation.
///
/// \availability <strong>This type only exists when exceptions are disabled.</strong>
/// Otherwise parse_result is just an alias for toml::table: \cpp
/// #if TOML_EXCEPTIONS
/// using parse_result = table;
/// #else
/// class parse_result { // ...
/// #endif
/// \ecpp
///
/// \detail A parse_result is effectively a discriminated union containing either a toml::table
/// or a toml::parse_error. Most member functions assume a particular one of these two states,
/// and calling them when in the wrong state will cause errors (e.g. attempting to access the
/// error object when parsing was successful). \cpp
/// toml::parse_result result = toml::parse_file("config.toml");
/// if (result)
/// do_stuff_with_a_table(result); //implicitly converts to table&
/// else
/// std::cerr << "Parse failed:\n"sv << result.error() << "\n";
/// \ecpp
///
/// \out
/// example output:
///
/// Parse failed:
/// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU'
/// (error occurred at line 1, column 13 of 'config.toml')
/// \eout
///
/// Getting node_views (`operator[]`, `at_path()`) and using the iterator accessor functions (`begin()`, `end()` etc.) are
/// unconditionally safe; when parsing fails these just return 'empty' values. A ranged-for loop on a failed
/// parse_result is also safe since `begin()` and `end()` return the same iterator and will not lead to any
/// dereferences and iterations.
class parse_result
{
private:
struct storage_t
{
static constexpr size_t size =
(sizeof(toml::table) < sizeof(parse_error) ? sizeof(parse_error) : sizeof(toml::table));
static constexpr size_t align =
(alignof(toml::table) < alignof(parse_error) ? alignof(parse_error) : alignof(toml::table));
alignas(align) unsigned char bytes[size];
};
alignas(storage_t::align) mutable storage_t storage_;
bool err_;
template <typename Type>
TOML_NODISCARD
TOML_ALWAYS_INLINE
static Type* get_as(storage_t& s) noexcept
{
return TOML_LAUNDER(reinterpret_cast<Type*>(s.bytes));
}
void destroy() noexcept
{
if (err_)
get_as<parse_error>(storage_)->~parse_error();
else
get_as<toml::table>(storage_)->~table();
}
public:
/// \brief Default constructs an 'error' result.
TOML_NODISCARD_CTOR
parse_result() noexcept //
: err_{ true }
{
::new (static_cast<void*>(storage_.bytes)) parse_error{ std::string{}, source_region{} };
}
TOML_NODISCARD_CTOR
explicit parse_result(toml::table&& tbl) noexcept //
: err_{ false }
{
::new (static_cast<void*>(storage_.bytes)) toml::table{ std::move(tbl) };
}
TOML_NODISCARD_CTOR
explicit parse_result(parse_error&& err) noexcept //
: err_{ true }
{
::new (static_cast<void*>(storage_.bytes)) parse_error{ std::move(err) };
}
/// \brief Move constructor.
TOML_NODISCARD_CTOR
parse_result(parse_result&& res) noexcept //
: err_{ res.err_ }
{
if (err_)
::new (static_cast<void*>(storage_.bytes)) parse_error{ std::move(res).error() };
else
::new (static_cast<void*>(storage_.bytes)) toml::table{ std::move(res).table() };
}
/// \brief Move-assignment operator.
parse_result& operator=(parse_result&& rhs) noexcept
{
if (err_ != rhs.err_)
{
destroy();
err_ = rhs.err_;
if (err_)
::new (static_cast<void*>(storage_.bytes)) parse_error{ std::move(rhs).error() };
else
::new (static_cast<void*>(storage_.bytes)) toml::table{ std::move(rhs).table() };
}
else
{
if (err_)
error() = std::move(rhs).error();
else
table() = std::move(rhs).table();
}
return *this;
}
/// \brief Destructor.
~parse_result() noexcept
{
destroy();
}
/// \name Result state
/// @{
/// \brief Returns true if parsing succeeeded.
TOML_NODISCARD
bool succeeded() const noexcept
{
return !err_;
}
/// \brief Returns true if parsing failed.
TOML_NODISCARD
bool failed() const noexcept
{
return err_;
}
/// \brief Returns true if parsing succeeded.
TOML_NODISCARD
explicit operator bool() const noexcept
{
return !err_;
}
/// @}
/// \name Successful parses
/// \warning It is undefined behaviour to call these functions when the result respresents a failed parse.
/// Check #failed(), #succeeded or #operator bool() to determine the result's state.
/// @{
/// \brief Returns the internal toml::table.
TOML_NODISCARD
toml::table& table() & noexcept
{
TOML_ASSERT_ASSUME(!err_);
return *get_as<toml::table>(storage_);
}
/// \brief Returns the internal toml::table (rvalue overload).
TOML_NODISCARD
toml::table&& table() && noexcept
{
TOML_ASSERT_ASSUME(!err_);
return static_cast<toml::table&&>(*get_as<toml::table>(storage_));
}
/// \brief Returns the internal toml::table (const lvalue overload).
TOML_NODISCARD
const toml::table& table() const& noexcept
{
TOML_ASSERT_ASSUME(!err_);
return *get_as<const toml::table>(storage_);
}
/// \brief Returns the internal toml::table.
TOML_NODISCARD
/* implicit */ operator toml::table&() noexcept
{
return table();
}
/// \brief Returns the internal toml::table (rvalue overload).
TOML_NODISCARD
/* implicit */ operator toml::table&&() noexcept
{
return std::move(table());
}
/// \brief Returns the internal toml::table (const lvalue overload).
TOML_NODISCARD
/* implicit */ operator const toml::table&() const noexcept
{
return table();
}
/// @}
/// \name Failed parses
/// \warning It is undefined behaviour to call these functions when the result respresents a successful parse.
/// Check #failed(), #succeeded or #operator bool() to determine the result's state.
/// @{
/// \brief Returns the internal toml::parse_error.
TOML_NODISCARD
parse_error& error() & noexcept
{
TOML_ASSERT_ASSUME(err_);
return *get_as<parse_error>(storage_);
}
/// \brief Returns the internal toml::parse_error (rvalue overload).
TOML_NODISCARD
parse_error&& error() && noexcept
{
TOML_ASSERT_ASSUME(err_);
return static_cast<parse_error&&>(*get_as<parse_error>(storage_));
}
/// \brief Returns the internal toml::parse_error (const lvalue overload).
TOML_NODISCARD
const parse_error& error() const& noexcept
{
TOML_ASSERT_ASSUME(err_);
return *get_as<const parse_error>(storage_);
}
/// \brief Returns the internal toml::parse_error.
TOML_NODISCARD
explicit operator parse_error&() noexcept
{
return error();
}
/// \brief Returns the internal toml::parse_error (rvalue overload).
TOML_NODISCARD
explicit operator parse_error&&() noexcept
{
return std::move(error());
}
/// \brief Returns the internal toml::parse_error (const lvalue overload).
TOML_NODISCARD
explicit operator const parse_error&() const noexcept
{
return error();
}
/// @}
/// \name Iteration
/// @{
/// \brief A BidirectionalIterator for iterating over key-value pairs in a wrapped toml::table.
using iterator = table_iterator;
/// \brief A BidirectionalIterator for iterating over const key-value pairs in a wrapped toml::table.
using const_iterator = const_table_iterator;
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Always returns the same value as #end() if parsing failed.
TOML_NODISCARD
table_iterator begin() noexcept
{
return err_ ? table_iterator{} : table().begin();
}
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Always returns the same value as #end() if parsing failed.
TOML_NODISCARD
const_table_iterator begin() const noexcept
{
return err_ ? const_table_iterator{} : table().begin();
}
/// \brief Returns an iterator to the first key-value pair in the wrapped table.
/// \remarks Always returns the same value as #cend() if parsing failed.
TOML_NODISCARD
const_table_iterator cbegin() const noexcept
{
return err_ ? const_table_iterator{} : table().cbegin();
}
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
TOML_NODISCARD
table_iterator end() noexcept
{
return err_ ? table_iterator{} : table().end();
}
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
TOML_NODISCARD
const_table_iterator end() const noexcept
{
return err_ ? const_table_iterator{} : table().end();
}
/// \brief Returns an iterator to one-past-the-last key-value pair in the wrapped table.
TOML_NODISCARD
const_table_iterator cend() const noexcept
{
return err_ ? const_table_iterator{} : table().cend();
}
/// @}
/// \name Node views
/// @{
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::node::at_path(std::string_view)
TOML_NODISCARD
node_view<node> at_path(std::string_view path) noexcept
{
return err_ ? node_view<node>{} : table().at_path(path);
}
/// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::node::at_path(std::string_view)
TOML_NODISCARD
node_view<const node> at_path(std::string_view path) const noexcept
{
return err_ ? node_view<const node>{} : table().at_path(path);
}
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::node::at_path(const toml::path&)
TOML_NODISCARD
node_view<node> at_path(const toml::path& path) noexcept
{
return err_ ? node_view<node>{} : table().at_path(path);
}
/// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::node::at_path(const toml::path&)
TOML_NODISCARD
node_view<const node> at_path(const toml::path& path) const noexcept
{
return err_ ? node_view<const node>{} : table().at_path(path);
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::node::at_path(std::string_view)
TOML_NODISCARD
node_view<node> at_path(std::wstring_view path)
{
return err_ ? node_view<node>{} : table().at_path(path);
}
/// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \see #toml::node::at_path(std::string_view)
TOML_NODISCARD
node_view<const node> at_path(std::wstring_view path) const
{
return err_ ? node_view<const node>{} : table().at_path(path);
}
#endif
/// \brief Returns a view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::node::operator[](const toml::path&)
TOML_NODISCARD
node_view<node> operator[](const toml::path& path) noexcept
{
return err_ ? node_view<node>{} : table()[path];
}
/// \brief Returns a const view of the subnode matching a fully-qualified "TOML path".
///
/// \see #toml::node::operator[](const toml::path&)
TOML_NODISCARD
node_view<const node> operator[](const toml::path& path) const noexcept
{
return err_ ? node_view<const node>{} : table()[path];
}
/// \brief Gets a node_view for the selected key-value pair in the wrapped table.
///
/// \param key The key used for the lookup.
///
/// \returns A view of the value at the given key if parsing was successful and a matching key existed,
/// or an empty node view.
///
/// \see toml::node_view
TOML_NODISCARD
node_view<node> operator[](std::string_view key) noexcept
{
return err_ ? node_view<node>{} : table()[key];
}
/// \brief Gets a node_view for the selected key-value pair in the wrapped table (const overload).
///
/// \param key The key used for the lookup.
///
/// \returns A view of the value at the given key if parsing was successful and a matching key existed,
/// or an empty node view.
///
/// \see toml::node_view
TOML_NODISCARD
node_view<const node> operator[](std::string_view key) const noexcept
{
return err_ ? node_view<const node>{} : table()[key];
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Gets a node_view for the selected key-value pair in the wrapped table.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \param key The key used for the lookup.
///
/// \returns A view of the value at the given key if parsing was successful and a matching key existed,
/// or an empty node view.
///
/// \see toml::node_view
TOML_NODISCARD
node_view<node> operator[](std::wstring_view key)
{
return err_ ? node_view<node>{} : table()[key];
}
/// \brief Gets a node_view for the selected key-value pair in the wrapped table (const overload).
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \param key The key used for the lookup.
///
/// \returns A view of the value at the given key if parsing was successful and a matching key existed,
/// or an empty node view.
///
/// \see toml::node_view
TOML_NODISCARD
node_view<const node> operator[](std::wstring_view key) const
{
return err_ ? node_view<const node>{} : table()[key];
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
/// @}
#if TOML_ENABLE_FORMATTERS
/// \brief Prints the held error or table object out to a text stream.
///
/// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
friend std::ostream& operator<<(std::ostream& os, const parse_result& result)
{
return result.err_ ? (os << result.error()) : (os << result.table());
}
#endif
};
TOML_ABI_NAMESPACE_END;
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_PARSER && !TOML_EXCEPTIONS

390
lib/toml++/impl/parser.h Normal file
View File

@ -0,0 +1,390 @@
//# 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.h"
#if TOML_ENABLE_PARSER
#include "table.h"
#include "parse_result.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex);
/// \brief Parses a TOML document from a string view.
///
/// \detail \cpp
/// auto tbl = toml::parse("a = 3"sv);
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path = {});
/// \brief Parses a TOML document from a string view.
///
/// \detail \cpp
/// auto tbl = toml::parse("a = 3"sv, "foo.toml");
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse(std::string_view doc, std::string && source_path);
/// \brief Parses a TOML document from a file.
///
/// \detail \cpp
/// toml::parse_result get_foo_toml()
/// {
/// return toml::parse_file("foo.toml");
/// }
/// \ecpp
///
/// \param file_path The TOML document to parse. Must be valid UTF-8.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse_file(std::string_view file_path);
#if TOML_HAS_CHAR8
/// \brief Parses a TOML document from a char8_t string view.
///
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv);
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string_view source_path = {});
/// \brief Parses a TOML document from a char8_t string view.
///
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv, "foo.toml");
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse(std::u8string_view doc, std::string && source_path);
/// \brief Parses a TOML document from a file.
///
/// \detail \cpp
/// toml::parse_result get_foo_toml()
/// {
/// return toml::parse_file(u8"foo.toml");
/// }
/// \ecpp
///
/// \param file_path The TOML document to parse. Must be valid UTF-8.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse_file(std::u8string_view file_path);
#endif // TOML_HAS_CHAR8
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Parses a TOML document from a string view.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \detail \cpp
/// auto tbl = toml::parse("a = 3"sv, L"foo.toml");
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse(std::string_view doc, std::wstring_view source_path);
/// \brief Parses a TOML document from a stream.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \detail \cpp
/// std::stringstream ss;
/// ss << "a = 3"sv;
///
/// auto tbl = toml::parse(ss);
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse(std::istream & doc, std::wstring_view source_path);
/// \brief Parses a TOML document from a file.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \detail \cpp
/// toml::parse_result get_foo_toml()
/// {
/// return toml::parse_file(L"foo.toml");
/// }
/// \ecpp
///
/// \param file_path The TOML document to parse. Must be valid UTF-8.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse_file(std::wstring_view file_path);
#endif // TOML_ENABLE_WINDOWS_COMPAT
#if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
/// \brief Parses a TOML document from a char8_t string view.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv, L"foo.toml");
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse(std::u8string_view doc, std::wstring_view source_path);
#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
/// \brief Parses a TOML document from a stream.
///
/// \detail \cpp
/// std::stringstream ss;
/// ss << "a = 3"sv;
///
/// auto tbl = toml::parse(ss);
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse(std::istream & doc, std::string_view source_path = {});
/// \brief Parses a TOML document from a stream.
///
/// \detail \cpp
/// std::stringstream ss;
/// ss << "a = 3"sv;
///
/// auto tbl = toml::parse(ss, "foo.toml");
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param doc The TOML document to parse. Must be valid UTF-8.
/// \param source_path The path used to initialize each node's `source().path`.
/// If you don't have a path (or you have no intention of using paths in diagnostics)
/// then this parameter can safely be left blank.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
parse_result TOML_CALLCONV parse(std::istream & doc, std::string && source_path);
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
inline namespace literals
{
TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, lit_ex, lit_noex);
/// \brief Parses TOML data from a string literal.
///
/// \detail \cpp
/// using namespace toml::literals;
///
/// auto tbl = "a = 3"_toml;
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param str The string data. Must be valid UTF-8.
/// \param len The string length.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_ALWAYS_INLINE
parse_result operator"" _toml(const char* str, size_t len)
{
return parse(std::string_view{ str, len });
}
#if TOML_HAS_CHAR8
/// \brief Parses TOML data from a UTF-8 string literal.
///
/// \detail \cpp
/// using namespace toml::literals;
///
/// auto tbl = u8"a = 3"_toml;
/// std::cout << tbl["a"] << "\n";
/// \ecpp
///
/// \out
/// 3
/// \eout
///
/// \param str The string data. Must be valid UTF-8.
/// \param len The string length.
///
/// \returns \conditional_return{With exceptions}
/// A toml::table.
/// \conditional_return{Without exceptions}
/// A toml::parse_result.
TOML_NODISCARD
TOML_ALWAYS_INLINE
parse_result operator"" _toml(const char8_t* str, size_t len)
{
return parse(std::u8string_view{ str, len });
}
#endif // TOML_HAS_CHAR8
TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS
}
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_PARSER

3917
lib/toml++/impl/parser.inl Normal file

File diff suppressed because it is too large Load Diff

851
lib/toml++/impl/path.h Normal file
View File

@ -0,0 +1,851 @@
//# 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 "forward_declarations.h"
#include "std_vector.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief Indicates type of path component, either a key, an index in an array, or invalid
enum class TOML_CLOSED_ENUM path_component_type : uint8_t
{
key = 0x1,
array_index = 0x2
};
/// \brief Represents a single component of a complete 'TOML-path': either a key or an array index
class TOML_EXPORTED_CLASS path_component
{
/// \cond
struct storage_t
{
static constexpr size_t size =
(sizeof(size_t) < sizeof(std::string) ? sizeof(std::string) : sizeof(size_t));
static constexpr size_t align =
(alignof(size_t) < alignof(std::string) ? alignof(std::string) : alignof(size_t));
alignas(align) unsigned char bytes[size];
};
alignas(storage_t::align) mutable storage_t value_storage_;
path_component_type type_;
TOML_PURE_GETTER
TOML_EXPORTED_STATIC_FUNCTION
static bool TOML_CALLCONV equal(const path_component&, const path_component&) noexcept;
template <typename Type>
TOML_PURE_INLINE_GETTER
static Type* get_as(storage_t& s) noexcept
{
return TOML_LAUNDER(reinterpret_cast<Type*>(s.bytes));
}
static void store_key(std::string_view key, storage_t& storage_)
{
::new (static_cast<void*>(storage_.bytes)) std::string{ key };
}
static void store_index(size_t index, storage_t& storage_) noexcept
{
::new (static_cast<void*>(storage_.bytes)) std::size_t{ index };
}
void destroy() noexcept
{
if (type_ == path_component_type::key)
get_as<std::string>(value_storage_)->~basic_string();
}
TOML_NODISCARD
size_t& index_ref() noexcept
{
TOML_ASSERT_ASSUME(type_ == path_component_type::array_index);
return *get_as<size_t>(value_storage_);
}
TOML_NODISCARD
std::string& key_ref() noexcept
{
TOML_ASSERT_ASSUME(type_ == path_component_type::key);
return *get_as<std::string>(value_storage_);
}
/// \endcond
public:
/// \brief Default constructor (creates an empty key).
TOML_NODISCARD_CTOR
TOML_EXPORTED_MEMBER_FUNCTION
path_component();
/// \brief Constructor for a path component that is an array index
TOML_NODISCARD_CTOR
TOML_EXPORTED_MEMBER_FUNCTION
path_component(size_t index) noexcept;
/// \brief Constructor for a path component that is a key string
TOML_NODISCARD_CTOR
TOML_EXPORTED_MEMBER_FUNCTION
path_component(std::string_view key);
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Constructor for a path component that is a key string
///
/// \availability This constructor is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD_CTOR
TOML_EXPORTED_MEMBER_FUNCTION
path_component(std::wstring_view key);
#endif
/// \brief Copy constructor.
TOML_NODISCARD_CTOR
TOML_EXPORTED_MEMBER_FUNCTION
path_component(const path_component& pc);
/// \brief Move constructor.
TOML_NODISCARD_CTOR
TOML_EXPORTED_MEMBER_FUNCTION
path_component(path_component&& pc) noexcept;
/// \brief Copy-assignment operator.
TOML_EXPORTED_MEMBER_FUNCTION
path_component& operator=(const path_component& rhs);
/// \brief Move-assignment operator.
TOML_EXPORTED_MEMBER_FUNCTION
path_component& operator=(path_component&& rhs) noexcept;
/// \brief Assigns an array index to this path component.
TOML_EXPORTED_MEMBER_FUNCTION
path_component& operator=(size_t new_index) noexcept;
/// \brief Assigns a path key to this path component.
TOML_EXPORTED_MEMBER_FUNCTION
path_component& operator=(std::string_view new_key);
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Assigns a path key to this path component.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_EXPORTED_MEMBER_FUNCTION
path_component& operator=(std::wstring_view new_key);
#endif
/// \brief Destructor.
~path_component() noexcept
{
destroy();
}
/// \name Array index accessors
/// \warning It is undefined behaviour to call these functions when the path component does not represent an array index.
/// Check #type() to determine the component's value type.
/// @{
/// \brief Returns the array index (const lvalue overload).
TOML_PURE_GETTER
size_t index() const noexcept
{
TOML_ASSERT_ASSUME(type_ == path_component_type::array_index);
return *get_as<const size_t>(value_storage_);
}
/// \brief Returns the array index (const lvalue).
TOML_PURE_INLINE_GETTER
explicit operator size_t() const noexcept
{
return index();
}
/// @}
/// \name Key accessors
/// \warning It is undefined behaviour to call these functions when the path component does not represent a key.
/// Check #type() to determine the component's value type.
/// @{
/// \brief Returns the key string.
TOML_PURE_GETTER
const std::string& key() const noexcept
{
TOML_ASSERT_ASSUME(type_ == path_component_type::key);
return *get_as<const std::string>(value_storage_);
}
/// \brief Returns the key string.
TOML_PURE_INLINE_GETTER
explicit operator const std::string&() const noexcept
{
return key();
}
/// @}
/// \brief Retrieve the type of this path component, either path_component::key or path_component::array_index
TOML_PURE_INLINE_GETTER
path_component_type type() const noexcept
{
return type_;
}
/// \name Equality
/// @{
/// \brief Returns true if two path components represent the same key or array index.
TOML_PURE_INLINE_GETTER
friend bool operator==(const path_component& lhs, const path_component& rhs) noexcept
{
return equal(lhs, rhs);
}
/// \brief Returns true if two path components do not represent the same key or array index.
TOML_PURE_INLINE_GETTER
friend bool operator!=(const path_component& lhs, const path_component& rhs) noexcept
{
return !equal(lhs, rhs);
}
/// @}
};
/// \brief A TOML path.
///
/// \detail This type parses and represents a path to a TOML node. It validates
/// the syntax of the path but does not ensure that the path refers to
/// a valid node in any particular TOML document. If parsing fails,
/// the object will evaluate as 'falsy', and will be empty.
///
/// \cpp
/// toml::path the_path("animals.cats[1]");
///
/// // can use with tbl.at_path or operator[]
/// std::cout << "second cat: " << tbl[the_path] << "\n";
/// std::cout << "cats: " << tbl.at_path(the_path.parent_path()) << "\n";
/// \ecpp
///
/// \out
/// second cat: lion
/// cats: ['tiger', 'lion', 'puma']
/// \eout
class TOML_EXPORTED_CLASS path
{
private:
/// \cond
std::vector<path_component> components_;
TOML_EXPORTED_MEMBER_FUNCTION
void print_to(std::ostream&) const;
TOML_PURE_GETTER
TOML_EXPORTED_STATIC_FUNCTION
static bool TOML_CALLCONV equal(const path&, const path&) noexcept;
/// \endcond
public:
/// \brief Default constructor.
TOML_NODISCARD_CTOR
path() noexcept = default;
/// \brief Construct a path by parsing from a string.
TOML_NODISCARD_CTOR
TOML_EXPORTED_MEMBER_FUNCTION
explicit path(std::string_view);
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Construct a path by parsing from a string.
///
/// \availability This constructor is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD_CTOR
TOML_EXPORTED_MEMBER_FUNCTION
explicit path(std::wstring_view);
#endif
/// \brief Default destructor.
~path() noexcept = default;
/// \brief Copy constructor.
TOML_NODISCARD_CTOR
path(const path&) = default;
/// \brief Move constructor.
TOML_NODISCARD_CTOR
path(path&&) noexcept = default;
/// \brief Returns the number of components in the path.
TOML_PURE_INLINE_GETTER
size_t size() const noexcept
{
return components_.size();
}
/// \brief Returns true if the path has one or more components.
TOML_PURE_INLINE_GETTER
explicit operator bool() const noexcept
{
return !components_.empty();
}
/// \brief Whether (true) or not (false) the path is empty
TOML_PURE_INLINE_GETTER
bool empty() const noexcept
{
return components_.empty();
}
/// \brief Fetch a path component by index.
TOML_PURE_INLINE_GETTER
path_component& operator[](size_t index) noexcept
{
TOML_ASSERT(index < size());
return components_[index];
}
/// \brief Fetch a path component by index (const overload).
TOML_PURE_INLINE_GETTER
const path_component& operator[](size_t index) const noexcept
{
TOML_ASSERT(index < size());
return components_[index];
}
/// \name Assignment
/// @{
/// \brief Copy-assignment operator.
path& operator=(const path&) = default;
/// \brief Move-assignment operator.
path& operator=(path&&) noexcept = default;
/// \brief Replaces the contents of the path by parsing from a string.
TOML_EXPORTED_MEMBER_FUNCTION
path& operator=(std::string_view);
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Replaces the contents of the path by parsing from a string.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_EXPORTED_MEMBER_FUNCTION
path& operator=(std::wstring_view);
#endif
/// \brief Replaces the contents of the path with that of another.
TOML_ALWAYS_INLINE
path& assign(const path& p)
{
return *this = p;
}
/// \brief Replaces the contents of the path with that of another.
TOML_ALWAYS_INLINE
path& assign(path&& p) noexcept
{
return *this = std::move(p);
}
/// \brief Replaces the contents of the path object by a new path
TOML_ALWAYS_INLINE
path& assign(std::string_view str)
{
return *this = str;
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Replaces the contents of the path object by a new path
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_ALWAYS_INLINE
path& assign(std::wstring_view str)
{
return *this = str;
}
#endif
/// @}
/// \name Appending
/// @{
/// \brief Appends another path onto the end of this one.
TOML_EXPORTED_MEMBER_FUNCTION
path& operator+=(const path&);
/// \brief Appends another path onto the end of this one.
TOML_EXPORTED_MEMBER_FUNCTION
path& operator+=(path&&);
/// \brief Parses a path and appends it onto the end of this one.
TOML_EXPORTED_MEMBER_FUNCTION
path& operator+=(std::string_view);
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Parses a path and appends it onto the end of this one.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_EXPORTED_MEMBER_FUNCTION
path& operator+=(std::wstring_view);
#endif
/// \brief Appends another path onto the end of this one.
TOML_ALWAYS_INLINE
path& append(const path& p)
{
return *this += p;
}
/// \brief Appends another path onto the end of this one.
TOML_ALWAYS_INLINE
path& append(path&& p)
{
return *this += std::move(p);
}
/// \brief Parses a path and appends it onto the end of this one.
TOML_ALWAYS_INLINE
path& append(std::string_view str)
{
return *this += str;
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Parses a path and appends it onto the end of this one.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_ALWAYS_INLINE
path& append(std::wstring_view str)
{
return *this += str;
}
#endif
/// @}
/// \name Prepending
/// @{
/// \brief Prepends another path onto the beginning of this one.
TOML_EXPORTED_MEMBER_FUNCTION
path& prepend(const path&);
/// \brief Prepends another path onto the beginning of this one.
TOML_EXPORTED_MEMBER_FUNCTION
path& prepend(path&&);
/// \brief Parses a path and prepends it onto the beginning of this one.
TOML_EXPORTED_MEMBER_FUNCTION
path& prepend(std::string_view);
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Parses a path and prepends it onto the beginning of this one.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_EXPORTED_MEMBER_FUNCTION
path& prepend(std::wstring_view);
#endif
/// @}
/// \name Concatenation
/// @{
/// \brief Concatenates two paths.
TOML_NODISCARD
friend path operator+(const path& lhs, const path& rhs)
{
path result = lhs;
result += rhs;
return result;
}
/// \brief Concatenates two paths.
TOML_NODISCARD
friend path operator+(const path& lhs, std::string_view rhs)
{
path result = lhs;
result += rhs;
return result;
}
/// \brief Concatenates two paths.
TOML_NODISCARD
friend path operator+(std::string_view lhs, const path& rhs)
{
path result = rhs;
result.prepend(lhs);
return result;
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Concatenates two paths.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD
friend path operator+(const path& lhs, std::wstring_view rhs)
{
path result = lhs;
result += rhs;
return result;
}
/// \brief Concatenates two paths.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD
friend path operator+(std::wstring_view lhs, const path& rhs)
{
path result = rhs;
result.prepend(lhs);
return result;
}
#endif
/// @}
/// \name String conversion
/// @{
/// \brief Prints the string representation of a #toml::path out to a stream.
TOML_ALWAYS_INLINE
friend std::ostream& operator<<(std::ostream& os, const path& rhs)
{
rhs.print_to(os);
return os;
}
/// \brief Returns a string representation of this path.
TOML_NODISCARD
TOML_EXPORTED_MEMBER_FUNCTION
std::string str() const;
/// \brief Returns a string representation of this path.
TOML_NODISCARD
TOML_ALWAYS_INLINE
explicit operator std::string() const
{
return str();
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Returns a string representation of this path.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD
TOML_EXPORTED_MEMBER_FUNCTION
std::wstring wide_str() const;
/// \brief Returns a string representation of this path.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD
TOML_ALWAYS_INLINE
explicit operator std::wstring() const
{
return wide_str();
}
#endif
/// @}
/// \name Equality
/// @{
/// \brief Returns whether two paths are the same.
TOML_PURE_INLINE_GETTER
friend bool operator==(const path& lhs, const path& rhs) noexcept
{
return equal(lhs, rhs);
}
/// \brief Returns whether two paths are not the same.
TOML_PURE_INLINE_GETTER
friend bool operator!=(const path& lhs, const path& rhs) noexcept
{
return !equal(lhs, rhs);
}
/// \brief Returns whether two paths are the same.
TOML_NODISCARD
TOML_ALWAYS_INLINE
friend bool operator==(const path& lhs, std::string_view rhs)
{
return lhs == path{ rhs };
}
/// \brief Returns whether two paths are the same.
TOML_NODISCARD
TOML_ALWAYS_INLINE
friend bool operator==(std::string_view lhs, const path& rhs)
{
return rhs == lhs;
}
/// \brief Returns whether two paths are not the same.
TOML_NODISCARD
TOML_ALWAYS_INLINE
friend bool operator!=(const path& lhs, std::string_view rhs)
{
return lhs != path{ rhs };
}
/// \brief Returns whether two paths are not the same.
TOML_NODISCARD
TOML_ALWAYS_INLINE
friend bool operator!=(std::string_view lhs, const path& rhs)
{
return rhs != lhs;
}
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief Returns whether two paths are the same.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD
TOML_ALWAYS_INLINE
friend bool operator==(const path& lhs, std::wstring_view rhs)
{
return lhs == path{ rhs };
}
/// \brief Returns whether two paths are the same.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD
TOML_ALWAYS_INLINE
friend bool operator==(std::wstring_view lhs, const path& rhs)
{
return rhs == lhs;
}
/// \brief Returns whether two paths are not the same.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD
TOML_ALWAYS_INLINE
friend bool operator!=(const path& lhs, std::wstring_view rhs)
{
return lhs != path{ rhs };
}
/// \brief Returns whether two paths are not the same.
///
/// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD
TOML_ALWAYS_INLINE
friend bool operator!=(std::wstring_view lhs, const path& rhs)
{
return rhs != lhs;
}
#endif // TOML_ENABLE_WINDOWS_COMPAT
/// @}
/// \name Iteration
/// @{
/// An iterator for iterating over the components in the path.
/// \see #toml::path_component
using iterator = std::vector<path_component>::iterator;
/// A const iterator for iterating over the components in the path.
/// \see #toml::path_component
using const_iterator = std::vector<path_component>::const_iterator;
/// \brief Returns an iterator to the first component in the path.
/// \see #toml::path_component
TOML_PURE_INLINE_GETTER
iterator begin() noexcept
{
return components_.begin();
}
/// \brief Returns an iterator to one-past-the-last component in the path.
/// \see #toml::path_component
TOML_PURE_INLINE_GETTER
iterator end() noexcept
{
return components_.end();
}
/// \brief Returns a const iterator to the first component in the path.
/// \see #toml::path_component
TOML_PURE_INLINE_GETTER
const_iterator begin() const noexcept
{
return components_.begin();
}
/// \brief Returns a const iterator to one-past-the-last component in the path.
/// \see #toml::path_component
TOML_PURE_INLINE_GETTER
const_iterator end() const noexcept
{
return components_.end();
}
/// \brief Returns a const iterator to the first component in the path.
/// \see #toml::path_component
TOML_PURE_INLINE_GETTER
const_iterator cbegin() const noexcept
{
return components_.begin();
}
/// \brief Returns a const iterator to one-past-the-last component in the path.
/// \see #toml::path_component
TOML_PURE_INLINE_GETTER
const_iterator cend() const noexcept
{
return components_.end();
}
/// @}
/// \name Subpaths and Truncation
/// @{
/// \brief Erases the contents of the path.
TOML_EXPORTED_MEMBER_FUNCTION
void clear() noexcept;
/// \brief Removes the number of terminal path components specified by n
TOML_EXPORTED_MEMBER_FUNCTION
path& truncate(size_t n);
/// \brief Returns a toml::path object which has had n terminal path components removed
TOML_NODISCARD
TOML_EXPORTED_MEMBER_FUNCTION
path truncated(size_t n) const;
/// \brief Returns a toml::path object representing the path of the parent node
TOML_NODISCARD
TOML_EXPORTED_MEMBER_FUNCTION
path parent() const;
/// \brief Returns a toml::path object representing terminal n-parts of a TOML path
TOML_NODISCARD
TOML_EXPORTED_MEMBER_FUNCTION
path leaf(size_t n = 1) const;
/// \brief Returns a toml::path object that is a specified subpath of the current path, representing the
/// range of path components from [start, end).
TOML_NODISCARD
TOML_EXPORTED_MEMBER_FUNCTION
path subpath(const_iterator start, const_iterator end) const;
/// \brief Returns a toml::path object that is a specified subpath of the current path, representing the
/// range of path components with indexes from [start, start + length].
TOML_NODISCARD
TOML_EXPORTED_MEMBER_FUNCTION
path subpath(size_t start, size_t length) const;
/// @}
};
inline namespace literals
{
/// \brief Parses a TOML path from a string literal.
///
/// \detail \cpp
/// using namespace toml::literals;
///
/// auto path = "main.settings.devices[2]"_tpath;
/// std::cout << path.parent_path() << "\n";
/// \ecpp
///
/// \out
/// main.settings.devices
/// \eout
///
/// \param str The string data.
/// \param len The string length.
///
/// \returns A #toml::path generated from the string literal.
TOML_NODISCARD
TOML_ALWAYS_INLINE
path operator"" _tpath(const char* str, size_t len)
{
return path(std::string_view{ str, len });
}
}
/// \brief Returns a view of the node matching a fully-qualified "TOML path".
///
/// \detail \cpp
/// auto config = toml::parse(R"(
///
/// [foo]
/// bar = [ 0, 1, 2, [ 3 ], { kek = 4 } ]
///
/// )"sv);
///
/// toml::path path1("foo.bar[2]");
/// toml::path path2("foo.bar[4].kek");
/// std::cout << toml::at_path(config, path1) << "\n";
/// std::cout << toml::at_path(config, path1.parent_path()) << "\n";
/// std::cout << toml::at_path(config, path2) << "\n";
/// std::cout << toml::at_path(config, path2.parent_path()) << "\n";
/// \ecpp
///
/// \out
/// 2
/// [ 0, 1, 2, [ 3 ], { kek = 4 } ]
/// 4
/// { kek = 4 }
/// \eout
///
///
/// \note Keys in paths are interpreted literally, so whitespace (or lack thereof) matters:
/// \cpp
/// toml::at_path(config, toml::path("foo.bar")) // same as config["foo"]["bar"]
/// toml::at_path(config, toml::path("foo. bar")) // same as config["foo"][" bar"]
/// toml::at_path(config, toml::path("foo..bar")) // same as config["foo"][""]["bar"]
/// toml::at_path(config, toml::path(".foo.bar")) // same as config[""]["foo"]["bar"]
/// \ecpp
/// <br>
/// Additionally, TOML allows '.' (period) characters to appear in keys if they are quoted strings.
/// This function makes no allowance for this, instead treating all period characters as sub-table delimiters.
///
/// \param root The root node from which the path will be traversed.
/// \param path The "TOML path" to traverse.
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
node_view<node> TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept;
/// \brief Returns a const view of the node matching a fully-qualified "TOML path".
///
/// \see #toml::at_path(node&, const toml::path& path)
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
node_view<const node> TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept;
}
TOML_NAMESPACE_END;
#include "header_end.h"

523
lib/toml++/impl/path.inl Normal file
View File

@ -0,0 +1,523 @@
//# 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.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "path.h"
#include "at_path.h"
#include "print_to_stream.h"
TOML_DISABLE_WARNINGS;
#if TOML_INT_CHARCONV
#include <charconv>
#endif
#include <sstream>
TOML_ENABLE_WARNINGS;
#include "header_start.h"
//#=====================================================================================================================
//# 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))
{}
#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;
}
#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_);
}
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_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_);
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_EXTERNAL_LINKAGE
path::path(std::wstring_view str) //
: path(impl::narrow(str))
{}
#endif
//#=== assignment =================================================
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));
}
#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;
}
#if TOML_ENABLE_WINDOWS_COMPAT
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 });
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_EXTERNAL_LINKAGE
path& path::prepend(std::wstring_view source)
{
return prepend(impl::narrow(source));
}
#endif
//#=== string conversion =================================================
TOML_EXTERNAL_LINKAGE
std::string path::str() const
{
if (empty())
return "";
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());
}
#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));
}
}
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() };
}
}
TOML_NAMESPACE_END;
#include "header_end.h"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,129 @@
//# 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 "std_string.h"
#include "forward_declarations.h"
#include "header_start.h"
TOML_IMPL_NAMESPACE_START
{
// Q: "why does print_to_stream() exist? why not just use ostream::write(), ostream::put() etc?"
// A: - I'm using <charconv> to format numerics. Faster and locale-independent.
// - I can (potentially) avoid forcing users to drag in <sstream> and <iomanip>.
// - Strings in C++. Honestly.
TOML_EXPORTED_FREE_FUNCTION
TOML_ATTR(nonnull)
void TOML_CALLCONV print_to_stream(std::ostream&, const char*, size_t);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, std::string_view);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const std::string&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, char);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, signed char, value_flags = {}, size_t min_digits = 0);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, signed short, value_flags = {}, size_t min_digits = 0);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, signed int, value_flags = {}, size_t min_digits = 0);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, signed long, value_flags = {}, size_t min_digits = 0);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, signed long long, value_flags = {}, size_t min_digits = 0);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, unsigned char, value_flags = {}, size_t min_digits = 0);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, unsigned short, value_flags = {}, size_t min_digits = 0);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, unsigned int, value_flags = {}, size_t min_digits = 0);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, unsigned long, value_flags = {}, size_t min_digits = 0);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, unsigned long long, value_flags = {}, size_t min_digits = 0);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, float, value_flags = {}, bool relaxed_precision = false);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, double, value_flags = {}, bool relaxed_precision = false);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, bool);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const toml::date&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const toml::time&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const toml::time_offset&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const toml::date_time&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const source_position&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const source_region&);
#if TOML_ENABLE_FORMATTERS
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const array&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const table&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const value<std::string>&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const value<int64_t>&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const value<double>&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const value<bool>&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const value<date>&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const value<time>&);
TOML_EXPORTED_FREE_FUNCTION
void TOML_CALLCONV print_to_stream(std::ostream&, const value<date_time>&);
#endif
template <typename T, typename U>
inline void print_to_stream_bookended(std::ostream & stream, const T& val, const U& bookend)
{
print_to_stream(stream, bookend);
print_to_stream(stream, val);
print_to_stream(stream, bookend);
}
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.h"

View File

@ -0,0 +1,490 @@
//# 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.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "print_to_stream.h"
#include "source_region.h"
#include "date_time.h"
#include "toml_formatter.h"
#include "value.h"
#include "array.h"
#include "table.h"
TOML_DISABLE_WARNINGS;
#include <ostream>
#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
#include <charconv>
#endif
#if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
#include <sstream>
#endif
#if !TOML_INT_CHARCONV
#include <iomanip>
#endif
TOML_ENABLE_WARNINGS;
#include "header_start.h"
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<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<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<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<uint64_t> = 20; // strlen("18446744073709551615")
template <>
inline constexpr size_t charconv_buffer_length<float> = 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;
for (size_t i = 0; i < min_digits; i++)
stream.put('0');
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;
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);
#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);
}
#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;
};
#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);
#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);
#endif
}
break;
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('\'');
}
}
#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 };
}
#endif
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.h"

35
lib/toml++/impl/simd.h Normal file
View File

@ -0,0 +1,35 @@
//# 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.h"
#if TOML_ENABLE_SIMD
#if defined(__SSE2__) \
|| (defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)))
#define TOML_HAS_SSE2 1
#endif
#if defined(__SSE4_1__) || (defined(_MSC_VER) && (defined(__AVX__) || defined(__AVX2__)))
#define TOML_HAS_SSE4_1 1
#endif
#endif // TOML_ENABLE_SIMD
#ifndef TOML_HAS_SSE2
#define TOML_HAS_SSE2 0
#endif
#ifndef TOML_HAS_SSE4_1
#define TOML_HAS_SSE4_1 0
#endif
TOML_DISABLE_WARNINGS;
#if TOML_HAS_SSE4_1
#include <smmintrin.h>
#endif
#if TOML_HAS_SSE2
#include <emmintrin.h>
#endif
TOML_ENABLE_WARNINGS;

View File

@ -0,0 +1,223 @@
//# 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 "std_optional.h"
#include "std_string.h"
#include "forward_declarations.h"
#include "print_to_stream.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief The integer type used to tally line numbers and columns.
using source_index = uint32_t;
/// \brief A pointer to a shared string resource containing a source path.
using source_path_ptr = std::shared_ptr<const std::string>;
/// \brief A source document line-and-column pair.
///
/// \detail \cpp
/// auto table = toml::parse_file("config.toml"sv);
/// std::cout << "The node 'description' was defined at "sv
/// << table.get("description")->source().begin()
/// << "\n";
/// \ecpp
///
/// \out
/// The value 'description' was defined at line 7, column 15
/// \eout
///
/// \remarks toml++'s parser is unicode-aware insofar as it knows how to handle
/// non-ASCII whitespace and newline characters, but it doesn't give much thought
/// to combining marks, grapheme clusters vs. characters, et cetera.
/// If a TOML document contains lots of codepoints outside of the ASCII range
/// you may find that your source_positions don't match those given by a text editor
/// (typically the line numbers will be accurate but column numbers will be too high).
/// <strong>This is not an error.</strong> I've chosen this behaviour as a deliberate trade-off
/// between parser complexity and correctness.
struct TOML_TRIVIAL_ABI source_position
{
/// \brief The line number.
/// \remarks Valid line numbers start at 1.
source_index line;
/// \brief The column number.
/// \remarks Valid column numbers start at 1.
source_index column;
/// \brief Returns true if both line and column numbers are non-zero.
TOML_PURE_GETTER
explicit constexpr operator bool() const noexcept
{
return line > source_index{} //
&& column > source_index{};
}
/// \brief Equality operator.
TOML_PURE_GETTER
friend constexpr bool operator==(const source_position& lhs, const source_position& rhs) noexcept
{
return lhs.line == rhs.line //
&& lhs.column == rhs.column;
}
/// \brief Inequality operator.
TOML_PURE_INLINE_GETTER
friend constexpr bool operator!=(const source_position& lhs, const source_position& rhs) noexcept
{
return !(lhs == rhs);
}
private:
/// \cond
TOML_PURE_GETTER
static constexpr uint64_t pack(const source_position& pos) noexcept
{
return static_cast<uint64_t>(pos.line) << 32 | static_cast<uint64_t>(pos.column);
}
/// \endcond
public:
/// \brief Less-than operator.
TOML_PURE_GETTER
friend constexpr bool operator<(const source_position& lhs, const source_position& rhs) noexcept
{
return pack(lhs) < pack(rhs);
}
/// \brief Less-than-or-equal-to operator.
TOML_PURE_GETTER
friend constexpr bool operator<=(const source_position& lhs, const source_position& rhs) noexcept
{
return pack(lhs) <= pack(rhs);
}
/// \brief Greater-than operator.
TOML_PURE_GETTER
friend constexpr bool operator>(const source_position& lhs, const source_position& rhs) noexcept
{
return pack(lhs) > pack(rhs);
}
/// \brief Greater-than-or-equal-to operator.
TOML_PURE_GETTER
friend constexpr bool operator>=(const source_position& lhs, const source_position& rhs) noexcept
{
return pack(lhs) >= pack(rhs);
}
/// \brief Prints a source_position to a stream.
///
/// \detail \cpp
/// auto tbl = toml::parse("bar = 42"sv);
///
/// std::cout << "The value for 'bar' was found on "sv
/// << tbl.get("bar")->source().begin()
/// << "\n";
/// \ecpp
///
/// \out
/// The value for 'bar' was found on line 1, column 7
/// \eout
///
/// \param lhs The stream.
/// \param rhs The source_position.
///
/// \returns The input stream.
friend std::ostream& operator<<(std::ostream& lhs, const source_position& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
/// \brief A source document region.
///
/// \detail \cpp
/// auto tbl = toml::parse_file("config.toml"sv);
/// if (auto server = tbl.get("server"))
/// {
/// std::cout << "begin: "sv << server->source().begin << "\n";
/// std::cout << "end: "sv << server->source().end << "\n";
/// std::cout << "path: "sv << *server->source().path << "\n";
/// }
/// \ecpp
///
/// \out
/// begin: line 3, column 1
/// end: line 3, column 22
/// path: config.toml
/// \eout
///
/// \remarks toml++'s parser is unicode-aware insofar as it knows how to handle
/// non-ASCII whitespace and newline characters, but it doesn't give much thought
/// to combining marks, grapheme clusters vs. characters, et cetera.
/// If a TOML document contains lots of codepoints outside of the ASCII range
/// you may find that your source_positions don't match those given by a text editor
/// (typically the line numbers will be accurate but column numbers will be too high).
/// <strong>This is not an error.</strong> I've chosen this behaviour as a deliberate trade-off
/// between parser complexity and correctness.
struct source_region
{
/// \brief The beginning of the region (inclusive).
source_position begin;
/// \brief The end of the region (exclusive).
source_position end;
/// \brief The path to the corresponding source document.
///
/// \remarks This will be `nullptr` if no path was provided to toml::parse().
source_path_ptr path;
#if TOML_ENABLE_WINDOWS_COMPAT
/// \brief The path to the corresponding source document as a wide-string.
///
/// \availability This function is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
///
/// \remarks This will return an empty optional if no path was provided to toml::parse().
TOML_NODISCARD
optional<std::wstring> wide_path() const
{
if (!path || path->empty())
return {};
return { impl::widen(*path) };
}
#endif
/// \brief Prints a source_region to a stream.
///
/// \detail \cpp
/// auto tbl = toml::parse("bar = 42", "config.toml");
///
/// std::cout << "The value for 'bar' was found on "sv
/// << tbl.get("bar")->source()
/// << "\n";
/// \ecpp
///
/// \out
/// The value for 'bar' was found on line 1, column 7 of 'config.toml'
/// \eout
///
/// \param lhs The stream.
/// \param rhs The source_position.
///
/// \returns The input stream.
friend std::ostream& operator<<(std::ostream& lhs, const source_region& rhs)
{
impl::print_to_stream(lhs, rhs);
return lhs;
}
};
}
TOML_NAMESPACE_END;
#include "header_end.h"

View File

@ -0,0 +1,12 @@
//# 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.h"
TOML_DISABLE_WARNINGS;
#if TOML_EXCEPTIONS
#include <stdexcept>
#endif
TOML_ENABLE_WARNINGS;

View File

@ -0,0 +1,10 @@
//# 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.h"
TOML_DISABLE_WARNINGS;
#include <initializer_list>
TOML_ENABLE_WARNINGS;

11
lib/toml++/impl/std_map.h Normal file
View File

@ -0,0 +1,11 @@
//# 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.h"
TOML_DISABLE_WARNINGS;
#include <map>
#include <iterator>
TOML_ENABLE_WARNINGS;

18
lib/toml++/impl/std_new.h Normal file
View File

@ -0,0 +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
#pragma once
#include "preprocessor.h"
TOML_DISABLE_WARNINGS;
#include <new>
TOML_ENABLE_WARNINGS;
#if (!defined(__apple_build_version__) && TOML_CLANG >= 8) || TOML_GCC >= 7 || TOML_ICC >= 1910 || TOML_MSVC >= 1914
#define TOML_LAUNDER(x) __builtin_launder(x)
#elif defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
#define TOML_LAUNDER(x) std::launder(x)
#else
#define TOML_LAUNDER(x) x
#endif

View File

@ -0,0 +1,32 @@
//# 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.h"
TOML_DISABLE_WARNINGS;
#if !TOML_HAS_CUSTOM_OPTIONAL_TYPE
#include <optional>
#endif
TOML_ENABLE_WARNINGS;
TOML_NAMESPACE_START
{
#if TOML_HAS_CUSTOM_OPTIONAL_TYPE
template <typename T>
using optional = TOML_OPTIONAL_TYPE<T>;
#else
/// \brief The 'optional' type used throughout the library.
///
/// \remarks By default this will be an alias for std::optional, but you can change the optional type
/// used by the library by defining #TOML_OPTIONAL_TYPE.
template <typename T>
using optional = std::optional<T>;
#endif
}
TOML_NAMESPACE_END;

View File

@ -0,0 +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
#pragma once
#include "preprocessor.h"
TOML_DISABLE_WARNINGS;
#include <string_view>
#include <string>
TOML_ENABLE_WARNINGS;
#if TOML_DOXYGEN \
|| (defined(__cpp_char8_t) && __cpp_char8_t >= 201811 && defined(__cpp_lib_char8_t) \
&& __cpp_lib_char8_t >= 201907)
#define TOML_HAS_CHAR8 1
#else
#define TOML_HAS_CHAR8 0
#endif
/// \cond
namespace toml // non-abi namespace; this is not an error
{
using namespace std::string_literals;
using namespace std::string_view_literals;
}
#if TOML_ENABLE_WINDOWS_COMPAT
TOML_IMPL_NAMESPACE_START
{
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
std::string narrow(std::wstring_view);
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
std::wstring widen(std::string_view);
#if TOML_HAS_CHAR8
TOML_NODISCARD
TOML_EXPORTED_FREE_FUNCTION
std::wstring widen(std::u8string_view);
#endif
}
TOML_IMPL_NAMESPACE_END;
#endif // TOML_ENABLE_WINDOWS_COMPAT
/// \endcond

View File

@ -0,0 +1,99 @@
//# 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.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_WINDOWS
#include "std_string.h"
#ifndef _WINDOWS_
#if TOML_INCLUDE_WINDOWS_H
#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 MultiByteToWideChar(unsigned int CodePage,
unsigned long dwFlags,
const char* lpMultiByteStr,
int cbMultiByte,
wchar_t* lpWideCharStr,
int cchWideChar);
#endif // TOML_INCLUDE_WINDOWS_H
#endif // _WINDOWS_
#include "header_start.h"
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;
}
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;
}
#if TOML_HAS_CHAR8
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() });
}
#endif // TOML_HAS_CHAR8
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_WINDOWS

View File

@ -0,0 +1,10 @@
//# 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.h"
TOML_DISABLE_WARNINGS;
#include <utility>
TOML_ENABLE_WARNINGS;

View File

@ -0,0 +1,10 @@
//# 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.h"
TOML_DISABLE_WARNINGS;
#include <variant>
TOML_ENABLE_WARNINGS;

View File

@ -0,0 +1,11 @@
//# 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.h"
TOML_DISABLE_WARNINGS;
#include <vector>
#include <iterator>
TOML_ENABLE_WARNINGS;

1961
lib/toml++/impl/table.h Normal file

File diff suppressed because it is too large Load Diff

318
lib/toml++/impl/table.inl Normal file
View File

@ -0,0 +1,318 @@
//# 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.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "table.h"
#include "node_view.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
table::table() noexcept
{
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
table::~table() noexcept
{
#if TOML_LIFETIME_HOOKS
TOML_TABLE_DESTROYED;
#endif
}
TOML_EXTERNAL_LINKAGE
table::table(const impl::table_init_pair* b, const impl::table_init_pair* e)
{
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
TOML_ASSERT_ASSUME(b);
TOML_ASSERT_ASSUME(e);
TOML_ASSERT_ASSUME(b <= e);
if TOML_UNLIKELY(b == e)
return;
for (; b != e; b++)
{
if (!b->value) // empty node_views
continue;
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));
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
}
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;
#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);
#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 };
}
#else
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;
}
}
TOML_NAMESPACE_END;
#include "header_end.h"

View File

@ -0,0 +1,153 @@
//# 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.h"
#if TOML_ENABLE_FORMATTERS
#include "std_vector.h"
#include "formatter.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted TOML.
///
/// \availability This class is only available when #TOML_ENABLE_FORMATTERS is enabled.
///
/// \remarks You generally don't need to create an instance of this class explicitly; the stream
/// operators of the TOML node types already print themselves out using this formatter.
///
/// \detail \cpp
/// auto tbl = toml::table{
/// { "description", "This is some TOML, yo." },
/// { "fruit", toml::array{ "apple", "orange", "pear" } },
/// { "numbers", toml::array{ 1, 2, 3, 4, 5 } },
/// { "table", toml::table{ { "foo", "bar" } } }
/// };
///
/// // these two lines are equivalent:
/// std::cout << toml::toml_formatter{ tbl } << "\n";
/// std::cout << tbl << "\n";
/// \ecpp
///
/// \out
/// description = "This is some TOML, yo."
/// fruit = ["apple", "orange", "pear"]
/// numbers = [1, 2, 3, 4, 5]
///
/// [table]
/// foo = "bar"
/// \eout
class TOML_EXPORTED_CLASS toml_formatter : impl::formatter
{
private:
/// \cond
using base = impl::formatter;
std::vector<const key*> key_path_;
bool pending_table_separator_ = false;
TOML_EXPORTED_MEMBER_FUNCTION
void print_pending_table_separator();
TOML_EXPORTED_MEMBER_FUNCTION
void print(const key&);
TOML_EXPORTED_MEMBER_FUNCTION
void print_inline(const toml::table&);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const toml::array&);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const toml::table&);
TOML_EXPORTED_MEMBER_FUNCTION
void print();
static constexpr impl::formatter_constants constants = { format_flags::none, // mandatory
format_flags::none, // ignored
"inf"sv,
"-inf"sv,
"nan"sv,
"true"sv,
"false"sv };
/// \endcond
public:
/// \brief The default flags for a toml_formatter.
static constexpr format_flags default_flags = constants.mandatory_flags //
| format_flags::allow_literal_strings //
| format_flags::allow_multi_line_strings //
| format_flags::allow_unicode_strings //
| format_flags::allow_real_tabs_in_strings //
| format_flags::allow_binary_integers //
| format_flags::allow_octal_integers //
| format_flags::allow_hexadecimal_integers //
| format_flags::indentation;
/// \brief Constructs a TOML formatter and binds it to a TOML object.
///
/// \param source The source TOML object.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit toml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ &source, nullptr, constants, { flags, " "sv } }
{}
#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
/// \brief Constructs a TOML formatter and binds it to a toml::parse_result.
///
/// \availability This constructor is only available when exceptions are disabled.
///
/// \attention Formatting a failed parse result will simply dump the error message out as-is.
/// This will not be valid TOML, but at least gives you something to log or show up in diagnostics:
/// \cpp
/// std::cout << toml::toml_formatter{ toml::parse("a = 'b'"sv) } // ok
/// << "\n\n"
/// << toml::toml_formatter{ toml::parse("a = "sv) } // malformed
/// << "\n";
/// \ecpp
/// \out
/// a = 'b'
///
/// Error while parsing key-value pair: encountered end-of-file
/// (error occurred at line 1, column 5)
/// \eout
/// Use the library with exceptions if you want to avoid this scenario.
///
/// \param result The parse result.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit toml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ nullptr, &result, constants, { flags, " "sv } }
{}
#endif
/// \brief Prints the bound TOML object out to the stream as formatted TOML.
friend std::ostream& operator<<(std::ostream& lhs, toml_formatter& rhs)
{
rhs.attach(lhs);
rhs.key_path_.clear();
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as formatted TOML (rvalue overload).
friend std::ostream& operator<<(std::ostream& lhs, toml_formatter&& rhs)
{
return lhs << rhs; // as lvalue
}
};
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -0,0 +1,405 @@
//# 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.h"
//# {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_FORMATTERS
#include "toml_formatter.h"
#include "print_to_stream.h"
#include "value.h"
#include "table.h"
#include "array.h"
#include "unicode.h"
#include "header_start.h"
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_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);
}
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.h"
#endif // TOML_ENABLE_FORMATTERS

197
lib/toml++/impl/unicode.h Normal file
View File

@ -0,0 +1,197 @@
//# 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 "unicode_autogenerated.h"
#include "header_start.h"
/// \cond
TOML_IMPL_NAMESPACE_START
{
TOML_CONST_GETTER
constexpr bool is_string_delimiter(char32_t c) noexcept
{
return c == U'"' || c == U'\'';
}
TOML_CONST_GETTER
constexpr bool is_ascii_letter(char32_t c) noexcept
{
return (c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z');
}
TOML_CONST_GETTER
constexpr bool is_binary_digit(char32_t c) noexcept
{
return c == U'0' || c == U'1';
}
TOML_CONST_GETTER
constexpr bool is_octal_digit(char32_t c) noexcept
{
return (c >= U'0' && c <= U'7');
}
TOML_CONST_GETTER
constexpr bool is_decimal_digit(char32_t c) noexcept
{
return (c >= U'0' && c <= U'9');
}
TOML_CONST_GETTER
constexpr bool is_hexadecimal_digit(char32_t c) noexcept
{
return U'0' <= c && c <= U'f' && (1ull << (static_cast<uint_least64_t>(c) - 0x30u)) & 0x7E0000007E03FFull;
}
template <typename T>
TOML_CONST_GETTER
constexpr uint_least32_t hex_to_dec(const T c) noexcept
{
if constexpr (std::is_same_v<remove_cvref<T>, uint_least32_t>)
return c >= 0x41u // >= 'A'
? 10u + (c | 0x20u) - 0x61u // - 'a'
: c - 0x30u // - '0'
;
else
return hex_to_dec(static_cast<uint_least32_t>(c));
}
TOML_CONST_GETTER
constexpr bool is_horizontal_whitespace(char32_t c) noexcept
{
return is_ascii_horizontal_whitespace(c) || is_non_ascii_horizontal_whitespace(c);
}
TOML_CONST_GETTER
constexpr bool is_vertical_whitespace(char32_t c) noexcept
{
return is_ascii_vertical_whitespace(c) || is_non_ascii_vertical_whitespace(c);
}
TOML_CONST_GETTER
constexpr bool is_whitespace(char32_t c) noexcept
{
return is_horizontal_whitespace(c) || is_vertical_whitespace(c);
}
TOML_CONST_GETTER
constexpr bool is_bare_key_character(char32_t c) noexcept
{
return is_ascii_bare_key_character(c)
#if TOML_LANG_UNRELEASED // toml/pull/891 (unicode bare keys)
|| is_non_ascii_bare_key_character(c)
#endif
;
}
TOML_CONST_GETTER
constexpr bool is_value_terminator(char32_t c) noexcept
{
return is_whitespace(c) || c == U']' || c == U'}' || c == U',' || c == U'#';
}
TOML_CONST_GETTER
constexpr bool is_control_character(char c) noexcept
{
return c <= '\u001F' || c == '\u007F';
}
TOML_CONST_GETTER
constexpr bool is_control_character(char32_t c) noexcept
{
return c <= U'\u001F' || c == U'\u007F';
}
TOML_CONST_GETTER
constexpr bool is_nontab_control_character(char32_t c) noexcept
{
return c <= U'\u0008' || (c >= U'\u000A' && c <= U'\u001F') || c == U'\u007F';
}
TOML_CONST_GETTER
constexpr bool is_unicode_surrogate(char32_t c) noexcept
{
return c >= 0xD800u && c <= 0xDFFF;
}
struct utf8_decoder
{
// utf8_decoder based on this: https://bjoern.hoehrmann.de/utf-8/decoder/dfa/
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
uint_least32_t state{};
char32_t codepoint{};
static constexpr uint8_t state_table[]{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6,
6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 12,
12, 12, 12, 12, 0, 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12,
12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36, 12,
36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12
};
TOML_PURE_INLINE_GETTER
constexpr bool error() const noexcept
{
return state == uint_least32_t{ 12u };
}
TOML_PURE_INLINE_GETTER
constexpr bool has_code_point() const noexcept
{
return state == uint_least32_t{};
}
TOML_PURE_INLINE_GETTER
constexpr bool needs_more_input() const noexcept
{
return !has_code_point() && !error();
}
constexpr void operator()(uint8_t byte) noexcept
{
TOML_ASSERT_ASSUME(!error());
const auto type = state_table[byte];
codepoint = static_cast<char32_t>(has_code_point() ? (uint_least32_t{ 255u } >> type) & byte
: (byte& uint_least32_t{ 63u })
| (static_cast<uint_least32_t>(codepoint) << 6));
state = state_table[state + uint_least32_t{ 256u } + type];
}
TOML_ALWAYS_INLINE
constexpr void operator()(char c) noexcept
{
operator()(static_cast<uint8_t>(c));
}
TOML_ALWAYS_INLINE
constexpr void reset() noexcept
{
state = {};
}
};
TOML_PURE_GETTER
TOML_ATTR(nonnull)
bool is_ascii(const char* str, size_t len) noexcept;
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
#include "header_end.h"

View File

@ -0,0 +1,60 @@
//# 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.h"
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#include "unicode.h"
#include "simd.h"
#include "header_start.h"
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);
#if TOML_HAS_SSE4_1
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;
#endif
}
}
#endif
for (; str < end; str++)
if (static_cast<unsigned char>(*str) > 127u)
return false;
return true;
}
}
TOML_IMPL_NAMESPACE_END;
#include "header_end.h"

View File

@ -0,0 +1,182 @@
//# 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.h"
#include "header_start.h"
/// \cond
#if TOML_GCC && TOML_GCC < 9
#pragma GCC push_options
#pragma GCC optimize("O1") // codegen bugs
#endif
// the functions in this namespace block are automatically generated by a tool - they are not meant to be hand-edited
TOML_IMPL_NAMESPACE_START
{
TOML_CONST_GETTER
constexpr bool is_ascii_horizontal_whitespace(char32_t c) noexcept
{
return c == U'\t' || c == U' ';
}
TOML_CONST_GETTER
constexpr bool is_non_ascii_horizontal_whitespace(char32_t c) noexcept
{
// 20 code units from 8 ranges (spanning a search area of 65120)
if (c < U'\xA0' || c > U'\uFEFF')
return false;
const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0xA0ull) / 0x3FAull;
if ((1ull << child_index_0) & 0x7FFFFFFFFFFFF75Eull)
return false;
if (c == U'\xA0' || c == U'\u3000' || c == U'\uFEFF')
return true;
switch (child_index_0)
{
case 0x05: return c == U'\u1680' || c == U'\u180E';
case 0x07:
return (U'\u2000' <= c && c <= U'\u200B') || (U'\u205F' <= c && c <= U'\u2060') || c == U'\u202F';
default: TOML_UNREACHABLE;
}
TOML_UNREACHABLE;
}
TOML_CONST_GETTER
constexpr bool is_ascii_vertical_whitespace(char32_t c) noexcept
{
return c >= U'\n' && c <= U'\r';
}
TOML_CONST_GETTER
constexpr bool is_non_ascii_vertical_whitespace(char32_t c) noexcept
{
return (U'\u2028' <= c && c <= U'\u2029') || c == U'\x85';
}
TOML_CONST_GETTER
constexpr bool is_ascii_bare_key_character(char32_t c) noexcept
{
#if TOML_LANG_UNRELEASED // toml/issues/644 ('+' in bare keys)
if TOML_UNLIKELY(c == U'+')
return true;
#endif
// 64 code units from 5 ranges (spanning a search area of 78)
if (c < U'-' || c > U'z')
return false;
return (((static_cast<uint_least64_t>(c) - 0x2Dull) / 0x40ull) != 0ull)
|| ((1ull << (static_cast<uint_least64_t>(c) - 0x2Dull)) & 0xFFF43FFFFFF01FF9ull);
}
#if TOML_LANG_UNRELEASED // toml/pull/891 (unicode bare keys)
TOML_CONST_GETTER
constexpr bool is_non_ascii_bare_key_character(char32_t c) noexcept
{
// 971732 code units from 16 ranges (spanning a search area of 982862)
if (c < U'\xB2' || c > U'\U000EFFFF')
return false;
const auto child_index_0 = (static_cast<uint_least64_t>(c) - 0xB2ull) / 0x3BFEull;
if ((1ull << child_index_0) & 0xFFFFFFFFFFFFFFE6ull)
return true;
switch (child_index_0)
{
case 0x00: // [0] 00B2 - 3CAF
{
// 12710 code units from 13 ranges (spanning a search area of 15358)
TOML_ASSUME(c >= U'\xB2' && c <= U'\u3CAF');
constexpr uint_least64_t bitmask_table_1[] = {
0xFFFFFFDFFFFFDC83u, 0xFFFFFFFFFFFFFFDFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFEFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0x000000000C003FFFu, 0xC000000000006000u, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x000000003FFFFFFFu,
0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
0x0000000000000000u, 0x0000000000000000u, 0xFFFFC00000000000u, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0x0000000000003FFFu, 0x0000000000000000u, 0x0000000000000000u,
0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u,
0x0000000000000000u, 0xFFFFFFFFFFFFC000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0x3FFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFF8000u, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu,
0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0xFFFFFFFFFFFFFFFFu, 0x3FFFFFFFFFFFFFFFu,
};
return bitmask_table_1[(static_cast<uint_least64_t>(c) - 0xB2ull) / 0x40ull]
& (0x1ull << ((static_cast<uint_least64_t>(c) - 0xB2ull) % 0x40ull));
}
case 0x03: return c <= U'\uD7FF';
case 0x04:
return (U'\uF900' <= c && c <= U'\uFDCF') || (U'\uFDF0' <= c && c <= U'\uFFFD') || U'\U00010000' <= c;
default: TOML_UNREACHABLE;
}
TOML_UNREACHABLE;
}
#endif // TOML_LANG_UNRELEASED
}
TOML_IMPL_NAMESPACE_END;
#if TOML_GCC && TOML_GCC < 9
#pragma GCC pop_options
#endif
/// \endcond
#include "header_end.h"

1270
lib/toml++/impl/value.h Normal file

File diff suppressed because it is too large Load Diff

13
lib/toml++/impl/version.h Normal file
View File

@ -0,0 +1,13 @@
//# 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
#define TOML_LIB_MAJOR 3
#define TOML_LIB_MINOR 3
#define TOML_LIB_PATCH 0
#define TOML_LANG_MAJOR 1
#define TOML_LANG_MINOR 0
#define TOML_LANG_PATCH 0

View File

@ -0,0 +1,139 @@
//# 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.h"
#if TOML_ENABLE_FORMATTERS
#include "formatter.h"
#include "header_start.h"
TOML_NAMESPACE_START
{
/// \brief A wrapper for printing TOML objects out to a stream as formatted YAML.
///
/// \availability This class is only available when #TOML_ENABLE_FORMATTERS is enabled.
///
/// \detail \cpp
/// auto some_toml = toml::parse(R"(
/// [fruit]
/// apple.color = "red"
/// apple.taste.sweet = true
///
/// [fruit.apple.texture]
/// smooth = true
/// )"sv);
/// std::cout << toml::yaml_formatter{ some_toml } << "\n";
/// \ecpp
///
/// \out
/// fruit:
/// apple:
/// color: red
/// taste:
/// sweet: true
/// texture:
/// smooth: true
/// \eout
class TOML_EXPORTED_CLASS yaml_formatter : impl::formatter
{
private:
/// \cond
using base = impl::formatter;
TOML_EXPORTED_MEMBER_FUNCTION
void print_yaml_string(const value<std::string>&);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const toml::table&, bool = false);
TOML_EXPORTED_MEMBER_FUNCTION
void print(const toml::array&, bool = false);
TOML_EXPORTED_MEMBER_FUNCTION
void print();
static constexpr impl::formatter_constants constants = {
//
format_flags::quote_dates_and_times | format_flags::indentation, // mandatory
format_flags::allow_multi_line_strings, // ignored
".inf"sv,
"-.inf"sv,
".NAN"sv,
"true"sv,
"false"sv
};
/// \endcond
public:
/// \brief The default flags for a yaml_formatter.
static constexpr format_flags default_flags = constants.mandatory_flags //
| format_flags::allow_literal_strings //
| format_flags::allow_unicode_strings //
| format_flags::allow_octal_integers //
| format_flags::allow_hexadecimal_integers;
/// \brief Constructs a YAML formatter and binds it to a TOML object.
///
/// \param source The source TOML object.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit yaml_formatter(const toml::node& source, format_flags flags = default_flags) noexcept
: base{ &source, nullptr, constants, { flags, " "sv } }
{}
#if TOML_DOXYGEN || (TOML_ENABLE_PARSER && !TOML_EXCEPTIONS)
/// \brief Constructs a YAML formatter and binds it to a toml::parse_result.
///
/// \availability This constructor is only available when exceptions are disabled.
///
/// \attention Formatting a failed parse result will simply dump the error message out as-is.
/// This will not be valid YAML, but at least gives you something to log or show up in diagnostics:
/// \cpp
/// std::cout << toml::yaml_formatter{ toml::parse("a = 'b'"sv) } // ok
/// << "\n\n"
/// << toml::yaml_formatter{ toml::parse("a = "sv) } // malformed
/// << "\n";
/// \ecpp
/// \out
/// a: b
///
/// Error while parsing key-value pair: encountered end-of-file
/// (error occurred at line 1, column 5)
/// \eout
/// Use the library with exceptions if you want to avoid this scenario.
///
/// \param result The parse result.
/// \param flags Format option flags.
TOML_NODISCARD_CTOR
explicit yaml_formatter(const toml::parse_result& result, format_flags flags = default_flags) noexcept
: base{ nullptr, &result, constants, { flags, " "sv } }
{}
#endif
/// \brief Prints the bound TOML object out to the stream as YAML.
friend std::ostream& TOML_CALLCONV operator<<(std::ostream& lhs, yaml_formatter& rhs)
{
rhs.attach(lhs);
rhs.print();
rhs.detach();
return lhs;
}
/// \brief Prints the bound TOML object out to the stream as YAML (rvalue overload).
friend std::ostream& TOML_CALLCONV operator<<(std::ostream& lhs, yaml_formatter&& rhs)
{
return lhs << rhs; // as lvalue
}
};
}
TOML_NAMESPACE_END;
#include "header_end.h"
#endif // TOML_ENABLE_FORMATTERS

View File

@ -0,0 +1,165 @@
//# 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.h"
//# {{
#if !TOML_IMPLEMENTATION
#error This is an implementation-only header.
#endif
//# }}
#if TOML_ENABLE_FORMATTERS
#include "yaml_formatter.h"
#include "print_to_stream.h"
#include "table.h"
#include "array.h"
#include "header_start.h"
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.h"
#endif // TOML_ENABLE_FORMATTERS

220
lib/toml++/toml.h Normal file
View File

@ -0,0 +1,220 @@
//# 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
#ifndef TOMLPLUSPLUS_H
#define TOMLPLUSPLUS_H
#define INCLUDE_TOMLPLUSPLUS_H // old guard name used pre-v3
#include "impl/preprocessor.h"
TOML_PUSH_WARNINGS;
TOML_DISABLE_SPAM_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
TOML_DISABLE_SUGGEST_ATTR_WARNINGS;
// misc warning false-positives
#if TOML_MSVC
#pragma warning(disable : 5031) // #pragma warning(pop): likely mismatch
#if TOML_SHARED_LIB
#pragma warning(disable : 4251) // dll exports for std lib types
#endif
#elif TOML_CLANG
TOML_PRAGMA_CLANG(diagnostic ignored "-Wheader-hygiene")
#if TOML_CLANG >= 12
TOML_PRAGMA_CLANG(diagnostic ignored "-Wc++20-extensions")
#endif
#if TOML_CLANG == 13
TOML_PRAGMA_CLANG(diagnostic ignored "-Wreserved-identifier")
#endif
#endif
#include "impl/std_new.h"
#include "impl/std_string.h"
#include "impl/std_optional.h"
#include "impl/forward_declarations.h"
#include "impl/print_to_stream.h"
#include "impl/source_region.h"
#include "impl/date_time.h"
#include "impl/at_path.h"
#include "impl/path.h"
#include "impl/node.h"
#include "impl/node_view.h"
#include "impl/value.h"
#include "impl/make_node.h"
#include "impl/array.h"
#include "impl/key.h"
#include "impl/table.h"
#include "impl/unicode_autogenerated.h"
#include "impl/unicode.h"
#include "impl/parse_error.h"
#include "impl/parse_result.h"
#include "impl/parser.h"
#include "impl/formatter.h"
#include "impl/toml_formatter.h"
#include "impl/json_formatter.h"
#include "impl/yaml_formatter.h"
#if TOML_IMPLEMENTATION
#include "impl/std_string.inl"
#include "impl/print_to_stream.inl"
#include "impl/node.inl"
#include "impl/at_path.inl"
#include "impl/path.inl"
#include "impl/array.inl"
#include "impl/table.inl"
#include "impl/unicode.inl"
#include "impl/parser.inl"
#include "impl/formatter.inl"
#include "impl/toml_formatter.inl"
#include "impl/json_formatter.inl"
#include "impl/yaml_formatter.inl"
#endif // TOML_IMPLEMENTATION
TOML_POP_WARNINGS;
// macro hygiene
#if TOML_UNDEF_MACROS
#undef TOML_ABI_NAMESPACE_BOOL
#undef TOML_ABI_NAMESPACE_END
#undef TOML_ABI_NAMESPACE_START
#undef TOML_ABI_NAMESPACES
#undef TOML_ABSTRACT_INTERFACE
#undef TOML_ALWAYS_INLINE
#undef TOML_ANON_NAMESPACE
#undef TOML_ANON_NAMESPACE_END
#undef TOML_ANON_NAMESPACE_START
#undef TOML_ARCH_AMD64
#undef TOML_ARCH_ARM
#undef TOML_ARCH_ARM32
#undef TOML_ARCH_ARM64
#undef TOML_ARCH_ITANIUM
#undef TOML_ARCH_X86
#undef TOML_ASSERT
#undef TOML_ASSERT_ASSUME
#undef TOML_ASSUME
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
#undef TOML_ATTR
#undef TOML_CLANG
#undef TOML_CLANG_VERSION
#undef TOML_CLOSED_ENUM
#undef TOML_CLOSED_FLAGS_ENUM
#undef TOML_COMPILER_HAS_EXCEPTIONS
#undef TOML_COMPILER_HAS_RTTI
#undef TOML_CONST
#undef TOML_CONST_GETTER
#undef TOML_CONST_INLINE_GETTER
#undef TOML_CONSTRAINED_TEMPLATE
#undef TOML_CPP
#undef TOML_DECLSPEC
#undef TOML_DELETE_DEFAULTS
#undef TOML_DISABLE_ARITHMETIC_WARNINGS
#undef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
#undef TOML_DISABLE_SPAM_WARNINGS
#undef TOML_DISABLE_SPAM_WARNINGS_CLANG_10
#undef TOML_DISABLE_SPAM_WARNINGS_CLANG_11
#undef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
#undef TOML_DISABLE_SWITCH_WARNINGS
#undef TOML_DISABLE_WARNINGS
#undef TOML_DOXYGEN
#undef TOML_EMPTY_BASES
#undef TOML_ENABLE_IF
#undef TOML_ENABLE_WARNINGS
#undef TOML_EVAL_BOOL_0
#undef TOML_EVAL_BOOL_1
#undef TOML_EXTERNAL_LINKAGE
#undef TOML_FLAGS_ENUM
#undef TOML_FLOAT_CHARCONV
#undef TOML_FLOAT128
#undef TOML_FLOAT16_DIG
#undef TOML_FLOAT16_LIMITS_SET
#undef TOML_FLOAT16_MANT_DIG
#undef TOML_FLOAT16_MAX_10_EXP
#undef TOML_FLOAT16_MAX_EXP
#undef TOML_FLOAT16_MIN_10_EXP
#undef TOML_FLOAT16_MIN_EXP
#undef TOML_GCC
#undef TOML_HAS_ATTR
#undef TOML_HAS_BUILTIN
#undef TOML_HAS_CHAR8
#undef TOML_HAS_CPP_ATTR
#undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
#undef TOML_HAS_FEATURE
#undef TOML_HAS_INCLUDE
#undef TOML_HAS_SSE2
#undef TOML_HAS_SSE4_1
#undef TOML_HIDDEN_CONSTRAINT
#undef TOML_ICC
#undef TOML_ICC_CL
#undef TOML_IMPL_NAMESPACE_END
#undef TOML_IMPL_NAMESPACE_START
#undef TOML_IMPLEMENTATION
#undef TOML_INCLUDE_WINDOWS_H
#undef TOML_INT_CHARCONV
#undef TOML_INT128
#undef TOML_INTELLISENSE
#undef TOML_INTERNAL_LINKAGE
#undef TOML_LANG_AT_LEAST
#undef TOML_LANG_EFFECTIVE_VERSION
#undef TOML_LANG_HIGHER_THAN
#undef TOML_LANG_UNRELEASED
#undef TOML_LAUNDER
#undef TOML_LIFETIME_HOOKS
#undef TOML_LIKELY
#undef TOML_LIKELY_CASE
#undef TOML_MAKE_FLAGS
#undef TOML_MAKE_FLAGS_
#undef TOML_MAKE_FLAGS_1
#undef TOML_MAKE_FLAGS_2
#undef TOML_MAKE_STRING
#undef TOML_MAKE_STRING_1
#undef TOML_MAKE_VERSION
#undef TOML_MSVC
#undef TOML_NAMESPACE
#undef TOML_NEVER_INLINE
#undef TOML_NODISCARD
#undef TOML_NODISCARD_CTOR
#undef TOML_OPEN_ENUM
#undef TOML_OPEN_FLAGS_ENUM
#undef TOML_PARSER_TYPENAME
#undef TOML_POP_WARNINGS
#undef TOML_PRAGMA_CLANG
#undef TOML_PRAGMA_CLANG_GE_10
#undef TOML_PRAGMA_CLANG_GE_11
#undef TOML_PRAGMA_CLANG_GE_9
#undef TOML_PRAGMA_GCC
#undef TOML_PRAGMA_ICC
#undef TOML_PRAGMA_MSVC
#undef TOML_PURE
#undef TOML_PURE_GETTER
#undef TOML_PURE_INLINE_GETTER
#undef TOML_PUSH_WARNINGS
#undef TOML_REQUIRES
#undef TOML_SA_LIST_BEG
#undef TOML_SA_LIST_END
#undef TOML_SA_LIST_NEW
#undef TOML_SA_LIST_NXT
#undef TOML_SA_LIST_SEP
#undef TOML_SA_NATIVE_VALUE_TYPE_LIST
#undef TOML_SA_NEWLINE
#undef TOML_SA_NODE_TYPE_LIST
#undef TOML_SA_UNWRAPPED_NODE_TYPE_LIST
#undef TOML_SA_VALUE_EXACT_FUNC_MESSAGE
#undef TOML_SA_VALUE_FUNC_MESSAGE
#undef TOML_SA_VALUE_MESSAGE_CONST_CHAR8
#undef TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
#undef TOML_SA_VALUE_MESSAGE_WSTRING
#undef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
#undef TOML_TRIVIAL_ABI
#undef TOML_UINT128
#undef TOML_UNLIKELY
#undef TOML_UNLIKELY_CASE
#undef TOML_UNREACHABLE
#undef TOML_UNUSED
#undef TOML_WINDOWS
#endif
#endif // TOMLPLUSPLUS_H

View File

@ -3,7 +3,7 @@ CFLAGS = -std=c++17 -Wall
SRCDIR = ./src
BINDIR = ./bin
$(BINDIR)/autom: $(SRCDIR)/main.cpp $(SRCDIR)/command.cpp $(SRCDIR)/inputparser.cpp
$(BINDIR)/autom: $(SRCDIR)/main.cpp $(SRCDIR)/command.cpp $(SRCDIR)/inputparser.cpp $(SRCDIR)/settings.cpp
$(CC) $(CFLAGS) $^ -o $@
.PHONY: clean

View File

@ -3,12 +3,6 @@
int main(int argc, char *argv[])
{
#ifdef _WIN32
_mkdir(dir.c_str());
#else
mkdir(dir.c_str(), 0777);
#endif
input(argc, argv);
return 0;
}
@ -22,6 +16,7 @@ void input(int argc, char *argv[])
command.addCommand("run", "[script] - Runs a script", runScript);
command.addCommand("help", "- Shows this help message", help);
command.addCommand("ls", "- Lists all scripts ", listScripts);
// command.addCommand("config", "open configure dialog", removeScript);
command.addCommand("add", "[script] - Adds a script", addScript);
command.addCommand("new", "[script] - Adds a script", addScript);
command.addCommand("edit", "[script] - Edits a script", editScript);
@ -54,7 +49,7 @@ void showScript(int argc, char *argv[])
while (getline(file, line))
{
line_number++;
std::cout << line_number << " "<< line << std::endl;
std::cout << line_number << " " << line << std::endl;
}
}
else
@ -110,11 +105,8 @@ void editScript(int argc, char *argv[])
void editScript(std::string name)
{
std::string script = dir + "/" + name;
#ifdef _WIN32
system(("notepad " + script).c_str());
#else
system(("nano " + script).c_str());
#endif
system((settings.getSetting("editor") + " " + script).c_str());
}
void removeScript(int argc, char *argv[])

View File

@ -1,4 +1,9 @@
#ifndef MAIN_H
#define MAIN_H
#include <iostream>
#include <string>
#include <sys/stat.h>
@ -7,17 +12,11 @@
#include "inputparser.h"
#include "command.h"
#include "settings.h"
Settings settings = Settings();
// directory for autom scripts
#ifdef _WIN32
#include <direct.h>
std::string home = getenv("USERPROFILE");
#else
std::string home = getenv("HOME");
#endif
// directory for autom scripts
std::string dir = home + "/autom";
std::string dir = settings.getSetting("autom_home_dir");
Command command = Command();
// input function for parsing arguments and creating commands and running them
@ -42,3 +41,5 @@ void help(int argc, char *argv[]);
// void list(int argc,char *argv[]);
// void edit(int argc,char *argv[]);
// void run(int argc,char *argv[]);
#endif // MAIN_H

33
src/settings.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "settings.h"
Setup setup = Setup();
Settings::Settings(void)
{
readSettings();
}
Settings::~Settings(void)
{
}
void Settings::readSettings()
{
std::ifstream file(setup.home + "/.automconfig.toml");
if (!file.is_open())
{
std::cout << "Error:" + setup.home + "/.automconfig.toml not found" << std::endl;
setup.createSettings();
readSettings();
}
settings = toml::parse(file);
}
std::string Settings::getSetting(std::string path)
{
std::string setting = settings[path].value_or("null");
return setting;
}

29
src/settings.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include "../lib/toml++/toml.h"
#include <direct.h>
#include "settings.h"
#include <fstream>
#include <iostream>
#include <algorithm>
#include <string>
#include "./setup.h"
class Settings
{
private:
toml::table settings;
std::string settings_name = ".automconfig.toml";
public:
Settings(void);
~Settings(void);
void readSettings();
std::string getSetting(std::string path);
};
#endif // SETTINGS_H

63
src/setup.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef SETUP_H
#define SETUP_H
#include <iostream>
#include <string>
#include <sys/stat.h>
#include <filesystem>
#include <fstream>
class Setup
{
private:
public:
#ifdef _WIN32
std::string home = getenv("USERPROFILE");
std::string editor = "notepad.exe";
#else
std::string home = getenv("HOME");
std::string editor = "vim";
#endif
Setup(/* args */)
{
home = home + "/.autom";
runSetup();
}
~Setup()
{
}
void createFolder()
{
#ifdef _WIN32
_mkdir((home).c_str());
#else
mkdir((home).c_str(), 0777);
#endif
}
void createSettings()
{
std::replace(home.begin(), home.end(), '\\', '/');
std::ofstream file(home + "/.automconfig.toml");
file << "editor = \"" << editor << "\"" << std::endl;
file << "search_dirs = [\"" << home << "\"]" << std::endl;
file << "autom_home_dir = \"" << home << "\"" << std::endl;
file.close();
}
void runSetup()
{
createFolder();
createSettings();
}
};
#endif // SETUP_H