aboutsummaryrefslogtreecommitdiff
path: root/src/DI/compressed_pair.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/DI/compressed_pair.hpp')
-rw-r--r--src/DI/compressed_pair.hpp188
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);
+ }
+};