moved is_homogenous to toml::node

also:
- added is_homogenous overload for identifying failure-causing element (to assist with implementing #45)
- added table::is_homogenous
- added value::is_homogenous (just for generic code's sake)
This commit is contained in:
Mark Gillard 2020-08-02 17:02:10 +03:00
parent b024ee6dc2
commit f6450f6ff9
18 changed files with 920 additions and 268 deletions

View File

@ -123,6 +123,11 @@
#undef TOML_SA_NEWLINE
#undef TOML_SA_NODE_TYPE_LIST
#undef TOML_SA_UNWRAPPED_NODE_TYPE_LIST
#undef TOML_SA_VALUE_EXACT_FUNC_MESSAGE
#undef TOML_SA_VALUE_FUNC_MESSAGE
#undef TOML_SA_VALUE_MESSAGE_CONST_CHAR8
#undef TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
#undef TOML_SA_VALUE_MESSAGE_WSTRING
#undef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
#undef TOML_TRIVIAL_ABI
#undef TOML_UINT128

View File

@ -403,69 +403,17 @@ TOML_NAMESPACE_START
}
/// \brief Always returns node_type::array for array nodes.
[[nodiscard]] node_type type() const noexcept override;
/// \brief Always returns `false` for array nodes.
[[nodiscard]] bool is_table() const noexcept override;
/// \brief Always returns `true` for array nodes.
[[nodiscard]] bool is_array() const noexcept override;
/// \brief Always returns `false` for array nodes.
[[nodiscard]] bool is_value() const noexcept override;
[[nodiscard]] array* as_array() noexcept override;
[[nodiscard]] const array* as_array() const noexcept override;
[[nodiscard]] bool is_array_of_tables() const noexcept override;
/// \brief Checks if the array contains elements of only one type.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << "homogenous: "sv << arr.is_homogeneous(toml::node_type::none) << "\n";
/// std::cout << "all floats: "sv << arr.is_homogeneous(toml::node_type::floating_point) << "\n";
/// std::cout << "all arrays: "sv << arr.is_homogeneous(toml::node_type::array) << "\n";
/// std::cout << "all ints: "sv << arr.is_homogeneous(toml::node_type::integer) << "\n";
///
/// \ecpp
///
/// \out
/// homogeneous: true
/// all floats: false
/// all arrays: false
/// all ints: true
/// \eout
///
/// \param type A TOML node type. <br>
/// <strong><em>toml::node_type::none: </em></strong> "is every node the same type?" <br>
/// <strong><em>Anything else:</em></strong> "is every node one of these?"
///
/// \returns True if the array was homogeneous.
///
/// \remarks Always returns `false` for empty arrays.
[[nodiscard]] bool is_homogeneous(node_type type) const noexcept;
/// \brief Checks if the array contains elements of only one type.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << "homogenous: "sv << arr.is_homogeneous() << "\n";
/// std::cout << "all doubles: "sv << arr.is_homogeneous<double>() << "\n";
/// std::cout << "all arrays: "sv << arr.is_homogeneous<toml::array>() << "\n";
/// std::cout << "all integers: "sv << arr.is_homogeneous<int64_t>() << "\n";
///
/// \ecpp
///
/// \out
/// homogeneous: true
/// all doubles: false
/// all arrays: false
/// all integers: true
/// \eout
///
/// \tparam ElemType A TOML node or value type. <br>
/// <strong><em>Left as `void`:</em></strong> "is every node the same type?" <br>
/// <strong><em>Explicitly specified:</em></strong> "is every node a T?"
///
/// \returns True if the array was homogeneous.
///
/// \remarks Always returns `false` for empty arrays.
[[nodiscard]] bool is_homogeneous(node_type ntype) const noexcept override;
[[nodiscard]] bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept override;
[[nodiscard]] bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept override;
template <typename ElemType = void>
[[nodiscard]]
bool is_homogeneous() const noexcept
@ -477,16 +425,9 @@ TOML_NAMESPACE_START
"The template type argument of array::is_homogeneous() must be void or one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
if constexpr (std::is_void_v<type>)
return is_homogeneous(node_type::none);
else
return is_homogeneous(impl::node_type_of<type>);
return is_homogeneous(impl::node_type_of<type>);
}
/// \brief Returns true if this array contains only tables.
[[nodiscard]] bool is_array_of_tables() const noexcept override;
/// \brief Gets a reference to the element at a specific index.
[[nodiscard]] node& operator[] (size_t index) noexcept;
/// \brief Gets a reference to the element at a specific index.

View File

@ -113,6 +113,59 @@ TOML_NAMESPACE_START
#undef TOML_MEMBER_ATTR
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype) const noexcept
{
if (elements.empty())
return false;
if (ntype == node_type::none)
ntype = elements[0]->type();
for (const auto& val : elements)
if (val->type() != ntype)
return false;
return true;
}
namespace impl
{
template <typename T, typename U>
TOML_INTERNAL_LINKAGE
bool array_is_homogeneous(T& elements, node_type ntype, U& first_nonmatch) noexcept
{
if (elements.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = elements[0]->type();
for (const auto& val : elements)
{
if (val->type() != ntype)
{
first_nonmatch = val.get();
return false;
}
}
return true;
}
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept
{
return impl::array_is_homogeneous(elements, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept
{
return impl::array_is_homogeneous(elements, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
void array::truncate(size_t new_size)
{
@ -263,22 +316,6 @@ TOML_NAMESPACE_START
return *this;
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type type) const noexcept
{
if (elements.empty())
return false;
if (type == node_type::none)
type = elements[0]->type();
for (const auto& val : elements)
if (val->type() != type)
return false;
return true;
}
TOML_EXTERNAL_LINKAGE
bool array::is_array_of_tables() const noexcept
{

View File

@ -549,6 +549,7 @@ TOML_IMPL_NAMESPACE_START
template <typename T> struct node_type_getter { static constexpr auto value = value_traits<T>::type; };
template <> struct node_type_getter<table> { static constexpr auto value = node_type::table; };
template <> struct node_type_getter<array> { static constexpr auto value = node_type::array; };
template <> struct node_type_getter<void> { static constexpr auto value = node_type::none; };
template <typename T>
inline constexpr node_type node_type_of = node_type_getter<unwrap_node<remove_cvref_t<T>>>::value;
@ -611,7 +612,7 @@ TOML_IMPL_NAMESPACE_START
[[nodiscard]]
TOML_ATTR(const)
TOML_ALWAYS_INLINE
constexpr std::underlying_type_t<T> unbox_enum(T val) noexcept
constexpr std::underlying_type_t<T> unwrap_enum(T val) noexcept
{
return static_cast<std::underlying_type_t<T>>(val);
}

View File

@ -34,7 +34,7 @@ TOML_NAMESPACE_START
TOML_ATTR(flatten)
constexpr format_flags operator & (format_flags lhs, format_flags rhs) noexcept
{
return static_cast<format_flags>(impl::unbox_enum(lhs) & impl::unbox_enum(rhs));
return static_cast<format_flags>(impl::unwrap_enum(lhs) & impl::unwrap_enum(rhs));
}
[[nodiscard]]
@ -43,7 +43,7 @@ TOML_NAMESPACE_START
TOML_ATTR(flatten)
constexpr format_flags operator | (format_flags lhs, format_flags rhs) noexcept
{
return static_cast<format_flags>( impl::unbox_enum(lhs) | impl::unbox_enum(rhs) );
return static_cast<format_flags>( impl::unwrap_enum(lhs) | impl::unwrap_enum(rhs) );
}
}
TOML_NAMESPACE_END

View File

@ -195,6 +195,104 @@ TOML_NAMESPACE_START
[[nodiscard]] virtual const toml::value<time>* as_time() const noexcept;
[[nodiscard]] virtual const toml::value<date_time>* as_date_time() const noexcept;
/// \brief Checks if a node contains values/elements of only one type.
///
/// \detail \cpp
/// auto cfg = toml::parse("arr = [ 1, 2, 3, 4.0 ]");
/// toml::array& arr = *cfg["arr"].as_array();
///
/// toml::node* nonmatch{};
/// if (arr.is_homogeneous(toml::node_type::integer, nonmatch))
/// std::cout << "array was homogeneous"sv << "\n";
/// else
/// std::cout << "array was not homogeneous!\n"
/// << "first non-match was a "sv << nonmatch->type() << " at " << nonmatch->source() << "\n";
/// \ecpp
///
/// \out
/// array was not homogeneous!
/// first non-match was a floating-point at line 1, column 18
/// \eout
///
/// \param ntype A TOML node type. <br>
/// <strong><em>toml::node_type::none: </em></strong> "is every element the same type?" <br>
/// <strong><em>Anything else:</em></strong> "is every element one of these?"
/// \param first_nonmatch Reference to a pointer in which the address of the first non-matching element
/// will be stored if the return value is false.
///
/// \returns True if the node was homogeneous.
///
/// \remarks Always returns `false` for empty tables and arrays.
[[nodiscard]] virtual bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept = 0;
/// \brief Checks if a node contains values/elements of only one type (const overload).
[[nodiscard]] virtual bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept = 0;
/// \brief Checks if the node contains values/elements of only one type.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << "homogenous: "sv << arr.is_homogeneous(toml::node_type::none) << "\n";
/// std::cout << "all floats: "sv << arr.is_homogeneous(toml::node_type::floating_point) << "\n";
/// std::cout << "all arrays: "sv << arr.is_homogeneous(toml::node_type::array) << "\n";
/// std::cout << "all ints: "sv << arr.is_homogeneous(toml::node_type::integer) << "\n";
///
/// \ecpp
///
/// \out
/// homogeneous: true
/// all floats: false
/// all arrays: false
/// all ints: true
/// \eout
///
/// \param ntype A TOML node type. <br>
/// <strong><em>toml::node_type::none: </em></strong> "is every element the same type?" <br>
/// <strong><em>Anything else:</em></strong> "is every element one of these?"
///
/// \returns True if the node was homogeneous.
///
/// \remarks Always returns `false` for empty tables and arrays.
[[nodiscard]] virtual bool is_homogeneous(node_type ntype) const noexcept = 0;
/// \brief Checks if the node contains values/elements of only one type.
///
/// \detail \cpp
/// auto arr = toml::array{ 1, 2, 3 };
/// std::cout << "homogenous: "sv << arr.is_homogeneous() << "\n";
/// std::cout << "all doubles: "sv << arr.is_homogeneous<double>() << "\n";
/// std::cout << "all arrays: "sv << arr.is_homogeneous<toml::array>() << "\n";
/// std::cout << "all integers: "sv << arr.is_homogeneous<int64_t>() << "\n";
///
/// \ecpp
///
/// \out
/// homogeneous: true
/// all floats: false
/// all arrays: false
/// all ints: true
/// \eout
///
/// \tparam ElemType A TOML node or value type. <br>
/// <strong><em>Left as `void`:</em></strong> "is every element the same type?" <br>
/// <strong><em>Explicitly specified:</em></strong> "is every element a T?"
///
/// \returns True if the node was homogeneous.
///
/// \remarks Always returns `false` for empty tables and arrays.
template <typename ElemType = void>
[[nodiscard]]
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>);
}
private:
@ -377,6 +475,14 @@ TOML_NAMESPACE_START
[[nodiscard]]
auto value_or(T&& default_value) const noexcept;
//template <typename T>
//[[nodiscard]]
//std::vector<T> select_exact() const noexcept;
//template <typename T>
//[[nodiscard]]
//std::vector<T> select() const noexcept;
/// \brief Gets a pointer to the node as a more specific node type.
///
/// \details \cpp

View File

@ -179,6 +179,110 @@ TOML_NAMESPACE_START
/// \brief Returns a pointer to the viewed node as a toml::value<date_time>, if it is one.
[[nodiscard]] auto as_date_time() const noexcept { return as<date_time>(); }
/// \brief Checks if the viewed node contains values/elements of only one type.
///
/// \detail \cpp
/// auto cfg = toml::parse("arr = [ 1, 2, 3, 4.0 ]");
///
/// toml::node* nonmatch{};
/// if (cfg["arr"].is_homogeneous(toml::node_type::integer, nonmatch))
/// std::cout << "array was homogeneous"sv << "\n";
/// else
/// std::cout << "array was not homogeneous!\n"
/// << "first non-match was a "sv << nonmatch->type() << " at " << nonmatch->source() << "\n";
/// \ecpp
///
/// \out
/// array was not homogeneous!
/// first non-match was a floating-point at line 1, column 18
/// \eout
///
/// \param ntype A TOML node type. <br>
/// <strong><em>toml::node_type::none: </em></strong> "is every element the same type?" <br>
/// <strong><em>Anything else:</em></strong> "is every element one of these?"
/// \param first_nonmatch Reference to a pointer in which the address of the first non-matching element
/// will be stored if the return value is false.
///
/// \returns True if the viewed node was homogeneous.
///
/// \remarks Always returns `false` if the view does not reference a node, or if the viewed node is
/// an empty table or array.
[[nodiscard]]
bool is_homogeneous(node_type ntype, viewed_type*& first_nonmatch) const noexcept
{
if (!node_)
{
first_nonmatch = {};
return false;
}
return node_->is_homogeneous(ntype, first_nonmatch);
}
/// \brief Checks if the viewed node contains values/elements of only one type.
///
/// \detail \cpp
/// auto cfg = toml::parse("arr = [ 1, 2, 3 ]");
/// std::cout << "homogenous: "sv << cfg["arr"].is_homogeneous(toml::node_type::none) << "\n";
/// std::cout << "all floats: "sv << cfg["arr"].is_homogeneous(toml::node_type::floating_point) << "\n";
/// std::cout << "all arrays: "sv << cfg["arr"].is_homogeneous(toml::node_type::array) << "\n";
/// std::cout << "all ints: "sv << cfg["arr"].is_homogeneous(toml::node_type::integer) << "\n";
///
/// \ecpp
///
/// \out
/// homogeneous: true
/// all floats: false
/// all arrays: false
/// all ints: true
/// \eout
///
/// \param ntype A TOML node type. <br>
/// <strong><em>toml::node_type::none: </em></strong> "is every element the same type?" <br>
/// <strong><em>Anything else:</em></strong> "is every element one of these?"
///
/// \returns True if the viewed node was homogeneous.
///
/// \remarks Always returns `false` if the view does not reference a node, or if the viewed node is
/// an empty table or array.
[[nodiscard]]
bool is_homogeneous(node_type ntype) const noexcept
{
return node_ ? node_->is_homogeneous(ntype) : false;
}
/// \brief Checks if the viewed node contains values/elements of only one type.
///
/// \detail \cpp
/// auto cfg = toml::parse("arr = [ 1, 2, 3 ]");
/// std::cout << "homogenous: "sv << cfg["arr"].is_homogeneous() << "\n";
/// std::cout << "all doubles: "sv << cfg["arr"].is_homogeneous<double>() << "\n";
/// std::cout << "all arrays: "sv << cfg["arr"].is_homogeneous<toml::array>() << "\n";
/// std::cout << "all integers: "sv << cfg["arr"].is_homogeneous<int64_t>() << "\n";
///
/// \ecpp
///
/// \out
/// homogeneous: true
/// all floats: false
/// all arrays: false
/// all ints: true
/// \eout
///
/// \tparam ElemType A TOML node or value type. <br>
/// <strong><em>Left as `void`:</em></strong> "is every element the same type?" <br>
/// <strong><em>Explicitly specified:</em></strong> "is every element a T?"
///
/// \returns True if the viewed node was homogeneous.
///
/// \remarks Always returns `false` if the view does not reference a node, or if the viewed node is
/// an empty table or array.
template <typename ElemType = void>
[[nodiscard]]
bool is_homogeneous() const noexcept
{
return node_ ? node_->template is_homogeneous<impl::unwrap_node<ElemType>>() : false;
}
/// \brief Gets the value contained by the referenced node.
///
/// \detail This function has 'exact' retrieval semantics; the only return value types allowed are the

View File

@ -83,7 +83,7 @@ TOML_ANON_NAMESPACE_START
{
using namespace ::toml::impl;
return node_type_friendly_names[unbox_enum(val)];
return node_type_friendly_names[unwrap_enum(val)];
}
[[nodiscard]]
@ -2068,7 +2068,7 @@ TOML_IMPL_NAMESPACE_START
// all correct value parses will come out of this list, so doing this as a switch is likely to
// be a better friend to the optimizer on the success path (failure path can be slow but that
// doesn't matter much).
switch (unbox_enum(traits))
switch (unwrap_enum(traits))
{
//=================== binary integers
// 0b10

View File

@ -450,8 +450,6 @@ is no longer necessary.
#define TOML_ARM 0
#endif
//#====================================================================================================================
//# EXTENDED INT AND FLOAT TYPES
//#====================================================================================================================

View File

@ -278,17 +278,30 @@ TOML_NAMESPACE_START
: table{ arr, N }
{}
/// \brief Always returns `node_type::table` for table nodes.
[[nodiscard]] node_type type() const noexcept override;
/// \brief Always returns `true` for table nodes.
[[nodiscard]] bool is_table() const noexcept override;
/// \brief Always returns `false` for table nodes.
[[nodiscard]] bool is_array() const noexcept override;
/// \brief Always returns `false` for table nodes.
[[nodiscard]] bool is_value() const noexcept override;
[[nodiscard]] table* as_table() noexcept override;
[[nodiscard]] const table* as_table() const noexcept override;
[[nodiscard]] bool is_homogeneous(node_type ntype) const noexcept override;
[[nodiscard]] bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept override;
[[nodiscard]] bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept override;
template <typename ElemType = void>
[[nodiscard]]
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 table::is_homogeneous() must be void or one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
return is_homogeneous(impl::node_type_of<type>);
}
/// \brief Returns true if this table is an inline table.
///
/// \remarks Runtime-constructed tables (i.e. those not created during
@ -1083,6 +1096,49 @@ TOML_NAMESPACE_START
template <typename Char>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const table&);
};
#ifndef DOXYGEN
//template <typename T>
//inline std::vector<T> node::select_exact() const noexcept
//{
// using namespace impl;
// static_assert(
// !is_wide_string<T> || TOML_WINDOWS_COMPAT,
// "Retrieving values as wide-character strings with node::select_exact() is only "
// "supported on Windows with TOML_WINDOWS_COMPAT enabled."
// );
// static_assert(
// (is_native<T> || can_represent_native<T>) && !is_cvref<T>,
// TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::select_exact()")
// );
//}
//template <typename T>
//inline std::vector<T> node::select() const noexcept
//{
// using namespace impl;
// static_assert(
// !is_wide_string<T> || TOML_WINDOWS_COMPAT,
// "Retrieving values as wide-character strings with node::select() is only "
// "supported on Windows with TOML_WINDOWS_COMPAT enabled."
// );
// static_assert(
// (is_native<T> || can_represent_native<T> || can_partially_represent_native<T>) && !is_cvref<T>,
// TOML_SA_VALUE_FUNC_MESSAGE("return type of node::select()")
// );
//}
#endif // !DOXYGEN
}
TOML_NAMESPACE_END

View File

@ -104,6 +104,63 @@ TOML_NAMESPACE_START
#undef TOML_MEMBER_ATTR
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype) const noexcept
{
if (map.empty())
return false;
if (ntype == node_type::none)
ntype = map.cbegin()->second->type();
for (const auto& [k, v] : map)
{
(void)k;
if (v->type() != ntype)
return false;
}
return true;
}
namespace impl
{
template <typename T, typename U>
TOML_INTERNAL_LINKAGE
bool table_is_homogeneous(T& map, node_type ntype, U& first_nonmatch) noexcept
{
if (map.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = map.cbegin()->second->type();
for (const auto& [k, v] : map)
{
(void)k;
if (v->type() != ntype)
{
first_nonmatch = v.get();
return false;
}
}
return true;
}
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept
{
return impl::table_is_homogeneous(map, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept
{
return impl::table_is_homogeneous(map, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
node_view<node> table::operator[] (std::string_view key) noexcept
{

View File

@ -7,6 +7,65 @@
#include "toml_node.h"
#include "toml_print_to_stream.h"
#ifndef DOXYGEN
#if TOML_WINDOWS_COMPAT
#define TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP "std::wstring"
#else
#define TOML_SA_VALUE_MESSAGE_WSTRING
#endif
#ifdef __cpp_lib_char8_t
#define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW TOML_SA_LIST_SEP "std::u8string_view"
#define TOML_SA_VALUE_MESSAGE_CONST_CHAR8 TOML_SA_LIST_SEP "const char8_t*"
#else
#define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
#define TOML_SA_VALUE_MESSAGE_CONST_CHAR8
#endif
#define TOML_SA_VALUE_EXACT_FUNC_MESSAGE(type_arg) \
"The " type_arg " must be one of:" \
TOML_SA_LIST_NEW "A native TOML value type" \
TOML_SA_NATIVE_VALUE_TYPE_LIST \
\
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
TOML_SA_LIST_BEG "std::string" \
TOML_SA_VALUE_MESSAGE_WSTRING \
TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
TOML_SA_LIST_END \
\
TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
TOML_SA_LIST_BEG "std::string_view" \
TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
TOML_SA_LIST_SEP "const char*" \
TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
TOML_SA_LIST_END
#define TOML_SA_VALUE_FUNC_MESSAGE(type_arg) \
"The " type_arg " must be one of:" \
TOML_SA_LIST_NEW "A native TOML value type" \
TOML_SA_NATIVE_VALUE_TYPE_LIST \
\
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
TOML_SA_LIST_BEG "std::string" \
TOML_SA_VALUE_MESSAGE_WSTRING \
TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
TOML_SA_LIST_END \
\
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type" \
TOML_SA_LIST_BEG "any other integer type" \
TOML_SA_LIST_SEP "any floating-point type >= 32 bits" \
TOML_SA_LIST_END \
\
TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
TOML_SA_LIST_BEG "std::string_view" \
TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
TOML_SA_LIST_SEP "const char*" \
TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
TOML_SA_LIST_END
#endif // !DOXYGEN
TOML_PUSH_WARNINGS
TOML_DISABLE_ARITHMETIC_WARNINGS
TOML_DISABLE_PADDING_WARNINGS
@ -218,11 +277,8 @@ TOML_NAMESPACE_START
/// - node_type::date_time
[[nodiscard]] node_type type() const noexcept override { return impl::node_type_of<value_type>; }
/// \brief Always returns `false` for value nodes.
[[nodiscard]] bool is_table() const noexcept override { return false; }
/// \brief Always returns `false` for value nodes.
[[nodiscard]] bool is_array() const noexcept override { return false; }
/// \brief Always returns `true` for value nodes.
[[nodiscard]] bool is_value() const noexcept override { return true; }
[[nodiscard]] bool is_string() const noexcept override { return std::is_same_v<value_type, std::string>; }
@ -234,36 +290,66 @@ TOML_NAMESPACE_START
[[nodiscard]] bool is_time() const noexcept override { return std::is_same_v<value_type, time>; }
[[nodiscard]] bool is_date_time() const noexcept override { return std::is_same_v<value_type, date_time>; }
/// \brief Returns a pointer to the value if the data type is a string.
[[nodiscard]] value<std::string>* as_string() noexcept override { return as_value<std::string>(this); }
/// \brief Returns a pointer to the value if the data type is an integer.
[[nodiscard]] value<int64_t>* as_integer() noexcept override { return as_value<int64_t>(this); }
/// \brief Returns a pointer to the value if the data type is a floating-point.
[[nodiscard]] value<double>* as_floating_point() noexcept override { return as_value<double>(this); }
/// \brief Returns a pointer to the value if the data type is boolean.
[[nodiscard]] value<bool>* as_boolean() noexcept override { return as_value<bool>(this); }
/// \brief Returns a pointer to the value if the data type is a date.
[[nodiscard]] value<date>* as_date() noexcept override { return as_value<date>(this); }
/// \brief Returns a pointer to the value if the data type is a time.
[[nodiscard]] value<time>* as_time() noexcept override { return as_value<time>(this); }
/// \brief Returns a pointer to the value if the data type is date-time.
[[nodiscard]] value<date_time>* as_date_time() noexcept override { return as_value<date_time>(this); }
/// \brief Returns a const pointer to the value if the data type is a string.
[[nodiscard]] const value<std::string>* as_string() const noexcept override { return as_value<std::string>(this); }
/// \brief Returns a const pointer to the value if the data type is an integer.
[[nodiscard]] const value<int64_t>* as_integer() const noexcept override { return as_value<int64_t>(this); }
/// \brief Returns a const pointer to the value if the data type is a floating-point.
[[nodiscard]] const value<double>* as_floating_point() const noexcept override { return as_value<double>(this); }
/// \brief Returns a const pointer to the value if the data type is a boolean.
[[nodiscard]] const value<bool>* as_boolean() const noexcept override { return as_value<bool>(this); }
/// \brief Returns a const pointer to the value if the data type is a date.
[[nodiscard]] const value<date>* as_date() const noexcept override { return as_value<date>(this); }
/// \brief Returns a const pointer to the value if the data type is a time.
[[nodiscard]] const value<time>* as_time() const noexcept override { return as_value<time>(this); }
/// \brief Returns a const pointer to the value if the data type is a date-time.
[[nodiscard]] const value<date_time>* as_date_time() const noexcept override { return as_value<date_time>(this); }
[[nodiscard]]
bool is_homogeneous(node_type ntype) const noexcept override
{
return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
}
[[nodiscard]]
bool is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept override
{
if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
{
first_nonmatch = this;
return false;
}
return true;
}
[[nodiscard]]
bool is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept override
{
if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
{
first_nonmatch = this;
return false;
}
return true;
}
template <typename ElemType = void>
[[nodiscard]]
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 value::is_homogeneous() must be void or one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
using type = impl::unwrap_node<ElemType>;
if constexpr (std::is_void_v<type>)
return true;
else
return impl::node_type_of<type> == impl::node_type_of<value_type>;
}
/// \brief Returns a reference to the underlying value.
[[nodiscard]] value_type& get() & noexcept { return val_; }
/// \brief Returns a reference to the underlying value (rvalue overload).
@ -315,8 +401,8 @@ TOML_NAMESPACE_START
using namespace impl;
static constexpr auto pack = [](auto l, auto r) constexpr noexcept
{
return (static_cast<uint64_t>(unbox_enum(l)) << 32)
| static_cast<uint64_t>(unbox_enum(r));
return (static_cast<uint64_t>(unwrap_enum(l)) << 32)
| static_cast<uint64_t>(unwrap_enum(r));
};
switch (pack(impl::fpclassify(lhs.val_), impl::fpclassify(rhs)))
@ -467,6 +553,9 @@ TOML_NAMESPACE_START
value(T) -> value<impl::native_type_of<impl::remove_cvref_t<T>>>;
#ifndef DOXYGEN
TOML_PUSH_WARNINGS
TOML_DISABLE_INIT_WARNINGS
TOML_DISABLE_SWITCH_WARNINGS
#if !TOML_HEADER_ONLY
extern template class TOML_API value<std::string>;
@ -477,10 +566,6 @@ TOML_NAMESPACE_START
extern template class TOML_API value<time>;
extern template class TOML_API value<date_time>;
#endif
TOML_PUSH_WARNINGS
TOML_DISABLE_INIT_WARNINGS
TOML_DISABLE_SWITCH_WARNINGS
template <typename T>
[[nodiscard]]
@ -543,29 +628,7 @@ TOML_NAMESPACE_START
static_assert(
(is_native<T> || can_represent_native<T>) && !is_cvref<T>,
"The return type of node::value_exact() must be one of:"
TOML_SA_LIST_NEW "A native TOML value type"
TOML_SA_NATIVE_VALUE_TYPE_LIST
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
TOML_SA_LIST_BEG "std::string"
#if TOML_WINDOWS_COMPAT
TOML_SA_LIST_SEP "std::wstring"
#endif
TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
TOML_SA_LIST_SEP "any floating-point type >= 64 bits"
TOML_SA_LIST_END
TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage"
TOML_SA_LIST_BEG "std::string_view"
#ifdef __cpp_lib_char8_t
TOML_SA_LIST_SEP "std::u8string_view"
#endif
TOML_SA_LIST_SEP "const char*"
#ifdef __cpp_lib_char8_t
TOML_SA_LIST_SEP "const char8_t*"
#endif
TOML_SA_LIST_END
TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()")
);
// prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
@ -590,34 +653,7 @@ TOML_NAMESPACE_START
);
static_assert(
(is_native<T> || can_represent_native<T> || can_partially_represent_native<T>) && !is_cvref<T>,
"The return type of node::value() must be one of:"
TOML_SA_LIST_NEW "A native TOML value type"
TOML_SA_NATIVE_VALUE_TYPE_LIST
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
TOML_SA_LIST_BEG "std::string"
#if TOML_WINDOWS_COMPAT
TOML_SA_LIST_SEP "std::wstring"
#endif
TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
TOML_SA_LIST_SEP "any floating-point type >= 64 bits"
TOML_SA_LIST_END
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
TOML_SA_LIST_BEG "any other integer type"
TOML_SA_LIST_SEP "any floating-point type >= 32 bits"
TOML_SA_LIST_END
TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage"
TOML_SA_LIST_BEG "std::string_view"
#ifdef __cpp_lib_char8_t
TOML_SA_LIST_SEP "std::u8string_view"
#endif
TOML_SA_LIST_SEP "const char*"
#ifdef __cpp_lib_char8_t
TOML_SA_LIST_SEP "const char8_t*"
#endif
TOML_SA_LIST_END
TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()")
);
// when asking for strings, dates, times and date_times there's no 'fuzzy' conversion
@ -760,7 +796,7 @@ TOML_NAMESPACE_START
static_assert(
traits::is_native || traits::can_represent_native || traits::can_partially_represent_native,
"The default return value type of node::value_or() must be one of:"
"The default value type of node::value_or() must be one of:"
TOML_SA_LIST_NEW "A native TOML value type"
TOML_SA_NATIVE_VALUE_TYPE_LIST
@ -799,6 +835,11 @@ TOML_NAMESPACE_START
// prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
if constexpr (traits::is_native || traits::can_represent_native || traits::can_partially_represent_native)
{
if constexpr (traits::is_native)
{
if (type() == node_type_of<value_type>)
return *ref_cast<typename traits::native_type>();
}
if (auto val = this->value<value_type>())
return *val;
if constexpr (std::is_pointer_v<value_type>)
@ -858,7 +899,6 @@ TOML_NAMESPACE_START
#endif // !TOML_HEADER_ONLY
TOML_POP_WARNINGS // TOML_DISABLE_INIT_WARNINGS, TOML_DISABLE_SWITCH_WARNINGS
#endif // !DOXYGEN
}
TOML_NAMESPACE_END

View File

@ -12,9 +12,6 @@ TOML_DISABLE_ALL_WARNINGS
TOML_POP_WARNINGS
#endif
// TOML_PUSH_WARNINGS
// TOML_DISABLE_ARITHMETIC_WARNINGS
template <typename T>
static constexpr T one = static_cast<T>(1);
@ -28,6 +25,9 @@ TEST_CASE("values - construction")
CHECK(equiv == v); \
CHECK(*v == equiv); \
CHECK(v.get() == equiv); \
CHECK(v.is_homogeneous()); \
CHECK(v.is_homogeneous<target_type>()); \
CHECK(v.is_homogeneous(impl::node_type_of<target_type>)); \
} while (false)
#define CHECK_VALUE_INIT(initializer, target_type) \
@ -86,8 +86,6 @@ TEST_CASE("values - construction")
#endif
}
// TOML_POP_WARNINGS
TEST_CASE("values - printing")
{
static constexpr auto print_value = [](auto&& raw)

View File

@ -26,27 +26,63 @@ TEST_CASE("parsing - arrays")
[](table&& tbl)
{
REQUIRE(tbl["integers"].as<array>());
CHECK(tbl["integers"].is_homogeneous());
CHECK(tbl["integers"].is_homogeneous(node_type::integer));
CHECK(!tbl["integers"].is_homogeneous(node_type::floating_point));
CHECK(tbl["integers"].is_homogeneous<int64_t>());
CHECK(!tbl["integers"].is_homogeneous<double>());
CHECK(tbl["integers"].as<array>()->is_homogeneous());
CHECK(tbl["integers"].as<array>()->is_homogeneous(node_type::integer));
CHECK(!tbl["integers"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(tbl["integers"].as<array>()->is_homogeneous<int64_t>());
CHECK(!tbl["integers"].as<array>()->is_homogeneous<double>());
CHECK(tbl["integers"].as<array>()->size() == 3);
CHECK(tbl["integers"][0] == 1);
CHECK(tbl["integers"][1] == 2);
CHECK(tbl["integers"][2] == 3);
REQUIRE(tbl["integers2"].as<array>());
CHECK(tbl["integers2"].is_homogeneous());
CHECK(tbl["integers2"].is_homogeneous(node_type::integer));
CHECK(!tbl["integers2"].is_homogeneous(node_type::floating_point));
CHECK(tbl["integers2"].is_homogeneous<int64_t>());
CHECK(!tbl["integers2"].is_homogeneous<double>());
CHECK(tbl["integers2"].as<array>()->is_homogeneous());
CHECK(tbl["integers2"].as<array>()->is_homogeneous(node_type::integer));
CHECK(!tbl["integers2"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(tbl["integers2"].as<array>()->is_homogeneous<int64_t>());
CHECK(!tbl["integers2"].as<array>()->is_homogeneous<double>());
CHECK(tbl["integers2"].as<array>()->size() == 3);
CHECK(tbl["integers2"][0] == 1);
CHECK(tbl["integers2"][1] == 2);
CHECK(tbl["integers2"][2] == 3);
REQUIRE(tbl["integers3"].as<array>());
CHECK(tbl["integers3"].is_homogeneous());
CHECK(tbl["integers3"].is_homogeneous(node_type::integer));
CHECK(!tbl["integers3"].is_homogeneous(node_type::floating_point));
CHECK(tbl["integers3"].is_homogeneous<int64_t>());
CHECK(!tbl["integers3"].is_homogeneous<double>());
CHECK(tbl["integers3"].as<array>()->is_homogeneous());
CHECK(tbl["integers3"].as<array>()->is_homogeneous(node_type::integer));
CHECK(!tbl["integers3"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(tbl["integers3"].as<array>()->is_homogeneous<int64_t>());
CHECK(!tbl["integers3"].as<array>()->is_homogeneous<double>());
CHECK(tbl["integers3"].as<array>()->size() == 2);
CHECK(tbl["integers3"][0] == 1);
CHECK(tbl["integers3"][1] == 2);
REQUIRE(tbl["colors"].as<array>());
CHECK(tbl["colors"].is_homogeneous());
CHECK(tbl["colors"].is_homogeneous(node_type::string));
CHECK(!tbl["colors"].is_homogeneous(node_type::floating_point));
CHECK(tbl["colors"].is_homogeneous<std::string>());
CHECK(!tbl["colors"].is_homogeneous<double>());
CHECK(tbl["colors"].as<array>()->is_homogeneous());
CHECK(tbl["colors"].as<array>()->is_homogeneous(node_type::string));
CHECK(!tbl["colors"].as<array>()->is_homogeneous(node_type::floating_point));
CHECK(tbl["colors"].as<array>()->is_homogeneous<std::string>());
CHECK(!tbl["colors"].as<array>()->is_homogeneous<double>());
CHECK(tbl["colors"].as<array>()->size() == 3);
CHECK(tbl["colors"][0] == "red"sv);
CHECK(tbl["colors"][1] == "yellow"sv);

View File

@ -5,8 +5,6 @@
#include "tests.h"
TOML_DISABLE_ARITHMETIC_WARNINGS
TEST_CASE("parsing - floats")
{
parsing_should_succeed(

View File

@ -18,15 +18,15 @@
#include "../include/toml++/toml.h"
#endif
TOML_DISABLE_ARITHMETIC_WARNINGS
TOML_PUSH_WARNINGS
TOML_DISABLE_ALL_WARNINGS
#include "catch2.h"
#include <sstream>
namespace toml {}
using namespace Catch::literals;
using namespace toml;
TOML_POP_WARNINGS
#define FILE_LINE_ARGS std::string_view{ __FILE__ }, __LINE__
@ -115,9 +115,6 @@ bool parsing_should_fail(
uint32_t test_line,
std::string_view toml_str);
TOML_PUSH_WARNINGS
TOML_DISABLE_ARITHMETIC_WARNINGS
template <typename T>
inline bool parse_expected_value(
std::string_view test_file,
@ -198,6 +195,28 @@ inline bool parse_expected_value(
REQUIRE(nv.node()->as<value_type>());
REQUIRE(nv.node()->type() == impl::node_type_of<T>);
// check homogeneity
REQUIRE(nv.is_homogeneous());
REQUIRE(nv.is_homogeneous(node_type::none));
REQUIRE(nv.is_homogeneous(impl::node_type_of<T>));
REQUIRE(nv.is_homogeneous<value_type>());
REQUIRE(nv.node()->is_homogeneous());
REQUIRE(nv.node()->is_homogeneous(node_type::none));
REQUIRE(nv.node()->is_homogeneous(impl::node_type_of<T>));
REQUIRE(nv.node()->is_homogeneous<value_type>());
for (auto nt = impl::unwrap_enum(node_type::table); nt <= impl::unwrap_enum(node_type::date_time); nt++)
{
if (node_type{ nt } == impl::node_type_of<T>)
continue;
node* first_nonmatch{};
REQUIRE(!nv.is_homogeneous(node_type{ nt }));
REQUIRE(!nv.is_homogeneous(node_type{ nt }, first_nonmatch));
REQUIRE(first_nonmatch == nv.node());
REQUIRE(!nv.node()->is_homogeneous(node_type{ nt }));
REQUIRE(!nv.node()->is_homogeneous(node_type{ nt }, first_nonmatch));
REQUIRE(first_nonmatch == nv.node());
}
// check the raw value
REQUIRE(nv.node()->value<value_type>() == expected);
REQUIRE(nv.node()->value_or(T{}) == expected);
@ -305,5 +324,3 @@ namespace Catch
extern template std::string stringify(const node_view<const node>&);
}
}
TOML_POP_WARNINGS // TOML_DISABLE_ARITHMETIC_WARNINGS

View File

@ -97,6 +97,9 @@ TEST_CASE("feedback - github/pull/50")
REQUIRE(val->is_number());
REQUIRE(val->is_integer());
REQUIRE(val->ref<int64_t>() == 10);
REQUIRE(val->value<int64_t>() == 10);
REQUIRE(val->value_or(0) == 10);
REQUIRE(val->value<double>() == 10.0);
REQUIRE(val->value_or(0.0) == 10.0);
}
}

429
toml.hpp
View File

@ -1066,6 +1066,7 @@ TOML_IMPL_NAMESPACE_START
template <typename T> struct node_type_getter { static constexpr auto value = value_traits<T>::type; };
template <> struct node_type_getter<table> { static constexpr auto value = node_type::table; };
template <> struct node_type_getter<array> { static constexpr auto value = node_type::array; };
template <> struct node_type_getter<void> { static constexpr auto value = node_type::none; };
template <typename T>
inline constexpr node_type node_type_of = node_type_getter<unwrap_node<remove_cvref_t<T>>>::value;
@ -1114,7 +1115,7 @@ TOML_IMPL_NAMESPACE_START
[[nodiscard]]
TOML_ATTR(const)
TOML_ALWAYS_INLINE
constexpr std::underlying_type_t<T> unbox_enum(T val) noexcept
constexpr std::underlying_type_t<T> unwrap_enum(T val) noexcept
{
return static_cast<std::underlying_type_t<T>>(val);
}
@ -2180,6 +2181,23 @@ TOML_NAMESPACE_START
[[nodiscard]] virtual const toml::value<date>* as_date() const noexcept;
[[nodiscard]] virtual const toml::value<time>* as_time() const noexcept;
[[nodiscard]] virtual const toml::value<date_time>* as_date_time() const noexcept;
[[nodiscard]] virtual bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept = 0;
[[nodiscard]] virtual bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept = 0;
[[nodiscard]] virtual bool is_homogeneous(node_type ntype) const noexcept = 0;
template <typename ElemType = void>
[[nodiscard]]
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>);
}
private:
@ -2205,6 +2223,14 @@ TOML_NAMESPACE_START
[[nodiscard]]
auto value_or(T&& default_value) const noexcept;
//template <typename T>
//[[nodiscard]]
//std::vector<T> select_exact() const noexcept;
//template <typename T>
//[[nodiscard]]
//std::vector<T> select() const noexcept;
template <typename T>
[[nodiscard]]
impl::wrap_node<T>* as() noexcept
@ -2474,6 +2500,65 @@ TOML_POP_WARNINGS // TOML_DISABLE_PADDING_WARNINGS, TOML_DISABLE_MISC_WARNINGS
//------------------------------------------ ↓ toml_value.h ----------------------------------------------------------
#if 1
#ifndef DOXYGEN
#if TOML_WINDOWS_COMPAT
#define TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP "std::wstring"
#else
#define TOML_SA_VALUE_MESSAGE_WSTRING
#endif
#ifdef __cpp_lib_char8_t
#define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW TOML_SA_LIST_SEP "std::u8string_view"
#define TOML_SA_VALUE_MESSAGE_CONST_CHAR8 TOML_SA_LIST_SEP "const char8_t*"
#else
#define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
#define TOML_SA_VALUE_MESSAGE_CONST_CHAR8
#endif
#define TOML_SA_VALUE_EXACT_FUNC_MESSAGE(type_arg) \
"The " type_arg " must be one of:" \
TOML_SA_LIST_NEW "A native TOML value type" \
TOML_SA_NATIVE_VALUE_TYPE_LIST \
\
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
TOML_SA_LIST_BEG "std::string" \
TOML_SA_VALUE_MESSAGE_WSTRING \
TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
TOML_SA_LIST_END \
\
TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
TOML_SA_LIST_BEG "std::string_view" \
TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
TOML_SA_LIST_SEP "const char*" \
TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
TOML_SA_LIST_END
#define TOML_SA_VALUE_FUNC_MESSAGE(type_arg) \
"The " type_arg " must be one of:" \
TOML_SA_LIST_NEW "A native TOML value type" \
TOML_SA_NATIVE_VALUE_TYPE_LIST \
\
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \
TOML_SA_LIST_BEG "std::string" \
TOML_SA_VALUE_MESSAGE_WSTRING \
TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \
TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \
TOML_SA_LIST_END \
\
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type" \
TOML_SA_LIST_BEG "any other integer type" \
TOML_SA_LIST_SEP "any floating-point type >= 32 bits" \
TOML_SA_LIST_END \
\
TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \
TOML_SA_LIST_BEG "std::string_view" \
TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \
TOML_SA_LIST_SEP "const char*" \
TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \
TOML_SA_LIST_END
#endif // !DOXYGEN
TOML_PUSH_WARNINGS
TOML_DISABLE_ARITHMETIC_WARNINGS
TOML_DISABLE_PADDING_WARNINGS
@ -2674,6 +2759,49 @@ TOML_NAMESPACE_START
[[nodiscard]] const value<date>* as_date() const noexcept override { return as_value<date>(this); }
[[nodiscard]] const value<time>* as_time() const noexcept override { return as_value<time>(this); }
[[nodiscard]] const value<date_time>* as_date_time() const noexcept override { return as_value<date_time>(this); }
[[nodiscard]]
bool is_homogeneous(node_type ntype) const noexcept override
{
return ntype == node_type::none || ntype == impl::node_type_of<value_type>;
}
[[nodiscard]]
bool is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept override
{
if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
{
first_nonmatch = this;
return false;
}
return true;
}
[[nodiscard]]
bool is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept override
{
if (ntype != node_type::none && ntype != impl::node_type_of<value_type>)
{
first_nonmatch = this;
return false;
}
return true;
}
template <typename ElemType = void>
[[nodiscard]]
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 value::is_homogeneous() must be void or one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
using type = impl::unwrap_node<ElemType>;
if constexpr (std::is_void_v<type>)
return true;
else
return impl::node_type_of<type> == impl::node_type_of<value_type>;
}
[[nodiscard]] value_type& get() & noexcept { return val_; }
[[nodiscard]] value_type&& get() && noexcept { return std::move(val_); }
@ -2713,8 +2841,8 @@ TOML_NAMESPACE_START
using namespace impl;
static constexpr auto pack = [](auto l, auto r) constexpr noexcept
{
return (static_cast<uint64_t>(unbox_enum(l)) << 32)
| static_cast<uint64_t>(unbox_enum(r));
return (static_cast<uint64_t>(unwrap_enum(l)) << 32)
| static_cast<uint64_t>(unwrap_enum(r));
};
switch (pack(impl::fpclassify(lhs.val_), impl::fpclassify(rhs)))
@ -2815,6 +2943,9 @@ TOML_NAMESPACE_START
value(T) -> value<impl::native_type_of<impl::remove_cvref_t<T>>>;
#ifndef DOXYGEN
TOML_PUSH_WARNINGS
TOML_DISABLE_INIT_WARNINGS
TOML_DISABLE_SWITCH_WARNINGS
#if !TOML_HEADER_ONLY
extern template class TOML_API value<std::string>;
@ -2826,10 +2957,6 @@ TOML_NAMESPACE_START
extern template class TOML_API value<date_time>;
#endif
TOML_PUSH_WARNINGS
TOML_DISABLE_INIT_WARNINGS
TOML_DISABLE_SWITCH_WARNINGS
template <typename T>
[[nodiscard]]
inline decltype(auto) node::get_value_exact() const noexcept
@ -2891,29 +3018,7 @@ TOML_NAMESPACE_START
static_assert(
(is_native<T> || can_represent_native<T>) && !is_cvref<T>,
"The return type of node::value_exact() must be one of:"
TOML_SA_LIST_NEW "A native TOML value type"
TOML_SA_NATIVE_VALUE_TYPE_LIST
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
TOML_SA_LIST_BEG "std::string"
#if TOML_WINDOWS_COMPAT
TOML_SA_LIST_SEP "std::wstring"
#endif
TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
TOML_SA_LIST_SEP "any floating-point type >= 64 bits"
TOML_SA_LIST_END
TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage"
TOML_SA_LIST_BEG "std::string_view"
#ifdef __cpp_lib_char8_t
TOML_SA_LIST_SEP "std::u8string_view"
#endif
TOML_SA_LIST_SEP "const char*"
#ifdef __cpp_lib_char8_t
TOML_SA_LIST_SEP "const char8_t*"
#endif
TOML_SA_LIST_END
TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()")
);
// prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
@ -2938,34 +3043,7 @@ TOML_NAMESPACE_START
);
static_assert(
(is_native<T> || can_represent_native<T> || can_partially_represent_native<T>) && !is_cvref<T>,
"The return type of node::value() must be one of:"
TOML_SA_LIST_NEW "A native TOML value type"
TOML_SA_NATIVE_VALUE_TYPE_LIST
TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type"
TOML_SA_LIST_BEG "std::string"
#if TOML_WINDOWS_COMPAT
TOML_SA_LIST_SEP "std::wstring"
#endif
TOML_SA_LIST_SEP "any signed integer type >= 64 bits"
TOML_SA_LIST_SEP "any floating-point type >= 64 bits"
TOML_SA_LIST_END
TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type"
TOML_SA_LIST_BEG "any other integer type"
TOML_SA_LIST_SEP "any floating-point type >= 32 bits"
TOML_SA_LIST_END
TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage"
TOML_SA_LIST_BEG "std::string_view"
#ifdef __cpp_lib_char8_t
TOML_SA_LIST_SEP "std::u8string_view"
#endif
TOML_SA_LIST_SEP "const char*"
#ifdef __cpp_lib_char8_t
TOML_SA_LIST_SEP "const char8_t*"
#endif
TOML_SA_LIST_END
TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()")
);
// when asking for strings, dates, times and date_times there's no 'fuzzy' conversion
@ -3107,7 +3185,7 @@ TOML_NAMESPACE_START
static_assert(
traits::is_native || traits::can_represent_native || traits::can_partially_represent_native,
"The default return value type of node::value_or() must be one of:"
"The default value type of node::value_or() must be one of:"
TOML_SA_LIST_NEW "A native TOML value type"
TOML_SA_NATIVE_VALUE_TYPE_LIST
@ -3146,6 +3224,11 @@ TOML_NAMESPACE_START
// prevent additional compiler error spam when the static_assert fails by gating behind if constexpr
if constexpr (traits::is_native || traits::can_represent_native || traits::can_partially_represent_native)
{
if constexpr (traits::is_native)
{
if (type() == node_type_of<value_type>)
return *ref_cast<typename traits::native_type>();
}
if (auto val = this->value<value_type>())
return *val;
if constexpr (std::is_pointer_v<value_type>)
@ -3205,7 +3288,6 @@ TOML_NAMESPACE_START
#endif // !TOML_HEADER_ONLY
TOML_POP_WARNINGS // TOML_DISABLE_INIT_WARNINGS, TOML_DISABLE_SWITCH_WARNINGS
#endif // !DOXYGEN
}
TOML_NAMESPACE_END
@ -3523,8 +3605,10 @@ TOML_NAMESPACE_START
[[nodiscard]] bool is_value() const noexcept override;
[[nodiscard]] array* as_array() noexcept override;
[[nodiscard]] const array* as_array() const noexcept override;
[[nodiscard]] bool is_homogeneous(node_type type) const noexcept;
[[nodiscard]] bool is_array_of_tables() const noexcept override;
[[nodiscard]] bool is_homogeneous(node_type ntype) const noexcept override;
[[nodiscard]] bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept override;
[[nodiscard]] bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept override;
template <typename ElemType = void>
[[nodiscard]]
bool is_homogeneous() const noexcept
@ -3536,14 +3620,9 @@ TOML_NAMESPACE_START
"The template type argument of array::is_homogeneous() must be void or one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
if constexpr (std::is_void_v<type>)
return is_homogeneous(node_type::none);
else
return is_homogeneous(impl::node_type_of<type>);
return is_homogeneous(impl::node_type_of<type>);
}
[[nodiscard]] bool is_array_of_tables() const noexcept override;
[[nodiscard]] node& operator[] (size_t index) noexcept;
[[nodiscard]] const node& operator[] (size_t index) const noexcept;
[[nodiscard]] node& front() noexcept;
@ -4024,6 +4103,23 @@ TOML_NAMESPACE_START
[[nodiscard]] bool is_value() const noexcept override;
[[nodiscard]] table* as_table() noexcept override;
[[nodiscard]] const table* as_table() const noexcept override;
[[nodiscard]] bool is_homogeneous(node_type ntype) const noexcept override;
[[nodiscard]] bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept override;
[[nodiscard]] bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept override;
template <typename ElemType = void>
[[nodiscard]]
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 table::is_homogeneous() must be void or one of:"
TOML_SA_UNWRAPPED_NODE_TYPE_LIST
);
return is_homogeneous(impl::node_type_of<type>);
}
[[nodiscard]] bool is_inline() const noexcept;
void is_inline(bool val) noexcept;
[[nodiscard]] node_view<node> operator[] (std::string_view key) noexcept;
@ -4289,6 +4385,43 @@ TOML_NAMESPACE_START
template <typename Char>
friend std::basic_ostream<Char>& operator << (std::basic_ostream<Char>&, const table&);
};
#ifndef DOXYGEN
//template <typename T>
//inline std::vector<T> node::select_exact() const noexcept
//{
// using namespace impl;
// static_assert(
// !is_wide_string<T> || TOML_WINDOWS_COMPAT,
// "Retrieving values as wide-character strings with node::select_exact() is only "
// "supported on Windows with TOML_WINDOWS_COMPAT enabled."
// );
// static_assert(
// (is_native<T> || can_represent_native<T>) && !is_cvref<T>,
// TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::select_exact()")
// );
//}
//template <typename T>
//inline std::vector<T> node::select() const noexcept
//{
// using namespace impl;
// static_assert(
// !is_wide_string<T> || TOML_WINDOWS_COMPAT,
// "Retrieving values as wide-character strings with node::select() is only "
// "supported on Windows with TOML_WINDOWS_COMPAT enabled."
// );
// static_assert(
// (is_native<T> || can_represent_native<T> || can_partially_represent_native<T>) && !is_cvref<T>,
// TOML_SA_VALUE_FUNC_MESSAGE("return type of node::select()")
// );
//}
#endif // !DOXYGEN
}
TOML_NAMESPACE_END
@ -4383,6 +4516,29 @@ TOML_NAMESPACE_START
[[nodiscard]] auto as_date() const noexcept { return as<date>(); }
[[nodiscard]] auto as_time() const noexcept { return as<time>(); }
[[nodiscard]] auto as_date_time() const noexcept { return as<date_time>(); }
[[nodiscard]]
bool is_homogeneous(node_type ntype, viewed_type*& first_nonmatch) const noexcept
{
if (!node_)
{
first_nonmatch = {};
return false;
}
return node_->is_homogeneous(ntype, first_nonmatch);
}
[[nodiscard]]
bool is_homogeneous(node_type ntype) const noexcept
{
return node_ ? node_->is_homogeneous(ntype) : false;
}
template <typename ElemType = void>
[[nodiscard]]
bool is_homogeneous() const noexcept
{
return node_ ? node_->template is_homogeneous<impl::unwrap_node<ElemType>>() : false;
}
template <typename T>
[[nodiscard]]
@ -5656,7 +5812,7 @@ TOML_NAMESPACE_START
TOML_ATTR(flatten)
constexpr format_flags operator & (format_flags lhs, format_flags rhs) noexcept
{
return static_cast<format_flags>(impl::unbox_enum(lhs) & impl::unbox_enum(rhs));
return static_cast<format_flags>(impl::unwrap_enum(lhs) & impl::unwrap_enum(rhs));
}
[[nodiscard]]
@ -5665,7 +5821,7 @@ TOML_NAMESPACE_START
TOML_ATTR(flatten)
constexpr format_flags operator | (format_flags lhs, format_flags rhs) noexcept
{
return static_cast<format_flags>( impl::unbox_enum(lhs) | impl::unbox_enum(rhs) );
return static_cast<format_flags>( impl::unwrap_enum(lhs) | impl::unwrap_enum(rhs) );
}
}
TOML_NAMESPACE_END
@ -7484,6 +7640,58 @@ TOML_NAMESPACE_START
#undef TOML_MEMBER_ATTR
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype) const noexcept
{
if (elements.empty())
return false;
if (ntype == node_type::none)
ntype = elements[0]->type();
for (const auto& val : elements)
if (val->type() != ntype)
return false;
return true;
}
namespace impl
{
template <typename T, typename U>
TOML_INTERNAL_LINKAGE
bool array_is_homogeneous(T& elements, node_type ntype, U& first_nonmatch) noexcept
{
if (elements.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = elements[0]->type();
for (const auto& val : elements)
{
if (val->type() != ntype)
{
first_nonmatch = val.get();
return false;
}
}
return true;
}
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept
{
return impl::array_is_homogeneous(elements, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept
{
return impl::array_is_homogeneous(elements, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
void array::truncate(size_t new_size)
{
@ -7634,21 +7842,6 @@ TOML_NAMESPACE_START
return *this;
}
TOML_EXTERNAL_LINKAGE
bool array::is_homogeneous(node_type type) const noexcept
{
if (elements.empty())
return false;
if (type == node_type::none)
type = elements[0]->type();
for (const auto& val : elements)
if (val->type() != type)
return false;
return true;
}
TOML_EXTERNAL_LINKAGE
bool array::is_array_of_tables() const noexcept
{
@ -7755,6 +7948,63 @@ TOML_NAMESPACE_START
#undef TOML_MEMBER_ATTR
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype) const noexcept
{
if (map.empty())
return false;
if (ntype == node_type::none)
ntype = map.cbegin()->second->type();
for (const auto& [k, v] : map)
{
(void)k;
if (v->type() != ntype)
return false;
}
return true;
}
namespace impl
{
template <typename T, typename U>
TOML_INTERNAL_LINKAGE
bool table_is_homogeneous(T& map, node_type ntype, U& first_nonmatch) noexcept
{
if (map.empty())
{
first_nonmatch = {};
return false;
}
if (ntype == node_type::none)
ntype = map.cbegin()->second->type();
for (const auto& [k, v] : map)
{
(void)k;
if (v->type() != ntype)
{
first_nonmatch = v.get();
return false;
}
}
return true;
}
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, toml::node*& first_nonmatch) noexcept
{
return impl::table_is_homogeneous(map, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
bool table::is_homogeneous(node_type ntype, const toml::node*& first_nonmatch) const noexcept
{
return impl::table_is_homogeneous(map, ntype, first_nonmatch);
}
TOML_EXTERNAL_LINKAGE
node_view<node> table::operator[] (std::string_view key) noexcept
{
@ -8415,7 +8665,7 @@ TOML_ANON_NAMESPACE_START
{
using namespace ::toml::impl;
return node_type_friendly_names[unbox_enum(val)];
return node_type_friendly_names[unwrap_enum(val)];
}
[[nodiscard]]
@ -10398,7 +10648,7 @@ TOML_IMPL_NAMESPACE_START
// all correct value parses will come out of this list, so doing this as a switch is likely to
// be a better friend to the optimizer on the success path (failure path can be slow but that
// doesn't matter much).
switch (unbox_enum(traits))
switch (unwrap_enum(traits))
{
//=================== binary integers
// 0b10
@ -11585,6 +11835,11 @@ TOML_NAMESPACE_END
#undef TOML_SA_NEWLINE
#undef TOML_SA_NODE_TYPE_LIST
#undef TOML_SA_UNWRAPPED_NODE_TYPE_LIST
#undef TOML_SA_VALUE_EXACT_FUNC_MESSAGE
#undef TOML_SA_VALUE_FUNC_MESSAGE
#undef TOML_SA_VALUE_MESSAGE_CONST_CHAR8
#undef TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
#undef TOML_SA_VALUE_MESSAGE_WSTRING
#undef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
#undef TOML_TRIVIAL_ABI
#undef TOML_UINT128