//# This file is a part of toml++ and is subject to the the terms of the MIT license. //# Copyright (c) Mark Gillard //# 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 struct native_value_maker { template TOML_NODISCARD static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v) { if constexpr (std::is_aggregate_v) return T{ static_cast(args)... }; else return T(static_cast(args)...); } }; template struct native_value_maker { template TOML_NODISCARD TOML_ALWAYS_INLINE static U&& make(U&& val) noexcept { return static_cast(val); } }; #if TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT struct string_maker { template TOML_NODISCARD static std::string make(T&& arg) { using arg_type = std::decay_t; #if TOML_HAS_CHAR8 if constexpr (is_one_of) { return std::string(reinterpret_cast(static_cast(arg))); } if constexpr (is_one_of) { return std::string(reinterpret_cast(static_cast(arg.data())), arg.length()); } #endif #if TOML_ENABLE_WINDOWS_COMPAT if constexpr (is_wide_string) { return narrow(static_cast(arg)); } #endif } }; #if TOML_HAS_CHAR8 template <> struct native_value_maker : string_maker {}; template <> struct native_value_maker : string_maker {}; template <> struct native_value_maker : string_maker {}; template <> struct native_value_maker : string_maker {}; #endif // TOML_HAS_CHAR8 #if TOML_ENABLE_WINDOWS_COMPAT template <> struct native_value_maker : string_maker {}; template <> struct native_value_maker : string_maker {}; template <> struct native_value_maker : string_maker {}; template <> struct native_value_maker : string_maker {}; #endif // TOML_ENABLE_WINDOWS_COMPAT #endif // TOML_HAS_CHAR8 || TOML_ENABLE_WINDOWS_COMPAT template TOML_CONST_GETTER inline optional node_integer_cast(int64_t val) noexcept { static_assert(node_type_of == node_type::integer); static_assert(!is_cvref); using traits = value_traits; 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(val) > static_cast(traits::max)) return {}; } else { if (val < int64_t{}) return {}; } } else { if (val < traits::min || val > traits::max) return {}; } return { static_cast(val) }; } template struct value_variadic_ctor_allowed : std::true_type {}; template struct value_variadic_ctor_allowed, value, 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 class value : public node { static_assert(impl::is_native && !impl::is_cvref, "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 TOML_CONST_INLINE_GETTER static auto as_value([[maybe_unused]] U* ptr) noexcept { if constexpr (std::is_same_v) 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, std::string_view, std::conditional_t, 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, impl::remove_cvref...>::value), typename... Args) TOML_NODISCARD_CTOR explicit value(Args&&... args) noexcept(noexcept(value_type( impl::native_value_maker...>::make(static_cast(args)...)))) : val_(impl::native_value_maker...>::make(static_cast(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; } TOML_PURE_GETTER bool is_homogeneous(node_type ntype) const noexcept final { return ntype == node_type::none || ntype == impl::node_type_of; } TOML_PURE_GETTER bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final { if (ntype != node_type::none && ntype != impl::node_type_of) { 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) { first_nonmatch = this; return false; } return true; } /// \cond template TOML_PURE_GETTER bool is_homogeneous() const noexcept { using type = impl::remove_cvref>; static_assert(std::is_void_v || toml::is_value || toml::is_container, "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) return true; else return impl::node_type_of == impl::node_type_of; } /// \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; } /// \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; } /// \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; } /// \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; } /// \brief Returns `true` if the #value_type is `bool`. TOML_CONST_INLINE_GETTER bool is_boolean() const noexcept final { return std::is_same_v; } /// \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; } /// \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; } /// \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; } /// @} /// \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, otherwise `nullptr`. TOML_CONST_INLINE_GETTER value* as_string() noexcept final { return as_value(this); } /// \brief Returns a pointer to the value if it is a value, otherwise `nullptr`. TOML_CONST_INLINE_GETTER value* as_integer() noexcept final { return as_value(this); } /// \brief Returns a pointer to the value if it is a value, otherwise `nullptr`. TOML_CONST_INLINE_GETTER value* as_floating_point() noexcept final { return as_value(this); } /// \brief Returns a pointer to the value if it is a value, otherwise `nullptr`. TOML_CONST_INLINE_GETTER value* as_boolean() noexcept final { return as_value(this); } /// \brief Returns a pointer to the value if it is a value, otherwise `nullptr`. TOML_CONST_INLINE_GETTER value* as_date() noexcept final { return as_value(this); } /// \brief Returns a pointer to the value if it is a value