diff options
Diffstat (limited to 'vendor/toml++/impl/value.hpp')
| -rw-r--r-- | vendor/toml++/impl/value.hpp | 1270 |
1 files changed, 1270 insertions, 0 deletions
diff --git a/vendor/toml++/impl/value.hpp b/vendor/toml++/impl/value.hpp new file mode 100644 index 0000000..6fb35dc --- /dev/null +++ b/vendor/toml++/impl/value.hpp @@ -0,0 +1,1270 @@ +//# 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 "node.hpp" +#include "print_to_stream.hpp" +#include "std_utility.hpp" +#include "header_start.hpp" +TOML_DISABLE_ARITHMETIC_WARNINGS; + +/// \cond +// clang-format off + +#if TOML_ENABLE_WINDOWS_COMPAT + #define TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP "std::wstring" +#else + #define TOML_SA_VALUE_MESSAGE_WSTRING +#endif +#if TOML_HAS_CHAR8 + #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW TOML_SA_LIST_SEP "std::u8string_view" + #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8 TOML_SA_LIST_SEP "const char8_t*" +#else + #define TOML_SA_VALUE_MESSAGE_U8STRING_VIEW + #define TOML_SA_VALUE_MESSAGE_CONST_CHAR8 +#endif + +#define TOML_SA_VALUE_EXACT_FUNC_MESSAGE(type_arg) \ + "The " type_arg " must be one of:" \ + TOML_SA_LIST_NEW "A native TOML value type" \ + TOML_SA_NATIVE_VALUE_TYPE_LIST \ + \ + TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \ + TOML_SA_LIST_BEG "std::string" \ + TOML_SA_VALUE_MESSAGE_WSTRING \ + TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \ + TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \ + TOML_SA_LIST_END \ + \ + TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \ + TOML_SA_LIST_BEG "std::string_view" \ + TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \ + TOML_SA_LIST_SEP "const char*" \ + TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \ + TOML_SA_LIST_END + +#define TOML_SA_VALUE_FUNC_MESSAGE(type_arg) \ + "The " type_arg " must be one of:" \ + TOML_SA_LIST_NEW "A native TOML value type" \ + TOML_SA_NATIVE_VALUE_TYPE_LIST \ + \ + TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" \ + TOML_SA_LIST_BEG "std::string" \ + TOML_SA_VALUE_MESSAGE_WSTRING \ + TOML_SA_LIST_SEP "any signed integer type >= 64 bits" \ + TOML_SA_LIST_SEP "any floating-point type >= 64 bits" \ + TOML_SA_LIST_END \ + \ + TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type" \ + TOML_SA_LIST_BEG "any other integral type" \ + TOML_SA_LIST_SEP "any floating-point type" \ + TOML_SA_LIST_END \ + \ + TOML_SA_LIST_NXT "An immutable view type not requiring additional temporary storage" \ + TOML_SA_LIST_BEG "std::string_view" \ + TOML_SA_VALUE_MESSAGE_U8STRING_VIEW \ + TOML_SA_LIST_SEP "const char*" \ + TOML_SA_VALUE_MESSAGE_CONST_CHAR8 \ + TOML_SA_LIST_END + +// clang-format on +/// \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); + } + }; + +#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>; +#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()); + } +#endif + +#if TOML_ENABLE_WINDOWS_COMPAT + 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 + +#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 + {}; +} +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)...)) + { +#if TOML_LIFETIME_HOOKS + TOML_VALUE_CREATED; +#endif + } + + /// \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; +#endif + } + + /// \brief Copy constructor with flags override. + TOML_NODISCARD_CTOR + value(const value& other, value_flags flags) noexcept // + : node(other), + val_{ other.val_ }, + flags_{ flags == preserve_source_value_flags ? other.flags_ : flags } + { +#if TOML_LIFETIME_HOOKS + TOML_VALUE_CREATED; +#endif + } + + /// \brief Move constructor. + TOML_NODISCARD_CTOR + value(value&& other) noexcept // + : node(std::move(other)), + val_{ std::move(other.val_) }, + flags_{ std::exchange(other.flags_, value_flags{}) } + { +#if TOML_LIFETIME_HOOKS + 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 } + { +#if TOML_LIFETIME_HOOKS + 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; + } + +#if TOML_LIFETIME_HOOKS + ~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>; + } + + /// @} + +#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; + } + +#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>) + { +#if TOML_ENABLE_WINDOWS_COMPAT + return widen(str); +#else + 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!"); + +#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>) + { +#if TOML_ENABLE_WINDOWS_COMPAT + + 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!"); + +#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>; + + // clang-format off + + static_assert( + traits::is_native || traits::can_represent_native || traits::can_partially_represent_native, + "The default value type of node::value_or() must be one of:" + TOML_SA_LIST_NEW "A native TOML value type" + TOML_SA_NATIVE_VALUE_TYPE_LIST + + TOML_SA_LIST_NXT "A non-view type capable of losslessly representing a native TOML value type" + TOML_SA_LIST_BEG "std::string" + #if TOML_ENABLE_WINDOWS_COMPAT + TOML_SA_LIST_SEP "std::wstring" + #endif + TOML_SA_LIST_SEP "any signed integer type >= 64 bits" + TOML_SA_LIST_SEP "any floating-point type >= 64 bits" + TOML_SA_LIST_END + + TOML_SA_LIST_NXT "A non-view type capable of (reasonably) representing a native TOML value type" + TOML_SA_LIST_BEG "any other integral type" + TOML_SA_LIST_SEP "any floating-point type" + TOML_SA_LIST_END + + TOML_SA_LIST_NXT "A compatible view type" + TOML_SA_LIST_BEG "std::string_view" + #if TOML_HAS_CHAR8 + TOML_SA_LIST_SEP "std::u8string_view" + #endif + #if TOML_ENABLE_WINDOWS_COMPAT + TOML_SA_LIST_SEP "std::wstring_view" + #endif + TOML_SA_LIST_SEP "const char*" + #if TOML_HAS_CHAR8 + TOML_SA_LIST_SEP "const char8_t*" + #endif + #if TOML_ENABLE_WINDOWS_COMPAT + TOML_SA_LIST_SEP "const wchar_t*" + #endif + 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 +} +TOML_NAMESPACE_END; + +#include "header_end.hpp" |
