added insert, emplace, push_back etc. compatibility with node_views

In service of satisfying #49.
This commit is contained in:
Mark Gillard 2020-07-28 01:04:52 +03:00
parent 17d1876529
commit 2efb15bf9e
47 changed files with 417 additions and 118 deletions

View File

@ -350,7 +350,6 @@ PREDEFINED = \
"TOML_TRIVIAL_ABI=" \ "TOML_TRIVIAL_ABI=" \
"TOML_EMPTY_BASES=" \ "TOML_EMPTY_BASES=" \
"TOML_INTERFACE" \ "TOML_INTERFACE" \
"TOML_SIMPLE_STATIC_ASSERT_MESSAGES=1" \
"TOML_INTERNAL_LINKAGE=static" "TOML_INTERNAL_LINKAGE=static"
EXPAND_AS_DEFINED = EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = NO SKIP_FUNCTION_MACROS = 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 Code Pro', monospace, monospace, monospace; font-family: 'Consolas', 'Source Code Pro', monospace;
} }
a.tpp-external a.tpp-external
@ -142,6 +142,7 @@ pre.m-code + pre.m-console span
.m-doc-details div table.m-table.m-fullwidth.m-flat tbody tr td strong em .m-doc-details div table.m-table.m-fullwidth.m-flat tbody tr td strong em
{ {
color: #a5c9ea; color: #a5c9ea;
font-style: normal;
} }
/* comments */ /* comments */
@ -316,9 +317,10 @@ pre > p.godbolt
{ {
float: right; float: right;
} }
@media only screen and ((max-width: 575px) or ((hover: none) and (pointer: coarse))) @media only screen and ((max-width: 575px) or (hover: none) or (pointer: coarse) or (pointer: none))
{ {
.godbolt { .godbolt
{
display: none; display: none;
} }
} }

View File

@ -129,7 +129,10 @@ int main(int argc, char** argv)
toml::node* new_node{}; toml::node* new_node{};
if (auto arr = tree.back()->as_array()) if (auto arr = tree.back()->as_array())
new_node = &arr->push_back(std::forward<decltype(obj)>(obj)); {
arr->push_back(std::forward<decltype(obj)>(obj));
new_node = &arr->back();
}
else else
new_node = &(*tree.back()->ref<toml::table>().insert_or_assign( new_node = &(*tree.back()->ref<toml::table>().insert_or_assign(
rand_string(rand<size_t>(1u, 4u), '-'), rand_string(rand<size_t>(1u, 4u), '-'),

View File

@ -15,7 +15,7 @@ TOML_IMPL_NAMESPACE_START
class TOML_TRIVIAL_ABI array_iterator final class TOML_TRIVIAL_ABI array_iterator final
{ {
private: private:
friend class ::toml::array; friend class TOML_NAMESPACE::array;
using raw_mutable_iterator = std::vector<std::unique_ptr<node>>::iterator; using raw_mutable_iterator = std::vector<std::unique_ptr<node>>::iterator;
using raw_const_iterator = std::vector<std::unique_ptr<node>>::const_iterator; using raw_const_iterator = std::vector<std::unique_ptr<node>>::const_iterator;
@ -180,6 +180,7 @@ TOML_IMPL_NAMESPACE_START
{ {
using type = unwrap_node<remove_cvref_t<T>>; using type = unwrap_node<remove_cvref_t<T>>;
static_assert(!std::is_same_v<type, node>); static_assert(!std::is_same_v<type, node>);
static_assert(!is_node_view<type>);
if constexpr (is_one_of<type, array, table>) if constexpr (is_one_of<type, array, table>)
{ {
@ -211,12 +212,17 @@ TOML_IMPL_NAMESPACE_START
template <typename T> template <typename T>
[[nodiscard]] [[nodiscard]]
TOML_ATTR(returns_nonnull)
auto* make_node(T&& val) noexcept auto* make_node(T&& val) noexcept
{ {
using type = unwrap_node<remove_cvref_t<T>>; using type = unwrap_node<remove_cvref_t<T>>;
if constexpr (std::is_same_v<type, node>) if constexpr (std::is_same_v<type, node> || is_node_view<type>)
{ {
if constexpr (is_node_view<type>)
{
if (!val)
return static_cast<toml::node*>(nullptr);
}
return std::forward<T>(val).visit([](auto&& concrete) noexcept return std::forward<T>(val).visit([](auto&& concrete) noexcept
{ {
return static_cast<toml::node*>(make_node_specialized(std::forward<decltype(concrete)>(concrete))); return static_cast<toml::node*>(make_node_specialized(std::forward<decltype(concrete)>(concrete)));
@ -228,7 +234,6 @@ TOML_IMPL_NAMESPACE_START
template <typename T> template <typename T>
[[nodiscard]] [[nodiscard]]
TOML_ATTR(returns_nonnull)
auto* make_node(inserter<T>&& val) noexcept auto* make_node(inserter<T>&& val) noexcept
{ {
return make_node(std::move(val.value)); return make_node(std::move(val.value));
@ -304,6 +309,17 @@ TOML_NAMESPACE_START
void preinsertion_resize(size_t idx, size_t count) noexcept; void preinsertion_resize(size_t idx, size_t count) noexcept;
template <typename T>
void emplace_back_if_not_empty_view(T&& val) noexcept
{
if constexpr (impl::is_node_view<T>)
{
if (!val)
return;
}
elements.emplace_back(impl::make_node(std::forward<T>(val)));
}
public: public:
using value_type = node; using value_type = node;
@ -376,11 +392,11 @@ TOML_NAMESPACE_START
explicit array(ElemType&& val, ElemTypes&&... vals) explicit array(ElemType&& val, ElemTypes&&... vals)
{ {
elements.reserve(sizeof...(ElemTypes) + 1_sz); elements.reserve(sizeof...(ElemTypes) + 1_sz);
elements.emplace_back(impl::make_node(std::forward<ElemType>(val))); emplace_back_if_not_empty_view(std::forward<ElemType>(val));
if constexpr (sizeof...(ElemTypes) > 0) if constexpr (sizeof...(ElemTypes) > 0)
{ {
( (
elements.emplace_back(impl::make_node(std::forward<ElemTypes>(vals))), emplace_back_if_not_empty_view(std::forward<ElemTypes>(vals)),
... ...
); );
} }
@ -529,14 +545,27 @@ TOML_NAMESPACE_START
/// [ 1, 'two', 3, [ 4, 5 ] ] /// [ 1, 'two', 3, [ 4, 5 ] ]
/// \eout /// \eout
/// ///
/// \tparam ElemType One of the TOML node or value types (or a type promotable to one). /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
/// (or a type promotable to one).
/// \param pos The insertion position. /// \param pos The insertion position.
/// \param val The node or value being inserted. /// \param val The node or value being inserted.
/// ///
/// \returns An iterator to the newly-inserted element. /// \returns <strong><em>Valid input:</em></strong><br>
/// An iterator to the newly-inserted element.
/// <br><br>
/// <strong><em>`val` is an empty toml::node_view:</em></strong><br>
/// end()
///
/// \attention The return value will always be `end()` if the input value was an empty toml::node_view,
/// because no insertion can take place. This is the only circumstance in which this can occur.
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, ElemType&& val) noexcept iterator insert(const_iterator pos, ElemType&& val) noexcept
{ {
if constexpr (impl::is_node_view<ElemType>)
{
if (!val)
return end();
}
return { elements.emplace(pos.raw_, impl::make_node(std::forward<ElemType>(val))) }; return { elements.emplace(pos.raw_, impl::make_node(std::forward<ElemType>(val))) };
} }
@ -562,15 +591,31 @@ TOML_NAMESPACE_START
/// ] /// ]
/// \eout /// \eout
/// ///
/// \tparam ElemType One of the TOML node or value types (or a type promotable to one). /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
/// (or a type promotable to one).
/// \param pos The insertion position. /// \param pos The insertion position.
/// \param count The number of times the node or value should be inserted. /// \param count The number of times the node or value should be inserted.
/// \param val The node or value being inserted. /// \param val The node or value being inserted.
/// ///
/// \returns An iterator to the first newly-inserted element (or a copy of `pos` if count was 0). /// \returns <strong><em>Valid input:</em></strong><br>
/// An iterator to the newly-inserted element.
/// <br><br>
/// <strong><em>`count == 0`:</em></strong><br>
/// A copy of pos
/// <br><br>
/// <strong><em>`val` is an empty toml::node_view:</em></strong><br>
/// end()
///
/// \attention The return value will always be `end()` if the input value was an empty toml::node_view,
/// because no insertion can take place. This is the only circumstance in which this can occur.
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, size_t count, ElemType&& val) noexcept iterator insert(const_iterator pos, size_t count, ElemType&& val) noexcept
{ {
if constexpr (impl::is_node_view<ElemType>)
{
if (!val)
return end();
}
switch (count) switch (count)
{ {
case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) }; case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) };
@ -597,50 +642,70 @@ TOML_NAMESPACE_START
/// \param first Iterator to the first node or value being inserted. /// \param first Iterator to the first node or value being inserted.
/// \param last Iterator to the one-past-the-last node or value being inserted. /// \param last Iterator to the one-past-the-last node or value being inserted.
/// ///
/// \returns An iterator to the first newly-inserted element (or a copy of `pos` if `first` >= `last`). /// \returns <strong><em>Valid input:</em></strong><br>
/// An iterator to the first newly-inserted element.
/// <br><br>
/// <strong><em>`first >= last`:</em></strong><br>
/// A copy of pos
/// <br><br>
/// <strong><em>All objects in the range were empty toml::node_views:</em></strong><br>
/// A copy of pos
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 distance = std::distance(first, last);
if (count <= 0) if (distance <= 0)
return { elements.begin() + (pos.raw_ - elements.cbegin()) }; return { elements.begin() + (pos.raw_ - elements.cbegin()) };
else if (count == 1)
return insert(pos, *first);
else else
{ {
auto count = distance;
using deref_type = decltype(*first);
if constexpr (impl::is_node_view<deref_type>)
{
for (auto it = first; it != last; it++)
if (!(*it))
count--;
if (!count)
return { elements.begin() + (pos.raw_ - elements.cbegin()) };
}
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin()); const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, static_cast<size_t>(count)); preinsertion_resize(start_idx, static_cast<size_t>(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++)
elements[i++].reset(impl::make_node(*it)); {
if constexpr (impl::is_node_view<deref_type>)
{
if (!(*it))
continue;
}
if constexpr (std::is_rvalue_reference_v<deref_type>)
elements[i++].reset(impl::make_node(std::move(*it)));
else
elements[i++].reset(impl::make_node(*it));
}
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) }; return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
} }
} }
/// \brief Inserts a range of elements into the array at a specific position. /// \brief Inserts a range of elements into the array at a specific position.
/// ///
/// \tparam ElemType One of the TOML node or value types (or a type promotable to one). /// \tparam ElemType toml::node_view, toml::table, toml::array, or a native TOML value type
/// (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 newly-inserted element (or a copy of `pos` if `ilist` was empty). /// \returns <strong><em>Valid input:</em></strong><br>
/// An iterator to the first newly-inserted element.
/// <br><br>
/// <strong><em>`ilist.size() == 0`:</em></strong><br>
/// A copy of pos
/// <br><br>
/// <strong><em>All objects in the list were empty toml::node_views:</em></strong><br>
/// A copy of pos
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, std::initializer_list<ElemType> ilist) noexcept iterator insert(const_iterator pos, std::initializer_list<ElemType> ilist) noexcept
{ {
switch (ilist.size()) return insert(pos, ilist.begin(), ilist.end());
{
case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) };
case 1: return insert(pos, *ilist.begin());
default:
{
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, ilist.size());
size_t i = start_idx;
for (auto& val : ilist)
elements[i++].reset(impl::make_node(val));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
}
}
} }
/// \brief Emplaces a new element at a specific position in the array. /// \brief Emplaces a new element at a specific position in the array.
@ -658,7 +723,7 @@ TOML_NAMESPACE_START
/// [ 1, 'drill', 2 ] /// [ 1, 'drill', 2 ]
/// \eout /// \eout
/// ///
/// \tparam ElemType One of the TOML node or value types. /// \tparam ElemType toml::table, toml::array, or any native TOML value type.
/// \tparam Args 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.
@ -745,13 +810,19 @@ TOML_NAMESPACE_START
/// [ 1, 2 ] /// [ 1, 2 ]
/// \eout /// \eout
/// ///
/// \tparam ElemType One of the TOML node or value types (or a type promotable to one). /// \tparam ElemType toml::node, toml::table, toml::array, or a native TOML value type
/// (or a type promotable to one).
/// ///
/// \param new_size The number of elements the array will have after resizing. /// \param new_size The number of elements the array will have after resizing.
/// \param default_init_val The node or value used to initialize new elements if the array needs to grow. /// \param default_init_val The node or value used to initialize new elements if the array needs to grow.
template <typename ElemType> template <typename ElemType>
void resize(size_t new_size, ElemType&& default_init_val) noexcept void resize(size_t new_size, ElemType&& default_init_val) noexcept
{ {
static_assert(
!impl::is_node_view<ElemType>,
"The default element type argument to toml::array::resize may not be toml::node_view."
);
if (!new_size) if (!new_size)
elements.clear(); elements.clear();
else if (new_size < elements.size()) else if (new_size < elements.size())
@ -800,16 +871,15 @@ TOML_NAMESPACE_START
/// [ 1, 2, 3, 4.0, [ 5, 'six' ] ] /// [ 1, 2, 3, 4.0, [ 5, 'six' ] ]
/// \eout /// \eout
/// ///
/// \tparam ElemType One of the TOML node or value types (or a type promotable to one). /// \tparam ElemType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
/// \param val The node or value being added. /// \param val The node or value being added.
/// ///
/// \returns A reference to the newly-constructed element. /// \attention No insertion takes place if the input value is an empty toml::node_view.
/// This is the only circumstance in which this can occur.
template <typename ElemType> template <typename ElemType>
decltype(auto) push_back(ElemType&& val) noexcept void push_back(ElemType&& val) noexcept
{ {
auto nde = impl::make_node(std::forward<ElemType>(val)); emplace_back_if_not_empty_view(std::forward<ElemType>(val));
elements.emplace_back(nde);
return *nde;
} }
/// \brief Emplaces a new element at the end of the array. /// \brief Emplaces a new element at the end of the array.
@ -825,7 +895,7 @@ TOML_NAMESPACE_START
/// [ 1, 2, [ 3, 'four' ] ] /// [ 1, 2, [ 3, 'four' ] ]
/// \eout /// \eout
/// ///
/// \tparam ElemType One of the TOML node or value types. /// \tparam ElemType toml::table, toml::array, or a native TOML value type
/// \tparam Args 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.
/// ///
@ -895,7 +965,7 @@ TOML_NAMESPACE_START
/// element [0] is an integer with value 42 /// element [0] is an integer with value 42
/// \eout /// \eout
/// ///
/// \tparam ElemType The element's type. /// \tparam ElemType toml::table, toml::array, or a native TOML value type
/// \param index The element's index. /// \param index The element's index.
/// ///
/// \returns A pointer to the selected element 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.
@ -910,7 +980,7 @@ TOML_NAMESPACE_START
/// \brief Gets the element 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 ElemType The element's type. /// \tparam ElemType toml::table, toml::array, or a native TOML value type
/// \param index The element's index. /// \param index The element's index.
/// ///
/// \returns A pointer to the selected element 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.

View File

@ -549,6 +549,9 @@ TOML_IMPL_NAMESPACE_START
template <> struct node_type_getter<array> { static constexpr auto value = node_type::array; }; template <> struct node_type_getter<array> { static constexpr auto value = node_type::array; };
template <typename T> template <typename T>
inline constexpr node_type node_type_of = node_type_getter<unwrap_node<remove_cvref_t<T>>>::value; inline constexpr node_type node_type_of = node_type_getter<unwrap_node<remove_cvref_t<T>>>::value;
template <typename T>
inline constexpr bool is_node_view = is_one_of<impl::remove_cvref_t<T>, node_view<node>, node_view<const node>>;
} }
TOML_IMPL_NAMESPACE_END TOML_IMPL_NAMESPACE_END

View File

@ -10,7 +10,7 @@ TOML_PUSH_WARNINGS
TOML_DISABLE_PADDING_WARNINGS TOML_DISABLE_PADDING_WARNINGS
TOML_DISABLE_MISC_WARNINGS TOML_DISABLE_MISC_WARNINGS
#if TOML_SIMPLE_STATIC_ASSERT_MESSAGES #if defined(doxygen) || TOML_SIMPLE_STATIC_ASSERT_MESSAGES
#define TOML_SA_NEWLINE " " #define TOML_SA_NEWLINE " "
#define TOML_SA_LIST_SEP ", " #define TOML_SA_LIST_SEP ", "

View File

@ -63,8 +63,8 @@ TOML_NAMESPACE_START
using viewed_type = ViewedType; using viewed_type = ViewedType;
private: private:
friend class toml::table; friend class TOML_NAMESPACE::table;
template <typename T> friend class toml::node_view; template <typename T> friend class TOML_NAMESPACE::node_view;
mutable viewed_type* node_ = nullptr; mutable viewed_type* node_ = nullptr;
@ -83,6 +83,19 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
node_view() noexcept = default; node_view() noexcept = default;
///// \brief Copy constructor.
TOML_NODISCARD_CTOR
node_view(const node_view&) noexcept = default;
///// \brief Copy-assignment operator.
TOML_NODISCARD_CTOR
node_view& operator= (const node_view&) noexcept = default;
///// \brief Move constructor.
node_view(node_view&&) noexcept = default;
node_view& operator= (node_view&&) noexcept = delete;
/// \brief Returns true if the view references a node. /// \brief Returns true if the view references a node.
[[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; } [[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; }
/// \brief Returns the node that's being referenced by the view. /// \brief Returns the node that's being referenced by the view.

View File

@ -25,7 +25,7 @@ TOML_IMPL_NAMESPACE_START
class table_iterator final class table_iterator final
{ {
private: private:
friend class ::toml::table; friend class TOML_NAMESPACE::table;
using proxy_type = table_proxy_pair<IsConst>; using proxy_type = table_proxy_pair<IsConst>;
using raw_mutable_iterator = string_map<std::unique_ptr<node>>::iterator; using raw_mutable_iterator = string_map<std::unique_ptr<node>>::iterator;
@ -278,7 +278,6 @@ TOML_NAMESPACE_START
: table{ arr, N } : table{ arr, N }
{} {}
/// \brief Always returns `node_type::table` for table nodes. /// \brief Always returns `node_type::table` for table nodes.
[[nodiscard]] node_type type() const noexcept override; [[nodiscard]] node_type type() const noexcept override;
/// \brief Always returns `true` for table nodes. /// \brief Always returns `true` for table nodes.
@ -453,13 +452,22 @@ TOML_NAMESPACE_START
/// \eout /// \eout
/// ///
/// \tparam KeyType std::string (or a type convertible to it). /// \tparam KeyType std::string (or a type convertible to it).
/// \tparam ValueType One of the TOML ndoe or value types (or a type promotable to one). /// \tparam ValueType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
/// (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 <strong><em>Valid input:</em></strong><br>
/// - An iterator to the insertion position (or the position of the value that prevented insertion) /// <ul>
/// - A boolean indicating if the insertion was successful. /// <li>An iterator to the insertion position (or the position of the value that prevented insertion)
/// <li>A boolean indicating if the insertion was successful.
/// </ul>
/// <strong><em>`val` is an empty toml::node_view:</em></strong><br>
/// `{ end(), false }`
///
/// \attention The return value will always be `{ end(), false }` if the input value was an
/// empty toml::node_view, because no insertion can take place. This is the only circumstance
/// in which this can occur.
template <typename KeyType, typename ValueType, typename = std::enable_if_t< template <typename KeyType, typename ValueType, typename = std::enable_if_t<
std::is_convertible_v<KeyType&&, std::string_view> std::is_convertible_v<KeyType&&, std::string_view>
|| impl::is_wide_string<KeyType> || impl::is_wide_string<KeyType>
@ -471,6 +479,12 @@ TOML_NAMESPACE_START
"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_node_view<ValueType>)
{
if (!val)
return { end(), false };
}
if constexpr (impl::is_wide_string<KeyType>) if constexpr (impl::is_wide_string<KeyType>)
{ {
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
@ -485,9 +499,9 @@ TOML_NAMESPACE_START
if (ipos == map.end() || ipos->first != key) if (ipos == map.end() || ipos->first != key)
{ {
ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val))); ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val)));
return { ipos, true }; return { iterator{ ipos }, true };
} }
return { ipos, false }; return { iterator{ ipos }, false };
} }
} }
@ -583,13 +597,22 @@ TOML_NAMESPACE_START
/// \eout /// \eout
/// ///
/// \tparam KeyType std::string (or a type convertible to it). /// \tparam KeyType std::string (or a type convertible to it).
/// \tparam ValueType One of the TOML node or value types (or a type promotable to one). /// \tparam ValueType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
/// (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 <strong><em>Valid input:</em></strong><br>
/// - An iterator to the value's position /// <ul>
/// - A boolean containing `true` if the value was inserted, `false` if it was assigned. /// <li>An iterator to the value's position
/// <li>`true` if the value was inserted, `false` if it was assigned.
/// </ul>
/// <strong><em>`val` is an empty toml::node_view:</em></strong><br>
/// `{ end(), false }`
///
/// \attention The return value will always be `{ end(), false }` if the input value was
/// an empty toml::node_view, because no insertion or assignment can take place.
/// This is the only circumstance in which this can occur.
template <typename KeyType, typename ValueType> template <typename KeyType, typename ValueType>
std::pair<iterator, bool> insert_or_assign(KeyType&& key, ValueType&& val) noexcept std::pair<iterator, bool> insert_or_assign(KeyType&& key, ValueType&& val) noexcept
{ {
@ -598,6 +621,12 @@ TOML_NAMESPACE_START
"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_node_view<ValueType>)
{
if (!val)
return { end(), false };
}
if constexpr (impl::is_wide_string<KeyType>) if constexpr (impl::is_wide_string<KeyType>)
{ {
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
@ -612,12 +641,12 @@ TOML_NAMESPACE_START
if (ipos == map.end() || ipos->first != key) if (ipos == map.end() || ipos->first != key)
{ {
ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val))); ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val)));
return { ipos, true }; return { iterator{ ipos }, true };
} }
else else
{ {
(*ipos).second.reset(impl::make_node(std::forward<ValueType>(val))); (*ipos).second.reset(impl::make_node(std::forward<ValueType>(val)));
return { ipos, false }; return { iterator{ ipos }, false };
} }
} }
} }
@ -649,13 +678,13 @@ TOML_NAMESPACE_START
/// { a = 1, b = 2, c = 3, d = "drill" } /// { a = 1, b = 2, c = 3, d = "drill" }
/// \eout /// \eout
/// ///
/// \tparam ValueType One of the TOML node or value types. /// \tparam ValueType toml::table, toml::array, or any native TOML value type.
/// \tparam KeyType std::string (or a type convertible to it). /// \tparam KeyType std::string (or a type convertible to it).
/// \tparam ValueArgs 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.
/// ///
/// \returns A std::pair containing: /// \returns A std::pair containing: <br>
/// - An iterator to the emplacement position (or the position of the value that prevented emplacement) /// - An iterator to the emplacement position (or the position of the value that prevented emplacement)
/// - A boolean indicating if the emplacement was successful. /// - A boolean indicating if the emplacement was successful.
/// ///
@ -694,9 +723,9 @@ TOML_NAMESPACE_START
std::forward<KeyType>(key), std::forward<KeyType>(key),
new impl::wrap_node<type>{ std::forward<ValueArgs>(args)... } new impl::wrap_node<type>{ std::forward<ValueArgs>(args)... }
); );
return { ipos, true }; return { iterator{ ipos }, true };
} }
return { ipos, false }; return { iterator{ ipos }, false };
} }
} }

View File

@ -70,6 +70,8 @@ TOML_NAMESPACE_START
{ {
for (size_t i = 0; i < count; i++) for (size_t i = 0; i < count; i++)
{ {
if (!pairs[i].value) // empty node_views
continue;
map.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)

View File

@ -120,6 +120,7 @@ def main():
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -256,7 +256,8 @@ TEST_CASE("arrays - insertion and erasure")
// push_back(ElemType&& val) noexcept // push_back(ElemType&& val) noexcept
{ {
decltype(auto) val = arr.push_back("test"sv); arr.push_back("test"sv);
auto& val = *arr.back().as_string();
CHECK(arr.size() == 6_sz); CHECK(arr.size() == 6_sz);
REQUIRE(arr.get_as<std::string>(5_sz)); REQUIRE(arr.get_as<std::string>(5_sz));
CHECK(*arr.get_as<std::string>(5_sz) == "test"sv); CHECK(*arr.get_as<std::string>(5_sz) == "test"sv);

View File

@ -21,6 +21,7 @@ test_sources = [
'manipulating_values.cpp', 'manipulating_values.cpp',
'unicode.cpp', 'unicode.cpp',
'unicode_generated.cpp', 'unicode_generated.cpp',
'user_feedback.cpp',
'windows_compat.cpp' 'windows_compat.cpp'
] ]
@ -300,12 +301,6 @@ foreach cpp20 : cpp20_modes
name = name + '_tlopt' name = name + '_tlopt'
endif endif
if compiler_supports_float16
if compiler.get_id() == 'gcc'
args += '-mfp16-format=ieee'
endif
endif
executables += [[ executables += [[
name, name,
executable( executable(

View File

@ -84,12 +84,12 @@
#ifndef SHOULD_HAVE_FLOAT16 #ifndef SHOULD_HAVE_FLOAT16
#define SHOULD_HAVE_FLOAT16 0 #define SHOULD_HAVE_FLOAT16 0
#endif #endif
#ifndef SHOULD_HAVE_INT128
#define SHOULD_HAVE_INT128 0
#endif
#ifndef SHOULD_HAVE_FLOAT128 #ifndef SHOULD_HAVE_FLOAT128
#define SHOULD_HAVE_FLOAT128 0 #define SHOULD_HAVE_FLOAT128 0
#endif #endif
#ifndef SHOULD_HAVE_INT128
#define SHOULD_HAVE_INT128 0
#endif
#ifndef SHOULD_HAVE_EXCEPTIONS #ifndef SHOULD_HAVE_EXCEPTIONS
#define SHOULD_HAVE_EXCEPTIONS 1 #define SHOULD_HAVE_EXCEPTIONS 1
#endif #endif

88
tests/user_feedback.cpp Normal file
View File

@ -0,0 +1,88 @@
// This file is a part of toml++ and is subject to the the terms of the MIT license.
// Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
// See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#include "tests.h"
// this file is about testing user misc. repros submitted via github issues, et cetera.
TEST_CASE("feedback - github/issues/49")
{
// see: https://github.com/marzer/tomlplusplus/issues/49#issuecomment-664428571
{
toml::table t1;
t1.insert_or_assign("bar1", toml::array{ 1, 2, 3 });
CHECK(t1 == toml::table{{
{ "bar1"sv, toml::array{ 1, 2, 3 } }
}});
t1.insert_or_assign("foo1", *t1.get("bar1"));
CHECK(t1 == toml::table{{
{ "bar1"sv, toml::array{ 1, 2, 3 } },
{ "foo1"sv, toml::array{ 1, 2, 3 } }
}});
//t1["foo1"] = t1["bar1"]; // does nothing, should this fail to compile?
// - yes -
//*t1["foo1"].node() = *t1["bar1"].node(); // compile failure; copying node_view would be a bad thing
// - correct; copying toml::node directly like that is impossible b.c. it's an abstract base class-
toml::array* array1 = t1["foo1"].node()->as_array();
array1->push_back(4);
CHECK(t1 == toml::table{{
{ "bar1"sv, toml::array{ 1, 2, 3 } },
{ "foo1"sv, toml::array{ 1, 2, 3, 4 } }
}});
t1.insert_or_assign("foo3", t1["foo1"]);
CHECK(t1 == toml::table{{
{ "bar1"sv, toml::array{ 1, 2, 3 } },
{ "foo1"sv, toml::array{ 1, 2, 3, 4 } },
{ "foo3"sv, toml::array{ 1, 2, 3, 4 } }
}});
t1.insert_or_assign("foo2", *t1["foo1"].node());
CHECK(t1 == toml::table{{
{ "bar1"sv, toml::array{ 1, 2, 3 } },
{ "foo1"sv, toml::array{ 1, 2, 3, 4 } },
{ "foo2"sv, toml::array{ 1, 2, 3, 4 } },
{ "foo3"sv, toml::array{ 1, 2, 3, 4 } }
}});
toml::array* array2 = t1["foo2"].node()->as_array();
array2->push_back("wrench");
CHECK(t1 == toml::table{{
{ "bar1"sv, toml::array{ 1, 2, 3 } },
{ "foo1"sv, toml::array{ 1, 2, 3, 4 } },
{ "foo2"sv, toml::array{ 1, 2, 3, 4, "wrench" } },
{ "foo3"sv, toml::array{ 1, 2, 3, 4 } }
}});
toml::table t2 = t1;
CHECK(t2 == t1);
CHECK(&t2 != &t1);
//t2.emplace("bar", toml::array{6, 7}); // fails to compile? not sure what I did wrong
// - it should be this: -
t2.emplace<toml::array>("bar", 6, 7);
CHECK(t2 == toml::table{{
{ "bar"sv, toml::array{ 6, 7 } },
{ "bar1"sv, toml::array{ 1, 2, 3 } },
{ "foo1"sv, toml::array{ 1, 2, 3, 4 } },
{ "foo2"sv, toml::array{ 1, 2, 3, 4, "wrench" } },
{ "foo3"sv, toml::array{ 1, 2, 3, 4 } }
}});
t2.insert_or_assign("bar2", toml::array{ 6, 7 });
CHECK(t2 == toml::table{{
{ "bar"sv, toml::array{ 6, 7 } },
{ "bar1"sv, toml::array{ 1, 2, 3 } },
{ "bar2"sv, toml::array{ 6, 7 } },
{ "foo1"sv, toml::array{ 1, 2, 3, 4 } },
{ "foo2"sv, toml::array{ 1, 2, 3, 4, "wrench" } },
{ "foo3"sv, toml::array{ 1, 2, 3, 4 } }
}});
}
}

139
toml.hpp
View File

@ -1067,6 +1067,9 @@ TOML_IMPL_NAMESPACE_START
template <> struct node_type_getter<array> { static constexpr auto value = node_type::array; }; template <> struct node_type_getter<array> { static constexpr auto value = node_type::array; };
template <typename T> template <typename T>
inline constexpr node_type node_type_of = node_type_getter<unwrap_node<remove_cvref_t<T>>>::value; inline constexpr node_type node_type_of = node_type_getter<unwrap_node<remove_cvref_t<T>>>::value;
template <typename T>
inline constexpr bool is_node_view = is_one_of<impl::remove_cvref_t<T>, node_view<node>, node_view<const node>>;
} }
TOML_IMPL_NAMESPACE_END TOML_IMPL_NAMESPACE_END
@ -2026,7 +2029,7 @@ TOML_PUSH_WARNINGS
TOML_DISABLE_PADDING_WARNINGS TOML_DISABLE_PADDING_WARNINGS
TOML_DISABLE_MISC_WARNINGS TOML_DISABLE_MISC_WARNINGS
#if TOML_SIMPLE_STATIC_ASSERT_MESSAGES #if defined(doxygen) || TOML_SIMPLE_STATIC_ASSERT_MESSAGES
#define TOML_SA_NEWLINE " " #define TOML_SA_NEWLINE " "
#define TOML_SA_LIST_SEP ", " #define TOML_SA_LIST_SEP ", "
@ -3235,7 +3238,7 @@ TOML_IMPL_NAMESPACE_START
class TOML_TRIVIAL_ABI array_iterator final class TOML_TRIVIAL_ABI array_iterator final
{ {
private: private:
friend class ::toml::array; friend class TOML_NAMESPACE::array;
using raw_mutable_iterator = std::vector<std::unique_ptr<node>>::iterator; using raw_mutable_iterator = std::vector<std::unique_ptr<node>>::iterator;
using raw_const_iterator = std::vector<std::unique_ptr<node>>::const_iterator; using raw_const_iterator = std::vector<std::unique_ptr<node>>::const_iterator;
@ -3400,6 +3403,7 @@ TOML_IMPL_NAMESPACE_START
{ {
using type = unwrap_node<remove_cvref_t<T>>; using type = unwrap_node<remove_cvref_t<T>>;
static_assert(!std::is_same_v<type, node>); static_assert(!std::is_same_v<type, node>);
static_assert(!is_node_view<type>);
if constexpr (is_one_of<type, array, table>) if constexpr (is_one_of<type, array, table>)
{ {
@ -3431,12 +3435,17 @@ TOML_IMPL_NAMESPACE_START
template <typename T> template <typename T>
[[nodiscard]] [[nodiscard]]
TOML_ATTR(returns_nonnull)
auto* make_node(T&& val) noexcept auto* make_node(T&& val) noexcept
{ {
using type = unwrap_node<remove_cvref_t<T>>; using type = unwrap_node<remove_cvref_t<T>>;
if constexpr (std::is_same_v<type, node>) if constexpr (std::is_same_v<type, node> || is_node_view<type>)
{ {
if constexpr (is_node_view<type>)
{
if (!val)
return static_cast<toml::node*>(nullptr);
}
return std::forward<T>(val).visit([](auto&& concrete) noexcept return std::forward<T>(val).visit([](auto&& concrete) noexcept
{ {
return static_cast<toml::node*>(make_node_specialized(std::forward<decltype(concrete)>(concrete))); return static_cast<toml::node*>(make_node_specialized(std::forward<decltype(concrete)>(concrete)));
@ -3448,7 +3457,6 @@ TOML_IMPL_NAMESPACE_START
template <typename T> template <typename T>
[[nodiscard]] [[nodiscard]]
TOML_ATTR(returns_nonnull)
auto* make_node(inserter<T>&& val) noexcept auto* make_node(inserter<T>&& val) noexcept
{ {
return make_node(std::move(val.value)); return make_node(std::move(val.value));
@ -3470,6 +3478,17 @@ TOML_NAMESPACE_START
void preinsertion_resize(size_t idx, size_t count) noexcept; void preinsertion_resize(size_t idx, size_t count) noexcept;
template <typename T>
void emplace_back_if_not_empty_view(T&& val) noexcept
{
if constexpr (impl::is_node_view<T>)
{
if (!val)
return;
}
elements.emplace_back(impl::make_node(std::forward<T>(val)));
}
public: public:
using value_type = node; using value_type = node;
@ -3499,11 +3518,11 @@ TOML_NAMESPACE_START
explicit array(ElemType&& val, ElemTypes&&... vals) explicit array(ElemType&& val, ElemTypes&&... vals)
{ {
elements.reserve(sizeof...(ElemTypes) + 1_sz); elements.reserve(sizeof...(ElemTypes) + 1_sz);
elements.emplace_back(impl::make_node(std::forward<ElemType>(val))); emplace_back_if_not_empty_view(std::forward<ElemType>(val));
if constexpr (sizeof...(ElemTypes) > 0) if constexpr (sizeof...(ElemTypes) > 0)
{ {
( (
elements.emplace_back(impl::make_node(std::forward<ElemTypes>(vals))), emplace_back_if_not_empty_view(std::forward<ElemTypes>(vals)),
... ...
); );
} }
@ -3560,12 +3579,22 @@ TOML_NAMESPACE_START
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, ElemType&& val) noexcept iterator insert(const_iterator pos, ElemType&& val) noexcept
{ {
if constexpr (impl::is_node_view<ElemType>)
{
if (!val)
return end();
}
return { elements.emplace(pos.raw_, impl::make_node(std::forward<ElemType>(val))) }; return { elements.emplace(pos.raw_, impl::make_node(std::forward<ElemType>(val))) };
} }
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, size_t count, ElemType&& val) noexcept iterator insert(const_iterator pos, size_t count, ElemType&& val) noexcept
{ {
if constexpr (impl::is_node_view<ElemType>)
{
if (!val)
return end();
}
switch (count) switch (count)
{ {
case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) }; case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) };
@ -3587,18 +3616,36 @@ TOML_NAMESPACE_START
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 distance = std::distance(first, last);
if (count <= 0) if (distance <= 0)
return { elements.begin() + (pos.raw_ - elements.cbegin()) }; return { elements.begin() + (pos.raw_ - elements.cbegin()) };
else if (count == 1)
return insert(pos, *first);
else else
{ {
auto count = distance;
using deref_type = decltype(*first);
if constexpr (impl::is_node_view<deref_type>)
{
for (auto it = first; it != last; it++)
if (!(*it))
count--;
if (!count)
return { elements.begin() + (pos.raw_ - elements.cbegin()) };
}
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin()); const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, static_cast<size_t>(count)); preinsertion_resize(start_idx, static_cast<size_t>(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++)
elements[i++].reset(impl::make_node(*it)); {
if constexpr (impl::is_node_view<deref_type>)
{
if (!(*it))
continue;
}
if constexpr (std::is_rvalue_reference_v<deref_type>)
elements[i++].reset(impl::make_node(std::move(*it)));
else
elements[i++].reset(impl::make_node(*it));
}
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) }; return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
} }
} }
@ -3606,20 +3653,7 @@ TOML_NAMESPACE_START
template <typename ElemType> template <typename ElemType>
iterator insert(const_iterator pos, std::initializer_list<ElemType> ilist) noexcept iterator insert(const_iterator pos, std::initializer_list<ElemType> ilist) noexcept
{ {
switch (ilist.size()) return insert(pos, ilist.begin(), ilist.end());
{
case 0: return { elements.begin() + (pos.raw_ - elements.cbegin()) };
case 1: return insert(pos, *ilist.begin());
default:
{
const auto start_idx = static_cast<size_t>(pos.raw_ - elements.cbegin());
preinsertion_resize(start_idx, ilist.size());
size_t i = start_idx;
for (auto& val : ilist)
elements[i++].reset(impl::make_node(val));
return { elements.begin() + static_cast<ptrdiff_t>(start_idx) };
}
}
} }
template <typename ElemType, typename... Args> template <typename ElemType, typename... Args>
@ -3641,6 +3675,11 @@ TOML_NAMESPACE_START
template <typename ElemType> template <typename ElemType>
void resize(size_t new_size, ElemType&& default_init_val) noexcept void resize(size_t new_size, ElemType&& default_init_val) noexcept
{ {
static_assert(
!impl::is_node_view<ElemType>,
"The default element type argument to toml::array::resize may not be toml::node_view."
);
if (!new_size) if (!new_size)
elements.clear(); elements.clear();
else if (new_size < elements.size()) else if (new_size < elements.size())
@ -3652,11 +3691,9 @@ TOML_NAMESPACE_START
void truncate(size_t new_size); void truncate(size_t new_size);
template <typename ElemType> template <typename ElemType>
decltype(auto) push_back(ElemType&& val) noexcept void push_back(ElemType&& val) noexcept
{ {
auto nde = impl::make_node(std::forward<ElemType>(val)); emplace_back_if_not_empty_view(std::forward<ElemType>(val));
elements.emplace_back(nde);
return *nde;
} }
template <typename ElemType, typename... Args> template <typename ElemType, typename... Args>
@ -3786,7 +3823,7 @@ TOML_IMPL_NAMESPACE_START
class table_iterator final class table_iterator final
{ {
private: private:
friend class ::toml::table; friend class TOML_NAMESPACE::table;
using proxy_type = table_proxy_pair<IsConst>; using proxy_type = table_proxy_pair<IsConst>;
using raw_mutable_iterator = string_map<std::unique_ptr<node>>::iterator; using raw_mutable_iterator = string_map<std::unique_ptr<node>>::iterator;
@ -4031,6 +4068,12 @@ TOML_NAMESPACE_START
"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_node_view<ValueType>)
{
if (!val)
return { end(), false };
}
if constexpr (impl::is_wide_string<KeyType>) if constexpr (impl::is_wide_string<KeyType>)
{ {
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
@ -4045,9 +4088,9 @@ TOML_NAMESPACE_START
if (ipos == map.end() || ipos->first != key) if (ipos == map.end() || ipos->first != key)
{ {
ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val))); ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val)));
return { ipos, true }; return { iterator{ ipos }, true };
} }
return { ipos, false }; return { iterator{ ipos }, false };
} }
} }
@ -4076,6 +4119,12 @@ TOML_NAMESPACE_START
"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_node_view<ValueType>)
{
if (!val)
return { end(), false };
}
if constexpr (impl::is_wide_string<KeyType>) if constexpr (impl::is_wide_string<KeyType>)
{ {
#if TOML_WINDOWS_COMPAT #if TOML_WINDOWS_COMPAT
@ -4090,12 +4139,12 @@ TOML_NAMESPACE_START
if (ipos == map.end() || ipos->first != key) if (ipos == map.end() || ipos->first != key)
{ {
ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val))); ipos = map.emplace_hint(ipos, std::forward<KeyType>(key), impl::make_node(std::forward<ValueType>(val)));
return { ipos, true }; return { iterator{ ipos }, true };
} }
else else
{ {
(*ipos).second.reset(impl::make_node(std::forward<ValueType>(val))); (*ipos).second.reset(impl::make_node(std::forward<ValueType>(val)));
return { ipos, false }; return { iterator{ ipos }, false };
} }
} }
} }
@ -4134,9 +4183,9 @@ TOML_NAMESPACE_START
std::forward<KeyType>(key), std::forward<KeyType>(key),
new impl::wrap_node<type>{ std::forward<ValueArgs>(args)... } new impl::wrap_node<type>{ std::forward<ValueArgs>(args)... }
); );
return { ipos, true }; return { iterator{ ipos }, true };
} }
return { ipos, false }; return { iterator{ ipos }, false };
} }
} }
@ -4274,8 +4323,8 @@ TOML_NAMESPACE_START
using viewed_type = ViewedType; using viewed_type = ViewedType;
private: private:
friend class toml::table; friend class TOML_NAMESPACE::table;
template <typename T> friend class toml::node_view; template <typename T> friend class TOML_NAMESPACE::node_view;
mutable viewed_type* node_ = nullptr; mutable viewed_type* node_ = nullptr;
@ -4292,6 +4341,16 @@ TOML_NAMESPACE_START
TOML_NODISCARD_CTOR TOML_NODISCARD_CTOR
node_view() noexcept = default; node_view() noexcept = default;
TOML_NODISCARD_CTOR
node_view(const node_view&) noexcept = default;
TOML_NODISCARD_CTOR
node_view& operator= (const node_view&) noexcept = default;
node_view(node_view&&) noexcept = default;
node_view& operator= (node_view&&) noexcept = delete;
[[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; } [[nodiscard]] explicit operator bool() const noexcept { return node_ != nullptr; }
[[nodiscard]] viewed_type* node() const noexcept { return node_; } [[nodiscard]] viewed_type* node() const noexcept { return node_; }
@ -7654,6 +7713,8 @@ TOML_NAMESPACE_START
{ {
for (size_t i = 0; i < count; i++) for (size_t i = 0; i < count; i++)
{ {
if (!pairs[i].value) // empty node_views
continue;
map.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)

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -77,6 +77,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unicode.cpp" /> <ClCompile Include="..\..\tests\unicode.cpp" />
<ClCompile Include="..\..\tests\unicode_generated.cpp" /> <ClCompile Include="..\..\tests\unicode_generated.cpp" />
<ClCompile Include="..\..\tests\user_feedback.cpp" />
<ClCompile Include="..\..\tests\windows_compat.cpp" /> <ClCompile Include="..\..\tests\windows_compat.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>