2020-01-04 14:21:38 +00:00
|
|
|
#pragma once
|
|
|
|
#include "toml_common.h"
|
|
|
|
|
|
|
|
namespace toml
|
|
|
|
{
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief A TOML node.
|
|
|
|
///
|
|
|
|
/// \detail A parsed TOML document forms a tree made up of tables, arrays and values.
|
|
|
|
/// This type is the base of each of those, providing a lot of the polymorphic plumbing.
|
2020-01-04 14:21:38 +00:00
|
|
|
class TOML_INTERFACE node
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
friend class impl::parser;
|
2020-01-07 15:52:50 +00:00
|
|
|
source_region source_{};
|
2020-01-04 14:21:38 +00:00
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
node(node&& other) noexcept
|
2020-01-07 15:52:50 +00:00
|
|
|
: source_{ std::move(other.source_) }
|
2020-02-03 09:12:43 +00:00
|
|
|
{
|
|
|
|
other.source_.begin = {};
|
|
|
|
other.source_.end = {};
|
|
|
|
}
|
2020-01-04 14:21:38 +00:00
|
|
|
|
|
|
|
node& operator= (node&& rhs) noexcept
|
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
source_ = std::move(rhs.source_);
|
2020-02-03 09:12:43 +00:00
|
|
|
rhs.source_.begin = {};
|
|
|
|
rhs.source_.end = {};
|
2020-01-04 14:21:38 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-01-06 18:21:16 +00:00
|
|
|
template <typename T>
|
|
|
|
[[nodiscard]] TOML_ALWAYS_INLINE
|
2020-02-16 13:11:57 +00:00
|
|
|
impl::node_of<T>& ref_cast() & noexcept { return *reinterpret_cast<impl::node_of<T>*>(this); }
|
2020-01-06 18:21:16 +00:00
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
[[nodiscard]] TOML_ALWAYS_INLINE
|
2020-02-16 13:11:57 +00:00
|
|
|
impl::node_of<T>&& ref_cast() && noexcept { return std::move(*reinterpret_cast<impl::node_of<T>*>(this)); }
|
2020-01-13 06:31:49 +00:00
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
[[nodiscard]] TOML_ALWAYS_INLINE
|
2020-02-16 13:11:57 +00:00
|
|
|
const impl::node_of<T>& ref_cast() const & noexcept { return *reinterpret_cast<const impl::node_of<T>*>(this); }
|
2020-01-13 06:31:49 +00:00
|
|
|
|
|
|
|
template <typename N, typename T>
|
|
|
|
using ref_cast_type = decltype(std::declval<N>().template ref_cast<T>());
|
2020-01-06 18:21:16 +00:00
|
|
|
|
2020-01-04 14:21:38 +00:00
|
|
|
node() noexcept = default;
|
|
|
|
node(const node&) = delete;
|
|
|
|
node& operator= (const node&) = delete;
|
2020-01-11 21:15:24 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2020-01-04 14:21:38 +00:00
|
|
|
virtual ~node() noexcept = default;
|
|
|
|
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns the node's type identifier.
|
2020-01-07 15:52:50 +00:00
|
|
|
[[nodiscard]] virtual node_type type() const noexcept = 0;
|
|
|
|
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns true if this node is a table.
|
2020-01-07 15:52:50 +00:00
|
|
|
[[nodiscard]] virtual bool is_table() const noexcept = 0;
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns true if this node is an array.
|
2020-01-07 15:52:50 +00:00
|
|
|
[[nodiscard]] virtual bool is_array() const noexcept = 0;
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns true if this node is a value.
|
2020-01-07 15:52:50 +00:00
|
|
|
[[nodiscard]] virtual bool is_value() const noexcept = 0;
|
|
|
|
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns true if this node is a string value.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual bool is_string() const noexcept { return false; }
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns true if this node is an integer value.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual bool is_integer() const noexcept { return false; }
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns true if this node is an floating-point value.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual bool is_floating_point() const noexcept { return false; }
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns true if this node is a boolean value.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual bool is_boolean() const noexcept { return false; }
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns true if this node is a local date value.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual bool is_date() const noexcept { return false; }
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns true if this node is a local time value.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual bool is_time() const noexcept { return false; }
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns true if this node is a date-time value.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual bool is_date_time() const noexcept { return false; }
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Returns true if this node is an array containing only tables.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual bool is_array_of_tables() const noexcept { return false; }
|
|
|
|
|
2020-01-12 15:37:02 +00:00
|
|
|
/// \brief Checks if a node is a specific type.
|
|
|
|
///
|
|
|
|
/// \tparam T The
|
|
|
|
///
|
|
|
|
/// \returns Returns true if this node is an instance
|
2020-01-04 14:21:38 +00:00
|
|
|
template <typename T>
|
2020-01-12 15:37:02 +00:00
|
|
|
[[nodiscard]] TOML_ALWAYS_INLINE
|
|
|
|
bool is() const noexcept
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-02-03 09:12:43 +00:00
|
|
|
using type = impl::unwrapped<impl::remove_cvref_t<T>>;
|
2020-01-04 14:21:38 +00:00
|
|
|
static_assert(
|
|
|
|
impl::is_value_or_node<type>,
|
|
|
|
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
|
|
|
);
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
if constexpr (std::is_same_v<type, table>) return is_table();
|
|
|
|
else if constexpr (std::is_same_v<type, array>) return is_array();
|
|
|
|
else if constexpr (std::is_same_v<type, string>) return is_string();
|
2020-01-04 14:21:38 +00:00
|
|
|
else if constexpr (std::is_same_v<type, int64_t>) return is_integer();
|
|
|
|
else if constexpr (std::is_same_v<type, double>) return is_floating_point();
|
|
|
|
else if constexpr (std::is_same_v<type, bool>) return is_boolean();
|
|
|
|
else if constexpr (std::is_same_v<type, date>) return is_date();
|
|
|
|
else if constexpr (std::is_same_v<type, time>) return is_time();
|
|
|
|
else if constexpr (std::is_same_v<type, date_time>) return is_date_time();
|
|
|
|
}
|
2020-01-13 06:31:49 +00:00
|
|
|
|
|
|
|
/// \brief Returns a pointer to the node as a toml::table, if it is one.
|
2020-01-07 15:52:50 +00:00
|
|
|
[[nodiscard]] virtual table* as_table() noexcept { return nullptr; }
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Returns a pointer to the node as a toml::array, if it is one.
|
2020-01-07 15:52:50 +00:00
|
|
|
[[nodiscard]] virtual array* as_array() noexcept { return nullptr; }
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Returns a pointer to the node as a toml::value<string>, if it is one.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual value<string>* as_string() noexcept { return nullptr; }
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Returns a pointer to the node as a toml::value<int64_t>, if it is one.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual value<int64_t>* as_integer() noexcept { return nullptr; }
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Returns a pointer to the node as a toml::value<double>, if it is one.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual value<double>* as_floating_point() noexcept { return nullptr; }
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Returns a pointer to the node as a toml::value<bool>, if it is one.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual value<bool>* as_boolean() noexcept { return nullptr; }
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Returns a pointer to the node as a toml::value<date>, if it is one.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual value<date>* as_date() noexcept { return nullptr; }
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Returns a pointer to the node as a toml::value<time>, if it is one.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual value<time>* as_time() noexcept { return nullptr; }
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Returns a pointer to the node as a toml::value<date_time>, if it is one.
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual value<date_time>* as_date_time() noexcept { return nullptr; }
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
[[nodiscard]] virtual const table* as_table() const noexcept { return nullptr; }
|
|
|
|
[[nodiscard]] virtual const array* as_array() const noexcept { return nullptr; }
|
2020-01-04 14:21:38 +00:00
|
|
|
[[nodiscard]] virtual const value<string>* as_string() const noexcept { return nullptr; }
|
|
|
|
[[nodiscard]] virtual const value<int64_t>* as_integer() const noexcept { return nullptr; }
|
|
|
|
[[nodiscard]] virtual const value<double>* as_floating_point() const noexcept { return nullptr; }
|
|
|
|
[[nodiscard]] virtual const value<bool>* as_boolean() const noexcept { return nullptr; }
|
|
|
|
[[nodiscard]] virtual const value<date>* as_date() const noexcept { return nullptr; }
|
|
|
|
[[nodiscard]] virtual const value<time>* as_time() const noexcept { return nullptr; }
|
|
|
|
[[nodiscard]] virtual const value<date_time>* as_date_time() const noexcept { return nullptr; }
|
|
|
|
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Gets a pointer to the node as a more specific node type.
|
|
|
|
///
|
|
|
|
/// \details \cpp
|
|
|
|
///
|
|
|
|
/// auto int_value = node->as<int64_t>();
|
|
|
|
/// auto tbl = node->as<toml::table>();
|
|
|
|
/// if (int_value)
|
|
|
|
/// std::cout << "Node is a value<int64_t>" << std::endl;
|
|
|
|
/// else if (tbl)
|
|
|
|
/// std::cout << "Node is a table" << std::endl;
|
|
|
|
///
|
|
|
|
/// // fully-qualified value node types also work:
|
|
|
|
/// auto int_value2 = node->as<toml::value<int64_t>>();
|
|
|
|
/// if (int_value2)
|
|
|
|
/// std::cout << "Node is a value<int64_t>" << std::endl;
|
|
|
|
///
|
|
|
|
/// \ecpp
|
|
|
|
///
|
|
|
|
/// \tparam T The node type or TOML value type to cast to.
|
|
|
|
///
|
|
|
|
/// \returns A pointer to the node as the given type, or nullptr if it was a different type.
|
2020-01-04 14:21:38 +00:00
|
|
|
template <typename T>
|
2020-01-06 18:21:16 +00:00
|
|
|
[[nodiscard]] TOML_ALWAYS_INLINE
|
2020-02-16 13:11:57 +00:00
|
|
|
impl::node_of<T>* as() noexcept
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-02-03 09:12:43 +00:00
|
|
|
using type = impl::unwrapped<T>;
|
2020-01-04 14:21:38 +00:00
|
|
|
static_assert(
|
|
|
|
impl::is_value_or_node<type>,
|
|
|
|
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
|
|
|
);
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
if constexpr (std::is_same_v<type, table>) return as_table();
|
|
|
|
else if constexpr (std::is_same_v<type, array>) return as_array();
|
|
|
|
else if constexpr (std::is_same_v<type, string>) return as_string();
|
2020-01-04 14:21:38 +00:00
|
|
|
else if constexpr (std::is_same_v<type, int64_t>) return as_integer();
|
|
|
|
else if constexpr (std::is_same_v<type, double>) return as_floating_point();
|
|
|
|
else if constexpr (std::is_same_v<type, bool>) return as_boolean();
|
|
|
|
else if constexpr (std::is_same_v<type, date>) return as_date();
|
|
|
|
else if constexpr (std::is_same_v<type, time>) return as_time();
|
|
|
|
else if constexpr (std::is_same_v<type, date_time>) return as_date_time();
|
|
|
|
}
|
|
|
|
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Gets a pointer to the node as a more specific node type (const overload).
|
2020-01-04 14:21:38 +00:00
|
|
|
template <typename T>
|
2020-01-06 18:21:16 +00:00
|
|
|
[[nodiscard]] TOML_ALWAYS_INLINE
|
2020-02-16 13:11:57 +00:00
|
|
|
const impl::node_of<T>* as() const noexcept
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-02-03 09:12:43 +00:00
|
|
|
using type = impl::unwrapped<T>;
|
2020-01-04 14:21:38 +00:00
|
|
|
static_assert(
|
|
|
|
impl::is_value_or_node<type>,
|
|
|
|
"Template type parameter must be one of the basic value types, a toml::table, or a toml::array"
|
|
|
|
);
|
|
|
|
|
2020-01-07 15:52:50 +00:00
|
|
|
if constexpr (std::is_same_v<type, table>) return as_table();
|
|
|
|
else if constexpr (std::is_same_v<type, array>) return as_array();
|
|
|
|
else if constexpr (std::is_same_v<type, string>) return as_string();
|
2020-01-04 14:21:38 +00:00
|
|
|
else if constexpr (std::is_same_v<type, int64_t>) return as_integer();
|
|
|
|
else if constexpr (std::is_same_v<type, double>) return as_floating_point();
|
|
|
|
else if constexpr (std::is_same_v<type, bool>) return as_boolean();
|
|
|
|
else if constexpr (std::is_same_v<type, date>) return as_date();
|
|
|
|
else if constexpr (std::is_same_v<type, time>) return as_time();
|
|
|
|
else if constexpr (std::is_same_v<type, date_time>) return as_date_time();
|
|
|
|
}
|
|
|
|
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Returns the source region responsible for generating this node during parsing.
|
2020-01-07 15:52:50 +00:00
|
|
|
[[nodiscard]] const source_region& source() const noexcept
|
2020-01-04 14:21:38 +00:00
|
|
|
{
|
2020-01-07 15:52:50 +00:00
|
|
|
return source_;
|
2020-01-04 14:21:38 +00:00
|
|
|
}
|
2020-01-06 18:21:16 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
2020-01-22 21:29:46 +00:00
|
|
|
template <typename FUNC, typename N, typename T>
|
|
|
|
static constexpr bool can_visit = std::is_invocable_v<FUNC, ref_cast_type<N, T>>;
|
|
|
|
|
|
|
|
template <typename FUNC, typename N>
|
|
|
|
static constexpr bool can_visit_any =
|
|
|
|
can_visit<FUNC, N, table>
|
|
|
|
|| can_visit<FUNC, N, array>
|
|
|
|
|| can_visit<FUNC, N, string>
|
|
|
|
|| can_visit<FUNC, N, int64_t>
|
|
|
|
|| can_visit<FUNC, N, double>
|
|
|
|
|| can_visit<FUNC, N, bool>
|
|
|
|
|| can_visit<FUNC, N, date>
|
|
|
|
|| can_visit<FUNC, N, time>
|
|
|
|
|| can_visit<FUNC, N, date_time>;
|
|
|
|
|
|
|
|
template <typename FUNC, typename N>
|
|
|
|
static constexpr bool can_visit_all =
|
|
|
|
can_visit<FUNC, N, table>
|
|
|
|
&& can_visit<FUNC, N, array>
|
|
|
|
&& can_visit<FUNC, N, string>
|
|
|
|
&& can_visit<FUNC, N, int64_t>
|
|
|
|
&& can_visit<FUNC, N, double>
|
|
|
|
&& can_visit<FUNC, N, bool>
|
|
|
|
&& can_visit<FUNC, N, date>
|
|
|
|
&& can_visit<FUNC, N, time>
|
|
|
|
&& can_visit<FUNC, N, date_time>;
|
|
|
|
|
|
|
|
#if TOML_EXCEPTIONS
|
|
|
|
|
|
|
|
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>>;
|
|
|
|
|
|
|
|
template <typename FUNC, typename N>
|
|
|
|
static constexpr bool visit_is_nothrow =
|
|
|
|
visit_is_nothrow_one<FUNC, N, table>
|
|
|
|
&& visit_is_nothrow_one<FUNC, N, array>
|
|
|
|
&& visit_is_nothrow_one<FUNC, N, string>
|
|
|
|
&& visit_is_nothrow_one<FUNC, N, int64_t>
|
|
|
|
&& visit_is_nothrow_one<FUNC, N, double>
|
|
|
|
&& visit_is_nothrow_one<FUNC, N, bool>
|
|
|
|
&& visit_is_nothrow_one<FUNC, N, date>
|
|
|
|
&& visit_is_nothrow_one<FUNC, N, time>
|
|
|
|
&& visit_is_nothrow_one<FUNC, N, date_time>;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
template <typename FUNC, typename N, typename T, bool = can_visit<FUNC, N, T>>
|
2020-01-13 06:31:49 +00:00
|
|
|
struct visit_return_type final
|
|
|
|
{
|
|
|
|
using type = decltype(std::declval<FUNC>()(std::declval<ref_cast_type<N, T>>()));
|
|
|
|
};
|
|
|
|
template <typename FUNC, typename N, typename T>
|
|
|
|
struct visit_return_type<FUNC, N, T, false> final
|
|
|
|
{
|
|
|
|
using type = void;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename A, typename B>
|
|
|
|
using nonvoid = std::conditional_t<std::is_void_v<A>, B, A>;
|
|
|
|
|
2020-01-22 21:29:46 +00:00
|
|
|
//# this is done using a static helper to preserve const and ref categories
|
|
|
|
//# (otherwise I'd have to implement this function thrice)
|
|
|
|
//# ((propagation in C++: a modern horror story))
|
2020-01-06 18:21:16 +00:00
|
|
|
template <typename N, typename FUNC>
|
2020-01-22 21:29:46 +00:00
|
|
|
static decltype(auto) do_visit(N&& node, FUNC&& visitor)
|
|
|
|
TOML_MAY_THROW_UNLESS(visit_is_nothrow<FUNC&&, N&&>)
|
2020-01-06 18:21:16 +00:00
|
|
|
{
|
|
|
|
static_assert(
|
2020-01-22 21:29:46 +00:00
|
|
|
can_visit_any<FUNC&&, N&&>,
|
2020-01-06 18:21:16 +00:00
|
|
|
"Visitors must be invocable for at least one of the toml::node specializations"
|
|
|
|
);
|
|
|
|
|
2020-01-13 06:31:49 +00:00
|
|
|
switch (node.type())
|
2020-01-06 18:21:16 +00:00
|
|
|
{
|
|
|
|
case node_type::table:
|
2020-01-22 21:29:46 +00:00
|
|
|
if constexpr (can_visit<FUNC&&, N&&, table>)
|
2020-01-13 06:31:49 +00:00
|
|
|
return std::forward<FUNC>(visitor)(std::forward<N>(node).template ref_cast<table>());
|
2020-01-06 18:21:16 +00:00
|
|
|
break;
|
|
|
|
case node_type::array:
|
2020-01-22 21:29:46 +00:00
|
|
|
if constexpr (can_visit<FUNC&&, N&&, array>)
|
2020-01-13 06:31:49 +00:00
|
|
|
return std::forward<FUNC>(visitor)(std::forward<N>(node).template ref_cast<array>());
|
2020-01-06 18:21:16 +00:00
|
|
|
break;
|
|
|
|
case node_type::string:
|
2020-01-22 21:29:46 +00:00
|
|
|
if constexpr (can_visit<FUNC&&, N&&, string>)
|
2020-01-13 06:31:49 +00:00
|
|
|
return std::forward<FUNC>(visitor)(std::forward<N>(node).template ref_cast<string>());
|
2020-01-06 18:21:16 +00:00
|
|
|
break;
|
|
|
|
case node_type::integer:
|
2020-01-22 21:29:46 +00:00
|
|
|
if constexpr (can_visit<FUNC&&, N&&, int64_t>)
|
2020-01-13 06:31:49 +00:00
|
|
|
return std::forward<FUNC>(visitor)(std::forward<N>(node).template ref_cast<int64_t>());
|
2020-01-06 18:21:16 +00:00
|
|
|
break;
|
|
|
|
case node_type::floating_point:
|
2020-01-22 21:29:46 +00:00
|
|
|
if constexpr (can_visit<FUNC&&, N&&, double>)
|
2020-01-13 06:31:49 +00:00
|
|
|
return std::forward<FUNC>(visitor)(std::forward<N>(node).template ref_cast<double>());
|
2020-01-06 18:21:16 +00:00
|
|
|
break;
|
|
|
|
case node_type::boolean:
|
2020-01-22 21:29:46 +00:00
|
|
|
if constexpr (can_visit<FUNC&&, N&&, bool>)
|
2020-01-13 06:31:49 +00:00
|
|
|
return std::forward<FUNC>(visitor)(std::forward<N>(node).template ref_cast<bool>());
|
2020-01-06 18:21:16 +00:00
|
|
|
break;
|
|
|
|
case node_type::date:
|
2020-01-22 21:29:46 +00:00
|
|
|
if constexpr (can_visit<FUNC&&, N&&, date>)
|
2020-01-13 06:31:49 +00:00
|
|
|
return std::forward<FUNC>(visitor)(std::forward<N>(node).template ref_cast<date>());
|
2020-01-06 18:21:16 +00:00
|
|
|
break;
|
|
|
|
case node_type::time:
|
2020-01-22 21:29:46 +00:00
|
|
|
if constexpr (can_visit<FUNC&&, N&&, time>)
|
2020-01-13 06:31:49 +00:00
|
|
|
return std::forward<FUNC>(visitor)(std::forward<N>(node).template ref_cast<time>());
|
2020-01-06 18:21:16 +00:00
|
|
|
break;
|
|
|
|
case node_type::date_time:
|
2020-01-22 21:29:46 +00:00
|
|
|
if constexpr (can_visit<FUNC&&, N&&, date_time>)
|
2020-01-13 06:31:49 +00:00
|
|
|
return std::forward<FUNC>(visitor)(std::forward<N>(node).template ref_cast<date_time>());
|
2020-01-06 18:21:16 +00:00
|
|
|
break;
|
|
|
|
TOML_NO_DEFAULT_CASE;
|
|
|
|
}
|
|
|
|
|
2020-01-22 21:29:46 +00:00
|
|
|
if constexpr (can_visit_all<FUNC&&, N&&>)
|
2020-01-06 18:21:16 +00:00
|
|
|
TOML_UNREACHABLE;
|
2020-01-13 06:31:49 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
using return_type =
|
|
|
|
nonvoid<typename visit_return_type<FUNC&&, N&&, table>::type,
|
|
|
|
nonvoid<typename visit_return_type<FUNC&&, N&&, array>::type,
|
|
|
|
nonvoid<typename visit_return_type<FUNC&&, N&&, string>::type,
|
|
|
|
nonvoid<typename visit_return_type<FUNC&&, N&&, int64_t>::type,
|
|
|
|
nonvoid<typename visit_return_type<FUNC&&, N&&, double>::type,
|
|
|
|
nonvoid<typename visit_return_type<FUNC&&, N&&, bool>::type,
|
|
|
|
nonvoid<typename visit_return_type<FUNC&&, N&&, date>::type,
|
|
|
|
nonvoid<typename visit_return_type<FUNC&&, N&&, time>::type,
|
2020-01-22 21:29:46 +00:00
|
|
|
typename visit_return_type<FUNC&&, N&&, date_time>::type
|
|
|
|
>>>>>>>>;
|
2020-01-13 06:31:49 +00:00
|
|
|
|
|
|
|
if constexpr (!std::is_void_v<return_type>)
|
|
|
|
{
|
|
|
|
static_assert(
|
|
|
|
std::is_default_constructible_v<return_type>,
|
|
|
|
"Non-exhaustive visitors must return a default-constructible type, or void"
|
|
|
|
);
|
|
|
|
return return_type{};
|
|
|
|
}
|
|
|
|
}
|
2020-01-06 18:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Invokes a visitor on the node based on the node's concrete type.
|
|
|
|
///
|
|
|
|
/// \details Visitation is useful when you expect
|
|
|
|
/// a node to be one of a set number of types and need
|
|
|
|
/// to handle these types differently. Using `visit()` allows
|
|
|
|
/// you to eliminate some of the casting/conversion boilerplate: \cpp
|
|
|
|
///
|
|
|
|
/// node.visit([](auto&& n)
|
|
|
|
/// {
|
|
|
|
/// if constexpr (toml::is_string<decltype(n)>)
|
2020-01-22 21:29:46 +00:00
|
|
|
/// do_something_with_a_string(*n)); //n is a toml::value<toml::string>
|
|
|
|
/// else if constexpr (toml::is_integer<decltype(n)>)
|
|
|
|
/// do_something_with_an_int(*n); //n is a toml::value<int64_t>
|
2020-01-13 06:31:49 +00:00
|
|
|
/// else
|
|
|
|
/// throw std::exception("Expected string or integer")
|
|
|
|
/// });
|
|
|
|
///
|
|
|
|
/// \ecpp
|
|
|
|
///
|
|
|
|
/// \tparam FUNC A callable type invocable with one or more of the
|
|
|
|
/// toml++ node types.
|
|
|
|
///
|
|
|
|
/// \param visitor The visitor object.
|
|
|
|
///
|
|
|
|
/// \returns The return value of the visitor.
|
2020-01-22 21:29:46 +00:00
|
|
|
/// Can be void. Non-exhaustive visitors must return a default-constructible type.
|
2020-01-13 06:31:49 +00:00
|
|
|
///
|
|
|
|
/// \see https://en.wikipedia.org/wiki/Visitor_pattern
|
|
|
|
template <typename FUNC>
|
2020-01-22 21:29:46 +00:00
|
|
|
decltype(auto) visit(FUNC&& visitor) & TOML_MAY_THROW_UNLESS(visit_is_nothrow<FUNC&&, node&>)
|
2020-01-13 06:31:49 +00:00
|
|
|
{
|
|
|
|
return do_visit(*this, std::forward<FUNC>(visitor));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Invokes a visitor on the node based on the node's concrete type (rvalue overload).
|
2020-01-06 18:21:16 +00:00
|
|
|
template <typename FUNC>
|
2020-01-22 21:29:46 +00:00
|
|
|
decltype(auto) visit(FUNC&& visitor) && TOML_MAY_THROW_UNLESS(visit_is_nothrow<FUNC&&, node&&>)
|
2020-01-06 18:21:16 +00:00
|
|
|
{
|
2020-01-13 06:31:49 +00:00
|
|
|
return do_visit(std::move(*this), std::forward<FUNC>(visitor));
|
2020-01-06 18:21:16 +00:00
|
|
|
}
|
|
|
|
|
2020-01-13 06:31:49 +00:00
|
|
|
/// \brief Invokes a visitor on the node based on the node's concrete type (const overload).
|
2020-01-06 18:21:16 +00:00
|
|
|
template <typename FUNC>
|
2020-01-22 21:29:46 +00:00
|
|
|
decltype(auto) visit(FUNC&& visitor) const& TOML_MAY_THROW_UNLESS(visit_is_nothrow<FUNC&&, const node&>)
|
2020-01-06 18:21:16 +00:00
|
|
|
{
|
2020-01-13 06:31:49 +00:00
|
|
|
return do_visit(*this, std::forward<FUNC>(visitor));
|
2020-01-06 18:21:16 +00:00
|
|
|
}
|
2020-01-04 14:21:38 +00:00
|
|
|
};
|
|
|
|
}
|