fixed array::insert not working correctly in some cases

also:
- improved the documentation for table and array
- fixed documentation font on mobile
This commit is contained in:
Mark Gillard 2020-07-26 15:03:33 +03:00
parent 35ada5d851
commit 539aad89f4
15 changed files with 800 additions and 699 deletions

View File

@ -70,7 +70,7 @@ EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 0
AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = NO

View File

@ -47,7 +47,7 @@ article div > section > section
pre, code, .tpp-enable-if > a
{
font-family: 'Consolas', 'Source Sans Pro', monospace;
font-family: 'Consolas', 'Source Code Pro', monospace, monospace, monospace;
}
a.tpp-external

View File

@ -3,10 +3,8 @@
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
//# {{
#ifndef INCLUDE_TOMLPLUSPLUS_H
#define INCLUDE_TOMLPLUSPLUS_H
//# }}
//# Note: most of these would be included transitively but
//# they're listed explicitly here because this file
@ -135,6 +133,4 @@
#undef TOML_USING_ANON_NAMESPACE
#endif
//# {{
#endif // INCLUDE_TOMLPLUSPLUS_H
//# }}

View File

@ -225,25 +225,34 @@ TOML_IMPL_NAMESPACE_END
TOML_NAMESPACE_START
{
/// \brief A RandomAccessIterator for iterating over nodes in a toml::array.
/// \brief A RandomAccessIterator for iterating over elements in a toml::array.
using array_iterator = impl::array_iterator<false>;
/// \brief A RandomAccessIterator for iterating over const nodes in a toml::array.
/// \brief A RandomAccessIterator for iterating over const elements in a toml::array.
using const_array_iterator = impl::array_iterator<true>;
/// \brief A TOML array.
///
/// \detail The interface of this type is modeled after std::vector, with some
/// additional considerations made for the heterogeneous nature of a
/// TOML array. \cpp
/// TOML array.
///
/// auto tbl = toml::parse("arr = [1, 2, 3, 4, 'five']"sv);
/// auto& arr = *tbl.get_as<toml::array>("arr");
/// std::cout << arr << std::endl;
/// \godbolt{sjK4da}
///
/// for (size_t i = 0; i < arr.size(); i++)
/// \cpp
///
/// toml::table tbl = toml::parse(R"(
/// arr = [1, 2, 3, 4, 'five']
/// )"sv);
///
/// // get the element as an array
/// toml::array& arr = *tbl.get_as<toml::array>("arr");
/// std::cout << arr << "\n";
///
/// // increment each element with visit()
/// for (auto&& elem : arr)
/// {
/// arr[i].visit([](auto&& el) noexcept
/// elem.visit([](auto&& el) noexcept
/// {
/// if constexpr (toml::is_number<decltype(el)>)
/// (*el)++;
@ -251,31 +260,34 @@ TOML_NAMESPACE_START
/// el = "six"sv;
/// });
/// }
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// // add and remove elements
/// arr.push_back(7);
/// arr.push_back(8.0f);
/// arr.push_back("nine"sv);
/// arr.erase(arr.cbegin());
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// arr.emplace_back<toml::array>(10, 11.0);
/// std::cout << arr << std::endl;
/// // emplace elements
/// arr.emplace_back<std::string>("ten");
/// arr.emplace_back<toml::array>(11, 12.0);
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [1, 2, 3, 4, "five"]
/// [2, 3, 4, 5, "six"]
/// [3, 4, 5, "six", 7, 8.0, "nine"]
/// [3, 4, 5, "six", 7, 8.0, "nine", [10, 11.0]]
/// [ 1, 2, 3, 4, 'five' ]
/// [ 2, 3, 4, 5, 'six' ]
/// [ 3, 4, 5, 'six', 7, 8.0, 'nine' ]
/// [ 3, 4, 5, 'six', 7, 8.0, 'nine', 'ten', [ 11, 12.0 ] ]
/// \eout
class TOML_API array final
: public node
{
private:
friend class TOML_PARSER_TYPENAME;
std::vector<std::unique_ptr<node>> values;
std::vector<std::unique_ptr<node>> elements;
void preinsertion_resize(size_t idx, size_t count) noexcept;
@ -287,9 +299,9 @@ TOML_NAMESPACE_START
using reference = node&;
using const_reference = const node&;
/// \brief A RandomAccessIterator for iterating over nodes in a toml::array.
/// \brief A RandomAccessIterator for iterating over elements in a toml::array.
using iterator = array_iterator;
/// \brief A RandomAccessIterator for iterating over const nodes in a toml::array.
/// \brief A RandomAccessIterator for iterating over const elements in a toml::array.
using const_iterator = const_array_iterator;
/// \brief Default constructor.
@ -300,16 +312,16 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR
array(array&& other) noexcept;
/// \brief Constructs an array with one or more initial values.
/// \brief Constructs an array with one or more initial elements.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2.0, "three"sv, toml::array{ 4, 5 } };
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [1, 2.0, "three", [4, 5]]
/// [ 1, 2.0, 'three', [ 4, 5 ] ]
/// \eout
///
/// \remark \parblock If you need to construct an array with one child array element, the array's move constructor
@ -318,8 +330,8 @@ TOML_NAMESPACE_START
/// // desired result: [ [ 42 ] ]
/// auto bad = toml::array{ toml::array{ 42 } }
/// auto good = toml::array{ toml::inserter{ toml::array{ 42 } } }
/// std::cout << "bad: " << bad << std::endl;
/// std::cout << "good:" << good << std::endl;
/// std::cout << "bad: " << bad << "\n";
/// std::cout << "good:" << good << "\n";
/// \ecpp
///
/// \out
@ -329,20 +341,20 @@ TOML_NAMESPACE_START
///
/// \endparblock
///
/// \tparam U One of the TOML node or value types (or a type promotable to one).
/// \tparam V One of the TOML node or value types (or a type promotable to one).
/// \param val The value used to initialize node 0.
/// \param vals The values used to initialize nodes 1...N.
template <typename U, typename... V>
/// \tparam ElemType One of the TOML node or value types (or a type promotable to one).
/// \tparam ElemTypes One of the TOML node or value types (or a type promotable to one).
/// \param val The node or value used to initialize element 0.
/// \param vals The nodes or values used to initialize elements 1...N.
template <typename ElemType, typename... ElemTypes>
TOML_NODISCARD_CTOR
explicit array(U&& val, V&&... vals)
explicit array(ElemType&& val, ElemTypes&&... vals)
{
values.reserve(sizeof...(V) + 1_sz);
values.emplace_back(impl::make_node(std::forward<U>(val)));
if constexpr (sizeof...(V) > 0)
elements.reserve(sizeof...(ElemTypes) + 1_sz);
elements.emplace_back(impl::make_node(std::forward<ElemType>(val)));
if constexpr (sizeof...(ElemTypes) > 0)
{
(
values.emplace_back(impl::make_node(std::forward<V>(vals))),
elements.emplace_back(impl::make_node(std::forward<ElemTypes>(vals))),
...
);
}
@ -365,41 +377,41 @@ TOML_NAMESPACE_START
[[nodiscard]] array* as_array() noexcept override;
[[nodiscard]] const array* as_array() const noexcept override;
/// \brief Checks if the array contains nodes of only one type.
/// \brief Checks if the array contains elements of only one type.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << "homogenous: "sv << arr.is_homogeneous(toml::node_type::none) << std::endl;
/// std::cout << "all floats: "sv << arr.is_homogeneous(toml::node_type::floating_point) << std::endl;
/// std::cout << "all arrays: "sv << arr.is_homogeneous(toml::node_type::array) << std::endl;
/// std::cout << "all integers: "sv << arr.is_homogeneous(toml::node_type::integer) << std::endl;
/// std::cout << "homogenous: "sv << arr.is_homogeneous(toml::node_type::none) << "\n";
/// std::cout << "all floats: "sv << arr.is_homogeneous(toml::node_type::floating_point) << "\n";
/// std::cout << "all arrays: "sv << arr.is_homogeneous(toml::node_type::array) << "\n";
/// std::cout << "all ints: "sv << arr.is_homogeneous(toml::node_type::integer) << "\n";
///
/// \ecpp
///
/// \out
/// homogeneous: true
/// all doubles: false
/// all floats: false
/// all arrays: false
/// all integers: true
/// all ints: true
/// \eout
///
/// \param type A TOML node type. <br>
/// <strong><em>`toml::node_type::none`: </em></strong> "is every node the same type?"
/// <strong><em>Anything else:</em></strong> "is every node one of these?" <br>
/// <strong><em>toml::node_type::none: </em></strong> "is every node the same type?" <br>
/// <strong><em>Anything else:</em></strong> "is every node one of these?"
///
/// \returns True if the array was homogeneous.
///
/// \remarks Always returns `false` for empty arrays.
[[nodiscard]] bool is_homogeneous(node_type type) const noexcept;
/// \brief Checks if the array contains nodes of only one type.
/// \brief Checks if the array contains elements of only one type.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << "homogenous: "sv << arr.is_homogeneous() << std::endl;
/// std::cout << "all doubles: "sv << arr.is_homogeneous<double>() << std::endl;
/// std::cout << "all arrays: "sv << arr.is_homogeneous<toml::array>() << std::endl;
/// std::cout << "all integers: "sv << arr.is_homogeneous<int64_t>() << std::endl;
/// std::cout << "homogenous: "sv << arr.is_homogeneous() << "\n";
/// std::cout << "all doubles: "sv << arr.is_homogeneous<double>() << "\n";
/// std::cout << "all arrays: "sv << arr.is_homogeneous<toml::array>() << "\n";
/// std::cout << "all integers: "sv << arr.is_homogeneous<int64_t>() << "\n";
///
/// \ecpp
///
@ -410,18 +422,18 @@ TOML_NAMESPACE_START
/// all integers: true
/// \eout
///
/// \tparam T A TOML node type. <br>
/// <strong><em>Left as `void`:</em></strong> "is every node the same type?"
/// <strong><em>Explicitly specified:</em></strong> "is every node a T?" <br>
/// \tparam ElemType A TOML node or value type. <br>
/// <strong><em>Left as `void`:</em></strong> "is every node the same type?" <br>
/// <strong><em>Explicitly specified:</em></strong> "is every node a T?"
///
/// \returns True if the array was homogeneous.
///
/// \remarks Always returns `false` for empty arrays.
template <typename T = void>
template <typename ElemType = void>
[[nodiscard]]
bool is_homogeneous() const noexcept
{
using type = impl::unwrap_node<T>;
using type = impl::unwrap_node<ElemType>;
static_assert(
std::is_void_v<type>
|| ((impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>),
@ -438,76 +450,76 @@ TOML_NAMESPACE_START
/// \brief Returns true if this array contains only tables.
[[nodiscard]] bool is_array_of_tables() const noexcept override;
/// \brief Gets a reference to the node at a specific index.
/// \brief Gets a reference to the element at a specific index.
[[nodiscard]] node& operator[] (size_t index) noexcept;
/// \brief Gets a reference to the node at a specific index.
/// \brief Gets a reference to the element at a specific index.
[[nodiscard]] const node& operator[] (size_t index) const noexcept;
/// \brief Returns a reference to the first node in the array.
/// \brief Returns a reference to the first element in the array.
[[nodiscard]] node& front() noexcept;
/// \brief Returns a reference to the first node in the array.
/// \brief Returns a reference to the first element in the array.
[[nodiscard]] const node& front() const noexcept;
/// \brief Returns a reference to the last node in the array.
/// \brief Returns a reference to the last element in the array.
[[nodiscard]] node& back() noexcept;
/// \brief Returns a reference to the last node in the array.
/// \brief Returns a reference to the last element in the array.
[[nodiscard]] const node& back() const noexcept;
/// \brief Returns an iterator to the first node.
/// \brief Returns an iterator to the first element.
[[nodiscard]] iterator begin() noexcept;
/// \brief Returns an iterator to the first node.
/// \brief Returns an iterator to the first element.
[[nodiscard]] const_iterator begin() const noexcept;
/// \brief Returns an iterator to the first node.
/// \brief Returns an iterator to the first element.
[[nodiscard]] const_iterator cbegin() const noexcept;
/// \brief Returns an iterator to one-past-the-last node.
/// \brief Returns an iterator to one-past-the-last element.
[[nodiscard]] iterator end() noexcept;
/// \brief Returns an iterator to one-past-the-last node.
/// \brief Returns an iterator to one-past-the-last element.
[[nodiscard]] const_iterator end() const noexcept;
/// \brief Returns an iterator to one-past-the-last node.
/// \brief Returns an iterator to one-past-the-last element.
[[nodiscard]] const_iterator cend() const noexcept;
/// \brief Returns true if the array is empty.
[[nodiscard]] bool empty() const noexcept;
/// \brief Returns the number of nodes in the array.
/// \brief Returns the number of elements in the array.
[[nodiscard]] size_t size() const noexcept;
/// \brief Reserves internal storage capacity up to a pre-determined number of nodes.
/// \brief Reserves internal storage capacity up to a pre-determined number of elements.
void reserve(size_t new_capacity);
/// \brief Removes all nodes from the array.
/// \brief Removes all elements from the array.
void clear() noexcept;
/// \brief Returns the maximum number of nodes that can be stored in an array on the current platform.
/// \brief Returns the maximum number of elements that can be stored in an array on the current platform.
[[nodiscard]] size_t max_size() const noexcept;
/// \brief Returns the current max number of nodes that may be held in the array's internal storage.
/// \brief Returns the current max number of elements that may be held in the array's internal storage.
[[nodiscard]] size_t capacity() const noexcept;
/// \brief Requests the removal of any unused internal storage capacity.
void shrink_to_fit();
/// \brief Inserts a new node at a specific position in the array.
/// \brief Inserts a new element at a specific position in the array.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 3 };
/// arr.insert(arr.cbegin() + 1, "two");
/// arr.insert(arr.cend(), toml::array{ 4, 5 });
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [1, "two", 3, [4, 5]]
/// [ 1, 'two', 3, [ 4, 5 ] ]
/// \eout
///
/// \tparam U One of the TOML node or value types (or a type promotable to one).
/// \tparam ElemType One of the TOML node or value types (or a type promotable to one).
/// \param pos The insertion position.
/// \param val The value being inserted.
/// \param val The node or value being inserted.
///
/// \returns An iterator to the inserted value.
template <typename U>
iterator insert(const_iterator pos, U&& val) noexcept
/// \returns An iterator to the newly-inserted element.
template <typename ElemType>
iterator insert(const_iterator pos, ElemType&& val) noexcept
{
return { values.emplace(pos.raw_, impl::make_node(std::forward<U>(val))) };
return { elements.emplace(pos.raw_, impl::make_node(std::forward<ElemType>(val))) };
}
/// \brief Repeatedly inserts a value starting at a specific position in the array.
/// \brief Repeatedly inserts a new element starting at a specific position in the array.
///
/// \detail \cpp
/// auto arr = toml::array{
@ -515,147 +527,146 @@ TOML_NAMESPACE_START
/// "and immediately we knew peace was never an option."
/// };
/// arr.insert(arr.cbegin() + 1, 3, "honk");
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [
/// "with an evil twinkle in its eye the goose said",
/// "honk",
/// "honk",
/// "honk",
/// "and immediately we knew peace was never an option."
/// 'with an evil twinkle in its eye the goose said',
/// 'honk',
/// 'honk',
/// 'honk',
/// 'and immediately we knew peace was never an option.'
/// ]
/// \eout
///
/// \tparam U One of the TOML value types (or a type promotable to one).
/// \tparam ElemType One of the TOML node or value types (or a type promotable to one).
/// \param pos The insertion position.
/// \param count The number of times the value should be inserted.
/// \param val The value being inserted.
/// \param count The number of times the node or value should be inserted.
/// \param val The node or value being inserted.
///
/// \returns An iterator to the first inserted value (or a copy of `pos` if count was 0).
template <typename U>
iterator insert(const_iterator pos, size_t count, U&& val) noexcept
/// \returns An iterator to the first newly-inserted element (or a copy of `pos` if count was 0).
template <typename ElemType>
iterator insert(const_iterator pos, size_t count, ElemType&& val) noexcept
{
switch (count)
{
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
case 1: return insert(pos, std::forward<U>(val));
case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) };
case 1: return insert(pos, std::forward<ElemType>(val));
default:
{
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, count);
size_t i = start_idx;
for (size_t e = start_idx + count - 1_sz; i < e; i++)
values[i].reset(impl::make_node(val));
elements[i].reset(impl::make_node(val));
//# potentially move the initial value into the last element
values[i].reset(impl::make_node(std::forward<U>(val)));
return { values.begin() + static_cast<ptrdiff_t>(start_idx) };
elements[i].reset(impl::make_node(std::forward<ElemType>(val)));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
}
}
}
/// \brief Inserts a range of values into the array at a specific position.
/// \brief Inserts a range of elements into the array at a specific position.
///
/// \tparam Iter An iterator type. Must satisfy ForwardIterator.
/// \param pos The insertion position.
/// \param first Iterator to the first value being inserted.
/// \param last Iterator to the one-past-the-last value being inserted.
/// \param first Iterator to the first node or value being inserted.
/// \param last Iterator to the one-past-the-last node or value being inserted.
///
/// \returns An iterator to the first inserted value (or a copy of `pos` if `first` == `last`).
/// \returns An iterator to the first newly-inserted element (or a copy of `pos` if `first` >= `last`).
template <typename Iter>
iterator insert(const_iterator pos, Iter first, Iter last) noexcept
{
const auto count = std::distance(first, last);
switch (count)
if (count <= 0)
return { elements.begin() + (pos.raw_ - elements.cbegin()) };
else if (count == 1)
return insert(pos, *first);
else
{
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
case 1: return insert(pos, *first);
default:
{
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
preinsertion_resize(start_idx, count);
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, static_cast<size_t>(count));
size_t i = start_idx;
for (auto it = first; it != last; it++)
values[i].reset(impl::make_node(*it));
return { values.begin() + static_cast<ptrdiff_t>(start_idx) };
}
elements[i++].reset(impl::make_node(*it));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
}
}
/// \brief Inserts a range of values into the array at a specific position.
/// \brief Inserts a range of elements into the array at a specific position.
///
/// \tparam U One of the TOML value types (or a type promotable to one).
/// \tparam ElemType One of the TOML node or value types (or a type promotable to one).
/// \param pos The insertion position.
/// \param ilist An initializer list containing the values to be inserted.
///
/// \returns An iterator to the first inserted value (or a copy of `pos` if `ilist` was empty).
template <typename U>
iterator insert(const_iterator pos, std::initializer_list<U> ilist) noexcept
/// \returns An iterator to the first newly-inserted element (or a copy of `pos` if `ilist` was empty).
template <typename ElemType>
iterator insert(const_iterator pos, std::initializer_list<ElemType> ilist) noexcept
{
switch (ilist.size())
{
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) };
case 1: return insert(pos, *ilist.begin());
default:
{
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, ilist.size());
size_t i = start_idx;
for (auto& val : ilist)
values[i].reset(impl::make_node(val));
return { values.begin() + static_cast<ptrdiff_t>(start_idx) };
elements[i++].reset(impl::make_node(val));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
}
}
}
/// \brief Emplaces a new value at a specific position in the array.
/// \brief Emplaces a new element at a specific position in the array.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2 };
///
/// //add a string using std::string's substring constructor
/// arr.emplace<std::string>(arr.cbegin() + 1, "this is not a drill"sv, 14, 5);
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [1, "drill", 2]
/// [ 1, 'drill', 2 ]
/// \eout
///
/// \tparam U One of the TOML node or value types.
/// \tparam V Value constructor argument types.
/// \tparam ElemType One of the TOML node or value types.
/// \tparam Args Value constructor argument types.
/// \param pos The insertion position.
/// \param args Arguments to forward to the value's constructor.
///
/// \returns An iterator to the inserted value.
/// \returns An iterator to the inserted element.
///
/// \remarks There is no difference between insert() and emplace()
/// for trivial value types (floats, ints, bools).
template <typename U, typename... V>
iterator emplace(const_iterator pos, V&&... args) noexcept
template <typename ElemType, typename... Args>
iterator emplace(const_iterator pos, Args&&... args) noexcept
{
using type = impl::unwrap_node<U>;
using type = impl::unwrap_node<ElemType>;
static_assert(
(impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
"Emplacement type parameter must be one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
return { values.emplace(pos.raw_, new impl::wrap_node<type>{ std::forward<V>(args)...} ) };
return { elements.emplace(pos.raw_, new impl::wrap_node<type>{ std::forward<Args>(args)...} ) };
}
/// \brief Removes the specified node from the array.
/// \brief Removes the specified element from the array.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// arr.erase(arr.cbegin() + 1);
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// \ecpp
///
@ -664,44 +675,46 @@ TOML_NAMESPACE_START
/// [ 1, 3 ]
/// \eout
///
/// \param pos Iterator to the node being erased.
/// \param pos Iterator to the element being erased.
///
/// \returns Iterator to the first node immediately following the removed node.
/// \returns Iterator to the first element immediately following the removed element.
iterator erase(const_iterator pos) noexcept;
/// \brief Removes the nodes in the range [first, last) from the array.
/// \brief Removes the elements in the range [first, last) from the array.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, "bad", "karma" 2 };
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// arr.erase(arr.cbegin() + 1, arr.cbegin() + 3);
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [1, "bad", "karma", 3]
/// [ 1, 'bad', 'karma', 3 ]
/// [ 1, 3 ]
/// \eout
///
/// \param first Iterator to the first node being erased.
/// \param last Iterator to the one-past-the-last node being erased.
/// \param first Iterator to the first element being erased.
/// \param last Iterator to the one-past-the-last element being erased.
///
/// \returns Iterator to the first node immediately following the last removed node.
/// \returns Iterator to the first element immediately following the last removed element.
iterator erase(const_iterator first, const_iterator last) noexcept;
/// \brief Resizes the array.
///
/// \detail \cpp
/// \detail \godbolt{W5zqx3}
///
/// \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// arr.resize(6, 42);
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// arr.resize(2, 0);
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// \ecpp
///
@ -711,32 +724,34 @@ TOML_NAMESPACE_START
/// [ 1, 2 ]
/// \eout
///
/// \tparam U One of the TOML value types (or a type promotable to one).
/// \tparam ElemType One of the TOML node or value types (or a type promotable to one).
///
/// \param new_size New number of elements the array will have.
/// \param default_init_val The value used to initialize new elements if the array needs to grow.
template <typename U>
void resize(size_t new_size, U&& default_init_val) noexcept
/// \param new_size The number of elements the array will have after resizing.
/// \param default_init_val The node or value used to initialize new elements if the array needs to grow.
template <typename ElemType>
void resize(size_t new_size, ElemType&& default_init_val) noexcept
{
if (!new_size)
values.clear();
else if (new_size < values.size())
values.resize(new_size);
else if (new_size > values.size())
insert(cend(), new_size - values.size(), std::forward<U>(default_init_val));
elements.clear();
else if (new_size < elements.size())
elements.resize(new_size);
else if (new_size > elements.size())
insert(cend(), new_size - elements.size(), std::forward<ElemType>(default_init_val));
}
/// \brief Shrinks the array to the given size.
///
/// \detail \cpp
/// \detail \godbolt{rxEzK5}
///
/// \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// arr.truncate(5); // no-op
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// arr.truncate(1);
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// \ecpp
///
@ -749,141 +764,141 @@ TOML_NAMESPACE_START
/// \remarks Does nothing if the requested size is larger than or equal to the current size.
void truncate(size_t new_size);
/// \brief Appends a new value to the end of the array.
/// \brief Appends a new element to the end of the array.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2 };
/// arr.push_back(3);
/// arr.push_back(4.0);
/// arr.push_back(toml::array{ 5, "six"sv });
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [1, 2, 3, 4.0, [5, "six"]]
/// [ 1, 2, 3, 4.0, [ 5, 'six' ] ]
/// \eout
///
/// \tparam U One of the TOML value types (or a type promotable to one).
/// \param val The value being added.
/// \tparam ElemType One of the TOML node or value types (or a type promotable to one).
/// \param val The node or value being added.
///
/// \returns A reference to the newly-constructed value node.
template <typename U>
decltype(auto) push_back(U&& val) noexcept
/// \returns A reference to the newly-constructed element.
template <typename ElemType>
decltype(auto) push_back(ElemType&& val) noexcept
{
auto nde = impl::make_node(std::forward<U>(val));
values.emplace_back(nde);
auto nde = impl::make_node(std::forward<ElemType>(val));
elements.emplace_back(nde);
return *nde;
}
/// \brief Emplaces a new value at the end of the array.
/// \brief Emplaces a new element at the end of the array.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2 };
/// arr.emplace_back<toml::array>(3, "four"sv);
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [1, 2, [3, "four"]]
/// [ 1, 2, [ 3, 'four' ] ]
/// \eout
///
/// \tparam U One of the TOML value types.
/// \tparam V Value constructor argument types.
/// \tparam ElemType One of the TOML node or value types.
/// \tparam Args Value constructor argument types.
/// \param args Arguments to forward to the value's constructor.
///
/// \returns A reference to the newly-constructed value node.
/// \returns A reference to the newly-constructed element.
///
/// \remarks There is no difference between push_back and emplace_back
/// \remarks There is no difference between push_back() and emplace_back()
/// For trivial value types (floats, ints, bools).
template <typename U, typename... V>
decltype(auto) emplace_back(V&&... args) noexcept
template <typename ElemType, typename... Args>
decltype(auto) emplace_back(Args&&... args) noexcept
{
using type = impl::unwrap_node<U>;
using type = impl::unwrap_node<ElemType>;
static_assert(
(impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
"Emplacement type parameter must be one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
auto nde = new impl::wrap_node<type>{ std::forward<V>(args)... };
values.emplace_back(nde);
auto nde = new impl::wrap_node<type>{ std::forward<Args>(args)... };
elements.emplace_back(nde);
return *nde;
}
/// \brief Removes the last node from the array.
/// \brief Removes the last element from the array.
void pop_back() noexcept;
/// \brief Gets the node at a specific index.
/// \brief Gets the element at a specific index.
///
/// \detail \cpp
/// auto arr = toml::array{ 99, "bottles of beer on the wall" };
/// std::cout << "node [0] exists: "sv << !!arr.get(0) << std::endl;
/// std::cout << "node [1] exists: "sv << !!arr.get(1) << std::endl;
/// std::cout << "node [2] exists: "sv << !!arr.get(2) << std::endl;
/// if (auto val = arr.get(0))
/// std::cout << "node [0] was an "sv << val->type() << std::endl;
/// std::cout << "element [0] exists: "sv << !!arr.get(0) << "\n";
/// std::cout << "element [1] exists: "sv << !!arr.get(1) << "\n";
/// std::cout << "element [2] exists: "sv << !!arr.get(2) << "\n";
/// if (toml::node* val = arr.get(0))
/// std::cout << "element [0] is an "sv << val->type() << "\n";
///
/// \ecpp
///
/// \out
/// node [0] exists: true
/// node [1] exists: true
/// node [2] exists: false
/// node [0] was an integer
/// element [0] exists: true
/// element [1] exists: true
/// element [2] exists: false
/// element [0] is an integer
/// \eout
///
/// \param index The node's index.
/// \param index The element's index.
///
/// \returns A pointer to the node at the specified index if one existed, or nullptr.
/// \returns A pointer to the element at the specified index if one existed, or nullptr.
[[nodiscard]] node* get(size_t index) noexcept;
/// \brief Gets the node at a specific index (const overload).
/// \brief Gets the element at a specific index (const overload).
///
/// \param index The node's index.
/// \param index The element's index.
///
/// \returns A pointer to the node at the specified index if one existed, or nullptr.
/// \returns A pointer to the element at the specified index if one existed, or nullptr.
[[nodiscard]] const node* get(size_t index) const noexcept;
/// \brief Gets the node at a specific index if it is a particular type.
/// \brief Gets the element at a specific index if it is a particular type.
///
/// \detail \cpp
/// auto arr = toml::array{ 42, "is the meaning of life, apparently."sv };
/// if (auto val = arr.get_as<int64_t>(0))
/// std::cout << "node [0] was an integer with value "sv << **val << std::endl;
/// if (toml::value<int64_t>* val = arr.get_as<int64_t>(0))
/// std::cout << "element [0] is an integer with value "sv << *val << "\n";
///
/// \ecpp
///
/// \out
/// node [0] was an integer with value 42
/// element [0] is an integer with value 42
/// \eout
///
/// \tparam T The node's type.
/// \param index The node's index.
/// \tparam ElemType The element's type.
/// \param index The element's index.
///
/// \returns A pointer to the selected node if it existed and was of the specified type, or nullptr.
template <typename T>
/// \returns A pointer to the selected element if it existed and was of the specified type, or nullptr.
template <typename ElemType>
[[nodiscard]]
impl::wrap_node<T>* get_as(size_t index) noexcept
impl::wrap_node<ElemType>* get_as(size_t index) noexcept
{
if (auto val = get(index))
return val->as<T>();
return val->as<ElemType>();
return nullptr;
}
/// \brief Gets the node at a specific index if it is a particular type (const overload).
/// \brief Gets the element at a specific index if it is a particular type (const overload).
///
/// \tparam T The node's type.
/// \param index The node's index.
/// \tparam ElemType The element's type.
/// \param index The element's index.
///
/// \returns A pointer to the selected node if it existed and was of the specified type, or nullptr.
template <typename T>
/// \returns A pointer to the selected element if it existed and was of the specified type, or nullptr.
template <typename ElemType>
[[nodiscard]]
const impl::wrap_node<T>* get_as(size_t index) const noexcept
const impl::wrap_node<ElemType>* get_as(size_t index) const noexcept
{
if (auto val = get(index))
return val->as<T>();
return val->as<ElemType>();
return nullptr;
}
@ -892,7 +907,7 @@ TOML_NAMESPACE_START
/// \param lhs The LHS array.
/// \param rhs The RHS array.
///
/// \returns True if the arrays contained the same values.
/// \returns True if the arrays contained the same elements.
friend bool operator == (const array& lhs, const array& rhs) noexcept;
/// \brief Inequality operator.
@ -900,7 +915,7 @@ TOML_NAMESPACE_START
/// \param lhs The LHS array.
/// \param rhs The RHS array.
///
/// \returns True if the arrays did not contain the same values.
/// \returns True if the arrays did not contain the same elements.
friend bool operator != (const array& lhs, const array& rhs) noexcept;
private:
@ -960,10 +975,10 @@ TOML_NAMESPACE_START
/// \detail \cpp
///
/// auto arr = toml::array{ 1, 2, toml::array{ 3, 4, toml::array{ 5 } }, 6, toml::array{} };
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// arr.flatten();
/// std::cout << arr << std::endl;
/// std::cout << arr << "\n";
///
/// \ecpp
///
@ -974,10 +989,11 @@ TOML_NAMESPACE_START
///
/// \remarks Arrays inside child tables are not flattened.
///
/// A reference to the array.
/// \returns A reference to the array.
array& flatten() &;
/// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself (rvalue overload).
/// \returns An rvalue reference to the array.
array&& flatten() &&
{
return static_cast<toml::array&&>(static_cast<toml::array&>(*this).flatten());

View File

@ -22,13 +22,16 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
void array::preinsertion_resize(size_t idx, size_t count) noexcept
{
const auto new_size = values.size() + count;
const auto inserting_at_end = idx == values.size();
values.resize(new_size);
TOML_ASSERT(idx <= elements.size());
TOML_ASSERT(count >= 1_sz);
const auto old_size = elements.size();
const auto new_size = old_size + count;
const auto inserting_at_end = idx == old_size;
elements.resize(new_size);
if (!inserting_at_end)
{
for (size_t r = new_size, e = idx + count, l = e; r-- > e; l--)
values[r] = std::move(values[l]);
for(size_t left = old_size, right = new_size - 1_sz; left --> idx; right--)
elements[right] = std::move(elements[left]);
}
}
@ -38,14 +41,14 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
array::array(array&& other) noexcept
: node{ std::move(other) },
values{ std::move(other.values) }
elements{ std::move(other.elements) }
{}
TOML_EXTERNAL_LINKAGE
array& array::operator= (array&& rhs) noexcept
{
node::operator=(std::move(rhs));
values = std::move(rhs.values);
elements = std::move(rhs.elements);
return *this;
}
@ -58,69 +61,69 @@ TOML_NAMESPACE_START
TOML_MEMBER_ATTR(const) const array* array::as_array() const noexcept { return this; }
TOML_MEMBER_ATTR(const) array* array::as_array() noexcept { return this; }
TOML_MEMBER_ATTR(pure) const node& array::operator[] (size_t index) const noexcept { return *values[index]; }
TOML_MEMBER_ATTR(pure) node& array::operator[] (size_t index) noexcept { return *values[index]; }
TOML_MEMBER_ATTR(pure) const node& array::operator[] (size_t index) const noexcept { return *elements[index]; }
TOML_MEMBER_ATTR(pure) node& array::operator[] (size_t index) noexcept { return *elements[index]; }
TOML_MEMBER_ATTR(pure) const node& array::front() const noexcept { return *values.front(); }
TOML_MEMBER_ATTR(pure) const node& array::back() const noexcept { return *values.back(); }
TOML_MEMBER_ATTR(pure) node& array::front() noexcept { return *values.front(); }
TOML_MEMBER_ATTR(pure) node& array::back() noexcept { return *values.back(); }
TOML_MEMBER_ATTR(pure) const node& array::front() const noexcept { return *elements.front(); }
TOML_MEMBER_ATTR(pure) const node& array::back() const noexcept { return *elements.back(); }
TOML_MEMBER_ATTR(pure) node& array::front() noexcept { return *elements.front(); }
TOML_MEMBER_ATTR(pure) node& array::back() noexcept { return *elements.back(); }
TOML_MEMBER_ATTR(pure) array::const_iterator array::begin() const noexcept { return { values.begin() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::end() const noexcept { return { values.end() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::cbegin() const noexcept { return { values.cbegin() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::cend() const noexcept { return { values.cend() }; }
TOML_MEMBER_ATTR(pure) array::iterator array::begin() noexcept { return { values.begin() }; }
TOML_MEMBER_ATTR(pure) array::iterator array::end() noexcept { return { values.end() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::begin() const noexcept { return { elements.begin() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::end() const noexcept { return { elements.end() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::cbegin() const noexcept { return { elements.cbegin() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::cend() const noexcept { return { elements.cend() }; }
TOML_MEMBER_ATTR(pure) array::iterator array::begin() noexcept { return { elements.begin() }; }
TOML_MEMBER_ATTR(pure) array::iterator array::end() noexcept { return { elements.end() }; }
TOML_MEMBER_ATTR(pure) size_t array::size() const noexcept { return values.size(); }
TOML_MEMBER_ATTR(pure) size_t array::capacity() const noexcept { return values.capacity(); }
TOML_MEMBER_ATTR(pure) bool array::empty() const noexcept { return values.empty(); }
TOML_MEMBER_ATTR(const) size_t array::max_size() const noexcept { return values.max_size(); }
TOML_MEMBER_ATTR(pure) size_t array::size() const noexcept { return elements.size(); }
TOML_MEMBER_ATTR(pure) size_t array::capacity() const noexcept { return elements.capacity(); }
TOML_MEMBER_ATTR(pure) bool array::empty() const noexcept { return elements.empty(); }
TOML_MEMBER_ATTR(const) size_t array::max_size() const noexcept { return elements.max_size(); }
TOML_EXTERNAL_LINKAGE void array::reserve(size_t new_capacity) { values.reserve(new_capacity); }
TOML_EXTERNAL_LINKAGE void array::clear() noexcept { values.clear(); }
TOML_EXTERNAL_LINKAGE void array::shrink_to_fit() { values.shrink_to_fit(); }
TOML_EXTERNAL_LINKAGE void array::reserve(size_t new_capacity) { elements.reserve(new_capacity); }
TOML_EXTERNAL_LINKAGE void array::clear() noexcept { elements.clear(); }
TOML_EXTERNAL_LINKAGE void array::shrink_to_fit() { elements.shrink_to_fit(); }
#undef TOML_MEMBER_ATTR
TOML_EXTERNAL_LINKAGE
void array::truncate(size_t new_size)
{
if (new_size < values.size())
values.resize(new_size);
if (new_size < elements.size())
elements.resize(new_size);
}
TOML_EXTERNAL_LINKAGE
array::iterator array::erase(const_iterator pos) noexcept
{
return { values.erase(pos.raw_) };
return { elements.erase(pos.raw_) };
}
TOML_EXTERNAL_LINKAGE
array::iterator array::erase(const_iterator first, const_iterator last) noexcept
{
return { values.erase(first.raw_, last.raw_) };
return { elements.erase(first.raw_, last.raw_) };
}
TOML_EXTERNAL_LINKAGE
void array::pop_back() noexcept
{
values.pop_back();
elements.pop_back();
}
TOML_EXTERNAL_LINKAGE
TOML_ATTR(pure)
node* array::get(size_t index) noexcept
{
return index < values.size() ? values[index].get() : nullptr;
return index < elements.size() ? elements[index].get() : nullptr;
}
TOML_EXTERNAL_LINKAGE
TOML_ATTR(pure)
const node* array::get(size_t index) const noexcept
{
return index < values.size() ? values[index].get() : nullptr;
return index < elements.size() ? elements[index].get() : nullptr;
}
TOML_API
@ -129,17 +132,17 @@ TOML_NAMESPACE_START
{
if (&lhs == &rhs)
return true;
if (lhs.values.size() != rhs.values.size())
if (lhs.elements.size() != rhs.elements.size())
return false;
for (size_t i = 0, e = lhs.values.size(); i < e; i++)
for (size_t i = 0, e = lhs.elements.size(); i < e; i++)
{
const auto lhs_type = lhs.values[i]->type();
const node& rhs_ = *rhs.values[i];
const auto lhs_type = lhs.elements[i]->type();
const node& rhs_ = *rhs.elements[i];
const auto rhs_type = rhs_.type();
if (lhs_type != rhs_type)
return false;
const bool equal = lhs.values[i]->visit([&](const auto& lhs_) noexcept
const bool equal = lhs.elements[i]->visit([&](const auto& lhs_) noexcept
{
return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_);
});
@ -160,9 +163,9 @@ TOML_NAMESPACE_START
size_t array::total_leaf_count() const noexcept
{
size_t leaves{};
for (size_t i = 0, e = values.size(); i < e; i++)
for (size_t i = 0, e = elements.size(); i < e; i++)
{
auto arr = values[i]->as_array();
auto arr = elements[i]->as_array();
leaves += arr ? arr->total_leaf_count() : 1_sz;
}
return leaves;
@ -173,29 +176,29 @@ TOML_NAMESPACE_START
{
for (size_t i = 0, e = child.size(); i < e; i++)
{
auto type = child.values[i]->type();
auto type = child.elements[i]->type();
if (type == node_type::array)
{
array& arr = *reinterpret_cast<array*>(child.values[i].get());
array& arr = *reinterpret_cast<array*>(child.elements[i].get());
if (!arr.empty())
flatten_child(std::move(arr), dest_index);
}
else
values[dest_index++] = std::move(child.values[i]);
elements[dest_index++] = std::move(child.elements[i]);
}
}
TOML_EXTERNAL_LINKAGE
array& array::flatten() &
{
if (values.empty())
if (elements.empty())
return *this;
bool requires_flattening = false;
size_t size_after_flattening = values.size();
for (size_t i = values.size(); i --> 0_sz;)
size_t size_after_flattening = elements.size();
for (size_t i = elements.size(); i --> 0_sz;)
{
auto arr = values[i]->as_array();
auto arr = elements[i]->as_array();
if (!arr)
continue;
size_after_flattening--; //discount the array itself
@ -206,25 +209,25 @@ TOML_NAMESPACE_START
size_after_flattening += leaf_count;
}
else
values.erase(values.cbegin() + static_cast<ptrdiff_t>(i));
elements.erase(elements.cbegin() + static_cast<ptrdiff_t>(i));
}
if (!requires_flattening)
return *this;
values.reserve(size_after_flattening);
elements.reserve(size_after_flattening);
size_t i = 0;
while (i < values.size())
while (i < elements.size())
{
auto arr = values[i]->as_array();
auto arr = elements[i]->as_array();
if (!arr)
{
i++;
continue;
}
std::unique_ptr<node> arr_storage = std::move(values[i]);
std::unique_ptr<node> arr_storage = std::move(elements[i]);
const auto leaf_count = arr->total_leaf_count();
if (leaf_count > 1_sz)
preinsertion_resize(i + 1_sz, leaf_count - 1_sz);
@ -237,13 +240,13 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type type) const noexcept
{
if (values.empty())
if (elements.empty())
return false;
if (type == node_type::none)
type = values[0]->type();
type = elements[0]->type();
for (const auto& val : values)
for (const auto& val : elements)
if (val->type() != type)
return false;

View File

@ -145,9 +145,6 @@ TOML_NAMESPACE_START // abi namespace
template <typename T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
//template <typename T, typename... U>
//struct is_one_of_ : std::integral_constant<bool, (false || ... || std::is_same_v<T, U>)> {};
template <typename T, typename... U>
inline constexpr bool is_one_of = (false || ... || std::is_same_v<T, U>);
@ -224,17 +221,17 @@ TOML_NAMESPACE_START // abi namespace
{
/// \brief Convenience literal operators for working with toml++.
///
/// \detail This namespace exists so you can safely hoist the UDL operators into another scope
/// without dragging in everything in the toml namespace: \cpp
/// \detail This namespace exists so you can safely hoist the toml++ literal operators into another scope
/// without dragging in everything from the toml namespace: \cpp
///
/// #include <toml++/toml.h>
/// using namespace toml::literals;
///
/// int main()
/// {
/// auto tbl = "vals = [1, 2, 3]"_toml;
/// toml::table tbl = "vals = [1, 2, 3]"_toml;
///
/// // ... do stuff with the table generated by the "_toml" UDL ...
/// // ... do stuff with the table generated by the "_toml" literal ...
///
/// return 0;
/// }

View File

@ -2456,7 +2456,7 @@ TOML_IMPL_NAMESPACE_START
auto child = parent->get(key.segments[i]);
if (!child)
{
child = parent->values.emplace(
child = parent->map.emplace(
key.segments[i],
new toml::table{}
).first->second.get();
@ -2472,9 +2472,9 @@ TOML_IMPL_NAMESPACE_START
{
// table arrays are a special case;
// the spec dictates we select the most recently declared element in the array.
TOML_ASSERT(!child->ref_cast<array>().values.empty());
TOML_ASSERT(child->ref_cast<array>().values.back()->is_table());
parent = &child->ref_cast<array>().values.back()->ref_cast<table>();
TOML_ASSERT(!child->ref_cast<array>().elements.empty());
TOML_ASSERT(child->ref_cast<array>().elements.back()->is_table());
parent = &child->ref_cast<array>().elements.back()->ref_cast<table>();
}
else
{
@ -2501,22 +2501,22 @@ TOML_IMPL_NAMESPACE_START
// set the starting regions, and return the table element
if (is_arr)
{
auto tab_arr = &parent->values.emplace(
auto tab_arr = &parent->map.emplace(
key.segments.back(),
new toml::array{}
).first->second->ref_cast<array>();
table_arrays.push_back(tab_arr);
tab_arr->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
tab_arr->values.emplace_back(new toml::table{});
tab_arr->values.back()->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
return &tab_arr->values.back()->ref_cast<table>();
tab_arr->elements.emplace_back(new toml::table{});
tab_arr->elements.back()->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
return &tab_arr->elements.back()->ref_cast<table>();
}
//otherwise we're just making a table
else
{
auto tab = &parent->values.emplace(
auto tab = &parent->map.emplace(
key.segments.back(),
new toml::table{})
.first->second->ref_cast<table>();
@ -2534,9 +2534,9 @@ TOML_IMPL_NAMESPACE_START
if (is_arr && matching_node->is_array() && find(table_arrays, &matching_node->ref_cast<array>()))
{
auto tab_arr = &matching_node->ref_cast<array>();
tab_arr->values.emplace_back(new toml::table{});
tab_arr->values.back()->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
return &tab_arr->values.back()->ref_cast<table>();
tab_arr->elements.emplace_back(new toml::table{});
tab_arr->elements.back()->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
return &tab_arr->elements.back()->ref_cast<table>();
}
else if (!is_arr
@ -2582,7 +2582,7 @@ TOML_IMPL_NAMESPACE_START
auto child = tab->get(kvp.key.segments[i]);
if (!child)
{
child = tab->values.emplace(
child = tab->map.emplace(
std::move(kvp.key.segments[i]),
new toml::table{}
).first->second.get();
@ -2615,7 +2615,7 @@ TOML_IMPL_NAMESPACE_START
}
return_if_error();
tab->values.emplace(
tab->map.emplace(
std::move(kvp.key.segments.back()),
std::unique_ptr<node>{ kvp.value }
);
@ -2689,7 +2689,7 @@ TOML_IMPL_NAMESPACE_START
return;
auto end = nde.source_.end;
for (auto& [k, v] : tbl.values)
for (auto& [k, v] : tbl.map)
{
(void)k;
update_region_ends(*v);
@ -2701,7 +2701,7 @@ TOML_IMPL_NAMESPACE_START
{
auto& arr = nde.ref_cast<array>();
auto end = nde.source_.end;
for (auto& v : arr.values)
for (auto& v : arr.elements)
{
update_region_ends(*v);
if (end < v->source_.end)
@ -2773,7 +2773,7 @@ TOML_IMPL_NAMESPACE_START
advance_and_return_if_error_or_eof({});
auto arr = new array{};
auto& vals = arr->values;
auto& vals = arr->elements;
enum parse_elem : int
{
none,

View File

@ -490,9 +490,8 @@ is no longer necessary.
//#====================================================================================================================
#include "toml_version.h"
//# {{
#define TOML_LIB_SINGLE_HEADER 0
//# }}
#define TOML_MAKE_VERSION(maj, min, rev) \
((maj) * 1000 + (min) * 25 + (rev))

View File

@ -213,7 +213,7 @@ TOML_NAMESPACE_START
private:
friend class TOML_PARSER_TYPENAME;
impl::string_map<std::unique_ptr<node>> values;
impl::string_map<std::unique_ptr<node>> map;
bool inline_ = false;
table(impl::table_init_pair*, size_t) noexcept;
@ -237,7 +237,7 @@ TOML_NAMESPACE_START
/// { "bar", 2.0 },
/// { "kek", "three" }
/// }};
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// \ecpp
///
@ -293,19 +293,21 @@ TOML_NAMESPACE_START
/// \brief Sets whether this table is a TOML inline table.
///
/// \detail \cpp
/// \detail \godbolt{an9xdj}
///
/// \cpp
/// auto tbl = toml::table{{
/// { "a", 1 },
/// { "b", 2 },
/// { "c", 3 },
/// { "d", toml::table{{ { "e", 4 } }} }
/// }};
/// std::cout << "is inline? "sv << tbl.is_inline() << std::endl;
/// std::cout << tbl << std::endl << std::endl;
/// std::cout << "is inline? "sv << tbl.is_inline() << "\n";
/// std::cout << tbl << "\n\n";
///
/// tbl.is_inline(!tbl.is_inline());
/// std::cout << "is inline? "sv << tbl.is_inline() << std::endl;
/// std::cout << tbl << std::endl;
/// std::cout << "is inline? "sv << tbl.is_inline() << "\n";
/// std::cout << tbl << "\n";
///
/// \ecpp
///
@ -314,9 +316,11 @@ TOML_NAMESPACE_START
/// a = 1
/// b = 2
/// c = 3
///
/// [d]
/// e = 4
///
///
/// is inline? true
/// { a = 1, b = 2, c = 3, d = { e = 4 } }
/// \eout
@ -411,63 +415,71 @@ TOML_NAMESPACE_START
/// \brief Inserts a new value at a specific key if one did not already exist.
///
/// \detail \cpp
/// \detail \godbolt{bMnW5r}
///
/// \cpp
/// auto tbl = toml::table{{
/// { "a", 1 },
/// { "b", 2 },
/// { "c", 3 }
/// }};
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// for (auto k : { "a", "d" })
/// {
/// auto result = tbl.insert(k, 42);
/// std::cout << "inserted with key '"sv << k << "': "sv << result.second << std::endl;
/// std::cout << "inserted with key '"sv << k << "': "sv << result.second << "\n";
/// }
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// \ecpp
///
/// \out
/// { a = 1, b = 2, c = 3 }
/// a = 1
/// b = 2
/// c = 3
///
/// inserted with key 'a': false
/// inserted with key 'd': true
/// { a = 1, b = 2, c = 3, d = 42 }
/// a = 1
/// b = 2
/// c = 3
/// d = 42
/// \eout
///
/// \tparam K std::string (or a type convertible to it).
/// \tparam V One of the TOML value types (or a type promotable to one).
/// \tparam KeyType std::string (or a type convertible to it).
/// \tparam ValueType One of the TOML ndoe or value types (or a type promotable to one).
/// \param key The key at which to insert the new value.
/// \param val The new value to insert.
///
/// \returns A std::pair containing:
/// - An iterator to the insertion position (or the position of the value that prevented insertion)
/// - A boolean indicating if the insertion was successful.
template <typename K, typename V, typename = std::enable_if_t<
std::is_convertible_v<K&&, std::string_view>
|| impl::is_wide_string<K>
template <typename KeyType, typename ValueType, typename = std::enable_if_t<
std::is_convertible_v<KeyType&&, std::string_view>
|| impl::is_wide_string<KeyType>
>>
std::pair<iterator, bool> insert(K&& key, V&& val) noexcept
std::pair<iterator, bool> insert(KeyType&& key, ValueType&& val) noexcept
{
static_assert(
!impl::is_wide_string<K> || TOML_WINDOWS_COMPAT,
!impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
"Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
if constexpr (impl::is_wide_string<K>)
if constexpr (impl::is_wide_string<KeyType>)
{
#if TOML_WINDOWS_COMPAT
return insert(impl::narrow(std::forward<K>(key)), std::forward<V>(val));
return insert(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val));
#else
static_assert(impl::dependent_false<K>, "Evaluated unreachable branch!");
static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
#endif
}
else
{
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
auto ipos = map.lower_bound(key);
if (ipos == map.end() || ipos->first != key)
{
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val)));
return { ipos, true };
}
return { ipos, false };
@ -476,26 +488,34 @@ TOML_NAMESPACE_START
/// \brief Inserts a series of key-value pairs into the table.
///
/// \detail \cpp
/// \detail \godbolt{bzYcce}
///
/// \cpp
/// auto tbl = toml::table{{
/// { "a", 1 },
/// { "b", 2 },
/// { "c", 3 }
/// }};
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// auto kvps = std::array<std::pair<std::string, int>>{{
/// auto kvps = std::array<std::pair<std::string, int>, 2>{{
/// { "d", 42 },
/// { "a", 43 }
/// { "a", 43 } // won't be inserted, 'a' already exists
/// }};
/// tbl.insert(kvps.begin(), kvps.end());
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// \ecpp
///
/// \out
/// { a = 1, b = 2, c = 3 }
/// { a = 1, b = 2, c = 3, d = 42 } //"a" already existed
/// a = 1
/// b = 2
/// c = 3
///
/// a = 1
/// b = 2
/// c = 3
/// d = 42
/// \eout
///
/// \tparam Iter An InputIterator to a collection of key-value pairs.
@ -524,66 +544,74 @@ TOML_NAMESPACE_START
/// \brief Inserts or assigns a value at a specific key.
///
/// \detail \cpp
/// \detail \godbolt{ddK563}
///
/// \cpp
/// auto tbl = toml::table{{
/// { "a", 1 },
/// { "b", 2 },
/// { "c", 3 }
/// }};
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// for (auto k : { "a", "d" })
/// {
/// auto result = tbl.insert_or_assign(k, 42);
/// std::cout << "value at key '"sv << k
/// << "' was "sv << (result.second ? "inserted"sv : "assigned"sv) << std::endl;
/// << "' was "sv << (result.second ? "inserted"sv : "assigned"sv) << "\n";
/// }
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// \ecpp
///
/// \out
/// { a = 1, b = 2, c = 3 }
/// a = 1
/// b = 2
/// c = 3
///
/// value at key 'a' was assigned
/// value at key 'd' was inserted
/// { a = 42, b = 2, c = 3, d = 42 }
/// a = 42
/// b = 2
/// c = 3
/// d = 42
/// \eout
///
/// \tparam K std::string (or a type convertible to it).
/// \tparam V One of the TOML value types (or a type promotable to one).
/// \tparam KeyType std::string (or a type convertible to it).
/// \tparam ValueType One of the TOML node or value types (or a type promotable to one).
/// \param key The key at which to insert or assign the value.
/// \param val The value to insert/assign.
///
/// \returns A std::pair containing:
/// - An iterator to the value's position
/// - A boolean containing `true` if the value was inserted, `false` if it was assigned.
template <typename K, typename V>
std::pair<iterator, bool> insert_or_assign(K&& key, V&& val) noexcept
template <typename KeyType, typename ValueType>
std::pair<iterator, bool> insert_or_assign(KeyType&& key, ValueType&& val) noexcept
{
static_assert(
!impl::is_wide_string<K> || TOML_WINDOWS_COMPAT,
!impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
"Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
if constexpr (impl::is_wide_string<K>)
if constexpr (impl::is_wide_string<KeyType>)
{
#if TOML_WINDOWS_COMPAT
return insert_or_assign(impl::narrow(std::forward<K>(key)), std::forward<V>(val));
return insert_or_assign(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val));
#else
static_assert(impl::dependent_false<K>, "Evaluated unreachable branch!");
static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
#endif
}
else
{
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
auto ipos = map.lower_bound(key);
if (ipos == map.end() || ipos->first != key)
{
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val)));
return { ipos, true };
}
else
{
(*ipos).second.reset(impl::make_node(std::forward<V>(val)));
(*ipos).second.reset(impl::make_node(std::forward<ValueType>(val)));
return { ipos, false };
}
}
@ -597,15 +625,15 @@ TOML_NAMESPACE_START
/// { "b", 2 },
/// { "c", 3 }
/// }};
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// for (auto k : { "a", "d" })
/// {
/// // add a string using std::string's substring constructor
/// auto result = tbl.emplace<std::string>(k, "this is not a drill"sv, 14, 5);
/// std::cout << "emplaced with key '"sv << k << "': "sv << result.second << std::endl;
/// std::cout << "emplaced with key '"sv << k << "': "sv << result.second << "\n";
/// }
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// \ecpp
///
@ -616,9 +644,9 @@ TOML_NAMESPACE_START
/// { a = 1, b = 2, c = 3, d = "drill" }
/// \eout
///
/// \tparam U One of the TOML node or value types.
/// \tparam K std::string (or a type convertible to it).
/// \tparam V Value constructor argument types.
/// \tparam ValueType One of the TOML node or value types.
/// \tparam KeyType std::string (or a type convertible to it).
/// \tparam ValueArgs Value constructor argument types.
/// \param key The key at which to emplace the new value.
/// \param args Arguments to forward to the value's constructor.
///
@ -627,39 +655,39 @@ TOML_NAMESPACE_START
/// - A boolean indicating if the emplacement was successful.
///
/// \remark There is no difference between insert() and emplace() for trivial value types (floats, ints, bools).
template <typename U, typename K, typename... V>
std::pair<iterator, bool> emplace(K&& key, V&&... args) noexcept
template <typename ValueType, typename KeyType, typename... ValueArgs>
std::pair<iterator, bool> emplace(KeyType&& key, ValueArgs&&... args) noexcept
{
static_assert(
!impl::is_wide_string<K> || TOML_WINDOWS_COMPAT,
!impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
"Emplacement using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
if constexpr (impl::is_wide_string<K>)
if constexpr (impl::is_wide_string<KeyType>)
{
#if TOML_WINDOWS_COMPAT
return emplace<U>(impl::narrow(std::forward<K>(key)), std::forward<V>(args)...);
return emplace<ValueType>(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueArgs>(args)...);
#else
static_assert(impl::dependent_false<U>, "Evaluated unreachable branch!");
static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
#endif
}
else
{
using type = impl::unwrap_node<U>;
using type = impl::unwrap_node<ValueType>;
static_assert(
(impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
"The emplacement type argument of table::emplace() must be one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
auto ipos = map.lower_bound(key);
if (ipos == map.end() || ipos->first != key)
{
ipos = values.emplace_hint(
ipos = map.emplace_hint(
ipos,
std::forward<K>(key),
new impl::wrap_node<type>{ std::forward<V>(args)... }
std::forward<KeyType>(key),
new impl::wrap_node<type>{ std::forward<ValueArgs>(args)... }
);
return { ipos, true };
}
@ -675,10 +703,10 @@ TOML_NAMESPACE_START
/// { "b", 2 },
/// { "c", 3 }
/// }};
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// tbl.erase(tbl.begin() + 1);
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// \ecpp
///
@ -700,10 +728,10 @@ TOML_NAMESPACE_START
/// { "b", 2 },
/// { "c", 3 }
/// }};
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// tbl.erase(tbl.cbegin() + 1);
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// \ecpp
///
@ -726,10 +754,10 @@ TOML_NAMESPACE_START
/// { "c", "karma" },
/// { "d", 2 }
/// }};
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// tbl.erase(tbl.cbegin() + 1, tbl.cbegin() + 3);
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// \ecpp
///
@ -752,11 +780,11 @@ TOML_NAMESPACE_START
/// { "b", 2 },
/// { "c", 3 }
/// }};
/// std::cout << tbl << std::endl;
/// std::cout << tbl << "\n";
///
/// std::cout << tbl.erase("b") << std::endl;
/// std::cout << tbl.erase("not an existing key") << std::endl;
/// std::cout << tbl << std::endl;
/// std::cout << tbl.erase("b") << "\n";
/// std::cout << tbl.erase("not an existing key") << "\n";
/// std::cout << tbl << "\n";
///
/// \ecpp
///
@ -838,11 +866,11 @@ TOML_NAMESPACE_START
/// { "a", 42, },
/// { "b", "is the meaning of life, apparently." }
/// }};
/// std::cout << R"(node ["a"] exists: )"sv << !!arr.get("a") << std::endl;
/// std::cout << R"(node ["b"] exists: )"sv << !!arr.get("b") << std::endl;
/// std::cout << R"(node ["c"] exists: )"sv << !!arr.get("c") << std::endl;
/// std::cout << R"(node ["a"] exists: )"sv << !!arr.get("a") << "\n";
/// std::cout << R"(node ["b"] exists: )"sv << !!arr.get("b") << "\n";
/// std::cout << R"(node ["c"] exists: )"sv << !!arr.get("c") << "\n";
/// if (auto val = arr.get("a"))
/// std::cout << R"(node ["a"] was an )"sv << val->type() << std::endl;
/// std::cout << R"(node ["a"] was an )"sv << val->type() << "\n";
///
/// \ecpp
///
@ -935,7 +963,7 @@ TOML_NAMESPACE_START
/// { "b", "is the meaning of life, apparently." }
/// }};
/// if (auto val = arr.get_as<int64_t>("a"))
/// std::cout << R"(node ["a"] was an integer with value )"sv << **val << std::endl;
/// std::cout << R"(node ["a"] was an integer with value )"sv << **val << "\n";
///
/// \ecpp
///
@ -943,60 +971,60 @@ TOML_NAMESPACE_START
/// node ["a"] was an integer with value 42
/// \eout
///
/// \tparam T The node's type.
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
template <typename T>
template <typename ValueType>
[[nodiscard]]
impl::wrap_node<T>* get_as(std::string_view key) noexcept
impl::wrap_node<ValueType>* get_as(std::string_view key) noexcept
{
return do_get_as<T>(values, key);
return do_get_as<ValueType>(map, key);
}
/// \brief Gets the node at a specific key if it is a particular type (const overload).
///
/// \tparam T The node's type.
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
template <typename T>
template <typename ValueType>
[[nodiscard]]
const impl::wrap_node<T>* get_as(std::string_view key) const noexcept
const impl::wrap_node<ValueType>* get_as(std::string_view key) const noexcept
{
return do_get_as<T>(values, key);
return do_get_as<ValueType>(map, key);
}
#if TOML_WINDOWS_COMPAT
/// \brief Gets the node at a specific key if it is a particular type.
///
/// \tparam T The node's type.
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
template <typename T>
template <typename ValueType>
[[nodiscard]]
impl::wrap_node<T>* get_as(std::wstring_view key) noexcept
impl::wrap_node<ValueType>* get_as(std::wstring_view key) noexcept
{
return get_as<T>(impl::narrow(key));
return get_as<ValueType>(impl::narrow(key));
}
/// \brief Gets the node at a specific key if it is a particular type (const overload).
///
/// \tparam T The node's type.
/// \tparam ValueType One of the TOML node or value types.
/// \param key The node's key.
///
/// \returns A pointer to the node at the specified key if it was of the given type, or nullptr.
///
/// \attention This overload is only available when #TOML_WINDOWS_COMPAT is enabled.
template <typename T>
template <typename ValueType>
[[nodiscard]]
const impl::wrap_node<T>* get_as(std::wstring_view key) const noexcept
const impl::wrap_node<ValueType>* get_as(std::wstring_view key) const noexcept
{
return get_as<T>(impl::narrow(key));
return get_as<ValueType>(impl::narrow(key));
}
#endif // TOML_WINDOWS_COMPAT
@ -1006,7 +1034,7 @@ TOML_NAMESPACE_START
/// \param lhs The LHS table.
/// \param rhs The RHS table.
///
/// \returns True if the tables contained the same keys and values.
/// \returns True if the tables contained the same keys and map.
friend bool operator == (const table& lhs, const table& rhs) noexcept;
/// \brief Inequality operator.
@ -1014,7 +1042,7 @@ TOML_NAMESPACE_START
/// \param lhs The LHS table.
/// \param rhs The RHS table.
///
/// \returns True if the tables did not contain the same keys and values.
/// \returns True if the tables did not contain the same keys and map.
friend bool operator != (const table& lhs, const table& rhs) noexcept;
/// \brief Prints the table out to a stream as formatted TOML.

View File

@ -25,7 +25,7 @@ TOML_NAMESPACE_START
{
for (size_t i = 0; i < count; i++)
{
values.insert_or_assign(
map.insert_or_assign(
std::move(pairs[i].key),
std::move(pairs[i].value)
);
@ -38,7 +38,7 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
table::table(table&& other) noexcept
: node{ std::move(other) },
values{ std::move(other.values) },
map{ std::move(other.map) },
inline_{ other.inline_ }
{}
@ -46,7 +46,7 @@ TOML_NAMESPACE_START
table& table::operator = (table&& rhs) noexcept
{
node::operator=(std::move(rhs));
values = std::move(rhs.values);
map = std::move(rhs.map);
inline_ = rhs.inline_;
return *this;
}
@ -63,16 +63,16 @@ TOML_NAMESPACE_START
TOML_MEMBER_ATTR(pure) bool table::is_inline() const noexcept { return inline_; }
TOML_EXTERNAL_LINKAGE void table::is_inline(bool val) noexcept { inline_ = val; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::begin() const noexcept { return { values.begin() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::end() const noexcept { return { values.end() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::cbegin() const noexcept { return { values.cbegin() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::cend() const noexcept { return { values.cend() }; }
TOML_EXTERNAL_LINKAGE table::iterator table::begin() noexcept { return { values.begin() }; }
TOML_EXTERNAL_LINKAGE table::iterator table::end() noexcept { return { values.end() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::begin() const noexcept { return { map.begin() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::end() const noexcept { return { map.end() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::cbegin() const noexcept { return { map.cbegin() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::cend() const noexcept { return { map.cend() }; }
TOML_EXTERNAL_LINKAGE table::iterator table::begin() noexcept { return { map.begin() }; }
TOML_EXTERNAL_LINKAGE table::iterator table::end() noexcept { return { map.end() }; }
TOML_MEMBER_ATTR(pure) bool table::empty() const noexcept { return values.empty(); }
TOML_MEMBER_ATTR(pure) size_t table::size() const noexcept { return values.size(); }
TOML_EXTERNAL_LINKAGE void table::clear() noexcept { values.clear(); }
TOML_MEMBER_ATTR(pure) bool table::empty() const noexcept { return map.empty(); }
TOML_MEMBER_ATTR(pure) size_t table::size() const noexcept { return map.size(); }
TOML_EXTERNAL_LINKAGE void table::clear() noexcept { map.clear(); }
#undef TOML_MEMBER_ATTR
@ -90,27 +90,27 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
table::iterator table::erase(iterator pos) noexcept
{
return { values.erase(pos.raw_) };
return { map.erase(pos.raw_) };
}
TOML_EXTERNAL_LINKAGE
table::iterator table::erase(const_iterator pos) noexcept
{
return { values.erase(pos.raw_) };
return { map.erase(pos.raw_) };
}
TOML_EXTERNAL_LINKAGE
table::iterator table::erase(const_iterator first, const_iterator last) noexcept
{
return { values.erase(first.raw_, last.raw_) };
return { map.erase(first.raw_, last.raw_) };
}
TOML_EXTERNAL_LINKAGE
bool table::erase(std::string_view key) noexcept
{
if (auto it = values.find(key); it != values.end())
if (auto it = map.find(key); it != map.end())
{
values.erase(it);
map.erase(it);
return true;
}
return false;
@ -119,31 +119,31 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
node* table::get(std::string_view key) noexcept
{
return do_get(values, key);
return do_get(map, key);
}
TOML_EXTERNAL_LINKAGE
const node* table::get(std::string_view key) const noexcept
{
return do_get(values, key);
return do_get(map, key);
}
TOML_EXTERNAL_LINKAGE
table::iterator table::find(std::string_view key) noexcept
{
return { values.find(key) };
return { map.find(key) };
}
TOML_EXTERNAL_LINKAGE
table::const_iterator table::find(std::string_view key) const noexcept
{
return { values.find(key) };
return { map.find(key) };
}
TOML_EXTERNAL_LINKAGE
bool table::contains(std::string_view key) const noexcept
{
return do_contains(values, key);
return do_contains(map, key);
}
#if TOML_WINDOWS_COMPAT
@ -203,10 +203,10 @@ TOML_NAMESPACE_START
{
if (&lhs == &rhs)
return true;
if (lhs.values.size() != rhs.values.size())
if (lhs.map.size() != rhs.map.size())
return false;
for (auto l = lhs.values.begin(), r = rhs.values.begin(), e = lhs.values.end(); l != e; l++, r++)
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;

View File

@ -84,7 +84,7 @@ TOML_IMPL_NAMESPACE_START
using traits = value_traits<T>;
if constexpr (!traits::is_signed)
{
if constexpr ((sizeof(T) * CHAR_BIT) <= 53) // 53 bits < int64_max < 54 bits
if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max
{
using common_t = decltype(int64_t{} + T{});
if (val < int64_t{} || static_cast<common_t>(val) > static_cast<common_t>(traits::max))

View File

@ -79,6 +79,7 @@ type_names = [
'default_formatter',
'format_flags',
'inserter',
'node_type',
]
all_namespaces = [
'std',

View File

@ -91,6 +91,13 @@ def main():
source_text = re.sub(blank_lines_between_returns_pattern, '\\1\n\\2', source_text, 0, re.I | re.M)
source_text = source_text.strip() + '\n'
# change TOML_LIB_SINGLE_HEADER to 1
source_text = re.sub(
'#\s*define\s+TOML_LIB_SINGLE_HEADER\s+[0-9]+',
'#define TOML_LIB_SINGLE_HEADER 1',
source_text, 0, re.I
)
# extract library version
library_version = {
'major': 0,
@ -145,16 +152,8 @@ def main():
write(line)
write('//')
write(utils.make_divider())
write('// clang-format off')
write('#ifndef INCLUDE_TOMLPLUSPLUS_H')
write('#define INCLUDE_TOMLPLUSPLUS_H')
write('')
write('#define TOML_LIB_SINGLE_HEADER 1')
write('')
write(source_text)
write('')
write('#endif // INCLUDE_TOMLPLUSPLUS_H')
write('// clang-format on')
output_str = output.getvalue().strip()
@ -171,6 +170,7 @@ def main():
if m:
defines[m.group(1)] = defined
ignore_list = ( # macros that are meant to stay public (user configs etc)
'INCLUDE_TOMLPLUSPLUS_H',
'TOML_API',
'TOML_UNRELEASED_FEATURES',
'TOML_LARGE_FILES',

View File

@ -157,6 +157,8 @@ TEST_CASE("arrays - equality")
TEST_CASE("arrays - insertion and erasure")
{
array arr;
// insert(const_iterator pos, ElemType&& val)
auto it = arr.insert(arr.cbegin(), 42);
CHECK(it == arr.begin());
CHECK(arr.size() == 1_sz);
@ -165,6 +167,7 @@ TEST_CASE("arrays - insertion and erasure")
CHECK(*arr.get_as<int64_t>(0_sz) == 42);
REQUIRE(arr == array{ 42 });
// insert(const_iterator pos, size_t count, ElemType&& val)
it = arr.insert(arr.cend(), 3, 10.0f);
CHECK(it == arr.begin() + 1);
CHECK(arr.size() == 4_sz);
@ -176,6 +179,7 @@ TEST_CASE("arrays - insertion and erasure")
CHECK(*arr.get_as<double>(3_sz) == 10.0);
REQUIRE(arr == array{ 42, 10.0, 10.0, 10.0 });
// emplace(const_iterator pos, Args &&... args) noexcept
it = arr.emplace<array>(arr.cbegin(), 1, 2, 3);
CHECK(it == arr.begin());
CHECK(arr.size() == 5_sz);
@ -183,6 +187,7 @@ TEST_CASE("arrays - insertion and erasure")
CHECK(arr.get_as<array>(0_sz)->size() == 3_sz);
REQUIRE(arr == array{ array{ 1, 2, 3 }, 42, 10.0, 10.0, 10.0 });
// push_back(ElemType&& val) noexcept
{
decltype(auto) val = arr.push_back("test"sv);
CHECK(arr.size() == 6_sz);
@ -193,6 +198,7 @@ TEST_CASE("arrays - insertion and erasure")
REQUIRE(arr == array{ array{ 1, 2, 3 }, 42, 10.0, 10.0, 10.0, "test"sv });
}
// decltype(auto) emplace_back(Args&&... args) noexcept
{
decltype(auto) val = arr.emplace_back<std::string>("test2"sv);
CHECK(arr.size() == 7_sz);
@ -203,12 +209,13 @@ TEST_CASE("arrays - insertion and erasure")
REQUIRE(arr == array{ array{ 1, 2, 3 }, 42, 10.0, 10.0, 10.0, "test"sv, "test2"sv });
}
// erase(const_iterator pos) noexcept;
it = arr.erase(arr.cbegin());
REQUIRE(arr == array{ 42, 10.0, 10.0, 10.0, "test"sv, "test2"sv });
CHECK(it == arr.begin());
CHECK(arr.size() == 6_sz);
// erase(const_iterator first, const_iterator last) noexcept;
it = arr.erase(arr.cbegin() + 2, arr.cbegin() + 4);
REQUIRE(arr == array{ 42, 10.0, "test"sv, "test2"sv });
CHECK(it == arr.begin() + 2);
@ -223,8 +230,66 @@ TEST_CASE("arrays - insertion and erasure")
CHECK(arr.size() == 0_sz);
CHECK(arr.empty());
// insert(const_iterator pos, Iter first, Iter last)
{
auto vals = std::vector{ 1.0, 2.0, 3.0 };
arr.insert(arr.cbegin(), vals.begin(), vals.end());
CHECK(arr.size() == 3_sz);
REQUIRE(arr.get_as<double>(0_sz));
CHECK(*arr.get_as<double>(0_sz) == 1.0);
REQUIRE(arr.get_as<double>(1_sz));
CHECK(*arr.get_as<double>(1_sz) == 2.0);
REQUIRE(arr.get_as<double>(2_sz));
CHECK(*arr.get_as<double>(2_sz) == 3.0);
arr.insert(arr.cbegin() + 1, vals.begin(), vals.end());
CHECK(arr.size() == 6_sz);
REQUIRE(arr.get_as<double>(0_sz));
CHECK(*arr.get_as<double>(0_sz) == 1.0);
REQUIRE(arr.get_as<double>(1_sz));
CHECK(*arr.get_as<double>(1_sz) == 1.0);
REQUIRE(arr.get_as<double>(2_sz));
CHECK(*arr.get_as<double>(2_sz) == 2.0);
REQUIRE(arr.get_as<double>(3_sz));
CHECK(*arr.get_as<double>(3_sz) == 3.0);
REQUIRE(arr.get_as<double>(4_sz));
CHECK(*arr.get_as<double>(4_sz) == 2.0);
REQUIRE(arr.get_as<double>(5_sz));
CHECK(*arr.get_as<double>(5_sz) == 3.0);
}
// iterator insert(const_iterator pos, std::initializer_list<ElemType> ilist) noexcept
{
arr.clear();
arr.insert(arr.cbegin(), { 1.0, 2.0, 3.0 });
CHECK(arr.size() == 3_sz);
REQUIRE(arr.get_as<double>(0_sz));
CHECK(*arr.get_as<double>(0_sz) == 1.0);
REQUIRE(arr.get_as<double>(1_sz));
CHECK(*arr.get_as<double>(1_sz) == 2.0);
REQUIRE(arr.get_as<double>(2_sz));
CHECK(*arr.get_as<double>(2_sz) == 3.0);
arr.insert(arr.cbegin() + 1, { 1.0, 2.0, 3.0 });
CHECK(arr.size() == 6_sz);
REQUIRE(arr.get_as<double>(0_sz));
CHECK(*arr.get_as<double>(0_sz) == 1.0);
REQUIRE(arr.get_as<double>(1_sz));
CHECK(*arr.get_as<double>(1_sz) == 1.0);
REQUIRE(arr.get_as<double>(2_sz));
CHECK(*arr.get_as<double>(2_sz) == 2.0);
REQUIRE(arr.get_as<double>(3_sz));
CHECK(*arr.get_as<double>(3_sz) == 3.0);
REQUIRE(arr.get_as<double>(4_sz));
CHECK(*arr.get_as<double>(4_sz) == 2.0);
REQUIRE(arr.get_as<double>(5_sz));
CHECK(*arr.get_as<double>(5_sz) == 3.0);
}
#if TOML_WINDOWS_COMPAT
arr.clear();
it = arr.insert(arr.cbegin(), L"test");
REQUIRE(*arr.get_as<std::string>(0_sz) == "test"sv);
@ -257,7 +322,7 @@ TEST_CASE("arrays - flattening")
{
array arr{
array{},
array{array{}},
array{inserter{array{}}},
array{array{},array{array{},array{}},array{}},
array{array{array{array{array{array{ 1 }}}}}}
};

422
toml.hpp
View File

@ -41,12 +41,9 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//----------------------------------------------------------------------------------------------------------------------
// clang-format off
#ifndef INCLUDE_TOMLPLUSPLUS_H
#define INCLUDE_TOMLPLUSPLUS_H
#define TOML_LIB_SINGLE_HEADER 1
//-------------- ↓ toml_preprocessor.h -------------------------------------------------------------------------------
#if 1
@ -507,6 +504,8 @@ is no longer necessary.
#define TOML_LANG_MINOR 0
#define TOML_LANG_PATCH 0
#define TOML_LIB_SINGLE_HEADER 1
#define TOML_MAKE_VERSION(maj, min, rev) \
((maj) * 1000 + (min) * 25 + (rev))
@ -714,9 +713,6 @@ TOML_NAMESPACE_START // abi namespace
template <typename T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
//template <typename T, typename... U>
//struct is_one_of_ : std::integral_constant<bool, (false || ... || std::is_same_v<T, U>)> {};
template <typename T, typename... U>
inline constexpr bool is_one_of = (false || ... || std::is_same_v<T, U>);
@ -2554,7 +2550,7 @@ TOML_IMPL_NAMESPACE_START
using traits = value_traits<T>;
if constexpr (!traits::is_signed)
{
if constexpr ((sizeof(T) * CHAR_BIT) <= 53) // 53 bits < int64_max < 54 bits
if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max
{
using common_t = decltype(int64_t{} + T{});
if (val < int64_t{} || static_cast<common_t>(val) > static_cast<common_t>(traits::max))
@ -3445,7 +3441,7 @@ TOML_NAMESPACE_START
{
private:
friend class TOML_PARSER_TYPENAME;
std::vector<std::unique_ptr<node>> values;
std::vector<std::unique_ptr<node>> elements;
void preinsertion_resize(size_t idx, size_t count) noexcept;
@ -3465,16 +3461,16 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR
array(array&& other) noexcept;
template <typename U, typename... V>
template <typename ElemType, typename... ElemTypes>
TOML_NODISCARD_CTOR
explicit array(U&& val, V&&... vals)
explicit array(ElemType&& val, ElemTypes&&... vals)
{
values.reserve(sizeof...(V) + 1_sz);
values.emplace_back(impl::make_node(std::forward<U>(val)));
if constexpr (sizeof...(V) > 0)
elements.reserve(sizeof...(ElemTypes) + 1_sz);
elements.emplace_back(impl::make_node(std::forward<ElemType>(val)));
if constexpr (sizeof...(ElemTypes) > 0)
{
(
values.emplace_back(impl::make_node(std::forward<V>(vals))),
elements.emplace_back(impl::make_node(std::forward<ElemTypes>(vals))),
...
);
}
@ -3493,11 +3489,11 @@ TOML_NAMESPACE_START
[[nodiscard]] const array* as_array() const noexcept override;
[[nodiscard]] bool is_homogeneous(node_type type) const noexcept;
template <typename T = void>
template <typename ElemType = void>
[[nodiscard]]
bool is_homogeneous() const noexcept
{
using type = impl::unwrap_node<T>;
using type = impl::unwrap_node<ElemType>;
static_assert(
std::is_void_v<type>
|| ((impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>),
@ -3533,29 +3529,29 @@ TOML_NAMESPACE_START
[[nodiscard]] size_t capacity() const noexcept;
void shrink_to_fit();
template <typename U>
iterator insert(const_iterator pos, U&& val) noexcept
template <typename ElemType>
iterator insert(const_iterator pos, ElemType&& val) noexcept
{
return { values.emplace(pos.raw_, impl::make_node(std::forward<U>(val))) };
return { elements.emplace(pos.raw_, impl::make_node(std::forward<ElemType>(val))) };
}
template <typename U>
iterator insert(const_iterator pos, size_t count, U&& val) noexcept
template <typename ElemType>
iterator insert(const_iterator pos, size_t count, ElemType&& val) noexcept
{
switch (count)
{
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
case 1: return insert(pos, std::forward<U>(val));
case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) };
case 1: return insert(pos, std::forward<ElemType>(val));
default:
{
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, count);
size_t i = start_idx;
for (size_t e = start_idx + count - 1_sz; i < e; i++)
values[i].reset(impl::make_node(val));
elements[i].reset(impl::make_node(val));
values[i].reset(impl::make_node(std::forward<U>(val)));
return { values.begin() + static_cast<ptrdiff_t>(start_idx) };
elements[i].reset(impl::make_node(std::forward<ElemType>(val)));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
}
}
}
@ -3564,90 +3560,89 @@ TOML_NAMESPACE_START
iterator insert(const_iterator pos, Iter first, Iter last) noexcept
{
const auto count = std::distance(first, last);
switch (count)
if (count <= 0)
return { elements.begin() + (pos.raw_ - elements.cbegin()) };
else if (count == 1)
return insert(pos, *first);
else
{
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
case 1: return insert(pos, *first);
default:
{
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
preinsertion_resize(start_idx, count);
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, static_cast<size_t>(count));
size_t i = start_idx;
for (auto it = first; it != last; it++)
values[i].reset(impl::make_node(*it));
return { values.begin() + static_cast<ptrdiff_t>(start_idx) };
}
elements[i++].reset(impl::make_node(*it));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
}
}
template <typename U>
iterator insert(const_iterator pos, std::initializer_list<U> ilist) noexcept
template <typename ElemType>
iterator insert(const_iterator pos, std::initializer_list<ElemType> ilist) noexcept
{
switch (ilist.size())
{
case 0: return { values.begin() + (pos.raw_ - values.cbegin()) };
case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) };
case 1: return insert(pos, *ilist.begin());
default:
{
const auto start_idx = static_cast<size_t>(pos.raw_ - values.cbegin());
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, ilist.size());
size_t i = start_idx;
for (auto& val : ilist)
values[i].reset(impl::make_node(val));
return { values.begin() + static_cast<ptrdiff_t>(start_idx) };
elements[i++].reset(impl::make_node(val));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
}
}
}
template <typename U, typename... V>
iterator emplace(const_iterator pos, V&&... args) noexcept
template <typename ElemType, typename... Args>
iterator emplace(const_iterator pos, Args&&... args) noexcept
{
using type = impl::unwrap_node<U>;
using type = impl::unwrap_node<ElemType>;
static_assert(
(impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
"Emplacement type parameter must be one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
return { values.emplace(pos.raw_, new impl::wrap_node<type>{ std::forward<V>(args)...} ) };
return { elements.emplace(pos.raw_, new impl::wrap_node<type>{ std::forward<Args>(args)...} ) };
}
iterator erase(const_iterator pos) noexcept;
iterator erase(const_iterator first, const_iterator last) noexcept;
template <typename U>
void resize(size_t new_size, U&& default_init_val) noexcept
template <typename ElemType>
void resize(size_t new_size, ElemType&& default_init_val) noexcept
{
if (!new_size)
values.clear();
else if (new_size < values.size())
values.resize(new_size);
else if (new_size > values.size())
insert(cend(), new_size - values.size(), std::forward<U>(default_init_val));
elements.clear();
else if (new_size < elements.size())
elements.resize(new_size);
else if (new_size > elements.size())
insert(cend(), new_size - elements.size(), std::forward<ElemType>(default_init_val));
}
void truncate(size_t new_size);
template <typename U>
decltype(auto) push_back(U&& val) noexcept
template <typename ElemType>
decltype(auto) push_back(ElemType&& val) noexcept
{
auto nde = impl::make_node(std::forward<U>(val));
values.emplace_back(nde);
auto nde = impl::make_node(std::forward<ElemType>(val));
elements.emplace_back(nde);
return *nde;
}
template <typename U, typename... V>
decltype(auto) emplace_back(V&&... args) noexcept
template <typename ElemType, typename... Args>
decltype(auto) emplace_back(Args&&... args) noexcept
{
using type = impl::unwrap_node<U>;
using type = impl::unwrap_node<ElemType>;
static_assert(
(impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
"Emplacement type parameter must be one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
auto nde = new impl::wrap_node<type>{ std::forward<V>(args)... };
values.emplace_back(nde);
auto nde = new impl::wrap_node<type>{ std::forward<Args>(args)... };
elements.emplace_back(nde);
return *nde;
}
@ -3655,21 +3650,21 @@ TOML_NAMESPACE_START
[[nodiscard]] node* get(size_t index) noexcept;
[[nodiscard]] const node* get(size_t index) const noexcept;
template <typename T>
template <typename ElemType>
[[nodiscard]]
impl::wrap_node<T>* get_as(size_t index) noexcept
impl::wrap_node<ElemType>* get_as(size_t index) noexcept
{
if (auto val = get(index))
return val->as<T>();
return val->as<ElemType>();
return nullptr;
}
template <typename T>
template <typename ElemType>
[[nodiscard]]
const impl::wrap_node<T>* get_as(size_t index) const noexcept
const impl::wrap_node<ElemType>* get_as(size_t index) const noexcept
{
if (auto val = get(index))
return val->as<T>();
return val->as<ElemType>();
return nullptr;
}
@ -3942,7 +3937,7 @@ TOML_NAMESPACE_START
private:
friend class TOML_PARSER_TYPENAME;
impl::string_map<std::unique_ptr<node>> values;
impl::string_map<std::unique_ptr<node>> map;
bool inline_ = false;
table(impl::table_init_pair*, size_t) noexcept;
@ -3996,31 +3991,31 @@ TOML_NAMESPACE_START
[[nodiscard]] size_t size() const noexcept;
void clear() noexcept;
template <typename K, typename V, typename = std::enable_if_t<
std::is_convertible_v<K&&, std::string_view>
|| impl::is_wide_string<K>
template <typename KeyType, typename ValueType, typename = std::enable_if_t<
std::is_convertible_v<KeyType&&, std::string_view>
|| impl::is_wide_string<KeyType>
>>
std::pair<iterator, bool> insert(K&& key, V&& val) noexcept
std::pair<iterator, bool> insert(KeyType&& key, ValueType&& val) noexcept
{
static_assert(
!impl::is_wide_string<K> || TOML_WINDOWS_COMPAT,
!impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
"Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
if constexpr (impl::is_wide_string<K>)
if constexpr (impl::is_wide_string<KeyType>)
{
#if TOML_WINDOWS_COMPAT
return insert(impl::narrow(std::forward<K>(key)), std::forward<V>(val));
return insert(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val));
#else
static_assert(impl::dependent_false<K>, "Evaluated unreachable branch!");
static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
#endif
}
else
{
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
auto ipos = map.lower_bound(key);
if (ipos == map.end() || ipos->first != key)
{
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val)));
return { ipos, true };
}
return { ipos, false };
@ -4044,71 +4039,71 @@ TOML_NAMESPACE_START
}
}
template <typename K, typename V>
std::pair<iterator, bool> insert_or_assign(K&& key, V&& val) noexcept
template <typename KeyType, typename ValueType>
std::pair<iterator, bool> insert_or_assign(KeyType&& key, ValueType&& val) noexcept
{
static_assert(
!impl::is_wide_string<K> || TOML_WINDOWS_COMPAT,
!impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
"Insertion using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
if constexpr (impl::is_wide_string<K>)
if constexpr (impl::is_wide_string<KeyType>)
{
#if TOML_WINDOWS_COMPAT
return insert_or_assign(impl::narrow(std::forward<K>(key)), std::forward<V>(val));
return insert_or_assign(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueType>(val));
#else
static_assert(impl::dependent_false<K>, "Evaluated unreachable branch!");
static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
#endif
}
else
{
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
auto ipos = map.lower_bound(key);
if (ipos == map.end() || ipos->first != key)
{
ipos = values.emplace_hint(ipos, std::forward<K>(key), impl::make_node(std::forward<V>(val)));
ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val)));
return { ipos, true };
}
else
{
(*ipos).second.reset(impl::make_node(std::forward<V>(val)));
(*ipos).second.reset(impl::make_node(std::forward<ValueType>(val)));
return { ipos, false };
}
}
}
template <typename U, typename K, typename... V>
std::pair<iterator, bool> emplace(K&& key, V&&... args) noexcept
template <typename ValueType, typename KeyType, typename... ValueArgs>
std::pair<iterator, bool> emplace(KeyType&& key, ValueArgs&&... args) noexcept
{
static_assert(
!impl::is_wide_string<K> || TOML_WINDOWS_COMPAT,
!impl::is_wide_string<KeyType> || TOML_WINDOWS_COMPAT,
"Emplacement using wide-character keys is only supported on Windows with TOML_WINDOWS_COMPAT enabled."
);
if constexpr (impl::is_wide_string<K>)
if constexpr (impl::is_wide_string<KeyType>)
{
#if TOML_WINDOWS_COMPAT
return emplace<U>(impl::narrow(std::forward<K>(key)), std::forward<V>(args)...);
return emplace<ValueType>(impl::narrow(std::forward<KeyType>(key)), std::forward<ValueArgs>(args)...);
#else
static_assert(impl::dependent_false<U>, "Evaluated unreachable branch!");
static_assert(impl::dependent_false<KeyType>, "Evaluated unreachable branch!");
#endif
}
else
{
using type = impl::unwrap_node<U>;
using type = impl::unwrap_node<ValueType>;
static_assert(
(impl::is_native<type> || impl::is_one_of<type, table, array>) && !impl::is_cvref<type>,
"The emplacement type argument of table::emplace() must be one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
auto ipos = values.lower_bound(key);
if (ipos == values.end() || ipos->first != key)
auto ipos = map.lower_bound(key);
if (ipos == map.end() || ipos->first != key)
{
ipos = values.emplace_hint(
ipos = map.emplace_hint(
ipos,
std::forward<K>(key),
new impl::wrap_node<type>{ std::forward<V>(args)... }
std::forward<KeyType>(key),
new impl::wrap_node<type>{ std::forward<ValueArgs>(args)... }
);
return { ipos, true };
}
@ -4189,34 +4184,34 @@ TOML_NAMESPACE_START
#endif // TOML_WINDOWS_COMPAT
template <typename T>
template <typename ValueType>
[[nodiscard]]
impl::wrap_node<T>* get_as(std::string_view key) noexcept
impl::wrap_node<ValueType>* get_as(std::string_view key) noexcept
{
return do_get_as<T>(values, key);
return do_get_as<ValueType>(map, key);
}
template <typename T>
template <typename ValueType>
[[nodiscard]]
const impl::wrap_node<T>* get_as(std::string_view key) const noexcept
const impl::wrap_node<ValueType>* get_as(std::string_view key) const noexcept
{
return do_get_as<T>(values, key);
return do_get_as<ValueType>(map, key);
}
#if TOML_WINDOWS_COMPAT
template <typename T>
template <typename ValueType>
[[nodiscard]]
impl::wrap_node<T>* get_as(std::wstring_view key) noexcept
impl::wrap_node<ValueType>* get_as(std::wstring_view key) noexcept
{
return get_as<T>(impl::narrow(key));
return get_as<ValueType>(impl::narrow(key));
}
template <typename T>
template <typename ValueType>
[[nodiscard]]
const impl::wrap_node<T>* get_as(std::wstring_view key) const noexcept
const impl::wrap_node<ValueType>* get_as(std::wstring_view key) const noexcept
{
return get_as<T>(impl::narrow(key));
return get_as<ValueType>(impl::narrow(key));
}
#endif // TOML_WINDOWS_COMPAT
@ -7302,13 +7297,16 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
void array::preinsertion_resize(size_t idx, size_t count) noexcept
{
const auto new_size = values.size() + count;
const auto inserting_at_end = idx == values.size();
values.resize(new_size);
TOML_ASSERT(idx <= elements.size());
TOML_ASSERT(count >= 1_sz);
const auto old_size = elements.size();
const auto new_size = old_size + count;
const auto inserting_at_end = idx == old_size;
elements.resize(new_size);
if (!inserting_at_end)
{
for (size_t r = new_size, e = idx + count, l = e; r-- > e; l--)
values[r] = std::move(values[l]);
for(size_t left = old_size, right = new_size - 1_sz; left --> idx; right--)
elements[right] = std::move(elements[left]);
}
}
@ -7318,14 +7316,14 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
array::array(array&& other) noexcept
: node{ std::move(other) },
values{ std::move(other.values) }
elements{ std::move(other.elements) }
{}
TOML_EXTERNAL_LINKAGE
array& array::operator= (array&& rhs) noexcept
{
node::operator=(std::move(rhs));
values = std::move(rhs.values);
elements = std::move(rhs.elements);
return *this;
}
@ -7338,69 +7336,69 @@ TOML_NAMESPACE_START
TOML_MEMBER_ATTR(const) const array* array::as_array() const noexcept { return this; }
TOML_MEMBER_ATTR(const) array* array::as_array() noexcept { return this; }
TOML_MEMBER_ATTR(pure) const node& array::operator[] (size_t index) const noexcept { return *values[index]; }
TOML_MEMBER_ATTR(pure) node& array::operator[] (size_t index) noexcept { return *values[index]; }
TOML_MEMBER_ATTR(pure) const node& array::operator[] (size_t index) const noexcept { return *elements[index]; }
TOML_MEMBER_ATTR(pure) node& array::operator[] (size_t index) noexcept { return *elements[index]; }
TOML_MEMBER_ATTR(pure) const node& array::front() const noexcept { return *values.front(); }
TOML_MEMBER_ATTR(pure) const node& array::back() const noexcept { return *values.back(); }
TOML_MEMBER_ATTR(pure) node& array::front() noexcept { return *values.front(); }
TOML_MEMBER_ATTR(pure) node& array::back() noexcept { return *values.back(); }
TOML_MEMBER_ATTR(pure) const node& array::front() const noexcept { return *elements.front(); }
TOML_MEMBER_ATTR(pure) const node& array::back() const noexcept { return *elements.back(); }
TOML_MEMBER_ATTR(pure) node& array::front() noexcept { return *elements.front(); }
TOML_MEMBER_ATTR(pure) node& array::back() noexcept { return *elements.back(); }
TOML_MEMBER_ATTR(pure) array::const_iterator array::begin() const noexcept { return { values.begin() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::end() const noexcept { return { values.end() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::cbegin() const noexcept { return { values.cbegin() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::cend() const noexcept { return { values.cend() }; }
TOML_MEMBER_ATTR(pure) array::iterator array::begin() noexcept { return { values.begin() }; }
TOML_MEMBER_ATTR(pure) array::iterator array::end() noexcept { return { values.end() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::begin() const noexcept { return { elements.begin() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::end() const noexcept { return { elements.end() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::cbegin() const noexcept { return { elements.cbegin() }; }
TOML_MEMBER_ATTR(pure) array::const_iterator array::cend() const noexcept { return { elements.cend() }; }
TOML_MEMBER_ATTR(pure) array::iterator array::begin() noexcept { return { elements.begin() }; }
TOML_MEMBER_ATTR(pure) array::iterator array::end() noexcept { return { elements.end() }; }
TOML_MEMBER_ATTR(pure) size_t array::size() const noexcept { return values.size(); }
TOML_MEMBER_ATTR(pure) size_t array::capacity() const noexcept { return values.capacity(); }
TOML_MEMBER_ATTR(pure) bool array::empty() const noexcept { return values.empty(); }
TOML_MEMBER_ATTR(const) size_t array::max_size() const noexcept { return values.max_size(); }
TOML_MEMBER_ATTR(pure) size_t array::size() const noexcept { return elements.size(); }
TOML_MEMBER_ATTR(pure) size_t array::capacity() const noexcept { return elements.capacity(); }
TOML_MEMBER_ATTR(pure) bool array::empty() const noexcept { return elements.empty(); }
TOML_MEMBER_ATTR(const) size_t array::max_size() const noexcept { return elements.max_size(); }
TOML_EXTERNAL_LINKAGE void array::reserve(size_t new_capacity) { values.reserve(new_capacity); }
TOML_EXTERNAL_LINKAGE void array::clear() noexcept { values.clear(); }
TOML_EXTERNAL_LINKAGE void array::shrink_to_fit() { values.shrink_to_fit(); }
TOML_EXTERNAL_LINKAGE void array::reserve(size_t new_capacity) { elements.reserve(new_capacity); }
TOML_EXTERNAL_LINKAGE void array::clear() noexcept { elements.clear(); }
TOML_EXTERNAL_LINKAGE void array::shrink_to_fit() { elements.shrink_to_fit(); }
#undef TOML_MEMBER_ATTR
TOML_EXTERNAL_LINKAGE
void array::truncate(size_t new_size)
{
if (new_size < values.size())
values.resize(new_size);
if (new_size < elements.size())
elements.resize(new_size);
}
TOML_EXTERNAL_LINKAGE
array::iterator array::erase(const_iterator pos) noexcept
{
return { values.erase(pos.raw_) };
return { elements.erase(pos.raw_) };
}
TOML_EXTERNAL_LINKAGE
array::iterator array::erase(const_iterator first, const_iterator last) noexcept
{
return { values.erase(first.raw_, last.raw_) };
return { elements.erase(first.raw_, last.raw_) };
}
TOML_EXTERNAL_LINKAGE
void array::pop_back() noexcept
{
values.pop_back();
elements.pop_back();
}
TOML_EXTERNAL_LINKAGE
TOML_ATTR(pure)
node* array::get(size_t index) noexcept
{
return index < values.size() ? values[index].get() : nullptr;
return index < elements.size() ? elements[index].get() : nullptr;
}
TOML_EXTERNAL_LINKAGE
TOML_ATTR(pure)
const node* array::get(size_t index) const noexcept
{
return index < values.size() ? values[index].get() : nullptr;
return index < elements.size() ? elements[index].get() : nullptr;
}
TOML_API
@ -7409,17 +7407,17 @@ TOML_NAMESPACE_START
{
if (&lhs == &rhs)
return true;
if (lhs.values.size() != rhs.values.size())
if (lhs.elements.size() != rhs.elements.size())
return false;
for (size_t i = 0, e = lhs.values.size(); i < e; i++)
for (size_t i = 0, e = lhs.elements.size(); i < e; i++)
{
const auto lhs_type = lhs.values[i]->type();
const node& rhs_ = *rhs.values[i];
const auto lhs_type = lhs.elements[i]->type();
const node& rhs_ = *rhs.elements[i];
const auto rhs_type = rhs_.type();
if (lhs_type != rhs_type)
return false;
const bool equal = lhs.values[i]->visit([&](const auto& lhs_) noexcept
const bool equal = lhs.elements[i]->visit([&](const auto& lhs_) noexcept
{
return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_);
});
@ -7440,9 +7438,9 @@ TOML_NAMESPACE_START
size_t array::total_leaf_count() const noexcept
{
size_t leaves{};
for (size_t i = 0, e = values.size(); i < e; i++)
for (size_t i = 0, e = elements.size(); i < e; i++)
{
auto arr = values[i]->as_array();
auto arr = elements[i]->as_array();
leaves += arr ? arr->total_leaf_count() : 1_sz;
}
return leaves;
@ -7453,29 +7451,29 @@ TOML_NAMESPACE_START
{
for (size_t i = 0, e = child.size(); i < e; i++)
{
auto type = child.values[i]->type();
auto type = child.elements[i]->type();
if (type == node_type::array)
{
array& arr = *reinterpret_cast<array*>(child.values[i].get());
array& arr = *reinterpret_cast<array*>(child.elements[i].get());
if (!arr.empty())
flatten_child(std::move(arr), dest_index);
}
else
values[dest_index++] = std::move(child.values[i]);
elements[dest_index++] = std::move(child.elements[i]);
}
}
TOML_EXTERNAL_LINKAGE
array& array::flatten() &
{
if (values.empty())
if (elements.empty())
return *this;
bool requires_flattening = false;
size_t size_after_flattening = values.size();
for (size_t i = values.size(); i --> 0_sz;)
size_t size_after_flattening = elements.size();
for (size_t i = elements.size(); i --> 0_sz;)
{
auto arr = values[i]->as_array();
auto arr = elements[i]->as_array();
if (!arr)
continue;
size_after_flattening--; //discount the array itself
@ -7486,25 +7484,25 @@ TOML_NAMESPACE_START
size_after_flattening += leaf_count;
}
else
values.erase(values.cbegin() + static_cast<ptrdiff_t>(i));
elements.erase(elements.cbegin() + static_cast<ptrdiff_t>(i));
}
if (!requires_flattening)
return *this;
values.reserve(size_after_flattening);
elements.reserve(size_after_flattening);
size_t i = 0;
while (i < values.size())
while (i < elements.size())
{
auto arr = values[i]->as_array();
auto arr = elements[i]->as_array();
if (!arr)
{
i++;
continue;
}
std::unique_ptr<node> arr_storage = std::move(values[i]);
std::unique_ptr<node> arr_storage = std::move(elements[i]);
const auto leaf_count = arr->total_leaf_count();
if (leaf_count > 1_sz)
preinsertion_resize(i + 1_sz, leaf_count - 1_sz);
@ -7517,13 +7515,13 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type type) const noexcept
{
if (values.empty())
if (elements.empty())
return false;
if (type == node_type::none)
type = values[0]->type();
type = elements[0]->type();
for (const auto& val : values)
for (const auto& val : elements)
if (val->type() != type)
return false;
return true;
@ -7556,7 +7554,7 @@ TOML_NAMESPACE_START
{
for (size_t i = 0; i < count; i++)
{
values.insert_or_assign(
map.insert_or_assign(
std::move(pairs[i].key),
std::move(pairs[i].value)
);
@ -7569,7 +7567,7 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
table::table(table&& other) noexcept
: node{ std::move(other) },
values{ std::move(other.values) },
map{ std::move(other.map) },
inline_{ other.inline_ }
{}
@ -7577,7 +7575,7 @@ TOML_NAMESPACE_START
table& table::operator = (table&& rhs) noexcept
{
node::operator=(std::move(rhs));
values = std::move(rhs.values);
map = std::move(rhs.map);
inline_ = rhs.inline_;
return *this;
}
@ -7594,16 +7592,16 @@ TOML_NAMESPACE_START
TOML_MEMBER_ATTR(pure) bool table::is_inline() const noexcept { return inline_; }
TOML_EXTERNAL_LINKAGE void table::is_inline(bool val) noexcept { inline_ = val; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::begin() const noexcept { return { values.begin() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::end() const noexcept { return { values.end() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::cbegin() const noexcept { return { values.cbegin() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::cend() const noexcept { return { values.cend() }; }
TOML_EXTERNAL_LINKAGE table::iterator table::begin() noexcept { return { values.begin() }; }
TOML_EXTERNAL_LINKAGE table::iterator table::end() noexcept { return { values.end() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::begin() const noexcept { return { map.begin() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::end() const noexcept { return { map.end() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::cbegin() const noexcept { return { map.cbegin() }; }
TOML_EXTERNAL_LINKAGE table::const_iterator table::cend() const noexcept { return { map.cend() }; }
TOML_EXTERNAL_LINKAGE table::iterator table::begin() noexcept { return { map.begin() }; }
TOML_EXTERNAL_LINKAGE table::iterator table::end() noexcept { return { map.end() }; }
TOML_MEMBER_ATTR(pure) bool table::empty() const noexcept { return values.empty(); }
TOML_MEMBER_ATTR(pure) size_t table::size() const noexcept { return values.size(); }
TOML_EXTERNAL_LINKAGE void table::clear() noexcept { values.clear(); }
TOML_MEMBER_ATTR(pure) bool table::empty() const noexcept { return map.empty(); }
TOML_MEMBER_ATTR(pure) size_t table::size() const noexcept { return map.size(); }
TOML_EXTERNAL_LINKAGE void table::clear() noexcept { map.clear(); }
#undef TOML_MEMBER_ATTR
@ -7621,27 +7619,27 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
table::iterator table::erase(iterator pos) noexcept
{
return { values.erase(pos.raw_) };
return { map.erase(pos.raw_) };
}
TOML_EXTERNAL_LINKAGE
table::iterator table::erase(const_iterator pos) noexcept
{
return { values.erase(pos.raw_) };
return { map.erase(pos.raw_) };
}
TOML_EXTERNAL_LINKAGE
table::iterator table::erase(const_iterator first, const_iterator last) noexcept
{
return { values.erase(first.raw_, last.raw_) };
return { map.erase(first.raw_, last.raw_) };
}
TOML_EXTERNAL_LINKAGE
bool table::erase(std::string_view key) noexcept
{
if (auto it = values.find(key); it != values.end())
if (auto it = map.find(key); it != map.end())
{
values.erase(it);
map.erase(it);
return true;
}
return false;
@ -7650,31 +7648,31 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
node* table::get(std::string_view key) noexcept
{
return do_get(values, key);
return do_get(map, key);
}
TOML_EXTERNAL_LINKAGE
const node* table::get(std::string_view key) const noexcept
{
return do_get(values, key);
return do_get(map, key);
}
TOML_EXTERNAL_LINKAGE
table::iterator table::find(std::string_view key) noexcept
{
return { values.find(key) };
return { map.find(key) };
}
TOML_EXTERNAL_LINKAGE
table::const_iterator table::find(std::string_view key) const noexcept
{
return { values.find(key) };
return { map.find(key) };
}
TOML_EXTERNAL_LINKAGE
bool table::contains(std::string_view key) const noexcept
{
return do_contains(values, key);
return do_contains(map, key);
}
#if TOML_WINDOWS_COMPAT
@ -7734,10 +7732,10 @@ TOML_NAMESPACE_START
{
if (&lhs == &rhs)
return true;
if (lhs.values.size() != rhs.values.size())
if (lhs.map.size() != rhs.map.size())
return false;
for (auto l = lhs.values.begin(), r = rhs.values.begin(), e = lhs.values.end(); l != e; l++, r++)
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;
@ -10638,7 +10636,7 @@ TOML_IMPL_NAMESPACE_START
auto child = parent->get(key.segments[i]);
if (!child)
{
child = parent->values.emplace(
child = parent->map.emplace(
key.segments[i],
new toml::table{}
).first->second.get();
@ -10654,9 +10652,9 @@ TOML_IMPL_NAMESPACE_START
{
// table arrays are a special case;
// the spec dictates we select the most recently declared element in the array.
TOML_ASSERT(!child->ref_cast<array>().values.empty());
TOML_ASSERT(child->ref_cast<array>().values.back()->is_table());
parent = &child->ref_cast<array>().values.back()->ref_cast<table>();
TOML_ASSERT(!child->ref_cast<array>().elements.empty());
TOML_ASSERT(child->ref_cast<array>().elements.back()->is_table());
parent = &child->ref_cast<array>().elements.back()->ref_cast<table>();
}
else
{
@ -10683,22 +10681,22 @@ TOML_IMPL_NAMESPACE_START
// set the starting regions, and return the table element
if (is_arr)
{
auto tab_arr = &parent->values.emplace(
auto tab_arr = &parent->map.emplace(
key.segments.back(),
new toml::array{}
).first->second->ref_cast<array>();
table_arrays.push_back(tab_arr);
tab_arr->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
tab_arr->values.emplace_back(new toml::table{});
tab_arr->values.back()->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
return &tab_arr->values.back()->ref_cast<table>();
tab_arr->elements.emplace_back(new toml::table{});
tab_arr->elements.back()->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
return &tab_arr->elements.back()->ref_cast<table>();
}
//otherwise we're just making a table
else
{
auto tab = &parent->values.emplace(
auto tab = &parent->map.emplace(
key.segments.back(),
new toml::table{})
.first->second->ref_cast<table>();
@ -10716,9 +10714,9 @@ TOML_IMPL_NAMESPACE_START
if (is_arr && matching_node->is_array() && find(table_arrays, &matching_node->ref_cast<array>()))
{
auto tab_arr = &matching_node->ref_cast<array>();
tab_arr->values.emplace_back(new toml::table{});
tab_arr->values.back()->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
return &tab_arr->values.back()->ref_cast<table>();
tab_arr->elements.emplace_back(new toml::table{});
tab_arr->elements.back()->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
return &tab_arr->elements.back()->ref_cast<table>();
}
else if (!is_arr
@ -10764,7 +10762,7 @@ TOML_IMPL_NAMESPACE_START
auto child = tab->get(kvp.key.segments[i]);
if (!child)
{
child = tab->values.emplace(
child = tab->map.emplace(
std::move(kvp.key.segments[i]),
new toml::table{}
).first->second.get();
@ -10797,7 +10795,7 @@ TOML_IMPL_NAMESPACE_START
}
return_if_error();
tab->values.emplace(
tab->map.emplace(
std::move(kvp.key.segments.back()),
std::unique_ptr<node>{ kvp.value }
);
@ -10869,7 +10867,7 @@ TOML_IMPL_NAMESPACE_START
return;
auto end = nde.source_.end;
for (auto& [k, v] : tbl.values)
for (auto& [k, v] : tbl.map)
{
(void)k;
update_region_ends(*v);
@ -10881,7 +10879,7 @@ TOML_IMPL_NAMESPACE_START
{
auto& arr = nde.ref_cast<array>();
auto end = nde.source_.end;
for (auto& v : arr.values)
for (auto& v : arr.elements)
{
update_region_ends(*v);
if (end < v->source_.end)
@ -10953,7 +10951,7 @@ TOML_IMPL_NAMESPACE_START
advance_and_return_if_error_or_eof({});
auto arr = new array{};
auto& vals = arr->values;
auto& vals = arr->elements;
enum parse_elem : int
{
none,
@ -11446,6 +11444,4 @@ TOML_NAMESPACE_END
#undef TOML_USING_ANON_NAMESPACE
#endif
#endif // INCLUDE_TOMLPLUSPLUS_H
// clang-format on