diff --git a/include/toml++/impl/path.h b/include/toml++/impl/path.h index e0dd5133..32dac309 100644 --- a/include/toml++/impl/path.h +++ b/include/toml++/impl/path.h @@ -6,7 +6,6 @@ #include "forward_declarations.h" #include "std_vector.h" -#include "std_variant.h" #include "header_start.h" TOML_NAMESPACE_START @@ -14,34 +13,82 @@ TOML_NAMESPACE_START /// \brief Indicates type of path component, either a key, an index in an array, or invalid enum class TOML_CLOSED_ENUM path_component_type : uint8_t { - invalid = 0x0, key = 0x1, array_index = 0x2 }; - /// \brief Holds the value of a path component, either the name of the key in a string_view, or the index of an array as a size_t - using path_component_value = std::variant; - /// \brief Represents a single component of a complete 'TOML-path': either a key or an array index - struct TOML_EXPORTED_CLASS path_component + class TOML_EXPORTED_CLASS path_component { - friend class path; + struct storage_t + { + static constexpr size_t size = + (sizeof(size_t) < sizeof(std::string) ? sizeof(std::string) : sizeof(size_t)); + static constexpr size_t align = + (alignof(size_t) < alignof(std::string) ? alignof(std::string) : alignof(size_t)); - private: - /// \cond + alignas(align) unsigned char bytes[size]; + }; + alignas(storage_t::align) mutable storage_t value_storage_; - path_component_value value_; path_component_type type_; TOML_PURE_GETTER TOML_EXPORTED_STATIC_FUNCTION static bool TOML_CALLCONV equal(const path_component&, const path_component&) noexcept; + template + TOML_NODISCARD + TOML_ALWAYS_INLINE + static Type* get_as(storage_t& s) noexcept + { + return TOML_LAUNDER(reinterpret_cast(s.bytes)); + } + + static void store_key(std::string_view key, storage_t& storage_) + { + ::new (static_cast(storage_.bytes)) std::string{ key }; + } + + static void store_index(size_t index, storage_t& storage_) + { + ::new (static_cast(storage_.bytes)) std::size_t{ index }; + } + + void destroy() noexcept + { + if (type_ == path_component_type::key) + get_as(value_storage_)->~basic_string(); + } + + TOML_NODISCARD + size_t& index() & noexcept + { + TOML_ASSERT_ASSUME(type_ == path_component_type::array_index); + return *get_as(value_storage_); + } + + TOML_NODISCARD + std::string& key() & noexcept + { + TOML_ASSERT_ASSUME(type_ == path_component_type::key); + return *get_as(value_storage_); + } + + /// \brief Returns the key string (const rvalue overload). + TOML_NODISCARD + std::string&& key() && noexcept + { + TOML_ASSERT_ASSUME(type_ == path_component_type::key); + return static_cast(*get_as(value_storage_)); + } + /// \endcond public: - /// \brief Default constructor. + /// \brief Default constructor (creates an empty key). TOML_NODISCARD_CTOR - path_component() noexcept = default; + TOML_EXPORTED_MEMBER_FUNCTION + path_component(); /// \brief Constructor for a path component that is an array index TOML_NODISCARD_CTOR @@ -62,13 +109,92 @@ TOML_NAMESPACE_START #endif - /// \brief Retrieve the value of this path component, either the key name or the aray index - TOML_PURE_INLINE_GETTER - const path_component_value& value() const noexcept + /// \brief Copy constructor. + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + path_component(const path_component& pc); + + /// \brief Move constructor. + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + path_component(path_component&& pc) noexcept; + + /// \brief Copy-assignment operator. + TOML_EXPORTED_MEMBER_FUNCTION + path_component& operator=(const path_component & rhs); + + /// \brief Move-assignment operator. + TOML_EXPORTED_MEMBER_FUNCTION + path_component& operator=(path_component && rhs) noexcept; + + /// \brief Destructor. + ~path_component() noexcept + { + destroy(); + } + + /// \name Array index accessors and casts + /// @{ + + /// \brief Returns the array index (const lvalue overload). + TOML_NODISCARD + const size_t& index() const& noexcept { - return value_; + TOML_ASSERT_ASSUME(type_ == path_component_type::array_index); + return *get_as(value_storage_); } + /// \brief Returns the array index (const lvalue). + TOML_NODISCARD + /* implicit */ operator const size_t&() const noexcept + { + return index(); + } + + /// @} + + /// \name Key accessors and casts + /// @{ + + /// \brief Returns the key string (const lvalue overload). + TOML_NODISCARD + const std::string& key() const& noexcept + { + TOML_ASSERT_ASSUME(type_ == path_component_type::key); + return *get_as(value_storage_); + } + + /// \brief Returns the key string (const rvalue overload). + TOML_NODISCARD + const std::string&& key() const&& noexcept + { + TOML_ASSERT_ASSUME(type_ == path_component_type::key); + return static_cast(*get_as(value_storage_)); + } + + /// \brief Returns the key string. + TOML_NODISCARD + explicit operator const std::string&() noexcept + { + return key(); + } + + /// \brief Returns the key string (rvalue overload). + TOML_NODISCARD + explicit operator const std::string&&() noexcept + { + return std::move(key()); + } + + /// \brief Returns the key string (const lvalue overload). + TOML_NODISCARD + explicit operator const std::string&() const noexcept + { + return key(); + } + + /// @} + /// \brief Retrieve the type of this path component, either path_component::key or path_component::array_index TOML_PURE_INLINE_GETTER path_component_type type() const noexcept @@ -92,17 +218,17 @@ TOML_NAMESPACE_START /// \brief Assigns an array index to this path component. Index must castable to size_t TOML_EXPORTED_MEMBER_FUNCTION - path_component& operator=(size_t index) noexcept; + path_component& operator=(size_t new_index) noexcept; /// \brief Assigns a path key to this path component. Key must be a string type TOML_EXPORTED_MEMBER_FUNCTION - path_component& operator=(std::string_view key); + path_component& operator=(std::string_view new_key); #if TOML_ENABLE_WINDOWS_COMPAT /// \brief Assigns a path key to this path component using window wide char strings. Key must be a wide char string type TOML_EXPORTED_MEMBER_FUNCTION - path_component& operator=(std::wstring_view key); + path_component& operator=(std::wstring_view new_key); #endif diff --git a/include/toml++/impl/path.inl b/include/toml++/impl/path.inl index a55ca0cc..00845fea 100644 --- a/include/toml++/impl/path.inl +++ b/include/toml++/impl/path.inl @@ -29,50 +29,153 @@ TOML_ENABLE_WARNINGS; TOML_NAMESPACE_START { TOML_EXTERNAL_LINKAGE - path_component::path_component(size_t index) noexcept : value_(index), type_(path_component_type::array_index) - { } + path_component::path_component() // + : type_{ path_component_type::key } + { + store_key("", value_storage_); + } TOML_EXTERNAL_LINKAGE - path_component::path_component(std::string_view key) : value_(std::string(key)), type_(path_component_type::key) - { } + path_component::path_component(size_t index) noexcept // + : type_(path_component_type::array_index) + { + store_index(index, value_storage_); + } + + TOML_EXTERNAL_LINKAGE + path_component::path_component(std::string_view key) // + : type_(path_component_type::key) + { + store_key(key, value_storage_); + } #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXTERNAL_LINKAGE - path_component::path_component(std::wstring_view key) : value_(impl::narrow(key)), type_(path_component_type::key) + path_component::path_component(std::wstring_view key) // + : path_component(impl::narrow(key)) { } -#endif +#endif + + TOML_EXTERNAL_LINKAGE + path_component::path_component(const path_component & pc) // + : type_{ pc.type_ } + { + if (type_ == path_component_type::array_index) + store_index(pc.index(), value_storage_); + else + store_key(pc.key(), value_storage_); + } + + TOML_EXTERNAL_LINKAGE + path_component::path_component(path_component && pc) noexcept // + : type_{ pc.type_ } + { + if (type_ == path_component_type::array_index) + store_index(pc.index(), value_storage_); + else + store_key(std::move(pc).key(), value_storage_); + } + + TOML_EXTERNAL_LINKAGE + path_component& path_component::operator=(const path_component& rhs) + { + if (type_ != rhs.type_) + { + destroy(); + + type_ = rhs.type_; + if (type_ == path_component_type::array_index) + store_index(rhs.index(), value_storage_); + else + store_key(rhs.key(), value_storage_); + } + else + { + if (type_ == path_component_type::array_index) + index() = rhs.index(); + else + key() = rhs.key(); + } + return *this; + } + + TOML_EXTERNAL_LINKAGE + path_component& path_component::operator=(path_component&& rhs) noexcept + { + if (type_ != rhs.type_) + { + destroy(); + + type_ = rhs.type_; + if (type_ == path_component_type::array_index) + store_index(std::move(rhs).index(), value_storage_); + else + store_key(std::move(rhs).key(), value_storage_); + } + else + { + if (type_ == path_component_type::array_index) + index() = std::move(rhs).index(); + else + key() = std::move(rhs).key(); + } + return *this; + } TOML_EXTERNAL_LINKAGE bool TOML_CALLCONV path_component::equal(const path_component& lhs, const path_component& rhs) noexcept { - return lhs.type_ == rhs.type_ && lhs.value_ == rhs.value_; + // Different comparison depending on contents + if (lhs.type_ != rhs.type_) + return false; + + if (lhs.type_ == path_component_type::array_index) + return lhs.index() == rhs.index(); + else // path_component_type::key + return lhs.key() == rhs.key(); } TOML_EXTERNAL_LINKAGE - path_component& path_component::operator= (size_t index) noexcept + path_component& path_component::operator= (size_t new_index) noexcept { - value_ = static_cast(index); - type_ = path_component_type::array_index; + // If currently a key, string will need to be destroyed regardless + destroy(); + + type_ = path_component_type::array_index; + store_index(new_index, value_storage_); + return *this; } TOML_EXTERNAL_LINKAGE - path_component& path_component::operator= (std::string_view key) + path_component& path_component::operator= (std::string_view new_key) { - value_ = std::string(key); - type_ = path_component_type::key; + if (type_ == path_component_type::key) + key() = new_key; + else + { + type_ = path_component_type::key; + store_key(new_key, value_storage_); + } + return *this; } #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXTERNAL_LINKAGE - path_component& path_component::operator= (std::wstring_view key) + path_component& path_component::operator= (std::wstring_view new_key) { - value_ = std::string(impl::narrow(key)); - type_ = path_component_type::key; + if (type_ == path_component_type::key) + key() = impl::narrow(new_key); + else + { + type_ = path_component_type::key; + store_key(impl::narrow(new_key), value_storage_); + } + return *this; } @@ -127,16 +230,16 @@ TOML_NAMESPACE_START bool root = true; for (const auto& component : components_) { - if (component.type_ == path_component_type::key) // key + if (component.type() == path_component_type::key) // key { if (!root) impl::print_to_stream(os, '.'); - impl::print_to_stream(os, std::get(component.value_)); + impl::print_to_stream(os, component.key()); } - else if (component.type_ == path_component_type::array_index) // array + else if (component.type() == path_component_type::array_index) // array { impl::print_to_stream(os, '['); - impl::print_to_stream(os, std::get(component.value_)); + impl::print_to_stream(os, component.index()); impl::print_to_stream(os, ']'); } root = false; @@ -379,21 +482,21 @@ TOML_NAMESPACE_START for (const auto& component : path) { auto type = component.type(); - if (type == path_component_type::array_index && std::holds_alternative(component.value())) + if (type == path_component_type::array_index) { const auto current_array = current->as(); if (!current_array) return {}; // not an array, using array index doesn't work - current = current_array->get(std::get(component.value())); + current = current_array->get(component.index()); } - else if (type == path_component_type::key && std::holds_alternative(component.value())) + else if (type == path_component_type::key) { const auto current_table = current->as(); if (!current_table) return {}; - current = current_table->get(std::get(component.value())); + current = current_table->get(component.key()); } else { diff --git a/toml.hpp b/toml.hpp index 3f4caa48..91ba791e 100644 --- a/toml.hpp +++ b/toml.hpp @@ -2680,12 +2680,6 @@ TOML_DISABLE_WARNINGS; #include TOML_ENABLE_WARNINGS; -//******** impl/std_variant.h **************************************************************************************** - -TOML_DISABLE_WARNINGS; -#include -TOML_ENABLE_WARNINGS; - //******** impl/path.h *********************************************************************************************** TOML_PUSH_WARNINGS; @@ -2701,30 +2695,79 @@ TOML_NAMESPACE_START { enum class TOML_CLOSED_ENUM path_component_type : uint8_t { - invalid = 0x0, key = 0x1, array_index = 0x2 }; - using path_component_value = std::variant; - - struct TOML_EXPORTED_CLASS path_component + class TOML_EXPORTED_CLASS path_component { - friend class path; + struct storage_t + { + static constexpr size_t size = + (sizeof(size_t) < sizeof(std::string) ? sizeof(std::string) : sizeof(size_t)); + static constexpr size_t align = + (alignof(size_t) < alignof(std::string) ? alignof(std::string) : alignof(size_t)); - private: + alignas(align) unsigned char bytes[size]; + }; + alignas(storage_t::align) mutable storage_t value_storage_; - path_component_value value_; path_component_type type_; TOML_PURE_GETTER TOML_EXPORTED_STATIC_FUNCTION static bool TOML_CALLCONV equal(const path_component&, const path_component&) noexcept; + template + TOML_NODISCARD + TOML_ALWAYS_INLINE + static Type* get_as(storage_t& s) noexcept + { + return TOML_LAUNDER(reinterpret_cast(s.bytes)); + } + + static void store_key(std::string_view key, storage_t& storage_) + { + ::new (static_cast(storage_.bytes)) std::string{ key }; + } + + static void store_index(size_t index, storage_t& storage_) + { + ::new (static_cast(storage_.bytes)) std::size_t{ index }; + } + + void destroy() noexcept + { + if (type_ == path_component_type::key) + get_as(value_storage_)->~basic_string(); + } + + TOML_NODISCARD + size_t& index() & noexcept + { + TOML_ASSERT_ASSUME(type_ == path_component_type::array_index); + return *get_as(value_storage_); + } + + TOML_NODISCARD + std::string& key() & noexcept + { + TOML_ASSERT_ASSUME(type_ == path_component_type::key); + return *get_as(value_storage_); + } + + TOML_NODISCARD + std::string&& key() && noexcept + { + TOML_ASSERT_ASSUME(type_ == path_component_type::key); + return static_cast(*get_as(value_storage_)); + } + public: TOML_NODISCARD_CTOR - path_component() noexcept = default; + TOML_EXPORTED_MEMBER_FUNCTION + path_component(); TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION @@ -2742,10 +2785,68 @@ TOML_NAMESPACE_START #endif - TOML_PURE_INLINE_GETTER - const path_component_value& value() const noexcept + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + path_component(const path_component& pc); + + TOML_NODISCARD_CTOR + TOML_EXPORTED_MEMBER_FUNCTION + path_component(path_component&& pc) noexcept; + + TOML_EXPORTED_MEMBER_FUNCTION + path_component& operator=(const path_component & rhs); + + TOML_EXPORTED_MEMBER_FUNCTION + path_component& operator=(path_component && rhs) noexcept; + + ~path_component() noexcept { - return value_; + destroy(); + } + + TOML_NODISCARD + const size_t& index() const& noexcept + { + TOML_ASSERT_ASSUME(type_ == path_component_type::array_index); + return *get_as(value_storage_); + } + + TOML_NODISCARD + /* implicit */ operator const size_t&() const noexcept + { + return index(); + } + + TOML_NODISCARD + const std::string& key() const& noexcept + { + TOML_ASSERT_ASSUME(type_ == path_component_type::key); + return *get_as(value_storage_); + } + + TOML_NODISCARD + const std::string&& key() const&& noexcept + { + TOML_ASSERT_ASSUME(type_ == path_component_type::key); + return static_cast(*get_as(value_storage_)); + } + + TOML_NODISCARD + explicit operator const std::string&() noexcept + { + return key(); + } + + TOML_NODISCARD + explicit operator const std::string&&() noexcept + { + return std::move(key()); + } + + TOML_NODISCARD + explicit operator const std::string&() const noexcept + { + return key(); } TOML_PURE_INLINE_GETTER @@ -2767,15 +2868,15 @@ TOML_NAMESPACE_START } TOML_EXPORTED_MEMBER_FUNCTION - path_component& operator=(size_t index) noexcept; + path_component& operator=(size_t new_index) noexcept; TOML_EXPORTED_MEMBER_FUNCTION - path_component& operator=(std::string_view key); + path_component& operator=(std::string_view new_key); #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXPORTED_MEMBER_FUNCTION - path_component& operator=(std::wstring_view key); + path_component& operator=(std::wstring_view new_key); #endif }; @@ -10527,50 +10628,153 @@ TOML_PUSH_WARNINGS; TOML_NAMESPACE_START { TOML_EXTERNAL_LINKAGE - path_component::path_component(size_t index) noexcept : value_(index), type_(path_component_type::array_index) - { } + path_component::path_component() // + : type_{ path_component_type::key } + { + store_key("", value_storage_); + } TOML_EXTERNAL_LINKAGE - path_component::path_component(std::string_view key) : value_(std::string(key)), type_(path_component_type::key) - { } + path_component::path_component(size_t index) noexcept // + : type_(path_component_type::array_index) + { + store_index(index, value_storage_); + } + + TOML_EXTERNAL_LINKAGE + path_component::path_component(std::string_view key) // + : type_(path_component_type::key) + { + store_key(key, value_storage_); + } #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXTERNAL_LINKAGE - path_component::path_component(std::wstring_view key) : value_(impl::narrow(key)), type_(path_component_type::key) + path_component::path_component(std::wstring_view key) // + : path_component(impl::narrow(key)) { } #endif + TOML_EXTERNAL_LINKAGE + path_component::path_component(const path_component & pc) // + : type_{ pc.type_ } + { + if (type_ == path_component_type::array_index) + store_index(pc.index(), value_storage_); + else + store_key(pc.key(), value_storage_); + } + + TOML_EXTERNAL_LINKAGE + path_component::path_component(path_component && pc) noexcept // + : type_{ pc.type_ } + { + if (type_ == path_component_type::array_index) + store_index(pc.index(), value_storage_); + else + store_key(std::move(pc).key(), value_storage_); + } + + TOML_EXTERNAL_LINKAGE + path_component& path_component::operator=(const path_component& rhs) + { + if (type_ != rhs.type_) + { + destroy(); + + type_ = rhs.type_; + if (type_ == path_component_type::array_index) + store_index(rhs.index(), value_storage_); + else + store_key(rhs.key(), value_storage_); + } + else + { + if (type_ == path_component_type::array_index) + index() = rhs.index(); + else + key() = rhs.key(); + } + return *this; + } + + TOML_EXTERNAL_LINKAGE + path_component& path_component::operator=(path_component&& rhs) noexcept + { + if (type_ != rhs.type_) + { + destroy(); + + type_ = rhs.type_; + if (type_ == path_component_type::array_index) + store_index(std::move(rhs).index(), value_storage_); + else + store_key(std::move(rhs).key(), value_storage_); + } + else + { + if (type_ == path_component_type::array_index) + index() = std::move(rhs).index(); + else + key() = std::move(rhs).key(); + } + return *this; + } + TOML_EXTERNAL_LINKAGE bool TOML_CALLCONV path_component::equal(const path_component& lhs, const path_component& rhs) noexcept { - return lhs.type_ == rhs.type_ && lhs.value_ == rhs.value_; + // Different comparison depending on contents + if (lhs.type_ != rhs.type_) + return false; + + if (lhs.type_ == path_component_type::array_index) + return lhs.index() == rhs.index(); + else // path_component_type::key + return lhs.key() == rhs.key(); } TOML_EXTERNAL_LINKAGE - path_component& path_component::operator= (size_t index) noexcept + path_component& path_component::operator= (size_t new_index) noexcept { - value_ = static_cast(index); - type_ = path_component_type::array_index; + // If currently a key, string will need to be destroyed regardless + destroy(); + + type_ = path_component_type::array_index; + store_index(new_index, value_storage_); + return *this; } TOML_EXTERNAL_LINKAGE - path_component& path_component::operator= (std::string_view key) + path_component& path_component::operator= (std::string_view new_key) { - value_ = std::string(key); - type_ = path_component_type::key; + if (type_ == path_component_type::key) + key() = new_key; + else + { + type_ = path_component_type::key; + store_key(new_key, value_storage_); + } + return *this; } #if TOML_ENABLE_WINDOWS_COMPAT TOML_EXTERNAL_LINKAGE - path_component& path_component::operator= (std::wstring_view key) + path_component& path_component::operator= (std::wstring_view new_key) { - value_ = std::string(impl::narrow(key)); - type_ = path_component_type::key; + if (type_ == path_component_type::key) + key() = impl::narrow(new_key); + else + { + type_ = path_component_type::key; + store_key(impl::narrow(new_key), value_storage_); + } + return *this; } @@ -10620,16 +10824,16 @@ TOML_NAMESPACE_START bool root = true; for (const auto& component : components_) { - if (component.type_ == path_component_type::key) // key + if (component.type() == path_component_type::key) // key { if (!root) impl::print_to_stream(os, '.'); - impl::print_to_stream(os, std::get(component.value_)); + impl::print_to_stream(os, component.key()); } - else if (component.type_ == path_component_type::array_index) // array + else if (component.type() == path_component_type::array_index) // array { impl::print_to_stream(os, '['); - impl::print_to_stream(os, std::get(component.value_)); + impl::print_to_stream(os, component.index()); impl::print_to_stream(os, ']'); } root = false; @@ -10856,21 +11060,21 @@ TOML_NAMESPACE_START for (const auto& component : path) { auto type = component.type(); - if (type == path_component_type::array_index && std::holds_alternative(component.value())) + if (type == path_component_type::array_index) { const auto current_array = current->as(); if (!current_array) return {}; // not an array, using array index doesn't work - current = current_array->get(std::get(component.value())); + current = current_array->get(component.index()); } - else if (type == path_component_type::key && std::holds_alternative(component.value())) + else if (type == path_component_type::key) { const auto current_table = current->as
(); if (!current_table) return {}; - current = current_table->get(std::get(component.value())); + current = current_table->get(component.key()); } else {