dune-common  2.5.0
hybridutilities.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 #ifndef DUNE_COMMON_HYBRIDUTILITIES_HH
4 #define DUNE_COMMON_HYBRIDUTILITIES_HH
5 
6 #include <tuple>
7 #include <utility>
8 
10 #include <dune/common/fvector.hh>
11 #include <dune/common/indices.hh>
12 
13 
14 
15 namespace Dune {
16 namespace Hybrid {
17 
18 namespace Impl {
19 
20  // Try if tuple_size is implemented for class
21  template<class T, int i>
22  constexpr auto size(const Dune::FieldVector<T, i>*, const PriorityTag<5>&)
23  -> decltype(std::integral_constant<std::size_t,i>())
24  {
25  return {};
26  }
27 
28  // Try if we have an instance of std::integer_sequence
29  template<class T, T... t, class Index>
30  constexpr auto size(std::integer_sequence<T, t...>, PriorityTag<4>)
31  {
32  using sizeAsType = std::tuple_size<decltype(std::make_tuple(t...))>;
33  return std::integral_constant<std::size_t, sizeAsType::value>();
34  }
35 
36  // Try if tuple_size is implemented for class
37  template<class T>
38  constexpr auto size(const T*, const PriorityTag<3>&)
39  -> decltype(std::integral_constant<std::size_t,std::tuple_size<T>::value>())
40  {
41  return {};
42  }
43 
44  // Try if there's a static constexpr size()
45  template<class T>
46  constexpr auto size(const T*, const PriorityTag<1>&)
47  -> decltype(std::integral_constant<std::size_t,T::size()>())
48  {
49  return {};
50  }
51 
52  // As a last resort try if there's a static constexpr size()
53  template<class T>
54  constexpr auto size(const T* t, const PriorityTag<0>&)
55  {
56  return t->size();
57  }
58 
59 } // namespace Impl
60 
61 
62 
84 template<class T>
85 constexpr auto size(const T& t)
86 {
87  return Impl::size(&t, PriorityTag<42>());
88 }
89 
90 
91 
92 namespace Impl {
93 
94  template<class Container, class Index,
95  std::enable_if_t<IsTuple<std::decay_t<Container>>::value, int> = 0>
96  constexpr decltype(auto) elementAt(Container&& c, Index&&, PriorityTag<2>)
97  {
98  return std::get<std::decay_t<Index>::value>(c);
99  }
100 
101  template<class T, T... t, class Index>
102  constexpr decltype(auto) elementAt(std::integer_sequence<T, t...> c, Index&&, PriorityTag<1>)
103  {
104  return std::get<std::decay_t<Index>::value>(std::make_tuple(std::integral_constant<T, t>()...));
105  }
106 
107  template<class Container, class Index>
108  constexpr decltype(auto) elementAt(Container&& c, Index&& i, PriorityTag<0>)
109  {
110  return c[i];
111  }
112 
113 } // namespace Impl
114 
115 
116 
137 template<class Container, class Index>
138 constexpr decltype(auto) elementAt(Container&& c, Index&& i)
139 {
140  return Impl::elementAt(std::forward<Container>(c), std::forward<Index>(i), PriorityTag<42>());
141 }
142 
143 
144 
145 namespace Impl {
146 
147  template<class Begin, class End>
149  {
150  public:
151 
152  template<std::size_t i>
153  constexpr auto operator[](Dune::index_constant<i>) const
154  {
155  return std::integral_constant<typename Begin::value_type, Begin::value+i>();
156  }
157 
158  static constexpr auto size()
159  {
160  return std::integral_constant<typename Begin::value_type, End::value - Begin::value>();
161  }
162  };
163 
164  template<class T>
166  {
167  public:
168  constexpr DynamicIntegralRange(const T& begin, const T& end):
169  begin_(begin),
170  end_(end)
171  {}
172 
173  constexpr auto size() const
174  {
175  return end_ - begin_;
176  }
177 
178  constexpr T operator[](const T&i) const
179  { return begin_+i; }
180 
181  private:
182  T begin_;
183  T end_;
184  };
185 
186  template<class Begin, class End,
187  std::enable_if_t<IsIntegralConstant<Begin>::value and IsIntegralConstant<End>::value, int> = 0>
188  constexpr auto integralRange(const Begin& begin, const End& end, const PriorityTag<1>&)
189  {
190  static_assert(Begin::value <= End::value, "You cannot create an integralRange where end<begin");
192  }
193 
194  // This should be constexpr but gcc-4.9 does not support
195  // the relaxed constexpr requirements. Hence for beeing
196  // constexpr the function body can only contain a return
197  // statement and no assertion before this.
198  template<class Begin, class End>
199  auto integralRange(const Begin& begin, const End& end, const PriorityTag<0>&)
200  {
201  assert(begin <= end);
202  return Impl::DynamicIntegralRange<End>(begin, end);
203  }
204 
205 } // namespace Impl
206 
207 
208 
226 template<class Begin, class End>
227 constexpr auto integralRange(const Begin& begin, const End& end)
228 {
229  return Impl::integralRange(begin, end, PriorityTag<42>());
230 }
231 
245 template<class End>
246 constexpr auto integralRange(const End& end)
247 {
249 }
250 
251 
252 
253 namespace Impl {
254 
255  template<class T>
256  void evaluateFoldExpression(std::initializer_list<T>&&)
257  {}
258 
259  template<class Range, class F, class Index, Index... i>
260  constexpr void forEachIndex(Range&& range, F&& f, std::integer_sequence<Index, i...>)
261  {
262  evaluateFoldExpression<int>({(f(Hybrid::elementAt(range, std::integral_constant<Index,i>())), 0)...});
263  }
264 
265  template<class F, class Index, Index... i>
266  constexpr void forEach(std::integer_sequence<Index, i...> range, F&& f, PriorityTag<2>)
267  {
268  evaluateFoldExpression<int>({(f(std::integral_constant<Index,i>()), 0)...});
269  }
270 
271 
272  template<class Range, class F,
273  std::enable_if_t<IsIntegralConstant<decltype(Hybrid::size(std::declval<Range>()))>::value, int> = 0>
274  constexpr void forEach(Range&& range, F&& f, PriorityTag<1>)
275  {
276  auto size = Hybrid::size(range);
277  auto indices = std::make_index_sequence<size>();
278  forEachIndex(std::forward<Range>(range), std::forward<F>(f), indices);
279  }
280 
281  template<class Range, class F>
282  constexpr void forEach(Range&& range, F&& f, PriorityTag<0>)
283  {
284  for(std::size_t i=0; i<range.size(); ++i)
285  f(range[i]);
286  // \todo Switch to real range for once DynamicIntegralRange has proper iterators
287  // for(auto e : range)
288  // f(e);
289  }
290 
291 } // namespace Impl
292 
293 
294 
313 template<class Range, class F>
314 constexpr void forEach(Range&& range, F&& f)
315 {
316  Impl::forEach(std::forward<Range>(range), std::forward<F>(f), PriorityTag<42>());
317 }
318 
319 
320 
336 template<class Range, class T, class F>
337 T accumulate(Range&& range, T value, F&& f)
338 {
339  forEach(std::forward<Range>(range), [&](auto&& entry) {
340  value = f(value, entry);
341  });
342  return value;
343 }
344 
345 
346 
347 namespace Impl {
348 
349  template<class IfFunc, class ElseFunc>
350  constexpr decltype(auto) ifElse(std::true_type, IfFunc&& ifFunc, ElseFunc&& elseFunc)
351  {
352  return ifFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
353  }
354 
355  template<class IfFunc, class ElseFunc>
356  constexpr decltype(auto) ifElse(std::false_type, IfFunc&& ifFunc, ElseFunc&& elseFunc)
357  {
358  return elseFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
359  }
360 
361  template<class IfFunc, class ElseFunc>
362  decltype(auto) ifElse(const bool& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
363  {
364  if (condition)
365  return ifFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
366  else
367  return elseFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
368  }
369 
370 } // namespace Impl
371 
372 
373 
394 template<class Condition, class IfFunc, class ElseFunc>
395 decltype(auto) ifElse(const Condition& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
396 {
397  return Impl::ifElse(condition, std::forward<IfFunc>(ifFunc), std::forward<ElseFunc>(elseFunc));
398 }
399 
407 template<class Condition, class IfFunc>
408 void ifElse(const Condition& condition, IfFunc&& ifFunc)
409 {
410  ifElse(condition, std::forward<IfFunc>(ifFunc), [](auto&& i) {});
411 }
412 
413 
414 
415 namespace Impl {
416 
417  template<class T1, class T2>
418  constexpr auto equals(const T1& t1, const T2& t2, PriorityTag<1>) -> decltype(T1::value, T2::value, std::integral_constant<bool,T1::value == T2::value>())
419  { return {}; }
420 
421  template<class T1, class T2>
422  constexpr auto equals(const T1& t1, const T2& t2, PriorityTag<0>)
423  {
424  return t1==t2;
425  }
426 
427 } // namespace Impl
428 
429 
430 
440 template<class T1, class T2>
441 constexpr auto equals(T1&& t1, T2&& t2)
442 {
443  return Impl::equals(std::forward<T1>(t1), std::forward<T2>(t2), PriorityTag<1>());
444 }
445 
446 
447 
448 namespace Impl {
449 
450  template<class Result, class T, class Value, class Branches, class ElseBranch>
451  constexpr Result switchCases(std::integer_sequence<T>, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
452  {
453  return elseBranch();
454  }
455 
456  template<class Result, class T, T t0, T... tt, class Value, class Branches, class ElseBranch>
457  constexpr Result switchCases(std::integer_sequence<T, t0, tt...>, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
458  {
459  return ifElse(
460  Hybrid::equals(std::integral_constant<T, t0>(), value),
461  [&](auto id) -> decltype(auto) {
462  return id(branches)(std::integral_constant<T, t0>());
463  }, [&](auto id) -> decltype(auto) {
464  return Impl::switchCases<Result>(id(std::integer_sequence<T, tt...>()), value, branches, elseBranch);
465  });
466  }
467 
468 } // namespace Impl
469 
470 
471 
499 template<class Cases, class Value, class Branches, class ElseBranch>
500 constexpr decltype(auto) switchCases(const Cases& cases, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
501 {
502  return Impl::switchCases<decltype(elseBranch())>(cases, value, std::forward<Branches>(branches), std::forward<ElseBranch>(elseBranch));
503 }
504 
525 template<class Cases, class Value, class Branches>
526 constexpr void switchCases(const Cases& cases, const Value& value, Branches&& branches)
527 {
528  return Impl::switchCases<void>(cases, value, std::forward<Branches>(branches), []() {});
529 }
530 
531 
532 } // namespace Hybrid
533 } // namespace Dune
534 
535 
536 #endif // #ifndef DUNE_COMMON_HYBRIDUTILITIES_HH
Helper class for tagging priorities.
Definition: typeutilities.hh:71
constexpr auto size(const T &t)
Size query.
Definition: hybridutilities.hh:85
Implements a vector constructed from a given type representing a field and a compile-time given size...
decltype(auto) constexpr elementAt(Container &&c, Index &&i)
Get element at given position from container.
Definition: hybridutilities.hh:138
decltype(auto) constexpr ifElse(std::true_type, IfFunc &&ifFunc, ElseFunc &&elseFunc)
Definition: hybridutilities.hh:350
static constexpr auto size()
Definition: hybridutilities.hh:158
constexpr DynamicIntegralRange(const T &begin, const T &end)
Definition: hybridutilities.hh:168
constexpr index_constant< 0 > _0
Compile time index with value 0.
Definition: indices.hh:49
Definition: typetraits.hh:207
STL namespace.
constexpr auto integralRange(const Begin &begin, const End &end, const PriorityTag< 1 > &)
Definition: hybridutilities.hh:188
constexpr auto operator[](Dune::index_constant< i >) const
Definition: hybridutilities.hh:153
Dune namespace.
Definition: alignment.hh:10
constexpr auto equals(T1 &&t1, T2 &&t2)
Equality comparison.
Definition: hybridutilities.hh:441
Definition: hybridutilities.hh:165
Check if T is an std::integral_constant<I, i>
Definition: typetraits.hh:545
Definition: typetraits.hh:200
constexpr Result switchCases(std::integer_sequence< T >, const Value &value, Branches &&branches, ElseBranch &&elseBranch)
Definition: hybridutilities.hh:451
Utilities for type computations, constraining overloads, ...
constexpr T operator[](const T &i) const
Definition: hybridutilities.hh:178
Helper class for tagging priorities.
Definition: typeutilities.hh:59
decltype(auto) constexpr elementAt(Container &&c, Index &&, PriorityTag< 2 >)
Definition: hybridutilities.hh:96
constexpr void forEachIndex(Range &&range, F &&f, std::integer_sequence< Index, i... >)
Definition: hybridutilities.hh:260
constexpr auto size() const
Definition: hybridutilities.hh:173
Definition: hybridutilities.hh:148
vector space out of a tensor product of fields.
Definition: densematrix.hh:39
void evaluateFoldExpression(std::initializer_list< T > &&)
Definition: hybridutilities.hh:256
constexpr auto size(const Dune::FieldVector< T, i > *, const PriorityTag< 5 > &) -> decltype(std::integral_constant< std::size_t, i >())
Definition: hybridutilities.hh:22
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:26
constexpr void forEach(std::integer_sequence< Index, i... > range, F &&f, PriorityTag< 2 >)
Definition: hybridutilities.hh:266
constexpr auto equals(const T1 &t1, const T2 &t2, PriorityTag< 1 >) -> decltype(T1::value, T2::value, std::integral_constant< bool, T1::value==T2::value >())
Definition: hybridutilities.hh:418
T accumulate(Range &&range, T value, F &&f)
Accumulate values.
Definition: hybridutilities.hh:337