diff --git a/.gitignore b/.gitignore index e257658..91a88f8 100644 --- a/.gitignore +++ b/.gitignore @@ -31,4 +31,5 @@ *.exe *.out *.app - +/peano +/typecollections diff --git a/README.md b/README.md index cf54e8e..f27d3c1 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,4 @@ A repository of samples in C++ - peano.cpp: Pattern Matching and Type Arithmetic in C++ +- typecollections.cpp : Pattern Matching of Variadic Templates for Type Collections in C++ diff --git a/typecollections.cpp b/typecollections.cpp new file mode 100644 index 0000000..bb8e5ab --- /dev/null +++ b/typecollections.cpp @@ -0,0 +1,318 @@ +// Pattern Matching of Variadic Templates for Type Collections in C++ +// - see peano.cpp for an introduction to type arithmetic +// - check a functional programming language like Haskell for +// the declaration and usage of recursive lists + +// compile and test: "c++ typecollections.cpp -o typecollections && ./typecollections" + +// +// typelist declaration +// + +template +struct typelist { +}; + +// +// typelist_index: get the (first) index of a type +// + +// empty declaration: compilation error if the type is not found +template +struct typelist_index { +}; + +// end of the recursion, the type match the head +template +struct typelist_index> { + enum : unsigned { value = 0 }; +}; + +// recursive declaration +template +struct typelist_index> { + enum : unsigned { value = typelist_index>::value + 1u }; +}; + +// +// typelist_get: get the type at the given index +// + +// empty declaration: compilation error if the index is out of bound +template +struct typelist_get { +}; + +// end of the recursion, the type match +template +struct typelist_get<0u, typelist<_type, tail...>> { + using type = _type; +}; + +// recursive declaration +template +struct typelist_get> { + using type = typename typelist_get>::type; +}; + +// +// typelist_insert: insert an element at the beginning of a list +// + +// declaration +template +struct typelist_insert { +}; + +// insert the new head, actually not recursive +template +struct typelist_insert> { + using type = typelist; +}; + +// +// typedict_entry declaration +// + +// typedict_entry declaration +template +struct typedict_entry { +}; + +// +// typedict_contains: check if the typelist contains the key +// + +// declaration and fallback if the key is missing +template +struct typedict_contains { + enum : bool { value = false }; +}; + +// end of the recursion when the key is found +template +struct typedict_contains, tail...>> { + enum : bool { value = true }; +}; + +// recursive declaration +template +struct typedict_contains> { + enum : bool { value = typedict_contains>::value }; +}; + +// +// typedict_index: get the (first) index of a key +// + +// empty declaration: compilation error if the key is missing +template +struct typedict_index { +}; + +// end of the recursion, the key match +template +struct typedict_index, tail...>> { + enum : unsigned { value = 0 }; +}; + +// recursive declaration +template +struct typedict_index> { + enum : unsigned { value = typedict_index>::value + 1u }; +}; + +// +// typedict_get: get the type associated with a key +// + +// empty declaration: compilation error if the key is missing +template +struct typedict_get { +}; + +// end of the recursion: the key match a typedict_entry in the list +template +struct typedict_get, tail...>> { + using type = _type; +}; + +// recursive declaration +template +struct typedict_get> { + using type = typename typedict_get>::type; +}; + +// +// typetree_flatten: flatten a tree +// + +// empty declaration: end of the recursion if the typelist is empty +template +struct typetree_flatten { + using type = typelist<>; +}; + +// recursive declaration when the first element is a list +template +struct typetree_flatten, tail...>> { + using type = typename typetree_flatten>::type; +}; + +// recursive declaration +template +struct typetree_flatten> { + using type = typename typelist_insert>::type>::type; +}; + +// +// now let's test! +// + +#include + +void test_typelist() { + using testlist = typelist; + + // output: index of bool = 0 + printf("index of bool = %u\n", + typelist_index::value); + + // output: index of int = 1 + printf("index of int = %u\n", + typelist_index::value); + + // output: index of float = 2 + printf("index of float = %u\n", + typelist_index::value); + + // compilation error: type not found + // printf("index of double = %u\n", + // typelist_index::value); + + auto const bool_value = typelist_get<0u, testlist>::type(true); + auto const int_value = typelist_get<1u, testlist>::type(42); + auto const float_value = typelist_get<2u, testlist>::type(3.14159f); + + // compilation error: cast not allowed + // auto const badtype_value = typelist_get<2u, testlist>::type("string"); + + // compilation error: index out of range + // auto const outofrange_value = typelist_get<3u, testlist>::type(); + + // output: bool = true, int = 42, float = 3.141590 + printf("bool = %s, int = %d, float = %f\n", + bool_value ? "true" : "false", int_value, float_value); +} + +void test_typedict() { + enum { + key1, + key2, + key3, + key4 + }; + + using testdict = typelist< + typedict_entry, + typedict_entry, + typedict_entry + >; + + // output: contains key1 = true + printf("contains key1 = %s\n", + typedict_contains::value ? "true" : "false"); + + // output: contains key4 = false + printf("contains key4 = %s\n", + typedict_contains::value ? "true" : "false"); + + // output: index of key1 = 0 + printf("index of key1 = %u\n", + typedict_index::value); + + // output: index of key2 = 1 + printf("index of key2 = %u\n", + typedict_index::value); + + // output: index of key3 = 2 + printf("index of key3 = %u\n", + typedict_index::value); + + // compilation error: entry not found + // printf("index of key4 = %u\n", + // typedict_index::value); + + auto const bool_value = typedict_get::type(true); + auto const int_value = typedict_get::type(42); + auto const float_value = typedict_get::type(3.14159f); + + // compilation error: cast not allowed + // auto const badtype_value = typedict_get::type("string"); + + // compilation error: entry not found + // auto const outofrange_value = typedict_get::type(); + + // output: bool = true, int = 42, float = 3.141590 + printf("bool = %s, int = %d, float = %f\n", + bool_value ? "true" : "false", int_value, float_value); +} + +void test_typetree() { + enum { + key1, + key2, + key3, + key4 + }; + + using testtree = typelist< + typelist< + typedict_entry + >, + typelist< + typelist< + typedict_entry + > + >, + typelist< + typelist< + typelist< + typedict_entry + >, + typedict_entry + > + > + >; + + using flattened = typetree_flatten::type; + + // output: index of key1 = 0 + printf("index of key1 = %u\n", + typedict_index::value); + + // output: index of key2 = 1 + printf("index of key2 = %u\n", + typedict_index::value); + + // output: index of key3 = 2 + printf("index of key3 = %u\n", + typedict_index::value); + + // output: index of key4 = 3 + printf("index of key4 = %u\n", + typedict_index::value); +} + +int main () { + printf("\n> typelist test:\n"); + test_typelist(); + + printf("\n> typedict test:\n"); + test_typedict(); + + printf("\n> typetree test:\n"); + test_typetree(); + + return 0; +}