export module utempl.tuple; import utempl.type_list; import utempl.overloaded; import std; namespace utempl { export template struct Wrapper { static constexpr auto kValue = Value; static constexpr auto value = Value; inline constexpr auto operator==(auto&& arg) const { return arg == Value; }; consteval operator decltype(Value)() const { // NOLINT return Value; }; consteval auto operator*() const { return Value; }; }; template struct TupleLeaf { T value; constexpr auto operator==(const TupleLeaf&) const -> bool = default; }; template struct TupleHelper; template struct TupleHelper, Ts...> : public TupleLeaf... { constexpr auto operator==(const TupleHelper&) const -> bool = default; }; export template struct Tuple; export template constexpr auto Get(Tuple& tuple) -> auto& requires(I < sizeof...(Ts)) { using Type = decltype(Get(TypeList{})); return static_cast&>(tuple).value; }; export template constexpr auto Get(const Tuple& tuple) -> const auto& requires(I < sizeof...(Ts)) { using Type = decltype(Get(TypeList{})); return static_cast&>(tuple).value; }; export template constexpr auto Get(Tuple&& tuple) -> decltype(auto) requires(I < sizeof...(Ts)) { using Type = decltype(Get(TypeList{})); return std::move(static_cast&&>(tuple).value); }; export template constexpr auto Get(T&& arg) -> decltype(get(std::forward(arg))) { return get(std::forward(arg)); }; export template struct Tuple : TupleHelper, Ts...> { template constexpr Tuple(TTs&&... args) /* NOLINT */ : TupleHelper, Ts...>{{std::forward(args)}...} {}; template constexpr Tuple(Fs&&... fs) // NOLINT requires(!std::invocable || ...) : TupleHelper, Ts...>{{fs()}...} {}; constexpr Tuple(Ts&&... args) : TupleHelper, Ts...>{{args}...} {}; // NOLINT constexpr Tuple(const Tuple&) = default; constexpr Tuple(Tuple&&) = default; constexpr Tuple(Tuple&) = default; constexpr auto operator=(const Tuple&) -> Tuple& = default; constexpr auto operator=(Tuple&&) -> Tuple& = default; constexpr auto operator=(Tuple&) -> Tuple& = default; constexpr Tuple() : TupleHelper, Ts...>() {}; constexpr auto operator==(const Tuple& other) const -> bool { return [&](std::index_sequence) { return ((Get(*this) == Get(other)) && ...); }(std::index_sequence_for()); }; template constexpr auto operator+(const Tuple& other) const -> Tuple { return [&](std::index_sequence, std::index_sequence) -> Tuple { return {Get(*this)..., Get(other)...}; }(std::index_sequence_for(), std::index_sequence_for()); }; template constexpr auto operator[](Wrapper) const -> const auto& { return Get(*this); }; template constexpr auto operator[](Wrapper) -> auto& { return Get(*this); }; }; export template <> struct Tuple<> { template constexpr auto operator+(const Tuple& other) const -> Tuple { return other; }; constexpr auto operator==(const Tuple<>&) const { return true; }; }; export template Tuple(Ts&&...) -> Tuple...>; export template consteval auto ListFromTuple(Tuple) -> TypeList { return {}; }; } // namespace utempl