1 /*
2     Copyright (C) 2013 Tom Bachmann
3 
4     This file is part of FLINT.
5 
6     FLINT is free software: you can redistribute it and/or modify it under
7     the terms of the GNU Lesser General Public License (LGPL) as published
8     by the Free Software Foundation; either version 2.1 of the License, or
9     (at your option) any later version.  See <http://www.gnu.org/licenses/>.
10 */
11 
12 #ifndef CXX_MP_H
13 #define CXX_MP_H
14 
15 namespace flint {
16 namespace mp {
17 /////////////////////////////////
18 // BASIC METAPROGRAMMING HELPERS
19 /////////////////////////////////
20 // Most of these helpers *compute* something. In this case, they have a static
21 // static const member "val" storing the result of the computation. The
22 // arguments of the computation are template parameters, and are usually *not*
23 // PODs, but instead themselves types with a static constant "val" member.
24 // See value_of, true_ and false_ for how to pass in explicit values to your
25 // computation.
26 
27 // Wrap the boolean value "v" into the static const member "val".
28 template<bool v> struct value_of { static const bool val = v; };
29 
30 // Boolean inputs for computations.
31 struct true_ : value_of<true> { };
32 struct false_ : value_of<false> { };
33 
34 // Compute if two input *types* (not values!) are equal.
35 template<class T, class U>
36 struct equal_types : false_ { };
37 template<class T>
38 struct equal_types<T, T> : true_ { };
39 
40 // Compute logical negation of the input value.
41 template<class T>
42 struct not_ : value_of<!T::val> { };
43 
44 // Compute logical and of the input values.
45 template<class T1, class T2, class T3 = void,
46     class T4 = void, class T5 = void, class T6 = void, class T7 = void, class T8 = void>
47 struct and_ : and_<T1, and_<T2, T3, T4, T5, T6, T7, T8> > { };
48 
49 template<class T, class U>
50 struct and_<T, U, void, void, void, void> : value_of<T::val && U::val> { };
51 
52 template<class T, bool u>
53 struct and_v : and_<T, value_of<u> > { };
54 
55 // Compute logical or of the input values.
56 template<class T1, class T2, class T3 = void,
57     class T4 = void, class T5 = void, class T6 = void>
58 struct or_ : or_<T1, or_<T2, T3, T4, T5> > { };
59 
60 template<class T, class U>
61 struct or_<T, U, void, void, void, void> : value_of<T::val || U::val> { };
62 
63 // Compute V1 or V2, depending on C
64 template<bool C, class V1, class V2>
65 struct if_v {typedef V1 type;};
66 template<class V1, class V2>
67 struct if_v<false, V1, V2> {typedef V2 type;};
68 
69 template<class C, class V1, class V2>
70 struct if_ : if_v<C::val, V1, V2> { };
71 
72 // Choose a value depending on a sequence of conditions.
73 // This has he same meaning as
74 //  int select(bool c1 = false, bool c2 = false, bool c3 = false)
75 //  {
76 //      if(c1)
77 //          return v1;
78 //      if(c2)
79 //          return v2;
80 //      if(c3)
81 //          return v3;
82 //      return d;
83 //  }
84 template<class D, class C1 = void, class V1 = void,
85     class C2 = void, class V2 = void,
86     class C3 = void, class V3 = void>
87 struct select : if_<C1, V1, typename select<D, C2, V2, C3, V3>::type> { };
88 
89 template<class D>
90 struct select<D,  void, void,  void, void,  void, void> {typedef D type;};
91 
92 // Conditional template enabling helper. (See below for explanation.)
93 template<bool, class U = void>
94 struct enable_if_v
95 {
96     typedef U type;
97     static const int val = 0;
98 };
99 template<class U>
100 struct enable_if_v<false, U> { };
101 
102 // Conditional template enabling.
103 //
104 // These two helpers (enable_if and disable_if) can be used wherever the
105 // SFINAE rule applies to conditionally enable or disable template
106 // specialisations.
107 //
108 // If T evaluaties to true, then enable_if has a member typedef "type", which
109 // is the parameter U, and also a static const int member val (of zero).
110 // If on the other hand T evaluates to false, then enable_if is empty.
111 // The meaning of T is reversed for disable_if.
112 // See e.g. [0] or the tests for how to use this.
113 //
114 // [0] http://www.boost.org/doc/libs/1_53_0/libs/utility/enable_if.html
115 //
116 template<class T, class U = void>
117 struct enable_if : public enable_if_v<T::val, U> { };
118 template<class T, class U = void>
119 struct disable_if : public enable_if<not_<T>, U> { };
120 
121 struct empty { };
122 } // mp
123 } // flint
124 
125 #endif
126