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/value.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/value.hpp')
| -rw-r--r-- | vendor/toml++/impl/value.hpp | 1964 |
1 files changed, 859 insertions, 1105 deletions
diff --git a/vendor/toml++/impl/value.hpp b/vendor/toml++/impl/value.hpp index 6fb35dc..964e90d 100644 --- a/vendor/toml++/impl/value.hpp +++ b/vendor/toml++/impl/value.hpp @@ -1,14 +1,14 @@ -//# 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 "date_time.hpp" +#include "header_start.hpp" #include "node.hpp" #include "print_to_stream.hpp" #include "std_utility.hpp" -#include "header_start.hpp" TOML_DISABLE_ARITHMETIC_WARNINGS; /// \cond @@ -74,1136 +74,892 @@ TOML_DISABLE_ARITHMETIC_WARNINGS; /// \endcond /// \cond -TOML_IMPL_NAMESPACE_START -{ - template <typename T, typename...> - struct native_value_maker - { - template <typename... Args> - TOML_NODISCARD - static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args&&...>) - { - if constexpr (std::is_aggregate_v<T>) - return T{ static_cast<Args&&>(args)... }; - else - return T(static_cast<Args&&>(args)...); - } - }; - - template <typename T> - struct native_value_maker<T, T> - { - template <typename U> - TOML_NODISCARD - TOML_ALWAYS_INLINE - static U&& make(U&& val) noexcept - { - return static_cast<U&&>(val); - } - }; +TOML_IMPL_NAMESPACE_START { + template <typename T, typename...> + struct native_value_maker { + template <typename... Args> + TOML_NODISCARD static T make(Args&&... args) noexcept( + std::is_nothrow_constructible_v<T, Args&&...>) { + if constexpr (std::is_aggregate_v<T>) + return T{static_cast<Args&&>(args)...}; + else + return T(static_cast<Args&&>(args)...); + } + }; + + template <typename T> + struct native_value_maker<T, T> { + template <typename U> + TOML_NODISCARD TOML_ALWAYS_INLINE static U&& make(U&& val) noexcept { + return static_cast<U&&>(val); + } + }; #if TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT - struct string_maker - { - template <typename T> - TOML_NODISCARD - static std::string make(T&& arg) - { - using arg_type = std::decay_t<T>; + struct string_maker { + template <typename T> + TOML_NODISCARD static std::string make(T&& arg) { + using arg_type = std::decay_t<T>; #if TOML_HAS_CHAR8 - if constexpr (is_one_of<arg_type, char8_t*, const char8_t*>) - { - return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg))); - } - if constexpr (is_one_of<arg_type, std::u8string, std::u8string_view>) - { - return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg.data())), - arg.length()); - } + if constexpr (is_one_of<arg_type, char8_t*, const char8_t*>) { + return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg))); + } + if constexpr (is_one_of<arg_type, std::u8string, std::u8string_view>) { + return std::string(reinterpret_cast<const char*>(static_cast<const char8_t*>(arg.data())), + arg.length()); + } #endif #if TOML_ENABLE_WINDOWS_COMPAT - if constexpr (is_wide_string<arg_type>) - { - return narrow(static_cast<T&&>(arg)); - } + if constexpr (is_wide_string<arg_type>) { + return narrow(static_cast<T&&>(arg)); + } #endif - } - }; + } + }; #if TOML_HAS_CHAR8 - template <> - struct native_value_maker<std::string, char8_t*> : string_maker - {}; - template <> - struct native_value_maker<std::string, const char8_t*> : string_maker - {}; - template <> - struct native_value_maker<std::string, std::u8string> : string_maker - {}; - template <> - struct native_value_maker<std::string, std::u8string_view> : string_maker - {}; -#endif // TOML_HAS_CHAR8 + template <> + struct native_value_maker<std::string, char8_t*> : string_maker {}; + template <> + struct native_value_maker<std::string, const char8_t*> : string_maker {}; + template <> + struct native_value_maker<std::string, std::u8string> : string_maker {}; + template <> + struct native_value_maker<std::string, std::u8string_view> : string_maker {}; +#endif // TOML_HAS_CHAR8 #if TOML_ENABLE_WINDOWS_COMPAT - template <> - struct native_value_maker<std::string, wchar_t*> : string_maker - {}; - template <> - struct native_value_maker<std::string, const wchar_t*> : string_maker - {}; - template <> - struct native_value_maker<std::string, std::wstring> : string_maker - {}; - template <> - struct native_value_maker<std::string, std::wstring_view> : string_maker - {}; -#endif // TOML_ENABLE_WINDOWS_COMPAT - -#endif // TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT - - template <typename T> - TOML_CONST_GETTER - inline optional<T> node_integer_cast(int64_t val) noexcept - { - static_assert(node_type_of<T> == node_type::integer); - static_assert(!is_cvref<T>); - - using traits = value_traits<T>; - if constexpr (!traits::is_signed) - { - if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max - { - using common_t = decltype(int64_t{} + T{}); - if (val < int64_t{} || static_cast<common_t>(val) > static_cast<common_t>(traits::max)) - return {}; - } - else - { - if (val < int64_t{}) - return {}; - } - } - else - { - if (val < traits::min || val > traits::max) - return {}; - } - return { static_cast<T>(val) }; - } - - template <typename...> - struct value_variadic_ctor_allowed : std::true_type - {}; - - template <typename T, typename... Args> - struct value_variadic_ctor_allowed<value<T>, value<T>, Args...> : std::false_type - {}; + template <> + struct native_value_maker<std::string, wchar_t*> : string_maker {}; + template <> + struct native_value_maker<std::string, const wchar_t*> : string_maker {}; + template <> + struct native_value_maker<std::string, std::wstring> : string_maker {}; + template <> + struct native_value_maker<std::string, std::wstring_view> : string_maker {}; +#endif // TOML_ENABLE_WINDOWS_COMPAT + +#endif // TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT + + template <typename T> + TOML_CONST_GETTER inline optional<T> node_integer_cast(int64_t val) noexcept { + static_assert(node_type_of<T> == node_type::integer); + static_assert(!is_cvref<T>); + + using traits = value_traits<T>; + if constexpr (!traits::is_signed) { + if constexpr ((sizeof(T) * CHAR_BIT) < 63) // 63 bits == int64_max + { + using common_t = decltype(int64_t{} + T{}); + if (val < int64_t{} || static_cast<common_t>(val) > static_cast<common_t>(traits::max)) + return {}; + } else { + if (val < int64_t{}) return {}; + } + } else { + if (val < traits::min || val > traits::max) return {}; + } + return {static_cast<T>(val)}; + } + + template <typename...> + struct value_variadic_ctor_allowed : std::true_type {}; + + template <typename T, typename... Args> + struct value_variadic_ctor_allowed<value<T>, value<T>, Args...> : std::false_type {}; } TOML_IMPL_NAMESPACE_END; /// \endcond -TOML_NAMESPACE_START -{ - /// \brief A TOML value. - /// - /// \tparam ValueType The value's native TOML data type. Can be one of: - /// - std::string - /// - toml::date - /// - toml::time - /// - toml::date_time - /// - int64_t - /// - double - /// - bool - template <typename ValueType> - class value : public node - { - static_assert(impl::is_native<ValueType> && !impl::is_cvref<ValueType>, - "A toml::value<> must model one of the native TOML value types:" TOML_SA_NATIVE_VALUE_TYPE_LIST); - - private: - /// \cond - - friend class TOML_PARSER_TYPENAME; - - template <typename T, typename U> - TOML_CONST_INLINE_GETTER - static auto as_value([[maybe_unused]] U* ptr) noexcept - { - if constexpr (std::is_same_v<value_type, T>) - return ptr; - else - return nullptr; - } - - ValueType val_; - value_flags flags_ = value_flags::none; - - /// \endcond - - public: - /// \brief The value's underlying data type. - using value_type = ValueType; - - /// \brief A type alias for 'value arguments'. - /// \details This differs according to the value's type argument: - /// - ints, floats, booleans: `value_type` - /// - strings: `string_view` - /// - everything else: `const value_type&` - using value_arg = POXY_IMPLEMENTATION_DETAIL( - std::conditional_t< - std::is_same_v<value_type, std::string>, - std::string_view, - std::conditional_t<impl::is_one_of<value_type, double, int64_t, bool>, value_type, const value_type&>>); - - /// \brief Constructs a toml value. - /// - /// \tparam Args Constructor argument types. - /// \param args Arguments to forward to the internal value's constructor. - TOML_HIDDEN_CONSTRAINT( - (impl::value_variadic_ctor_allowed<value<ValueType>, impl::remove_cvref<Args>...>::value), - typename... Args) - TOML_NODISCARD_CTOR - explicit value(Args&&... args) noexcept(noexcept(value_type( - impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...)))) - : val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(args)...)) - { +TOML_NAMESPACE_START { + /// \brief A TOML value. + /// + /// \tparam ValueType The value's native TOML data type. Can be one of: + /// - std::string + /// - toml::date + /// - toml::time + /// - toml::date_time + /// - int64_t + /// - double + /// - bool + template <typename ValueType> + class value : public node { + static_assert(impl::is_native<ValueType> && !impl::is_cvref<ValueType>, + "A toml::value<> must model one of the native TOML value " + "types:" TOML_SA_NATIVE_VALUE_TYPE_LIST); + + private: + /// \cond + + friend class TOML_PARSER_TYPENAME; + + template <typename T, typename U> + TOML_CONST_INLINE_GETTER static auto as_value([[maybe_unused]] U* ptr) noexcept { + if constexpr (std::is_same_v<value_type, T>) + return ptr; + else + return nullptr; + } + + ValueType val_; + value_flags flags_ = value_flags::none; + + /// \endcond + + public: + /// \brief The value's underlying data type. + using value_type = ValueType; + + /// \brief A type alias for 'value arguments'. + /// \details This differs according to the value's type argument: + /// - ints, floats, booleans: `value_type` + /// - strings: `string_view` + /// - everything else: `const value_type&` + using value_arg = POXY_IMPLEMENTATION_DETAIL( + std::conditional_t<std::is_same_v<value_type, std::string>, std::string_view, + std::conditional_t<impl::is_one_of<value_type, double, int64_t, bool>, + value_type, const value_type&>>); + + /// \brief Constructs a toml value. + /// + /// \tparam Args Constructor argument types. + /// \param args Arguments to forward to the internal value's constructor. + TOML_HIDDEN_CONSTRAINT( + (impl::value_variadic_ctor_allowed<value<ValueType>, impl::remove_cvref<Args>...>::value), + typename... Args) + TOML_NODISCARD_CTOR + explicit value(Args&&... args) noexcept( + noexcept(value_type(impl::native_value_maker<value_type, std::decay_t<Args>...>::make( + static_cast<Args&&>(args)...)))) + : val_(impl::native_value_maker<value_type, std::decay_t<Args>...>::make( + static_cast<Args&&>(args)...)) { #if TOML_LIFETIME_HOOKS - TOML_VALUE_CREATED; + TOML_VALUE_CREATED; #endif - } - - /// \brief Copy constructor. - TOML_NODISCARD_CTOR - value(const value& other) noexcept // - : node(other), - val_{ other.val_ }, - flags_{ other.flags_ } - { + } + + /// \brief Copy constructor. + TOML_NODISCARD_CTOR + value(const value& other) noexcept // + : node(other), val_{other.val_}, flags_{other.flags_} { #if TOML_LIFETIME_HOOKS - TOML_VALUE_CREATED; + TOML_VALUE_CREATED; #endif - } - - /// \brief Copy constructor with flags override. - TOML_NODISCARD_CTOR - value(const value& other, value_flags flags) noexcept // - : node(other), - val_{ other.val_ }, - flags_{ flags == preserve_source_value_flags ? other.flags_ : flags } - { + } + + /// \brief Copy constructor with flags override. + TOML_NODISCARD_CTOR + value(const value& other, value_flags flags) noexcept // + : node(other), + val_{other.val_}, + flags_{flags == preserve_source_value_flags ? other.flags_ : flags} { #if TOML_LIFETIME_HOOKS - TOML_VALUE_CREATED; + TOML_VALUE_CREATED; #endif - } - - /// \brief Move constructor. - TOML_NODISCARD_CTOR - value(value&& other) noexcept // - : node(std::move(other)), - val_{ std::move(other.val_) }, - flags_{ std::exchange(other.flags_, value_flags{}) } - { + } + + /// \brief Move constructor. + TOML_NODISCARD_CTOR + value(value&& other) noexcept // + : node(std::move(other)), + val_{std::move(other.val_)}, + flags_{std::exchange(other.flags_, value_flags{})} { #if TOML_LIFETIME_HOOKS - TOML_VALUE_CREATED; + TOML_VALUE_CREATED; #endif - } - - /// \brief Move constructor with flags override. - TOML_NODISCARD_CTOR - value(value&& other, value_flags flags) noexcept // - : node(std::move(other)), - val_{ std::move(other.val_) }, - flags_{ flags == preserve_source_value_flags ? other.flags_ : flags } - { + } + + /// \brief Move constructor with flags override. + TOML_NODISCARD_CTOR + value(value&& other, value_flags flags) noexcept // + : node(std::move(other)), + val_{std::move(other.val_)}, + flags_{flags == preserve_source_value_flags ? other.flags_ : flags} { #if TOML_LIFETIME_HOOKS - TOML_VALUE_CREATED; + TOML_VALUE_CREATED; #endif - other.flags_ = {}; - } - - /// \brief Copy-assignment operator. - value& operator=(const value& rhs) noexcept - { - node::operator=(rhs); - val_ = rhs.val_; - flags_ = rhs.flags_; - return *this; - } - - /// \brief Move-assignment operator. - value& operator=(value&& rhs) noexcept - { - if (&rhs != this) - { - node::operator=(std::move(rhs)); - val_ = std::move(rhs.val_); - flags_ = std::exchange(rhs.flags_, value_flags{}); - } - return *this; - } + other.flags_ = {}; + } + + /// \brief Copy-assignment operator. + value& operator=(const value& rhs) noexcept { + node::operator=(rhs); + val_ = rhs.val_; + flags_ = rhs.flags_; + return *this; + } + + /// \brief Move-assignment operator. + value& operator=(value&& rhs) noexcept { + if (&rhs != this) { + node::operator=(std::move(rhs)); + val_ = std::move(rhs.val_); + flags_ = std::exchange(rhs.flags_, value_flags{}); + } + return *this; + } #if TOML_LIFETIME_HOOKS - ~value() noexcept - { - TOML_VALUE_DESTROYED; - } + ~value() noexcept { TOML_VALUE_DESTROYED; } #endif - /// \name Type checks - /// @{ - - /// \brief Returns the value's node type identifier. - /// - /// \returns One of: - /// - node_type::string - /// - node_type::integer - /// - node_type::floating_point - /// - node_type::boolean - /// - node_type::date - /// - node_type::time - /// - node_type::date_time - TOML_CONST_INLINE_GETTER - node_type type() const noexcept final - { - return impl::node_type_of<value_type>; - } - - TOML_PURE_GETTER - bool is_homogeneous(node_type ntype) const noexcept final - { - return ntype == node_type::none || ntype == impl::node_type_of<value_type>; - } - - TOML_PURE_GETTER - bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final - { - if (ntype != node_type::none && ntype != impl::node_type_of<value_type>) - { - first_nonmatch = this; - return false; - } - return true; - } - - TOML_PURE_GETTER - bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final - { - if (ntype != node_type::none && ntype != impl::node_type_of<value_type>) - { - first_nonmatch = this; - return false; - } - return true; - } - - /// \cond - 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 value::is_homogeneous() must be void or one " - "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); - - if constexpr (std::is_void_v<type>) - return true; - else - return impl::node_type_of<type> == impl::node_type_of<value_type>; - } - /// \endcond - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_table() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_array() const noexcept final - { - return false; - } - - /// \brief Returns `false`. - TOML_CONST_INLINE_GETTER - bool is_array_of_tables() const noexcept final - { - return false; - } - - /// \brief Returns `true`. - TOML_CONST_INLINE_GETTER - bool is_value() const noexcept final - { - return true; - } - - /// \brief Returns `true` if the #value_type is std::string. - TOML_CONST_INLINE_GETTER - bool is_string() const noexcept final - { - return std::is_same_v<value_type, std::string>; - } - - /// \brief Returns `true` if the #value_type is int64_t. - TOML_CONST_INLINE_GETTER - bool is_integer() const noexcept final - { - return std::is_same_v<value_type, int64_t>; - } - - /// \brief Returns `true` if the #value_type is `double`. - TOML_CONST_INLINE_GETTER - bool is_floating_point() const noexcept final - { - return std::is_same_v<value_type, double>; - } - - /// \brief Returns `true` if the #value_type is int64_t or `double`. - TOML_CONST_INLINE_GETTER - bool is_number() const noexcept final - { - return impl::is_one_of<value_type, int64_t, double>; - } - - /// \brief Returns `true` if the #value_type is `bool`. - TOML_CONST_INLINE_GETTER - bool is_boolean() const noexcept final - { - return std::is_same_v<value_type, bool>; - } - - /// \brief Returns `true` if the #value_type is toml::date. - TOML_CONST_INLINE_GETTER - bool is_date() const noexcept final - { - return std::is_same_v<value_type, date>; - } - - /// \brief Returns `true` if the #value_type is toml::time. - TOML_CONST_INLINE_GETTER - bool is_time() const noexcept final - { - return std::is_same_v<value_type, time>; - } - - /// \brief Returns `true` if the #value_type is toml_date_time. - TOML_CONST_INLINE_GETTER - bool is_date_time() const noexcept final - { - return std::is_same_v<value_type, date_time>; - } - - /// @} - - /// \name Type casts - /// @{ - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - table* as_table() noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - array* as_array() noexcept final - { - return nullptr; - } - - /// \brief Returns a pointer to the value if it is a value<std::string>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - value<std::string>* as_string() noexcept final - { - return as_value<std::string>(this); - } - - /// \brief Returns a pointer to the value if it is a value<int64_t>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - value<int64_t>* as_integer() noexcept final - { - return as_value<int64_t>(this); - } - - /// \brief Returns a pointer to the value if it is a value<double>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - value<double>* as_floating_point() noexcept final - { - return as_value<double>(this); - } - - /// \brief Returns a pointer to the value if it is a value<bool>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - value<bool>* as_boolean() noexcept final - { - return as_value<bool>(this); - } - - /// \brief Returns a pointer to the value if it is a value<date>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - value<date>* as_date() noexcept final - { - return as_value<date>(this); - } - - /// \brief Returns a pointer to the value if it is a value<time>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - value<time>* as_time() noexcept final - { - return as_value<time>(this); - } - - /// \brief Returns a pointer to the value if it is a value<date_time>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - value<date_time>* as_date_time() noexcept final - { - return as_value<date_time>(this); - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - const table* as_table() const noexcept final - { - return nullptr; - } - - /// \brief Returns `nullptr`. - TOML_CONST_INLINE_GETTER - const array* as_array() const noexcept final - { - return nullptr; - } - - /// \brief Returns a const-qualified pointer to the value if it is a value<std::string>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - const value<std::string>* as_string() const noexcept final - { - return as_value<std::string>(this); - } - - /// \brief Returns a const-qualified pointer to the value if it is a value<int64_t>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - const value<int64_t>* as_integer() const noexcept final - { - return as_value<int64_t>(this); - } - - /// \brief Returns a const-qualified pointer to the value if it is a value<double>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - const value<double>* as_floating_point() const noexcept final - { - return as_value<double>(this); - } - - /// \brief Returns a const-qualified pointer to the value if it is a value<bool>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - const value<bool>* as_boolean() const noexcept final - { - return as_value<bool>(this); - } - - /// \brief Returns a const-qualified pointer to the value if it is a value<date>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - const value<date>* as_date() const noexcept final - { - return as_value<date>(this); - } - - /// \brief Returns a const-qualified pointer to the value if it is a value<time>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - const value<time>* as_time() const noexcept final - { - return as_value<time>(this); - } - - /// \brief Returns a const-qualified pointer to the value if it is a value<date_time>, otherwise `nullptr`. - TOML_CONST_INLINE_GETTER - const value<date_time>* as_date_time() const noexcept final - { - return as_value<date_time>(this); - } - - /// @} - - /// \name Value retrieval - /// @{ - - /// \brief Returns a reference to the underlying value. - TOML_PURE_INLINE_GETTER - value_type& get() & noexcept - { - return val_; - } - - /// \brief Returns a reference to the underlying value (rvalue overload). - TOML_PURE_INLINE_GETTER - value_type&& get() && noexcept - { - return static_cast<value_type&&>(val_); - } - - /// \brief Returns a reference to the underlying value (const overload). - TOML_PURE_INLINE_GETTER - const value_type& get() const& noexcept - { - return val_; - } - - /// \brief Returns a reference to the underlying value (const rvalue overload). - TOML_PURE_INLINE_GETTER - const value_type&& get() const&& noexcept - { - return static_cast<const value_type&&>(val_); - } - - /// \brief Returns a reference to the underlying value. - TOML_PURE_INLINE_GETTER - value_type& operator*() & noexcept - { - return val_; - } - - /// \brief Returns a reference to the underlying value (rvalue overload). - TOML_PURE_INLINE_GETTER - value_type&& operator*() && noexcept - { - return static_cast<value_type&&>(val_); - } - - /// \brief Returns a reference to the underlying value (const overload). - TOML_PURE_INLINE_GETTER - const value_type& operator*() const& noexcept - { - return val_; - } - - /// \brief Returns a reference to the underlying value (const rvalue overload). - TOML_PURE_INLINE_GETTER - const value_type&& operator*() const&& noexcept - { - return static_cast<const value_type&&>(val_); - } - - /// \brief Returns a reference to the underlying value. - TOML_PURE_INLINE_GETTER - explicit operator value_type&() & noexcept - { - return val_; - } - - /// \brief Returns a reference to the underlying value (rvalue overload). - TOML_PURE_INLINE_GETTER - explicit operator value_type&&() && noexcept - { - return static_cast<value_type&&>(val_); - } - - /// \brief Returns a reference to the underlying value (const overload). - TOML_PURE_INLINE_GETTER - explicit operator const value_type&() const& noexcept - { - return val_; - } - - /// \brief Returns a reference to the underlying value (const rvalue overload). - TOML_PURE_INLINE_GETTER - explicit operator const value_type&&() && noexcept - { - return static_cast<const value_type&&>(val_); - } - - /// \brief Returns a pointer to the underlying value. - /// - /// \availability This operator is only available when #value_type is a class/struct. - TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type) - TOML_PURE_INLINE_GETTER - value_type* operator->() noexcept - { - return &val_; - } - - /// \brief Returns a pointer to the underlying value (const overload). - /// - /// \availability This operator is only available when #value_type is a class/struct. - TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type) - TOML_PURE_INLINE_GETTER - const value_type* operator->() const noexcept - { - return &val_; - } - - /// @} - - /// \name Metadata - /// @{ - - /// \brief Returns the metadata flags associated with this value. - TOML_NODISCARD - value_flags flags() const noexcept - { - return flags_; - } - - /// \brief Sets the metadata flags associated with this value. - /// \returns A reference to the value object. - value& flags(value_flags new_flags) noexcept - { - flags_ = new_flags; - return *this; - } - - /// @} - - /// \brief Value-assignment operator. - value& operator=(value_arg rhs) noexcept - { - if constexpr (std::is_same_v<value_type, std::string>) - val_.assign(rhs); - else - val_ = rhs; - return *this; - } - - TOML_CONSTRAINED_TEMPLATE((std::is_same_v<T, std::string>), typename T = value_type) - value& operator=(std::string&& rhs) noexcept - { - val_ = std::move(rhs); - return *this; - } - - /// \name Equality and Comparison - /// @{ - - /// \brief Value equality operator. - TOML_PURE_GETTER - friend bool operator==(const value& lhs, value_arg rhs) noexcept - { - if constexpr (std::is_same_v<value_type, double>) - { - const auto lhs_nan = impl::fpclassify(lhs.val_) == impl::fp_class::nan; - const auto rhs_nan = impl::fpclassify(rhs) == impl::fp_class::nan; - if (lhs_nan != rhs_nan) - return false; - if (lhs_nan) - return true; - } - return lhs.val_ == rhs; - } - TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, ); - - /// \brief Value less-than operator. - TOML_PURE_GETTER - friend bool operator<(const value& lhs, value_arg rhs) noexcept - { - return lhs.val_ < rhs; - } - - /// \brief Value less-than operator. - TOML_PURE_GETTER - friend bool operator<(value_arg lhs, const value& rhs) noexcept - { - return lhs < rhs.val_; - } - - /// \brief Value less-than-or-equal-to operator. - TOML_PURE_GETTER - friend bool operator<=(const value& lhs, value_arg rhs) noexcept - { - return lhs.val_ <= rhs; - } - - /// \brief Value less-than-or-equal-to operator. - TOML_PURE_GETTER - friend bool operator<=(value_arg lhs, const value& rhs) noexcept - { - return lhs <= rhs.val_; - } - - /// \brief Value greater-than operator. - TOML_PURE_GETTER - friend bool operator>(const value& lhs, value_arg rhs) noexcept - { - return lhs.val_ > rhs; - } - - /// \brief Value greater-than operator. - TOML_PURE_GETTER - friend bool operator>(value_arg lhs, const value& rhs) noexcept - { - return lhs > rhs.val_; - } - - /// \brief Value greater-than-or-equal-to operator. - TOML_PURE_GETTER - friend bool operator>=(const value& lhs, value_arg rhs) noexcept - { - return lhs.val_ >= rhs; - } - - /// \brief Value greater-than-or-equal-to operator. - TOML_PURE_GETTER - friend bool operator>=(value_arg lhs, const value& rhs) noexcept - { - return lhs >= rhs.val_; - } - - /// \brief Equality operator. - /// - /// \param lhs The LHS value. - /// \param rhs The RHS value. - /// - /// \returns True if the values were of the same type and contained the same value. - template <typename T> - TOML_PURE_GETTER - friend bool operator==(const value& lhs, const value<T>& rhs) noexcept - { - if constexpr (std::is_same_v<value_type, T>) - return lhs == rhs.val_; // calls asymmetrical value-equality operator defined above - else - return false; - } - - /// \brief Inequality operator. - /// - /// \param lhs The LHS value. - /// \param rhs The RHS value. - /// - /// \returns True if the values were not of the same type, or did not contain the same value. - template <typename T> - TOML_PURE_INLINE_GETTER - friend bool operator!=(const value& lhs, const value<T>& rhs) noexcept - { - return !(lhs == rhs); - } - - /// \brief Less-than operator. - /// - /// \param lhs The LHS toml::value. - /// \param rhs The RHS toml::value. - /// - /// \returns \conditional_return{Same value types} - /// `lhs.get() < rhs.get()` - /// \conditional_return{Different value types} - /// `lhs.type() < rhs.type()` - template <typename T> - TOML_PURE_GETTER - friend bool operator<(const value& lhs, const value<T>& rhs) noexcept - { - if constexpr (std::is_same_v<value_type, T>) - return lhs.val_ < rhs.val_; - else - return impl::node_type_of<value_type> < impl::node_type_of<T>; - } - - /// \brief Less-than-or-equal-to operator. - /// - /// \param lhs The LHS toml::value. - /// \param rhs The RHS toml::value. - /// - /// \returns \conditional_return{Same value types} - /// `lhs.get() <= rhs.get()` - /// \conditional_return{Different value types} - /// `lhs.type() <= rhs.type()` - template <typename T> - TOML_PURE_GETTER - friend bool operator<=(const value& lhs, const value<T>& rhs) noexcept - { - if constexpr (std::is_same_v<value_type, T>) - return lhs.val_ <= rhs.val_; - else - return impl::node_type_of<value_type> <= impl::node_type_of<T>; - } - - /// \brief Greater-than operator. - /// - /// \param lhs The LHS toml::value. - /// \param rhs The RHS toml::value. - /// - /// \returns \conditional_return{Same value types} - /// `lhs.get() > rhs.get()` - /// \conditional_return{Different value types} - /// `lhs.type() > rhs.type()` - template <typename T> - TOML_PURE_GETTER - friend bool operator>(const value& lhs, const value<T>& rhs) noexcept - { - if constexpr (std::is_same_v<value_type, T>) - return lhs.val_ > rhs.val_; - else - return impl::node_type_of<value_type> > impl::node_type_of<T>; - } - - /// \brief Greater-than-or-equal-to operator. - /// - /// \param lhs The LHS toml::value. - /// \param rhs The RHS toml::value. - /// - /// \returns \conditional_return{Same value types} - /// `lhs.get() >= rhs.get()` - /// \conditional_return{Different value types} - /// `lhs.type() >= rhs.type()` - template <typename T> - TOML_PURE_GETTER - friend bool operator>=(const value& lhs, const value<T>& rhs) noexcept - { - if constexpr (std::is_same_v<value_type, T>) - return lhs.val_ >= rhs.val_; - else - return impl::node_type_of<value_type> >= impl::node_type_of<T>; - } - - /// @} + /// \name Type checks + /// @{ + + /// \brief Returns the value's node type identifier. + /// + /// \returns One of: + /// - node_type::string + /// - node_type::integer + /// - node_type::floating_point + /// - node_type::boolean + /// - node_type::date + /// - node_type::time + /// - node_type::date_time + TOML_CONST_INLINE_GETTER + node_type type() const noexcept final { return impl::node_type_of<value_type>; } + + TOML_PURE_GETTER + bool is_homogeneous(node_type ntype) const noexcept final { + return ntype == node_type::none || ntype == impl::node_type_of<value_type>; + } + + TOML_PURE_GETTER + bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final { + if (ntype != node_type::none && ntype != impl::node_type_of<value_type>) { + first_nonmatch = this; + return false; + } + return true; + } + + TOML_PURE_GETTER + bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final { + if (ntype != node_type::none && ntype != impl::node_type_of<value_type>) { + first_nonmatch = this; + return false; + } + return true; + } + + /// \cond + 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 value::is_homogeneous() must be void or one " + "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST); + + if constexpr (std::is_void_v<type>) + return true; + else + return impl::node_type_of<type> == impl::node_type_of<value_type>; + } + /// \endcond + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_table() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_array() const noexcept final { return false; } + + /// \brief Returns `false`. + TOML_CONST_INLINE_GETTER + bool is_array_of_tables() const noexcept final { return false; } + + /// \brief Returns `true`. + TOML_CONST_INLINE_GETTER + bool is_value() const noexcept final { return true; } + + /// \brief Returns `true` if the #value_type is std::string. + TOML_CONST_INLINE_GETTER + bool is_string() const noexcept final { return std::is_same_v<value_type, std::string>; } + + /// \brief Returns `true` if the #value_type is int64_t. + TOML_CONST_INLINE_GETTER + bool is_integer() const noexcept final { return std::is_same_v<value_type, int64_t>; } + + /// \brief Returns `true` if the #value_type is `double`. + TOML_CONST_INLINE_GETTER + bool is_floating_point() const noexcept final { return std::is_same_v<value_type, double>; } + + /// \brief Returns `true` if the #value_type is int64_t or `double`. + TOML_CONST_INLINE_GETTER + bool is_number() const noexcept final { return impl::is_one_of<value_type, int64_t, double>; } + + /// \brief Returns `true` if the #value_type is `bool`. + TOML_CONST_INLINE_GETTER + bool is_boolean() const noexcept final { return std::is_same_v<value_type, bool>; } + + /// \brief Returns `true` if the #value_type is toml::date. + TOML_CONST_INLINE_GETTER + bool is_date() const noexcept final { return std::is_same_v<value_type, date>; } + + /// \brief Returns `true` if the #value_type is toml::time. + TOML_CONST_INLINE_GETTER + bool is_time() const noexcept final { return std::is_same_v<value_type, time>; } + + /// \brief Returns `true` if the #value_type is toml_date_time. + TOML_CONST_INLINE_GETTER + bool is_date_time() const noexcept final { return std::is_same_v<value_type, date_time>; } + + /// @} + + /// \name Type casts + /// @{ + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + table* as_table() noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + array* as_array() noexcept final { return nullptr; } + + /// \brief Returns a pointer to the value if it is a value<std::string>, otherwise `nullptr`. + TOML_CONST_INLINE_GETTER + value<std::string>* as_string() noexcept final { return as_value<std::string>(this); } + + /// \brief Returns a pointer to the value if it is a value<int64_t>, otherwise `nullptr`. + TOML_CONST_INLINE_GETTER + value<int64_t>* as_integer() noexcept final { return as_value<int64_t>(this); } + + /// \brief Returns a pointer to the value if it is a value<double>, otherwise `nullptr`. + TOML_CONST_INLINE_GETTER + value<double>* as_floating_point() noexcept final { return as_value<double>(this); } + + /// \brief Returns a pointer to the value if it is a value<bool>, otherwise `nullptr`. + TOML_CONST_INLINE_GETTER + value<bool>* as_boolean() noexcept final { return as_value<bool>(this); } + + /// \brief Returns a pointer to the value if it is a value<date>, otherwise `nullptr`. + TOML_CONST_INLINE_GETTER + value<date>* as_date() noexcept final { return as_value<date>(this); } + + /// \brief Returns a pointer to the value if it is a value<time>, otherwise `nullptr`. + TOML_CONST_INLINE_GETTER + value<time>* as_time() noexcept final { return as_value<time>(this); } + + /// \brief Returns a pointer to the value if it is a value<date_time>, otherwise `nullptr`. + TOML_CONST_INLINE_GETTER + value<date_time>* as_date_time() noexcept final { return as_value<date_time>(this); } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + const table* as_table() const noexcept final { return nullptr; } + + /// \brief Returns `nullptr`. + TOML_CONST_INLINE_GETTER + const array* as_array() const noexcept final { return nullptr; } + + /// \brief Returns a const-qualified pointer to the value if it is a value<std::string>, + /// otherwise `nullptr`. + TOML_CONST_INLINE_GETTER + const value<std::string>* as_string() const noexcept final { + return as_value<std::string>(this); + } + + /// \brief Returns a const-qualified pointer to the value if it is a value<int64_t>, otherwise + /// `nullptr`. + TOML_CONST_INLINE_GETTER + const value<int64_t>* as_integer() const noexcept final { return as_value<int64_t>(this); } + + /// \brief Returns a const-qualified pointer to the value if it is a value<double>, otherwise + /// `nullptr`. + TOML_CONST_INLINE_GETTER + const value<double>* as_floating_point() const noexcept final { return as_value<double>(this); } + + /// \brief Returns a const-qualified pointer to the value if it is a value<bool>, otherwise + /// `nullptr`. + TOML_CONST_INLINE_GETTER + const value<bool>* as_boolean() const noexcept final { return as_value<bool>(this); } + + /// \brief Returns a const-qualified pointer to the value if it is a value<date>, otherwise + /// `nullptr`. + TOML_CONST_INLINE_GETTER + const value<date>* as_date() const noexcept final { return as_value<date>(this); } + + /// \brief Returns a const-qualified pointer to the value if it is a value<time>, otherwise + /// `nullptr`. + TOML_CONST_INLINE_GETTER + const value<time>* as_time() const noexcept final { return as_value<time>(this); } + + /// \brief Returns a const-qualified pointer to the value if it is a value<date_time>, otherwise + /// `nullptr`. + TOML_CONST_INLINE_GETTER + const value<date_time>* as_date_time() const noexcept final { + return as_value<date_time>(this); + } + + /// @} + + /// \name Value retrieval + /// @{ + + /// \brief Returns a reference to the underlying value. + TOML_PURE_INLINE_GETTER + value_type& get() & noexcept { return val_; } + + /// \brief Returns a reference to the underlying value (rvalue overload). + TOML_PURE_INLINE_GETTER + value_type&& get() && noexcept { return static_cast<value_type&&>(val_); } + + /// \brief Returns a reference to the underlying value (const overload). + TOML_PURE_INLINE_GETTER + const value_type& get() const& noexcept { return val_; } + + /// \brief Returns a reference to the underlying value (const rvalue overload). + TOML_PURE_INLINE_GETTER + const value_type&& get() const&& noexcept { return static_cast<const value_type&&>(val_); } + + /// \brief Returns a reference to the underlying value. + TOML_PURE_INLINE_GETTER + value_type& operator*() & noexcept { return val_; } + + /// \brief Returns a reference to the underlying value (rvalue overload). + TOML_PURE_INLINE_GETTER + value_type&& operator*() && noexcept { return static_cast<value_type&&>(val_); } + + /// \brief Returns a reference to the underlying value (const overload). + TOML_PURE_INLINE_GETTER + const value_type& operator*() const& noexcept { return val_; } + + /// \brief Returns a reference to the underlying value (const rvalue overload). + TOML_PURE_INLINE_GETTER + const value_type&& operator*() const&& noexcept { + return static_cast<const value_type&&>(val_); + } + + /// \brief Returns a reference to the underlying value. + TOML_PURE_INLINE_GETTER + explicit operator value_type&() & noexcept { return val_; } + + /// \brief Returns a reference to the underlying value (rvalue overload). + TOML_PURE_INLINE_GETTER + explicit operator value_type&&() && noexcept { return static_cast<value_type&&>(val_); } + + /// \brief Returns a reference to the underlying value (const overload). + TOML_PURE_INLINE_GETTER + explicit operator const value_type&() const& noexcept { return val_; } + + /// \brief Returns a reference to the underlying value (const rvalue overload). + TOML_PURE_INLINE_GETTER + explicit operator const value_type&&() && noexcept { + return static_cast<const value_type&&>(val_); + } + + /// \brief Returns a pointer to the underlying value. + /// + /// \availability This operator is only available when #value_type is a class/struct. + TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type) + TOML_PURE_INLINE_GETTER + value_type* operator->() noexcept { return &val_; } + + /// \brief Returns a pointer to the underlying value (const overload). + /// + /// \availability This operator is only available when #value_type is a class/struct. + TOML_HIDDEN_CONSTRAINT(std::is_class_v<T>, typename T = value_type) + TOML_PURE_INLINE_GETTER + const value_type* operator->() const noexcept { return &val_; } + + /// @} + + /// \name Metadata + /// @{ + + /// \brief Returns the metadata flags associated with this value. + TOML_NODISCARD + value_flags flags() const noexcept { return flags_; } + + /// \brief Sets the metadata flags associated with this value. + /// \returns A reference to the value object. + value& flags(value_flags new_flags) noexcept { + flags_ = new_flags; + return *this; + } + + /// @} + + /// \brief Value-assignment operator. + value& operator=(value_arg rhs) noexcept { + if constexpr (std::is_same_v<value_type, std::string>) + val_.assign(rhs); + else + val_ = rhs; + return *this; + } + + TOML_CONSTRAINED_TEMPLATE((std::is_same_v<T, std::string>), typename T = value_type) + value& operator=(std::string&& rhs) noexcept { + val_ = std::move(rhs); + return *this; + } + + /// \name Equality and Comparison + /// @{ + + /// \brief Value equality operator. + TOML_PURE_GETTER + friend bool operator==(const value& lhs, value_arg rhs) noexcept { + if constexpr (std::is_same_v<value_type, double>) { + const auto lhs_nan = impl::fpclassify(lhs.val_) == impl::fp_class::nan; + const auto rhs_nan = impl::fpclassify(rhs) == impl::fp_class::nan; + if (lhs_nan != rhs_nan) return false; + if (lhs_nan) return true; + } + return lhs.val_ == rhs; + } + TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, ); + + /// \brief Value less-than operator. + TOML_PURE_GETTER + friend bool operator<(const value& lhs, value_arg rhs) noexcept { return lhs.val_ < rhs; } + + /// \brief Value less-than operator. + TOML_PURE_GETTER + friend bool operator<(value_arg lhs, const value& rhs) noexcept { return lhs < rhs.val_; } + + /// \brief Value less-than-or-equal-to operator. + TOML_PURE_GETTER + friend bool operator<=(const value& lhs, value_arg rhs) noexcept { return lhs.val_ <= rhs; } + + /// \brief Value less-than-or-equal-to operator. + TOML_PURE_GETTER + friend bool operator<=(value_arg lhs, const value& rhs) noexcept { return lhs <= rhs.val_; } + + /// \brief Value greater-than operator. + TOML_PURE_GETTER + friend bool operator>(const value& lhs, value_arg rhs) noexcept { return lhs.val_ > rhs; } + + /// \brief Value greater-than operator. + TOML_PURE_GETTER + friend bool operator>(value_arg lhs, const value& rhs) noexcept { return lhs > rhs.val_; } + + /// \brief Value greater-than-or-equal-to operator. + TOML_PURE_GETTER + friend bool operator>=(const value& lhs, value_arg rhs) noexcept { return lhs.val_ >= rhs; } + + /// \brief Value greater-than-or-equal-to operator. + TOML_PURE_GETTER + friend bool operator>=(value_arg lhs, const value& rhs) noexcept { return lhs >= rhs.val_; } + + /// \brief Equality operator. + /// + /// \param lhs The LHS value. + /// \param rhs The RHS value. + /// + /// \returns True if the values were of the same type and contained the same value. + template <typename T> + TOML_PURE_GETTER friend bool operator==(const value& lhs, const value<T>& rhs) noexcept { + if constexpr (std::is_same_v<value_type, T>) + return lhs == rhs.val_; // calls asymmetrical value-equality operator defined above + else + return false; + } + + /// \brief Inequality operator. + /// + /// \param lhs The LHS value. + /// \param rhs The RHS value. + /// + /// \returns True if the values were not of the same type, or did not contain the same value. + template <typename T> + TOML_PURE_INLINE_GETTER friend bool operator!=(const value& lhs, const value<T>& rhs) noexcept { + return !(lhs == rhs); + } + + /// \brief Less-than operator. + /// + /// \param lhs The LHS toml::value. + /// \param rhs The RHS toml::value. + /// + /// \returns \conditional_return{Same value types} + /// `lhs.get() < rhs.get()` + /// \conditional_return{Different value types} + /// `lhs.type() < rhs.type()` + template <typename T> + TOML_PURE_GETTER friend bool operator<(const value& lhs, const value<T>& rhs) noexcept { + if constexpr (std::is_same_v<value_type, T>) + return lhs.val_ < rhs.val_; + else + return impl::node_type_of<value_type> < impl::node_type_of<T>; + } + + /// \brief Less-than-or-equal-to operator. + /// + /// \param lhs The LHS toml::value. + /// \param rhs The RHS toml::value. + /// + /// \returns \conditional_return{Same value types} + /// `lhs.get() <= rhs.get()` + /// \conditional_return{Different value types} + /// `lhs.type() <= rhs.type()` + template <typename T> + TOML_PURE_GETTER friend bool operator<=(const value& lhs, const value<T>& rhs) noexcept { + if constexpr (std::is_same_v<value_type, T>) + return lhs.val_ <= rhs.val_; + else + return impl::node_type_of<value_type> <= impl::node_type_of<T>; + } + + /// \brief Greater-than operator. + /// + /// \param lhs The LHS toml::value. + /// \param rhs The RHS toml::value. + /// + /// \returns \conditional_return{Same value types} + /// `lhs.get() > rhs.get()` + /// \conditional_return{Different value types} + /// `lhs.type() > rhs.type()` + template <typename T> + TOML_PURE_GETTER friend bool operator>(const value& lhs, const value<T>& rhs) noexcept { + if constexpr (std::is_same_v<value_type, T>) + return lhs.val_ > rhs.val_; + else + return impl::node_type_of<value_type> > impl::node_type_of<T>; + } + + /// \brief Greater-than-or-equal-to operator. + /// + /// \param lhs The LHS toml::value. + /// \param rhs The RHS toml::value. + /// + /// \returns \conditional_return{Same value types} + /// `lhs.get() >= rhs.get()` + /// \conditional_return{Different value types} + /// `lhs.type() >= rhs.type()` + template <typename T> + TOML_PURE_GETTER friend bool operator>=(const value& lhs, const value<T>& rhs) noexcept { + if constexpr (std::is_same_v<value_type, T>) + return lhs.val_ >= rhs.val_; + else + return impl::node_type_of<value_type> >= impl::node_type_of<T>; + } + + /// @} #if TOML_ENABLE_FORMATTERS - /// \brief Prints the value out to a stream as formatted TOML. - /// - /// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled. - friend std::ostream& operator<<(std::ostream& lhs, const value& rhs) - { - impl::print_to_stream(lhs, rhs); - return lhs; - } + /// \brief Prints the value out to a stream as formatted TOML. + /// + /// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled. + friend std::ostream& operator<<(std::ostream& lhs, const value& rhs) { + impl::print_to_stream(lhs, rhs); + return lhs; + } #endif - }; - - /// \cond - - template <typename T> - value(T) -> value<impl::native_type_of<impl::remove_cvref<T>>>; - template <typename T> - value(T, value_flags) -> value<impl::native_type_of<impl::remove_cvref<T>>>; - - template <typename T> - TOML_NODISCARD - inline decltype(auto) node::get_value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>) - { - using namespace impl; - - static_assert(node_type_of<T> != node_type::none); - static_assert(node_type_of<T> != node_type::table); - static_assert(node_type_of<T> != node_type::array); - static_assert(is_native<T> || can_represent_native<T>); - static_assert(!is_cvref<T>); - TOML_ASSERT(this->type() == node_type_of<T>); - - if constexpr (node_type_of<T> == node_type::string) - { - const auto& str = *ref_cast<std::string>(); - if constexpr (std::is_same_v<T, std::string>) - return str; - else if constexpr (std::is_same_v<T, std::string_view>) - return T{ str }; - else if constexpr (std::is_same_v<T, const char*>) - return str.c_str(); - - else if constexpr (std::is_same_v<T, std::wstring>) - { + }; + + /// \cond + + template <typename T> + value(T) -> value<impl::native_type_of<impl::remove_cvref<T>>>; + template <typename T> + value(T, value_flags) -> value<impl::native_type_of<impl::remove_cvref<T>>>; + + template <typename T> + TOML_NODISCARD inline decltype(auto) node::get_value_exact() + const noexcept(impl::value_retrieval_is_nothrow<T>) { + using namespace impl; + + static_assert(node_type_of<T> != node_type::none); + static_assert(node_type_of<T> != node_type::table); + static_assert(node_type_of<T> != node_type::array); + static_assert(is_native<T> || can_represent_native<T>); + static_assert(!is_cvref<T>); + TOML_ASSERT(this->type() == node_type_of<T>); + + if constexpr (node_type_of<T> == node_type::string) { + const auto& str = *ref_cast<std::string>(); + if constexpr (std::is_same_v<T, std::string>) + return str; + else if constexpr (std::is_same_v<T, std::string_view>) + return T{str}; + else if constexpr (std::is_same_v<T, const char*>) + return str.c_str(); + + else if constexpr (std::is_same_v<T, std::wstring>) { #if TOML_ENABLE_WINDOWS_COMPAT - return widen(str); + return widen(str); #else - static_assert(always_false<T>, "Evaluated unreachable branch!"); + static_assert(always_false<T>, "Evaluated unreachable branch!"); #endif - } + } #if TOML_HAS_CHAR8 - // char -> char8_t (potentially unsafe - the feature is 'experimental'!) - else if constexpr (is_one_of<T, std::u8string, std::u8string_view>) - return T(reinterpret_cast<const char8_t*>(str.c_str()), str.length()); - else if constexpr (std::is_same_v<T, const char8_t*>) - return reinterpret_cast<const char8_t*>(str.c_str()); - else - static_assert(always_false<T>, "Evaluated unreachable branch!"); + // char -> char8_t (potentially unsafe - the feature is 'experimental'!) + else if constexpr (is_one_of<T, std::u8string, std::u8string_view>) + return T(reinterpret_cast<const char8_t*>(str.c_str()), str.length()); + else if constexpr (std::is_same_v<T, const char8_t*>) + return reinterpret_cast<const char8_t*>(str.c_str()); + else + static_assert(always_false<T>, "Evaluated unreachable branch!"); #endif - } - else - return static_cast<T>(*ref_cast<native_type_of<T>>()); - } - - template <typename T> - TOML_NODISCARD - inline optional<T> node::value_exact() const noexcept(impl::value_retrieval_is_nothrow<T>) - { - using namespace impl; - - static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT, - "Retrieving values as wide-character strings with node::value_exact() is only " - "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."); - - static_assert((is_native<T> || can_represent_native<T>)&&!is_cvref<T>, - TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()")); - - // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr - if constexpr ((is_native<T> || can_represent_native<T>)&&!is_cvref<T>) - { - if (type() == node_type_of<T>) - return { this->get_value_exact<T>() }; - else - return {}; - } - } - - template <typename T> - TOML_NODISCARD - inline optional<T> node::value() const noexcept(impl::value_retrieval_is_nothrow<T>) - { - using namespace impl; - - static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT, - "Retrieving values as wide-character strings with node::value() is only " - "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."); - static_assert((is_native<T> || can_represent_native<T> || can_partially_represent_native<T>)&&!is_cvref<T>, - TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()")); - - // when asking for strings, dates, times and date_times there's no 'fuzzy' conversion - // semantics to be mindful of so the exact retrieval is enough. - if constexpr (is_natively_one_of<T, std::string, time, date, date_time>) - { - if (type() == node_type_of<T>) - return { this->get_value_exact<T>() }; - else - return {}; - } - - // everything else requires a bit of logicking. - else - { - switch (type()) - { - // int -> * - case node_type::integer: - { - // int -> int - if constexpr (is_natively_one_of<T, int64_t>) - { - if constexpr (is_native<T> || can_represent_native<T>) - return static_cast<T>(*ref_cast<int64_t>()); - else - return node_integer_cast<T>(*ref_cast<int64_t>()); - } - - // int -> float - else if constexpr (is_natively_one_of<T, double>) - { - const int64_t val = *ref_cast<int64_t>(); - if constexpr (std::numeric_limits<T>::digits < 64) - { - constexpr auto largest_whole_float = (int64_t{ 1 } << std::numeric_limits<T>::digits); - if (val < -largest_whole_float || val > largest_whole_float) - return {}; - } - return static_cast<T>(val); - } - - // int -> bool - else if constexpr (is_natively_one_of<T, bool>) - return static_cast<bool>(*ref_cast<int64_t>()); - - // int -> anything else - else - return {}; - } - - // float -> * - case node_type::floating_point: - { - // float -> float - if constexpr (is_natively_one_of<T, double>) - { - if constexpr (is_native<T> || can_represent_native<T>) - return { static_cast<T>(*ref_cast<double>()) }; - else - { - const double val = *ref_cast<double>(); - if (impl::fpclassify(val) == fp_class::ok - && (val < (std::numeric_limits<T>::lowest)() || val > (std::numeric_limits<T>::max)())) - return {}; - return { static_cast<T>(val) }; - } - } - - // float -> int - else if constexpr (is_natively_one_of<T, int64_t>) - { - const double val = *ref_cast<double>(); - if (impl::fpclassify(val) == fp_class::ok - && static_cast<double>(static_cast<int64_t>(val)) == val) - return node_integer_cast<T>(static_cast<int64_t>(val)); - else - return {}; - } - - // float -> anything else - else - return {}; - } - - // bool -> * - case node_type::boolean: - { - // bool -> bool - if constexpr (is_natively_one_of<T, bool>) - return { *ref_cast<bool>() }; - - // bool -> int - else if constexpr (is_natively_one_of<T, int64_t>) - return { static_cast<T>(*ref_cast<bool>()) }; - - // bool -> anything else - else - return {}; - } - } - - // non-values, or 'exact' types covered above - return {}; - } - } - - template <typename T> - TOML_NODISCARD - inline auto node::value_or(T && default_value) const noexcept(impl::value_retrieval_is_nothrow<T>) - { - using namespace impl; - - static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT, - "Retrieving values as wide-character strings with node::value_or() is only " - "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."); - - if constexpr (is_wide_string<T>) - { + } else + return static_cast<T>(*ref_cast<native_type_of<T>>()); + } + + template <typename T> + TOML_NODISCARD inline optional<T> node::value_exact() + const noexcept(impl::value_retrieval_is_nothrow<T>) { + using namespace impl; + + static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT, + "Retrieving values as wide-character strings with node::value_exact() is only " + "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."); + + static_assert((is_native<T> || can_represent_native<T>) && !is_cvref<T>, + TOML_SA_VALUE_EXACT_FUNC_MESSAGE("return type of node::value_exact()")); + + // prevent additional compiler error spam when the static_assert fails by gating behind if + // constexpr + if constexpr ((is_native<T> || can_represent_native<T>) && !is_cvref<T>) { + if (type() == node_type_of<T>) + return {this->get_value_exact<T>()}; + else + return {}; + } + } + + template <typename T> + TOML_NODISCARD inline optional<T> node::value() + const noexcept(impl::value_retrieval_is_nothrow<T>) { + using namespace impl; + + static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT, + "Retrieving values as wide-character strings with node::value() is only " + "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."); + static_assert((is_native<T> || can_represent_native<T> || can_partially_represent_native<T>) && + !is_cvref<T>, + TOML_SA_VALUE_FUNC_MESSAGE("return type of node::value()")); + + // when asking for strings, dates, times and date_times there's no 'fuzzy' conversion + // semantics to be mindful of so the exact retrieval is enough. + if constexpr (is_natively_one_of<T, std::string, time, date, date_time>) { + if (type() == node_type_of<T>) + return {this->get_value_exact<T>()}; + else + return {}; + } + + // everything else requires a bit of logicking. + else { + switch (type()) { + // int -> * + case node_type::integer: { + // int -> int + if constexpr (is_natively_one_of<T, int64_t>) { + if constexpr (is_native<T> || can_represent_native<T>) + return static_cast<T>(*ref_cast<int64_t>()); + else + return node_integer_cast<T>(*ref_cast<int64_t>()); + } + + // int -> float + else if constexpr (is_natively_one_of<T, double>) { + const int64_t val = *ref_cast<int64_t>(); + if constexpr (std::numeric_limits<T>::digits < 64) { + constexpr auto largest_whole_float = (int64_t{1} << std::numeric_limits<T>::digits); + if (val < -largest_whole_float || val > largest_whole_float) return {}; + } + return static_cast<T>(val); + } + + // int -> bool + else if constexpr (is_natively_one_of<T, bool>) + return static_cast<bool>(*ref_cast<int64_t>()); + + // int -> anything else + else + return {}; + } + + // float -> * + case node_type::floating_point: { + // float -> float + if constexpr (is_natively_one_of<T, double>) { + if constexpr (is_native<T> || can_represent_native<T>) + return {static_cast<T>(*ref_cast<double>())}; + else { + const double val = *ref_cast<double>(); + if (impl::fpclassify(val) == fp_class::ok && + (val < (std::numeric_limits<T>::lowest)() || + val > (std::numeric_limits<T>::max)())) + return {}; + return {static_cast<T>(val)}; + } + } + + // float -> int + else if constexpr (is_natively_one_of<T, int64_t>) { + const double val = *ref_cast<double>(); + if (impl::fpclassify(val) == fp_class::ok && + static_cast<double>(static_cast<int64_t>(val)) == val) + return node_integer_cast<T>(static_cast<int64_t>(val)); + else + return {}; + } + + // float -> anything else + else + return {}; + } + + // bool -> * + case node_type::boolean: { + // bool -> bool + if constexpr (is_natively_one_of<T, bool>) return {*ref_cast<bool>()}; + + // bool -> int + else if constexpr (is_natively_one_of<T, int64_t>) + return {static_cast<T>(*ref_cast<bool>())}; + + // bool -> anything else + else + return {}; + } + } + + // non-values, or 'exact' types covered above + return {}; + } + } + + template <typename T> + TOML_NODISCARD inline auto node::value_or(T && default_value) + const noexcept(impl::value_retrieval_is_nothrow<T>) { + using namespace impl; + + static_assert(!is_wide_string<T> || TOML_ENABLE_WINDOWS_COMPAT, + "Retrieving values as wide-character strings with node::value_or() is only " + "supported on Windows with TOML_ENABLE_WINDOWS_COMPAT enabled."); + + if constexpr (is_wide_string<T>) { #if TOML_ENABLE_WINDOWS_COMPAT - if (type() == node_type::string) - return widen(*ref_cast<std::string>()); - return std::wstring{ static_cast<T&&>(default_value) }; + if (type() == node_type::string) return widen(*ref_cast<std::string>()); + return std::wstring{static_cast<T&&>(default_value)}; #else - static_assert(always_false<T>, "Evaluated unreachable branch!"); + static_assert(always_false<T>, "Evaluated unreachable branch!"); #endif - } - else - { - using value_type = - std::conditional_t<std::is_pointer_v<std::decay_t<T>>, - std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>, - std::decay_t<T>>; - using traits = value_traits<value_type>; + } else { + using value_type = std::conditional_t< + std::is_pointer_v<std::decay_t<T>>, + std::add_pointer_t<std::add_const_t<std::remove_pointer_t<std::decay_t<T>>>>, + std::decay_t<T>>; + using traits = value_traits<value_type>; - // clang-format off + // clang-format off static_assert( traits::is_native || traits::can_represent_native || traits::can_partially_represent_native, @@ -1243,27 +999,25 @@ TOML_NAMESPACE_START TOML_SA_LIST_END ); - // clang-format on - - // prevent additional compiler error spam when the static_assert fails by gating behind if constexpr - if constexpr (traits::is_native || traits::can_represent_native || traits::can_partially_represent_native) - { - if constexpr (traits::is_native) - { - if (type() == node_type_of<value_type>) - return *ref_cast<typename traits::native_type>(); - } - if (auto val = this->value<value_type>()) - return *val; - if constexpr (std::is_pointer_v<value_type>) - return value_type{ default_value }; - else - return static_cast<T&&>(default_value); - } - } - } - - /// \endcond + // clang-format on + + // prevent additional compiler error spam when the static_assert fails by gating behind if + // constexpr + if constexpr (traits::is_native || traits::can_represent_native || + traits::can_partially_represent_native) { + if constexpr (traits::is_native) { + if (type() == node_type_of<value_type>) return *ref_cast<typename traits::native_type>(); + } + if (auto val = this->value<value_type>()) return *val; + if constexpr (std::is_pointer_v<value_type>) + return value_type{default_value}; + else + return static_cast<T&&>(default_value); + } + } + } + + /// \endcond } TOML_NAMESPACE_END; |
