// TypeList
#ifndef TYPE_LIST_HPP
#define TYPE_LIST_HPP
#include <tuple>
#include <type_traits>
/*
size -> get size of type list
empty -> whether the list is empty
push_front -> remove first type from type list
front -> get first type from type list
pop_front -> remove first element from list
max_type -> return max type
min_type -> return min type
reverse -> reverse elements of list
push_back -> add a new type to the last of type list
pop_back -> remove last element from list
back -> get last type from type list
find_first_index_of -> ......
*/
namespace my::type {
using empty_list = std::tuple<>;
// -------------to_type_list--------------
template <typename... Types>
struct to_type_list : std::enable_if<true, std::tuple<Types...>> {};
template <template <typename...> typename TemplateClass, typename... Types>
struct to_type_list<TemplateClass<Types...>>
: std::enable_if<true, std::tuple<Types...>> {};
template <template <typename...> typename T, typename...>
struct accept_parameters_from_type_list;
template <template <typename...> typename TemplateClass, typename... Types>
struct accept_parameters_from_type_list<TemplateClass, std::tuple<Types...>> {
using type = TemplateClass<Types...>;
};
// --------------type_size-----------------
template <typename T>
struct size;
template <typename... Types>
struct size<std::tuple<Types...>>
: std::integral_constant<size_t, sizeof...(Types)> {};
// ------------------front---------------------------
template <typename T>
struct front;
template <typename T, typename... Types>
struct front<std::tuple<T, Types...>> : std::enable_if<true, T> {};
// ------------------type_empty------------------------------
template <typename T>
struct empty;
template <typename... Types>
struct empty<std::tuple<Types...>>
: std::conditional_t<(sizeof...(Types) == 0), std::true_type,
std::false_type> {};
// push T at the head of list
template <typename T, typename... List>
struct push_front;
template <typename T, typename... Types>
struct push_front<T, std::tuple<Types...>>
: std::enable_if<true, std::tuple<T, Types...>> {};
// pop the first type of list
template <typename List>
struct pop_front;
template <typename T, typename... Types>
struct pop_front<std::tuple<T, Types...>>
: std::enable_if<true, std::tuple<Types...>> {};
// max type
template <typename List>
struct max_type;
template <typename T>
struct max_type<std::tuple<T>> : std::enable_if<true, T> {};
template <typename T1, typename T2, typename... Types>
struct max_type<std::tuple<T1, T2, Types...>>
: std::conditional_t<(sizeof(T1) > sizeof(T2)),
max_type<std::tuple<T1, Types...>>,
max_type<std::tuple<T2, Types...>>> {};
// min type
template <typename List>
struct min_type;
template <typename T>
struct min_type<std::tuple<T>> : std::enable_if<true, T> {};
template <typename T1, typename T2, typename... Types>
struct min_type<std::tuple<T1, T2, Types...>>
: std::conditional_t<(sizeof(T1) < sizeof(T2)),
min_type<std::tuple<T1, Types...>>,
min_type<std::tuple<T2, Types...>>> {};
template <size_t Index, typename List>
struct index_of;
template <typename T, typename... Types>
struct index_of<0, std::tuple<T, Types...>> : std::enable_if<true, T> {};
template <size_t Index, typename T1, typename T2, typename... Types>
struct index_of<Index, std::tuple<T1, T2, Types...>>
: index_of<Index - 1, std::tuple<T2, Types...>> {};
namespace hide {
template <typename List1, typename List2>
struct reverse_helper;
template <typename T, typename... Types1, typename... Types2>
struct reverse_helper<std::tuple<T, Types1...>, std::tuple<Types2...>>
: reverse_helper<std::tuple<Types1...>, std::tuple<T, Types2...>> {};
template <typename... Types>
struct reverse_helper<std::tuple<>, std::tuple<Types...>>
: std::enable_if<true, std::tuple<Types...>> {};
} // namespace hide
template <typename List>
struct reverse;
template <typename T>
struct reverse<std::tuple<T>> : std::enable_if<true, std::tuple<T>> {};
template <typename T1, typename T2, typename... Types>
struct reverse<std::tuple<T1, T2, Types...>>
: hide::reverse_helper<std::tuple<T2, Types...>, std::tuple<T1>> {};
template <typename List>
struct back;
template <typename T>
struct back<std::tuple<T>> : std::enable_if<true, T> {};
template <typename T, typename... Types>
struct back<std::tuple<T, Types...>> : back<std::tuple<Types...>> {};
namespace hide {
// another way in c++17 to implement back with O(1) instantiation depth
template <typename... Types>
struct select_last {
using type = typename decltype((std::enable_if<true, Types>{}, ...))::type;
};
} // namespace hide
template <typename T, typename List>
struct push_back;
template <typename T, typename... Types>
struct push_back<T, std::tuple<Types...>>
: std::enable_if<true, std::tuple<Types..., T>> {};
template <typename List>
struct pop_back;
// template <typename T>
// struct pop_back<std::tuple<T>> : std::enable_if<true, std::tuple<>> {};
// template <typename T, typename... Types>
// struct pop_back<std::tuple<T, Types...>>
// : reverse<typename pop_front<
// typename reverse<std::tuple<T, Types...>>::type>::type> {};
namespace hide {
template <typename List1, typename List2>
struct pop_back_helper;
template <typename... Types1, typename... Types2, typename T1, typename T2>
struct pop_back_helper<std::tuple<Types1...>, std::tuple<T1, T2, Types2...>>
: pop_back_helper<std::tuple<Types1..., T1>, std::tuple<T2, Types2...>> {};
template <typename... Types, typename T>
struct pop_back_helper<std::tuple<Types...>, std::tuple<T>>
: std::enable_if<true, std::tuple<Types...>> {};
} // namespace hide
template <typename... Types>
struct pop_back<std::tuple<Types...>>
: hide::pop_back_helper<std::tuple<>, std::tuple<Types...>> {};
// find the first type in Typeist
template <typename List, typename TargetType>
struct find_first_index_of;
namespace hide {
template <size_t Index, typename List, typename TargetType>
struct find_first_index_of_helper;
template <size_t Index, typename T1, typename...Types, typename TargetType>
struct find_first_index_of_helper<Index, std::tuple<T1, Types...>, TargetType>
: std::conditional_t<std::is_same_v<T1, TargetType>,
std::integral_constant<size_t, Index>,
find_first_index_of_helper<Index + 1, std::tuple<Types...>,
TargetType>
> { };
constexpr size_t npos = static_cast<size_t>(-1);
template <size_t Index, typename TargetType>
struct find_first_index_of_helper<Index, std::tuple<>, TargetType>
: std::integral_constant<size_t, npos> { };
}
template <typename... Types, typename TargetType>
struct find_first_index_of<std::tuple<Types...>, TargetType>
: hide::find_first_index_of_helper<0, std::tuple<Types...>, TargetType> { };
// constexpr auto a = find_first_index_of<std::tuple<int, double, bool>, int>::value;
// constexpr auto b = find_first_index_of<std::tuple<int, double, bool>, double>::value;
// constexpr auto c = find_first_index_of<std::tuple<int, double, bool>, bool>::value;
// constexpr auto d = find_first_index_of<std::tuple<int, double, bool>, char>::value;
} // namespace my::type
#endif