field_expr_utilities.h
Go to the documentation of this file.
#ifndef _RHEOLEF_FIELD_EXPR_UTILITIES_H
#define _RHEOLEF_FIELD_EXPR_UTILITIES_H
//
// This file is part of Rheolef.
//
// Copyright (C) 2000-2009 Pierre Saramito
//
// Rheolef is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Rheolef is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Rheolef; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// ==========================================================================
//
// utiities for field expressions
//
// author: Pierre.Saramito@imag.fr
//
// date: 4 september 2015
//
#include "rheolef/promote.h"
#include "rheolef/point.h"
#include "rheolef/space_constant.h"
#include <functional>
#include <type_traits>
namespace rheolef {
// forward declaration:
template <typename T, typename M> class field_basic;
namespace details {
// ---------------------------------------------------------------------------
// type comparator, up to std::decay
// ---------------------------------------------------------------------------
template <typename T1, typename T2>
struct decay_is_same
: std::is_same<
typename std::decay<T1>::type,
typename std::decay<T2>::type
>::type
{};
// ---------------------------------------------------------------------------
// metaprogramming logicals: and, or, not with types
// ---------------------------------------------------------------------------
template<typename...>
struct or_type;
template<>
struct or_type<>
: public std::false_type
{ };
template<typename B1>
struct or_type<B1>
: public B1
{ };
template<typename B1, typename B2>
struct or_type<B1, B2>
: public std::conditional<B1::value, B1, B2>::type
{ };
template<typename B1, typename B2, typename B3, typename... Bn>
struct or_type<B1, B2, B3, Bn...>
: public std::conditional<B1::value, B1, or_type<B2, B3, Bn...>>::type
{ };
template<typename...>
struct and_type;
template<>
struct and_type<>
: public std::true_type
{ };
template<typename B1>
struct and_type<B1>
: public B1
{ };
template<typename B1, typename B2>
struct and_type<B1, B2>
: public std::conditional<B1::value, B2, B1>::type
{ };
template<typename B1, typename B2, typename B3, typename... Bn>
struct and_type<B1, B2, B3, Bn...>
: public std::conditional<B1::value, and_type<B2, B3, Bn...>, B1>::type
{ };
template<typename P>
struct not_type
: public std::integral_constant<bool, !P::value>
{ };
// ------------------------------------------
// tools for creating index lists
// ------------------------------------------
// TODO: C++2014 introduced index_sequence : test configure, etc
// the structure that encapsulates index lists
template <size_t... Is>
struct index_list {};
// Collects internal details for generating index ranges [MIN, MAX)
// declare primary template for index range builder
template <size_t MIN, size_t N, size_t... Is>
struct range_builder;
// base step
template <size_t MIN, size_t... Is>
struct range_builder<MIN, MIN, Is...>
{
typedef index_list<Is...> type;
};
// induction step
template <size_t MIN, size_t N, size_t... Is>
struct range_builder: public range_builder<MIN, N - 1, N - 1, Is...>
{
};
// Meta-function that returns a [MIN, MAX[ index range
template<size_t MIN, size_t MAX>
using index_range = typename range_builder<MIN, MAX>::type;
// ---------------------------------------------------------------------------
// general functor traits
// ---------------------------------------------------------------------------
// https://functionalcpp.wordpress.com/2013/08/05/function-traits/
// functor:
template <typename T>
struct functor_traits : public functor_traits<decltype(&T::operator())> {};
template <typename C, typename R, typename... Args>
struct functor_traits<R(C::*)(Args...) const> { // op() with a const qualifier
using result_type = R;
static const std::size_t arity = sizeof...(Args);
template <std::size_t I>
struct arg {
static_assert(I < arity, "error: invalid parameter index.");
using type = typename std::tuple_element<I, std::tuple<Args...> >::type;
using decay_type = typename std::decay<type>::type;
};
typedef std::tuple<Args...> args_tuple_type;
using function_type = R (Args...);
using function_pointer_type = R (*)(Args...);
using copiable_type = C;
using functor_type = C;
};
// true function:
template<class F>
struct true_function_traits;
template<class R, class... Args>
struct true_function_traits<R(*)(Args...)> : public true_function_traits<R(Args...)> {};
template<class R, class... Args>
struct true_function_traits<R(Args...)> {
using result_type = R;
static constexpr std::size_t arity = sizeof...(Args);
template <std::size_t I>
struct arg {
static_assert(I < arity, "error: invalid parameter index.");
using type = typename std::tuple_element<I,std::tuple<Args...> >::type;
};
typedef std::tuple<Args...> args_tuple_type;
using function_type = R (Args...);
using function_pointer_type = R (*)(Args...);
//using copiable_type = std::function<R(Args...)>; // more levels of indirections
using copiable_type = function_pointer_type; // shorter
using functor_type = std::function<R(Args...)>;
};
// select either true-fonction or functor
template<class F> struct function_traits : functor_traits<F> {};
template <typename R, typename... Args> struct function_traits <R(Args...)> : true_function_traits<R(Args...)> {};
template <typename R, typename... Args> struct function_traits <R(*)(Args...)> : true_function_traits<R(Args...)> {};
// field class is not an ordinary function/functor : for compose(field,args...) filtering
template <typename T, typename M> struct function_traits <field_basic<T,M> > {};
// -----------------------------------------------------------------------
// is_callable<Funct,Signature>::value : for both functions and functors
// -----------------------------------------------------------------------
// http://stackoverflow.com/questions/9083593/is-an-is-functor-c-trait-class-possible
// build R (*)(Args...) from R (Args...)
// compile error if signature is not a valid function signature
template <typename, typename>
struct build_free_function {};
template <typename F, typename R, typename ... Args>
struct build_free_function<F, R (Args...)>
{ using type = R (*)(Args...); };
// build R (C::*)(Args...) from R (Args...)
// R (C::*)(Args...) const from R (Args...) const
// R (C::*)(Args...) volatile from R (Args...) volatile
// compile error if signature is not a valid member function signature
template <typename, typename>
struct build_class_function {};
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...)>
{ using type = R (C::*)(Args...); };
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...) const>
{ using type = R (C::*)(Args...) const; };
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...) volatile>
{ using type = R (C::*)(Args...) volatile; };
// determine whether a class C has an operator() with signature S
template <typename C, typename S>
struct is_functor_with_signature {
typedef char (& yes)[1];
typedef char (& no)[2];
// helper struct to determine that C::operator() does indeed have
// the desired signature; &C::operator() is only of type
// R (C::*)(Args...) if this is true
template <typename T, T> struct check;
// T is needed to enable SFINAE
template <typename T> static yes deduce(check<
typename build_class_function<C, S>::type, &T::operator()> *);
// fallback if check helper could not be built
template <typename> static no deduce(...);
static bool constexpr value = sizeof(deduce<C>(0)) == sizeof(yes);
};
// determine whether a free function pointer F has signature S
template <typename F, typename S>
struct is_function_with_signature {
// check whether F and the function pointer of S are of the same
// type
static bool constexpr value = std::is_same<
F, typename build_free_function<F, S>::type
>::value;
};
// C is a class, delegate to is_functor_with_signature
template <typename C, typename S, bool>
struct is_callable_impl
: std::integral_constant<
bool, is_functor_with_signature<C, S>::value
>
{};
// F is not a class, delegate to is_function_with_signature
template <typename F, typename S>
struct is_callable_impl<F, S, false>
: std::integral_constant<
bool, is_function_with_signature<F, S>::value
>
{};
// Determine whether type Callable is callable with signature Signature.
// Compliant with functors, i.e. classes that declare operator(); and free
// function pointers: R (*)(Args...), but not R (Args...)!
template <typename Callable, typename Signature>
struct is_callable
: is_callable_impl<
Callable, Signature,
std::is_class<Callable>::value
>
{};
// specil case for function R (Args...)
template <typename Signature>
struct is_callable<Signature,Signature> : std::true_type {};
namespace { // tests
struct A { void operator()(); };
struct B {};
struct C {
int operator()(int &, void **) const;
int operator()(double);
};
void a();
int b;
int c(int &, void **);
int c(double);
#define _RHEOLEF_IS_CALLABLE_POSITIVE "should be recognized as callable"
#define _RHEOLEF_IS_CALLABLE_NEGATIVE "should not be recognized as callable"
static_assert(is_callable<A, void ()>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
static_assert(!is_callable<B, void ()>::value, _RHEOLEF_IS_CALLABLE_NEGATIVE);
static_assert(is_callable<C, int (int &, void **) const>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
static_assert(is_callable<C, int (double)>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
static_assert(is_callable<decltype(static_cast<int (*)(int &, void **)>(&c)), int (int &, void **)>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
static_assert(is_callable<decltype(static_cast<int (*)(double)>(&c)), int (double)>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
static_assert(is_callable<int(double),int(double)>::value, _RHEOLEF_IS_CALLABLE_POSITIVE);
#undef _RHEOLEF_IS_CALLABLE_POSITIVE
#undef _RHEOLEF_IS_CALLABLE_NEGATIVE
} // tests
// ---------------------------------------------------------------------------
// is_functor: suppose an only one operator()
// ---------------------------------------------------------------------------
template <typename, typename> struct get_functor_result_impl {};
template <typename C, typename R, typename ... Args>
struct get_functor_result_impl<C, R (C::*)(Args...)> {
using type = R;
};
template <typename C, typename R, typename ... Args>
struct get_functor_result_impl<C, R (C::*)(Args...) const> {
using type = R;
};
template <typename C, typename R, typename ... Args>
struct get_functor_result_impl<C, R (C::*)(Args...) volatile> {
using type = R;
};
template <typename F, typename Sfinae = void> struct get_functor_result {
static const bool value = false;
};
template <typename F> struct get_functor_result <F,
typename std::enable_if<
std::is_member_function_pointer<decltype(&F::operator())>::value
>::type
> {
using type = typename get_functor_result_impl<F,decltype(&F::operator())>::type;
static const bool value = true;
};
template <typename F, typename Sfinae = void> struct is_functor : std::false_type {};
template <typename F> struct is_functor<F,
typename std::enable_if<
get_functor_result<F>::value
>::type
> : std::true_type {};
// ---------------------------------------------------------------------------
// class F is field_functor or field_true_function ?
//
// is_field_true_function : F = R (const point_basic<T>&)
// is_field_functor : F have R (F::*) (const point_basic<T>&) const
// with some T = some float type and R = any result_type
// ---------------------------------------------------------------------------
// is_field_true_function
template<class F> struct is_field_true_function : std::false_type {};
template<class R, class T> struct is_field_true_function <R(const point_basic<T>&)> : std::true_type {};
template<class R, class T> struct is_field_true_function <R(*)(const point_basic<T>&)> : std::true_type {};
// is_field_functor
template<class F, class Sfinae = void> struct is_field_functor : std::false_type {};
template<class F> struct is_field_functor<F,typename std::enable_if<
std::is_class<F>::value
&& is_functor<F>::value
>::type>
: std::conditional<
// TODO: arg = basic_point<T> with any T
is_callable<F,typename get_functor_result<F>::type (const point&) const>::value
, std::true_type, std::false_type>::type {};
// is_field_function = is_field_true_function || is_field_functor
template<class F, class Sfinae = void> struct is_field_function : std::false_type {};
template<class F> struct is_field_function<F,
typename std::enable_if<
is_field_true_function<F>::value
|| is_field_functor<F>::value
>::type
> : std::true_type {};
template<class F, class Sfinae = void> struct field_function_traits {};
#ifdef TO_CLEAN
template<class R, class T> struct field_function_traits <R(*)(const point_basic<T>&)> :
field_function_traits <R(const point_basic<T>&)> {};
#endif // TO_CLEAN
template<class F> struct field_function_traits<F,
typename std::enable_if<
is_field_true_function<F>::value
>::type
> {
typedef typename function_traits<F>::result_type result_type;
};
template<class F> struct field_function_traits<F,
typename std::enable_if<
is_field_functor<F>::value
>::type
> {
typedef typename functor_traits<F>::result_type result_type;
};
}} // namespace rheolef::details
#endif // _RHEOLEF_FIELD_EXPR_UTILITIES_H
rheolef::field_basic
Definition: field.h:235
rheolef::point_basic
Definition: point.h:87
rheolef::std
Definition: vec_expr_v2.h:402
rheolef::type
rheolef::std type
rheolef::value
rheolef::std value
T
Expr1::float_type T
Definition: field_expr.h:261
_RHEOLEF_IS_CALLABLE_NEGATIVE
#define _RHEOLEF_IS_CALLABLE_NEGATIVE
Definition: field_expr_utilities.h:299
_RHEOLEF_IS_CALLABLE_POSITIVE
#define _RHEOLEF_IS_CALLABLE_POSITIVE
Definition: field_expr_utilities.h:298
mkgeo_ball.b
int b
Definition: mkgeo_ball.sh:152
mkgeo_ball.c
int c
Definition: mkgeo_ball.sh:153
mkgeo_ball.a
int a
Definition: mkgeo_ball.sh:151
rheolef::details::index_range
typename range_builder< MIN, MAX >::type index_range
Definition: field_expr_utilities.h:137
rheolef
This file is part of Rheolef.
Definition: compiler_eigen.h:37
N
size_t N
Definition: neumann-laplace-check.cc:24
rheolef::details::and_type< B1, B2 >
Definition: field_expr_utilities.h:96
rheolef::details::and_type< B1 >
Definition: field_expr_utilities.h:91
rheolef::details::and_type<>
Definition: field_expr_utilities.h:86
rheolef::details::and_type
Definition: field_expr_utilities.h:81
rheolef::details::build_class_function< C, R(Args...) const >::type
R(C::*)(Args...) const type
Definition: field_expr_utilities.h:221
rheolef::details::build_class_function< C, R(Args...) volatile >::type
R(C::*)(Args...) volatile type
Definition: field_expr_utilities.h:225
rheolef::details::build_class_function< C, R(Args...)>::type
R(C::*)(Args...) type
Definition: field_expr_utilities.h:217
rheolef::details::build_class_function
Definition: field_expr_utilities.h:213
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
rheolef::details::decay_is_same
Definition: field_expr_utilities.h:51
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::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::field_function_traits
Definition: field_expr_utilities.h:378
rheolef::details::function_traits
Definition: field_expr_utilities.h:188
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::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::functor_traits< R(C::*)(Args...) const >::function_type
R(Args...) function_type
Definition: field_expr_utilities.h:159
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::functor_traits< R(C::*)(Args...) const >::function_pointer_type
R(*)(Args...) function_pointer_type
Definition: field_expr_utilities.h:160
rheolef::details::functor_traits< R(C::*)(Args...) const >::copiable_type
C copiable_type
Definition: field_expr_utilities.h:161
rheolef::details::functor_traits< R(C::*)(Args...) const >::functor_type
C functor_type
Definition: field_expr_utilities.h:162
rheolef::details::functor_traits< R(C::*)(Args...) const >::result_type
R result_type
Definition: field_expr_utilities.h:150
rheolef::details::functor_traits
Definition: field_expr_utilities.h:146
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::get_functor_result_impl< C, R(C::*)(Args...) const >::type
R type
Definition: field_expr_utilities.h:322
rheolef::details::get_functor_result_impl< C, R(C::*)(Args...) volatile >::type
R type
Definition: field_expr_utilities.h:326
rheolef::details::get_functor_result_impl< C, R(C::*)(Args...)>::type
R type
Definition: field_expr_utilities.h:318
rheolef::details::get_functor_result_impl
Definition: field_expr_utilities.h:315
rheolef::details::get_functor_result
Definition: field_expr_utilities.h:328
rheolef::details::get_functor_result::value
static const bool value
Definition: field_expr_utilities.h:329
rheolef::details::index_list
Definition: field_expr_utilities.h:115
rheolef::details::is_callable_impl
Definition: field_expr_utilities.h:263
rheolef::details::is_callable
Definition: field_expr_utilities.h:282
rheolef::details::is_field_function
Definition: field_expr_utilities.h:370
rheolef::details::is_field_functor
Definition: field_expr_utilities.h:359
rheolef::details::is_field_true_function
Definition: field_expr_utilities.h:354
rheolef::details::is_function_with_signature
Definition: field_expr_utilities.h:249
rheolef::details::is_function_with_signature::value
static constexpr bool value
Definition: field_expr_utilities.h:252
rheolef::details::is_functor_with_signature::check
Definition: field_expr_utilities.h:236
rheolef::details::is_functor_with_signature
Definition: field_expr_utilities.h:229
rheolef::details::is_functor_with_signature::deduce
static no deduce(...)
rheolef::details::is_functor_with_signature::yes
char(& yes)[1]
Definition: field_expr_utilities.h:230
rheolef::details::is_functor_with_signature::value
static constexpr bool value
Definition: field_expr_utilities.h:244
rheolef::details::is_functor_with_signature::no
char(& no)[2]
Definition: field_expr_utilities.h:231
rheolef::details::is_functor_with_signature::deduce
static yes deduce(check< typename build_class_function< C, S >::type, &T::operator()> *)
rheolef::details::is_functor
Definition: field_expr_utilities.h:340
rheolef::details::not_type
Definition: field_expr_utilities.h:106
rheolef::details::or_type< B1, B2 >
Definition: field_expr_utilities.h:73
rheolef::details::or_type< B1 >
Definition: field_expr_utilities.h:68
rheolef::details::or_type<>
Definition: field_expr_utilities.h:63
rheolef::details::or_type
Definition: field_expr_utilities.h:58
rheolef::details::range_builder< MIN, MIN, Is... >::type
index_list< Is... > type
Definition: field_expr_utilities.h:126
rheolef::details::range_builder
Definition: field_expr_utilities.h:132
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::true_function_traits< R(Args...)>::function_type
R(Args...) function_type
Definition: field_expr_utilities.h:181
rheolef::details::true_function_traits< R(Args...)>::args_tuple_type
std::tuple< Args... > args_tuple_type
Definition: field_expr_utilities.h:180
rheolef::details::true_function_traits< R(Args...)>::function_pointer_type
R(*)(Args...) function_pointer_type
Definition: field_expr_utilities.h:182
rheolef::details::true_function_traits< R(Args...)>::copiable_type
function_pointer_type copiable_type
Definition: field_expr_utilities.h:184
rheolef::details::true_function_traits< R(Args...)>::functor_type
std::function< R(Args...)> functor_type
Definition: field_expr_utilities.h:185
rheolef::details::true_function_traits< R(Args...)>::result_type
R result_type
Definition: field_expr_utilities.h:173
rheolef::details::true_function_traits
Definition: field_expr_utilities.h:166
M
Expr1::memory_type M
Definition: vec_expr_v2.h:416