Rheolef  7.1
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 "rheolef/space_constant.h"
33 #include <functional>
34 #include <type_traits>
35 
36 namespace rheolef {
37 // forward declaration:
38 template <typename T, typename M> class field_basic;
39 
40 namespace details {
41 
42 // ---------------------------------------------------------------------------
43 // type comparator, up to std::decay
44 // ---------------------------------------------------------------------------
45 template <typename T1, typename T2>
47  : std::is_same<
48  typename std::decay<T1>::type,
49  typename std::decay<T2>::type
50  >::type
51 {};
52 
53 // ---------------------------------------------------------------------------
54 // metaprogramming logicals: and, or, not with types
55 // ---------------------------------------------------------------------------
56 
57 template<typename...>
58  struct or_type;
59 
60 template<>
61  struct or_type<>
62  : public std::false_type
63  { };
64 
65 template<typename B1>
66  struct or_type<B1>
67  : public B1
68  { };
69 
70 template<typename B1, typename B2>
72  : public std::conditional<B1::value, B1, B2>::type
73  { };
74 
75 template<typename B1, typename B2, typename B3, typename... Bn>
76  struct or_type<B1, B2, B3, Bn...>
77  : public std::conditional<B1::value, B1, or_type<B2, B3, Bn...>>::type
78  { };
79 
80 template<typename...>
81  struct and_type;
82 
83 template<>
84  struct and_type<>
85  : public std::true_type
86  { };
87 
88 template<typename B1>
89  struct and_type<B1>
90  : public B1
91  { };
92 
93 template<typename B1, typename B2>
95  : public std::conditional<B1::value, B2, B1>::type
96  { };
97 
98 template<typename B1, typename B2, typename B3, typename... Bn>
99  struct and_type<B1, B2, B3, Bn...>
100  : public std::conditional<B1::value, and_type<B2, B3, Bn...>, B1>::type
101  { };
102 
103 template<typename P>
104  struct not_type
105  : public std::integral_constant<bool, !P::value>
106  { };
107 
108 // ------------------------------------------
109 // tools for creating index lists
110 // ------------------------------------------
111 // TODO: C++2014 introduced index_sequence : test configure, etc
112 
113 // the structure that encapsulates index lists
114 template <size_t... Is>
115 struct index_list {};
116 
117 // Collects internal details for generating index ranges [MIN, MAX)
118  // declare primary template for index range builder
119  template <size_t MIN, size_t N, size_t... Is>
121 
122  // base step
123  template <size_t MIN, size_t... Is>
124  struct range_builder<MIN, MIN, Is...>
125  {
126  typedef index_list<Is...> type;
127  };
128 
129  // induction step
130  template <size_t MIN, size_t N, size_t... Is>
131  struct range_builder: public range_builder<MIN, N - 1, N - 1, Is...>
132  {
133  };
134 
135 // Meta-function that returns a [MIN, MAX[ index range
136 template<size_t MIN, size_t MAX>
138 
139 // ---------------------------------------------------------------------------
140 // general functor traits
141 // ---------------------------------------------------------------------------
142 // https://functionalcpp.wordpress.com/2013/08/05/function-traits/
143 
144 // functor:
145 template <typename T>
146 struct functor_traits : public functor_traits<decltype(&T::operator())> {};
147 
148 template <typename C, typename R, typename... Args>
149 struct functor_traits<R(C::*)(Args...) const> { // op() with a const qualifier
150  using result_type = R;
151  static const std::size_t arity = sizeof...(Args);
152  template <std::size_t I>
153  struct arg {
154  static_assert(I < arity, "error: invalid parameter index.");
155  using type = typename std::tuple_element<I, std::tuple<Args...> >::type;
156  using decay_type = typename std::decay<type>::type;
157  };
158  typedef std::tuple<Args...> args_tuple_type;
159  using function_type = R (Args...);
160  using function_pointer_type = R (*)(Args...);
161  using copiable_type = C;
162  using functor_type = C;
163 };
164 // true function:
165 template<class F>
167 
168 template<class R, class... Args>
169 struct true_function_traits<R(*)(Args...)> : public true_function_traits<R(Args...)> {};
170 
171 template<class R, class... Args>
172 struct true_function_traits<R(Args...)> {
173  using result_type = R;
174  static constexpr std::size_t arity = sizeof...(Args);
175  template <std::size_t I>
176  struct arg {
177  static_assert(I < arity, "error: invalid parameter index.");
178  using type = typename std::tuple_element<I,std::tuple<Args...> >::type;
179  };
180  typedef std::tuple<Args...> args_tuple_type;
181  using function_type = R (Args...);
182  using function_pointer_type = R (*)(Args...);
183  //using copiable_type = std::function<R(Args...)>; // more levels of indirections
185  using functor_type = std::function<R(Args...)>;
186 };
187 // select either true-fonction or functor
188 template<class F> struct function_traits : functor_traits<F> {};
189 template <typename R, typename... Args> struct function_traits <R(Args...)> : true_function_traits<R(Args...)> {};
190 template <typename R, typename... Args> struct function_traits <R(*)(Args...)> : true_function_traits<R(Args...)> {};
191 
192 // field class is not an ordinary function/functor : for compose(field,args...) filtering
193 template <typename T, typename M> struct function_traits <field_basic<T,M> > {};
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 // ---------------------------------------------------------------------------
347 // class F is field_functor or field_true_function ?
348 //
349 // is_field_true_function : F = R (const point_basic<T>&)
350 // is_field_functor : F have R (F::*) (const point_basic<T>&) const
351 // with some T = some float type and R = any result_type
352 // ---------------------------------------------------------------------------
353 // is_field_true_function
354 template<class F> struct is_field_true_function : std::false_type {};
355 template<class R, class T> struct is_field_true_function <R(const point_basic<T>&)> : std::true_type {};
356 template<class R, class T> struct is_field_true_function <R(*)(const point_basic<T>&)> : std::true_type {};
357 
358 // is_field_functor
359 template<class F, class Sfinae = void> struct is_field_functor : std::false_type {};
360 template<class F> struct is_field_functor<F,typename std::enable_if<
361  std::is_class<F>::value
362  && is_functor<F>::value
363  >::type>
364  : std::conditional<
365  // TODO: arg = basic_point<T> with any T
366  is_callable<F,typename get_functor_result<F>::type (const point&) const>::value
367  , std::true_type, std::false_type>::type {};
368 
369 // is_field_function = is_field_true_function || is_field_functor
370 template<class F, class Sfinae = void> struct is_field_function : std::false_type {};
371 template<class F> struct is_field_function<F,
372  typename std::enable_if<
373  is_field_true_function<F>::value
374  || is_field_functor<F>::value
375  >::type
376 > : std::true_type {};
377 
378 template<class F, class Sfinae = void> struct field_function_traits {};
379 #ifdef TO_CLEAN
380 template<class R, class T> struct field_function_traits <R(*)(const point_basic<T>&)> :
381  field_function_traits <R(const point_basic<T>&)> {};
382 #endif // TO_CLEAN
383 template<class F> struct field_function_traits<F,
384  typename std::enable_if<
385  is_field_true_function<F>::value
386  >::type
387 > {
389 };
390 template<class F> struct field_function_traits<F,
391  typename std::enable_if<
392  is_field_functor<F>::value
393  >::type
394 > {
396 };
397 
398 }} // namespace rheolef::details
399 #endif // _RHEOLEF_FIELD_EXPR_UTILITIES_H
rheolef::details::functor_traits< R(C::*)(Args...) const >::args_tuple_type
std::tuple< Args... > args_tuple_type
Definition: field_expr_utilities.h:158
rheolef::details::build_class_function
Definition: field_expr_utilities.h:213
rheolef::details::true_function_traits< R(Args...)>::args_tuple_type
std::tuple< Args... > args_tuple_type
Definition: field_expr_utilities.h:180
rheolef::point_basic
Definition: point.h:87
rheolef::details::or_type
Definition: field_expr_utilities.h:58
rheolef::details::is_functor
Definition: field_expr_utilities.h:340
rheolef::details::is_functor_with_signature::no
char(& no)[2]
Definition: field_expr_utilities.h:231
rheolef::details::and_type<>
Definition: field_expr_utilities.h:84
rheolef::details::build_free_function< F, R(Args...)>::type
R(*)(Args...) type
Definition: field_expr_utilities.h:206
rheolef::details::build_free_function
Definition: field_expr_utilities.h:202
N
size_t N
Definition: neumann-laplace-check.cc:24
rheolef::details::is_field_true_function
Definition: field_expr_utilities.h:354
rheolef::details::is_field_functor
Definition: field_expr_utilities.h:359
rheolef::details::functor_traits< R(C::*)(Args...) const >::arg::decay_type
typename std::decay< type >::type decay_type
Definition: field_expr_utilities.h:156
rheolef::details::get_functor_result_impl< C, R(C::*)(Args...) const >::type
R type
Definition: field_expr_utilities.h:322
rheolef::value
rheolef::std value
rheolef::details::is_functor_with_signature
Definition: field_expr_utilities.h:229
mkgeo_ball.c
c
Definition: mkgeo_ball.sh:153
rheolef::type
rheolef::std type
rheolef::details::or_type< B1, B2 >
Definition: field_expr_utilities.h:71
rheolef::details::true_function_traits< R(Args...)>::result_type
R result_type
Definition: field_expr_utilities.h:173
rheolef::details::functor_traits< R(C::*)(Args...) const >::arg::type
typename std::tuple_element< I, std::tuple< Args... > >::type type
Definition: field_expr_utilities.h:155
rheolef::details::is_functor_with_signature::check
Definition: field_expr_utilities.h:236
rheolef::details::functor_traits< R(C::*)(Args...) const >::function_pointer_type
R(*)(Args...) function_pointer_type
Definition: field_expr_utilities.h:160
rheolef::details::field_function_traits< F, typename std::enable_if< is_field_true_function< F >::value >::type >::result_type
function_traits< F >::result_type result_type
Definition: field_expr_utilities.h:388
rheolef::details::true_function_traits< R(Args...)>::function_pointer_type
R(*)(Args...) function_pointer_type
Definition: field_expr_utilities.h:182
rheolef::details::get_functor_result_impl< C, R(C::*)(Args...) volatile >::type
R type
Definition: field_expr_utilities.h:326
rheolef::details::is_function_with_signature
Definition: field_expr_utilities.h:249
rheolef::details::functor_traits< R(C::*)(Args...) const >::result_type
R result_type
Definition: field_expr_utilities.h:150
rheolef::details::build_class_function< C, R(Args...) const >::type
R(C::*)(Args...) const type
Definition: field_expr_utilities.h:221
rheolef::details::and_type
Definition: field_expr_utilities.h:81
rheolef::details::index_range
typename range_builder< MIN, MAX >::type index_range
Definition: field_expr_utilities.h:137
rheolef::details::and_type< B1, B2 >
Definition: field_expr_utilities.h:94
rheolef::details::build_class_function< C, R(Args...) volatile >::type
R(C::*)(Args...) volatile type
Definition: field_expr_utilities.h:225
rheolef::details::function_traits
Definition: field_expr_utilities.h:188
rheolef::details::true_function_traits< R(Args...)>::function_type
R(Args...) function_type
Definition: field_expr_utilities.h:181
rheolef::details::or_type< B1 >
Definition: field_expr_utilities.h:66
rheolef::details::get_functor_result::value
static const bool value
Definition: field_expr_utilities.h:329
rheolef::details::is_functor_with_signature::yes
char(& yes)[1]
Definition: field_expr_utilities.h:230
_RHEOLEF_IS_CALLABLE_NEGATIVE
#define _RHEOLEF_IS_CALLABLE_NEGATIVE
Definition: field_expr_utilities.h:299
rheolef::field_basic
Definition: field_expr_utilities.h:38
rheolef::details::or_type<>
Definition: field_expr_utilities.h:61
rheolef::details::field_function_traits< F, typename std::enable_if< is_field_functor< F >::value >::type >::result_type
functor_traits< F >::result_type result_type
Definition: field_expr_utilities.h:395
rheolef::details::is_callable_impl
Definition: field_expr_utilities.h:259
rheolef
This file is part of Rheolef.
Definition: compiler_eigen.h:37
rheolef::details::is_field_function
Definition: field_expr_utilities.h:370
rheolef::details::get_functor_result< F, typename std::enable_if< std::is_member_function_pointer< decltype(&F::operator())>::value >::type >::type
typename get_functor_result_impl< F, decltype(&F::operator())>::type type
Definition: field_expr_utilities.h:336
rheolef::details::range_builder< MIN, MIN, Is... >::type
index_list< Is... > type
Definition: field_expr_utilities.h:126
rheolef::details::functor_traits< R(C::*)(Args...) const >::copiable_type
C copiable_type
Definition: field_expr_utilities.h:161
rheolef::details::field_function_traits
Definition: field_expr_utilities.h:378
rheolef::details::true_function_traits< R(Args...)>::copiable_type
function_pointer_type copiable_type
Definition: field_expr_utilities.h:184
rheolef::details::and_type< B1 >
Definition: field_expr_utilities.h:89
rheolef::details::true_function_traits< R(Args...)>::functor_type
std::function< R(Args...)> functor_type
Definition: field_expr_utilities.h:185
mkgeo_ball.b
b
Definition: mkgeo_ball.sh:152
mkgeo_ball.a
a
Definition: mkgeo_ball.sh:151
rheolef::details::is_functor_with_signature::value
static constexpr bool value
Definition: field_expr_utilities.h:244
rheolef::details::is_functor_with_signature::deduce
static yes deduce(check< typename build_class_function< C, S >::type, &T::operator()> *)
rheolef::details::get_functor_result_impl< C, R(C::*)(Args...)>::type
R type
Definition: field_expr_utilities.h:318
rheolef::details::not_type
Definition: field_expr_utilities.h:104
rheolef::details::index_list
Definition: field_expr_utilities.h:115
rheolef::details::is_callable
Definition: field_expr_utilities.h:277
rheolef::details::true_function_traits< R(Args...)>::arg::type
typename std::tuple_element< I, std::tuple< Args... > >::type type
Definition: field_expr_utilities.h:178
rheolef::details::functor_traits< R(C::*)(Args...) const >::function_type
R(Args...) function_type
Definition: field_expr_utilities.h:159
rheolef::details::is_function_with_signature::value
static constexpr bool value
Definition: field_expr_utilities.h:252
rheolef::details::functor_traits< R(C::*)(Args...) const >::functor_type
C functor_type
Definition: field_expr_utilities.h:162
_RHEOLEF_IS_CALLABLE_POSITIVE
#define _RHEOLEF_IS_CALLABLE_POSITIVE
Definition: field_expr_utilities.h:298
rheolef::std
Definition: vec_expr_v2.h:391
rheolef::details::get_functor_result_impl
Definition: field_expr_utilities.h:315
rheolef::details::functor_traits
Definition: field_expr_utilities.h:146
rheolef::details::true_function_traits
Definition: field_expr_utilities.h:166
M
Expr1::memory_type M
Definition: vec_expr_v2.h:385
rheolef::details::range_builder
Definition: field_expr_utilities.h:120
rheolef::details::get_functor_result
Definition: field_expr_utilities.h:328
T
Expr1::float_type T
Definition: field_expr.h:218
rheolef::details::decay_is_same
Definition: field_expr_utilities.h:46
rheolef::details::build_class_function< C, R(Args...)>::type
R(C::*)(Args...) type
Definition: field_expr_utilities.h:217