From dc8c474ec4460d07e42c97e5fc24af99ec5bf3e4 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Sun, 7 Apr 2024 22:56:39 +0200 Subject: typelist: a type list with some algorithms --- type_list.cc | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 type_list.cc diff --git a/type_list.cc b/type_list.cc new file mode 100644 index 0000000..5a22b16 --- /dev/null +++ b/type_list.cc @@ -0,0 +1,164 @@ +#if 0 +set -xe +g++ -std=c++11 -fsyntax-only type_list.cc +clang++ -std=c++11 -fsyntax-only type_list.cc +exit 0 +#endif + +#include + +// Simple type list. +// +// A type list, as the name suggests, is a type which holds a list of types. +// Type lists can be arbitrarily nested and contain other type lists. +// +// Given a type list one can apply different algorithms, like adding types, +// flattening type lists and so on, where some are implement here. +// +// This is merely for fun and serves as a brain jogging exercise. + +namespace tl { +template +struct type_list; + +// -- GET ---------------------------------------------------------------------- + +template +struct get { + static_assert(Index < sizeof...(Tail) + 1, "index out of bounds"); + using type = typename get::type; +}; + +template +struct get<0, Head, Tail...> { + using type = Head; +}; + +template +using get_t = typename get::type; + +// -- PREPEND ------------------------------------------------------------------ + +template +struct prepend; + +template +using prepend_t = typename prepend::type; + +template +struct prepend> { + using type = type_list; +}; + +// -- FLATTEN ------------------------------------------------------------------ + +template +struct flatten; + +template +using flatten_t = typename flatten::type; + +template +struct flatten { + using type = prepend_t>; +}; + +// Specialization (1): +// Unpack inner types of LEADING type_list parameter and recursively flatten. +template +struct flatten, Tail...> { + using type = flatten_t; +}; + +// Specialization (2): +// Unpack inner types of SINGLE type_list parameter and recursively flatten. +template +struct flatten> { + using type = flatten_t; +}; + +// Specialization (3): +// Pack single non-type_list type into a type_list (recursive base case). +template +struct flatten { + using type = type_list; +}; + +// -- TYPE_LIST ---------------------------------------------------------------- + +template +struct type_list { + using self = type_list; + + static constexpr std::size_t len = sizeof...(Tail) + 1 /* Head */; + + // Get type at specific INDEX. + template + using get = get_t; + + // Prepend TYPE to the type list. + template + using prepend = prepend_t; + + // Flatten nested type lists. + using flatten = flatten_t; +}; +} // namespace tl + +// -- TESTS -------------------------------------------------------------------- + +#if __cplusplus >= 201703L +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__); +#else +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, "test failed"); +#endif + +// Flat type list. +namespace test1 { +using list = tl::type_list; +STATIC_ASSERT(list::len == 3); +STATIC_ASSERT(std::is_same, int>::value); +STATIC_ASSERT(std::is_same, char>::value); +STATIC_ASSERT(std::is_same, int>::value); +STATIC_ASSERT(std::is_same, + tl::type_list>::value); +STATIC_ASSERT(std::is_same::value); +} // namespace test1 + +// Nested type lists. +namespace test2 { +using list = tl::type_list, void>; +STATIC_ASSERT(list::len == 3); +STATIC_ASSERT(std::is_same, int>::value); +STATIC_ASSERT(std::is_same, tl::type_list>::value); +STATIC_ASSERT(std::is_same, void>::value); + +STATIC_ASSERT( + std::is_same< + list::prepend>, + tl::type_list, int, tl::type_list, void>>:: + value); + +using flat = list::flatten; +STATIC_ASSERT(flat::len == 3); +STATIC_ASSERT(std::is_same, int>::value); +STATIC_ASSERT(std::is_same, char>::value); +STATIC_ASSERT(std::is_same, void>::value); +} // namespace test2 + +// Deeply nested type lists. +namespace test3 { +using list = tl::type_list, int>>; +STATIC_ASSERT(list::len == 1); +STATIC_ASSERT( + std::is_same, + tl::type_list, int>>::value); + +using flat = list::flatten; +STATIC_ASSERT(flat::len == 3); +STATIC_ASSERT(std::is_same, char>::value); +STATIC_ASSERT(std::is_same, void>::value); +STATIC_ASSERT(std::is_same, int>::value); +} // namespace test3 + +#undef STATIC_ASSERT -- cgit v1.2.3