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