Rheolef  7.2
an efficient C++ finite element environment
 
Loading...
Searching...
No Matches
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
35namespace rheolef { namespace details {
36
37// ---------------------------------------------------------------------------
38// type comparator, up to std::decay
39// ---------------------------------------------------------------------------
40template <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
53template<typename...>
54 struct or_type;
55
56template<>
57 struct or_type<>
58 : public std::false_type
59 { };
60
61template<typename B1>
63 : public B1
64 { };
65
66template<typename B1, typename B2>
68 : public std::conditional<B1::value, B1, B2>::type
69 { };
70
71template<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
76template<typename...>
77 struct and_type;
78
79template<>
81 : public std::true_type
82 { };
83
84template<typename B1>
86 : public B1
87 { };
88
89template<typename B1, typename B2>
91 : public std::conditional<B1::value, B2, B1>::type
92 { };
93
94template<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
99template<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
110template <size_t... Is>
111struct 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
132template<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:
141template <typename T>
142struct functor_traits : public functor_traits<decltype(&T::operator())> {};
143
144template <typename C, typename R, typename... Args>
145struct 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:
161template<class F>
163
164template<class R, class... Args>
165struct true_function_traits<R(*)(Args...)> : public true_function_traits<R(Args...)> {};
166
167template<class R, class... Args>
168struct 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
184template<class F> struct function_traits : functor_traits<F> {};
185template <typename R, typename... Args> struct function_traits <R(Args...)> : true_function_traits<R(Args...)> {};
186template <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
191template <typename T, typename M> class field_basic; // forward declaration
192template <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
201template <typename, typename>
203
204template <typename F, typename R, typename ... Args>
205struct 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
212template <typename, typename>
214
215template <typename C, typename R, typename ... Args>
216struct build_class_function<C, R (Args...)>
217{ using type = R (C::*)(Args...); };
218
219template <typename C, typename R, typename ... Args>
220struct build_class_function<C, R (Args...) const>
221{ using type = R (C::*)(Args...) const; };
222
223template <typename C, typename R, typename ... Args>
224struct 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
228template <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
248template <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
258template <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
266template <typename F, typename S>
267struct 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...)!
276template <typename Callable, typename Signature>
279 Callable, Signature,
280 std::is_class<Callable>::value
281 >
282{};
283// specil case for function R (Args...)
284template <typename Signature>
285struct is_callable<Signature,Signature> : std::true_type {};
286
287namespace { // 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
315template <typename, typename> struct get_functor_result_impl {};
316template <typename C, typename R, typename ... Args>
317struct get_functor_result_impl<C, R (C::*)(Args...)> {
318 using type = R;
319};
320template <typename C, typename R, typename ... Args>
321struct get_functor_result_impl<C, R (C::*)(Args...) const> {
322 using type = R;
323};
324template <typename C, typename R, typename ... Args>
325struct get_functor_result_impl<C, R (C::*)(Args...) volatile> {
326 using type = R;
327};
328template <typename F, typename Sfinae = void> struct get_functor_result {
329 static const bool value = false;
330};
331template <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
340template <typename F, typename Sfinae = void> struct is_functor : std::false_type {};
341template <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
355template<class F> struct is_field_true_function : std::false_type {};
356template<class R, class T> struct is_field_true_function <R(const point_basic<T>&)> : std::true_type {};
357template<class R, class T> struct is_field_true_function <R(*)(const point_basic<T>&)> : std::true_type {};
358
359// is_field_functor
360template<class F, class Sfinae = void> struct is_field_functor : std::false_type {};
361template<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
371template<class F, class Sfinae = void> struct is_field_function : std::false_type {};
372template<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
379template<class F, class Sfinae = void> struct field_function_traits {};
380template<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};
387template<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
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
STL namespace.
size_t N
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