Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 96 additions & 24 deletions include/iris/type_list.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,97 @@ struct concat_type_list<type_list<Ts...>, type_list<Us...>, Rest...>

// ----------------------------------------------------------

namespace detail {
template<class... Ts>
struct type_bases : Ts...
{
template<template<class...> class TT>
using rebind = TT<Ts...>;
};

template<class... Ts>
struct identity_bases : std::type_identity<Ts>...
requires (sizeof...(Ts) > 0)
struct type_bases<std::type_identity<Ts>...> : std::type_identity<Ts>...
{
template<template<class...> class TT>
using rebind = TT<Ts...>;
};

namespace detail {

template<class Bases, class T>
struct type_bases_push_back_impl;

template<class... Ts, class T>
struct type_bases_push_back_impl<type_bases<std::type_identity<Ts>...>, T>
{
using type = type_bases<std::type_identity<Ts>..., std::type_identity<T>>;
};

} // detail

template<class Bases, class T>
using type_bases_push_back = detail::type_bases_push_back_impl<Bases, T>::type;

// --------------------------------------------------

template<class... Ts>
using identity_bases = type_bases<std::type_identity<Ts>...>;

template<class T, class BasesT>
concept identity_base_of = requires(BasesT* bases) {
concept has_identity_base = requires(BasesT* bases) {
static_cast<std::type_identity<T>*>(bases);
};

// --------------------------------------------------

template<std::size_t I, class T>
struct indexed_virtual_identity : virtual std::type_identity<T>
{
static void select(std::type_identity<T>*);
};

template<std::size_t... Is, class... Ts>
requires (sizeof...(Ts) > 0)
struct type_bases<indexed_virtual_identity<Is, Ts>...> : indexed_virtual_identity<Is, Ts>...
{
template<template<class...> class TT>
using rebind = TT<Ts...>;

using indexed_virtual_identity<Is, Ts>::select...;
};

template<class T, class BasesT>
concept has_exactly_one_identity_base = requires(std::type_identity<T>* base) {
// If multiple bases exist, overload resolution is ambiguous
BasesT::select(base);
};

// --------------------------------------------------

namespace detail {

template<template<std::size_t, class> class IdentityTT, class Indexes, class... Ts>
struct indexed_identity_bases_impl;

template<template<std::size_t, class> class IdentityTT, std::size_t... Is, class... Ts>
struct indexed_identity_bases_impl<
IdentityTT, std::index_sequence<Is...>, Ts...
>
{
using type = type_bases<IdentityTT<Is, Ts>...>;
};

} // detail

template<class... Ts>
using indexed_virtual_identity_bases = detail::indexed_identity_bases_impl<
indexed_virtual_identity, std::index_sequence_for<Ts...>, Ts...
>::type;

// --------------------------------------------------

namespace detail {

template<class BasesT, class... Ts>
struct unique_type_list_impl;

Expand All @@ -83,13 +160,13 @@ struct unique_type_list_impl<BasesT>
};

template<class BasesT, class T, class... Rest>
requires identity_base_of<T, BasesT>
requires has_identity_base<T, BasesT>
struct unique_type_list_impl<BasesT, T, Rest...>
: unique_type_list_impl<BasesT, Rest...>
{};

template<class... AcceptedTs, class T, class... Rest>
requires (!identity_base_of<T, identity_bases<AcceptedTs...>>)
requires (!has_identity_base<T, identity_bases<AcceptedTs...>>)
struct unique_type_list_impl<identity_bases<AcceptedTs...>, T, Rest...>
: unique_type_list_impl<identity_bases<AcceptedTs..., T>, Rest...>
{};
Expand All @@ -109,7 +186,7 @@ template<class... Ts>
struct unique_type_list<type_list<Ts...>>
{
using type = detail::unique_type_list_impl<
detail::identity_bases<>, Ts...
identity_bases<>, Ts...
>::type::template rebind<type_list>;
};

Expand Down Expand Up @@ -248,33 +325,28 @@ inline constexpr std::size_t find_index_v = find_index<T, List>::value;


template<class T, class... Ts>
struct is_in : std::disjunction<std::is_same<T, Ts>...> {};
struct is_in : std::bool_constant<
has_identity_base<T, indexed_virtual_identity_bases<Ts...>>
>
{};

template<class T, class... Ts>
inline constexpr bool is_in_v = is_in<T, Ts...>::value;
inline constexpr bool is_in_v = has_identity_base<T, indexed_virtual_identity_bases<Ts...>>;

// ----------------------------------------------------------

namespace detail {

template<bool Found, class T, class... Us>
struct exactly_once_impl : std::bool_constant<Found> {};

template<class T, class U, class... Us>
struct exactly_once_impl<false, T, U, Us...>
: exactly_once_impl<std::is_same_v<T, U>, T, Us...> {};

template<class T, class U, class... Us>
struct exactly_once_impl<true, T, U, Us...>
: std::conditional_t<std::is_same_v<T, U>, std::false_type, exactly_once_impl<true, T, Us...>> {};

} // detail

template<class T, class List>
struct exactly_once;

template<class T, template<class...> class TT, class... Ts>
struct exactly_once<T, TT<Ts...>> : detail::exactly_once_impl<false, T, Ts...>
struct exactly_once<T, TT<Ts...>> : std::false_type
{
static_assert(sizeof...(Ts) > 0);
};

template<class T, template<class...> class TT, class... Ts>
requires has_exactly_one_identity_base<T, indexed_virtual_identity_bases<Ts...>>
struct exactly_once<T, TT<Ts...>> : std::true_type
{
static_assert(sizeof...(Ts) > 0);
};
Expand Down
2 changes: 1 addition & 1 deletion test/type_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ TEST_CASE("pack_indexing")
TEST_CASE("exactly_once")
{
STATIC_CHECK(iris::exactly_once_v<int, type_list<int, float>>);
STATIC_CHECK_FALSE(iris::exactly_once_v<int, type_list<int, int>>);
STATIC_CHECK(!iris::exactly_once_v<int, type_list<int, int>>);
}

TEST_CASE("is_in")
Expand Down
Loading