dune-common  2.11
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 © 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 
25 namespace Hybrid {
26 
27 namespace Impl {
28 
29  // Try if std::tuple_size is implemented for class
30  template<class T>
31  constexpr auto size(const T&, const PriorityTag<2>&)
32  -> decltype(std::integral_constant<std::size_t,std::tuple_size<T>::value>())
33  {
34  return {};
35  }
36 
37  // Try if there's a static constexpr size() method
38  template<class T>
39  constexpr auto size(const T&, const PriorityTag<1>&)
40  -> decltype(std::integral_constant<std::size_t,T::size()>())
41  {
42  return {};
43  }
44 
45  // As a last resort try if there's a non-static size()
46  template<class T>
47  constexpr auto size(const T& t, const PriorityTag<0>&)
48  {
49  return t.size();
50  }
51 
52 } // namespace Impl
53 
54 
55 
77 template<class T>
78 constexpr auto size(const T& t)
79 {
80  return Impl::size(t, PriorityTag<42>());
81 }
82 
83 
84 
85 namespace Impl {
86 
87  template<class Container, class Index,
88  std::enable_if_t<IsTuple<std::decay_t<Container>>::value, int> = 0>
89  constexpr decltype(auto) elementAt(Container&& c, Index&&, PriorityTag<2>)
90  {
91  return std::get<std::decay_t<Index>::value>(c);
92  }
93 
94  template<class T, T... t, class Index>
95  constexpr decltype(auto) elementAt(std::integer_sequence<T, t...> c, Index, PriorityTag<1>)
96  {
97  return Dune::get<Index::value>(c);
98  }
99 
100  template<class Container, class Index>
101  constexpr decltype(auto) elementAt(Container&& c, Index&& i, PriorityTag<0>)
102  {
103  return c[i];
104  }
105 
106 } // namespace Impl
107 
108 
109 
130 template<class Container, class Index>
131 constexpr decltype(auto) elementAt(Container&& c, Index&& i)
132 {
133  return Impl::elementAt(std::forward<Container>(c), std::forward<Index>(i), PriorityTag<42>());
134 }
135 
136 
137 
138 namespace Impl {
139 
140  template<class Begin, class End,
141  std::enable_if_t<IsIntegralConstant<Begin>::value and IsIntegralConstant<End>::value, int> = 0>
142  constexpr auto integralRange(const Begin& /*begin*/, const End& /*end*/, const PriorityTag<1>&)
143  {
144  static_assert(Begin::value <= End::value, "You cannot create an integralRange where end<begin");
146  }
147 
148  template<class Begin, class End>
149  constexpr auto integralRange(const Begin& begin, const End& end, const PriorityTag<0>&)
150  {
151  assert(begin<=end && "You cannot create an integralRange where end<begin");
152  return Dune::IntegralRange<End>(begin, end);
153  }
154 
155 } // namespace Impl
156 
157 
158 
176 template<class Begin, class End>
177 constexpr auto integralRange(const Begin& begin, const End& end)
178 {
179  return Impl::integralRange(begin, end, PriorityTag<42>());
180 }
181 
195 template<class End>
196 constexpr auto integralRange(const End& end)
197 {
199 }
200 
201 
202 
203 namespace Impl {
204 
205  template<class T>
206  constexpr void evaluateFoldExpression(std::initializer_list<T>&&)
207  {}
208 
209  template<class Range, class F, class Index, Index... i>
210  constexpr void forEachIndex(Range&& range, F&& f, std::integer_sequence<Index, i...>)
211  {
212  evaluateFoldExpression<int>({(f(Hybrid::elementAt(range, std::integral_constant<Index,i>())), 0)...});
213  }
214 
215  template<class F, class Index, Index... i>
216  constexpr void forEach(std::integer_sequence<Index, i...> /*range*/, F&& f, PriorityTag<2>)
217  {
218  evaluateFoldExpression<int>({(f(std::integral_constant<Index,i>()), 0)...});
219  }
220 
221 
222  template<class Range, class F,
223  std::enable_if_t<IsIntegralConstant<decltype(Hybrid::size(std::declval<Range>()))>::value, int> = 0>
224  constexpr void forEach(Range&& range, F&& f, PriorityTag<1>)
225  {
226  auto size = Hybrid::size(range);
227  auto indices = std::make_index_sequence<size>();
228  (forEachIndex)(std::forward<Range>(range), std::forward<F>(f), indices);
229  }
230 
231  template<class Range, class F>
232  constexpr void forEach(Range&& range, F&& f, PriorityTag<0>)
233  {
234  for(auto&& e : range)
235  f(e);
236  }
237 
238 } // namespace Impl
239 
240 
241 
260 template<class Range, class F>
261 constexpr void forEach(Range&& range, F&& f)
262 {
263  Impl::forEach(std::forward<Range>(range), std::forward<F>(f), PriorityTag<42>());
264 }
265 
266 
267 
283 template<class Range, class T, class F>
284 constexpr T accumulate(Range&& range, T value, F&& f)
285 {
286  forEach(std::forward<Range>(range), [&](auto&& entry) {
287  value = f(value, entry);
288  });
289  return value;
290 }
291 
292 
293 
294 namespace Impl {
295 
296  struct Id {
297  template<class T>
298  constexpr T operator()(T&& x) const {
299  return std::forward<T>(x);
300  }
301  };
302 
303  template<class IfFunc, class ElseFunc>
304  constexpr decltype(auto) ifElse(std::true_type, IfFunc&& ifFunc, ElseFunc&& /*elseFunc*/)
305  {
306  return ifFunc(Id{});
307  }
308 
309  template<class IfFunc, class ElseFunc>
310  constexpr decltype(auto) ifElse(std::false_type, IfFunc&& /*ifFunc*/, ElseFunc&& elseFunc)
311  {
312  return elseFunc(Id{});
313  }
314 
315  template<class IfFunc, class ElseFunc>
316  decltype(auto) ifElse(const bool& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
317  {
318  if (condition)
319  return ifFunc(Id{});
320  else
321  return elseFunc(Id{});
322  }
323 
324 } // namespace Impl
325 
326 
327 
348 template<class Condition, class IfFunc, class ElseFunc>
349 decltype(auto) ifElse(const Condition& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
350 {
351  return Impl::ifElse(condition, std::forward<IfFunc>(ifFunc), std::forward<ElseFunc>(elseFunc));
352 }
353 
361 template<class Condition, class IfFunc>
362 void ifElse(const Condition& condition, IfFunc&& ifFunc)
363 {
364  ifElse(condition, std::forward<IfFunc>(ifFunc), [](auto&&) {});
365 }
366 
367 
368 
369 namespace Impl {
370 
371  struct Max {
372  template<class... Args>
373  constexpr decltype(auto) operator()(Args&&... args) const
374  {
375  using T = std::common_type_t<Args...>;
376  return std::max({T(args)...});
377  }
378  };
379 
380  struct Min {
381  template<class... Args>
382  constexpr decltype(auto) operator()(Args&&... args) const
383  {
384  using T = std::common_type_t<Args...>;
385  return std::min({T(args)...});
386  }
387  };
388 
389 } // namespace Impl
390 
391 
422 template<class Functor>
424 
425  static_assert(std::is_default_constructible_v<Functor>,
426  "Operator in integral expressions shall be constexpr default constructible");
427 
428  inline static constexpr Functor _functor = Functor{};
429 
430 public:
431 
441  template<class... Args>
442  constexpr decltype(auto) operator()(const Args&... args) const
443  {
444  if constexpr (std::conjunction_v<IsCompileTimeConstant<Args>...>)
445  {
446  constexpr auto result = _functor(Args::value...);
447  // apply functor on integral constant arguments and return an integral constant of the result
448  // this is guaranteed to be evaluated at compile-time
449  return std::integral_constant<std::remove_cv_t<decltype(result)>,result>{};
450  } else {
451  // apply functor directly on arguments and return the result of the functor
452  // (integral constants are likely to be casted to underlying type)
453  // this not is guaranteed to be evaluated at compile-time although is possible if expression is constexpr
454  return _functor(args...);
455  }
456  }
457 };
458 
463 template<class Functor>
464 constexpr HybridFunctor<Functor> hybridFunctor(const Functor&)
465 {
466  return {};
467 }
468 
489 inline constexpr auto max = hybridFunctor(Impl::Max{});
490 
511 inline constexpr auto min = hybridFunctor(Impl::Min{});
512 
533 inline constexpr auto plus = hybridFunctor(std::plus<>{});
534 
555 inline constexpr auto minus = hybridFunctor(std::minus<>{});
556 
577 inline constexpr auto equal_to = hybridFunctor(std::equal_to<>{});
578 
579 
580 namespace Impl {
581 
582  // This overload is selected if the passed value is already a compile time constant.
583  template<class Result, class T, T t0, T... tt, class ValueType, ValueType value, class Branches, class ElseBranch>
584  constexpr Result switchCases(std::integer_sequence<T, t0, tt...>, const std::integral_constant<ValueType, value>& /*value*/, Branches&& branches, ElseBranch&& elseBranch)
585  {
586  // In case we pass a value known at compile time, we no longer have to do
587  // a dynamic to static dispatch via recursion. The only thing that's left
588  // is to check if the value is contained in the passed range.
589  // If this is true, we have to pass it to the branches callback
590  // as an appropriate integral_constant type. Otherwise we have to
591  // execute the else callback.
592  if constexpr (((t0 == value) || ... || (tt == value)))
593  return branches(std::integral_constant<T, value>{});
594  else
595  return elseBranch();
596  }
597 
598  // This overload is selected if the passed value is dynamic.
599  template<class Result, class T, class Value, class Branches, class ElseBranch>
600  constexpr Result switchCases(std::integer_sequence<T>, const Value& /*value*/, Branches&& /*branches*/, ElseBranch&& elseBranch)
601  {
602  return elseBranch();
603  }
604 
605  template<class Result, class T, T t0, T... tt, class Value, class Branches, class ElseBranch>
606  constexpr Result switchCases(std::integer_sequence<T, t0, tt...>, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
607  {
608  if (t0 == value)
609  return branches(std::integral_constant<T, t0>());
610  else
611  return Impl::switchCases<Result>(std::integer_sequence<T, tt...>(), value, branches, elseBranch);
612  }
613 
614  // This overload is selected if the range of cases is an IntegralRange
615  template <class Result, class T, class Value, class Branches, class ElseBranch>
616  constexpr Result switchCases(IntegralRange<T> range, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
617  {
618  return range.contains(value) ? branches(T(value)) : elseBranch();
619  }
620 
621  // This overload is selected if the range of cases is a StaticIntegralRange
622  template <class Result, class T, T to, T from, class Value, class Branches, class ElseBranch>
623  constexpr Result switchCases(StaticIntegralRange<T, to, from> range, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
624  {
625  using seq = typename decltype(range)::integer_sequence;
626  return Impl::switchCases<Result>(seq{}, value, branches, elseBranch);
627  }
628 
629 } // namespace Impl
630 
631 
632 
660 template<class Cases, class Value, class Branches, class ElseBranch>
661 constexpr decltype(auto) switchCases(const Cases& cases, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
662 {
663  return Impl::switchCases<decltype(elseBranch())>(cases, value, std::forward<Branches>(branches), std::forward<ElseBranch>(elseBranch));
664 }
665 
685 template<class Cases, class Value, class Branches>
686 constexpr void switchCases(const Cases& cases, const Value& value, Branches&& branches)
687 {
688  Impl::switchCases<void>(cases, value, std::forward<Branches>(branches),
689  []{ assert(false && "value not found in range"); });
690 }
691 
710 template <class T, class Value, class Branches>
711 constexpr void switchCases(IntegralRange<T> range, const Value& value, Branches&& branches)
712 {
713  assert(range.contains(value) && "value not found in range");
714  branches(T(value));
715 }
716 
717 } // namespace Hybrid
718 } // namespace Dune
719 
720 
721 #endif // #ifndef DUNE_COMMON_HYBRIDUTILITIES_HH
decltype(auto) constexpr elementAt(Container &&c, Index &&i)
Get element at given position from container.
Definition: hybridutilities.hh:131
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:489
constexpr HybridFunctor< Functor > hybridFunctor(const Functor &)
Returns an HybridFunctor adaptor.
Definition: hybridutilities.hh:464
constexpr auto plus
Function object for performing addition.
Definition: hybridutilities.hh:533
constexpr auto minus
Function object for performing subtraction.
Definition: hybridutilities.hh:555
I i
Definition: hybridmultiindex.hh:328
Utilities for reduction like operations on ranges.
static integer range for use in range-based for loops
Definition: rangeutilities.hh:223
Dune namespace
Definition: alignedallocator.hh:12
Check if T is an std::integral_constant<I, i>
Definition: typetraits.hh:383
Utilities for type computations, constraining overloads, ...
static constexpr IntegralRange< std::decay_t< T > > range(T &&from, U &&to) noexcept
free standing function for setting up a range based for loop over an integer range for (auto i: range...
Definition: rangeutilities.hh:288
Adapter of a hybrid functor that maintains results hybrid.
Definition: hybridutilities.hh:423
Definition: binaryfunctions.hh:33
constexpr auto integralRange(const Begin &begin, const End &end)
Create an integral range.
Definition: hybridutilities.hh:177
Helper class for tagging priorities.
Definition: typeutilities.hh:86
constexpr auto min
Function object that returns the smaller of the given values.
Definition: hybridutilities.hh:511
Implements a vector constructed from a given type representing a field and a compile-time given size...
constexpr index_constant< 0 > _0
Compile time index with value 0.
Definition: indices.hh:52
Helper class for tagging priorities.
Definition: typeutilities.hh:72
constexpr auto equal_to
Function object for performing equality comparison.
Definition: hybridutilities.hh:577
dynamic integer range for use in range-based for loops
Definition: rangeutilities.hh:170
void ifElse(const Condition &condition, IfFunc &&ifFunc)
A conditional expression.
Definition: hybridutilities.hh:362
constexpr T accumulate(Range &&range, T value, F &&f)
Accumulate values.
Definition: hybridutilities.hh:284
decltype(auto) constexpr switchCases(const Cases &cases, const Value &value, Branches &&branches, ElseBranch &&elseBranch)
Switch statement.
Definition: hybridutilities.hh:661
decltype(auto) ifElse(const Condition &condition, IfFunc &&ifFunc, ElseFunc &&elseFunc)
A conditional expression.
Definition: hybridutilities.hh:349
constexpr auto size(const T &t)
Size query.
Definition: hybridutilities.hh:78
STL namespace.
Traits for type conversions and type information.
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:261
constexpr auto integralRange(const End &end)
Create an integral range starting from 0.
Definition: hybridutilities.hh:196
Check if T is an integral constant or any type derived from std::integral_constant.
Definition: typetraits.hh:409