]> git.tdb.fi Git - libs/core.git/blob - source/core/typelist.h
ecc28faf64b1d41d2ca20e599ef1aac8935238e5
[libs/core.git] / source / core / typelist.h
1 #ifndef MSP_CORE_TYPELIST_H_
2 #define MSP_CORE_TYPELIST_H_
3
4 namespace Msp {
5
6 /** Sentinel type for type lists */
7 struct NullType { };
8
9
10 /** A "cons cell" for types.  Composed of a head and a tail.  To construct
11 longer lists, use another TypeCons as the tail.  The tail of the last TypeCons
12 should by NullType. */
13 template<typename H, typename T>
14 struct TypeCons
15 {
16         typedef H Head;
17         typedef T Tail;
18 };
19
20
21 /** Basic terminated type list of one element. */
22 template<typename T1>
23 struct TypeList1
24 {
25         typedef TypeCons<T1, NullType> Type;
26 };
27
28 /** Specialization to avoid creating a TypeCons with two NullTypes. */
29 template<>
30 struct TypeList1<NullType>
31 {
32         typedef NullType Type;
33 };
34
35 /** Specialization to avoid creating a TypeCons with another TypeCons as its
36 head. */
37 template<typename T1, typename T2>
38 struct TypeList1<TypeCons<T1, T2> >
39 {
40         typedef TypeCons<T1, T2> Type;
41 };
42
43 /** Basic terminated type list of two elements. */
44 template<typename T1, typename T2>
45 struct TypeList2
46 {
47         typedef TypeCons<T1, typename TypeList1<T2>::Type> Type;
48 };
49
50 /** Specialization to ignore an initial NullType. */
51 template<typename T1>
52 struct TypeList2<NullType, T1>
53 {
54         typedef typename TypeList1<T1>::Type Type;
55 };
56
57 /** Specialization to flatten an initial TypeCons. */
58 template<typename T1, typename T2, typename T3>
59 struct TypeList2<TypeCons<T1, T2>, T3>
60 {
61         typedef typename TypeList2<T1, typename TypeList2<T2, T3>::Type>::Type Type;
62 };
63
64
65 /** A terminated type list of five elements.  Use the typedef Type inside to
66 obtain the actual list type.  If any of the types is a type list itself, the
67 entire structure is flattened to a single list. */
68 template<typename T1, typename T2 = NullType, typename T3 = NullType, typename T4 = NullType, typename T5 = NullType>
69 struct TypeList
70 {
71         typedef typename TypeList<T1, typename TypeList<T2, T3, T4, T5>::Type>::Type Type;
72 };
73
74 /** Specialization of TypeList for one element. */
75 template<typename T1>
76 struct TypeList<T1, NullType, NullType, NullType, NullType>
77 {
78         typedef typename TypeList1<T1>::Type Type;
79 };
80
81 /** Specialization of TypeList for two elements. */
82 template<typename T1, typename T2>
83 struct TypeList<T1, T2, NullType, NullType, NullType>
84 {
85         typedef typename TypeList2<T1, T2>::Type Type;
86 };
87
88 /** Specialization of TypeList for three elements. */
89 template<typename T1, typename T2, typename T3>
90 struct TypeList<T1, T2, T3, NullType, NullType>
91 {
92         typedef typename TypeList<T1, typename TypeList<T2, T3>::Type>::Type Type;
93 };
94
95 /** Specialization of TypeList for four elements. */
96 template<typename T1, typename T2, typename T3, typename T4>
97 struct TypeList<T1, T2, T3, T4, NullType>
98 {
99         typedef typename TypeList<T1, typename TypeList<T2, T3, T4>::Type>::Type Type;
100 };
101
102
103 /** A helper for selecting a type from a list based on a predicate.  The
104 predicate should be a template taking a single type argument and defining a
105 compile-time constant with the name "value", which evaluates to true if the
106 type is considered a match.  The result can be obtained from the member
107 typedef Type.  If the list contains no matching type, an ugly and confusing
108 compiler error will result. */
109 template<typename L, template<typename> class P, bool f = P<typename L::Head>::value>
110 struct TypeChooser;
111
112 /** Specialization for a matching type.  Picks the head of the list as the
113 result. */
114 template<typename L, template<typename> class P>
115 struct TypeChooser<L, P, true>
116 {
117         typedef typename L::Head Type;
118 };
119
120 /** Specialization for a non-matchin type.  Recursively inspects the tail of
121 the list. */
122 template<typename L, template<typename> class P>
123 struct TypeChooser<L, P, false>
124 {
125         typedef typename TypeChooser<typename L::Tail, P>::Type Type;
126 };
127
128 } // namespace Msp
129
130 #endif