diff options
| author | Amlal El Mahrouss <amlal@nekernel.org> | 2026-03-08 15:50:45 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-08 15:50:45 +0100 |
| commit | 386b6ba6702aaf121a8667b68fba86385dad68ed (patch) | |
| tree | 985c7eda4fafa827eaad88b6b469b0baba791817 /vendor/toml++/impl/node.hpp | |
| parent | 7a469801ecb55fcde0199d4e41b1cec3a17dcb05 (diff) | |
| parent | ddb1cbc831b6d13b985d91022f01e955e24ae871 (diff) | |
Merge pull request #25 from ne-foss-org/nebuild-patches-deref
[CHORE] Patching TOML manifest parser to avoid null deref.
Diffstat (limited to 'vendor/toml++/impl/node.hpp')
| -rw-r--r-- | vendor/toml++/impl/node.hpp | 2096 |
1 files changed, 1037 insertions, 1059 deletions
diff --git a/vendor/toml++/impl/node.hpp b/vendor/toml++/impl/node.hpp index e4e316a..3ed1429 100644 --- a/vendor/toml++/impl/node.hpp +++ b/vendor/toml++/impl/node.hpp @@ -1,754 +1,733 @@ -//# This file is a part of toml++ and is subject to the the terms of the MIT license. -//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au> -//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. -// SPDX-License-Identifier: MIT +// # This file is a part of toml++ and is subject to the the terms of the MIT license. +// # Copyright (c) Mark Gillard <mark.gillard@outlook.com.au> +// # See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. +// SPDX-License-Identifier: MIT #pragma once -#include "std_utility.hpp" #include "forward_declarations.hpp" -#include "source_region.hpp" #include "header_start.hpp" +#include "source_region.hpp" +#include "std_utility.hpp" -TOML_NAMESPACE_START -{ - /// \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. - class TOML_ABSTRACT_INTERFACE TOML_EXPORTED_CLASS node - { - private: - /// \cond - - friend class TOML_PARSER_TYPENAME; - source_region source_{}; - - template <typename T> - 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 ref_type<T, N&&> do_ref(N&& n) noexcept - { - 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_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<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>()); - } - - protected: - TOML_EXPORTED_MEMBER_FUNCTION - node() noexcept; - - TOML_EXPORTED_MEMBER_FUNCTION - node(const node&) noexcept; - - TOML_EXPORTED_MEMBER_FUNCTION - node(node&&) noexcept; - - TOML_EXPORTED_MEMBER_FUNCTION - node& operator=(const node&) noexcept; - - TOML_EXPORTED_MEMBER_FUNCTION - 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 - ref_cast_type<T, node&> ref_cast() & noexcept - { - 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 - ref_cast_type<T, node&&> ref_cast() && noexcept - { - 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 - 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)); - } - - 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 - - public: - TOML_EXPORTED_MEMBER_FUNCTION - virtual ~node() noexcept; - - /// \name Type checks - /// @{ - - /// \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> - /// \conditional_return{toml::node_type::none} - /// "is every element the same type?" - /// \conditional_return{Anything else} - /// "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. - TOML_PURE_GETTER - 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). - TOML_PURE_GETTER - 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> - /// \conditional_return{toml::node_type::none} - /// "is every element the same type?" - /// \conditional_return{Anything else} - /// "is every element one of these?" - /// - /// \returns True if the node was homogeneous. - /// - /// \remarks Always returns `false` for empty tables and arrays. - TOML_PURE_GETTER - 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> - /// \conditional_return{Left as `void`} - /// "is every element the same type?" <br> - /// \conditional_return{Explicitly specified} - /// "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> - TOML_PURE_GETTER - bool is_homogeneous() const noexcept - { - using type = impl::remove_cvref<impl::unwrap_node<ElemType>>; - static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<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>); - } - - /// \brief Returns the node's type identifier. - TOML_PURE_GETTER - virtual node_type type() const noexcept = 0; - - /// \brief Returns true if this node is a table. - TOML_PURE_GETTER - virtual bool is_table() const noexcept = 0; - - /// \brief Returns true if this node is an array. - TOML_PURE_GETTER - virtual bool is_array() const noexcept = 0; - - /// \brief Returns true if this node is an array containing only tables. - TOML_PURE_GETTER - virtual bool is_array_of_tables() const noexcept = 0; - - /// \brief Returns true if this node is a value. - TOML_PURE_GETTER - virtual bool is_value() const noexcept = 0; - - /// \brief Returns true if this node is a string value. - TOML_PURE_GETTER - virtual bool is_string() const noexcept = 0; - - /// \brief Returns true if this node is an integer value. - TOML_PURE_GETTER - virtual bool is_integer() const noexcept = 0; - - /// \brief Returns true if this node is an floating-point value. - TOML_PURE_GETTER - virtual bool is_floating_point() const noexcept = 0; - - /// \brief Returns true if this node is an integer or floating-point value. - TOML_PURE_GETTER - virtual bool is_number() const noexcept = 0; - - /// \brief Returns true if this node is a boolean value. - TOML_PURE_GETTER - virtual bool is_boolean() const noexcept = 0; - - /// \brief Returns true if this node is a local date value. - TOML_PURE_GETTER - virtual bool is_date() const noexcept = 0; - - /// \brief Returns true if this node is a local time value. - TOML_PURE_GETTER - virtual bool is_time() const noexcept = 0; - - /// \brief Returns true if this node is a date-time value. - TOML_PURE_GETTER - virtual bool is_date_time() const noexcept = 0; - - /// \brief Checks if a node is a specific type. - /// - /// \tparam T A TOML node or value type. - /// - /// \returns Returns true if this node is an instance of the specified type. - template <typename T> - TOML_PURE_INLINE_GETTER - bool is() const noexcept - { - using type = impl::remove_cvref<impl::unwrap_node<T>>; - static_assert(toml::is_value<type> || toml::is_container<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>) - return is_table(); - else if constexpr (std::is_same_v<type, array>) - return is_array(); - else if constexpr (std::is_same_v<type, std::string>) - return is_string(); - 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(); - } - - /// @} - - /// \name Type casts - /// @{ - - /// \brief Returns a pointer to the node as a toml::table, if it is one. - TOML_PURE_GETTER - virtual table* as_table() noexcept = 0; - - /// \brief Returns a pointer to the node as a toml::array, if it is one. - TOML_PURE_GETTER - virtual array* as_array() noexcept = 0; - - /// \brief Returns a pointer to the node as a toml::value<std::string>, if it is one. - TOML_PURE_GETTER - virtual toml::value<std::string>* as_string() noexcept = 0; - - /// \brief Returns a pointer to the node as a toml::value<int64_t>, if it is one. - TOML_PURE_GETTER - virtual toml::value<int64_t>* as_integer() noexcept = 0; - - /// \brief Returns a pointer to the node as a toml::value<double>, if it is one. - TOML_PURE_GETTER - virtual toml::value<double>* as_floating_point() noexcept = 0; - - /// \brief Returns a pointer to the node as a toml::value<bool>, if it is one. - TOML_PURE_GETTER - virtual toml::value<bool>* as_boolean() noexcept = 0; - - /// \brief Returns a pointer to the node as a toml::value<toml::date>, if it is one. - TOML_PURE_GETTER - virtual toml::value<date>* as_date() noexcept = 0; - - /// \brief Returns a pointer to the node as a toml::value<toml::time>, if it is one. - TOML_PURE_GETTER - virtual toml::value<time>* as_time() noexcept = 0; - - /// \brief Returns a pointer to the node as a toml::value<toml::date_time>, if it is one. - TOML_PURE_GETTER - virtual toml::value<date_time>* as_date_time() noexcept = 0; - - /// \brief Returns a const-qualified pointer to the node as a toml::table, if it is one. - TOML_PURE_GETTER - virtual const table* as_table() const noexcept = 0; - - /// \brief Returns a const-qualified pointer to the node as a toml::array, if it is one. - TOML_PURE_GETTER - virtual const array* as_array() const noexcept = 0; - - /// \brief Returns a const-qualified pointer to the node as a toml::value<std::string>, if it is one. - TOML_PURE_GETTER - virtual const toml::value<std::string>* as_string() const noexcept = 0; - - /// \brief Returns a const-qualified pointer to the node as a toml::value<int64_t>, if it is one. - TOML_PURE_GETTER - virtual const toml::value<int64_t>* as_integer() const noexcept = 0; - - /// \brief Returns a const-qualified pointer to the node as a toml::value<double>, if it is one. - TOML_PURE_GETTER - virtual const toml::value<double>* as_floating_point() const noexcept = 0; - - /// \brief Returns a const-qualified pointer to the node as a toml::value<bool>, if it is one. - TOML_PURE_GETTER - virtual const toml::value<bool>* as_boolean() const noexcept = 0; - - /// \brief Returns a const-qualified pointer to the node as a toml::value<toml::date>, if it is one. - TOML_PURE_GETTER - virtual const toml::value<date>* as_date() const noexcept = 0; - - /// \brief Returns a const-qualified pointer to the node as a toml::value<toml::time>, if it is one. - TOML_PURE_GETTER - virtual const toml::value<time>* as_time() const noexcept = 0; - - /// \brief Returns a const-qualified pointer to the node as a toml::value<toml::date_time>, if it is one. - TOML_PURE_GETTER - virtual const toml::value<date_time>* as_date_time() const noexcept = 0; - - /// \brief Gets a pointer to the node as a more specific node type. - /// - /// \details \cpp - /// - /// toml::value<int64_t>* int_value = node->as<int64_t>(); - /// toml::table* tbl = node->as<toml::table>(); - /// if (int_value) - /// std::cout << "Node is a value<int64_t>\n"; - /// else if (tbl) - /// std::cout << "Node is a table\n"; - /// - /// // fully-qualified value node types also work (useful for template code): - /// 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. - /// - /// \returns A pointer to the node as the given type, or nullptr if it was a different type. - template <typename T> - TOML_PURE_INLINE_GETTER - impl::wrap_node<T>* as() noexcept - { - 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<unwrapped_type, table>) - return as_table(); - else if constexpr (std::is_same_v<unwrapped_type, array>) - return as_array(); - else if constexpr (std::is_same_v<unwrapped_type, std::string>) - return as_string(); - else if constexpr (std::is_same_v<unwrapped_type, int64_t>) - return as_integer(); - else if constexpr (std::is_same_v<unwrapped_type, double>) - return as_floating_point(); - else if constexpr (std::is_same_v<unwrapped_type, bool>) - return as_boolean(); - else if constexpr (std::is_same_v<unwrapped_type, date>) - return as_date(); - else if constexpr (std::is_same_v<unwrapped_type, time>) - return as_time(); - else if constexpr (std::is_same_v<unwrapped_type, date_time>) - return as_date_time(); - } - - /// \brief Gets a pointer to the node as a more specific node type (const overload). - template <typename T> - TOML_PURE_INLINE_GETTER - const impl::wrap_node<T>* as() const noexcept - { - 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<unwrapped_type, table>) - return as_table(); - else if constexpr (std::is_same_v<unwrapped_type, array>) - return as_array(); - else if constexpr (std::is_same_v<unwrapped_type, std::string>) - return as_string(); - else if constexpr (std::is_same_v<unwrapped_type, int64_t>) - return as_integer(); - else if constexpr (std::is_same_v<unwrapped_type, double>) - return as_floating_point(); - else if constexpr (std::is_same_v<unwrapped_type, bool>) - return as_boolean(); - else if constexpr (std::is_same_v<unwrapped_type, date>) - return as_date(); - else if constexpr (std::is_same_v<unwrapped_type, time>) - return as_time(); - else if constexpr (std::is_same_v<unwrapped_type, date_time>) - return as_date_time(); - } - - /// @} - - /// \name Value retrieval - /// @{ - - /// \brief Gets the value contained by this node. - /// - /// \detail This function has 'exact' retrieval semantics; the only return value types allowed are the - /// TOML native value types, or types that can losslessly represent a native value type (e.g. - /// std::wstring on Windows). - /// - /// \tparam T One of the native TOML value types, or a type capable of losslessly representing one. - /// - /// \returns The underlying value if the node was a value of the - /// matching type (or losslessly convertible to it), or an empty optional. - /// - /// \see node::value() - template <typename T> - TOML_NODISCARD - optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>); - - /// \brief Gets the value contained by this node. - /// - /// \detail This function has 'permissive' retrieval semantics; some value types are allowed - /// to convert to others (e.g. retrieving a boolean as an integer), and the specified return value - /// type can be any type where a reasonable conversion from a native TOML value exists - /// (e.g. std::wstring on Windows). If the source value cannot be represented by - /// the destination type, an empty optional is returned. - /// - /// \godbolt{zzG81K} - /// - /// \cpp - /// auto tbl = toml::parse(R"( - /// int = -10 - /// flt = 25.0 - /// pi = 3.14159 - /// bool = false - /// huge = 9223372036854775807 - /// str = "foo" - /// )"sv); - /// - /// const auto print_value_with_typename = - /// [&](std::string_view key, std::string_view type_name, auto* dummy) - /// { - /// std::cout << "- " << std::setw(18) << std::left << type_name; - /// using type = std::remove_pointer_t<decltype(dummy)>; - /// if (auto val = tbl.get(key)->value<type>(); val) - /// std::cout << *val << "\n"; - /// else - /// std::cout << "n/a\n"; - /// }; - /// - /// #define print_value(key, T) print_value_with_typename(key, #T, (T*)nullptr) - /// - /// for (auto key : { "int", "flt", "pi", "bool", "huge", "str" }) - /// { - /// std::cout << tbl[key].type() << " value '" << key << "' as:\n"; - /// print_value(key, bool); - /// print_value(key, int); - /// print_value(key, unsigned int); - /// print_value(key, long long); - /// print_value(key, float); - /// print_value(key, double); - /// print_value(key, std::string); - /// print_value(key, std::string_view); - /// print_value(key, const char*); - /// std::cout << "\n"; - /// } - /// \ecpp - /// - /// \out - /// integer value 'int' as: - /// - bool true - /// - int -10 - /// - unsigned int n/a - /// - long long -10 - /// - float -10 - /// - double -10 - /// - std::string n/a - /// - std::string_view n/a - /// - const char* n/a - /// - /// floating-point value 'flt' as: - /// - bool n/a - /// - int 25 - /// - unsigned int 25 - /// - long long 25 - /// - float 25 - /// - double 25 - /// - std::string n/a - /// - std::string_view n/a - /// - const char* n/a - /// - /// floating-point value 'pi' as: - /// - bool n/a - /// - int n/a - /// - unsigned int n/a - /// - long long n/a - /// - float 3.14159 - /// - double 3.14159 - /// - std::string n/a - /// - std::string_view n/a - /// - const char* n/a - /// - /// boolean value 'bool' as: - /// - bool false - /// - int 0 - /// - unsigned int 0 - /// - long long 0 - /// - float n/a - /// - double n/a - /// - std::string n/a - /// - std::string_view n/a - /// - const char* n/a - /// - /// integer value 'huge' as: - /// - bool true - /// - int n/a - /// - unsigned int n/a - /// - long long 9223372036854775807 - /// - float n/a - /// - double n/a - /// - std::string n/a - /// - std::string_view n/a - /// - const char* n/a - /// - /// string value 'str' as: - /// - bool n/a - /// - int n/a - /// - unsigned int n/a - /// - long long n/a - /// - float n/a - /// - double n/a - /// - std::string foo - /// - std::string_view foo - /// - const char* foo - /// \eout - /// - /// \tparam T One of the native TOML value types, or a type capable of converting to one. - /// - /// \returns The underlying value if the node was a value of the matching type (or convertible to it) - /// and within the range of the output type, or an empty optional. - /// - /// \note If you want strict value retrieval semantics that do not allow for any type conversions, - /// use node::value_exact() instead. - /// - /// \see node::value_exact() - template <typename T> - TOML_NODISCARD - optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>); - - /// \brief Gets the raw value contained by this node, or a default. - /// - /// \tparam T Default value type. Must be one of the native TOML value types, - /// or convertible to it. - /// \param default_value The default value to return if the node wasn't a value, wasn't the - /// correct type, or no conversion was possible. - /// - /// \returns The underlying value if the node was a value of the matching type (or convertible to it) - /// and within the range of the output type, or the provided default. - /// - /// \note This function has the same permissive retrieval semantics as node::value(). If you want strict - /// value retrieval semantics that do not allow for any type conversions, use node::value_exact() - /// instead. - /// - /// \see - /// - node::value() - /// - node::value_exact() - template <typename T> - TOML_NODISCARD - auto value_or(T&& default_value) const noexcept(impl::value_retrieval_is_nothrow<T>); - - /// \brief Gets a raw reference to a node's underlying data. - /// - /// \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 - /// - /// auto tbl = toml::parse(R"( - /// min = 32 - /// max = 45 - /// )"sv); - /// - /// int64_t& min_ref = tbl.at("min").ref<int64_t>(); // matching type - /// double& max_ref = tbl.at("max").ref<double>(); // mismatched type, hits assert() - /// \ecpp - /// - /// \note Specifying explicit ref qualifiers acts as an explicit ref-category cast, - /// whereas specifying explicit cv-ref qualifiers merges them with whatever - /// the cv qualification of the node is (to ensure cv-correctness is propagated), e.g.: - /// | node | T | return type | - /// |-------------|------------------------|------------------------------| - /// | 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&& | - /// - /// \tparam T toml::table, toml::array, or one of the TOML value types. - /// - /// \returns A reference to the underlying data. - template <typename T> - TOML_PURE_GETTER - decltype(auto) ref() & noexcept - { - return do_ref<T>(*this); - } - - /// \brief Gets a raw reference to a node's underlying data (rvalue overload). - template <typename T> - TOML_PURE_GETTER - decltype(auto) ref() && noexcept - { - return do_ref<T>(std::move(*this)); - } - - /// \brief Gets a raw reference to a node's underlying data (const lvalue overload). - template <typename T> - TOML_PURE_GETTER - decltype(auto) ref() const& noexcept - { - return do_ref<T>(*this); - } - - /// \brief Gets a raw reference to a 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 - /// @{ - - /// \brief Returns the source region responsible for generating this node during parsing. - TOML_PURE_INLINE_GETTER - const source_region& source() const noexcept - { - return source_; - } - - /// @} - - private: - /// \cond - - template <typename Func, typename Node, typename T> - static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<T, Node>>; - - template <typename Func, typename Node, typename T> - static constexpr bool can_visit_nothrow = std::is_nothrow_invocable_v<Func, ref_cast_type<T, Node>>; - - template <typename Func, typename Node> - static constexpr bool can_visit_any = can_visit<Func, Node, table> // - || can_visit<Func, Node, array> // - || can_visit<Func, Node, std::string> // - || can_visit<Func, Node, int64_t> // - || can_visit<Func, Node, double> // - || can_visit<Func, Node, bool> // - || can_visit<Func, Node, date> // - || can_visit<Func, Node, time> // - || can_visit<Func, Node, date_time>; - - // clang-format off +TOML_NAMESPACE_START { + /// \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. + class TOML_ABSTRACT_INTERFACE TOML_EXPORTED_CLASS node { + private: + /// \cond + + friend class TOML_PARSER_TYPENAME; + source_region source_{}; + + template <typename T> + 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 ref_type<T, N&&> do_ref(N&& n) noexcept { + 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_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<out_ref>(const_cast<node_ref>(n).template ref_cast<val_type>()); + } + + protected: + TOML_EXPORTED_MEMBER_FUNCTION + node() noexcept; + + TOML_EXPORTED_MEMBER_FUNCTION + node(const node&) noexcept; + + TOML_EXPORTED_MEMBER_FUNCTION + node(node&&) noexcept; + + TOML_EXPORTED_MEMBER_FUNCTION + node& operator=(const node&) noexcept; + + TOML_EXPORTED_MEMBER_FUNCTION + 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 ref_cast_type<T, node&> ref_cast() & noexcept { + 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 ref_cast_type<T, node&&> ref_cast() && noexcept { + 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 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)); + } + + 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 + + public: + TOML_EXPORTED_MEMBER_FUNCTION + virtual ~node() noexcept; + + /// \name Type checks + /// @{ + + /// \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> + /// \conditional_return{toml::node_type::none} + /// "is every element the same type?" + /// \conditional_return{Anything else} + /// "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. + TOML_PURE_GETTER + 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). + TOML_PURE_GETTER + 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> + /// \conditional_return{toml::node_type::none} + /// "is every element the same type?" + /// \conditional_return{Anything else} + /// "is every element one of these?" + /// + /// \returns True if the node was homogeneous. + /// + /// \remarks Always returns `false` for empty tables and arrays. + TOML_PURE_GETTER + 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> + /// \conditional_return{Left as `void`} + /// "is every element the same type?" <br> + /// \conditional_return{Explicitly specified} + /// "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> + TOML_PURE_GETTER bool is_homogeneous() const noexcept { + using type = impl::remove_cvref<impl::unwrap_node<ElemType>>; + static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<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>); + } + + /// \brief Returns the node's type identifier. + TOML_PURE_GETTER + virtual node_type type() const noexcept = 0; + + /// \brief Returns true if this node is a table. + TOML_PURE_GETTER + virtual bool is_table() const noexcept = 0; + + /// \brief Returns true if this node is an array. + TOML_PURE_GETTER + virtual bool is_array() const noexcept = 0; + + /// \brief Returns true if this node is an array containing only tables. + TOML_PURE_GETTER + virtual bool is_array_of_tables() const noexcept = 0; + + /// \brief Returns true if this node is a value. + TOML_PURE_GETTER + virtual bool is_value() const noexcept = 0; + + /// \brief Returns true if this node is a string value. + TOML_PURE_GETTER + virtual bool is_string() const noexcept = 0; + + /// \brief Returns true if this node is an integer value. + TOML_PURE_GETTER + virtual bool is_integer() const noexcept = 0; + + /// \brief Returns true if this node is an floating-point value. + TOML_PURE_GETTER + virtual bool is_floating_point() const noexcept = 0; + + /// \brief Returns true if this node is an integer or floating-point value. + TOML_PURE_GETTER + virtual bool is_number() const noexcept = 0; + + /// \brief Returns true if this node is a boolean value. + TOML_PURE_GETTER + virtual bool is_boolean() const noexcept = 0; + + /// \brief Returns true if this node is a local date value. + TOML_PURE_GETTER + virtual bool is_date() const noexcept = 0; + + /// \brief Returns true if this node is a local time value. + TOML_PURE_GETTER + virtual bool is_time() const noexcept = 0; + + /// \brief Returns true if this node is a date-time value. + TOML_PURE_GETTER + virtual bool is_date_time() const noexcept = 0; + + /// \brief Checks if a node is a specific type. + /// + /// \tparam T A TOML node or value type. + /// + /// \returns Returns true if this node is an instance of the specified type. + template <typename T> + TOML_PURE_INLINE_GETTER bool is() const noexcept { + using type = impl::remove_cvref<impl::unwrap_node<T>>; + static_assert(toml::is_value<type> || toml::is_container<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>) + return is_table(); + else if constexpr (std::is_same_v<type, array>) + return is_array(); + else if constexpr (std::is_same_v<type, std::string>) + return is_string(); + 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(); + } + + /// @} + + /// \name Type casts + /// @{ + + /// \brief Returns a pointer to the node as a toml::table, if it is one. + TOML_PURE_GETTER + virtual table* as_table() noexcept = 0; + + /// \brief Returns a pointer to the node as a toml::array, if it is one. + TOML_PURE_GETTER + virtual array* as_array() noexcept = 0; + + /// \brief Returns a pointer to the node as a toml::value<std::string>, if it is one. + TOML_PURE_GETTER + virtual toml::value<std::string>* as_string() noexcept = 0; + + /// \brief Returns a pointer to the node as a toml::value<int64_t>, if it is one. + TOML_PURE_GETTER + virtual toml::value<int64_t>* as_integer() noexcept = 0; + + /// \brief Returns a pointer to the node as a toml::value<double>, if it is one. + TOML_PURE_GETTER + virtual toml::value<double>* as_floating_point() noexcept = 0; + + /// \brief Returns a pointer to the node as a toml::value<bool>, if it is one. + TOML_PURE_GETTER + virtual toml::value<bool>* as_boolean() noexcept = 0; + + /// \brief Returns a pointer to the node as a toml::value<toml::date>, if it is one. + TOML_PURE_GETTER + virtual toml::value<date>* as_date() noexcept = 0; + + /// \brief Returns a pointer to the node as a toml::value<toml::time>, if it is one. + TOML_PURE_GETTER + virtual toml::value<time>* as_time() noexcept = 0; + + /// \brief Returns a pointer to the node as a toml::value<toml::date_time>, if it is one. + TOML_PURE_GETTER + virtual toml::value<date_time>* as_date_time() noexcept = 0; + + /// \brief Returns a const-qualified pointer to the node as a toml::table, if it is one. + TOML_PURE_GETTER + virtual const table* as_table() const noexcept = 0; + + /// \brief Returns a const-qualified pointer to the node as a toml::array, if it is one. + TOML_PURE_GETTER + virtual const array* as_array() const noexcept = 0; + + /// \brief Returns a const-qualified pointer to the node as a toml::value<std::string>, if it + /// is one. + TOML_PURE_GETTER + virtual const toml::value<std::string>* as_string() const noexcept = 0; + + /// \brief Returns a const-qualified pointer to the node as a toml::value<int64_t>, if it is + /// one. + TOML_PURE_GETTER + virtual const toml::value<int64_t>* as_integer() const noexcept = 0; + + /// \brief Returns a const-qualified pointer to the node as a toml::value<double>, if it is + /// one. + TOML_PURE_GETTER + virtual const toml::value<double>* as_floating_point() const noexcept = 0; + + /// \brief Returns a const-qualified pointer to the node as a toml::value<bool>, if it is one. + TOML_PURE_GETTER + virtual const toml::value<bool>* as_boolean() const noexcept = 0; + + /// \brief Returns a const-qualified pointer to the node as a toml::value<toml::date>, if it is + /// one. + TOML_PURE_GETTER + virtual const toml::value<date>* as_date() const noexcept = 0; + + /// \brief Returns a const-qualified pointer to the node as a toml::value<toml::time>, if it is + /// one. + TOML_PURE_GETTER + virtual const toml::value<time>* as_time() const noexcept = 0; + + /// \brief Returns a const-qualified pointer to the node as a toml::value<toml::date_time>, if + /// it is one. + TOML_PURE_GETTER + virtual const toml::value<date_time>* as_date_time() const noexcept = 0; + + /// \brief Gets a pointer to the node as a more specific node type. + /// + /// \details \cpp + /// + /// toml::value<int64_t>* int_value = node->as<int64_t>(); + /// toml::table* tbl = node->as<toml::table>(); + /// if (int_value) + /// std::cout << "Node is a value<int64_t>\n"; + /// else if (tbl) + /// std::cout << "Node is a table\n"; + /// + /// // fully-qualified value node types also work (useful for template code): + /// 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. + /// + /// \returns A pointer to the node as the given type, or nullptr if it was a different type. + template <typename T> + TOML_PURE_INLINE_GETTER impl::wrap_node<T>* as() noexcept { + 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<unwrapped_type, table>) + return as_table(); + else if constexpr (std::is_same_v<unwrapped_type, array>) + return as_array(); + else if constexpr (std::is_same_v<unwrapped_type, std::string>) + return as_string(); + else if constexpr (std::is_same_v<unwrapped_type, int64_t>) + return as_integer(); + else if constexpr (std::is_same_v<unwrapped_type, double>) + return as_floating_point(); + else if constexpr (std::is_same_v<unwrapped_type, bool>) + return as_boolean(); + else if constexpr (std::is_same_v<unwrapped_type, date>) + return as_date(); + else if constexpr (std::is_same_v<unwrapped_type, time>) + return as_time(); + else if constexpr (std::is_same_v<unwrapped_type, date_time>) + return as_date_time(); + } + + /// \brief Gets a pointer to the node as a more specific node type (const overload). + template <typename T> + TOML_PURE_INLINE_GETTER const impl::wrap_node<T>* as() const noexcept { + 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<unwrapped_type, table>) + return as_table(); + else if constexpr (std::is_same_v<unwrapped_type, array>) + return as_array(); + else if constexpr (std::is_same_v<unwrapped_type, std::string>) + return as_string(); + else if constexpr (std::is_same_v<unwrapped_type, int64_t>) + return as_integer(); + else if constexpr (std::is_same_v<unwrapped_type, double>) + return as_floating_point(); + else if constexpr (std::is_same_v<unwrapped_type, bool>) + return as_boolean(); + else if constexpr (std::is_same_v<unwrapped_type, date>) + return as_date(); + else if constexpr (std::is_same_v<unwrapped_type, time>) + return as_time(); + else if constexpr (std::is_same_v<unwrapped_type, date_time>) + return as_date_time(); + } + + /// @} + + /// \name Value retrieval + /// @{ + + /// \brief Gets the value contained by this node. + /// + /// \detail This function has 'exact' retrieval semantics; the only return value types allowed + /// are the TOML native value types, or types that can losslessly represent a native value type + /// (e.g. std::wstring on Windows). + /// + /// \tparam T One of the native TOML value types, or a type capable of losslessly representing + /// one. + /// + /// \returns The underlying value if the node was a value of the + /// matching type (or losslessly convertible to it), or an empty optional. + /// + /// \see node::value() + template <typename T> + TOML_NODISCARD optional<T> value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>); + + /// \brief Gets the value contained by this node. + /// + /// \detail This function has 'permissive' retrieval semantics; some value types are allowed + /// to convert to others (e.g. retrieving a boolean as an integer), and the specified return + /// value type can be any type where a reasonable conversion from a native TOML value exists + /// (e.g. std::wstring on Windows). If the source value cannot be represented by + /// the destination type, an empty optional is returned. + /// + /// \godbolt{zzG81K} + /// + /// \cpp + /// auto tbl = toml::parse(R"( + /// int = -10 + /// flt = 25.0 + /// pi = 3.14159 + /// bool = false + /// huge = 9223372036854775807 + /// str = "foo" + /// )"sv); + /// + /// const auto print_value_with_typename = + /// [&](std::string_view key, std::string_view type_name, auto* dummy) + /// { + /// std::cout << "- " << std::setw(18) << std::left << type_name; + /// using type = std::remove_pointer_t<decltype(dummy)>; + /// if (auto val = tbl.get(key)->value<type>(); val) + /// std::cout << *val << "\n"; + /// else + /// std::cout << "n/a\n"; + /// }; + /// + /// #define print_value(key, T) print_value_with_typename(key, #T, (T*)nullptr) + /// + /// for (auto key : { "int", "flt", "pi", "bool", "huge", "str" }) + /// { + /// std::cout << tbl[key].type() << " value '" << key << "' as:\n"; + /// print_value(key, bool); + /// print_value(key, int); + /// print_value(key, unsigned int); + /// print_value(key, long long); + /// print_value(key, float); + /// print_value(key, double); + /// print_value(key, std::string); + /// print_value(key, std::string_view); + /// print_value(key, const char*); + /// std::cout << "\n"; + /// } + /// \ecpp + /// + /// \out + /// integer value 'int' as: + /// - bool true + /// - int -10 + /// - unsigned int n/a + /// - long long -10 + /// - float -10 + /// - double -10 + /// - std::string n/a + /// - std::string_view n/a + /// - const char* n/a + /// + /// floating-point value 'flt' as: + /// - bool n/a + /// - int 25 + /// - unsigned int 25 + /// - long long 25 + /// - float 25 + /// - double 25 + /// - std::string n/a + /// - std::string_view n/a + /// - const char* n/a + /// + /// floating-point value 'pi' as: + /// - bool n/a + /// - int n/a + /// - unsigned int n/a + /// - long long n/a + /// - float 3.14159 + /// - double 3.14159 + /// - std::string n/a + /// - std::string_view n/a + /// - const char* n/a + /// + /// boolean value 'bool' as: + /// - bool false + /// - int 0 + /// - unsigned int 0 + /// - long long 0 + /// - float n/a + /// - double n/a + /// - std::string n/a + /// - std::string_view n/a + /// - const char* n/a + /// + /// integer value 'huge' as: + /// - bool true + /// - int n/a + /// - unsigned int n/a + /// - long long 9223372036854775807 + /// - float n/a + /// - double n/a + /// - std::string n/a + /// - std::string_view n/a + /// - const char* n/a + /// + /// string value 'str' as: + /// - bool n/a + /// - int n/a + /// - unsigned int n/a + /// - long long n/a + /// - float n/a + /// - double n/a + /// - std::string foo + /// - std::string_view foo + /// - const char* foo + /// \eout + /// + /// \tparam T One of the native TOML value types, or a type capable of converting to one. + /// + /// \returns The underlying value if the node was a value of the matching type (or convertible + /// to it) and within the range of the output type, or an empty optional. + /// + /// \note If you want strict value retrieval semantics that do not allow for any type + /// conversions, use node::value_exact() instead. + /// + /// \see node::value_exact() + template <typename T> + TOML_NODISCARD optional<T> value() const noexcept(impl::value_retrieval_is_nothrow<T>); + + /// \brief Gets the raw value contained by this node, or a default. + /// + /// \tparam T Default value type. Must be one of the native TOML value types, + /// or convertible to it. + /// \param default_value The default value to return if the node wasn't a value, wasn't the + /// correct type, or no conversion was possible. + /// + /// \returns The underlying value if the node was a value of the matching type (or convertible + /// to it) and within the range of the output type, or the provided default. + /// + /// \note This function has the same permissive retrieval semantics as node::value(). If you + /// want strict value retrieval semantics that do not allow for any type conversions, use + /// node::value_exact() instead. + /// + /// \see + /// - node::value() + /// - node::value_exact() + template <typename T> + TOML_NODISCARD auto value_or(T&& default_value) const + noexcept(impl::value_retrieval_is_nothrow<T>); + + /// \brief Gets a raw reference to a node's underlying data. + /// + /// \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 + /// + /// auto tbl = toml::parse(R"( + /// min = 32 + /// max = 45 + /// )"sv); + /// + /// int64_t& min_ref = tbl.at("min").ref<int64_t>(); // matching type + /// double& max_ref = tbl.at("max").ref<double>(); // mismatched type, hits assert() + /// \ecpp + /// + /// \note Specifying explicit ref qualifiers acts as an explicit ref-category cast, + /// whereas specifying explicit cv-ref qualifiers merges them with whatever + /// the cv qualification of the node is (to ensure cv-correctness is propagated), e.g.: + /// | node | T | return type | + /// |-------------|------------------------|------------------------------| + /// | 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&& | + /// + /// \tparam T toml::table, toml::array, or one of the TOML value types. + /// + /// \returns A reference to the underlying data. + template <typename T> + TOML_PURE_GETTER decltype(auto) ref() & noexcept { + return do_ref<T>(*this); + } + + /// \brief Gets a raw reference to a node's underlying data (rvalue overload). + template <typename T> + TOML_PURE_GETTER decltype(auto) ref() && noexcept { + return do_ref<T>(std::move(*this)); + } + + /// \brief Gets a raw reference to a node's underlying data (const lvalue overload). + template <typename T> + TOML_PURE_GETTER decltype(auto) ref() const& noexcept { + return do_ref<T>(*this); + } + + /// \brief Gets a raw reference to a 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 + /// @{ + + /// \brief Returns the source region responsible for generating this node during parsing. + TOML_PURE_INLINE_GETTER + const source_region& source() const noexcept { return source_; } + + /// @} + + private: + /// \cond + + template <typename Func, typename Node, typename T> + static constexpr bool can_visit = std::is_invocable_v<Func, ref_cast_type<T, Node>>; + + template <typename Func, typename Node, typename T> + static constexpr bool can_visit_nothrow = + std::is_nothrow_invocable_v<Func, ref_cast_type<T, Node>>; + + template <typename Func, typename Node> + static constexpr bool can_visit_any = can_visit<Func, Node, table> // + || can_visit<Func, Node, array> // + || can_visit<Func, Node, std::string> // + || can_visit<Func, Node, int64_t> // + || can_visit<Func, Node, double> // + || can_visit<Func, Node, bool> // + || can_visit<Func, Node, date> // + || can_visit<Func, Node, time> // + || can_visit<Func, Node, date_time>; + + // clang-format off template <typename Func, typename Node> static constexpr bool can_visit_all = can_visit<Func, Node, table> // @@ -775,86 +754,87 @@ TOML_NAMESPACE_START && visit_is_nothrow_one<Func, Node, time> // && visit_is_nothrow_one<Func, Node, date_time>; - // clang-format on - - template <typename Func, typename Node, typename T, bool = can_visit<Func, Node, T>> - struct visit_return_type_ - { - using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<T, Node>>())); - }; - template <typename Func, typename Node, typename T> - struct visit_return_type_<Func, Node, T, false> - { - using type = void; - }; - - template <typename Func, typename Node, typename T> - using visit_return_type = typename visit_return_type_<Func, Node, T>::type; - - template <typename A, typename B> - using nonvoid = std::conditional_t<std::is_void_v<A>, B, A>; - - template <typename Func, typename Node> - static decltype(auto) do_visit(Func&& visitor, Node&& n) noexcept(visit_is_nothrow<Func&&, Node&&>) - { - static_assert(can_visit_any<Func&&, Node&&>, - "TOML node visitors must be invocable for at least one of the toml::node " - "specializations:" TOML_SA_NODE_TYPE_LIST); - - switch (n.type()) - { - case node_type::table: - if constexpr (can_visit<Func&&, Node&&, table>) - return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<table>()); - break; - - case node_type::array: - if constexpr (can_visit<Func&&, Node&&, array>) - return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<array>()); - break; - - case node_type::string: - if constexpr (can_visit<Func&&, Node&&, std::string>) - return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<std::string>()); - break; - - case node_type::integer: - if constexpr (can_visit<Func&&, Node&&, int64_t>) - return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<int64_t>()); - break; - - case node_type::floating_point: - if constexpr (can_visit<Func&&, Node&&, double>) - return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<double>()); - break; - - case node_type::boolean: - if constexpr (can_visit<Func&&, Node&&, bool>) - return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<bool>()); - break; - - case node_type::date: - if constexpr (can_visit<Func&&, Node&&, date>) - return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<date>()); - break; - - case node_type::time: - if constexpr (can_visit<Func&&, Node&&, time>) - return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<time>()); - break; - - case node_type::date_time: - if constexpr (can_visit<Func&&, Node&&, date_time>) - return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<date_time>()); - break; - - case node_type::none: TOML_UNREACHABLE; - default: TOML_UNREACHABLE; - } - - if constexpr (!can_visit_all<Func&&, Node&&>) - { - // clang-format off + // clang-format on + + template <typename Func, typename Node, typename T, bool = can_visit<Func, Node, T>> + struct visit_return_type_ { + using type = decltype(std::declval<Func>()(std::declval<ref_cast_type<T, Node>>())); + }; + template <typename Func, typename Node, typename T> + struct visit_return_type_<Func, Node, T, false> { + using type = void; + }; + + template <typename Func, typename Node, typename T> + using visit_return_type = typename visit_return_type_<Func, Node, T>::type; + + template <typename A, typename B> + using nonvoid = std::conditional_t<std::is_void_v<A>, B, A>; + + template <typename Func, typename Node> + static decltype(auto) do_visit(Func&& visitor, + Node&& n) noexcept(visit_is_nothrow<Func&&, Node&&>) { + static_assert(can_visit_any<Func&&, Node&&>, + "TOML node visitors must be invocable for at least one of the toml::node " + "specializations:" TOML_SA_NODE_TYPE_LIST); + + switch (n.type()) { + case node_type::table: + if constexpr (can_visit<Func&&, Node&&, table>) + return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<table>()); + break; + + case node_type::array: + if constexpr (can_visit<Func&&, Node&&, array>) + return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<array>()); + break; + + case node_type::string: + if constexpr (can_visit<Func&&, Node&&, std::string>) + return static_cast<Func&&>(visitor)( + static_cast<Node&&>(n).template ref_cast<std::string>()); + break; + + case node_type::integer: + if constexpr (can_visit<Func&&, Node&&, int64_t>) + return static_cast<Func&&>(visitor)( + static_cast<Node&&>(n).template ref_cast<int64_t>()); + break; + + case node_type::floating_point: + if constexpr (can_visit<Func&&, Node&&, double>) + return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<double>()); + break; + + case node_type::boolean: + if constexpr (can_visit<Func&&, Node&&, bool>) + return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<bool>()); + break; + + case node_type::date: + if constexpr (can_visit<Func&&, Node&&, date>) + return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<date>()); + break; + + case node_type::time: + if constexpr (can_visit<Func&&, Node&&, time>) + return static_cast<Func&&>(visitor)(static_cast<Node&&>(n).template ref_cast<time>()); + break; + + case node_type::date_time: + if constexpr (can_visit<Func&&, Node&&, date_time>) + return static_cast<Func&&>(visitor)( + static_cast<Node&&>(n).template ref_cast<date_time>()); + break; + + case node_type::none: + TOML_UNREACHABLE; + default: + TOML_UNREACHABLE; + } + + if constexpr (!can_visit_all<Func&&, Node&&>) { + // clang-format off using return_type = nonvoid<visit_return_type<Func&&, Node&&, table>, @@ -868,246 +848,244 @@ TOML_NAMESPACE_START visit_return_type<Func&&, Node&&, date_time> >>>>>>>>; - // clang-format on - - 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{}; - } - } - } - - /// \endcond - - public: - /// \name Visitation - /// @{ - - /// \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)>) - /// do_something_with_a_string(*n)); //n is a toml::value<std::string> - /// else if constexpr (toml::is_integer<decltype(n)>) - /// do_something_with_an_int(*n); //n is a toml::value<int64_t> - /// }); - /// \ecpp - /// - /// Visitor functions need not be generic; specifying a concrete node type as the input argument type - /// effectively acts a 'filter', only invoking the visitor if the concrete type is compatible. - /// Thus the example above can be re-written as: \cpp - /// node.visit([](toml::value<std::string>& s) { do_something_with_a_string(*s)); }); - /// node.visit([](toml::value<int64_t>& i) { do_something_with_an_int(*i)); }); - /// \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. - /// Can be void. Non-exhaustive visitors must return a default-constructible type. - /// - /// \see https://en.wikipedia.org/wiki/Visitor_pattern - template <typename Func> - decltype(auto) visit(Func&& visitor) & noexcept(visit_is_nothrow<Func&&, node&>) - { - return do_visit(static_cast<Func&&>(visitor), *this); - } - - /// \brief Invokes a visitor on the node based on the node's concrete type (rvalue overload). - template <typename Func> - decltype(auto) visit(Func&& visitor) && noexcept(visit_is_nothrow<Func&&, node&&>) - { - return do_visit(static_cast<Func&&>(visitor), static_cast<node&&>(*this)); - } - - /// \brief Invokes a visitor on the node based on the node's concrete type (const lvalue overload). - template <typename Func> - decltype(auto) visit(Func&& visitor) const& noexcept(visit_is_nothrow<Func&&, const node&>) - { - return do_visit(static_cast<Func&&>(visitor), *this); - } - - /// \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<Func&&>(visitor), static_cast<const node&&>(*this)); - } - - /// @} - - /// \name Node views - /// @{ - - /// \brief Creates a node_view pointing to this node. - TOML_NODISCARD - explicit operator node_view<node>() noexcept; - - /// \brief Creates a node_view pointing to this node (const overload). - TOML_NODISCARD - explicit operator node_view<const node>() const noexcept; - - /// \brief Returns a view of the subnode matching a fully-qualified "TOML path". - /// - /// \detail \cpp - /// auto config = toml::parse(R"( - /// - /// [foo] - /// bar = [ 0, 1, 2, [ 3 ], { kek = 4 } ] - /// - /// )"sv); - /// - /// std::cout << config.at_path("foo.bar[2]") << "\n"; - /// std::cout << config.at_path("foo.bar[3][0]") << "\n"; - /// std::cout << config.at_path("foo.bar[4].kek") << "\n"; - /// \ecpp - /// - /// \out - /// 2 - /// 3 - /// 4 - /// \eout - /// - /// - /// \note Keys in paths are interpreted literally, so whitespace (or lack thereof) matters: - /// \cpp - /// config.at_path( "foo.bar") // same as node_view{ config }["foo"]["bar"] - /// config.at_path( "foo. bar") // same as node_view{ config }["foo"][" bar"] - /// config.at_path( "foo..bar") // same as node_view{ config }["foo"][""]["bar"] - /// config.at_path( ".foo.bar") // same as node_view{ config }[""]["foo"]["bar"] - /// \ecpp - /// <br> - /// Additionally, TOML allows '.' (period) characters to appear in keys if they are quoted strings. - /// This function makes no allowance for this, instead treating all period characters as sub-table delimiters. - /// If you have periods in your table keys, first consider: - /// 1. Not doing that - /// 2. Using node_view::operator[] instead. - /// - /// \param path The "TOML path" to traverse. - TOML_NODISCARD - TOML_EXPORTED_MEMBER_FUNCTION - node_view<node> at_path(std::string_view path) noexcept; - - /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path". - /// - /// \see #at_path(std::string_view) - TOML_NODISCARD - TOML_EXPORTED_MEMBER_FUNCTION - node_view<const node> at_path(std::string_view path) const noexcept; - - /// \brief Returns a view of the subnode matching a fully-qualified "TOML path". - /// - /// \detail \cpp - /// auto config = toml::parse(R"( - /// - /// [foo] - /// bar = [ 0, 1, 2, [ 3 ], { kek = 4 } ] - /// - /// )"sv); - /// - /// toml::path path1("foo.bar[2]"); - /// toml::path path2("foo.bar[4].kek"); - /// std::cout << config.at_path(path1) << "\n"; - /// std::cout << config.at_path(path1.parent_path()) << "\n"; - /// std::cout << config.at_path(path2) << "\n"; - /// std::cout << config.at_path(path2.parent_path()) << "\n"; - /// \ecpp - /// - /// \out - /// 2 - /// [ 0, 1, 2, [ 3 ], { kek = 4 } ] - /// 4 - /// { kek = 4 } - /// \eout - /// - /// - /// \note Keys in paths are interpreted literally, so whitespace (or lack thereof) matters: - /// \cpp - /// config.at_path(toml::path("foo.bar")) // same as node_view{ config }["foo"]["bar"] - /// config.at_path(toml::path("foo. bar")) // same as node_view{ config }["foo"][" bar"] - /// config.at_path(toml::path("foo..bar")) // same as node_view{ config }["foo"][""]["bar"] - /// config.at_path(toml::path(".foo.bar")) // same as node_view{ config }[""]["foo"]["bar"] - /// \ecpp - /// <br> - /// Additionally, TOML allows '.' (period) characters to appear in keys if they are quoted strings. - /// This function makes no allowance for this, instead treating all period characters as sub-table delimiters. - /// - /// \param path The "TOML path" to traverse. - TOML_NODISCARD - TOML_EXPORTED_MEMBER_FUNCTION - node_view<node> at_path(const toml::path& path) noexcept; - - /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path". - /// - /// \see #at_path(const toml::path&) - TOML_NODISCARD - TOML_EXPORTED_MEMBER_FUNCTION - node_view<const node> at_path(const toml::path& path) const noexcept; + // clang-format on + + 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{}; + } + } + } + + /// \endcond + + public: + /// \name Visitation + /// @{ + + /// \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)>) + /// do_something_with_a_string(*n)); //n is a toml::value<std::string> + /// else if constexpr (toml::is_integer<decltype(n)>) + /// do_something_with_an_int(*n); //n is a toml::value<int64_t> + /// }); + /// \ecpp + /// + /// Visitor functions need not be generic; specifying a concrete node type as the input argument + /// type effectively acts a 'filter', only invoking the visitor if the concrete type is + /// compatible. Thus the example above can be re-written as: \cpp + /// node.visit([](toml::value<std::string>& s) { do_something_with_a_string(*s)); }); + /// node.visit([](toml::value<int64_t>& i) { do_something_with_an_int(*i)); }); + /// \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. + /// Can be void. Non-exhaustive visitors must return a default-constructible type. + /// + /// \see https://en.wikipedia.org/wiki/Visitor_pattern + template <typename Func> + decltype(auto) visit(Func&& visitor) & noexcept(visit_is_nothrow<Func&&, node&>) { + return do_visit(static_cast<Func&&>(visitor), *this); + } + + /// \brief Invokes a visitor on the node based on the node's concrete type (rvalue overload). + template <typename Func> + decltype(auto) visit(Func&& visitor) && noexcept(visit_is_nothrow<Func&&, node&&>) { + return do_visit(static_cast<Func&&>(visitor), static_cast<node&&>(*this)); + } + + /// \brief Invokes a visitor on the node based on the node's concrete type (const lvalue + /// overload). + template <typename Func> + decltype(auto) visit(Func&& visitor) const& noexcept(visit_is_nothrow<Func&&, const node&>) { + return do_visit(static_cast<Func&&>(visitor), *this); + } + + /// \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<Func&&>(visitor), static_cast<const node&&>(*this)); + } + + /// @} + + /// \name Node views + /// @{ + + /// \brief Creates a node_view pointing to this node. + TOML_NODISCARD + explicit operator node_view<node>() noexcept; + + /// \brief Creates a node_view pointing to this node (const overload). + TOML_NODISCARD + explicit operator node_view<const node>() const noexcept; + + /// \brief Returns a view of the subnode matching a fully-qualified "TOML path". + /// + /// \detail \cpp + /// auto config = toml::parse(R"( + /// + /// [foo] + /// bar = [ 0, 1, 2, [ 3 ], { kek = 4 } ] + /// + /// )"sv); + /// + /// std::cout << config.at_path("foo.bar[2]") << "\n"; + /// std::cout << config.at_path("foo.bar[3][0]") << "\n"; + /// std::cout << config.at_path("foo.bar[4].kek") << "\n"; + /// \ecpp + /// + /// \out + /// 2 + /// 3 + /// 4 + /// \eout + /// + /// + /// \note Keys in paths are interpreted literally, so whitespace (or lack thereof) matters: + /// \cpp + /// config.at_path( "foo.bar") // same as node_view{ config }["foo"]["bar"] + /// config.at_path( "foo. bar") // same as node_view{ config }["foo"][" bar"] + /// config.at_path( "foo..bar") // same as node_view{ config }["foo"][""]["bar"] + /// config.at_path( ".foo.bar") // same as node_view{ config }[""]["foo"]["bar"] + /// \ecpp + /// <br> + /// Additionally, TOML allows '.' (period) characters to appear in keys if they are quoted + /// strings. This function makes no allowance for this, instead treating all period characters + /// as sub-table delimiters. If you have periods in your table keys, first consider: + /// 1. Not doing that + /// 2. Using node_view::operator[] instead. + /// + /// \param path The "TOML path" to traverse. + TOML_NODISCARD + TOML_EXPORTED_MEMBER_FUNCTION + node_view<node> at_path(std::string_view path) noexcept; + + /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path". + /// + /// \see #at_path(std::string_view) + TOML_NODISCARD + TOML_EXPORTED_MEMBER_FUNCTION + node_view<const node> at_path(std::string_view path) const noexcept; + + /// \brief Returns a view of the subnode matching a fully-qualified "TOML path". + /// + /// \detail \cpp + /// auto config = toml::parse(R"( + /// + /// [foo] + /// bar = [ 0, 1, 2, [ 3 ], { kek = 4 } ] + /// + /// )"sv); + /// + /// toml::path path1("foo.bar[2]"); + /// toml::path path2("foo.bar[4].kek"); + /// std::cout << config.at_path(path1) << "\n"; + /// std::cout << config.at_path(path1.parent_path()) << "\n"; + /// std::cout << config.at_path(path2) << "\n"; + /// std::cout << config.at_path(path2.parent_path()) << "\n"; + /// \ecpp + /// + /// \out + /// 2 + /// [ 0, 1, 2, [ 3 ], { kek = 4 } ] + /// 4 + /// { kek = 4 } + /// \eout + /// + /// + /// \note Keys in paths are interpreted literally, so whitespace (or lack thereof) matters: + /// \cpp + /// config.at_path(toml::path("foo.bar")) // same as node_view{ config }["foo"]["bar"] + /// config.at_path(toml::path("foo. bar")) // same as node_view{ config }["foo"][" bar"] + /// config.at_path(toml::path("foo..bar")) // same as node_view{ config }["foo"][""]["bar"] + /// config.at_path(toml::path(".foo.bar")) // same as node_view{ config }[""]["foo"]["bar"] + /// \ecpp + /// <br> + /// Additionally, TOML allows '.' (period) characters to appear in keys if they are quoted + /// strings. This function makes no allowance for this, instead treating all period characters + /// as sub-table delimiters. + /// + /// \param path The "TOML path" to traverse. + TOML_NODISCARD + TOML_EXPORTED_MEMBER_FUNCTION + node_view<node> at_path(const toml::path& path) noexcept; + + /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path". + /// + /// \see #at_path(const toml::path&) + TOML_NODISCARD + TOML_EXPORTED_MEMBER_FUNCTION + node_view<const node> at_path(const toml::path& path) const noexcept; #if TOML_ENABLE_WINDOWS_COMPAT - /// \brief Returns a view of the subnode matching a fully-qualified "TOML path". - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \see #at_path(std::string_view) - TOML_NODISCARD - TOML_EXPORTED_MEMBER_FUNCTION - node_view<node> at_path(std::wstring_view path); - - /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path". - /// - /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. - /// - /// \see #at_path(std::string_view) - TOML_NODISCARD - TOML_EXPORTED_MEMBER_FUNCTION - node_view<const node> at_path(std::wstring_view path) const; - -#endif // TOML_ENABLE_WINDOWS_COMPAT - - /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path". - /// - /// \param path The "TOML path" to the desired child. - /// - /// \returns A view of the child node at the given path if one existed, or an empty node view. - /// - /// \see toml::node_view - TOML_NODISCARD - TOML_EXPORTED_MEMBER_FUNCTION - node_view<node> operator[](const toml::path& path) noexcept; - - /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path". - /// - /// \param path The "TOML path" to the desired child. - /// - /// \returns A view of the child node at the given path if one existed, or an empty node view. - /// - /// \see toml::node_view - TOML_NODISCARD - TOML_EXPORTED_MEMBER_FUNCTION - node_view<const node> operator[](const toml::path& path) const noexcept; - - /// @} - }; + /// \brief Returns a view of the subnode matching a fully-qualified "TOML path". + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \see #at_path(std::string_view) + TOML_NODISCARD + TOML_EXPORTED_MEMBER_FUNCTION + node_view<node> at_path(std::wstring_view path); + + /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path". + /// + /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled. + /// + /// \see #at_path(std::string_view) + TOML_NODISCARD + TOML_EXPORTED_MEMBER_FUNCTION + node_view<const node> at_path(std::wstring_view path) const; + +#endif // TOML_ENABLE_WINDOWS_COMPAT + + /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path". + /// + /// \param path The "TOML path" to the desired child. + /// + /// \returns A view of the child node at the given path if one existed, or an empty node view. + /// + /// \see toml::node_view + TOML_NODISCARD + TOML_EXPORTED_MEMBER_FUNCTION + node_view<node> operator[](const toml::path& path) noexcept; + + /// \brief Returns a const view of the subnode matching a fully-qualified "TOML path". + /// + /// \param path The "TOML path" to the desired child. + /// + /// \returns A view of the child node at the given path if one existed, or an empty node view. + /// + /// \see toml::node_view + TOML_NODISCARD + TOML_EXPORTED_MEMBER_FUNCTION + node_view<const node> operator[](const toml::path& path) const noexcept; + + /// @} + }; } TOML_NAMESPACE_END; /// \cond -TOML_IMPL_NAMESPACE_START -{ - TOML_PURE_GETTER - TOML_EXPORTED_FREE_FUNCTION - bool TOML_CALLCONV node_deep_equality(const node*, const node*) noexcept; +TOML_IMPL_NAMESPACE_START { + TOML_PURE_GETTER + TOML_EXPORTED_FREE_FUNCTION + bool TOML_CALLCONV node_deep_equality(const node*, const node*) noexcept; } TOML_IMPL_NAMESPACE_END; /// \endcond |
