Loading...
Searching...
No Matches
type_list.h
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2025 John Wellbelove
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef ETL_TYPE_LIST_INCLUDED
#define ETL_TYPE_LIST_INCLUDED
#include "platform.h"
#include "index_of_type.h"
#include "integral_limits.h"
#include "largest.h"
#include "static_assert.h"
#include "type_traits.h"
#include "utility.h"
#if ETL_USING_CPP11
namespace etl
{
//***************************************************************************
//***************************************************************************
static ETL_CONSTANT size_t type_list_npos = etl::integral_limits<size_t>::max;
//***************************************************************************
// Type list forward declaration.
//***************************************************************************
template <typename... TTypes>
struct type_list;
//***************************************************************************
//***************************************************************************
template <typename T>
struct is_type_list : etl::false_type
{
};
template <typename... TTypes>
struct is_type_list<etl::type_list<TTypes...>> : etl::true_type
{
};
#if ETL_USING_CPP17
template <typename T>
inline constexpr bool is_type_list_v = is_type_list<T>::value;
#endif
//***************************************************************************
//***************************************************************************
template <>
struct type_list<>
{
static constexpr size_t size = 0U;
using index_sequence_type = etl::make_index_sequence<0>;
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;
};
namespace private_type_list
{
// helper to solve the issue that recursed-rest can't be put directly in
// type_list::tail definition
template <typename... TTypes>
struct recursion_helper
{
using type = type_list<TTypes...>;
};
} // namespace private_type_list
//***************************************************************************
//***************************************************************************
template <typename THead, typename... TTail>
struct type_list<THead, TTail...> : type_list<TTail...>
{
using head = THead;
using tail = typename private_type_list::recursion_helper<TTail...>::type;
static constexpr size_t size = sizeof...(TTail) + 1U;
using index_sequence_type = etl::make_index_sequence< sizeof...(TTail) + 1U>;
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;
};
//***************************************************************************
//***************************************************************************
template <typename THead>
struct type_list<THead> : type_list<>
{
using head = THead;
using tail = typename private_type_list::recursion_helper<>::type;
static constexpr size_t size = 1U;
using index_sequence_type = etl::make_index_sequence<1>;
private:
type_list() ETL_DELETE;
type_list(const type_list&) ETL_DELETE;
type_list& operator=(const type_list&) ETL_DELETE;
};
//***************************************************************************
//***************************************************************************
template <typename TTypes>
struct type_list_size;
template <typename... TTypes>
struct type_list_size<etl::type_list<TTypes...>> : public etl::integral_constant<size_t, sizeof...(TTypes)>
{
};
#if ETL_USING_CPP17
template <typename... TTypes>
inline constexpr size_t type_list_size_v = type_list_size<etl::type_list<TTypes...>>::value;
#endif
//***************************************************************************
//***************************************************************************
template <typename TTypeList, size_t Index>
struct type_list_type_at_index
{
ETL_STATIC_ASSERT(Index < TTypeList::size, "etl::type_list_type_at_index out of range");
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
using type = typename type_list_type_at_index<typename TTypeList::tail, Index - 1>::type;
};
template <typename TTypeList>
struct type_list_type_at_index<TTypeList, 0>
{
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
using type = typename TTypeList::head;
};
template <typename TTypeList, size_t Index>
using type_list_type_at_index_t = typename type_list_type_at_index<TTypeList, Index>::type;
//***************************************************************************
//***************************************************************************
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 + 1)>
{
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
};
template <typename T>
struct type_list_index_of_type<type_list<>, T> : public etl::integral_constant<size_t, etl::type_list_npos>
{
};
#if ETL_USING_CPP17
template <typename TTypeList, typename T>
inline constexpr size_t type_list_index_of_type_v = etl::type_list_index_of_type<TTypeList, T>::value;
#endif
//***************************************************************************
//***************************************************************************
namespace private_type_list
{
template <typename TTypeList, typename T, size_t Index, typename TResult>
struct type_list_indices_of_type_impl;
// The general case, check the head type, then recurse with the rest of the
// types.
template <typename Head, typename... Tail, typename T, size_t Index, typename TResult>
struct type_list_indices_of_type_impl<etl::type_list<Head, Tail...>, T, Index, TResult>
{
private:
// If Head is the same as T then append a new index to the result,
// otherwise no change.
using next_result = etl::conditional_t<etl::is_same<Head, T>::value, etl::index_sequence_push_back_t<TResult, Index>, TResult>;
public:
// Recurse with the rest of the type_list, passing on the current result.
using type = typename type_list_indices_of_type_impl<etl::type_list<Tail...>, T, Index + 1U, next_result>::type;
};
// Specialisation for an empty type_list.
// This is the terminating specialisation for the general case.
template <typename T, size_t Index, typename TResult>
struct type_list_indices_of_type_impl<etl::type_list<>, T, Index, TResult>
{
using type = TResult;
};
} // namespace private_type_list
template <typename TTypeList, typename T>
struct type_list_indices_of_type
{
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
using type = typename private_type_list::type_list_indices_of_type_impl< TTypeList, T, 0U, etl::index_sequence<>>::type;
};
#if ETL_USING_CPP11
template <typename TTypeList, typename T>
using type_list_indices_of_type_t = typename type_list_indices_of_type<TTypeList, T>::type;
#endif
//***************************************************************************
//***************************************************************************
template <typename TTypeList, typename T>
struct type_list_contains;
template <typename T, typename... TTypes>
struct type_list_contains<etl::type_list<TTypes...>, T> : public etl::is_one_of<T, TTypes...>
{
};
template <typename T>
struct type_list_contains<type_list<>, T> : public etl::bool_constant<false>
{
};
#if ETL_USING_CPP17
template <typename TTypeList, typename T>
inline constexpr bool type_list_contains_v = etl::type_list_contains<TTypeList, T>::value;
#endif
//***************************************************************************
//***************************************************************************
template <typename TTypeList, typename T>
struct type_list_has_duplicates_of;
template <typename T, typename... TTypes>
struct type_list_has_duplicates_of<etl::type_list<TTypes...>, T> : public etl::has_duplicates_of<T, TTypes...>
{
};
template <typename T>
struct type_list_has_duplicates_of<type_list<>, T> : public etl::integral_constant<bool, false>
{
};
#if ETL_USING_CPP17
template <typename TTypeList, typename T>
inline constexpr bool type_list_has_duplicates_of_v = etl::type_list_has_duplicates_of<TTypeList, T>::value;
#endif
//***************************************************************************
//***************************************************************************
template <typename TTypeList, typename T>
struct type_list_count_of;
template <typename T, typename... TTypes>
struct type_list_count_of<etl::type_list<TTypes...>, T> : public etl::count_of<T, TTypes...>
{
};
template <typename T>
struct type_list_count_of<type_list<>, T> : public etl::integral_constant<size_t, 0>
{
};
#if ETL_USING_CPP17
template <typename TTypeList, typename T>
inline constexpr size_t type_list_count_of_v = etl::type_list_count_of<TTypeList, T>::value;
#endif
//***************************************************************************
//***************************************************************************
template <typename T>
struct type_list_max_size;
template <typename... TTypes>
struct type_list_max_size<etl::type_list<TTypes...>> : public etl::integral_constant<size_t, etl::largest<TTypes...>::size>
{
};
template <>
struct type_list_max_size<type_list<>> : public etl::integral_constant<size_t, 0>
{
};
#if ETL_USING_CPP17
template <typename TTypeList>
inline constexpr size_t type_list_max_size_v = etl::type_list_max_size<TTypeList>::value;
#endif
//***************************************************************************
//***************************************************************************
template <typename T>
struct type_list_max_alignment;
template <typename... TTypes>
struct type_list_max_alignment<etl::type_list<TTypes...>> : public etl::integral_constant<size_t, etl::largest<TTypes...>::alignment>
{
};
template <>
struct type_list_max_alignment<type_list<>> : public etl::integral_constant<size_t, 1>
{
};
#if ETL_USING_CPP17
template <typename TTypeList>
inline constexpr size_t type_list_max_alignment_v = etl::type_list_max_alignment<TTypeList>::value;
#endif
//***************************************************************************
//***************************************************************************
template <typename TTypeList, size_t... Indices>
struct type_list_select
{
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
using type = type_list<type_list_type_at_index_t<TTypeList, Indices>...>;
};
template <typename TTypeList, size_t... Indices>
using type_list_select_t = typename type_list_select<TTypeList, Indices...>::type;
template <typename TTypeList, size_t... Indices>
using type_list_select_from_indexes = type_list_select<TTypeList, Indices...>;
template <typename TTypeList, size_t... Indices>
using type_list_select_from_indexes_t = typename type_list_select<TTypeList, Indices...>::type;
//***************************************************************************
//***************************************************************************
template <typename TTypeList, typename TIndexSequence>
struct type_list_select_from_index_sequence;
template <typename TTypeList, size_t... Indices>
struct type_list_select_from_index_sequence<TTypeList, etl::index_sequence<Indices...>>
{
using type = etl::type_list_select_t<TTypeList, Indices...>;
};
template <typename TTypeList, typename TIndexSequence>
using type_list_select_from_index_sequence_t = typename type_list_select_from_index_sequence<TTypeList, TIndexSequence>::type;
//***************************************************************************
//***************************************************************************
template <typename... TTypes>
struct type_list_cat;
// The general case, concatenate the first two type_lists, then recurse with
// the result and the rest of the type_lists.
template <typename... TTypes1, typename... TTypes2, typename... TTail>
struct type_list_cat<etl::type_list<TTypes1...>, etl::type_list<TTypes2...>, TTail...>
{
using type = typename type_list_cat<etl::type_list<TTypes1..., TTypes2...>, TTail...>::type;
};
template <typename T>
struct type_list_cat<T>
{
using type = T;
};
template <>
struct type_list_cat<>
{
using type = etl::type_list<>;
};
template <typename... TypeLists>
using type_list_cat_t = typename type_list_cat<TypeLists...>::type;
//***************************************************************************
//***************************************************************************
template <typename T, typename... TTypes>
struct type_list_push_front;
template <typename T, typename... TTypes>
struct type_list_push_front<etl::type_list<TTypes...>, T>
{
using type = type_list<T, TTypes...>;
};
template <typename TypeList, typename T>
using type_list_push_front_t = typename type_list_push_front<TypeList, T>::type;
//***************************************************************************
//***************************************************************************
template <typename T, typename... TTypes>
struct type_list_push_back;
template <typename T, typename... TTypes>
struct type_list_push_back<etl::type_list<TTypes...>, T>
{
using type = type_list<TTypes..., T>;
};
template <typename TypeList, typename T>
using type_list_push_back_t = typename type_list_push_back<TypeList, T>::type;
//***************************************************************************
//***************************************************************************
template <typename TTypeList, typename T, size_t Index>
struct type_list_insert
{
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, 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>;
public:
// Concatenate the prefix, new type, and suffix to create the new type list
// with T inserted at the correct position.
using type = etl::type_list_cat_t<prefix, etl::type_list<T>, suffix>;
};
#if ETL_USING_CPP11
template <typename TTypeList, typename T, size_t Index>
using type_list_insert_t = typename etl::type_list_insert<TTypeList, T, Index>::type;
#endif
//***************************************************************************
//***************************************************************************
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_push_front_t<rest, Head>>::type;
};
} // namespace private_type_list
//***************************************************************************
//***************************************************************************
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
//***************************************************************************
//***************************************************************************
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
//***************************************************************************
//***************************************************************************
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_push_back_t<TResult, Head>>;
public:
using type = typename type_list_unique_impl<etl::type_list<Tail...>, next_result>::type;
};
} // namespace private_type_list
//***************************************************************************
//***************************************************************************
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
//***************************************************************************
//***************************************************************************
template <typename TTypeList>
struct type_list_is_unique
// Create a unique version of the type list, and check if it is the same as
// the original list. If they are the same, then all types in the original
// list are unique.
: etl::bool_constant< etl::is_same< TTypeList, typename type_list_unique<TTypeList>::type>::value>
{
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
};
#if ETL_USING_CPP17
template <typename TTypeList>
inline constexpr bool type_list_is_unique_v = etl::type_list_is_unique<TTypeList>::value;
#endif
//***************************************************************************
//***************************************************************************
template <typename T>
struct type_list_is_empty;
template <>
struct type_list_is_empty<etl::type_list<>> : etl::true_type
{
};
template <typename... TTypes>
struct type_list_is_empty<etl::type_list<TTypes...>> : etl::false_type
{
};
#if ETL_USING_CPP17
template <typename... TTypes>
inline constexpr bool type_list_is_empty_v = type_list_is_empty<TTypes...>::value;
#endif
//***************************************************************************
//***************************************************************************
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>...>
{
};
#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
//***************************************************************************
//***************************************************************************
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>...>
{
};
#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
//***************************************************************************
//***************************************************************************
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>...>>
{
};
#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
//***************************************************************************
//***************************************************************************
// Primary template
template <typename TFromList, typename TToList>
struct type_lists_are_convertible;
// Specialization: both lists empty, convertible
template <>
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
&& 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");
};
#if ETL_USING_CPP17
template <typename TFromList, typename TToList>
inline constexpr bool type_lists_are_convertible_v = etl::type_lists_are_convertible<TFromList, TToList>::value;
#endif
namespace private_type_list
{
//*********************************
template <typename TTypeList, template <typename, typename> class TCompare>
struct type_list_is_sorted_impl;
//*********************************
// Empty list is sorted
template <template <typename, typename> class TCompare>
struct type_list_is_sorted_impl<etl::type_list<>, TCompare> : etl::true_type
{
};
//*********************************
// Single element list is sorted
template <typename T0, template <typename, typename> class TCompare>
struct type_list_is_sorted_impl<etl::type_list<T0>, TCompare> : etl::true_type
{
};
//*********************************
// Ensure that the list is sorted.
// Recursively compare the head to the next element to ensure that the list
// is sorted.
template <typename Head, typename Next, typename... Tail, template <typename, typename> class TCompare>
struct type_list_is_sorted_impl<etl::type_list<Head, Next, Tail...>, TCompare>
: etl::bool_constant< !TCompare<Next, Head>::value && type_list_is_sorted_impl< etl::type_list<Next, Tail...>, TCompare>::value>
{
};
} // namespace private_type_list
//*****************************************************************************
//*****************************************************************************
template <typename TTypeList, template <typename, typename> class TCompare>
struct type_list_is_sorted : public private_type_list::type_list_is_sorted_impl<TTypeList, TCompare>
{
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
};
#if ETL_USING_CPP17
template <typename TTypeList, template <typename, typename> class TCompare>
inline constexpr bool type_list_is_sorted_v = etl::type_list_is_sorted<TTypeList, TCompare>::value;
#endif
//*****************************************************************************
namespace private_type_list
{
//*********************************
template <bool InsertBefore, typename Head, typename T, template <typename, typename> class TCompare, typename... Tail>
struct insert_sorted_impl;
//*********************************
template <typename TSortedList, typename T, template <typename, typename> class TCompare>
struct type_list_insert_sorted_impl;
//*********************************
// Insert T into sorted list using TCompare
// Empty list -> T becomes the list
template <typename T, template <typename, typename> class TCompare>
struct type_list_insert_sorted_impl<etl::type_list<>, T, TCompare>
{
using type = etl::type_list<T>;
};
//*********************************
// Insert T into the correct position in the sorted list, as determined by
// TCompare
template <typename Head, typename... Tail, typename T, template <typename, typename> class TCompare>
struct type_list_insert_sorted_impl<etl::type_list<Head, Tail...>, T, TCompare>
{
using type = typename insert_sorted_impl<TCompare<T, Head>::value, Head, T, TCompare, Tail...>::type;
};
//*********************************
// If InsertBefore is true, then T should be inserted before Head
template <typename Head, typename T, template <typename, typename> class TCompare, typename... Tail>
struct insert_sorted_impl<true, Head, T, TCompare, Tail...>
{
using type = etl::type_list<T, Head, Tail...>;
};
//*********************************
// If InsertBefore is false, then T should be inserted after Head, so we
// recursively call insert_sorted_impl on the tail of the list
template <typename Head, typename T, template <typename, typename> class TCompare, typename... Tail>
struct insert_sorted_impl<false, Head, T, TCompare, Tail...>
{
using type = etl::type_list_push_front_t< typename type_list_insert_sorted_impl<etl::type_list<Tail...>, T, TCompare>::type, Head>;
};
} // namespace private_type_list
//*****************************************************************************
//*****************************************************************************
template <typename TTypeList, typename T, template <typename, typename> class TCompare>
struct type_list_insert_sorted : public private_type_list::type_list_insert_sorted_impl<TTypeList, T, TCompare>
{
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
ETL_STATIC_ASSERT((etl::type_list_is_sorted<TTypeList, TCompare>::value), "Cannot insert into a non-sorted type list");
};
#if ETL_USING_CPP11
template <typename TTypeList, typename T, template <typename, typename> class TCompare>
using type_list_insert_sorted_t = typename etl::type_list_insert_sorted<TTypeList, T, TCompare>::type;
#endif
//***************************************************************************
namespace private_type_list
{
//*********************************
// Forward declaration
template <typename TTypeList, template <typename, typename> class TCompare>
struct type_list_sort_impl;
//*********************************
// Empty list
template <template <typename, typename> class TCompare>
struct type_list_sort_impl<etl::type_list<>, TCompare>
{
using type = etl::type_list<>;
};
//*********************************
// Single element list
template <typename T0, template <typename, typename> class TCompare>
struct type_list_sort_impl<etl::type_list<T0>, TCompare>
{
using type = etl::type_list<T0>;
};
//*********************************
// Define a new type_list by sorting the types according to TCompare
template <typename Head, typename... Tail, template <typename, typename> class TCompare>
struct type_list_sort_impl<etl::type_list<Head, Tail...>, TCompare>
{
private:
using sorted_tail = typename type_list_sort_impl<etl::type_list<Tail...>, TCompare>::type;
public:
using type = typename etl::type_list_insert_sorted<sorted_tail, Head, TCompare>::type;
};
} // namespace private_type_list
//*****************************************************************************
//*****************************************************************************
template <typename TTypeList, template <typename, typename> class TCompare>
struct type_list_sort : public private_type_list::type_list_sort_impl<TTypeList, TCompare>
{
ETL_STATIC_ASSERT((etl::is_type_list<TTypeList>::value), "TTypeList must be an etl::type_list");
};
#if ETL_USING_CPP11
template <typename TTypeList, template <typename, typename> class TCompare>
using type_list_sort_t = typename etl::type_list_sort<TTypeList, TCompare>::type;
#endif
//*****************************************************************************
//*****************************************************************************
template <typename T, typename... TypeLists>
struct type_list_in_all_lists : etl::conjunction<etl::type_list_contains<TypeLists, T>...>
{
};
// Specialisation if no lists provided.
template <typename T>
struct type_list_in_all_lists<T> : etl::false_type
{
};
#if ETL_USING_CPP17
template <typename T, typename... TypeLists>
inline constexpr bool type_list_in_all_lists_v = type_list_in_all_lists<T, TypeLists...>::value;
#endif
//*****************************************************************************
//*****************************************************************************
template <typename T, typename... TypeLists>
struct type_list_in_any_list : etl::false_type
{
};
// Recursive case: Check the first list using your helper.
template <typename T, typename FirstList, typename... RestLists>
struct type_list_in_any_list<T, FirstList, RestLists...>
: etl::conditional<type_list_contains<FirstList, T>::value, etl::true_type, type_list_in_any_list<T, RestLists...>>::type
{
};
#if ETL_USING_CPP17
template <typename T, typename... TypeLists>
inline constexpr bool type_list_in_any_list_v = type_list_in_any_list<T, TypeLists...>::value;
#endif
//*****************************************************************************
//*****************************************************************************
template <typename T, typename... Lists>
using type_list_in_no_lists = etl::bool_constant<!type_list_in_any_list<T, Lists...>::value>;
#if ETL_USING_CPP17
template <typename T, typename... Lists>
inline constexpr bool type_list_in_no_lists_v = type_list_in_no_lists<T, Lists...>::value;
#endif
//*****************************************************************************
namespace private_type_list
{
template <typename TInputList, typename TAccumulatedResult, typename... TOtherLists>
struct type_list_remove_from_accumulator;
// Base case: No more types to process, return the accumulated result.
template <typename TAccumulatedResult, typename... TOtherLists>
struct type_list_remove_from_accumulator<etl::type_list<>, TAccumulatedResult, TOtherLists...>
{
using type = TAccumulatedResult;
};
// Recursive case: Process Head, accumulate result forward.
template <typename Head, typename... Tail, typename TAccumulatedResult, typename... TOtherLists>
struct type_list_remove_from_accumulator<etl::type_list<Head, Tail...>, TAccumulatedResult, TOtherLists...>
{
private:
// Check if Head does not exist in any of the other lists.
static constexpr bool head_is_not_in_other_lists = etl::type_list_in_no_lists<Head, TOtherLists...>::value;
// Append Head to the result if it's NOT in any of the other lists.
using accumulated = etl::conditional_t<head_is_not_in_other_lists, etl::type_list_push_back_t<TAccumulatedResult, Head>, TAccumulatedResult>;
public:
// Recurse with the updated accumulator and remaining types.
using type = typename type_list_remove_from_accumulator<etl::type_list<Tail...>, accumulated, TOtherLists...>::type;
};
//*****************************************************************************
// Extract the first list and call the main implementation.
//*****************************************************************************
template <typename... TypeLists>
struct type_list_remove_from_helper;
// An difference of no type_lists is an empty type_list.
template <>
struct type_list_remove_from_helper<>
{
using type = etl::type_list<>;
};
// One list, so just return it.
template <typename TypeList>
struct type_list_remove_from_helper<TypeList>
{
using type = TypeList;
};
// Two or more lists.
template <typename TFirstList, typename... TRestLists>
struct type_list_remove_from_helper<TFirstList, TRestLists...>
{
using type = typename type_list_remove_from_accumulator<TFirstList, etl::type_list<>, TRestLists...>::type;
};
} // namespace private_type_list
//***************************************************************************
//***************************************************************************
template <typename... TypeLists>
struct type_list_remove_from
{
// Ensure all parameters are actually type_lists.
static_assert(etl::conjunction<etl::is_type_list<TypeLists>...>::value, "All parameters must be etl::type_list types");
using type = typename private_type_list::type_list_remove_from_helper<TypeLists...>::type;
};
template <typename... TypeLists>
using type_list_remove_from_t = typename type_list_remove_from<TypeLists...>::type;
//***************************************************************************
//***************************************************************************
template <typename... TypeLists>
struct type_list_cat_unique
{
// Ensure all parameters are actually type_lists (optional, but helpful).
static_assert(etl::conjunction<etl::is_type_list<TypeLists>...>::value, "All parameters must be etl::type_list types");
using type = etl::type_list_unique_t<type_list_cat_t<TypeLists...>>;
};
template <typename... TypeLists>
using type_list_cat_unique_t = typename type_list_cat_unique<TypeLists...>::type;
//****************************************************************************
namespace private_type_list
{
template <typename TInputList, typename TAccumulatedResult, typename... TOtherLists>
struct type_list_select_common_types_accumulator;
// Base case: No more types to process, return the accumulated result.
template <typename TAccumulatedResult, typename... TOtherLists>
struct type_list_select_common_types_accumulator<etl::type_list<>, TAccumulatedResult, TOtherLists...>
{
using type = TAccumulatedResult;
};
// Recursive case: Process Head, accumulate result forward.
template <typename Head, typename... Tail, typename TAccumulatedResult, typename... TOtherLists>
struct type_list_select_common_types_accumulator<etl::type_list<Head, Tail...>, TAccumulatedResult, TOtherLists...>
{
private:
// Check if Head exists in all other lists.
static constexpr bool head_is_in_all_lists = etl::type_list_in_all_lists<Head, TOtherLists...>::value;
// Append Head to the result if it's in all lists AND not already added.
using accumulated = etl::conditional_t<head_is_in_all_lists, etl::type_list_push_back_t<TAccumulatedResult, Head>, TAccumulatedResult>;
public:
// Recurse with the updated accumulator and remaining types.
using type = typename type_list_select_common_types_accumulator<etl::type_list<Tail...>, accumulated, TOtherLists...>::type;
};
//*****************************************************************************
// Extract the first list and call the main implementation.
//*****************************************************************************
template <typename... TypeLists>
struct type_list_select_common_types_helper;
// An intersection of no type lists is an empty type_list.
template <>
struct type_list_select_common_types_helper<>
{
using type = etl::type_list<>;
};
// One list, so just return it.
template <typename TypeList>
struct type_list_select_common_types_helper<TypeList>
{
using type = etl::type_list_unique_t<TypeList>;
};
// Two or more lists, use the intersection algorithm.
template <typename TFirstList, typename... TRestLists>
struct type_list_select_common_types_helper<TFirstList, TRestLists...>
{
private:
// Remove duplicates from the first list.
using first_unique = etl::type_list_unique_t<TFirstList>;
public:
using type = typename type_list_select_common_types_accumulator<first_unique, etl::type_list<>, TRestLists...>::type;
};
} // namespace private_type_list
//*****************************************************************************
//*****************************************************************************
template <typename... TypeLists>
struct type_list_select_common_types
{
// Ensure all parameters are actually type_lists (optional, but helpful).
static_assert(etl::conjunction<etl::is_type_list<TypeLists>...>::value, "All parameters must be etl::type_list types");
using type = typename private_type_list::type_list_select_common_types_helper<TypeLists...>::type;
};
template <typename... TypeLists>
using type_list_select_common_types_t = typename type_list_select_common_types<TypeLists...>::type;
//*****************************************************************************
//*****************************************************************************
template <typename... TypeLists>
struct type_list_select_not_common_types
{
// Ensure all parameters are actually type_lists (optional, but helpful).
static_assert(etl::conjunction<etl::is_type_list<TypeLists>...>::value, "All parameters must be etl::type_list types");
using type = etl::type_list_remove_from_t<etl::type_list_cat_unique_t<TypeLists...>, etl::type_list_select_common_types_t<TypeLists...>>;
};
template <typename... TypeLists>
using type_list_select_not_common_types_t = typename type_list_select_not_common_types<TypeLists...>::type;
} // namespace etl
#endif
#endif
integral_limits.h
largest.h
etl
Definition absolute.h:40
etl::false_type
integral_constant< bool, false > false_type
integral_constant specialisations
Definition type_traits.h:80
etl::size
ETL_CONSTEXPR TContainer::size_type size(const TContainer &container)
Definition iterator.h:1434
platform.h
type_traits.h
utility.h