diff --git a/include/etl/type_list.h b/include/etl/type_list.h index 19eddc15..1afd55f0 100644 --- a/include/etl/type_list.h +++ b/include/etl/type_list.h @@ -48,11 +48,14 @@ namespace etl static ETL_CONSTANT size_t type_list_npos = etl::integral_limits::max; //*************************************************************************** - /// Type list forward declaration. + // Type list forward declaration. //*************************************************************************** template struct type_list; + //*************************************************************************** + /// Check if a type is an etl::type_list. + //*************************************************************************** template struct is_type_list : etl::false_type {}; @@ -76,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; @@ -106,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; @@ -154,8 +159,8 @@ namespace etl template struct type_list_type_at_index { - ETL_STATIC_ASSERT(Index < type_list_size::value, "etl::type_list_type_at_index out of range"); - ETL_STATIC_ASSERT((etl::is_base_of, TTypeList>::value), "TTypeList must be an etl::type_list"); + ETL_STATIC_ASSERT(Index < TTypeList::size, "etl::type_list_type_at_index out of range"); + ETL_STATIC_ASSERT((etl::is_type_list::value), "TTypeList must be an etl::type_list"); using type = typename type_list_type_at_index::type; }; @@ -163,6 +168,8 @@ namespace etl template struct type_list_type_at_index { + ETL_STATIC_ASSERT((etl::is_type_list::value), "TTypeList must be an etl::type_list"); + using type = typename TTypeList::head; }; @@ -170,16 +177,18 @@ namespace etl using type_list_type_at_index_t = typename type_list_type_at_index::type; //*************************************************************************** - /// Defines an integral constant that is the index of the specified type in the type_list. + /// Defines an integral constant that is the index of the first instance of specified type in the type_list. /// If the type is not in the type_list, then defined as etl::type_list_npos. + /// Useful for type lists that do not contain duplicates, otherwise use type_list_indices_of_type. + /// Static asserts if TTypeList is not an etl::type_list. //*************************************************************************** template struct type_list_index_of_type : public etl::integral_constant::value ? 0 : - (type_list_index_of_type::value == etl::type_list_npos ? etl::type_list_npos : + (type_list_index_of_type::value == etl::type_list_npos ? etl::type_list_npos : type_list_index_of_type::value + 1)> { - ETL_STATIC_ASSERT((etl::is_base_of, TTypeList>::value), "TTypeList must be an etl::type_list"); + ETL_STATIC_ASSERT((etl::is_type_list::value), "TTypeList must be an etl::type_list"); }; template @@ -193,6 +202,56 @@ namespace etl inline constexpr size_t type_list_index_of_v = etl::type_list_index_of_type::value; #endif + //*************************************************************************** + /// Defines an index_sequence of indices where T appears in the type_list. + /// If the type is not in the type_list, then defined as an empty index_sequence. + /// Useful for type lists that contain duplicates, otherwise use type_list_index_of_type. + /// Static asserts if TTypeList is not an etl::type_list. + //*************************************************************************** + namespace private_type_list + { + template + struct type_list_indices_of_type_impl; + + // The general case, check the head type, then recurse with the rest of the types. + template + struct type_list_indices_of_type_impl, 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::value, + etl::index_sequence_push_back_t, + TResult>; + + public: + + // Recurse with the rest of the type_list, passing on the current result. + using type = typename type_list_indices_of_type_impl, T, Index + 1U, next_result>::type; + }; + + // Specialisation for an empty type_list. + // This is the terminating specialisation for the general case. + template + struct type_list_indices_of_type_impl, T, Index, TResult> + { + using type = TResult; + }; + } + + template + struct type_list_indices_of_type + { + ETL_STATIC_ASSERT((etl::is_type_list::value), "TTypeList must be an etl::type_list"); + + using type = typename private_type_list::type_list_indices_of_type_impl>::type; + }; + +#if ETL_USING_CPP11 + template + using type_list_indices_of_type_t = typename type_list_indices_of_type::type; +#endif + //*************************************************************************** /// Defines a bool constant that is true if the type_list contains the specified type, otherwise false. //*************************************************************************** @@ -311,12 +370,12 @@ namespace etl #endif //*************************************************************************** - /// Declares a new type_list by selecting types from a given type_list, according to an index sequence. + /// Declares a new type_list by selecting types from a given type_list, according to a list if indices. //*************************************************************************** template struct type_list_select { - ETL_STATIC_ASSERT((etl::is_base_of, TTypeList>::value), "TTypeList must be an etl::type_list"); + ETL_STATIC_ASSERT((etl::is_type_list::value), "TTypeList must be an etl::type_list"); using type = type_list...>; }; @@ -324,6 +383,21 @@ namespace etl template using type_list_select_t = typename type_list_select::type; + //*************************************************************************** + /// Declares a new type_list by selecting types from a given type_list, according to an index sequence. + //*************************************************************************** + template + struct type_list_select_from_index_sequence; + + template + struct type_list_select_from_index_sequence> + { + using type = etl::type_list_select_t; + }; + + template + using type_list_select_from_index_sequence_t = typename type_list_select_from_index_sequence::type; + //*************************************************************************** /// Concatenates two or more type_lists. //*************************************************************************** @@ -345,6 +419,345 @@ namespace etl template using type_list_cat_t = typename type_list_cat::type; + //*************************************************************************** + /// Add a type to the beginning of a type_list. + //*************************************************************************** + template + struct type_list_push_front; + + template + struct type_list_push_front, T> + { + using type = type_list; + }; + + template + using type_list_push_front_t = typename type_list_push_front::type; + + //*************************************************************************** + /// Add a type to the end of a type_list. + //*************************************************************************** + template + struct type_list_push_back; + + template + struct type_list_push_back, T> + { + using type = type_list; + }; + + template + using type_list_push_back_t = typename type_list_push_back::type; + + //*************************************************************************** + /// Insert a type at an index in a type_list. + /// Inserts before the type currently at Index. + /// If Index == size of the type_list, the type is appended. + //*************************************************************************** + template + struct type_list_insert + { + private: + + ETL_STATIC_ASSERT((etl::is_type_list::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; + using index_sequence_for_suffix = etl::make_index_sequence_with_offset; + + using prefix = etl::type_list_select_from_index_sequence_t; + using suffix = etl::type_list_select_from_index_sequence_t; + + 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, suffix>; + }; + +#if ETL_USING_CPP11 + template + using type_list_insert_t = typename etl::type_list_insert::type; +#endif + + //*************************************************************************** + /// Remove a type at an index in a type_list. + //*************************************************************************** + template + struct type_list_remove + { + private: + + ETL_STATIC_ASSERT((etl::is_type_list::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; + using index_sequence_for_suffix = etl::make_index_sequence_with_offset; + + using prefix = etl::type_list_select_from_index_sequence_t; + using suffix = etl::type_list_select_from_index_sequence_t; + + public: + + // Concatenate the prefix and suffix to create the new type list with the Index element removed. + using type = etl::type_list_cat_t; + }; + +#if ETL_USING_CPP11 + template + using type_list_remove_t = typename etl::type_list_remove::type; +#endif + + //*************************************************************************** + // Remove types that satisfy a predicate from a type_list. + //*************************************************************************** + namespace private_type_list + { + template class TPredicate> + struct type_list_remove_if_impl; + + template