1 /* Metaprogramming utilities.
2    Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3    Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #ifndef PPL_meta_programming_hh
25 #define PPL_meta_programming_hh 1
26 
27 #include <gmpxx.h>
28 
29 namespace Parma_Polyhedra_Library {
30 
31 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
32 /*! \brief
33   Declares a per-class constant of type <CODE>bool</CODE>, called \p name
34   and with value \p value.
35 
36   \ingroup PPL_CXX_interface
37   Differently from static constants, \p name needs not (and cannot) be
38   defined (for static constants, the need for a further definition is
39   mandated by Section 9.4.2/4 of the C++ standard).
40 */
41 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
42 #define const_bool_nodef(name, value)           \
43   enum const_bool_value_ ## name { PPL_U(name) = (value) }
44 
45 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
46 /*! \brief
47   Declares a per-class constant of type <CODE>int</CODE>, called \p name
48   and with value \p value.
49 
50   \ingroup PPL_CXX_interface
51   Differently from static constants, \p name needs not (and cannot) be
52   defined (for static constants, the need for a further definition is
53   mandated by Section 9.4.2/4 of the C++ standard).
54 */
55 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
56 #define const_int_nodef(name, value) \
57   enum anonymous_enum_ ## name { PPL_U(name) = (value) }
58 
59 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
60 /*! \brief
61   Declares a per-class constant of type \p type, called \p name
62   and with value \p value.  The value of the constant is accessible
63   by means of the syntax <CODE>name()</CODE>.
64 
65   \ingroup PPL_CXX_interface
66   Differently from static constants, \p name needs not (and cannot) be
67   defined (for static constants, the need for a further definition is
68   mandated by Section 9.4.2/4 of the C++ standard).
69 */
70 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
71 #define const_value_nodef(type, name, value)    \
72   static type PPL_U(name)() {                   \
73     return (value);                             \
74   }
75 
76 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
77 /*! \brief
78   Declares a per-class constant of type \p type, called \p name
79   and with value \p value.  A constant reference to the constant
80   is accessible by means of the syntax <CODE>name()</CODE>.
81 
82   \ingroup PPL_CXX_interface
83   Differently from static constants, \p name needs not (and cannot) be
84   defined (for static constants, the need for a further definition is
85   mandated by Section 9.4.2/4 of the C++ standard).
86 */
87 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
88 #define const_ref_nodef(type, name, value)                              \
89   static const type& PPL_U(name)() {                                    \
90     static type PPL_U(name) = (value);                                       \
91     return (name);                                                      \
92   }
93 
94 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
95 /*! \brief
96   A class that is only defined if \p b evaluates to <CODE>true</CODE>.
97 
98   \ingroup PPL_CXX_interface
99   This is the non-specialized case, so the class is declared but not defined.
100 */
101 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
102 template <bool b>
103 struct Compile_Time_Check;
104 
105 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
106 /*! \brief
107   A class that is only defined if \p b evaluates to <CODE>true</CODE>.
108 
109   \ingroup PPL_CXX_interface
110   This is the specialized case with \p b equal to <CODE>true</CODE>,
111   so the class is declared and (trivially) defined.
112 */
113 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
114 template <>
115 struct Compile_Time_Check<true> {
116 };
117 
118 #define PPL_COMPILE_TIME_CHECK_NAME(suffix) compile_time_check_ ## suffix
119 #define PPL_COMPILE_TIME_CHECK_AUX(e, suffix)                           \
120   enum anonymous_enum_compile_time_check_ ## suffix {                   \
121     /* If e evaluates to false, then the sizeof cannot be compiled. */  \
122     PPL_COMPILE_TIME_CHECK_NAME(suffix)                                 \
123       = sizeof(Parma_Polyhedra_Library::Compile_Time_Check<(e)>)        \
124   }
125 
126 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
127 /*! \brief
128   Produces a compilation error if the compile-time constant \p e does
129   not evaluate to <CODE>true</CODE>
130   \ingroup PPL_CXX_interface
131 */
132 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
133 #define PPL_COMPILE_TIME_CHECK(e, msg) PPL_COMPILE_TIME_CHECK_AUX(e, __LINE__)
134 
135 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
136 /*! \brief
137   A class holding a constant called <CODE>value</CODE> that evaluates
138   to \p b.
139   \ingroup PPL_CXX_interface
140 */
141 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
142 template <bool b>
143 struct Bool {
144   enum const_bool_value {
145     value = b
146   };
147 };
148 
149 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
150 /*! \brief
151   A class holding a constant called <CODE>value</CODE> that evaluates
152   to <CODE>true</CODE>.
153   \ingroup PPL_CXX_interface
154 */
155 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
156 struct True : public Bool<true> {
157 };
158 
159 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
160 /*! \brief
161   A class holding a constant called <CODE>value</CODE> that evaluates
162   to <CODE>false</CODE>.
163   \ingroup PPL_CXX_interface
164 */
165 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
166 struct False : public Bool<false> {
167 };
168 
169 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
170 /*! \brief
171   A class holding a constant called <CODE>value</CODE> that evaluates
172   to <CODE>true</CODE> if and only if \p T1 is the same type as \p T2.
173 
174   \ingroup PPL_CXX_interface
175   This is the non-specialized case, in which \p T1 and \p T2 can be different.
176 */
177 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
178 template <typename T1, typename T2>
179 struct Is_Same : public False {
180 };
181 
182 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
183 /*! \brief
184   A class holding a constant called <CODE>value</CODE> that evaluates
185   to <CODE>true</CODE> if and only if \p T1 is the same type as \p T2.
186 
187   \ingroup PPL_CXX_interface
188   This is the specialization in which \p T1 and \p T2 are equal.
189 */
190 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
191 template <typename T>
192 struct Is_Same<T, T> : public True {
193 };
194 
195 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
196 /*! \brief
197   A class holding a constant called <CODE>value</CODE> that evaluates
198   to <CODE>true</CODE> if and only if \p Base is the same type as \p Derived
199   or \p Derived is a class derived from \p Base.
200 
201   \ingroup PPL_CXX_interface
202   \note
203   Care must be taken to use this predicate with template classes.
204   Suppose we have
205   \code
206   template <typename T> struct B;
207   template <typename T> struct D : public B<T>;
208   \endcode
209   Of course, we cannot test if, for some type variable <CODE>U</CODE>, we have
210   <CODE>Is_Same_Or_Derived<B<U>, Type>:: const_bool_value:: value == true</CODE>.
211   But we can do as follows:
212   \code
213   struct B_Base {
214   };
215 
216   template <typename T> struct B : public B_Base;
217   \endcode
218   This enables us to inquire
219   <CODE>Is_Same_Or_Derived<B_Base, Type>:: const_bool_value:: value</CODE>.
220 */
221 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
222 template <typename Base, typename Derived>
223 struct Is_Same_Or_Derived {
224 
225 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
226   //! A class that is constructible from just anything.
227 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
228   struct Any {
229     //! The universal constructor.
230     template <typename T>
231     Any(const T&);
232   };
233 
234   //! Overloading with \p Base.
235   static char func(const Base&);
236 
237   //! Overloading with \p Any.
238   static double func(Any);
239 
240   //! A function obtaining a const reference to a \p Derived object.
241   static const Derived& derived_object();
242 
243   PPL_COMPILE_TIME_CHECK(sizeof(char) != sizeof(double),
244                          "architecture with sizeof(char) == sizeof(double)"
245                          " (!?)");
246 
247   enum const_bool_value {
248     /*!
249       Assuming <CODE>sizeof(char) != sizeof(double)</CODE>, the C++
250       overload resolution mechanism guarantees that <CODE>value</CODE>
251       evaluates to <CODE>true</CODE> if and only if <CODE>Base</CODE>
252       is the same type as <CODE>Derived</CODE> or <CODE>Derived</CODE>
253       is a class derived from <CODE>Base</CODE>.
254     */
255     value = (sizeof(func(derived_object())) == sizeof(char))
256   };
257 };
258 
259 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
260 /*! \brief
261   A class that provides a type member called <CODE>type</CODE> equivalent
262   to \p T if and only if \p b is <CODE>true</CODE>.
263 
264   \ingroup PPL_CXX_interface
265   This is the non-specialized case, in which the <CODE>type</CODE> member
266   is not present.
267 */
268 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
269 template <bool b, typename T = void>
270 struct Enable_If {
271 };
272 
273 template <typename Type, Type, typename T = void>
274 struct Enable_If_Is {
275   typedef T type;
276 };
277 
278 #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
279 /*! \brief
280   A class that provides a type member called <CODE>type</CODE> equivalent
281   to \p T if and only if \p b is <CODE>true</CODE>.
282 
283   \ingroup PPL_CXX_interface
284   This is the specialization in which the <CODE>type</CODE> member
285   is present.
286 
287   \note
288   Let <CODE>T</CODE>, <CODE>T1</CODE> and <CODE>T2</CODE> be any type
289   expressions and suppose we have some template function
290   <CODE>T f(T1, T2)</CODE>.  If we want to declare a specialization
291   that is enabled only if some compile-time checkable condition holds,
292   we simply declare the specialization by
293   \code
294   template ...
295   typename Enable_If<condition, T>::type
296   foo(T1 x, T2 y);
297   \endcode
298   For all the instantiations of the template parameters that cause
299   <CODE>condition</CODE> to evaluate to <CODE>false</CODE>,
300   the <CODE>Enable_If<condition, T>::type</CODE> member will not be defined.
301   Hence, for that instantiations, the specialization will not be eligible.
302 */
303 #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS)
304 template <typename T>
305 struct Enable_If<true, T> {
306   typedef T type;
307 };
308 
309 template <typename T>
310 struct Is_Native : public False {
311 };
312 
313 template <> struct Is_Native<char> : public True { };
314 template <> struct Is_Native<signed char> : public True { };
315 template <> struct Is_Native<signed short> : public True { };
316 template <> struct Is_Native<signed int> : public True { };
317 template <> struct Is_Native<signed long> : public True { };
318 template <> struct Is_Native<signed long long> : public True { };
319 template <> struct Is_Native<unsigned char> : public True { };
320 template <> struct Is_Native<unsigned short> : public True { };
321 template <> struct Is_Native<unsigned int> : public True { };
322 template <> struct Is_Native<unsigned long> : public True { };
323 template <> struct Is_Native<unsigned long long> : public True { };
324 
325 #if PPL_SUPPORTED_FLOAT
326 template <> struct Is_Native<float> : public True { };
327 #endif
328 #if PPL_SUPPORTED_DOUBLE
329 template <> struct Is_Native<double> : public True { };
330 #endif
331 #if PPL_SUPPORTED_LONG_DOUBLE
332 template <> struct Is_Native<long double> : public True { };
333 #endif
334 
335 template <> struct Is_Native<mpz_class> : public True { };
336 
337 template <> struct Is_Native<mpq_class> : public True { };
338 
339 } // namespace Parma_Polyhedra_Library
340 
341 #endif // !defined(PPL_meta_programming_hh)
342