Dune Core Modules (2.6.0)

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#ifndef DUNE_COMMON_HYBRIDUTILITIES_HH
4#define DUNE_COMMON_HYBRIDUTILITIES_HH
5
6#include <tuple>
7#include <utility>
8
12#include <dune/common/indices.hh>
13#include <dune/common/assertandreturn.hh>
14#include <dune/common/unused.hh>
15
16
17
18namespace Dune {
19namespace Hybrid {
20
21namespace 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
79template<class T>
80constexpr auto size(const T& t)
81{
82 return Impl::size(t, PriorityTag<42>());
83}
84
85
86
87namespace 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
132template<class Container, class Index>
133constexpr 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
140namespace Impl {
141
142 template<class Begin, class End>
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
220template<class Begin, class End>
221constexpr auto integralRange(const Begin& begin, const End& end)
222{
223 return Impl::integralRange(begin, end, PriorityTag<42>());
224}
225
239template<class End>
240constexpr auto integralRange(const End& end)
241{
243}
244
245
246
247namespace 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
307template<class Range, class F>
308constexpr void forEach(Range&& range, F&& f)
309{
310 Impl::forEach(std::forward<Range>(range), std::forward<F>(f), PriorityTag<42>());
311}
312
313
314
330template<class Range, class T, class F>
331T 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
341namespace 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
388template<class Condition, class IfFunc, class ElseFunc>
389decltype(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
401template<class Condition, class IfFunc>
402void ifElse(const Condition& condition, IfFunc&& ifFunc)
403{
404 ifElse(condition, std::forward<IfFunc>(ifFunc), [](auto&& i) { DUNE_UNUSED_PARAMETER(i); });
405}
406
407
408
409namespace 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
434template<class T1, class T2>
435constexpr 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
442namespace 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
493template<class Cases, class Value, class Branches, class ElseBranch>
494constexpr 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
519template<class Cases, class Value, class Branches>
520constexpr 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
vector space out of a tensor product of fields.
Definition: fvector.hh:93
static integer range for use in range-based for loops
Definition: rangeutilities.hh:221
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:50
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:27
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
#define DUNE_ASSERT_AND_RETURN(C, X)
Asserts a condition and return on success in constexpr context.
Definition: assertandreturn.hh:20
#define DUNE_UNUSED_PARAMETER(parm)
A macro to mark intentionally unused function parameters with.
Definition: unused.hh:25
void ifElse(const Condition &condition, IfFunc &&ifFunc)
A conditional expression.
Definition: hybridutilities.hh:402
constexpr auto size(const T &t)
Size query.
Definition: hybridutilities.hh:80
constexpr auto integralRange(const End &end)
Create an integral range starting from 0.
Definition: hybridutilities.hh:240
constexpr auto equals(T1 &&t1, T2 &&t2)
Equality comparison.
Definition: hybridutilities.hh:435
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:308
T accumulate(Range &&range, T value, F &&f)
Accumulate values.
Definition: hybridutilities.hh:331
constexpr void switchCases(const Cases &cases, const Value &value, Branches &&branches)
Switch statement.
Definition: hybridutilities.hh:520
constexpr decltype(auto) elementAt(Container &&c, Index &&i)
Get element at given position from container.
Definition: hybridutilities.hh:133
Dune namespace.
Definition: alignedallocator.hh:10
Helper class for tagging priorities.
Definition: typeutilities.hh:71
Traits for type conversions and type information.
Utilities for type computations, constraining overloads, ...
Definition of the DUNE_UNUSED macro for the case that config.h is not available.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)