95 lines
3.2 KiB
C++
95 lines
3.2 KiB
C++
#pragma once
|
|
#include <utempl/type_list.hpp>
|
|
|
|
namespace utempl {
|
|
|
|
template <auto>
|
|
struct Wrapper;
|
|
namespace impl {
|
|
|
|
template <auto, typename T>
|
|
struct TupleLeaf {
|
|
T value;
|
|
template <typename TT>
|
|
inline constexpr TupleLeaf(TT&& arg) : value(std::forward<TT>(arg)) {};
|
|
inline constexpr TupleLeaf(const TupleLeaf&) = default;
|
|
inline constexpr TupleLeaf(TupleLeaf&&) = default;
|
|
inline constexpr bool operator==(const TupleLeaf&) const = default;
|
|
};
|
|
|
|
|
|
template <typename, typename...>
|
|
struct TupleHelper;
|
|
|
|
template <std::size_t... Is, typename... Ts>
|
|
struct TupleHelper<std::index_sequence<Is...>, Ts...> : public TupleLeaf<Is, Ts>... {
|
|
template <typename... TTs>
|
|
inline constexpr TupleHelper(TTs&&... args) :
|
|
TupleLeaf<Is, Ts>{std::forward<TTs>(args)}... {};
|
|
inline constexpr TupleHelper(const TupleHelper&) = default;
|
|
inline constexpr TupleHelper(TupleHelper&&) = default;
|
|
inline constexpr bool operator==(const TupleHelper&) const = default;
|
|
};
|
|
|
|
} // namespace impl
|
|
|
|
template <typename... Ts>
|
|
struct Tuple;
|
|
|
|
template <std::size_t I, typename... Ts>
|
|
inline constexpr auto Get(Tuple<Ts...>& tuple) -> auto& requires (I < sizeof...(Ts)) {
|
|
using Type = decltype(Get<I>(TypeList<Ts...>{}));
|
|
return static_cast<impl::TupleLeaf<I, Type>&>(tuple).value;
|
|
};
|
|
|
|
template <std::size_t I, typename... Ts>
|
|
inline constexpr auto Get(const Tuple<Ts...>& tuple) -> const auto& requires (I < sizeof...(Ts)) {
|
|
using Type = decltype(Get<I>(TypeList<Ts...>{}));
|
|
return static_cast<const impl::TupleLeaf<I, Type>&>(tuple).value;
|
|
};
|
|
|
|
template <std::size_t I, typename... Ts>
|
|
inline constexpr auto Get(Tuple<Ts...>&& tuple) -> auto&& requires (I < sizeof...(Ts)) {
|
|
using Type = decltype(Get<I>(TypeList<Ts...>{}));
|
|
return std::move(static_cast<impl::TupleLeaf<I, Type>&&>(tuple).value);
|
|
};
|
|
|
|
template <std::size_t I, typename T>
|
|
inline constexpr auto Get(T&& arg) -> decltype(get<I>(std::forward<T>(arg))) {
|
|
return get<I>(std::forward<T>(arg));
|
|
};
|
|
|
|
template <typename... Ts>
|
|
struct Tuple : public impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...> {
|
|
template <typename... TTs>
|
|
inline constexpr Tuple(TTs&&... args) :
|
|
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>(std::forward<TTs>(args)...) {};
|
|
inline constexpr Tuple(const Tuple&) = default;
|
|
inline constexpr Tuple(Tuple&&) = default;
|
|
inline constexpr bool operator==(const Tuple&) const = default;
|
|
template <typename... TTs>
|
|
inline constexpr auto operator+(const Tuple<TTs...>& other) const -> Tuple<Ts..., TTs...> {
|
|
return [&]<auto... Is, auto... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>) -> Tuple<Ts..., TTs...> {
|
|
return {Get<Is>(*this)..., Get<IIs>(other)...};
|
|
}(std::make_index_sequence<sizeof...(Ts)>(), std::make_index_sequence<sizeof...(TTs)>());
|
|
};
|
|
template <auto I>
|
|
inline constexpr auto operator[](Wrapper<I>) const -> const auto& {
|
|
return Get<I>(*this);
|
|
};
|
|
template <auto I>
|
|
inline constexpr auto operator[](Wrapper<I>) -> auto& {
|
|
return Get<I>(*this);
|
|
};
|
|
};
|
|
|
|
template <typename... Ts>
|
|
Tuple(Ts&&...) -> Tuple<std::remove_cvref_t<Ts>...>;
|
|
|
|
template <typename... Ts>
|
|
consteval auto ListFromTuple(Tuple<Ts...>) -> TypeList<Ts...> {
|
|
return {};
|
|
};
|
|
|
|
|
|
} // namespace utempl
|