dune-common  2.6-git
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 
11 #include <dune/common/fvector.hh>
12 #include <dune/common/indices.hh>
14 #include <dune/common/unused.hh>
15 
16 
17 
18 namespace Dune {
19 namespace Hybrid {
20 
21 namespace Impl {
22 
23  // Try if tuple_size is implemented for class
24  template<class T, int i>
25  constexpr auto size(const Dune::FieldVector<T, i>&, const PriorityTag<5>&)
26  -> decltype(std::integral_constant<std::size_t,i>())
27  {
28  return {};
29  }
30 
31  // Try if tuple_size is implemented for class
32  template<class T>
33  constexpr auto size(const T&, const PriorityTag<3>&)
34  -> decltype(std::integral_constant<std::size_t,std::tuple_size<T>::value>())
35  {
36  return {};
37  }
38 
39  // Try if there's a static constexpr size()
40  template<class T>
41  constexpr auto size(const T&, const PriorityTag<1>&)
42  -> decltype(std::integral_constant<std::size_t,T::size()>())
43  {
44  return {};
45  }
46 
47  // As a last resort try if there's a static constexpr size()
48  template<class T>
49  constexpr auto size(const T& t, const PriorityTag<0>&)
50  {
51  return t.size();
52  }
53 
54 } // namespace Impl
55 
56 
57 
79 template<class T>
80 constexpr auto size(const T& t)
81 {
82  return Impl::size(t, PriorityTag<42>());
83 }
84 
85 
86 
87 namespace Impl {
88 
89  template<class Container, class Index,
90  std::enable_if_t<IsTuple<std::decay_t<Container>>::value, int> = 0>
91  constexpr decltype(auto) elementAt(Container&& c, Index&&, PriorityTag<2>)
92  {
93  return std::get<std::decay_t<Index>::value>(c);
94  }
95 
96  template<class T, T... t, class Index>
97  constexpr decltype(auto) elementAt(std::integer_sequence<T, t...> c, Index, PriorityTag<1>)
98  {
99  return Dune::integerSequenceEntry(c, std::integral_constant<std::size_t, Index::value>());
100  }
101 
102  template<class Container, class Index>
103  constexpr decltype(auto) elementAt(Container&& c, Index&& i, PriorityTag<0>)
104  {
105  return c[i];
106  }
107 
108 } // namespace Impl
109 
110 
111 
132 template<class Container, class Index>
133 constexpr decltype(auto) elementAt(Container&& c, Index&& i)
134 {
135  return Impl::elementAt(std::forward<Container>(c), std::forward<Index>(i), PriorityTag<42>());
136 }
137 
138 
139 
140 namespace Impl {
141 
142  template<class Begin, class End>
143  class StaticIntegralRange
144  {
145  public:
146 
147  template<std::size_t i>
148  constexpr auto operator[](Dune::index_constant<i>) const
149  {
150  return std::integral_constant<typename Begin::value_type, Begin::value+i>();
151  }
152 
153  static constexpr auto size()
154  {
155  return std::integral_constant<typename Begin::value_type, End::value - Begin::value>();
156  }
157  };
158 
159  template<class T>
160  class DynamicIntegralRange
161  {
162  public:
163  constexpr DynamicIntegralRange(const T& begin, const T& end):
164  begin_(begin),
165  end_(end)
166  {}
167 
168  constexpr auto size() const
169  {
170  return end_ - begin_;
171  }
172 
173  constexpr T operator[](const T&i) const
174  { return begin_+i; }
175 
176  private:
177  T begin_;
178  T end_;
179  };
180 
181  template<class Begin, class End,
182  std::enable_if_t<IsIntegralConstant<Begin>::value and IsIntegralConstant<End>::value, int> = 0>
183  constexpr auto integralRange(const Begin& /*begin*/, const End& /*end*/, const PriorityTag<1>&)
184  {
185  static_assert(Begin::value <= End::value, "You cannot create an integralRange where end<begin");
186  return Impl::StaticIntegralRange<Begin,End>();
187  }
188 
189  // This should be constexpr but gcc-4.9 does not support
190  // the relaxed constexpr requirements. Hence for being
191  // constexpr the function body can only contain a return
192  // statement and no assertion before this.
193  template<class Begin, class End>
194  constexpr auto integralRange(const Begin& begin, const End& end, const PriorityTag<0>&)
195  {
196  return DUNE_ASSERT_AND_RETURN(begin<=end, Impl::DynamicIntegralRange<End>(begin, end));
197  }
198 
199 } // namespace Impl
200 
201 
202 
220 template<class Begin, class End>
221 constexpr auto integralRange(const Begin& begin, const End& end)
222 {
223  return Impl::integralRange(begin, end, PriorityTag<42>());
224 }
225 
239 template<class End>
240 constexpr auto integralRange(const End& end)
241 {
243 }
244 
245 
246 
247 namespace Impl {
248 
249  template<class T>
250  void evaluateFoldExpression(std::initializer_list<T>&&)
251  {}
252 
253  template<class Range, class F, class Index, Index... i>
254  constexpr void forEachIndex(Range&& range, F&& f, std::integer_sequence<Index, i...>)
255  {
256  evaluateFoldExpression<int>({(f(Hybrid::elementAt(range, std::integral_constant<Index,i>())), 0)...});
257  }
258 
259  template<class F, class Index, Index... i>
260  constexpr void forEach(std::integer_sequence<Index, i...> /*range*/, F&& f, PriorityTag<2>)
261  {
262  evaluateFoldExpression<int>({(f(std::integral_constant<Index,i>()), 0)...});
263  }
264 
265 
266  template<class Range, class F,
267  std::enable_if_t<IsIntegralConstant<decltype(Hybrid::size(std::declval<Range>()))>::value, int> = 0>
268  constexpr void forEach(Range&& range, F&& f, PriorityTag<1>)
269  {
270  auto size = Hybrid::size(range);
271  auto indices = std::make_index_sequence<size>();
272  (forEachIndex)(std::forward<Range>(range), std::forward<F>(f), indices);
273  }
274 
275  template<class Range, class F>
276  constexpr void forEach(Range&& range, F&& f, PriorityTag<0>)
277  {
278  for(std::size_t i=0; i<range.size(); ++i)
279  f(range[i]);
280  // \todo Switch to real range for once DynamicIntegralRange has proper iterators
281  // for(auto e : range)
282  // f(e);
283  }
284 
285 } // namespace Impl
286 
287 
288 
307 template<class Range, class F>
308 constexpr void forEach(Range&& range, F&& f)
309 {
310  Impl::forEach(std::forward<Range>(range), std::forward<F>(f), PriorityTag<42>());
311 }
312 
313 
314 
330 template<class Range, class T, class F>
331 T accumulate(Range&& range, T value, F&& f)
332 {
333  forEach(std::forward<Range>(range), [&](auto&& entry) {
334  value = f(value, entry);
335  });
336  return value;
337 }
338 
339 
340 
341 namespace Impl {
342 
343  template<class IfFunc, class ElseFunc>
344  constexpr decltype(auto) ifElse(std::true_type, IfFunc&& ifFunc, ElseFunc&& /*elseFunc*/)
345  {
346  return ifFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
347  }
348 
349  template<class IfFunc, class ElseFunc>
350  constexpr decltype(auto) ifElse(std::false_type, IfFunc&& /*ifFunc*/, ElseFunc&& elseFunc)
351  {
352  return elseFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
353  }
354 
355  template<class IfFunc, class ElseFunc>
356  decltype(auto) ifElse(const bool& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
357  {
358  if (condition)
359  return ifFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
360  else
361  return elseFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
362  }
363 
364 } // namespace Impl
365 
366 
367 
388 template<class Condition, class IfFunc, class ElseFunc>
389 decltype(auto) ifElse(const Condition& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
390 {
391  return Impl::ifElse(condition, std::forward<IfFunc>(ifFunc), std::forward<ElseFunc>(elseFunc));
392 }
393 
401 template<class Condition, class IfFunc>
402 void ifElse(const Condition& condition, IfFunc&& ifFunc)
403 {
404  ifElse(condition, std::forward<IfFunc>(ifFunc), [](auto&& i) { DUNE_UNUSED_PARAMETER(i); });
405 }
406 
407 
408 
409 namespace Impl {
410 
411  template<class T1, class T2>
412  constexpr auto equals(const T1& /*t1*/, const T2& /*t2*/, PriorityTag<1>) -> decltype(T1::value, T2::value, std::integral_constant<bool,T1::value == T2::value>())
413  { return {}; }
414 
415  template<class T1, class T2>
416  constexpr auto equals(const T1& t1, const T2& t2, PriorityTag<0>)
417  {
418  return t1==t2;
419  }
420 
421 } // namespace Impl
422 
423 
424 
434 template<class T1, class T2>
435 constexpr auto equals(T1&& t1, T2&& t2)
436 {
437  return Impl::equals(std::forward<T1>(t1), std::forward<T2>(t2), PriorityTag<1>());
438 }
439 
440 
441 
442 namespace Impl {
443 
444  template<class Result, class T, class Value, class Branches, class ElseBranch>
445  constexpr Result switchCases(std::integer_sequence<T>, const Value& /*value*/, Branches&& /*branches*/, ElseBranch&& elseBranch)
446  {
447  return elseBranch();
448  }
449 
450  template<class Result, class T, T t0, T... tt, class Value, class Branches, class ElseBranch>
451  constexpr Result switchCases(std::integer_sequence<T, t0, tt...>, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
452  {
453  return ifElse(
454  Hybrid::equals(std::integral_constant<T, t0>(), value),
455  [&](auto id) -> decltype(auto) {
456  return id(branches)(std::integral_constant<T, t0>());
457  }, [&](auto id) -> decltype(auto) {
458  return Impl::switchCases<Result>(id(std::integer_sequence<T, tt...>()), value, branches, elseBranch);
459  });
460  }
461 
462 } // namespace Impl
463 
464 
465 
493 template<class Cases, class Value, class Branches, class ElseBranch>
494 constexpr decltype(auto) switchCases(const Cases& cases, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
495 {
496  return Impl::switchCases<decltype(elseBranch())>(cases, value, std::forward<Branches>(branches), std::forward<ElseBranch>(elseBranch));
497 }
498 
519 template<class Cases, class Value, class Branches>
520 constexpr void switchCases(const Cases& cases, const Value& value, Branches&& branches)
521 {
522  return Impl::switchCases<void>(cases, value, std::forward<Branches>(branches), []() {});
523 }
524 
525 
526 } // namespace Hybrid
527 } // namespace Dune
528 
529 
530 #endif // #ifndef DUNE_COMMON_HYBRIDUTILITIES_HH
Dune::Hybrid::forEach
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:308
Dune::Hybrid::ifElse
decltype(auto) ifElse(const Condition &condition, IfFunc &&ifFunc, ElseFunc &&elseFunc)
A conditional expression.
Definition: hybridutilities.hh:389
Dune::Hybrid::elementAt
constexpr decltype(auto) elementAt(Container &&c, Index &&i)
Get element at given position from container.
Definition: hybridutilities.hh:133
Dune::Hybrid::size
constexpr auto size(const T &t)
Size query.
Definition: hybridutilities.hh:80
DUNE_ASSERT_AND_RETURN
#define DUNE_ASSERT_AND_RETURN(C, X)
Asserts a condition and return on success in constexpr context.
Definition: assertandreturn.hh:20
Dune::Hybrid::ifElse
void ifElse(const Condition &condition, IfFunc &&ifFunc)
A conditional expression.
Definition: hybridutilities.hh:402
DUNE_UNUSED_PARAMETER
#define DUNE_UNUSED_PARAMETER(parm)
A macro to mark intentionally unused function parameters with.
Definition: unused.hh:25
Dune::range
static StaticIntegralRange< T, to, from > range(std::integral_constant< T, from >, std::integral_constant< T, to >) noexcept
Definition: rangeutilities.hh:290
indices.hh
Dune::Hybrid::accumulate
T accumulate(Range &&range, T value, F &&f)
Accumulate values.
Definition: hybridutilities.hh:331
Dune
Dune namespace.
Definition: alignedallocator.hh:9
Dune::integerSequenceEntry
constexpr auto integerSequenceEntry(std::integer_sequence< T, t... >, std::integral_constant< std::size_t, index > i)
Get entry of std::integer_sequence.
Definition: typetraits.hh:518
unused.hh
Definition of the DUNE_UNUSED macro for the case that config.h is not available.
Dune::Indices::_0
constexpr index_constant< 0 > _0
Compile time index with value 0.
Definition: indices.hh:50
Dune::Hybrid::integralRange
constexpr auto integralRange(const End &end)
Create an integral range starting from 0.
Definition: hybridutilities.hh:240
fvector.hh
Implements a vector constructed from a given type representing a field and a compile-time given size.
Dune::PriorityTag< 0 >
Helper class for tagging priorities.
Definition: typeutilities.hh:82
Dune::PriorityTag
Helper class for tagging priorities.
Definition: typeutilities.hh:70
Dune::Hybrid::equals
constexpr auto equals(T1 &&t1, T2 &&t2)
Equality comparison.
Definition: hybridutilities.hh:435
typeutilities.hh
Utilities for type computations, constraining overloads, ...
Dune::StaticIntegralRange
static integer range for use in range-based for loops
Definition: rangeutilities.hh:220
assertandreturn.hh
Dune::Hybrid::switchCases
constexpr decltype(auto) switchCases(const Cases &cases, const Value &value, Branches &&branches, ElseBranch &&elseBranch)
Switch statement.
Definition: hybridutilities.hh:494
Dune::Hybrid::integralRange
constexpr auto integralRange(const Begin &begin, const End &end)
Create an integral range.
Definition: hybridutilities.hh:221
Dune::index_constant
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:27
Dune::FieldVector
vector space out of a tensor product of fields.
Definition: densematrix.hh:40
typetraits.hh
Traits for type conversions and type information.