DUNE PDELab (git)

indexaccess.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_FUNCTIONS_COMMON_INDEX_ACCESS_HH
4#define DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH
5
6
7#include <utility>
8#include <type_traits>
9
12#include <dune/common/hybridutilities.hh>
13
14#include <dune/functions/common/utility.hh>
15
16
17
18namespace Dune {
19namespace Functions {
20
21
22namespace Imp {
23
24namespace Concept {
25
26template<class size_type>
27struct HasDynamicIndexAccess
28{
29 template<class C>
30 auto require(C&& c) -> decltype(
31 c[std::declval<size_type>()]
32 );
33};
34
35struct HasStaticIndexAccess
36{
37 template<class C>
38 auto require(C&& c) -> decltype(
40 );
41};
42
43} // namespace Concept
44
45} // namespace Imp
46
47
48
61template<class C, class I, class F,
62 std::enable_if_t< Dune::models<Imp::Concept::HasDynamicIndexAccess<I>, C>(), int> = 0>
63auto hybridIndexAccess(C&& c, const I& i, F&& f)
64 -> decltype(f(c[i]))
65{
66 return f(c[i]);
67}
68
86template<class C, class I, class F,
87 std::enable_if_t< not Dune::models<Imp::Concept::HasDynamicIndexAccess<I>, C>(), int> = 0>
88decltype(auto) hybridIndexAccess(C&& c, const I& i, F&& f)
89{
90 using Size = decltype(Hybrid::size(c));
91 return Hybrid::switchCases(std::make_index_sequence<Size::value>(), i,
92 [&](const auto& ii) -> decltype(auto){
93 return f(c[ii]);
94 }, [&]() -> decltype(auto){
95 return f(c[Dune::Indices::_0]);
96 });
97}
98
99
100namespace Imp {
101
115 template<class Index, std::size_t offset=1>
116 class ShiftedDynamicMultiIndex
117 {
118 public:
119 ShiftedDynamicMultiIndex(const Index& index) :
120 index_(index)
121 {}
122
123 std::size_t operator[](std::size_t position) const
124 {
125 if (position<size())
126 return index_[position+offset];
127 else
128 return 0;
129 }
130
134 ShiftedDynamicMultiIndex<Index, offset+1> pop() const
135 {
136 return {index_};
137 }
138
139 std::size_t size() const
140 {
141 if (offset < index_.size())
142 return index_.size() - offset;
143 else
144 return 0;
145 }
146
147 const Index& originalIndex() const
148 {
149 return index_;
150 }
151
152 private:
153 const Index& index_;
154 };
155
156 template<class Index, std::size_t offset=1>
157 class ShiftedStaticMultiIndex
158 {
159 public:
160 ShiftedStaticMultiIndex(const Index& index) :
161 index_(index)
162 {}
163
164 template<std::size_t i>
165 auto operator[](Dune::index_constant<i>) const
166 {
167 if constexpr (i<size()) {
168 return index_[Dune::index_constant<i+offset>{}];
169 } else {
171 }
172 }
173
177 ShiftedStaticMultiIndex<Index, offset+1> pop() const
178 {
179 return {index_};
180 }
181
182 static constexpr std::size_t size()
183 {
184 auto fullSize = decltype(Hybrid::size(std::declval<Index>()))::value;
185 if (offset < fullSize)
186 return fullSize - offset;
187 else
188 return 0;
189 }
190
191 private:
192 const Index& index_;
193 };
194
200 template<std::size_t offset, class Index>
201 ShiftedDynamicMultiIndex<Index, offset> shiftedDynamicMultiIndex(const Index& index)
202 {
203 return {index};
204 }
205
214 template<std::size_t offset, class Index, std::size_t oldOffset>
215 ShiftedDynamicMultiIndex<Index, offset+oldOffset> shiftedDynamicMultiIndex(const ShiftedDynamicMultiIndex<Index, oldOffset>& index)
216 {
217 return {index.originalIndex()};
218 }
219
220 template<std::size_t offset, class Index>
221 ShiftedStaticMultiIndex<Index, offset> shiftedStaticMultiIndex(const Index& index)
222 {
223 return {index};
224 }
225
226} // namespace Imp
227
228
229
230
231namespace Imp {
232
233template<class Result, class Index>
234struct MultiIndexResolver
235{
236 MultiIndexResolver(const Index& index) :
237 index_(index)
238 {}
239
240 template<class C,
241 std::enable_if_t<not std::is_convertible_v<C&, Result>, int> = 0>
242 Result operator()(C&& c)
243 {
244 auto&& subIndex = Imp::shiftedDynamicMultiIndex<1>(index_);
245 auto&& subIndexResolver = MultiIndexResolver<Result, decltype(subIndex)>(subIndex);
246 return (Result)(hybridIndexAccess(c, index_[Dune::Indices::_0], subIndexResolver));
247 }
248
249 template<class C,
250 std::enable_if_t<std::is_convertible_v<C&, Result>, int> = 0>
251 Result operator()(C&& c)
252 {
253 return (Result)(std::forward<C>(c));
254 }
255
256 const Index& index_;
257};
258
259} // namespace Imp
260
261
262
281template<class Result, class C, class MultiIndex>
282Result hybridMultiIndexAccess(C&& c, const MultiIndex& index)
283{
284
285 Imp::MultiIndexResolver<Result, MultiIndex> multiIndexResolver(index);
286 return multiIndexResolver(c);
287}
288
289
290
291
292
293
294namespace Imp {
295
296 template<class C, class MultiIndex, class IsFinal>
297 constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex, const IsFinal& isFinal)
298 {
299 // If c is already considered final simply return it,
300 // else resolve the next multiIndex entry.
301 return Hybrid::ifElse(isFinal(c), [&, c = forwardCapture(std::forward<C>(c))](auto) -> decltype(auto) {
302 assert(multiIndex.size() == 0);
303 return c.forward();
304 }, [&](auto) -> decltype(auto) {
305 auto hasDynamicAccess = callableCheck([](auto&& cc) -> std::void_t<decltype(cc[0])> {});
306
307 // Split multiIndex into first entry and remaining ones.
308 auto i = multiIndex[0];
309 auto tail = multiIndex.pop();
310
311 // Resolve first multiIndex entry by c[multiIndex[0]] and
312 // continue resolving with the remaining remaining ones.
313 // If c has a dynamic operator[] this is straight forward.
314 // Else the dynamic multiIndex[0] has to be translated into
315 // a static one using hybridIndexAccess.
316 return Hybrid::ifElse(hasDynamicAccess(c), [&](auto id) -> decltype(auto) {
317 return Imp::resolveDynamicMultiIndex(id(c)[i], tail, isFinal);
318 }, [&](auto id) -> decltype(auto) {
319 // auto indexRange = range(Hybrid::size(id(c)));
320 auto indexRange = typename decltype(range(Hybrid::size(id(c))))::integer_sequence();
321 return Hybrid::switchCases(indexRange, i, [&](auto static_i) -> decltype(auto){
322 // Do rescursion with static version of i
323 return Imp::resolveDynamicMultiIndex(id(c)[static_i], tail, isFinal);
324 }, [&]() -> decltype(auto){
325 // As fallback we use c[0] this is needed, because there must be one branch that matches.
327 });
328 });
329 });
330 }
331
332 template<class C, class MultiIndex>
333 constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
334 {
335 auto isExhausted = Hybrid::equals(Hybrid::size(multiIndex), Dune::Indices::_0);
336 return Hybrid::ifElse(isExhausted, [&, c = forwardCapture(std::forward<C>(c))](auto) -> decltype(auto) {
337 return c.forward();
338 }, [&](auto id) -> decltype(auto) {
339 auto head = multiIndex[Dune::Indices::_0];
340 auto tail = multiIndex.pop();
341
342 return Imp::resolveStaticMultiIndex(id(c)[head], tail);
343 });
344 }
345
346} // namespace Imp
347
348
349
372template<class C, class MultiIndex, class IsFinal>
373constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex, const IsFinal& isFinal)
374{
375 return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), isFinal);
376}
377
394template<class C, class MultiIndex>
395constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex)
396{
397 auto hasNoIndexAccess = negatePredicate(callableCheck([](auto&& cc) -> std::void_t<decltype(cc[Dune::Indices::_0])> {}));
398 return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), hasNoIndexAccess);
399}
400
416template<class C, class MultiIndex>
417constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
418{
419 return Imp::resolveStaticMultiIndex(std::forward<C>(c), Imp::shiftedStaticMultiIndex<0>(multiIndex));
420}
421
422
423
424} // namespace Dune::Functions
425} // namespace Dune
426
427
428
429#endif // DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH
Infrastructure for concepts.
Traits for type conversions and type information.
constexpr index_constant< 0 > _0
Compile time index with value 0.
Definition: indices.hh:52
std::integral_constant< std::size_t, i > index_constant
An index constant with value i.
Definition: indices.hh:29
typename Impl::voider< Types... >::type void_t
Is void for all valid input types. The workhorse for C++11 SFINAE-techniques.
Definition: typetraits.hh:40
constexpr decltype(auto) switchCases(const Cases &cases, const Value &value, Branches &&branches, ElseBranch &&elseBranch)
Switch statement.
Definition: hybridutilities.hh:655
decltype(auto) ifElse(const Condition &condition, IfFunc &&ifFunc, ElseFunc &&elseFunc)
A conditional expression.
Definition: hybridutilities.hh:344
constexpr auto equals
Function object for performing equality comparison.
Definition: hybridutilities.hh:572
auto hybridIndexAccess(C &&c, const I &i, F &&f) -> decltype(f(c[i]))
Provide operator[] index-access for containers.
Definition: indexaccess.hh:63
constexpr decltype(auto) resolveStaticMultiIndex(C &&c, const MultiIndex &multiIndex)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:417
auto callableCheck(Expression f)
Create a predicate for checking validity of expressions.
Definition: utility.hh:279
constexpr decltype(auto) resolveDynamicMultiIndex(C &&c, const MultiIndex &multiIndex)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:395
Result hybridMultiIndexAccess(C &&c, const MultiIndex &index)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:282
auto negatePredicate(Check check)
Negate given predicate.
Definition: utility.hh:304
Dune namespace.
Definition: alignedallocator.hh:13
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75
constexpr std::integer_sequence< T, II... > tail(std::integer_sequence< T, I0, II... >)
For a sequence [head,tail...) return the tail sequence.
Definition: integersequence.hh:58
constexpr std::integral_constant< T, I0 > head(std::integer_sequence< T, I0, II... >)
For a sequence [head,tail...) return the single head element.
Definition: integersequence.hh:53
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)