Added etl::type_list_all_of, etl::type_list_any_of, and etl::type_list_none_of

This commit is contained in:
John Wellbelove 2026-02-19 09:16:13 +00:00
parent dc0f62cc3f
commit 25b88e509b
2 changed files with 217 additions and 11 deletions

View File

@ -183,7 +183,7 @@ namespace etl
template <typename TTypeList, typename T>
struct type_list_index_of_type
: public etl::integral_constant<size_t, etl::is_same<typename TTypeList::head, T>::value ? 0 :
(type_list_index_of_type<typename TTypeList::tail, T>::value == etl::type_list_npos ? etl::type_list_npos :
(type_list_index_of_type<typename TTypeList::tail, T>::value == etl::type_list_npos ? etl::type_list_npos :
type_list_index_of_type<typename TTypeList::tail, T>::value + 1)>
{
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
@ -606,6 +606,78 @@ namespace etl
using type_list_unique_t = typename etl::type_list_unique<TTypeList>::type;
#endif
//***************************************************************************
/// Checks that all types in a type_list satisfy a unary predicate.
/// Predicate must be: template <typename T> struct Pred : etl::bool_constant<...> {};
//***************************************************************************
template <typename TTypeList, template <typename> class TPredicate>
struct type_list_all_of;
template <template <typename> class TPredicate, typename... TTypes>
struct type_list_all_of<etl::type_list<TTypes...>, TPredicate>
: etl::conjunction<TPredicate<TTypes>...>
{
};
template <template <typename> class TPredicate>
struct type_list_all_of<etl::type_list<>, TPredicate>
: etl::bool_constant<false>
{
};
#if ETL_USING_CPP17
template <typename TTypeList, template <typename> class TPredicate>
inline constexpr bool type_list_all_of_v = type_list_all_of<TTypeList, TPredicate>::value;
#endif
//***************************************************************************
/// Checks that any type in a type_list satisfies a unary predicate.
/// Predicate must be: template <typename T> struct Pred : etl::bool_constant<...> {};
//***************************************************************************
template <typename TTypeList, template <typename> class TPredicate>
struct type_list_any_of;
template <template <typename> class TPredicate, typename... TTypes>
struct type_list_any_of<etl::type_list<TTypes...>, TPredicate>
: etl::disjunction<TPredicate<TTypes>...>
{
};
template <template <typename> class TPredicate>
struct type_list_any_of<etl::type_list<>, TPredicate>
: etl::bool_constant<false>
{
};
#if ETL_USING_CPP17
template <typename TTypeList, template <typename> class TPredicate>
inline constexpr bool type_list_any_of_v = type_list_any_of<TTypeList, TPredicate>::value;
#endif
//***************************************************************************
/// Checks that no types in a type_list satisfy a unary predicate.
/// Predicate must be: template <typename T> struct Pred : etl::bool_constant<...> {};
//***************************************************************************
template <typename TTypeList, template <typename> class TPredicate>
struct type_list_none_of;
template <template <typename> class TPredicate, typename... TTypes>
struct type_list_none_of<etl::type_list<TTypes...>, TPredicate>
: etl::negation<etl::disjunction<TPredicate<TTypes>...>>
{
};
template <template <typename> class TPredicate>
struct type_list_none_of<etl::type_list<>, TPredicate>
: etl::bool_constant<true>
{
};
#if ETL_USING_CPP17
template <typename TTypeList, template <typename> class TPredicate>
inline constexpr bool type_list_none_of_v = type_list_none_of<TTypeList, TPredicate>::value;
#endif
//***************************************************************************
/// Checks that two type lists are convertible.
/// Static asserts if the type lists are not the same length.
@ -616,15 +688,15 @@ namespace etl
// Specialization: both lists empty, convertible
template <>
struct type_lists_are_convertible<etl::type_list<>, etl::type_list<>>
struct type_lists_are_convertible<etl::type_list<>, etl::type_list<>>
: public etl::true_type
{
};
// Recursive case: check head types, then recurse
template <typename TFromHead, typename... TFromTail, typename TToHead, typename... TToTail>
struct type_lists_are_convertible<etl::type_list<TFromHead, TFromTail...>, etl::type_list<TToHead, TToTail...>>
: public etl::bool_constant<etl::is_convertible<TFromHead, TToHead>::value &&
struct type_lists_are_convertible<etl::type_list<TFromHead, TFromTail...>, etl::type_list<TToHead, TToTail...>>
: public etl::bool_constant<etl::is_convertible<TFromHead, TToHead>::value &&
etl::type_lists_are_convertible<etl::type_list<TFromTail...>, etl::type_list<TToTail...>>::value>
{
static_assert(sizeof...(TFromTail) == sizeof...(TToTail), "Type lists are not the same length");
@ -686,7 +758,7 @@ namespace etl
//*****************************************************************************
namespace private_type_list
{
{
//*********************************
template <bool InsertBefore, typename Head, typename T, template <typename, typename> class TCompare, typename... Tail>
struct insert_sorted_impl;

View File

@ -36,18 +36,29 @@ namespace
{
#if ETL_USING_CPP11
struct A { static constexpr int id = 0; };
struct B { static constexpr int id = 1; };
struct C { static constexpr int id = 2; };
template <typename T>
struct is_type_a : etl::bool_constant<std::is_same<T, A>::value>
{
};
template <typename T>
struct is_type_b : etl::bool_constant<std::is_same<T, B>::value>
{
};
template <typename T>
struct is_type_c : etl::bool_constant<std::is_same<T, C>::value>
{
};
// Convenience comparator for types that expose a constexpr integral ID (ascending)
template <typename T1, typename T2>
struct by_asencding_id : etl::bool_constant<(T1::id < T2::id)>
struct by_ascencding_id : etl::bool_constant<(T1::id < T2::id)>
{
};
@ -300,7 +311,7 @@ namespace
TEST(test_type_list_sort_empty_list)
{
using list = etl::type_list<>;
using result = etl::type_list_sort_t<list, by_asencding_id>;
using result = etl::type_list_sort_t<list, by_ascencding_id>;
using expected = etl::type_list<>;
CHECK((etl::is_same<result, expected>::value));
@ -311,7 +322,7 @@ namespace
TEST(test_type_list_sort_single_list)
{
using list = etl::type_list<A>;
using result = etl::type_list_sort_t<list, by_asencding_id>;
using result = etl::type_list_sort_t<list, by_ascencding_id>;
using expected = etl::type_list<A>;
CHECK((etl::is_same<result, expected>::value));
@ -322,7 +333,7 @@ namespace
TEST(test_type_list_sort_multiple_list)
{
using list = etl::type_list<B, C, A>;
using result = etl::type_list_sort_t<list, by_asencding_id>;
using result = etl::type_list_sort_t<list, by_ascencding_id>;
using expected = etl::type_list<A, B, C>;
CHECK((etl::is_same<result, expected>::value));
@ -398,7 +409,7 @@ namespace
CHECK((etl::is_same<result1, expected1>::value));
CHECK((etl::is_same<result2, expected2>::value));
CHECK((etl::is_same<result3, expected3>::value));
CHECK_EQUAL(3U, etl::type_list_size<result1>::value);
CHECK_EQUAL(3U, etl::type_list_size<result2>::value);
CHECK_EQUAL(3U, etl::type_list_size<result3>::value);
@ -490,7 +501,7 @@ namespace
TEST(test_type_list_pop_front_empty_list)
{
// Uncomment to generate static_assert error.
//using list = etl::type_list<>;
//using result1 = etl::type_list_pop_front_t<list>;
}
@ -566,6 +577,129 @@ namespace
CHECK_EQUAL(3U, etl::type_list_size<result1>::value);
}
//*************************************************************************
TEST(test_type_list_all_of_for_empty_list)
{
using list1 = etl::type_list<>;
CHECK_FALSE((etl::type_list_all_of<list1, is_type_a>::value));
CHECK_FALSE((etl::type_list_all_of<list1, is_type_b>::value));
CHECK_FALSE((etl::type_list_all_of<list1, is_type_c>::value));
#if ETL_USING_CPP17
CHECK_FALSE((etl::type_list_all_of_v<list1, is_type_a>));
CHECK_FALSE((etl::type_list_all_of_v<list1, is_type_b>));
CHECK_FALSE((etl::type_list_all_of_v<list1, is_type_c>));
#endif
}
//*************************************************************************
TEST(test_type_list_all_of_for_non_empty_list)
{
using list1 = etl::type_list<A, B, C>;
using list2 = etl::type_list<B, B, B>;
CHECK_FALSE((etl::type_list_all_of<list1, is_type_a>::value));
CHECK_FALSE((etl::type_list_all_of<list1, is_type_b>::value));
CHECK_FALSE((etl::type_list_all_of<list1, is_type_c>::value));
CHECK_FALSE((etl::type_list_all_of<list2, is_type_a>::value));
CHECK_TRUE((etl::type_list_all_of<list2, is_type_b>::value));
CHECK_FALSE((etl::type_list_all_of<list2, is_type_c>::value));
#if ETL_USING_CPP17
CHECK_FALSE((etl::type_list_all_of_v<list1, is_type_a>));
CHECK_FALSE((etl::type_list_all_of_v<list1, is_type_b>));
CHECK_FALSE((etl::type_list_all_of_v<list1, is_type_c>));
CHECK_FALSE((etl::type_list_all_of_v<list2, is_type_a>));
CHECK_TRUE((etl::type_list_all_of_v<list2, is_type_b>));
CHECK_FALSE((etl::type_list_all_of_v<list2, is_type_c>));
#endif
}
//*************************************************************************
TEST(test_type_list_any_of_for_empty_list)
{
using list1 = etl::type_list<>;
CHECK_FALSE((etl::type_list_any_of<list1, is_type_a>::value));
CHECK_FALSE((etl::type_list_any_of<list1, is_type_b>::value));
CHECK_FALSE((etl::type_list_any_of<list1, is_type_c>::value));
#if ETL_USING_CPP17
CHECK_FALSE((etl::type_list_any_of_v<list1, is_type_a>));
CHECK_FALSE((etl::type_list_any_of_v<list1, is_type_b>));
CHECK_FALSE((etl::type_list_any_of_v<list1, is_type_c>));
#endif
}
//*************************************************************************
TEST(test_type_list_any_of_for_non_empty_list)
{
using list1 = etl::type_list<A, B, C>;
using list2 = etl::type_list<B, B, B>;
CHECK_TRUE((etl::type_list_any_of<list1, is_type_a>::value));
CHECK_TRUE((etl::type_list_any_of<list1, is_type_b>::value));
CHECK_TRUE((etl::type_list_any_of<list1, is_type_c>::value));
CHECK_FALSE((etl::type_list_any_of<list2, is_type_a>::value));
CHECK_TRUE((etl::type_list_any_of<list2, is_type_b>::value));
CHECK_FALSE((etl::type_list_any_of<list2, is_type_c>::value));
#if ETL_USING_CPP17
CHECK_TRUE((etl::type_list_any_of_v<list1, is_type_a>));
CHECK_TRUE((etl::type_list_any_of_v<list1, is_type_b>));
CHECK_TRUE((etl::type_list_any_of_v<list1, is_type_c>));
CHECK_FALSE((etl::type_list_any_of_v<list2, is_type_a>));
CHECK_TRUE((etl::type_list_any_of_v<list2, is_type_b>));
CHECK_FALSE((etl::type_list_any_of_v<list2, is_type_c>));
#endif
}
//*************************************************************************
TEST(test_type_list_none_of_for_empty_list)
{
using list1 = etl::type_list<>;
CHECK_TRUE((etl::type_list_none_of<list1, is_type_a>::value));
CHECK_TRUE((etl::type_list_none_of<list1, is_type_b>::value));
CHECK_TRUE((etl::type_list_none_of<list1, is_type_c>::value));
#if ETL_USING_CPP17
CHECK_TRUE((etl::type_list_none_of_v<list1, is_type_a>));
CHECK_TRUE((etl::type_list_none_of_v<list1, is_type_b>));
CHECK_TRUE((etl::type_list_none_of_v<list1, is_type_c>));
#endif
}
//*************************************************************************
TEST(test_type_list_none_of_for_non_empty_list)
{
using list1 = etl::type_list<A, B, C>;
using list2 = etl::type_list<B, B, B>;
CHECK_FALSE((etl::type_list_none_of<list1, is_type_a>::value));
CHECK_FALSE((etl::type_list_none_of<list1, is_type_b>::value));
CHECK_FALSE((etl::type_list_none_of<list1, is_type_c>::value));
CHECK_TRUE((etl::type_list_none_of<list2, is_type_a>::value));
CHECK_FALSE((etl::type_list_none_of<list2, is_type_b>::value));
CHECK_TRUE((etl::type_list_none_of<list2, is_type_c>::value));
#if ETL_USING_CPP17
CHECK_FALSE((etl::type_list_none_of_v<list1, is_type_a>));
CHECK_FALSE((etl::type_list_none_of_v<list1, is_type_b>));
CHECK_FALSE((etl::type_list_none_of_v<list1, is_type_c>));
CHECK_TRUE((etl::type_list_none_of_v<list2, is_type_a>));
CHECK_FALSE((etl::type_list_none_of_v<list2, is_type_b>));
CHECK_TRUE((etl::type_list_none_of_v<list2, is_type_c>));
#endif
}
}
#endif
}