dune-common 3.0-git
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
12
13
14
15namespace Dune {
16namespace Hybrid {
17
18namespace Impl {
19
20 // Try if tuple_size is implemented for class
21 template<class T, int i>
22 constexpr auto size(const Dune::FieldVector<T, i>*, const PriorityTag<5>&)
23 -> decltype(std::integral_constant<std::size_t,i>())
24 {
25 return {};
26 }
27
28 // Try if we have an instance of std::integer_sequence
29 template<class T, T... t, class Index>
30 constexpr auto size(std::integer_sequence<T, t...>, PriorityTag<4>)
31 {
32 using sizeAsType = std::tuple_size<decltype(std::make_tuple(t...))>;
33 return std::integral_constant<std::size_t, sizeAsType::value>();
34 }
35
36 // Try if tuple_size is implemented for class
37 template<class T>
38 constexpr auto size(const T*, const PriorityTag<3>&)
39 -> decltype(std::integral_constant<std::size_t,std::tuple_size<T>::value>())
40 {
41 return {};
42 }
43
44 // Try if there's a static constexpr size()
45 template<class T>
46 constexpr auto size(const T*, const PriorityTag<1>&)
47 -> decltype(std::integral_constant<std::size_t,T::size()>())
48 {
49 return {};
50 }
51
52 // As a last resort try if there's a static constexpr size()
53 template<class T>
54 constexpr auto size(const T* t, const PriorityTag<0>&)
55 {
56 return t->size();
57 }
58
59} // namespace Impl
60
61
62
84template<class T>
85constexpr auto size(const T& t)
86{
87 return Impl::size(&t, PriorityTag<42>());
88}
89
90
91
92namespace Impl {
93
94 template<class Container, class Index,
95 std::enable_if_t<IsTuple<std::decay_t<Container>>::value, int> = 0>
96 constexpr decltype(auto) elementAt(Container&& c, Index&&, PriorityTag<2>)
97 {
98 return std::get<std::decay_t<Index>::value>(c);
99 }
100
101 template<class T, T... t, class Index>
102 constexpr decltype(auto) elementAt(std::integer_sequence<T, t...> c, Index&&, PriorityTag<1>)
103 {
104 return std::get<std::decay_t<Index>::value>(std::make_tuple(std::integral_constant<T, t>()...));
105 }
106
107 template<class Container, class Index>
108 constexpr decltype(auto) elementAt(Container&& c, Index&& i, PriorityTag<0>)
109 {
110 return c[i];
111 }
112
113} // namespace Impl
114
115
116
137template<class Container, class Index>
138constexpr decltype(auto) elementAt(Container&& c, Index&& i)
139{
140 return Impl::elementAt(std::forward<Container>(c), std::forward<Index>(i), PriorityTag<42>());
141}
142
143
144
145namespace Impl {
146
147 template<class Begin, class End>
149 {
150 public:
151
152 template<std::size_t i>
154 {
156 }
157
158 static constexpr auto size()
159 {
160 return std::integral_constant<typename Begin::value_type, End::value - Begin::value>();
161 }
162 };
163
164 template<class T>
166 {
167 public:
168 constexpr DynamicIntegralRange(const T& begin, const T& end):
169 begin_(begin),
170 end_(end)
171 {}
172
173 constexpr auto size() const
174 {
175 return end_ - begin_;
176 }
177
178 constexpr T operator[](const T&i) const
179 { return begin_+i; }
180
181 private:
182 T begin_;
183 T end_;
184 };
185
186 template<class Begin, class End,
187 std::enable_if_t<IsIntegralConstant<Begin>::value and IsIntegralConstant<End>::value, int> = 0>
188 constexpr auto integralRange(const Begin& begin, const End& end, const PriorityTag<1>&)
189 {
190 static_assert(Begin::value <= End::value, "You cannot create an integralRange where end<begin");
192 }
193
194 // This should be constexpr but gcc-4.9 does not support
195 // the relaxed constexpr requirements. Hence for beeing
196 // constexpr the function body can only contain a return
197 // statement and no assertion before this.
198 template<class Begin, class End>
199 auto integralRange(const Begin& begin, const End& end, const PriorityTag<0>&)
200 {
201 assert(begin <= end);
202 return Impl::DynamicIntegralRange<End>(begin, end);
203 }
204
205} // namespace Impl
206
207
208
226template<class Begin, class End>
227constexpr auto integralRange(const Begin& begin, const End& end)
228{
229 return Impl::integralRange(begin, end, PriorityTag<42>());
230}
231
245template<class End>
246constexpr auto integralRange(const End& end)
247{
249}
250
251
252
253namespace Impl {
254
255 template<class T>
256 void evaluateFoldExpression(std::initializer_list<T>&&)
257 {}
258
259 template<class Range, class F, class Index, Index... i>
260 constexpr void forEachIndex(Range&& range, F&& f, std::integer_sequence<Index, i...>)
261 {
262 evaluateFoldExpression<int>({(f(Hybrid::elementAt(range, std::integral_constant<Index,i>())), 0)...});
263 }
264
265 template<class Range, class F,
266 std::enable_if_t<IsIntegralConstant<decltype(Hybrid::size(std::declval<Range>()))>::value, int> = 0>
267 constexpr void forEach(Range&& range, F&& f, PriorityTag<1>)
268 {
269 auto size = Hybrid::size(range);
270 auto indices = std::make_index_sequence<size>();
271 forEachIndex(std::forward<Range>(range), std::forward<F>(f), indices);
272 }
273
274 template<class Range, class F>
275 constexpr void forEach(Range&& range, F&& f, PriorityTag<0>)
276 {
277 for(std::size_t i=0; i<range.size(); ++i)
278 f(range[i]);
279 // \todo Switch to real range for once DynamicIntegralRange has proper iterators
280 // for(auto e : range)
281 // f(e);
282 }
283
284} // namespace Impl
285
286
287
306template<class Range, class F>
307constexpr void forEach(Range&& range, F&& f)
308{
309 Impl::forEach(std::forward<Range>(range), std::forward<F>(f), PriorityTag<42>());
310}
311
312
313
329template<class Range, class T, class F>
330T accumulate(Range&& range, T value, F&& f)
331{
332 forEach(std::forward<Range>(range), [&](auto&& entry) {
333 value = f(value, entry);
334 });
335 return value;
336}
337
338
339
340namespace Impl {
341
342 template<class IfFunc, class ElseFunc>
343 constexpr decltype(auto) ifElse(std::true_type, IfFunc&& ifFunc, ElseFunc&& elseFunc)
344 {
345 return ifFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
346 }
347
348 template<class IfFunc, class ElseFunc>
349 constexpr decltype(auto) ifElse(std::false_type, IfFunc&& ifFunc, ElseFunc&& elseFunc)
350 {
351 return elseFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
352 }
353
354 template<class IfFunc, class ElseFunc>
355 decltype(auto) ifElse(const bool& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
356 {
357 if (condition)
358 return ifFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
359 else
360 return elseFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
361 }
362
363} // namespace Impl
364
365
366
387template<class Condition, class IfFunc, class ElseFunc>
388decltype(auto) ifElse(const Condition& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
389{
390 return Impl::ifElse(condition, std::forward<IfFunc>(ifFunc), std::forward<ElseFunc>(elseFunc));
391}
392
400template<class Condition, class IfFunc>
401void ifElse(const Condition& condition, IfFunc&& ifFunc)
402{
403 ifElse(condition, std::forward<IfFunc>(ifFunc), [](auto&& i) {});
404}
405
406
407
408namespace Impl {
409
410 template<class T1, class T2>
411 constexpr auto equals(const T1& t1, const T2& t2, PriorityTag<1>) -> decltype(T1::value, T2::value, std::integral_constant<bool,T1::value == T2::value>())
412 { return {}; }
413
414 template<class T1, class T2>
415 constexpr auto equals(const T1& t1, const T2& t2, PriorityTag<0>)
416 {
417 return t1==t2;
418 }
419
420} // namespace Impl
421
422
423
433template<class T1, class T2>
434constexpr auto equals(T1&& t1, T2&& t2)
435{
436 return Impl::equals(std::forward<T1>(t1), std::forward<T2>(t2), PriorityTag<1>());
437}
438
439
440
441namespace Impl {
442
443 template<class Result, class T, class Value, class Branches, class ElseBranch>
444 constexpr Result switchCases(std::integer_sequence<T>, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
445 {
446 return elseBranch();
447 }
448
449 template<class Result, class T, T t0, T... tt, class Value, class Branches, class ElseBranch>
450 constexpr Result switchCases(std::integer_sequence<T, t0, tt...>, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
451 {
452 return ifElse(
453 Hybrid::equals(std::integral_constant<T, t0>(), value),
454 [&](auto id) -> decltype(auto) {
455 return id(branches)(std::integral_constant<T, t0>());
456 }, [&](auto id) -> decltype(auto) {
457 return Impl::switchCases<Result>(id(std::integer_sequence<T, tt...>()), value, branches, elseBranch);
458 });
459 }
460
461} // namespace Impl
462
463
464
492template<class Cases, class Value, class Branches, class ElseBranch>
493constexpr decltype(auto) switchCases(const Cases& cases, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
494{
495 return Impl::switchCases<decltype(elseBranch())>(cases, value, std::forward<Branches>(branches), std::forward<ElseBranch>(elseBranch));
496}
497
518template<class Cases, class Value, class Branches>
519constexpr void switchCases(const Cases& cases, const Value& value, Branches&& branches)
520{
521 return Impl::switchCases<void>(cases, value, std::forward<Branches>(branches), []() {});
522}
523
524
525} // namespace Hybrid
526} // namespace Dune
527
528
529#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 type computations, constraining overloads, ...
constexpr index_constant< 0 > _0
Compile time index with value 0.
Definition indices.hh:49
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition indices.hh:26
constexpr auto size(const T &t)
Size query.
Definition hybridutilities.hh:85
constexpr auto equals(T1 &&t1, T2 &&t2)
Equality comparison.
Definition hybridutilities.hh:434
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition hybridutilities.hh:307
constexpr decltype(auto) switchCases(const Cases &cases, const Value &value, Branches &&branches, ElseBranch &&elseBranch)
Switch statement.
Definition hybridutilities.hh:493
T accumulate(Range &&range, T value, F &&f)
Accumulate values.
Definition hybridutilities.hh:330
decltype(auto) ifElse(const Condition &condition, IfFunc &&ifFunc, ElseFunc &&elseFunc)
A conditional expression.
Definition hybridutilities.hh:388
constexpr auto integralRange(const Begin &begin, const End &end)
Create an integral range.
Definition hybridutilities.hh:227
constexpr decltype(auto) elementAt(Container &&c, Index &&i)
Get element at given position from container.
Definition hybridutilities.hh:138
Dune namespace.
Definition alignment.hh:11
constexpr auto integralRange(const Begin &begin, const End &end, const PriorityTag< 1 > &)
Definition hybridutilities.hh:188
constexpr decltype(auto) elementAt(Container &&c, Index &&, PriorityTag< 2 >)
Definition hybridutilities.hh:96
constexpr auto size(const Dune::FieldVector< T, i > *, const PriorityTag< 5 > &) -> decltype(std::integral_constant< std::size_t, i >())
Definition hybridutilities.hh:22
vector space out of a tensor product of fields.
Definition fvector.hh:93
Definition hybridutilities.hh:149
static constexpr auto size()
Definition hybridutilities.hh:158
constexpr auto operator[](Dune::index_constant< i >) const
Definition hybridutilities.hh:153
Definition hybridutilities.hh:166
constexpr T operator[](const T &i) const
Definition hybridutilities.hh:178
constexpr DynamicIntegralRange(const T &begin, const T &end)
Definition hybridutilities.hh:168
constexpr auto size() const
Definition hybridutilities.hh:173
Check if T is an std::integral_constant<I, i>
Definition typetraits.hh:532
Helper class for tagging priorities.
Definition typeutilities.hh:60