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 MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 0 TOC_INCLUDE_HEADINGS = 0
AUTOLINK_SUPPORT = YES AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = YES BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = NO IDL_PROPERTY_SUPPORT = NO

View File

@ -47,7 +47,7 @@ article div > section > section
pre, code, .tpp-enable-if > a 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 a.tpp-external

View File

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

View File

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

View File

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

View File

@ -145,9 +145,6 @@ TOML_NAMESPACE_START // abi namespace
template <typename T> template <typename T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<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> template <typename T, typename... U>
inline constexpr bool is_one_of = (false || ... || std::is_same_v<T, 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++. /// \brief Convenience literal operators for working with toml++.
/// ///
/// \detail This namespace exists so you can safely hoist the UDL operators into another scope /// \detail This namespace exists so you can safely hoist the toml++ literal operators into another scope
/// without dragging in everything in the toml namespace: \cpp /// without dragging in everything from the toml namespace: \cpp
/// ///
/// #include <toml++/toml.h> /// #include <toml++/toml.h>
/// using namespace toml::literals; /// using namespace toml::literals;
/// ///
/// int main() /// 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; /// return 0;
/// } /// }

View File

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

View File

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

View File

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

View File

@ -84,7 +84,7 @@ TOML_IMPL_NAMESPACE_START
using traits = value_traits<T>; using traits = value_traits<T>;
if constexpr (!traits::is_signed) 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{}); using common_t = decltype(int64_t{} + T{});
if (val < int64_t{} || static_cast<common_t>(val) > static_cast<common_t>(traits::max)) 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', 'default_formatter',
'format_flags', 'format_flags',
'inserter', 'inserter',
'node_type',
] ]
all_namespaces = [ all_namespaces = [
'std', '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 = re.sub(blank_lines_between_returns_pattern, '\\1\n\\2', source_text, 0, re.I | re.M)
source_text = source_text.strip() + '\n' 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 # extract library version
library_version = { library_version = {
'major': 0, 'major': 0,
@ -145,16 +152,8 @@ def main():
write(line) write(line)
write('//') write('//')
write(utils.make_divider()) 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(source_text)
write('') write('')
write('#endif // INCLUDE_TOMLPLUSPLUS_H')
write('// clang-format on')
output_str = output.getvalue().strip() output_str = output.getvalue().strip()
@ -171,6 +170,7 @@ def main():
if m: if m:
defines[m.group(1)] = defined defines[m.group(1)] = defined
ignore_list = ( # macros that are meant to stay public (user configs etc) ignore_list = ( # macros that are meant to stay public (user configs etc)
'INCLUDE_TOMLPLUSPLUS_H',
'TOML_API', 'TOML_API',
'TOML_UNRELEASED_FEATURES', 'TOML_UNRELEASED_FEATURES',
'TOML_LARGE_FILES', 'TOML_LARGE_FILES',

View File

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