Dune Core Modules (2.9.1)

hybridutilities.hh
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
14#include <dune/common/indices.hh>
15#include <dune/common/assertandreturn.hh>
17
18
19
20namespace Dune {
21namespace Hybrid {
22
23namespace 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
81template<class T>
82constexpr auto size(const T& t)
83{
84 return Impl::size(t, PriorityTag<42>());
85}
86
87
88
89namespace 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
134template<class Container, class Index>
135constexpr 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
142namespace 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
183template<class Begin, class End>
184constexpr auto integralRange(const Begin& begin, const End& end)
185{
186 return Impl::integralRange(begin, end, PriorityTag<42>());
187}
188
202template<class End>
203constexpr auto integralRange(const End& end)
204{
206}
207
208
209
210namespace 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
267template<class Range, class F>
268constexpr void forEach(Range&& range, F&& f)
269{
270 Impl::forEach(std::forward<Range>(range), std::forward<F>(f), PriorityTag<42>());
271}
272
273
274
290template<class Range, class T, class F>
291constexpr 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
301namespace 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
355template<class Condition, class IfFunc, class ElseFunc>
356decltype(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
368template<class Condition, class IfFunc>
369void ifElse(const Condition& condition, IfFunc&& ifFunc)
370{
371 ifElse(condition, std::forward<IfFunc>(ifFunc), [](auto&&) {});
372}
373
374
375
376namespace 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
401template<class T1, class T2>
402constexpr 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
409namespace 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
460template<class Cases, class Value, class Branches, class ElseBranch>
461constexpr 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
486template<class Cases, class Value, class Branches>
487constexpr 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
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
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:53
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
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 void switchCases(const Cases &cases, const Value &value, Branches &&branches)
Switch statement.
Definition: hybridutilities.hh:487
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
Dune namespace.
Definition: alignedallocator.hh:13
Utilities for reduction like operations on ranges.
Check if T is an std::integral_constant<I, i>
Definition: typetraits.hh:384
Helper class for tagging priorities.
Definition: typeutilities.hh:73
Traits for type conversions and type information.
Utilities for type computations, constraining overloads, ...
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 21, 23:30, 2024)