Rheolef  7.2
an efficient C++ finite element environment
field_expr_utilities.h
Go to the documentation of this file.
1 #ifndef _RHEOLEF_FIELD_EXPR_UTILITIES_H
2 #define _RHEOLEF_FIELD_EXPR_UTILITIES_H
3 //
4 // This file is part of Rheolef.
5 //
6 // Copyright (C) 2000-2009 Pierre Saramito
7 //
8 // Rheolef is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // Rheolef is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with Rheolef; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 //
22 // ==========================================================================
23 //
24 // utiities for field expressions
25 //
26 // author: Pierre.Saramito@imag.fr
27 //
28 // date: 4 september 2015
29 //
30 #include "rheolef/promote.h"
31 #include "rheolef/point.h"
32 #include <functional>
33 #include <type_traits>
34 
35 namespace rheolef { namespace details {
36 
37 // ---------------------------------------------------------------------------
38 // type comparator, up to std::decay
39 // ---------------------------------------------------------------------------
40 template <typename T1, typename T2>
42  : std::is_same<
43  typename std::decay<T1>::type,
44  typename std::decay<T2>::type
45  >::type
46 {};
47 
48 // ---------------------------------------------------------------------------
49 // metaprogramming logicals: and, or, not with types
50 // ---------------------------------------------------------------------------
51 // TODO: obsolete, replace it by std::disjunction<...> etc
52 
53 template<typename...>
54  struct or_type;
55 
56 template<>
57  struct or_type<>
58  : public std::false_type
59  { };
60 
61 template<typename B1>
62  struct or_type<B1>
63  : public B1
64  { };
65 
66 template<typename B1, typename B2>
68  : public std::conditional<B1::value, B1, B2>::type
69  { };
70 
71 template<typename B1, typename B2, typename B3, typename... Bn>
72  struct or_type<B1, B2, B3, Bn...>
73  : public std::conditional<B1::value, B1, or_type<B2, B3, Bn...>>::type
74  { };
75 
76 template<typename...>
77  struct and_type;
78 
79 template<>
80  struct and_type<>
81  : public std::true_type
82  { };
83 
84 template<typename B1>
85  struct and_type<B1>
86  : public B1
87  { };
88 
89 template<typename B1, typename B2>
91  : public std::conditional<B1::value, B2, B1>::type
92  { };
93 
94 template<typename B1, typename B2, typename B3, typename... Bn>
95  struct and_type<B1, B2, B3, Bn...>
96  : public std::conditional<B1::value, and_type<B2, B3, Bn...>, B1>::type
97  { };
98 
99 template<typename P>
100  struct not_type
101  : public std::integral_constant<bool, !P::value>
102  { };
103 
104 // ------------------------------------------
105 // tools for creating index lists
106 // ------------------------------------------
107 // TODO: C++2014 introduced index_sequence : test configure, etc
108 
109 // the structure that encapsulates index lists
110 template <size_t... Is>
111 struct index_list {};
112 
113 // Collects internal details for generating index ranges [MIN, MAX)
114  // declare primary template for index range builder
115  template <size_t MIN, size_t N, size_t... Is>
116  struct range_builder;
117 
118  // base step
119  template <size_t MIN, size_t... Is>
120  struct range_builder<MIN, MIN, Is...>
121  {
122  typedef index_list<Is...> type;
123  };
124 
125  // induction step
126  template <size_t MIN, size_t N, size_t... Is>
127  struct range_builder: public range_builder<MIN, N - 1, N - 1, Is...>
128  {
129  };
130 
131 // Meta-function that returns a [MIN, MAX[ index range
132 template<size_t MIN, size_t MAX>
134 
135 // ---------------------------------------------------------------------------
136 // general functor traits
137 // ---------------------------------------------------------------------------
138 // https://functionalcpp.wordpress.com/2013/08/05/function-traits/
139 
140 // functor:
141 template <typename T>
142 struct functor_traits : public functor_traits<decltype(&T::operator())> {};
143 
144 template <typename C, typename R, typename... Args>
145 struct functor_traits<R(C::*)(Args...) const> { // op() with a const qualifier
146  using result_type = R;
147  static const std::size_t arity = sizeof...(Args);
148  template <std::size_t I>
149  struct arg {
150  static_assert(I < arity, "error: invalid parameter index.");
151  using type = typename std::tuple_element<I, std::tuple<Args...> >::type;
152  using decay_type = typename std::decay<type>::type;
153  };
154  typedef std::tuple<Args...> args_tuple_type;
155  using function_type = R (Args...);
156  using function_pointer_type = R (*)(Args...);
157  using copiable_type = C;
158  using functor_type = C;
159 };
160 // true function:
161 template<class F>
163 
164 template<class R, class... Args>
165 struct true_function_traits<R(*)(Args...)> : public true_function_traits<R(Args...)> {};
166 
167 template<class R, class... Args>
168 struct true_function_traits<R(Args...)> {
169  using result_type = R;
170  static constexpr std::size_t arity = sizeof...(Args);
171  template <std::size_t I>
172  struct arg {
173  static_assert(I < arity, "error: invalid parameter index.");
174  using type = typename std::tuple_element<I,std::tuple<Args...> >::type;
175  };
176  typedef std::tuple<Args...> args_tuple_type;
177  using function_type = R (Args...);
178  using function_pointer_type = R (*)(Args...);
179  //using copiable_type = std::function<R(Args...)>; // more levels of indirections
181  using functor_type = std::function<R(Args...)>;
182 };
183 // select either true-fonction or functor
184 template<class F> struct function_traits : functor_traits<F> {};
185 template <typename R, typename... Args> struct function_traits <R(Args...)> : true_function_traits<R(Args...)> {};
186 template <typename R, typename... Args> struct function_traits <R(*)(Args...)> : true_function_traits<R(Args...)> {};
187 
188 #ifdef TO_CLEAN
189 // field class is not an ordinary function/functor : for compose(field,args...) filtering
190 // TODO: should be moved in field.h
191 template <typename T, typename M> class field_basic; // forward declaration
192 template <typename T, typename M> struct function_traits <field_basic<T,M> > {};
193 #endif // TO_CLEAN
194 // -----------------------------------------------------------------------
195 // is_callable<Funct,Signature>::value : for both functions and functors
196 // -----------------------------------------------------------------------
197 // http://stackoverflow.com/questions/9083593/is-an-is-functor-c-trait-class-possible
198 
199 // build R (*)(Args...) from R (Args...)
200 // compile error if signature is not a valid function signature
201 template <typename, typename>
203 
204 template <typename F, typename R, typename ... Args>
205 struct build_free_function<F, R (Args...)>
206 { using type = R (*)(Args...); };
207 
208 // build R (C::*)(Args...) from R (Args...)
209 // R (C::*)(Args...) const from R (Args...) const
210 // R (C::*)(Args...) volatile from R (Args...) volatile
211 // compile error if signature is not a valid member function signature
212 template <typename, typename>
214 
215 template <typename C, typename R, typename ... Args>
216 struct build_class_function<C, R (Args...)>
217 { using type = R (C::*)(Args...); };
218 
219 template <typename C, typename R, typename ... Args>
220 struct build_class_function<C, R (Args...) const>
221 { using type = R (C::*)(Args...) const; };
222 
223 template <typename C, typename R, typename ... Args>
224 struct build_class_function<C, R (Args...) volatile>
225 { using type = R (C::*)(Args...) volatile; };
226 
227 // determine whether a class C has an operator() with signature S
228 template <typename C, typename S>
230  typedef char (& yes)[1];
231  typedef char (& no)[2];
232 
233  // helper struct to determine that C::operator() does indeed have
234  // the desired signature; &C::operator() is only of type
235  // R (C::*)(Args...) if this is true
236  template <typename T, T> struct check;
237 
238  // T is needed to enable SFINAE
239  template <typename T> static yes deduce(check<
240  typename build_class_function<C, S>::type, &T::operator()> *);
241  // fallback if check helper could not be built
242  template <typename> static no deduce(...);
243 
244  static bool constexpr value = sizeof(deduce<C>(0)) == sizeof(yes);
245 };
246 
247 // determine whether a free function pointer F has signature S
248 template <typename F, typename S>
250  // check whether F and the function pointer of S are of the same
251  // type
252  static bool constexpr value = std::is_same<
254  >::value;
255 };
256 
257 // C is a class, delegate to is_functor_with_signature
258 template <typename C, typename S, bool>
260  : std::integral_constant<
261  bool, is_functor_with_signature<C, S>::value
262  >
263  {};
264 
265 // F is not a class, delegate to is_function_with_signature
266 template <typename F, typename S>
267 struct is_callable_impl<F, S, false>
268  : std::integral_constant<
269  bool, is_function_with_signature<F, S>::value
270  >
271  {};
272 
273 // Determine whether type Callable is callable with signature Signature.
274 // Compliant with functors, i.e. classes that declare operator(); and free
275 // function pointers: R (*)(Args...), but not R (Args...)!
276 template <typename Callable, typename Signature>
279  Callable, Signature,
280  std::is_class<Callable>::value
281  >
282 {};
283 // specil case for function R (Args...)
284 template <typename Signature>
285 struct is_callable<Signature,Signature> : std::true_type {};
286 
287 namespace { // tests
288  struct A { void operator()(); };
289  struct B {};
290  struct C {
291  int operator()(int &, void **) const;
292  int operator()(double);
293  };
294  void a();
295  int b;
296  int c(int &, void **);
297  int c(double);
298 #define _RHEOLEF_IS_CALLABLE_POSITIVE "should be recognized as callable"
299 #define _RHEOLEF_IS_CALLABLE_NEGATIVE "should not be recognized as callable"
300  static_assert(is_callable<A, void ()>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
301  static_assert(!is_callable<B, void ()>::value, _RHEOLEF_IS_CALLABLE_NEGATIVE);
302  static_assert(is_callable<C, int (int &, void **) const>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
303  static_assert(is_callable<C, int (double)>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
304  static_assert(is_callable<decltype(static_cast<int (*)(int &, void **)>(&c)), int (int &, void **)>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
305  static_assert(is_callable<decltype(static_cast<int (*)(double)>(&c)), int (double)>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
306  static_assert(is_callable<int(double),int(double)>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
307 #undef _RHEOLEF_IS_CALLABLE_POSITIVE
308 #undef _RHEOLEF_IS_CALLABLE_NEGATIVE
309 } // tests
310 
311 // ---------------------------------------------------------------------------
312 // is_functor: suppose an only one operator()
313 // ---------------------------------------------------------------------------
314 
315 template <typename, typename> struct get_functor_result_impl {};
316 template <typename C, typename R, typename ... Args>
317 struct get_functor_result_impl<C, R (C::*)(Args...)> {
318  using type = R;
319 };
320 template <typename C, typename R, typename ... Args>
321 struct get_functor_result_impl<C, R (C::*)(Args...) const> {
322  using type = R;
323 };
324 template <typename C, typename R, typename ... Args>
325 struct get_functor_result_impl<C, R (C::*)(Args...) volatile> {
326  using type = R;
327 };
328 template <typename F, typename Sfinae = void> struct get_functor_result {
329  static const bool value = false;
330 };
331 template <typename F> struct get_functor_result <F,
332  typename std::enable_if<
333  std::is_member_function_pointer<decltype(&F::operator())>::value
334  >::type
335 > {
336  using type = typename get_functor_result_impl<F,decltype(&F::operator())>::type;
337  static const bool value = true;
338 };
339 
340 template <typename F, typename Sfinae = void> struct is_functor : std::false_type {};
341 template <typename F> struct is_functor<F,
342  typename std::enable_if<
343  get_functor_result<F>::value
344  >::type
345 > : std::true_type {};
346 #ifdef TO_CLEAN
347 // ---------------------------------------------------------------------------
348 // class F is field_functor or field_true_function ?
349 //
350 // is_field_true_function : F = R (const point_basic<T>&)
351 // is_field_functor : F have R (F::*) (const point_basic<T>&) const
352 // with some T = some float type and R = any result_type
353 // ---------------------------------------------------------------------------
354 // is_field_true_function
355 template<class F> struct is_field_true_function : std::false_type {};
356 template<class R, class T> struct is_field_true_function <R(const point_basic<T>&)> : std::true_type {};
357 template<class R, class T> struct is_field_true_function <R(*)(const point_basic<T>&)> : std::true_type {};
358 
359 // is_field_functor
360 template<class F, class Sfinae = void> struct is_field_functor : std::false_type {};
361 template<class F> struct is_field_functor<F,typename std::enable_if<
362  std::is_class<F>::value
363  && is_functor<F>::value
364  >::type>
365  : std::conditional<
366  // TODO: arg = basic_point<T> with any T
367  is_callable<F,typename get_functor_result<F>::type (const point&) const>::value
368  , std::true_type, std::false_type>::type {};
369 
370 // is_field_function = is_field_true_function || is_field_functor
371 template<class F, class Sfinae = void> struct is_field_function : std::false_type {};
372 template<class F> struct is_field_function<F,
373  typename std::enable_if<
374  is_field_true_function<F>::value
375  || is_field_functor<F>::value
376  >::type
377 > : std::true_type {};
378 
379 template<class F, class Sfinae = void> struct field_function_traits {};
380 template<class F> struct field_function_traits<F,
381  typename std::enable_if<
382  is_field_true_function<F>::value
383  >::type
384 > {
385  typedef typename function_traits<F>::result_type result_type;
386 };
387 template<class F> struct field_function_traits<F,
388  typename std::enable_if<
389  is_field_functor<F>::value
390  >::type
391 > {
392  typedef typename functor_traits<F>::result_type result_type;
393 };
394 #endif // TO_CLEAN
395 
396 }} // namespace rheolef::details
397 #endif // _RHEOLEF_FIELD_EXPR_UTILITIES_H
rheolef::std type
point_basic< T >
Definition: piola_fem.h:135
typename details::generic_binary_traits< BinaryFunction >::template result_hint< typename Expr1::result_type, typename Expr2::result_type >::type result_type
rheolef::std value
Expr1::float_type T
Definition: field_expr.h:230
#define _RHEOLEF_IS_CALLABLE_NEGATIVE
#define _RHEOLEF_IS_CALLABLE_POSITIVE
typename range_builder< MIN, MAX >::type index_range
This file is part of Rheolef.
t operator()(const t &a, const t &b)
Definition: space.cc:386
size_t N
A(size_t d1)
typename std::tuple_element< I, std::tuple< Args... > >::type type
static yes deduce(check< typename build_class_function< C, S >::type, &T::operator()> *)
typename std::tuple_element< I, std::tuple< Args... > >::type type
Expr1::memory_type M
Definition: vec_expr_v2.h:416