dune-common  2.7.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 
11 #include <dune/common/fvector.hh>
12 #include <dune/common/indices.hh>
14 #include <dune/common/unused.hh>
16 
17 
18 
19 namespace Dune {
20 namespace Hybrid {
21 
22 namespace Impl {
23 
24  // Try if tuple_size is implemented for class
25  template<class T, int i>
26  constexpr auto size(const Dune::FieldVector<T, i>&, const PriorityTag<5>&)
27  -> decltype(std::integral_constant<std::size_t,i>())
28  {
29  return {};
30  }
31 
32  // Try if tuple_size is implemented for class
33  template<class T>
34  constexpr auto size(const T&, const PriorityTag<3>&)
35  -> decltype(std::integral_constant<std::size_t,std::tuple_size<T>::value>())
36  {
37  return {};
38  }
39 
40  // Try if there's a static constexpr size()
41  template<class T>
42  constexpr auto size(const T&, const PriorityTag<1>&)
43  -> decltype(std::integral_constant<std::size_t,T::size()>())
44  {
45  return {};
46  }
47 
48  // As a last resort try if there's a static constexpr size()
49  template<class T>
50  constexpr auto size(const T& t, const PriorityTag<0>&)
51  {
52  return t.size();
53  }
54 
55 } // namespace Impl
56 
57 
58 
80 template<class T>
81 constexpr auto size(const T& t)
82 {
83  return Impl::size(t, PriorityTag<42>());
84 }
85 
86 
87 
88 namespace Impl {
89 
90  template<class Container, class Index,
91  std::enable_if_t<IsTuple<std::decay_t<Container>>::value, int> = 0>
92  constexpr decltype(auto) elementAt(Container&& c, Index&&, PriorityTag<2>)
93  {
94  return std::get<std::decay_t<Index>::value>(c);
95  }
96 
97  template<class T, T... t, class Index>
98  constexpr decltype(auto) elementAt(std::integer_sequence<T, t...> c, Index, PriorityTag<1>)
99  {
100  return Dune::integerSequenceEntry(c, std::integral_constant<std::size_t, Index::value>());
101  }
102 
103  template<class Container, class Index>
104  constexpr decltype(auto) elementAt(Container&& c, Index&& i, PriorityTag<0>)
105  {
106  return c[i];
107  }
108 
109 } // namespace Impl
110 
111 
112 
133 template<class Container, class Index>
134 constexpr decltype(auto) elementAt(Container&& c, Index&& i)
135 {
136  return Impl::elementAt(std::forward<Container>(c), std::forward<Index>(i), PriorityTag<42>());
137 }
138 
139 
140 
141 namespace Impl {
142 
143  template<class Begin, class End,
144  std::enable_if_t<IsIntegralConstant<Begin>::value and IsIntegralConstant<End>::value, int> = 0>
145  constexpr auto integralRange(const Begin& /*begin*/, const End& /*end*/, const PriorityTag<1>&)
146  {
147  static_assert(Begin::value <= End::value, "You cannot create an integralRange where end<begin");
149  }
150 
151  // This should be constexpr but gcc-4.9 does not support
152  // the relaxed constexpr requirements. Hence for being
153  // constexpr the function body can only contain a return
154  // statement and no assertion before this.
155  template<class Begin, class End>
156  constexpr auto integralRange(const Begin& begin, const End& end, const PriorityTag<0>&)
157  {
158  return DUNE_ASSERT_AND_RETURN(begin<=end, Dune::IntegralRange<End>(begin, end));
159  }
160 
161 } // namespace Impl
162 
163 
164 
182 template<class Begin, class End>
183 constexpr auto integralRange(const Begin& begin, const End& end)
184 {
185  return Impl::integralRange(begin, end, PriorityTag<42>());
186 }
187 
201 template<class End>
202 constexpr auto integralRange(const End& end)
203 {
205 }
206 
207 
208 
209 namespace Impl {
210 
211  template<class T>
212  void evaluateFoldExpression(std::initializer_list<T>&&)
213  {}
214 
215  template<class Range, class F, class Index, Index... i>
216  constexpr void forEachIndex(Range&& range, F&& f, std::integer_sequence<Index, i...>)
217  {
218  evaluateFoldExpression<int>({(f(Hybrid::elementAt(range, std::integral_constant<Index,i>())), 0)...});
219  }
220 
221  template<class F, class Index, Index... i>
222  constexpr void forEach(std::integer_sequence<Index, i...> /*range*/, F&& f, PriorityTag<2>)
223  {
224  evaluateFoldExpression<int>({(f(std::integral_constant<Index,i>()), 0)...});
225  }
226 
227 
228  template<class Range, class F,
229  std::enable_if_t<IsIntegralConstant<decltype(Hybrid::size(std::declval<Range>()))>::value, int> = 0>
230  constexpr void forEach(Range&& range, F&& f, PriorityTag<1>)
231  {
232  auto size = Hybrid::size(range);
233  auto indices = std::make_index_sequence<size>();
234  (forEachIndex)(std::forward<Range>(range), std::forward<F>(f), indices);
235  }
236 
237  template<class Range, class F>
238  constexpr void forEach(Range&& range, F&& f, PriorityTag<0>)
239  {
240  for(auto&& e : range)
241  f(e);
242  }
243 
244 } // namespace Impl
245 
246 
247 
266 template<class Range, class F>
267 constexpr void forEach(Range&& range, F&& f)
268 {
269  Impl::forEach(std::forward<Range>(range), std::forward<F>(f), PriorityTag<42>());
270 }
271 
272 
273 
289 template<class Range, class T, class F>
290 T accumulate(Range&& range, T value, F&& f)
291 {
292  forEach(std::forward<Range>(range), [&](auto&& entry) {
293  value = f(value, entry);
294  });
295  return value;
296 }
297 
298 
299 
300 namespace Impl {
301 
302  struct Id {
303  template<class T>
304  constexpr T operator()(T&& x) const {
305  return std::forward<T>(x);
306  }
307  };
308 
309  template<class IfFunc, class ElseFunc>
310  constexpr decltype(auto) ifElse(std::true_type, IfFunc&& ifFunc, ElseFunc&& /*elseFunc*/)
311  {
312  return ifFunc(Id{});
313  }
314 
315  template<class IfFunc, class ElseFunc>
316  constexpr decltype(auto) ifElse(std::false_type, IfFunc&& /*ifFunc*/, ElseFunc&& elseFunc)
317  {
318  return elseFunc(Id{});
319  }
320 
321  template<class IfFunc, class ElseFunc>
322  decltype(auto) ifElse(const bool& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
323  {
324  if (condition)
325  return ifFunc(Id{});
326  else
327  return elseFunc(Id{});
328  }
329 
330 } // namespace Impl
331 
332 
333 
354 template<class Condition, class IfFunc, class ElseFunc>
355 decltype(auto) ifElse(const Condition& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
356 {
357  return Impl::ifElse(condition, std::forward<IfFunc>(ifFunc), std::forward<ElseFunc>(elseFunc));
358 }
359 
367 template<class Condition, class IfFunc>
368 void ifElse(const Condition& condition, IfFunc&& ifFunc)
369 {
370  ifElse(condition, std::forward<IfFunc>(ifFunc), [](auto&& i) { DUNE_UNUSED_PARAMETER(i); });
371 }
372 
373 
374 
375 namespace Impl {
376 
377  template<class T1, class T2>
378  constexpr auto equals(const T1& /*t1*/, const T2& /*t2*/, PriorityTag<1>) -> decltype(T1::value, T2::value, std::integral_constant<bool,T1::value == T2::value>())
379  { return {}; }
380 
381  template<class T1, class T2>
382  constexpr auto equals(const T1& t1, const T2& t2, PriorityTag<0>)
383  {
384  return t1==t2;
385  }
386 
387 } // namespace Impl
388 
389 
390 
400 template<class T1, class T2>
401 constexpr auto equals(T1&& t1, T2&& t2)
402 {
403  return Impl::equals(std::forward<T1>(t1), std::forward<T2>(t2), PriorityTag<1>());
404 }
405 
406 
407 
408 namespace Impl {
409 
410  template<class Result, class T, class Value, class Branches, class ElseBranch>
411  constexpr Result switchCases(std::integer_sequence<T>, const Value& /*value*/, Branches&& /*branches*/, ElseBranch&& elseBranch)
412  {
413  return elseBranch();
414  }
415 
416  template<class Result, class T, T t0, T... tt, class Value, class Branches, class ElseBranch>
417  constexpr Result switchCases(std::integer_sequence<T, t0, tt...>, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
418  {
419  return ifElse(
420  Hybrid::equals(std::integral_constant<T, t0>(), value),
421  [&](auto id) -> decltype(auto) {
422  return id(branches)(std::integral_constant<T, t0>());
423  }, [&](auto id) -> decltype(auto) {
424  return Impl::switchCases<Result>(id(std::integer_sequence<T, tt...>()), value, branches, elseBranch);
425  });
426  }
427 
428 } // namespace Impl
429 
430 
431 
459 template<class Cases, class Value, class Branches, class ElseBranch>
460 constexpr decltype(auto) switchCases(const Cases& cases, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
461 {
462  return Impl::switchCases<decltype(elseBranch())>(cases, value, std::forward<Branches>(branches), std::forward<ElseBranch>(elseBranch));
463 }
464 
485 template<class Cases, class Value, class Branches>
486 constexpr void switchCases(const Cases& cases, const Value& value, Branches&& branches)
487 {
488  return Impl::switchCases<void>(cases, value, std::forward<Branches>(branches), []() {});
489 }
490 
491 
492 } // namespace Hybrid
493 } // namespace Dune
494 
495 
496 #endif // #ifndef DUNE_COMMON_HYBRIDUTILITIES_HH
typeutilities.hh
Utilities for type computations, constraining overloads, ...
Dune::Hybrid::size
constexpr auto size(const T &t)
Size query.
Definition: hybridutilities.hh:81
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::Indices::_0
constexpr index_constant< 0 > _0
Compile time index with value 0.
Definition: indices.hh:51
Dune::PriorityTag
Helper class for tagging priorities.
Definition: typeutilities.hh:70
DUNE_UNUSED_PARAMETER
#define DUNE_UNUSED_PARAMETER(parm)
A macro to mark intentionally unused function parameters with.
Definition: unused.hh:25
Dune::Hybrid::ifElse
void ifElse(const Condition &condition, IfFunc &&ifFunc)
A conditional expression.
Definition: hybridutilities.hh:368
Dune::IsIntegralConstant
Check if T is an std::integral_constant<I, i>
Definition: typetraits.hh:464
Dune::Hybrid::equals
constexpr auto equals(T1 &&t1, T2 &&t2)
Equality comparison.
Definition: hybridutilities.hh:401
Dune::StaticIntegralRange
static integer range for use in range-based for loops
Definition: rangeutilities.hh:221
Dune::range
static StaticIntegralRange< T, to, from > range(std::integral_constant< T, from >, std::integral_constant< T, to >) noexcept
Definition: rangeutilities.hh:297
Dune::Hybrid::integralRange
constexpr auto integralRange(const Begin &begin, const End &end)
Create an integral range.
Definition: hybridutilities.hh:183
fvector.hh
Implements a vector constructed from a given type representing a field and a compile-time given size.
typetraits.hh
Traits for type conversions and type information.
Dune::Hybrid::ifElse
decltype(auto) ifElse(const Condition &condition, IfFunc &&ifFunc, ElseFunc &&elseFunc)
A conditional expression.
Definition: hybridutilities.hh:355
Dune::Hybrid::accumulate
T accumulate(Range &&range, T value, F &&f)
Accumulate values.
Definition: hybridutilities.hh:290
indices.hh
Dune::Hybrid::forEach
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:267
Dune::Hybrid::switchCases
constexpr decltype(auto) switchCases(const Cases &cases, const Value &value, Branches &&branches, ElseBranch &&elseBranch)
Switch statement.
Definition: hybridutilities.hh:460
assertandreturn.hh
Dune::IntegralRange
dynamic integer range for use in range-based for loops
Definition: rangeutilities.hh:171
unused.hh
Definition of the DUNE_UNUSED macro for the case that config.h is not available.
Dune::FieldVector
vector space out of a tensor product of fields.
Definition: densematrix.hh:42
Dune::Hybrid::elementAt
constexpr decltype(auto) elementAt(Container &&c, Index &&i)
Get element at given position from container.
Definition: hybridutilities.hh:134
Dune::PriorityTag< 0 >
Helper class for tagging priorities.
Definition: typeutilities.hh:84
Dune::Hybrid::integralRange
constexpr auto integralRange(const End &end)
Create an integral range starting from 0.
Definition: hybridutilities.hh:202
rangeutilities.hh
Utilities for reduction like operations on ranges.
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:543
Dune
Dune namespace.
Definition: alignedallocator.hh:13