utempl/include/utempl/meta_info.hpp

82 lines
2.5 KiB
C++

#pragma once
#include <utempl/loopholes/counter.hpp>
#include <utempl/type_list.hpp>
namespace utempl {
namespace impl {
struct Types {};
} // namespace impl
template <std::size_t Id, typename Tag>
struct MetaInfoKey {};
template <typename T, typename Tag = impl::Types>
struct MetaInfo {
static constexpr std::size_t kTypeId = loopholes::Counter<Tag, T>();
using Type = T;
private:
static constexpr auto _ = loopholes::Injector<MetaInfoKey<kTypeId, Tag>{}, TypeList<T>{}>{};
};
template <typename T, typename Tag = impl::Types>
inline constexpr std::size_t kTypeId = MetaInfo<T, Tag>::kTypeId;
template <typename Tag,
typename T,
typename... Ts,
typename... TTs,
std::size_t Id = loopholes::Counter<Tag, T, Ts..., TTs...>(),
auto = loopholes::Injector<MetaInfoKey<Id, Tag>{}, TypeList<T>{}>{}>
consteval auto AddTypeToTag(TTs&&...) -> std::size_t {
return Id;
};
template <std::size_t Id, typename Tag = impl::Types>
using GetMetaInfo = MetaInfo<typename decltype(Magic(loopholes::Getter<MetaInfoKey<Id, Tag>{}>{}))::Type>;
template <std::size_t Id, typename Tag = impl::Types>
using GetType = GetMetaInfo<Id, Tag>::Type;
namespace impl {
template <typename Tag, std::size_t I = 0, typename... Ts, typename G>
static consteval auto GetTypeListForTag(G g)
requires(I == 0 || requires { Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{}); })
{
if constexpr(I == 0 && !requires { Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{}); }) {
return TypeList{};
} else {
if constexpr(requires { GetTypeListForTag<Tag, I + 1, Ts...>(g); }) {
constexpr auto type = Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{});
return GetTypeListForTag<Tag, I + 1, Ts..., typename decltype(type)::Type>(g);
} else {
constexpr auto type = Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{});
return TypeList<Ts..., typename decltype(type)::Type>();
};
};
};
} // namespace impl
template <typename Tag = impl::Types, typename... Ts>
consteval auto GetTypeListForTag() {
return impl::GetTypeListForTag<Tag>(TypeList<Ts...>{});
};
template <typename Tag, typename... Ts, auto I = utempl::loopholes::CountValue<Tag, Ts...>() - 1>
consteval auto GetCurrentTagType() {
return Magic(utempl::loopholes::Getter<MetaInfoKey<I, Tag>{}>());
};
/*
static_assert(kTypeId<int> == 0);
static_assert(kTypeId<void> == 1);
static_assert(AddTypeToTag<impl::Types, void, int>() == 2);
static_assert(std::is_same_v<decltype(GetTypeListForTag()), TypeList<int, void, void>>);
*/
} // namespace utempl