#pragma once #include "yacppdic/detail/internal/misc_concepts.hpp" #include "yacppdic/detail/internal/tuple_indices.hpp" #include #include #include #include namespace yacppdic::internal { // Tag used to default initialize one or both of the pair's elements. class DefaultInitTag { }; class ValueInitTag { }; template concept ValueCanBeEmptyBase = std::is_empty_v && !std::is_final_v; template class CompressedPairElement { public: using ValueReference = Value &; using ConstValueReference = const Value &; constexpr explicit CompressedPairElement(DefaultInitTag /*default_init_tag*/ ) noexcept {}; constexpr explicit CompressedPairElement(ValueInitTag /*value_init_tag*/) noexcept : _value() { } template requires std::same_as> // NOLINTNEXTLINE(bugprone-forwarding-reference-overload) constexpr explicit CompressedPairElement(ElementValue &&value) noexcept : _value(std::forward(value)) { } template constexpr CompressedPairElement( std::piecewise_construct_t /*tag_type*/, std::tuple args, TupleIndices /*tuple_indices*/ ) noexcept : _value(std::forward(std::get(args))...) { } auto get() noexcept -> ValueReference { return _value; } [[nodiscard]] auto get() const noexcept -> ConstValueReference { return _value; } private: Value _value; }; template requires ValueCanBeEmptyBase class CompressedPairElement : private Value { public: using ValueReference = Value &; using ConstValueReference = const Value &; constexpr CompressedPairElement() noexcept = default; constexpr explicit CompressedPairElement(DefaultInitTag /*unused*/) noexcept {} constexpr explicit CompressedPairElement(ValueInitTag /*unused*/) noexcept : Value() { } template requires std::same_as::type> // NOLINTNEXTLINE(bugprone-forwarding-reference-overload) constexpr explicit CompressedPairElement(ElementValue &&value) noexcept : Value(std::forward(value)) { } template constexpr CompressedPairElement( std::piecewise_construct_t /*unused*/, std::tuple args, TupleIndices /*unused*/ ) noexcept : Value(std::forward(std::get(args))...) { } auto get() noexcept -> ValueReference { return *this; } [[nodiscard]] auto get() const noexcept -> ConstValueReference { return *this; } }; template requires NotSameAs class CompressedPair : private CompressedPairElement, private CompressedPairElement { public: using BaseOne = CompressedPairElement; using BaseTwo = CompressedPairElement; template requires std::default_initializable && std::default_initializable constexpr CompressedPair() noexcept; template constexpr CompressedPair( FirstValue &&first_value, SecondValue &&second_value ) noexcept; template constexpr CompressedPair( std::piecewise_construct_t piecewise_construct, std::tuple first_args, std::tuple second_args ) noexcept; auto first() noexcept -> typename BaseOne::ValueReference; [[nodiscard]] auto first() const noexcept -> typename BaseOne::ConstValueReference; auto second() noexcept -> typename BaseTwo::ValueReference; [[nodiscard]] auto second() const noexcept -> typename BaseTwo::ConstValueReference; constexpr static auto get_first_base(CompressedPair *pair) noexcept -> BaseOne *; constexpr static auto get_second_base(CompressedPair *pair) noexcept -> BaseTwo *; }; } // namespace yacppdic::internal #include "compressed_pair-impl.hpp"