mirror of
https://github.com/ETLCPP/etl.git
synced 2026-06-16 00:46:03 +08:00
Added etl::type_list_remove, etl::type_list_remove_if, etl::type_list_unique, etl::type_list_pop_front, etl::type_list_pop_back
This commit is contained in:
parent
f25e6b9d07
commit
43972b416e
@ -79,6 +79,7 @@ namespace etl
|
||||
|
||||
private:
|
||||
|
||||
// A type_list cannot be instantiated, so delete the constructor and assignment operators.
|
||||
type_list() ETL_DELETE;
|
||||
type_list(const type_list&) ETL_DELETE;
|
||||
type_list& operator =(const type_list&) ETL_DELETE;
|
||||
@ -109,6 +110,7 @@ namespace etl
|
||||
|
||||
private:
|
||||
|
||||
// A type_list cannot be instantiated, so delete the constructor and assignment operators.
|
||||
type_list() ETL_DELETE;
|
||||
type_list(const type_list&) ETL_DELETE;
|
||||
type_list& operator =(const type_list&) ETL_DELETE;
|
||||
@ -418,10 +420,10 @@ namespace etl
|
||||
private:
|
||||
|
||||
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
|
||||
ETL_STATIC_ASSERT(Index <= etl::TTypeList::size, "Index out of range");
|
||||
ETL_STATIC_ASSERT(Index <= TTypeList::size, "Index out of range");
|
||||
|
||||
using index_sequence_for_prefix = etl::make_index_sequence<Index>;
|
||||
using index_sequence_for_suffix = etl::make_index_sequence_with_offset<Index, etl::TTypeList::size - Index>;
|
||||
using index_sequence_for_suffix = etl::make_index_sequence_with_offset<Index, TTypeList::size - Index>;
|
||||
|
||||
using prefix = etl::type_list_select_from_index_sequence_t<TTypeList, index_sequence_for_prefix>;
|
||||
using suffix = etl::type_list_select_from_index_sequence_t<TTypeList, index_sequence_for_suffix>;
|
||||
@ -437,6 +439,173 @@ namespace etl
|
||||
using type_list_insert_t = typename etl::type_list_insert<TTypeList, T, Index>::type;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// Remove a type at an index in a type_list.
|
||||
//***************************************************************************
|
||||
template <typename TTypeList, size_t Index>
|
||||
struct type_list_remove
|
||||
{
|
||||
private:
|
||||
|
||||
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
|
||||
ETL_STATIC_ASSERT(Index < TTypeList::size, "Index out of range");
|
||||
|
||||
using index_sequence_for_prefix = etl::make_index_sequence<Index>;
|
||||
using index_sequence_for_suffix = etl::make_index_sequence_with_offset<Index + 1, TTypeList::size - Index - 1>;
|
||||
|
||||
using prefix = etl::type_list_select_from_index_sequence_t<TTypeList, index_sequence_for_prefix>;
|
||||
using suffix = etl::type_list_select_from_index_sequence_t<TTypeList, index_sequence_for_suffix>;
|
||||
|
||||
public:
|
||||
|
||||
// Concatenate the prefix and suffix to create the new type list with the Index element removed.
|
||||
using type = etl::type_list_cat_t<prefix, suffix>;
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
template <typename TTypeList, size_t Index>
|
||||
using type_list_remove_t = typename etl::type_list_remove<TTypeList, Index>::type;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
// Remove types that satisfy a predicate from a type_list.
|
||||
//***************************************************************************
|
||||
namespace private_type_list
|
||||
{
|
||||
template <typename TTypeList, template <typename> class TPredicate>
|
||||
struct type_list_remove_if_impl;
|
||||
|
||||
template <template <typename> class TPredicate>
|
||||
struct type_list_remove_if_impl<etl::type_list<>, TPredicate>
|
||||
{
|
||||
using type = etl::type_list<>;
|
||||
};
|
||||
|
||||
template <typename Head, typename... Tail, template <typename> class TPredicate>
|
||||
struct type_list_remove_if_impl<etl::type_list<Head, Tail...>, TPredicate>
|
||||
{
|
||||
private:
|
||||
|
||||
using rest = typename type_list_remove_if_impl<etl::type_list<Tail...>, TPredicate>::type;
|
||||
|
||||
public:
|
||||
|
||||
using type = typename etl::conditional<TPredicate<Head>::value,
|
||||
rest,
|
||||
etl::type_list_prepend_t<rest, Head>>::type;
|
||||
};
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Remove types that satisfy a predicate from a type_list.
|
||||
/// Predicate must be: template <typename T> struct Pred : etl::bool_constant<...> {};
|
||||
//***************************************************************************
|
||||
template <typename TTypeList, template <typename> class TPredicate>
|
||||
struct type_list_remove_if
|
||||
{
|
||||
private:
|
||||
|
||||
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
|
||||
|
||||
public:
|
||||
|
||||
using type = typename private_type_list::type_list_remove_if_impl<TTypeList, TPredicate>::type;
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
template <typename TTypeList, template <typename> class TPredicate>
|
||||
using type_list_remove_if_t = typename etl::type_list_remove_if<TTypeList, TPredicate>::type;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// Removes the first type from a type_list.
|
||||
//***************************************************************************
|
||||
template <typename TTypeList>
|
||||
struct type_list_pop_front
|
||||
{
|
||||
private:
|
||||
|
||||
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
|
||||
ETL_STATIC_ASSERT(TTypeList::size > 0U, "Cannot pop_front from an empty type_list");
|
||||
|
||||
public:
|
||||
|
||||
using type = typename TTypeList::tail;
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
template <typename TTypeList>
|
||||
using type_list_pop_front_t = typename etl::type_list_pop_front<TTypeList>::type;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// Removes the last type from a type_list.
|
||||
//***************************************************************************
|
||||
template <typename TTypeList>
|
||||
struct type_list_pop_back
|
||||
{
|
||||
private:
|
||||
|
||||
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
|
||||
ETL_STATIC_ASSERT(TTypeList::size > 0U, "Cannot pop_back from an empty type_list");
|
||||
|
||||
public:
|
||||
|
||||
using type = typename etl::type_list_remove<TTypeList, TTypeList::size - 1U>::type;
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
template <typename TTypeList>
|
||||
using type_list_pop_back_t = typename etl::type_list_pop_back<TTypeList>::type;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
// Remove duplicate types from a type_list, preserving the first occurrence.
|
||||
//***************************************************************************
|
||||
namespace private_type_list
|
||||
{
|
||||
template <typename TTypeList, typename TResult>
|
||||
struct type_list_unique_impl;
|
||||
|
||||
// Base case: empty list, return the result.
|
||||
template <typename TResult>
|
||||
struct type_list_unique_impl<etl::type_list<>, TResult>
|
||||
{
|
||||
using type = TResult;
|
||||
};
|
||||
|
||||
// Recursive case: Check if the head is already in the result, if not add it, then recurse on the tail.
|
||||
template <typename Head, typename... Tail, typename TResult>
|
||||
struct type_list_unique_impl<etl::type_list<Head, Tail...>, TResult>
|
||||
{
|
||||
private:
|
||||
|
||||
using next_result = etl::conditional_t<etl::type_list_contains<TResult, Head>::value,
|
||||
TResult,
|
||||
etl::type_list_append_t<TResult, Head>>;
|
||||
|
||||
public:
|
||||
|
||||
using type = typename type_list_unique_impl<etl::type_list<Tail...>, next_result>::type;
|
||||
};
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Defines a new type_list by removing duplicate types from a given type_list, preserving the first occurrence.
|
||||
//***************************************************************************
|
||||
template <typename TTypeList>
|
||||
struct type_list_unique
|
||||
{
|
||||
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
|
||||
|
||||
using type = typename private_type_list::type_list_unique_impl<TTypeList, etl::type_list<>>::type;
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
template <typename TTypeList>
|
||||
using type_list_unique_t = typename etl::type_list_unique<TTypeList>::type;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// Checks that two type lists are convertible.
|
||||
/// Static asserts if the type lists are not the same length.
|
||||
|
||||
@ -40,6 +40,11 @@ namespace
|
||||
struct B { static constexpr int id = 1; };
|
||||
struct C { static constexpr int id = 2; };
|
||||
|
||||
template <typename T>
|
||||
struct is_type_b : etl::bool_constant<std::is_same<T, B>::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)>
|
||||
@ -376,7 +381,7 @@ namespace
|
||||
using expected = etl::type_list<A>;
|
||||
|
||||
CHECK((etl::is_same<result, expected>::value));
|
||||
//CHECK_EQUAL(1U, etl::type_list_size<result>::value);
|
||||
CHECK_EQUAL(1U, etl::type_list_size<result>::value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -394,9 +399,172 @@ namespace
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_list_remove_from_empty_list)
|
||||
{
|
||||
// Uncomment to generate static_assert error.
|
||||
|
||||
//using list = etl::type_list<>;
|
||||
//using result1 = etl::type_list_remove_t<list, 0>;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_list_remove_from_single_list)
|
||||
{
|
||||
using list = etl::type_list<A>;
|
||||
using result1 = etl::type_list_remove_t<list, 0>;
|
||||
using expected1 = etl::type_list<>;
|
||||
|
||||
CHECK((etl::is_same<result1, expected1>::value));
|
||||
|
||||
CHECK_EQUAL(0U, etl::type_list_size<result1>::value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_list_remove_from_multiple_list)
|
||||
{
|
||||
using list = etl::type_list<A, B, C>;
|
||||
using result1 = etl::type_list_remove_t<list, 0>;
|
||||
using result2 = etl::type_list_remove_t<list, 1>;
|
||||
using result3 = etl::type_list_remove_t<list, 2>;
|
||||
using expected1 = etl::type_list<B, C>;
|
||||
using expected2 = etl::type_list<A, C>;
|
||||
using expected3 = etl::type_list<A, B>;
|
||||
|
||||
CHECK((etl::is_same<result1, expected1>::value));
|
||||
CHECK((etl::is_same<result2, expected2>::value));
|
||||
CHECK((etl::is_same<result3, expected3>::value));
|
||||
|
||||
CHECK_EQUAL(2U, etl::type_list_size<result1>::value);
|
||||
CHECK_EQUAL(2U, etl::type_list_size<result2>::value);
|
||||
CHECK_EQUAL(2U, etl::type_list_size<result3>::value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_list_remove_if_from_empty_list)
|
||||
{
|
||||
using list = etl::type_list<>;
|
||||
using result1 = etl::type_list_remove_if_t<list, is_type_b>;
|
||||
using expected1 = etl::type_list<>;
|
||||
|
||||
CHECK((etl::is_same<result1, expected1>::value));
|
||||
|
||||
CHECK_EQUAL(0U, etl::type_list_size<result1>::value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_list_remove_if_from_single_list)
|
||||
{
|
||||
using list1 = etl::type_list<A>;
|
||||
using list2 = etl::type_list<B>;
|
||||
using result1 = etl::type_list_remove_if_t<list1, is_type_b>;
|
||||
using result2 = etl::type_list_remove_if_t<list2, is_type_b>;
|
||||
using expected1 = etl::type_list<A>;
|
||||
using expected2 = etl::type_list<>;
|
||||
|
||||
CHECK((etl::is_same<result1, expected1>::value));
|
||||
CHECK((etl::is_same<result2, expected2>::value));
|
||||
|
||||
CHECK_EQUAL(1U, etl::type_list_size<result1>::value);
|
||||
CHECK_EQUAL(0U, etl::type_list_size<result2>::value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_list_remove_if_from_multiple_list)
|
||||
{
|
||||
using list = etl::type_list<A, B, C>;
|
||||
using result1 = etl::type_list_remove_if_t<list, is_type_b>;
|
||||
using expected1 = etl::type_list<A, C>;
|
||||
|
||||
CHECK((etl::is_same<result1, expected1>::value));
|
||||
|
||||
CHECK_EQUAL(2U, etl::type_list_size<result1>::value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
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>;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_list_pop_front_from_non_empty_list)
|
||||
{
|
||||
using list = etl::type_list<A, B, C>;
|
||||
using result1 = etl::type_list_pop_front_t<list>;
|
||||
using result2 = etl::type_list_pop_front_t<result1>;
|
||||
using result3 = etl::type_list_pop_front_t<result2>;
|
||||
using expected1 = etl::type_list<B, C>;
|
||||
using expected2 = etl::type_list<C>;
|
||||
using expected3 = etl::type_list<>;
|
||||
|
||||
CHECK((etl::is_same<result1, expected1>::value));
|
||||
CHECK((etl::is_same<result2, expected2>::value));
|
||||
CHECK((etl::is_same<result3, expected3>::value));
|
||||
|
||||
CHECK_EQUAL(2U, etl::type_list_size<result1>::value);
|
||||
CHECK_EQUAL(1U, etl::type_list_size<result2>::value);
|
||||
CHECK_EQUAL(0U, etl::type_list_size<result3>::value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_list_pop_back_empty_list)
|
||||
{
|
||||
// Uncomment to generate static_assert error.
|
||||
|
||||
//using list = etl::type_list<>;
|
||||
//using result1 = etl::type_list_pop_front_t<list>;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_list_pop_back_from_non_empty_list)
|
||||
{
|
||||
using list = etl::type_list<A, B, C>;
|
||||
using result1 = etl::type_list_pop_back_t<list>;
|
||||
using result2 = etl::type_list_pop_back_t<result1>;
|
||||
using result3 = etl::type_list_pop_back_t<result2>;
|
||||
using expected1 = etl::type_list<A, B>;
|
||||
using expected2 = etl::type_list<A>;
|
||||
using expected3 = etl::type_list<>;
|
||||
|
||||
CHECK((etl::is_same<result1, expected1>::value));
|
||||
CHECK((etl::is_same<result2, expected2>::value));
|
||||
CHECK((etl::is_same<result3, expected3>::value));
|
||||
|
||||
CHECK_EQUAL(2U, etl::type_list_size<result1>::value);
|
||||
CHECK_EQUAL(1U, etl::type_list_size<result2>::value);
|
||||
CHECK_EQUAL(0U, etl::type_list_size<result3>::value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_list_unique_for_empty_list)
|
||||
{
|
||||
using list = etl::type_list<>;
|
||||
using result = etl::type_list_unique_t<list>;
|
||||
using expected = etl::type_list<>;
|
||||
|
||||
CHECK((etl::is_same<result, expected>::value));
|
||||
CHECK_EQUAL(0U, etl::type_list_size<result>::value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_list_unique_for_non_empty_list)
|
||||
{
|
||||
using list = etl::type_list<A, B, A, C, C, B, C>;
|
||||
using result1 = etl::type_list_unique_t<list>;
|
||||
using expected1 = etl::type_list<A, B, C>;
|
||||
|
||||
CHECK((etl::is_same<result1, expected1>::value));
|
||||
|
||||
CHECK_EQUAL(3U, etl::type_list_size<result1>::value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user