diff options
Diffstat (limited to 'src/DI/compressed_pair.hpp')
-rw-r--r-- | src/DI/compressed_pair.hpp | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/DI/compressed_pair.hpp b/src/DI/compressed_pair.hpp new file mode 100644 index 0000000..6e05e29 --- /dev/null +++ b/src/DI/compressed_pair.hpp @@ -0,0 +1,188 @@ +#pragma once + +#include "DI/extra_concepts.hpp" + +#include <concepts> +#include <tuple> +#include <type_traits> +#include <utility> + +// Tag used to default initialize one or both of the pair's elements. +struct DefaultInitTag +{ +}; + +struct ValueInitTag +{ +}; + +template <size_t...> +struct TupleIndices +{ +}; + +template <class IdxType, IdxType... Values> +struct IntegerSequence +{ + template <template <class OIdxType, OIdxType...> class ToIndexSeq, class ToIndexType> + using Convert = ToIndexSeq<ToIndexType, Values...>; + + template <size_t Sp> + using ToTupleIndices = TupleIndices<(Values + Sp)...>; +}; + +template <size_t SizeOne, size_t SizeTwo> +using MakeIndices = + typename __make_integer_seq<IntegerSequence, size_t, + SizeOne - SizeTwo>::template ToTupleIndices<SizeTwo>; + +template <size_t SizeOne, size_t SizeTwo = 0> +requires(SizeTwo <= SizeOne) struct MakeTupleIndices +{ + using type = MakeIndices<SizeOne, SizeTwo>; +}; + +template <typename Value> +concept ValueCanBeEmptyBase = std::is_empty_v<Value> && !std::is_final_v<Value>; + +template <class Value, int Idx> +struct CompressedPairElement +{ + using ValueReference = Value &; + using ConstValueReference = const Value &; + + constexpr explicit CompressedPairElement(DefaultInitTag /*unused*/) {} + + constexpr explicit CompressedPairElement(ValueInitTag /*unused*/) : _value() {} + + template <class ElementValue> + requires std::same_as<CompressedPairElement, typename std::decay<ElementValue>::type> + // NOLINTNEXTLINE(bugprone-forwarding-reference-overload) + constexpr explicit CompressedPairElement(ElementValue &&value) + : _value(std::forward<ElementValue>(value)) + { + } + + template <class... Args, size_t... Indexes> + constexpr CompressedPairElement(std::piecewise_construct_t /*unused*/, + std::tuple<Args...> args, + TupleIndices<Indexes...> /*unused*/) + : _value(std::forward<Args>(std::get<Indexes>(args))...) + { + } + + auto get() noexcept -> ValueReference + { + return _value; + } + + [[nodiscard]] auto get() const noexcept -> ConstValueReference + { + return _value; + } + +private: + Value _value; +}; + +template <class Value, int Idx> +requires ValueCanBeEmptyBase<Value> +struct CompressedPairElement<Value, Idx> : private Value +{ + using ValueReference = Value &; + using ConstValueReference = const Value &; + + constexpr CompressedPairElement() = default; + + constexpr explicit CompressedPairElement(DefaultInitTag /*unused*/) {} + + constexpr explicit CompressedPairElement(ValueInitTag /*unused*/) : Value() {} + + template <class ElementValue> + requires std::same_as<CompressedPairElement, typename std::decay<ElementValue>::type> + // NOLINTNEXTLINE(bugprone-forwarding-reference-overload) + constexpr explicit CompressedPairElement(ElementValue &&value) + : Value(std::forward<ElementValue>(value)) + { + } + + template <class... Args, size_t... Indexes> + constexpr CompressedPairElement(std::piecewise_construct_t /*unused*/, + std::tuple<Args...> args, + TupleIndices<Indexes...> /*unused*/) + : Value(std::forward<Args>(std::get<Indexes>(args))...) + { + } + + auto get() noexcept -> ValueReference + { + return *this; + } + + [[nodiscard]] auto get() const noexcept -> ConstValueReference + { + return *this; + } +}; + +template <class ValueOne, class ValueTwo> +requires NotSameAs<ValueOne, ValueTwo> +class CompressedPair : private CompressedPairElement<ValueOne, 0>, + private CompressedPairElement<ValueTwo, 1> +{ +public: + using BaseOne = CompressedPairElement<ValueOne, 0>; + using BaseTwo = CompressedPairElement<ValueTwo, 1>; + + template <typename> + requires std::default_initializable<ValueOne> && std::default_initializable<ValueTwo> + constexpr CompressedPair() : BaseOne(ValueInitTag()), BaseTwo(ValueInitTag()) {} + + template <class FirstValue, class SecondValue> + constexpr CompressedPair(FirstValue &&first_value, SecondValue &&second_value) + : BaseOne(std::forward<FirstValue>(first_value)), + BaseTwo(std::forward<SecondValue>(second_value)) + { + } + + template <class... ArgsOne, class... ArgsTwo> + constexpr CompressedPair(std::piecewise_construct_t piecewise_construct, + std::tuple<ArgsOne...> first_args, + std::tuple<ArgsTwo...> second_args) + : BaseOne(piecewise_construct, std::move(first_args), + typename MakeTupleIndices<sizeof...(ArgsOne)>::type()), + BaseTwo(piecewise_construct, std::move(second_args), + typename MakeTupleIndices<sizeof...(ArgsTwo)>::type()) + { + } + + auto first() noexcept -> typename BaseOne::ValueReference + { + return static_cast<BaseOne &>(*this).get(); + } + + [[nodiscard]] auto first() const noexcept -> typename BaseOne::ConstValueReference + { + return static_cast<BaseOne const &>(*this).get(); + } + + auto second() noexcept -> typename BaseTwo::ValueReference + { + return static_cast<BaseTwo &>(*this).get(); + } + + [[nodiscard]] auto second() const noexcept -> typename BaseTwo::ConstValueReference + { + return static_cast<BaseTwo const &>(*this).get(); + } + + constexpr static auto get_first_base(CompressedPair *pair) noexcept -> BaseOne * + { + return static_cast<BaseOne *>(pair); + } + + constexpr static auto get_second_base(CompressedPair *pair) noexcept -> BaseTwo * + { + return static_cast<BaseTwo *>(pair); + } +}; |