//# This file is a part of toml++ and is subject to the the terms of the MIT license. //# Copyright (c) 2019-2020 Mark Gillard //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. // SPDX-License-Identifier: MIT #pragma once #include "toml_node.h" #include "toml_print_to_stream.h" #ifndef DOXYGEN #if TOML_WINDOWS_COMPAT #define TOML_SA_VALUE_MESSAGE_WSTRING TOML_SA_LIST_SEP "std::wstring" #else #define TOML_SA_VALUE_MESSAGE_WSTRING #endif #ifdef __cpp_lib_char8_t #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 integer type" \ TOML_SA_LIST_SEP "any floating-point type >= 32 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 #endif // !DOXYGEN TOML_PUSH_WARNINGS TOML_DISABLE_ARITHMETIC_WARNINGS TOML_IMPL_NAMESPACE_START { template struct native_value_maker { template [[nodiscard]] static T make(Args&&... args) noexcept(std::is_nothrow_constructible_v) { return T(std::forward(args)...); } }; template struct native_value_maker { template [[nodiscard]] TOML_ALWAYS_INLINE static U&& make(U&& val) noexcept { return std::forward(val); } }; #if defined(__cpp_lib_char8_t) || TOML_WINDOWS_COMPAT struct string_maker { template [[nodiscard]] static std::string make(T&& arg) noexcept { #ifdef __cpp_lib_char8_t if constexpr (is_one_of, char8_t*, const char8_t*>) return std::string(reinterpret_cast(static_cast(arg))); else if constexpr (is_one_of, std::u8string, std::u8string_view>) return std::string(reinterpret_cast(static_cast(arg.data())), arg.length()); #endif // __cpp_lib_char8_t #if TOML_WINDOWS_COMPAT if constexpr (is_wide_string) return narrow(std::forward(arg)); #endif // TOML_WINDOWS_COMPAT } }; #ifdef __cpp_lib_char8_t 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 // __cpp_lib_char8_t #if TOML_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_WINDOWS_COMPAT #endif // defined(__cpp_lib_char8_t) || TOML_WINDOWS_COMPAT template [[nodiscard]] TOML_ATTR(const) 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) }; } } TOML_IMPL_NAMESPACE_END 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 TOML_API value final : 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: friend class TOML_PARSER_TYPENAME; template [[nodiscard]] TOML_ALWAYS_INLINE TOML_ATTR(const) 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; #if TOML_LIFETIME_HOOKS void lh_ctor() noexcept { TOML_VALUE_CREATED; } void lh_dtor() noexcept { TOML_VALUE_DESTROYED; } #endif 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 = 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. template TOML_NODISCARD_CTOR explicit value(Args&&... args) noexcept(noexcept(value_type( impl::native_value_maker...>::make(std::forward(args)...) ))) : val_(impl::native_value_maker...>::make(std::forward(args)...)) { #if TOML_LIFETIME_HOOKS lh_ctor(); #endif } /// \brief Copy constructor. TOML_NODISCARD_CTOR value(const value& other) noexcept : node{ other }, val_{ other.val_ }, flags_{ other.flags_ } { #if TOML_LIFETIME_HOOKS lh_ctor(); #endif } /// \brief Move constructor. TOML_NODISCARD_CTOR value(value&& other) noexcept : node{ std::move(other) }, val_{ std::move(other.val_) }, flags_{ other.flags_ } { #if TOML_LIFETIME_HOOKS lh_ctor(); #endif } /// \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_ = rhs.flags_; } return *this; } #if TOML_LIFETIME_HOOKS ~value() noexcept override { lh_dtor(); } #endif /// \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 [[nodiscard]] node_type type() const noexcept override { return impl::node_type_of; } [[nodiscard]] bool is_table() const noexcept override { return false; } [[nodiscard]] bool is_array() const noexcept override { return false; } [[nodiscard]] bool is_value() const noexcept override { return true; } [[nodiscard]] bool is_string() const noexcept override { return std::is_same_v; } [[nodiscard]] bool is_integer() const noexcept override { return std::is_same_v; } [[nodiscard]] bool is_floating_point() const noexcept override { return std::is_same_v; } [[nodiscard]] bool is_number() const noexcept override { return impl::is_one_of; } [[nodiscard]] bool is_boolean() const noexcept override { return std::is_same_v; } [[nodiscard]] bool is_date() const noexcept override { return std::is_same_v; } [[nodiscard]] bool is_time() const noexcept override { return std::is_same_v; } [[nodiscard]] bool is_date_time() const noexcept override { return std::is_same_v; } [[nodiscard]] value* as_string() noexcept override { return as_value(this); } [[nodiscard]] value* as_integer() noexcept override { return as_value(this); } [[nodiscard]] value* as_floating_point() noexcept override { return as_value(this); } [[nodiscard]] value* as_boolean() noexcept override { return as_value(this); } [[nodiscard]] value* as_date() noexcept override { return as_value(this); } [[nodiscard]] value