dune-pdelab  2.5-dev
backend/interface.hh
Go to the documentation of this file.
1 #ifndef DUNE_PDELAB_BACKEND_INTERFACE_HH
2 #define DUNE_PDELAB_BACKEND_INTERFACE_HH
3 
4 #include <type_traits>
5 #include <utility>
6 
7 namespace Dune {
8  namespace PDELab {
9  namespace Backend {
10 
11 #ifndef DOXYGEN
12 
13  namespace impl {
14 
15  // This class needs to be specialized by each backend and return the correct
16  // vector wrapper type via the nested type named "type"
17  template<typename Backend, typename GridFunctionSpace, typename FieldType>
18  struct BackendVectorSelectorHelper
19  {};
20 
21  template<typename GridFunctionSpace, typename FieldType>
22  struct BackendVectorSelector
23  {
24  typedef typename GridFunctionSpace::Traits::Backend Backend;
25  typedef typename BackendVectorSelectorHelper<Backend, GridFunctionSpace, FieldType>::Type Type;
26  };
27 
28  template<typename Backend, typename VU, typename VV, typename E>
29  struct BackendMatrixSelector
30  {
31  typedef typename Backend::template MatrixHelper<VV,VU,E>::type Type;
32  };
33 
34  // marker mixin type used by the generic implementation below to decide whether a type
35  // is a PDELab wrapper around a native object - for internal use only!
36  struct WrapperBase
37  {};
38 
39  // mixin class for PDELab wrappers around vectors and matrices.
40  // All backend wrappers should inherit from this class and set the
41  // template parameter to the type of the native container of the backend that they are
42  // wrapping.
43  // Moreover, they have to provide methods
44  //
45  // NativeContainer& native()
46  // const NativeContainer& native() const
47  //
48  // that provide access to the wrapped data structure. These two methods should be private;
49  // in that case, the Wrapper<NativeContainer> mixin must be a friend of the wrapper implementation
50  // so that it can access the native() methods.
51  template<typename NativeContainer>
52  struct Wrapper
53  : public WrapperBase
54  {
55 
56  using native_type = NativeContainer;
57 
58  template<typename U>
59  static auto access_native(U&& u) -> decltype(u.native())
60  {
61  // make sure the wrapper actually returns the right type of object
62  static_assert(
63  std::is_same<
64  typename std::decay<
65  decltype(u.native())
66  >::type,
67  NativeContainer
68  >::value,
69  "u.native() must return a cv-qualified xvalue of type T"
70  );
71 
72  return u.native();
73  }
74 
75  };
76 
77  } // namespace impl
78 
79  } // namespace Backend
80 
81 
82  namespace Backend{
83 
84 #endif // DOXYGEN
85 
86 
105  template<typename GridFunctionSpace, typename FieldType>
106  using Vector = typename impl::BackendVectorSelector<GridFunctionSpace, FieldType>::Type;
107 
126  template<typename Backend, typename VU, typename VV, typename E>
127  using Matrix = typename impl::BackendMatrixSelector<Backend, VU, VV, E>::Type;
128 
129 
130  namespace {
131 
132  // helper TMP to deduce the native type of a wrapper. It works by checking whether
133  // T inherits from WrapperBase. In that case, it returns the nested typedef native_type,
134  // otherwise T is returned unchanged.
135  template<typename T>
136  struct native_type
137  {
138 
139  // We need to defer the (possible) extraction of the nested type until we are sure
140  // that the nested type actually exists. That'w what these lazy_... structs are for:
141  // a std::conditional picks the correct version, and the actual evaluation only happens
142  // after the evaluation of the std::conditional.
143 
144  struct lazy_identity
145  {
146  template<typename U>
147  struct evaluate
148  {
149  using type = U;
150  };
151 
152  };
153 
154  struct lazy_native_type
155  {
156 
157  template<typename U>
158  struct evaluate
159  {
160  using type = typename U::native_type;
161  };
162 
163  };
164 
165  using type = typename std::conditional<
167  lazy_native_type,
168  lazy_identity
169  >::type::template evaluate<T>::type;
170  };
171 
172  }
173 
175  template<typename T>
176  using Native = typename native_type<T>::type;
177 
178 #ifdef DOXYEN
179 
181  template<typename T>
182  Native<T> native(T&& t);
183 
184 #else // DOXYGEN
185 
186  // version for mutable reference to wrapper
187  template<typename T>
188  typename std::enable_if<
190  Native<T>&
191  >::type
192  native(T& t)
193  {
194  return impl::Wrapper<Native<T>>::access_native(t);
195  }
196 
197  // version for const reference to wrapper
198  template<typename T>
199  typename std::enable_if<
200  std::is_base_of<impl::WrapperBase,T>::value,
201  const Native<T>&
202  >::type
203  native(const T& t)
204  {
205  return impl::Wrapper<Native<T>>::access_native(t);
206  }
207 
208  // version for non-wrapper class. Important: Don't drop the std::decay<>!
209  template<typename T>
210  typename std::enable_if<
211  !std::is_base_of<impl::WrapperBase,typename std::decay<T>::type>::value,
212  decltype(std::forward<T>(std::declval<T&&>()))
213  >::type
214  native(T&& t)
215  {
216  return std::forward<T>(t);
217  }
218 
219 #endif // DOXYGEN
220 
221  } // namespace Backend
222  } // namespace PDELab
223 } // namespace Dune
224 
225 #endif // DUNE_PDELAB_BACKEND_INTERFACE_HH
typename impl::BackendMatrixSelector< Backend, VU, VV, E >::Type Matrix
alias of the return type of BackendMatrixSelector
Definition: backend/interface.hh:127
std::enable_if< std::is_base_of< impl::WrapperBase, T >::value, Native< T > &>::type native(T &t)
Definition: backend/interface.hh:192
typename native_type< T >::type Native
Alias of the native container type associated with T or T itself if it is not a backend wrapper...
Definition: backend/interface.hh:176
typename impl::BackendVectorSelector< GridFunctionSpace, FieldType >::Type Vector
alias of the return type of BackendVectorSelector
Definition: backend/interface.hh:106
For backward compatibility – Do not use this!
Definition: adaptivity.hh:27
B Backend
Definition: gridfunctionspace.hh:127
static const unsigned int value
Definition: gridfunctionspace/tags.hh:139