fixed strong exception guarantee edge-cases

also:
- added `value` copy+move constructor overloads with flags override
`table::ref()` now supports explicit ref categories and cv-qualifiers
This commit is contained in:
Mark Gillard 2021-11-14 19:24:19 +02:00
parent 32df34add2
commit 9066ac7d01
22 changed files with 2537 additions and 1621 deletions

View File

@ -22,8 +22,8 @@ code changes at callsites or in build systems are indicated with ⚠️.
#### Fixes:
- ⚠️ fixed incorrect `noexcept` specifications on many functions
- ⚠️ fixed `toml::table` init-list constructor requiring double-brackets
- fixed `toml::json_formatter` not formatting inf and nan incorrectly
- fixed `toml::table` init-list constructor requiring double-brackets
- fixed `TOML_API` + extern templates causing linker errors in some circumstances
- fixed an illegal table redefinition edge case (#112) (@python36)
- fixed documentation issues
@ -32,6 +32,7 @@ code changes at callsites or in build systems are indicated with ⚠️.
- fixed missing `#include <utility>`
- fixed missing `TOML_API` on interfaces
- fixed parser not correctly round-tripping the format of binary and octal integers in some cases
- fixed strong exception guarantee edge-cases in `toml::table` and `toml::array`
#### Additions:
- added `operator->` to `toml::value` for class types
@ -52,6 +53,7 @@ code changes at callsites or in build systems are indicated with ⚠&#xFE0F;.
- added `toml::table::emplace_hint()` (same semantics as `std::map::emplace_hint()`)
- added `toml::table::lower_bound()` (same semantics as `std::map::lower_bound()`)
- added `toml::table::prune()`
- added `toml::value` copy+move constructor overloads with flags override
- added `toml::yaml_formatter`
- added `TOML_ENABLE_FORMATTERS` option
- added clang's enum annotation attributes to all enums
@ -70,6 +72,7 @@ code changes at callsites or in build systems are indicated with ⚠&#xFE0F;.
- ⚠&#xFE0F; renamed `TOML_PARSER` option to `TOML_ENABLE_PARSER` (`TOML_PARSER` will continue to work but is deprecated)
- ⚠&#xFE0F; renamed `TOML_UNRELEASED_FEATURES` to `TOML_ENABLE_UNRELEASED_FEATURES` (`TOML_UNRELEASED_FEATURES` will continue to work but is deprecated)
- ⚠&#xFE0F; renamed `TOML_WINDOWS_COMPAT` to `TOML_ENABLE_WINDOWS_COMPAT` (`TOML_WINDOWS_COMPAT` will continue to work but is deprecated)
- `toml::table::ref()` now supports explicit ref categories and cv-qualifiers
- applied clang-format to all the things 🎉&#xFE0F;
- improved performance of parser
- made date/time constructors accept any integral types

View File

@ -21,31 +21,31 @@ TOML_IMPL_NAMESPACE_START
template <bool>
friend class array_iterator;
using raw_mutable_iterator = std::vector<node_ptr>::iterator;
using raw_const_iterator = std::vector<node_ptr>::const_iterator;
using raw_iterator = std::conditional_t<IsConst, raw_const_iterator, raw_mutable_iterator>;
using mutable_vector_iterator = std::vector<node_ptr>::iterator;
using const_vector_iterator = std::vector<node_ptr>::const_iterator;
using vector_iterator = std::conditional_t<IsConst, const_vector_iterator, mutable_vector_iterator>;
mutable raw_iterator iter_;
mutable vector_iterator iter_;
public:
using value_type = std::conditional_t<IsConst, const node, node>;
using reference = value_type&;
using pointer = value_type*;
using difference_type = ptrdiff_t;
using iterator_category = typename std::iterator_traits<raw_iterator>::iterator_category;
using iterator_category = typename std::iterator_traits<vector_iterator>::iterator_category;
TOML_NODISCARD_CTOR
array_iterator() noexcept = default;
TOML_NODISCARD_CTOR
array_iterator(raw_mutable_iterator raw) noexcept //
: iter_{ raw }
array_iterator(mutable_vector_iterator iter) noexcept //
: iter_{ iter }
{}
TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
TOML_NODISCARD_CTOR
array_iterator(raw_const_iterator raw) noexcept //
: iter_{ raw }
array_iterator(const_vector_iterator iter) noexcept //
: iter_{ iter }
{}
TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
@ -98,7 +98,14 @@ TOML_IMPL_NAMESPACE_START
}
TOML_PURE_INLINE_GETTER
operator const raw_iterator&() const noexcept
operator const vector_iterator&() const noexcept
{
return iter_;
}
TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
TOML_PURE_INLINE_GETTER
operator const const_vector_iterator() const noexcept
{
return iter_;
}
@ -181,6 +188,17 @@ TOML_IMPL_NAMESPACE_START
return *(iter_ + idx)->get();
}
};
struct array_init_elem
{
mutable node_ptr value;
template <typename T>
TOML_NODISCARD_CTOR
array_init_elem(T&& val, value_flags flags = preserve_source_value_flags) //
: value{ make_node(static_cast<T&&>(val), flags) }
{}
};
}
TOML_IMPL_NAMESPACE_END;
/// \endcond
@ -235,7 +253,6 @@ TOML_NAMESPACE_START
/// arr.emplace_back<std::string>("ten");
/// arr.emplace_back<toml::array>(11, 12.0);
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
@ -249,11 +266,29 @@ TOML_NAMESPACE_START
private:
/// \cond
std::vector<impl::node_ptr> elems_;
using vector_type = std::vector<impl::node_ptr>;
using vector_iterator = typename vector_type::iterator;
using const_vector_iterator = typename vector_type::const_iterator;
vector_type elems_;
TOML_NODISCARD_CTOR
TOML_API
array(const impl::array_init_elem*, const impl::array_init_elem*);
TOML_NODISCARD_CTOR
array(std::false_type, std::initializer_list<impl::array_init_elem> elems) //
: array{ elems.begin(), elems.end() }
{}
TOML_API
void preinsertion_resize(size_t idx, size_t count);
TOML_API
void insert_at_back(impl::node_ptr&&);
TOML_API
vector_iterator insert_at(const_vector_iterator, impl::node_ptr&&);
template <typename T>
void emplace_back_if_not_empty_view(T&& val, value_flags flags)
{
@ -262,7 +297,7 @@ TOML_NAMESPACE_START
if (!val)
return;
}
elems_.emplace_back(impl::make_node(static_cast<T&&>(val), flags));
insert_at_back(impl::make_node(static_cast<T&&>(val), flags));
}
TOML_NODISCARD
@ -271,6 +306,7 @@ TOML_NAMESPACE_START
TOML_API
void flatten_child(array&& child, size_t& dest_index) noexcept;
/// \endcond
public:
@ -316,14 +352,6 @@ TOML_NAMESPACE_START
TOML_API
array(array&& other) noexcept;
/// \brief Copy-assignment operator.
TOML_API
array& operator=(const array&);
/// \brief Move-assignment operator.
TOML_API
array& operator=(array&& rhs) noexcept;
/// \brief Constructs an array with one or more initial elements.
///
/// \detail \cpp
@ -361,18 +389,18 @@ TOML_NAMESPACE_START
typename... ElemTypes)
TOML_NODISCARD_CTOR
explicit array(ElemType&& val, ElemTypes&&... vals)
{
elems_.reserve(sizeof...(ElemTypes) + 1u);
emplace_back_if_not_empty_view(static_cast<ElemType&&>(val), preserve_source_value_flags);
if constexpr (sizeof...(ElemTypes) > 0)
{
(emplace_back_if_not_empty_view(static_cast<ElemTypes&&>(vals), preserve_source_value_flags), ...);
}
: array{ std::false_type{},
std::initializer_list<impl::array_init_elem>{ static_cast<ElemType&&>(val),
static_cast<ElemTypes&&>(vals)... } }
{}
#if TOML_LIFETIME_HOOKS
TOML_ARRAY_CREATED;
#endif
}
/// \brief Copy-assignment operator.
TOML_API
array& operator=(const array&);
/// \brief Move-assignment operator.
TOML_API
array& operator=(array&& rhs) noexcept;
/// \name Type checks
/// @{
@ -401,13 +429,13 @@ TOML_NAMESPACE_START
TOML_PURE_GETTER
bool is_homogeneous() const noexcept
{
using type = impl::unwrap_node<ElemType>;
static_assert(
std::is_void_v<
type> || ((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>),
"The template type argument of array::is_homogeneous() must be void or one "
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
return is_homogeneous(impl::node_type_of<type>);
using unwrapped_type = impl::unwrap_node<impl::remove_cvref<ElemType>>;
static_assert(std::is_void_v<unwrapped_type> //
|| (impl::is_native<unwrapped_type> || impl::is_one_of<unwrapped_type, table, array>),
"The template type argument of array::is_homogeneous() must be void or one "
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
return is_homogeneous(impl::node_type_of<unwrapped_type>);
}
/// \endcond
@ -628,7 +656,7 @@ TOML_NAMESPACE_START
/// @}
/// \name Array operations
/// \name Value retrieval
/// @{
/// \brief Gets a pointer to the element at a specific index.
@ -640,7 +668,6 @@ TOML_NAMESPACE_START
/// std::cout << "element [2] exists: "sv << !!arr.get(2) << "\n";
/// if (toml::node* val = arr.get(0))
/// std::cout << "element [0] is an "sv << val->type() << "\n";
///
/// \ecpp
///
/// \out
@ -676,7 +703,6 @@ TOML_NAMESPACE_START
/// auto arr = toml::array{ 42, "is the meaning of life, apparently."sv };
/// if (toml::value<int64_t>* val = arr.get_as<int64_t>(0))
/// std::cout << "element [0] is an integer with value "sv << *val << "\n";
///
/// \ecpp
///
/// \out
@ -763,6 +789,11 @@ TOML_NAMESPACE_START
return *elems_.back();
}
/// @}
/// \name Iterators
/// @{
/// \brief Returns an iterator to the first element.
TOML_NODISCARD
iterator begin() noexcept
@ -805,6 +836,11 @@ TOML_NAMESPACE_START
return elems_.cend();
}
/// @}
/// \name Size and Capacity
/// @{
/// \brief Returns true if the array is empty.
TOML_NODISCARD
bool empty() const noexcept
@ -819,18 +855,6 @@ TOML_NAMESPACE_START
return elems_.size();
}
/// \brief Reserves internal storage capacity up to a pre-determined number of elements.
void reserve(size_t new_capacity)
{
elems_.reserve(new_capacity);
}
/// \brief Removes all elements from the array.
void clear() noexcept
{
elems_.clear();
}
/// \brief Returns the maximum number of elements that can be stored in an array on the current platform.
TOML_NODISCARD
size_t max_size() const noexcept
@ -845,12 +869,205 @@ TOML_NAMESPACE_START
return elems_.capacity();
}
/// \brief Reserves internal storage capacity up to a pre-determined number of elements.
TOML_API
void reserve(size_t new_capacity);
/// \brief Requests the removal of any unused internal storage capacity.
void shrink_to_fit()
TOML_API
void shrink_to_fit();
/// \brief Shrinks the array to the given size.
///
/// \detail \godbolt{rxEzK5}
///
/// \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << arr << "\n";
///
/// arr.truncate(5); // no-op
/// std::cout << arr << "\n";
///
/// arr.truncate(1);
/// std::cout << arr << "\n";
/// \ecpp
///
/// \out
/// [ 1, 2, 3 ]
/// [ 1, 2, 3 ]
/// [ 1]
/// \eout
///
/// \remarks Does nothing if the requested size is larger than or equal to the current size.
TOML_API
void truncate(size_t new_size);
/// \brief Resizes the array.
///
/// \detail \godbolt{W5zqx3}
///
/// \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << arr << "\n";
///
/// arr.resize(6, 42);
/// std::cout << arr << "\n";
///
/// arr.resize(2, 0);
/// std::cout << arr << "\n";
/// \ecpp
///
/// \out
/// [ 1, 2, 3 ]
/// [ 1, 2, 3, 42, 42, 42 ]
/// [ 1, 2 ]
/// \eout
///
/// \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 default_init_val The node or value used to initialize new elements if the array needs to grow.
/// \param default_init_flags Value flags to apply to new values created if new elements are created by growing.
template <typename ElemType>
void resize(size_t new_size,
ElemType&& default_init_val,
value_flags default_init_flags = preserve_source_value_flags)
{
elems_.shrink_to_fit();
static_assert(!is_node_view<ElemType>,
"The default element type argument to toml::array::resize may not be toml::node_view.");
if (!new_size)
clear();
else if (new_size > elems_.size())
insert(cend(), new_size - elems_.size(), static_cast<ElemType&&>(default_init_val), default_init_flags);
else
truncate(new_size);
}
/// @}
/// \name Erasure
/// @{
/// \brief Removes the specified element from the array.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << arr << "\n";
///
/// arr.erase(arr.cbegin() + 1);
/// std::cout << arr << "\n";
/// \ecpp
///
/// \out
/// [ 1, 2, 3 ]
/// [ 1, 3 ]
/// \eout
///
/// \param pos Iterator to the element being erased.
///
/// \returns Iterator to the first element immediately following the removed element.
TOML_API
iterator erase(const_iterator pos) noexcept;
/// \brief Removes the elements in the range [first, last) from the array.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, "bad", "karma" 2 };
/// std::cout << arr << "\n";
///
/// arr.erase(arr.cbegin() + 1, arr.cbegin() + 3);
/// std::cout << arr << "\n";
/// \ecpp
///
/// \out
/// [ 1, 'bad', 'karma', 3 ]
/// [ 1, 3 ]
/// \eout
///
/// \param first Iterator to the first element being erased.
/// \param last Iterator to the one-past-the-last element being erased.
///
/// \returns Iterator to the first element immediately following the last removed element.
TOML_API
iterator erase(const_iterator first, const_iterator last) noexcept;
/// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself.
///
/// \detail \cpp
///
/// auto arr = toml::array{ 1, 2, toml::array{ 3, 4, toml::array{ 5 } }, 6, toml::array{} };
/// std::cout << arr << "\n";
///
/// arr.flatten();
/// std::cout << arr << "\n";
/// \ecpp
///
/// \out
/// [ 1, 2, [ 3, 4, [ 5 ] ], 6, [] ]
/// [ 1, 2, 3, 4, 5, 6 ]
/// \eout
///
/// \remarks Arrays inside child tables are not flattened.
///
/// \returns A reference to the array.
TOML_API
array& flatten() &;
/// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself (rvalue overload).
///
/// \returns An rvalue reference to the array.
array&& flatten() &&
{
return static_cast<toml::array&&>(this->flatten());
}
/// \brief Removes empty child arrays and tables.
///
/// \detail \cpp
///
/// auto arr = toml::array{ 1, 2, toml::array{ }, toml::array{ 3, toml::array{ } }, 4 };
/// std::cout << arr << "\n";
///
/// arr.prune(true);
/// std::cout << arr << "\n";
/// \ecpp
///
/// \out
/// [ 1, 2, [], [ 3, [] ], 4 ]
/// [ 1, 2, [ 3 ], 4 ]
/// \eout
///
/// \param recursive Should child arrays and tables themselves be pruned?
///
/// \returns A reference to the array.
TOML_API
array& prune(bool recursive = true) & noexcept;
/// \brief Removes empty child arrays and tables (rvalue overload).
///
/// \param recursive Should child arrays and tables themselves be pruned?
///
/// \returns An rvalue reference to the array.
array&& prune(bool recursive = true) && noexcept
{
return static_cast<toml::array&&>(this->prune(recursive));
}
/// \brief Removes the last element from the array.
TOML_API
void pop_back() noexcept;
/// \brief Removes all elements from the array.
TOML_API
void clear() noexcept;
/// @}
/// \name Insertion and Emplacement
/// @{
/// \brief Inserts a new element at a specific position in the array.
///
/// \detail \cpp
@ -858,7 +1075,6 @@ TOML_NAMESPACE_START
/// arr.insert(arr.cbegin() + 1, "two");
/// arr.insert(arr.cend(), toml::array{ 4, 5 });
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
@ -873,10 +1089,10 @@ TOML_NAMESPACE_START
///
/// \returns \conditional_return{Valid input}
/// An iterator to the newly-inserted element.
/// \conditional_return{Input is an empty toml::node_view}
/// \conditional_return{Input is a null toml::node_view}
/// end()
///
/// \attention The return value will always be `end()` if the input value was an empty toml::node_view,
/// \attention The return value will always be `end()` if the input value was a null toml::node_view,
/// because no insertion can take place. This is the only circumstance in which this can occur.
template <typename ElemType>
iterator insert(const_iterator pos, ElemType&& val, value_flags flags = preserve_source_value_flags)
@ -886,7 +1102,7 @@ TOML_NAMESPACE_START
if (!val)
return end();
}
return elems_.emplace(pos, impl::make_node(static_cast<ElemType&&>(val), flags));
return insert_at(pos, impl::make_node(static_cast<ElemType&&>(val), flags));
}
/// \brief Repeatedly inserts a new element starting at a specific position in the array.
@ -898,7 +1114,6 @@ TOML_NAMESPACE_START
/// };
/// arr.insert(arr.cbegin() + 1, 3, "honk");
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
@ -922,10 +1137,10 @@ TOML_NAMESPACE_START
/// An iterator to the newly-inserted element.
/// \conditional_return{count == 0}
/// A copy of pos
/// \conditional_return{Input is an empty toml::node_view}
/// \conditional_return{Input is a null toml::node_view}
/// end()
///
/// \attention The return value will always be `end()` if the input value was an empty toml::node_view,
/// \attention The return value will always be `end()` if the input value was a null toml::node_view,
/// because no insertion can take place. This is the only circumstance in which this can occur.
template <typename ElemType>
iterator insert(const_iterator pos,
@ -969,7 +1184,7 @@ TOML_NAMESPACE_START
/// An iterator to the first newly-inserted element.
/// \conditional_return{first >= last}
/// A copy of pos
/// \conditional_return{All objects in the range were empty toml::node_views}
/// \conditional_return{All objects in the range were null toml::node_views}
/// A copy of pos
template <typename Iter>
iterator insert(const_iterator pos, Iter first, Iter last, value_flags flags = preserve_source_value_flags)
@ -1020,7 +1235,7 @@ TOML_NAMESPACE_START
/// An iterator to the first newly-inserted element.
/// \conditional_return{Input list is empty}
/// A copy of pos
/// \conditional_return{All objects in the list were empty toml::node_views}
/// \conditional_return{All objects in the list were null toml::node_views}
/// A copy of pos
template <typename ElemType>
iterator insert(const_iterator pos,
@ -1038,7 +1253,6 @@ TOML_NAMESPACE_START
/// //add a string using std::string's substring constructor
/// arr.emplace<std::string>(arr.cbegin() + 1, "this is not a drill"sv, 14, 5);
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
@ -1061,7 +1275,7 @@ TOML_NAMESPACE_START
static_assert((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
"Emplacement type parameter must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
return elems_.emplace(pos, new impl::wrap_node<type>{ static_cast<Args&&>(args)... });
return insert_at(pos, impl::node_ptr{ new impl::wrap_node<type>{ static_cast<Args&&>(args)... } });
}
/// \brief Replaces the element at a specific position in the array with a different value.
@ -1086,10 +1300,10 @@ TOML_NAMESPACE_START
///
/// \returns \conditional_return{Valid input}
/// An iterator to the replaced element.
/// \conditional_return{Input is an empty toml::node_view}
/// \conditional_return{Input is a null toml::node_view}
/// end()
///
/// \attention The return value will always be `end()` if the input value was an empty toml::node_view,
/// \attention The return value will always be `end()` if the input value was a null toml::node_view,
/// because no replacement can take place. This is the only circumstance in which this can occur.
template <typename ElemType>
iterator replace(const_iterator pos, ElemType&& val, value_flags flags = preserve_source_value_flags)
@ -1107,128 +1321,6 @@ TOML_NAMESPACE_START
return it;
}
/// \brief Removes the specified element from the array.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << arr << "\n";
///
/// arr.erase(arr.cbegin() + 1);
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [ 1, 2, 3 ]
/// [ 1, 3 ]
/// \eout
///
/// \param pos Iterator to the element being erased.
///
/// \returns Iterator to the first element immediately following the removed element.
iterator erase(const_iterator pos) noexcept
{
return elems_.erase(pos);
}
/// \brief Removes the elements in the range [first, last) from the array.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, "bad", "karma" 2 };
/// std::cout << arr << "\n";
///
/// arr.erase(arr.cbegin() + 1, arr.cbegin() + 3);
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [ 1, 'bad', 'karma', 3 ]
/// [ 1, 3 ]
/// \eout
///
/// \param first Iterator to the first element being erased.
/// \param last Iterator to the one-past-the-last element being erased.
///
/// \returns Iterator to the first element immediately following the last removed element.
iterator erase(const_iterator first, const_iterator last) noexcept
{
return elems_.erase(first, last);
}
/// \brief Resizes the array.
///
/// \detail \godbolt{W5zqx3}
///
/// \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << arr << "\n";
///
/// arr.resize(6, 42);
/// std::cout << arr << "\n";
///
/// arr.resize(2, 0);
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [ 1, 2, 3 ]
/// [ 1, 2, 3, 42, 42, 42 ]
/// [ 1, 2 ]
/// \eout
///
/// \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 default_init_val The node or value used to initialize new elements if the array needs to grow.
/// \param default_init_flags Value flags to apply to new values created if new elements are created by growing.
template <typename ElemType>
void resize(size_t new_size,
ElemType&& default_init_val,
value_flags default_init_flags = preserve_source_value_flags)
{
static_assert(!is_node_view<ElemType>,
"The default element type argument to toml::array::resize may not be toml::node_view.");
if (!new_size)
elems_.clear();
else if (new_size < elems_.size())
elems_.resize(new_size);
else if (new_size > elems_.size())
insert(cend(), new_size - elems_.size(), static_cast<ElemType&&>(default_init_val), default_init_flags);
}
/// \brief Shrinks the array to the given size.
///
/// \detail \godbolt{rxEzK5}
///
/// \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << arr << "\n";
///
/// arr.truncate(5); // no-op
/// std::cout << arr << "\n";
///
/// arr.truncate(1);
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [ 1, 2, 3 ]
/// [ 1, 2, 3 ]
/// [ 1]
/// \eout
///
/// \remarks Does nothing if the requested size is larger than or equal to the current size.
void truncate(size_t new_size)
{
if (new_size < elems_.size())
elems_.resize(new_size);
}
/// \brief Appends a new element to the end of the array.
///
/// \detail \cpp
@ -1237,7 +1329,6 @@ TOML_NAMESPACE_START
/// arr.push_back(4.0);
/// arr.push_back(toml::array{ 5, "six"sv });
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
@ -1248,7 +1339,7 @@ TOML_NAMESPACE_START
/// \param val The node or value being added.
/// \param flags Value flags to apply to new values.
///
/// \attention No insertion takes place if the input value is an empty toml::node_view.
/// \attention No insertion takes place if the input value is a null toml::node_view.
/// This is the only circumstance in which this can occur.
template <typename ElemType>
void push_back(ElemType&& val, value_flags flags = preserve_source_value_flags)
@ -1262,7 +1353,6 @@ TOML_NAMESPACE_START
/// auto arr = toml::array{ 1, 2 };
/// arr.emplace_back<toml::array>(3, "four"sv);
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
@ -1296,86 +1386,17 @@ TOML_NAMESPACE_START
if constexpr (moving_node_ptr)
{
elems_.emplace_back(static_cast<ElemArgs&&>(args)...);
insert_at_back(static_cast<ElemArgs&&>(args)...);
return *elems_.back();
}
else
{
auto nde = new impl::wrap_node<unwrapped_type>{ static_cast<ElemArgs&&>(args)... };
elems_.emplace_back(nde);
return *nde;
auto ptr = new impl::wrap_node<unwrapped_type>{ static_cast<ElemArgs&&>(args)... };
insert_at_back(impl::node_ptr{ ptr });
return *ptr;
}
}
/// \brief Removes the last element from the array.
void pop_back() noexcept
{
elems_.pop_back();
}
/// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself.
///
/// \detail \cpp
///
/// auto arr = toml::array{ 1, 2, toml::array{ 3, 4, toml::array{ 5 } }, 6, toml::array{} };
/// std::cout << arr << "\n";
///
/// arr.flatten();
/// std::cout << arr << "\n";
///
/// \ecpp
///
/// \out
/// [ 1, 2, [ 3, 4, [ 5 ] ], 6, [] ]
/// [ 1, 2, 3, 4, 5, 6 ]
/// \eout
///
/// \remarks Arrays inside child tables are not flattened.
///
/// \returns A reference to the array.
TOML_API
array& flatten() &;
/// \brief Flattens this array, recursively hoisting the contents of child arrays up into itself (rvalue overload).
///
/// \returns An rvalue reference to the array.
array&& flatten() &&
{
return static_cast<toml::array&&>(this->flatten());
}
/// \brief Removes empty child arrays and tables.
///
/// \detail \cpp
///
/// auto arr = toml::array{ 1, 2, toml::array{ }, toml::array{ 3, toml::array{ } }, 4 };
/// std::cout << arr << "\n";
///
/// arr.prune();
/// std::cout << arr << "\n";
/// \ecpp
///
/// \out
/// [ 1, 2, [], [ 3, [] ], 4 ]
/// [ 1, 2, [ 3 ], 4 ]
/// \eout
///
/// \param recursive Should child arrays and tables themselves be pruned?
///
/// \returns A reference to the array.
TOML_API
array& prune(bool recursive = true) & noexcept;
/// \brief Removes empty child arrays and tables (rvalue overload).
///
/// \param recursive Should child arrays and tables themselves be pruned?
///
/// \returns An rvalue reference to the array.
array&& prune(bool recursive = true) && noexcept
{
return static_cast<toml::array&&>(this->prune(recursive));
}
/// @}
private:

View File

@ -16,6 +16,37 @@
TOML_NAMESPACE_START
{
TOML_EXTERNAL_LINKAGE
array::array(const impl::array_init_elem* b, const impl::array_init_elem* e)
{
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
TOML_ASSERT_ASSUME(b);
TOML_ASSERT_ASSUME(e);
TOML_ASSERT_ASSUME(b <= e);
if TOML_UNLIKELY(b == e)
return;
size_t cap{};
for (auto it = b; it != e; it++)
{
if (it->value)
cap++;
}
if TOML_UNLIKELY(!cap)
return;
elems_.reserve(cap);
for (; b != e; b++)
{
if (b->value)
elems_.push_back(std::move(b->value));
}
}
TOML_EXTERNAL_LINKAGE
array::array(const array& other) //
: node(other)
@ -32,7 +63,7 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
array::array(array && other) noexcept //
: node(std::move(other)),
elems_{ std::move(other.elems_) }
elems_(std::move(other.elems_))
{
#if TOML_LIFETIME_HOOKS
TOML_ARRAY_CREATED;
@ -68,7 +99,7 @@ TOML_NAMESPACE_START
void array::preinsertion_resize(size_t idx, size_t count)
{
TOML_ASSERT(idx <= elems_.size());
TOML_ASSERT(count >= 1u);
TOML_ASSERT_ASSUME(count >= 1u);
const auto old_size = elems_.size();
const auto new_size = old_size + count;
const auto inserting_at_end = idx == old_size;
@ -80,6 +111,18 @@ TOML_NAMESPACE_START
}
}
TOML_EXTERNAL_LINKAGE
void array::insert_at_back(impl::node_ptr && elem)
{
elems_.push_back(std::move(elem));
}
TOML_API
array::vector_iterator array::insert_at(const_vector_iterator pos, impl::node_ptr && elem)
{
return elems_.insert(pos, std::move(elem));
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype) const noexcept
{
@ -136,34 +179,41 @@ TOML_NAMESPACE_START
#else
auto n = get(index);
TOML_ASSERT(n && "element index not found in array!");
TOML_ASSERT_ASSUME(n && "element index not found in array!");
return *n;
#endif
}
TOML_EXTERNAL_LINKAGE
bool array::equal(const array& lhs, const array& rhs) noexcept
void array::reserve(size_t new_capacity)
{
if (&lhs == &rhs)
return true;
if (lhs.elems_.size() != rhs.elems_.size())
return false;
for (size_t i = 0, e = lhs.elems_.size(); i < e; i++)
{
const auto lhs_type = lhs.elems_[i]->type();
const node& rhs_ = *rhs.elems_[i];
const auto rhs_type = rhs_.type();
if (lhs_type != rhs_type)
return false;
elems_.reserve(new_capacity);
}
const bool equal = lhs.elems_[i]->visit(
[&](const auto& lhs_) noexcept
{ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
if (!equal)
return false;
}
return true;
TOML_EXTERNAL_LINKAGE
void array::shrink_to_fit()
{
elems_.shrink_to_fit();
}
TOML_EXTERNAL_LINKAGE
void array::truncate(size_t new_size)
{
if (new_size < elems_.size())
elems_.resize(new_size);
}
TOML_EXTERNAL_LINKAGE
array::iterator array::erase(const_iterator pos) noexcept
{
return elems_.erase(pos);
}
TOML_EXTERNAL_LINKAGE
array::iterator array::erase(const_iterator first, const_iterator last) noexcept
{
return elems_.erase(first, last);
}
TOML_EXTERNAL_LINKAGE
@ -270,6 +320,42 @@ TOML_NAMESPACE_START
return *this;
}
TOML_EXTERNAL_LINKAGE
void array::pop_back() noexcept
{
elems_.pop_back();
}
TOML_EXTERNAL_LINKAGE
void array::clear() noexcept
{
elems_.clear();
}
TOML_EXTERNAL_LINKAGE
bool array::equal(const array& lhs, const array& rhs) noexcept
{
if (&lhs == &rhs)
return true;
if (lhs.elems_.size() != rhs.elems_.size())
return false;
for (size_t i = 0, e = lhs.elems_.size(); i < e; i++)
{
const auto lhs_type = lhs.elems_[i]->type();
const node& rhs_ = *rhs.elems_[i];
const auto rhs_type = rhs_.type();
if (lhs_type != rhs_type)
return false;
const bool equal = lhs.elems_[i]->visit(
[&](const auto& lhs_) noexcept
{ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
if (!equal)
return false;
}
return true;
}
}
TOML_NAMESPACE_END;

View File

@ -229,7 +229,6 @@ TOML_NAMESPACE_START
/// std::cout << toml::time_offset{ -2, 30 } << "\n";
/// std::cout << toml::time_offset{ -2, -30 } << "\n";
/// std::cout << toml::time_offset{ 0, 0 } << "\n";
///
/// \ecpp
///
/// \out

View File

@ -37,7 +37,7 @@ TOML_IMPL_NAMESPACE_START
constants_{ &constants },
config_{ config }
{
TOML_ASSERT(source_ != nullptr);
TOML_ASSERT_ASSUME(source_);
config_.flags = (config_.flags | constants_->mandatory_flags) & ~constants_->ignored_flags;

View File

@ -395,6 +395,62 @@ TOML_IMPL_NAMESPACE_START
&& !is_wide_string<T>;
template <typename, typename>
struct copy_ref_;
template <typename Dest, typename Src>
using copy_ref = typename copy_ref_<Dest, Src>::type;
template <typename Dest, typename Src>
struct copy_ref_
{
using type = Dest;
};
template <typename Dest, typename Src>
struct copy_ref_<Dest, Src&>
{
using type = std::add_lvalue_reference_t<Dest>;
};
template <typename Dest, typename Src>
struct copy_ref_<Dest, Src&&>
{
using type = std::add_rvalue_reference_t<Dest>;
};
template <typename, typename>
struct copy_cv_;
template <typename Dest, typename Src>
using copy_cv = typename copy_cv_<Dest, Src>::type;
template <typename Dest, typename Src>
struct copy_cv_
{
using type = Dest;
};
template <typename Dest, typename Src>
struct copy_cv_<Dest, const Src>
{
using type = std::add_const_t<Dest>;
};
template <typename Dest, typename Src>
struct copy_cv_<Dest, volatile Src>
{
using type = std::add_volatile_t<Dest>;
};
template <typename Dest, typename Src>
struct copy_cv_<Dest, const volatile Src>
{
using type = std::add_cv_t<Dest>;
};
template <typename Dest, typename Src>
using copy_cvref =
copy_ref<copy_ref<copy_cv<std::remove_reference_t<Dest>, std::remove_reference_t<Src>>, Dest>, Src>;
template <typename T>
inline constexpr bool dependent_false = false;
@ -416,21 +472,21 @@ TOML_IMPL_NAMESPACE_START
static constexpr auto type = node_type::none;
};
template <typename T>
struct value_traits<const T> : value_traits<T>
{};
template <typename T>
struct value_traits<volatile T> : value_traits<T>
{};
template <typename T>
struct value_traits<const volatile T> : value_traits<T>
{};
template <typename T>
struct value_traits<T&> : value_traits<T>
{};
template <typename T>
struct value_traits<T&&> : value_traits<T>
{};
template <typename T>
struct value_traits<T* const> : value_traits<T*>
{};
template <typename T>
struct value_traits<T* volatile> : value_traits<T*>
{};
template <typename T>
struct value_traits<T* const volatile> : value_traits<T*>
{};
// integer value_traits specializations - standard types
template <typename T>
@ -747,6 +803,21 @@ TOML_IMPL_NAMESPACE_START
{
using type = T;
};
template <typename T>
struct node_wrapper<const T>
{
using type = std::add_const_t<typename node_wrapper<T>::type>;
};
template <typename T>
struct node_wrapper<volatile T>
{
using type = std::add_volatile_t<typename node_wrapper<T>::type>;
};
template <typename T>
struct node_wrapper<const volatile T>
{
using type = std::add_const_t<std::add_volatile_t<typename node_wrapper<T>::type>>;
};
template <>
struct node_wrapper<std::string>
{
@ -783,7 +854,7 @@ TOML_IMPL_NAMESPACE_START
using type = value<date_time>;
};
template <typename T>
using wrap_node = typename node_wrapper<T>::type;
using wrap_node = typename node_wrapper<std::remove_reference_t<T>>::type;
// nodes => native value types
template <typename T>
@ -797,7 +868,22 @@ TOML_IMPL_NAMESPACE_START
using type = T;
};
template <typename T>
using unwrap_node = typename node_unwrapper<T>::type;
struct node_unwrapper<const value<T>>
{
using type = std::add_const_t<T>;
};
template <typename T>
struct node_unwrapper<volatile value<T>>
{
using type = std::add_volatile_t<T>;
};
template <typename T>
struct node_unwrapper<const volatile value<T>>
{
using type = std::add_volatile_t<std::add_const_t<T>>;
};
template <typename T>
using unwrap_node = typename node_unwrapper<std::remove_reference_t<T>>::type;
template <typename T>
struct node_type_getter

View File

@ -36,39 +36,46 @@ TOML_NAMESPACE_START
public:
/// \brief Default constructor.
TOML_NODISCARD_CTOR
key() noexcept = default;
/// \brief Constructs a key from a string view and source region.
TOML_NODISCARD_CTOR
explicit key(std::string_view k, source_region&& src = {}) //
: key_{ k },
source_{ std::move(src) }
{}
/// \brief Constructs a key from a string view and source region.
TOML_NODISCARD_CTOR
explicit key(std::string_view k, const source_region& src) //
: key_{ k },
source_{ src }
{}
/// \brief Constructs a key from a string and source region.
TOML_NODISCARD_CTOR
explicit key(std::string&& k, source_region&& src = {}) noexcept //
: key_{ std::move(k) },
source_{ std::move(src) }
{}
/// \brief Constructs a key from a string and source region.
TOML_NODISCARD_CTOR
explicit key(std::string&& k, const source_region& src) noexcept //
: key_{ std::move(k) },
source_{ src }
{}
/// \brief Constructs a key from a c-string and source region.
TOML_NODISCARD_CTOR
explicit key(const char* k, source_region&& src = {}) //
: key_{ k },
source_{ std::move(src) }
{}
/// \brief Constructs a key from a c-string view and source region.
TOML_NODISCARD_CTOR
explicit key(const char* k, const source_region& src) //
: key_{ k },
source_{ src }
@ -79,6 +86,7 @@ TOML_NAMESPACE_START
/// \brief Constructs a key from a wide string view and source region.
///
/// \availability This constructor is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD_CTOR
explicit key(std::wstring_view k, source_region&& src = {}) //
: key_{ impl::narrow(k) },
source_{ std::move(src) }
@ -87,6 +95,7 @@ TOML_NAMESPACE_START
/// \brief Constructs a key from a wide string and source region.
///
/// \availability This constructor is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
TOML_NODISCARD_CTOR
explicit key(std::wstring_view k, const source_region& src) //
: key_{ impl::narrow(k) },
source_{ src }

View File

@ -22,7 +22,7 @@ TOML_IMPL_NAMESPACE_START
// arrays + tables - invoke copy/move ctor
if constexpr (is_one_of<unwrapped_type, array, table>)
{
return new unwrapped_type{ static_cast<T&&>(val) };
return new unwrapped_type(static_cast<T&&>(val));
}
// values

View File

@ -27,20 +27,41 @@ TOML_NAMESPACE_START
TOML_NODISCARD
decltype(auto) get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>);
template <typename T, typename N>
using ref_type_ = std::conditional_t< //
std::is_reference_v<T>, //
impl::copy_ref<impl::copy_cv<impl::unwrap_node<T>, std::remove_reference_t<N>>, T>, //
impl::copy_cvref<impl::unwrap_node<T>, N> //
>;
template <typename T, typename N>
using ref_type = std::conditional_t< //
std::is_reference_v<N>, //
ref_type_<T, N>, //
ref_type_<T, std::add_lvalue_reference_t<N>> //
>;
template <typename T, typename N>
TOML_PURE_GETTER
static decltype(auto) do_ref(N&& n) noexcept
static ref_type<T, N&&> do_ref(N&& n) noexcept
{
using type = impl::unwrap_node<T>;
static_assert((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
using unwrapped_type = impl::unwrap_node<T>;
static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
"The template type argument of node::ref() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
TOML_ASSERT(
n.template is<T>()
&& "template type argument T provided to toml::node::ref() didn't match the node's actual type");
if constexpr (impl::is_native<type>)
return static_cast<N&&>(n).template ref_cast<type>().get();
TOML_ASSERT_ASSUME(
n.template is<unwrapped_type>()
&& "template type argument provided to toml::node::ref() didn't match the node's actual type");
using node_ref = std::remove_volatile_t<std::remove_reference_t<N>>&;
using val_type = std::remove_volatile_t<unwrapped_type>;
using out_ref = ref_type<T, N&&>;
static_assert(std::is_reference_v<out_ref>);
if constexpr (toml::is_value<unwrapped_type>)
return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>().get());
else
return static_cast<N&&>(n).template ref_cast<type>();
return static_cast<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>());
}
protected:
@ -58,29 +79,55 @@ TOML_NAMESPACE_START
TOML_API
node& operator=(node&&) noexcept;
template <typename T, typename N>
using ref_cast_type_ = std::conditional_t< //
std::is_reference_v<T>, //
impl::copy_ref<impl::copy_cv<impl::wrap_node<T>, std::remove_reference_t<N>>, T>, //
impl::copy_cvref<impl::wrap_node<T>, N> //
>;
template <typename T, typename N>
using ref_cast_type = std::conditional_t< //
std::is_reference_v<N>, //
ref_cast_type_<T, N>, //
ref_cast_type_<T, std::add_lvalue_reference_t<N>> //
>;
template <typename T>
TOML_PURE_INLINE_GETTER
impl::wrap_node<T>& ref_cast() & noexcept
ref_cast_type<T, node&> ref_cast() & noexcept
{
return *reinterpret_cast<impl::wrap_node<T>*>(this);
using out_ref = ref_cast_type<T, node&>;
using out_type = std::remove_reference_t<out_ref>;
return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
}
template <typename T>
TOML_PURE_INLINE_GETTER
impl::wrap_node<T>&& ref_cast() && noexcept
ref_cast_type<T, node&&> ref_cast() && noexcept
{
return std::move(*reinterpret_cast<impl::wrap_node<T>*>(this));
using out_ref = ref_cast_type<T, node&&>;
using out_type = std::remove_reference_t<out_ref>;
return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
}
template <typename T>
TOML_PURE_INLINE_GETTER
const impl::wrap_node<T>& ref_cast() const& noexcept
ref_cast_type<T, const node&> ref_cast() const& noexcept
{
return *reinterpret_cast<const impl::wrap_node<T>*>(this);
using out_ref = ref_cast_type<T, const node&>;
using out_type = std::remove_reference_t<out_ref>;
return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
}
template <typename N, typename T>
using ref_cast_type = decltype(std::declval<N>().template ref_cast<T>());
template <typename T>
TOML_PURE_INLINE_GETTER
ref_cast_type<T, const node&&> ref_cast() const&& noexcept
{
using out_ref = ref_cast_type<T, const node&&>;
using out_type = std::remove_reference_t<out_ref>;
return static_cast<out_ref>(*reinterpret_cast<out_type*>(this));
}
/// \endcond
@ -137,7 +184,6 @@ TOML_NAMESPACE_START
/// std::cout << "all floats: "sv << arr.is_homogeneous(toml::node_type::floating_point) << "\n";
/// std::cout << "all arrays: "sv << arr.is_homogeneous(toml::node_type::array) << "\n";
/// std::cout << "all ints: "sv << arr.is_homogeneous(toml::node_type::integer) << "\n";
///
/// \ecpp
///
/// \out
@ -167,7 +213,6 @@ TOML_NAMESPACE_START
/// std::cout << "all doubles: "sv << arr.is_homogeneous<double>() << "\n";
/// std::cout << "all arrays: "sv << arr.is_homogeneous<toml::array>() << "\n";
/// std::cout << "all integers: "sv << arr.is_homogeneous<int64_t>() << "\n";
///
/// \ecpp
///
/// \out
@ -190,13 +235,13 @@ TOML_NAMESPACE_START
TOML_PURE_GETTER
bool is_homogeneous() const noexcept
{
using type = impl::unwrap_node<ElemType>;
static_assert(
std::is_void_v<
type> || ((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>),
"The template type argument of node::is_homogeneous() must be void or one "
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
return is_homogeneous(impl::node_type_of<type>);
using unwrapped_type = impl::unwrap_node<impl::remove_cvref<ElemType>>;
static_assert(std::is_void_v<unwrapped_type> //
|| (toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>),
"The template type argument of node::is_homogeneous() must be void or one "
"of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
return is_homogeneous(impl::node_type_of<unwrapped_type>);
}
/// \brief Returns the node's type identifier.
@ -260,27 +305,27 @@ TOML_NAMESPACE_START
TOML_PURE_INLINE_GETTER
bool is() const noexcept
{
using type = impl::unwrap_node<T>;
static_assert((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
"The template type argument of node::is() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
if constexpr (std::is_same_v<type, table>)
if constexpr (std::is_same_v<unwrapped_type, table>)
return is_table();
else if constexpr (std::is_same_v<type, array>)
else if constexpr (std::is_same_v<unwrapped_type, array>)
return is_array();
else if constexpr (std::is_same_v<type, std::string>)
else if constexpr (std::is_same_v<unwrapped_type, std::string>)
return is_string();
else if constexpr (std::is_same_v<type, int64_t>)
else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
return is_integer();
else if constexpr (std::is_same_v<type, double>)
else if constexpr (std::is_same_v<unwrapped_type, double>)
return is_floating_point();
else if constexpr (std::is_same_v<type, bool>)
else if constexpr (std::is_same_v<unwrapped_type, bool>)
return is_boolean();
else if constexpr (std::is_same_v<type, date>)
else if constexpr (std::is_same_v<unwrapped_type, date>)
return is_date();
else if constexpr (std::is_same_v<type, time>)
else if constexpr (std::is_same_v<unwrapped_type, time>)
return is_time();
else if constexpr (std::is_same_v<type, date_time>)
else if constexpr (std::is_same_v<unwrapped_type, date_time>)
return is_date_time();
}
@ -376,7 +421,6 @@ TOML_NAMESPACE_START
/// toml::value<int64_t>* int_value2 = node->as<toml::value<int64_t>>();
/// if (int_value2)
/// std::cout << "Node is a value<int64_t>\n";
///
/// \ecpp
///
/// \tparam T The node type or TOML value type to cast to.
@ -386,27 +430,27 @@ TOML_NAMESPACE_START
TOML_PURE_INLINE_GETTER
impl::wrap_node<T>* as() noexcept
{
using type = impl::unwrap_node<T>;
static_assert((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
"The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
if constexpr (std::is_same_v<type, table>)
if constexpr (std::is_same_v<unwrapped_type, table>)
return as_table();
else if constexpr (std::is_same_v<type, array>)
else if constexpr (std::is_same_v<unwrapped_type, array>)
return as_array();
else if constexpr (std::is_same_v<type, std::string>)
else if constexpr (std::is_same_v<unwrapped_type, std::string>)
return as_string();
else if constexpr (std::is_same_v<type, int64_t>)
else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
return as_integer();
else if constexpr (std::is_same_v<type, double>)
else if constexpr (std::is_same_v<unwrapped_type, double>)
return as_floating_point();
else if constexpr (std::is_same_v<type, bool>)
else if constexpr (std::is_same_v<unwrapped_type, bool>)
return as_boolean();
else if constexpr (std::is_same_v<type, date>)
else if constexpr (std::is_same_v<unwrapped_type, date>)
return as_date();
else if constexpr (std::is_same_v<type, time>)
else if constexpr (std::is_same_v<unwrapped_type, time>)
return as_time();
else if constexpr (std::is_same_v<type, date_time>)
else if constexpr (std::is_same_v<unwrapped_type, date_time>)
return as_date_time();
}
@ -415,27 +459,27 @@ TOML_NAMESPACE_START
TOML_PURE_INLINE_GETTER
const impl::wrap_node<T>* as() const noexcept
{
using type = impl::unwrap_node<T>;
static_assert((impl::is_native<type> || impl::is_one_of<type, table, array>)&&!impl::is_cvref<type>,
using unwrapped_type = impl::unwrap_node<impl::remove_cvref<T>>;
static_assert(toml::is_value<unwrapped_type> || toml::is_container<unwrapped_type>,
"The template type argument of node::as() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
if constexpr (std::is_same_v<type, table>)
if constexpr (std::is_same_v<unwrapped_type, table>)
return as_table();
else if constexpr (std::is_same_v<type, array>)
else if constexpr (std::is_same_v<unwrapped_type, array>)
return as_array();
else if constexpr (std::is_same_v<type, std::string>)
else if constexpr (std::is_same_v<unwrapped_type, std::string>)
return as_string();
else if constexpr (std::is_same_v<type, int64_t>)
else if constexpr (std::is_same_v<unwrapped_type, int64_t>)
return as_integer();
else if constexpr (std::is_same_v<type, double>)
else if constexpr (std::is_same_v<unwrapped_type, double>)
return as_floating_point();
else if constexpr (std::is_same_v<type, bool>)
else if constexpr (std::is_same_v<unwrapped_type, bool>)
return as_boolean();
else if constexpr (std::is_same_v<type, date>)
else if constexpr (std::is_same_v<unwrapped_type, date>)
return as_date();
else if constexpr (std::is_same_v<type, time>)
else if constexpr (std::is_same_v<unwrapped_type, time>)
return as_time();
else if constexpr (std::is_same_v<type, date_time>)
else if constexpr (std::is_same_v<unwrapped_type, date_time>)
return as_date_time();
}
@ -621,6 +665,23 @@ TOML_NAMESPACE_START
/// \brief Gets a raw reference to a value node's underlying data.
///
/// \note Providing explicit ref qualifiers acts as an explicit ref-category cast. Providing
/// explicit cv-ref qualifiers 'merges' them with whatever the cv qualification of the node is. Examples:
/// | node | T | return type |
/// |-------------|------------------------|------------------------------|
/// | node& | std::string | std::string& |
/// | node& | std::string& | std::string& |
/// | node& | std::string&& | std::string&& |
/// | node&& | std::string | std::string&& |
/// | node&& | std::string& | std::string& |
/// | node&& | std::string&& | std::string&& |
/// | const node& | std::string | const std::string& |
/// | const node& | std::string& | const std::string& |
/// | const node& | std::string&& | const std::string&& |
/// | const node& | volatile std::string | const volatile std::string& |
/// | const node& | volatile std::string& | const volatile std::string& |
/// | const node& | volatile std::string&& | const volatile std::string&& |
///
/// \warning This function is dangerous if used carelessly and **WILL** break your code if the
/// chosen value type doesn't match the node's actual type. In debug builds an assertion
/// will fire when invalid accesses are attempted: \cpp
@ -632,7 +693,6 @@ TOML_NAMESPACE_START
///
/// int64_t& min_ref = tbl.get("min")->ref<int64_t>(); // matching type
/// double& max_ref = tbl.get("max")->ref<double>(); // mismatched type, hits assert()
///
/// \ecpp
///
/// \tparam T One of the TOML value types.
@ -640,7 +700,7 @@ TOML_NAMESPACE_START
/// \returns A reference to the underlying data.
template <typename T>
TOML_PURE_GETTER
impl::unwrap_node<T>& ref() & noexcept
decltype(auto) ref() & noexcept
{
return do_ref<T>(*this);
}
@ -648,7 +708,7 @@ TOML_NAMESPACE_START
/// \brief Gets a raw reference to a value node's underlying data (rvalue overload).
template <typename T>
TOML_PURE_GETTER
impl::unwrap_node<T>&& ref() && noexcept
decltype(auto) ref() && noexcept
{
return do_ref<T>(std::move(*this));
}
@ -656,11 +716,19 @@ TOML_NAMESPACE_START
/// \brief Gets a raw reference to a value node's underlying data (const lvalue overload).
template <typename T>
TOML_PURE_GETTER
const impl::unwrap_node<T>& ref() const& noexcept
decltype(auto) ref() const& noexcept
{
return do_ref<T>(*this);
}
/// \brief Gets a raw reference to a value node's underlying data (const rvalue overload).
template <typename T>
TOML_PURE_GETTER
decltype(auto) ref() const&& noexcept
{
return do_ref<T>(std::move(*this));
}
/// @}
/// \name Metadata
@ -681,7 +749,7 @@ TOML_NAMESPACE_START
// clang-format off
template <typename Func, typename N, typename T>
static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<N, T>>;
static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<T, N>>;
template <typename Func, typename N>
static constexpr bool can_visit_any =
@ -710,7 +778,7 @@ TOML_NAMESPACE_START
template <typename Func, typename N, typename T>
static constexpr bool visit_is_nothrow_one =
!can_visit<Func, N, T>
|| std::is_nothrow_invocable_v<Func, ref_cast_type<N, T>>;
|| std::is_nothrow_invocable_v<Func, ref_cast_type<T, N>>;
template <typename Func, typename N>
static constexpr bool visit_is_nothrow =
@ -729,7 +797,7 @@ TOML_NAMESPACE_START
template <typename Func, typename N, typename T, bool = can_visit<Func, N, T>>
struct visit_return_type_
{
using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<N, T>>()));
using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<T, N>>()));
};
template <typename Func, typename N, typename T>
struct visit_return_type_<Func, N, T, false>
@ -856,7 +924,6 @@ TOML_NAMESPACE_START
/// else
/// throw std::exception{ "Expected string or integer" };
/// });
///
/// \ecpp
///
/// \tparam Func A callable type invocable with one or more of the
@ -888,6 +955,13 @@ TOML_NAMESPACE_START
return do_visit(*this, static_cast<Func&&>(visitor));
}
/// \brief Invokes a visitor on the node based on the node's concrete type (const rvalue overload).
template <typename Func>
decltype(auto) visit(Func&& visitor) const&& noexcept(visit_is_nothrow<Func&&, const node&&>)
{
return do_visit(static_cast<const node&&>(*this), static_cast<Func&&>(visitor));
}
/// @}
/// \name Node views

View File

@ -225,7 +225,7 @@ TOML_NAMESPACE_START
TOML_PURE_GETTER
bool is() const noexcept
{
return node_ ? node_->template is<T>() : false;
return node_ ? node_->template is<impl::unwrap_node<impl::remove_cvref<T>>>() : false;
}
/// \brief Checks if the viewed node contains values/elements of only one type.
@ -276,7 +276,6 @@ TOML_NAMESPACE_START
/// std::cout << "all floats: "sv << cfg["arr"].is_homogeneous(toml::node_type::floating_point) << "\n";
/// std::cout << "all arrays: "sv << cfg["arr"].is_homogeneous(toml::node_type::array) << "\n";
/// std::cout << "all ints: "sv << cfg["arr"].is_homogeneous(toml::node_type::integer) << "\n";
///
/// \ecpp
///
/// \out
@ -308,7 +307,6 @@ TOML_NAMESPACE_START
/// std::cout << "all doubles: "sv << cfg["arr"].is_homogeneous<double>() << "\n";
/// std::cout << "all arrays: "sv << cfg["arr"].is_homogeneous<toml::array>() << "\n";
/// std::cout << "all integers: "sv << cfg["arr"].is_homogeneous<int64_t>() << "\n";
///
/// \ecpp
///
/// \out
@ -330,7 +328,7 @@ TOML_NAMESPACE_START
TOML_PURE_GETTER
bool is_homogeneous() const noexcept
{
return node_ ? node_->template is_homogeneous<impl::unwrap_node<ElemType>>() : false;
return node_ ? node_->template is_homogeneous<impl::unwrap_node<impl::remove_cvref<ElemType>>>() : false;
}
/// @}
@ -347,70 +345,70 @@ TOML_NAMESPACE_START
/// \see toml::node::as()
template <typename T>
TOML_PURE_GETTER
auto as() const noexcept
auto* as() const noexcept
{
return node_ ? node_->template as<T>() : nullptr;
}
/// \brief Returns a pointer to the viewed node as a toml::table, if it is one.
TOML_PURE_GETTER
auto as_table() const noexcept
auto* as_table() const noexcept
{
return as<table>();
}
/// \brief Returns a pointer to the viewed node as a toml::array, if it is one.
TOML_PURE_GETTER
auto as_array() const noexcept
auto* as_array() const noexcept
{
return as<array>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<string>, if it is one.
TOML_PURE_GETTER
auto as_string() const noexcept
auto* as_string() const noexcept
{
return as<std::string>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<int64_t>, if it is one.
TOML_PURE_GETTER
auto as_integer() const noexcept
auto* as_integer() const noexcept
{
return as<int64_t>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<double>, if it is one.
TOML_PURE_GETTER
auto as_floating_point() const noexcept
auto* as_floating_point() const noexcept
{
return as<double>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<bool>, if it is one.
TOML_PURE_GETTER
auto as_boolean() const noexcept
auto* as_boolean() const noexcept
{
return as<bool>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<date>, if it is one.
TOML_PURE_GETTER
auto as_date() const noexcept
auto* as_date() const noexcept
{
return as<date>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<time>, if it is one.
TOML_PURE_GETTER
auto as_time() const noexcept
auto* as_time() const noexcept
{
return as<time>();
}
/// \brief Returns a pointer to the viewed node as a toml::value<date_time>, if it is one.
TOML_PURE_GETTER
auto as_date_time() const noexcept
auto* as_date_time() const noexcept
{
return as<date_time>();
}
@ -528,6 +526,17 @@ TOML_NAMESPACE_START
/// \brief Gets a raw reference to the viewed node's underlying data.
///
/// /// \note Providing explicit ref qualifiers acts as an explicit ref-category cast. Providing
/// explicit cv-ref qualifiers 'merges' them with whatever the cv qualification of the viewed node is. Examples:
/// | node | T | return type |
/// |-------------|------------------------|------------------------------|
/// | node | std::string | std::string& |
/// | node | std::string& | std::string& |
/// | node | std::string&& | std::string&& |
/// | const node | volatile std::string | const volatile std::string& |
/// | const node | volatile std::string& | const volatile std::string& |
/// | const node | volatile std::string&& | const volatile std::string&& |
///
/// \warning This function is dangerous if used carelessly and **WILL** break your code if the
/// node_view didn't reference a node, or the chosen value type doesn't match the node's
/// actual type. In debug builds an assertion will fire when invalid accesses are attempted: \cpp
@ -540,7 +549,6 @@ TOML_NAMESPACE_START
/// int64_t& min_ref = tbl["min"].ref<int64_t>(); // matching type
/// double& max_ref = tbl["max"].ref<double>(); // mismatched type, hits assert()
/// int64_t& foo_ref = tbl["foo"].ref<int64_t>(); // nonexistent key, hits assert()
///
/// \ecpp
///
/// \tparam T One of the TOML value types.
@ -550,8 +558,8 @@ TOML_NAMESPACE_START
TOML_PURE_INLINE_GETTER
decltype(auto) ref() const noexcept
{
TOML_ASSERT(node_ && "toml::node_view::ref() called on a node_view that did not reference a node");
return node_->template ref<impl::unwrap_node<T>>();
TOML_ASSERT_ASSUME(node_ && "toml::node_view::ref() called on a node_view that did not reference a node");
return node_->template ref<T>();
}
/// @}

View File

@ -35,7 +35,6 @@ TOML_NAMESPACE_START
/// do_stuff_with_a_table(result); //implicitly converts to table&
/// else
/// std::cerr << "Parse failed:\n"sv << result.error() << "\n";
///
/// \ecpp
///
/// \out
@ -114,7 +113,7 @@ TOML_NAMESPACE_START
TOML_NODISCARD
toml::table& table() & noexcept
{
TOML_ASSERT(!err_);
TOML_ASSERT_ASSUME(!err_);
return *get_as<toml::table>(storage_);
}
@ -122,7 +121,7 @@ TOML_NAMESPACE_START
TOML_NODISCARD
toml::table&& table() && noexcept
{
TOML_ASSERT(!err_);
TOML_ASSERT_ASSUME(!err_);
return static_cast<toml::table&&>(*get_as<toml::table>(storage_));
}
@ -130,7 +129,7 @@ TOML_NAMESPACE_START
TOML_NODISCARD
const toml::table& table() const& noexcept
{
TOML_ASSERT(!err_);
TOML_ASSERT_ASSUME(!err_);
return *get_as<const toml::table>(storage_);
}
@ -138,7 +137,7 @@ TOML_NAMESPACE_START
TOML_NODISCARD
parse_error& error() & noexcept
{
TOML_ASSERT(err_);
TOML_ASSERT_ASSUME(err_);
return *get_as<parse_error>(storage_);
}
@ -146,7 +145,7 @@ TOML_NAMESPACE_START
TOML_NODISCARD
parse_error&& error() && noexcept
{
TOML_ASSERT(err_);
TOML_ASSERT_ASSUME(err_);
return static_cast<parse_error&&>(*get_as<parse_error>(storage_));
}
@ -154,7 +153,7 @@ TOML_NAMESPACE_START
TOML_NODISCARD
const parse_error& error() const& noexcept
{
TOML_ASSERT(err_);
TOML_ASSERT_ASSUME(err_);
return *get_as<const parse_error>(storage_);
}

View File

@ -20,7 +20,6 @@ TOML_NAMESPACE_START
/// \detail \cpp
/// auto tbl = toml::parse("a = 3"sv);
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -45,7 +44,6 @@ TOML_NAMESPACE_START
/// \detail \cpp
/// auto tbl = toml::parse("a = 3"sv, "foo.toml");
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -91,7 +89,6 @@ TOML_NAMESPACE_START
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv);
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -116,7 +113,6 @@ TOML_NAMESPACE_START
/// \detail \cpp
/// auto tbl = toml::parse(u8"a = 3"sv, "foo.toml");
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -166,7 +162,6 @@ TOML_NAMESPACE_START
/// \detail \cpp
/// auto tbl = toml::parse("a = 3"sv, L"foo.toml");
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -196,7 +191,6 @@ TOML_NAMESPACE_START
///
/// auto tbl = toml::parse(ss);
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -277,7 +271,6 @@ TOML_NAMESPACE_START
///
/// auto tbl = toml::parse(ss);
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -305,7 +298,6 @@ TOML_NAMESPACE_START
///
/// auto tbl = toml::parse(ss, "foo.toml");
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -338,7 +330,6 @@ TOML_NAMESPACE_START
///
/// auto tbl = "a = 3"_toml;
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out
@ -367,7 +358,6 @@ TOML_NAMESPACE_START
///
/// auto tbl = u8"a = 3"_toml;
/// std::cout << tbl["a"] << "\n";
///
/// \ecpp
///
/// \out

View File

@ -41,12 +41,6 @@ TOML_ENABLE_WARNINGS;
//# UTF8 STREAMS
//#---------------------------------------------------------------------------------------------------------------------
#ifdef NDEBUG
#define assert_or_assume(cond) TOML_ASSUME(cond)
#else
#define assert_or_assume(cond) TOML_ASSERT(cond)
#endif
TOML_ANON_NAMESPACE_START
{
template <typename T>
@ -158,7 +152,7 @@ TOML_ANON_NAMESPACE_START
TOML_ATTR(nonnull)
size_t operator()(void* dest, size_t num) noexcept
{
assert_or_assume(!eof());
TOML_ASSERT_ASSUME(!eof());
num = impl::min(position_ + num, source_.length()) - position_;
std::memcpy(dest, source_.data() + position_, num);
@ -271,8 +265,8 @@ TOML_ANON_NAMESPACE_START
#if TOML_EXCEPTIONS
#define utf8_reader_error(...) throw parse_error(__VA_ARGS__)
#define utf8_reader_return_after_error(...) (void)0
#define utf8_reader_error_check(...) (void)0
#define utf8_reader_return_after_error(...) static_assert(true)
#define utf8_reader_error_check(...) static_assert(true)
#else
#define utf8_reader_error(...) err_.emplace(__VA_ARGS__)
#define utf8_reader_return_after_error(...) return __VA_ARGS__
@ -366,7 +360,7 @@ TOML_ANON_NAMESPACE_START
return false;
}
assert_or_assume(raw_bytes_read);
TOML_ASSERT_ASSUME(raw_bytes_read);
std::memset(&codepoints_, 0, sizeof(codepoints_));
// helper for calculating decoded codepoint line+cols
@ -453,7 +447,7 @@ TOML_ANON_NAMESPACE_START
}
}
assert_or_assume(codepoints_.count);
TOML_ASSERT_ASSUME(codepoints_.count);
calc_positions();
// handle general I/O errors
@ -501,11 +495,11 @@ TOML_ANON_NAMESPACE_START
if TOML_UNLIKELY(!stream_ || !read_next_block())
return nullptr;
assert_or_assume(!codepoints_.current);
TOML_ASSERT_ASSUME(!codepoints_.current);
}
assert_or_assume(codepoints_.count);
assert_or_assume(codepoints_.count <= block_capacity);
assert_or_assume(codepoints_.current < codepoints_.count);
TOML_ASSERT_ASSUME(codepoints_.count);
TOML_ASSERT_ASSUME(codepoints_.count <= block_capacity);
TOML_ASSERT_ASSUME(codepoints_.current < codepoints_.count);
return &codepoints_.buffer[codepoints_.current++];
}
@ -537,7 +531,7 @@ TOML_ANON_NAMESPACE_START
utf8_reader(std::basic_istream<Char>&, std::string &&) -> utf8_reader<std::basic_istream<Char>>;
#if TOML_EXCEPTIONS
#define utf8_buffered_reader_error_check(...) (void)0
#define utf8_buffered_reader_error_check(...) static_assert(true)
#else
#define utf8_buffered_reader_error_check(...) \
do \
@ -621,8 +615,8 @@ TOML_ANON_NAMESPACE_START
{
utf8_buffered_reader_error_check({});
assert_or_assume(history_.count);
assert_or_assume(negative_offset_ + count <= history_.count);
TOML_ASSERT_ASSUME(history_.count);
TOML_ASSERT_ASSUME(negative_offset_ + count <= history_.count);
negative_offset_ += count;
@ -869,11 +863,7 @@ TOML_ANON_NAMESPACE_START
parse_scope& operator=(const parse_scope&) = delete;
parse_scope& operator=(parse_scope&&) = delete;
};
#define push_parse_scope_2(scope, line) \
parse_scope ps_##line \
{ \
current_scope, scope \
}
#define push_parse_scope_2(scope, line) parse_scope ps_##line(current_scope, scope)
#define push_parse_scope_1(scope, line) push_parse_scope_2(scope, line)
#define push_parse_scope(scope) push_parse_scope_1(scope, __LINE__)
@ -965,7 +955,7 @@ TOML_ANON_NAMESPACE_END;
// of toml++.
#define is_eof() !cp
#define assert_not_eof() assert_or_assume(cp != nullptr)
#define assert_not_eof() TOML_ASSERT_ASSUME(cp != nullptr)
#define return_if_eof(...) \
do \
{ \
@ -1126,7 +1116,7 @@ TOML_IMPL_NAMESPACE_START
void go_back(size_t count = 1) noexcept
{
return_if_error();
assert_or_assume(count);
TOML_ASSERT_ASSUME(count);
cp = reader.step_back(count);
prev_pos = cp->position;
@ -1290,8 +1280,8 @@ TOML_IMPL_NAMESPACE_START
bool consume_digit_sequence(T* digits, size_t len)
{
return_if_error({});
assert_or_assume(digits);
assert_or_assume(len);
TOML_ASSERT_ASSUME(digits);
TOML_ASSERT_ASSUME(len);
for (size_t i = 0; i < len; i++)
{
@ -1310,8 +1300,8 @@ TOML_IMPL_NAMESPACE_START
size_t consume_variable_length_digit_sequence(T* buffer, size_t max_len)
{
return_if_error({});
assert_or_assume(buffer);
assert_or_assume(max_len);
TOML_ASSERT_ASSUME(buffer);
TOML_ASSERT_ASSUME(max_len);
size_t i = {};
for (; i < max_len; i++)
@ -1331,7 +1321,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(*cp == U'"');
TOML_ASSERT_ASSUME(*cp == U'"');
push_parse_scope("string"sv);
// skip the '"'
@ -1557,7 +1547,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(*cp == U'\'');
TOML_ASSERT_ASSUME(*cp == U'\'');
push_parse_scope("literal string"sv);
// skip the delimiter
@ -1661,7 +1651,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(is_string_delimiter(*cp));
TOML_ASSERT_ASSUME(is_string_delimiter(*cp));
push_parse_scope("string"sv);
// get the first three characters to determine the string type
@ -1705,7 +1695,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(is_bare_key_character(*cp));
TOML_ASSERT_ASSUME(is_bare_key_character(*cp));
string_buffer.clear();
@ -1727,7 +1717,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(is_match(*cp, U't', U'f', U'T', U'F'));
TOML_ASSERT_ASSUME(is_match(*cp, U't', U'f', U'T', U'F'));
push_parse_scope("boolean"sv);
start_recording(true);
@ -1752,7 +1742,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(is_match(*cp, U'i', U'n', U'I', U'N', U'+', U'-'));
TOML_ASSERT_ASSUME(is_match(*cp, U'i', U'n', U'I', U'N', U'+', U'-'));
push_parse_scope("floating-point"sv);
start_recording(true);
@ -1782,7 +1772,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(is_match(*cp, U'+', U'-', U'.') || is_decimal_digit(*cp));
TOML_ASSERT_ASSUME(is_match(*cp, U'+', U'-', U'.') || is_decimal_digit(*cp));
push_parse_scope("floating-point"sv);
// sign
@ -1938,7 +1928,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(is_match(*cp, U'0', U'+', U'-'));
TOML_ASSERT_ASSUME(is_match(*cp, U'0', U'+', U'-'));
push_parse_scope("hexadecimal floating-point"sv);
#if TOML_LANG_UNRELEASED // toml/issues/562 (hexfloats)
@ -2235,7 +2225,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(is_decimal_digit(*cp));
TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
push_parse_scope("date"sv);
// "YYYY"
@ -2290,7 +2280,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(is_decimal_digit(*cp));
TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
push_parse_scope("time"sv);
static constexpr size_t max_digits = 9;
@ -2382,7 +2372,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(is_decimal_digit(*cp));
TOML_ASSERT_ASSUME(is_decimal_digit(*cp));
push_parse_scope("date-time"sv);
// "YYYY-MM-DD"
@ -2459,8 +2449,8 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(!is_control_character(*cp));
assert_or_assume(*cp != U'_');
TOML_ASSERT_ASSUME(!is_control_character(*cp));
TOML_ASSERT_ASSUME(*cp != U'_');
switch (cp->value)
{
@ -2501,7 +2491,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(!is_value_terminator(*cp));
TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
push_parse_scope("value"sv);
const parse_depth_counter depth_counter{ nested_values };
@ -2525,8 +2515,8 @@ TOML_IMPL_NAMESPACE_START
do
{
assert_or_assume(!is_control_character(*cp));
assert_or_assume(*cp != U'_');
TOML_ASSERT_ASSUME(!is_control_character(*cp));
TOML_ASSERT_ASSUME(*cp != U'_');
// detect the value type and parse accordingly,
// starting with value types that can be detected
@ -2584,7 +2574,7 @@ TOML_IMPL_NAMESPACE_START
{
if (is_eof())
return;
assert_or_assume(!is_value_terminator(*cp));
TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
do
{
@ -2596,7 +2586,7 @@ TOML_IMPL_NAMESPACE_START
add_trait(has_digits);
else if (is_ascii_letter(c))
{
assert_or_assume((c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z'));
TOML_ASSERT_ASSUME((c >= U'a' && c <= U'z') || (c >= U'A' && c <= U'Z'));
switch (static_cast<char32_t>(c | 32u))
{
case U'b':
@ -2633,7 +2623,7 @@ TOML_IMPL_NAMESPACE_START
}
else if (c <= U':')
{
assert_or_assume(c < U'0' || c > U'9');
TOML_ASSERT_ASSUME(c < U'0' || c > U'9');
switch (c)
{
case U'+': add_trait(has_plus); break;
@ -2715,7 +2705,7 @@ TOML_IMPL_NAMESPACE_START
// now things that can be identified from two or more characters
return_if_error({});
assert_or_assume(char_count >= 2u);
TOML_ASSERT_ASSUME(char_count >= 2u);
// do some 'fuzzy matching' where there's no ambiguity, since that allows the specific
// typed parse functions to take over and show better diagnostics if there's an issue
@ -2978,7 +2968,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(is_bare_key_character(*cp) || is_string_delimiter(*cp));
TOML_ASSERT_ASSUME(is_bare_key_character(*cp) || is_string_delimiter(*cp));
push_parse_scope("key"sv);
key_buffer.clear();
@ -3065,7 +3055,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(*cp == U'[');
TOML_ASSERT_ASSUME(*cp == U'[');
push_parse_scope("table header"sv);
const source_position header_begin_pos = cp->position;
@ -3267,7 +3257,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(is_string_delimiter(*cp) || is_bare_key_character(*cp));
TOML_ASSERT_ASSUME(is_string_delimiter(*cp) || is_bare_key_character(*cp));
push_parse_scope("key-value pair"sv);
// read the key into the key buffer
@ -3425,7 +3415,7 @@ TOML_IMPL_NAMESPACE_START
auto end = nde.source_.end;
for (auto&& [k, v] : tbl)
{
(void)k;
TOML_UNUSED(k);
update_region_ends(v);
if (end < v.source_.end)
end = v.source_.end;
@ -3493,7 +3483,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(*cp == U'[');
TOML_ASSERT_ASSUME(*cp == U'[');
push_parse_scope("array"sv);
// skip opening '['
@ -3558,7 +3548,7 @@ TOML_IMPL_NAMESPACE_START
{
return_if_error({});
assert_not_eof();
assert_or_assume(*cp == U'{');
TOML_ASSERT_ASSUME(*cp == U'{');
push_parse_scope("inline table"sv);
// skip opening '{'
@ -3645,11 +3635,8 @@ TOML_IMPL_NAMESPACE_END;
#undef TOML_RETURNS_BY_THROWING
#undef advance_and_return_if_error
#undef advance_and_return_if_error_or_eof
#undef assert_or_assume
#undef assert_not_eof
#undef assert_not_error
#undef bdigit_msk
#undef bzero_msk
#undef is_eof
#undef is_error
#undef parse_error_break
@ -3663,7 +3650,6 @@ TOML_IMPL_NAMESPACE_END;
#undef set_error_and_return
#undef set_error_and_return_default
#undef set_error_and_return_if_eof
#undef signs_msk
#undef utf8_buffered_reader_error_check
#undef utf8_reader_error
#undef utf8_reader_error_check

View File

@ -101,7 +101,7 @@
#define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS
#define TOML_ASSUME(cond) __builtin_assume(cond)
#define TOML_ASSUME(expr) __builtin_assume(expr)
#define TOML_UNREACHABLE __builtin_unreachable()
#define TOML_ATTR(...) __attribute__((__VA_ARGS__))
#if defined(_MSC_VER) // msvc compat mode
@ -235,7 +235,7 @@
#define TOML_ALWAYS_INLINE __forceinline
#endif
#define TOML_NEVER_INLINE __declspec(noinline)
#define TOML_ASSUME(cond) __assume(cond)
#define TOML_ASSUME(expr) __assume(expr)
#define TOML_UNREACHABLE __assume(0)
#define TOML_ABSTRACT_BASE __declspec(novtable)
#define TOML_EMPTY_BASES __declspec(empty_bases)
@ -588,11 +588,11 @@
#endif
#ifndef TOML_ASSUME
#define TOML_ASSUME(cond) (void)0
#define TOML_ASSUME(expr) static_assert(true)
#endif
#ifndef TOML_UNREACHABLE
#define TOML_UNREACHABLE TOML_ASSERT(false)
#define TOML_UNREACHABLE TOML_ASSUME(false)
#endif
#ifndef TOML_FLAGS_ENUM
@ -743,6 +743,8 @@
#define TOML_CONST_INLINE_GETTER TOML_NODISCARD TOML_ALWAYS_INLINE
#endif
#define TOML_UNUSED(...) static_cast<void>(__VA_ARGS__)
//======================================================================================================================
// SFINAE
//======================================================================================================================
@ -871,18 +873,23 @@
//# ASSERT
//#====================================================================================================================
TOML_DISABLE_WARNINGS;
#ifndef TOML_ASSERT
#ifdef NDEBUG
#define TOML_ASSERT(expr) static_cast<void>(0)
#else
#ifndef assert
#include <cassert>
#endif
#define TOML_ASSERT(expr) assert(expr)
#endif
#ifdef NDEBUG
#undef TOML_ASSERT
#define TOML_ASSERT(expr) static_assert(true)
#endif
#ifndef TOML_ASSERT
#ifndef assert
TOML_DISABLE_WARNINGS;
#include <cassert>
TOML_ENABLE_WARNINGS;
#endif
#define TOML_ASSERT(expr) assert(expr)
#endif
#ifdef NDEBUG
#define TOML_ASSERT_ASSUME(expr) TOML_ASSUME(expr)
#else
#define TOML_ASSERT_ASSUME(expr) TOML_ASSERT(expr)
#endif
TOML_ENABLE_WARNINGS;
//#====================================================================================================================
//# STATIC ASSERT MESSAGE FORMATTING

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,17 @@ TOML_NAMESPACE_START
TOML_EXTERNAL_LINKAGE
table::table(const impl::table_init_pair* b, const impl::table_init_pair* e)
{
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
TOML_ASSERT_ASSUME(b);
TOML_ASSERT_ASSUME(e);
TOML_ASSERT_ASSUME(b <= e);
if TOML_UNLIKELY(b == e)
return;
for (; b != e; b++)
{
if (!b->value) // empty node_views
@ -27,10 +38,6 @@ TOML_NAMESPACE_START
map_.insert_or_assign(std::move(b->key), std::move(b->value));
}
#if TOML_LIFETIME_HOOKS
TOML_TABLE_CREATED;
#endif
}
TOML_EXTERNAL_LINKAGE
@ -94,7 +101,7 @@ TOML_NAMESPACE_START
for (auto&& [k, v] : map_)
{
static_cast<void>(k);
TOML_UNUSED(k);
if (v->type() != ntype)
return false;
}
@ -114,7 +121,7 @@ TOML_NAMESPACE_START
ntype = map_.cbegin()->second->type();
for (const auto& [k, v] : map_)
{
static_cast<void>(k);
TOML_UNUSED(k);
if (v->type() != ntype)
{
first_nonmatch = v.get();
@ -158,7 +165,7 @@ TOML_NAMESPACE_START
#else
TOML_ASSERT(n && "key not found in table!");
TOML_ASSERT_ASSUME(n && "key not found in table!");
#endif
@ -166,43 +173,44 @@ TOML_NAMESPACE_START
}
TOML_EXTERNAL_LINKAGE
bool table::equal(const table& lhs, const table& rhs) noexcept
table::map_iterator table::get_lower_bound(std::string_view key) noexcept
{
if (&lhs == &rhs)
return true;
if (lhs.map_.size() != rhs.map_.size())
return false;
return map_.lower_bound(key);
}
for (auto l = lhs.map_.begin(), r = rhs.map_.begin(), e = lhs.map_.end(); l != e; l++, r++)
TOML_EXTERNAL_LINKAGE
table::iterator table::find(std::string_view key) noexcept
{
return map_.find(key);
}
TOML_EXTERNAL_LINKAGE
table::const_iterator table::find(std::string_view key) const noexcept
{
return map_.find(key);
}
TOML_EXTERNAL_LINKAGE
table::map_iterator table::erase(const_map_iterator pos) noexcept
{
return map_.erase(pos);
}
TOML_EXTERNAL_LINKAGE
table::map_iterator table::erase(const_map_iterator begin, const_map_iterator end) noexcept
{
return map_.erase(begin, end);
}
TOML_EXTERNAL_LINKAGE
size_t table::erase(std::string_view key) noexcept
{
if (auto it = map_.find(key); it != map_.end())
{
if (l->first != r->first)
return false;
const auto lhs_type = l->second->type();
const node& rhs_ = *r->second;
const auto rhs_type = rhs_.type();
if (lhs_type != rhs_type)
return false;
const bool equal = l->second->visit(
[&](const auto& lhs_) noexcept
{ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
if (!equal)
return false;
map_.erase(it);
return size_t{ 1 };
}
return true;
}
TOML_EXTERNAL_LINKAGE
table::iterator table::lower_bound(std::string_view key) noexcept
{
return iterator{ map_.lower_bound(key) };
}
TOML_EXTERNAL_LINKAGE
table::const_iterator table::lower_bound(std::string_view key) const noexcept
{
return const_iterator{ map_.lower_bound(key) };
return size_t{};
}
TOML_EXTERNAL_LINKAGE
@ -240,6 +248,46 @@ TOML_NAMESPACE_START
return *this;
}
TOML_EXTERNAL_LINKAGE
void table::clear() noexcept
{
map_.clear();
}
TOML_EXTERNAL_LINKAGE
table::map_iterator table::insert_with_hint(const_iterator hint, key && k, impl::node_ptr && v)
{
return map_.emplace_hint(hint, std::move(k), std::move(v));
}
TOML_EXTERNAL_LINKAGE
bool table::equal(const table& lhs, const table& rhs) noexcept
{
if (&lhs == &rhs)
return true;
if (lhs.map_.size() != rhs.map_.size())
return false;
for (auto l = lhs.map_.begin(), r = rhs.map_.begin(), e = lhs.map_.end(); l != e; l++, r++)
{
if (l->first != r->first)
return false;
const auto lhs_type = l->second->type();
const node& rhs_ = *r->second;
const auto rhs_type = rhs_.type();
if (lhs_type != rhs_type)
return false;
const bool equal = l->second->visit(
[&](const auto& lhs_) noexcept
{ return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
if (!equal)
return false;
}
return true;
}
}
TOML_NAMESPACE_END;

View File

@ -288,7 +288,7 @@ TOML_NAMESPACE_START
size_t child_table_array_count{};
for (auto&& [child_k, child_v] : child_tbl)
{
(void)child_k;
TOML_UNUSED(child_k);
const auto child_type = child_v.type();
TOML_ASSUME(child_type != node_type::none);
switch (child_type)

View File

@ -938,7 +938,7 @@ TOML_IMPL_NAMESPACE_START
constexpr void operator()(uint8_t byte) noexcept
{
TOML_ASSERT(!error());
TOML_ASSERT_ASSUME(!error());
const auto type = state_table[byte];

View File

@ -82,7 +82,10 @@ TOML_IMPL_NAMESPACE_START
TOML_NODISCARD
static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>)
{
return T(static_cast<Args&&>(args)...);
if constexpr (std::is_aggregate_v<T>)
return T{ static_cast<Args&&>(args)... };
else
return T(static_cast<Args&&>(args)...);
}
};
@ -106,18 +109,25 @@ TOML_IMPL_NAMESPACE_START
TOML_NODISCARD
static std::string make(T&& arg) noexcept
{
using arg_type = std::decay_t<T>;
#if TOML_HAS_CHAR8
if constexpr (is_one_of<std::decay_t<T>, char8_t*, const char8_t*>)
if constexpr (is_one_of<arg_type, char8_t*, const char8_t*>)
{
return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg)));
else if constexpr (is_one_of<remove_cvref<T>, std::u8string, std::u8string_view>)
}
if constexpr (is_one_of<arg_type, std::u8string, std::u8string_view>)
{
return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg.data())),
arg.length());
#endif // TOML_HAS_CHAR8
}
#endif
#if TOML_ENABLE_WINDOWS_COMPAT
if constexpr (is_wide_string<T>)
if constexpr (is_wide_string<arg_type>)
{
return narrow(static_cast<T&&>(arg));
#endif // TOML_ENABLE_WINDOWS_COMPAT
}
#endif
}
};
@ -266,6 +276,18 @@ TOML_NAMESPACE_START
#endif
}
/// \brief Copy constructor with flags override.
TOML_NODISCARD_CTOR
value(const value& other, value_flags flags) noexcept //
: node(other),
val_{ other.val_ },
flags_{ flags == preserve_source_value_flags ? other.flags_ : flags }
{
#if TOML_LIFETIME_HOOKS
TOML_VALUE_CREATED;
#endif
}
/// \brief Move constructor.
TOML_NODISCARD_CTOR
value(value&& other) noexcept //
@ -278,6 +300,18 @@ TOML_NAMESPACE_START
#endif
}
/// \brief Move constructor with flags override.
TOML_NODISCARD_CTOR
value(value&& other, value_flags flags) noexcept //
: node(std::move(other)),
val_{ std::move(other.val_) },
flags_{ flags == preserve_source_value_flags ? other.flags_ : flags }
{
#if TOML_LIFETIME_HOOKS
TOML_VALUE_CREATED;
#endif
}
/// \brief Copy-assignment operator.
value& operator=(const value& rhs) noexcept
{
@ -614,6 +648,13 @@ TOML_NAMESPACE_START
return val_;
}
/// \brief Returns a reference to the underlying value (const rvalue overload).
TOML_PURE_INLINE_GETTER
const value_type&& get() const&& noexcept
{
return static_cast<const value_type&&>(val_);
}
/// \brief Returns a reference to the underlying value.
TOML_PURE_INLINE_GETTER
value_type& operator*() & noexcept
@ -635,6 +676,13 @@ TOML_NAMESPACE_START
return val_;
}
/// \brief Returns a reference to the underlying value (const rvalue overload).
TOML_PURE_INLINE_GETTER
const value_type&& operator*() const&& noexcept
{
return static_cast<const value_type&&>(val_);
}
/// \brief Returns a reference to the underlying value.
TOML_PURE_INLINE_GETTER
explicit operator value_type&() & noexcept
@ -656,6 +704,13 @@ TOML_NAMESPACE_START
return val_;
}
/// \brief Returns a reference to the underlying value (const rvalue overload).
TOML_PURE_INLINE_GETTER
explicit operator const value_type&&() && noexcept
{
return static_cast<const value_type&&>(val_);
}
/// \brief Returns a pointer to the underlying value.
///
/// \availability This operator is only available when #value_type is a class/struct.

View File

@ -77,6 +77,7 @@ TOML_POP_WARNINGS;
#undef TOML_ANON_NAMESPACE_START
#undef TOML_ARM
#undef TOML_ASSERT
#undef TOML_ASSERT_ASSUME
#undef TOML_ASSUME
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
#undef TOML_ATTR
@ -172,6 +173,7 @@ TOML_POP_WARNINGS;
#undef TOML_UINT128
#undef TOML_UNLIKELY
#undef TOML_UNREACHABLE
#undef TOML_UNUSED
#endif
#endif // TOMLPLUSPLUS_H

View File

@ -303,25 +303,115 @@ namespace toml
CHECK_INSERTED_AS(TOML_FLOAT16, value<double>);
#endif
static_assert(is_same_v<decltype(declval<node&>().ref<double>()), double&>);
static_assert(is_same_v<decltype(declval<node&&>().ref<double>()), double&&>);
static_assert(is_same_v<decltype(declval<const node&>().ref<double>()), const double&>);
static_assert(is_same_v<decltype(declval<node&>().ref<value<double>>()), double&>);
static_assert(is_same_v<decltype(declval<node&&>().ref<value<double>>()), double&&>);
static_assert(is_same_v<decltype(declval<const node&>().ref<value<double>>()), const double&>);
static_assert(is_same_v<decltype(declval<node&>().ref<table>()), table&>);
static_assert(is_same_v<decltype(declval<node&&>().ref<table>()), table&&>);
static_assert(is_same_v<decltype(declval<const node&>().ref<table>()), const table&>);
static_assert(is_same_v<decltype(declval<node&>().ref<array>()), array&>);
static_assert(is_same_v<decltype(declval<node&&>().ref<array>()), array&&>);
static_assert(is_same_v<decltype(declval<const node&>().ref<array>()), const array&>);
#define CHECK_NODE_REF_TYPE(T) \
static_assert(is_same_v<decltype(declval<node&>().ref<T>()), T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const T>()), const T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<volatile T>()), volatile T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<T&>()), T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<volatile T&>()), volatile T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<T&&>()), T&&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<volatile T&&>()), volatile T&&>); \
static_assert(is_same_v<decltype(declval<node&>().ref<const volatile T&&>()), const volatile T&&>); \
\
static_assert(is_same_v<decltype(declval<node&&>().ref<T>()), T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const T>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<volatile T>()), volatile T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const volatile T>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<T&>()), T&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<volatile T&>()), volatile T&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<T&&>()), T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<volatile T&&>()), volatile T&&>); \
static_assert(is_same_v<decltype(declval<node&&>().ref<const volatile T&&>()), const volatile T&&>); \
\
static_assert(is_same_v<decltype(declval<const node&>().ref<T>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const T>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<volatile T&&>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<const node&>().ref<const volatile T&&>()), const volatile T&&>); \
\
static_assert(is_same_v<decltype(declval<const node&&>().ref<T>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const T>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<volatile T>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const volatile T>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<volatile T&&>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<const node&&>().ref<const volatile T&&>()), const volatile T&&>)
CHECK_NODE_REF_TYPE(table);
CHECK_NODE_REF_TYPE(array);
CHECK_NODE_REF_TYPE(std::string);
CHECK_NODE_REF_TYPE(int64_t);
CHECK_NODE_REF_TYPE(double);
CHECK_NODE_REF_TYPE(bool);
CHECK_NODE_REF_TYPE(date);
CHECK_NODE_REF_TYPE(time);
CHECK_NODE_REF_TYPE(date_time);
#define CHECK_NODE_VIEW_REF_TYPE(T) \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<T>()), T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const T>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<volatile T>()), volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<T&>()), T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<volatile T&>()), volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<T&&>()), T&&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<volatile T&&>()), volatile T&&>); \
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<const volatile T&&>()), const volatile T&&>)
CHECK_NODE_VIEW_REF_TYPE(table);
CHECK_NODE_VIEW_REF_TYPE(array);
CHECK_NODE_VIEW_REF_TYPE(std::string);
CHECK_NODE_VIEW_REF_TYPE(int64_t);
CHECK_NODE_VIEW_REF_TYPE(double);
CHECK_NODE_VIEW_REF_TYPE(bool);
CHECK_NODE_VIEW_REF_TYPE(date);
CHECK_NODE_VIEW_REF_TYPE(time);
CHECK_NODE_VIEW_REF_TYPE(date_time);
#define CHECK_CONST_NODE_VIEW_REF_TYPE(T) \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<T>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const T>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const volatile T>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const T&>()), const T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const volatile T&>()), const volatile T&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const T&&>()), const T&&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<volatile T&&>()), const volatile T&&>); \
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<const volatile T&&>()), const volatile T&&>)
CHECK_CONST_NODE_VIEW_REF_TYPE(table);
CHECK_CONST_NODE_VIEW_REF_TYPE(array);
CHECK_CONST_NODE_VIEW_REF_TYPE(std::string);
CHECK_CONST_NODE_VIEW_REF_TYPE(int64_t);
CHECK_CONST_NODE_VIEW_REF_TYPE(double);
CHECK_CONST_NODE_VIEW_REF_TYPE(bool);
CHECK_CONST_NODE_VIEW_REF_TYPE(date);
CHECK_CONST_NODE_VIEW_REF_TYPE(time);
CHECK_CONST_NODE_VIEW_REF_TYPE(date_time);
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<double>()), double&>);
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<double>()), const double&>);
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<value<double>>()), double&>);
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<value<double>>()), const double&>);
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<table>()), table&>);
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<table>()), const table&>);
static_assert(is_same_v<decltype(declval<node_view<node>>().ref<array>()), array&>);
static_assert(is_same_v<decltype(declval<node_view<const node>>().ref<array>()), const array&>);
}

1496
toml.hpp

File diff suppressed because it is too large Load Diff