dune-functions 2.9.0
indexaccess.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_FUNCTIONS_COMMON_INDEX_ACCESS_HH
4#define DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH
5
6
7#include <utility>
8#include <type_traits>
9
10#include <dune/common/typetraits.hh>
11#include <dune/common/concept.hh>
12#include <dune/common/hybridutilities.hh>
13
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(
39 c[Dune::Indices::_0]
40 );
41};
42
43} // namespace Concept
44
45} // namespace Imp
46
47
48
61template<class C, class I, class F,
62 typename std::enable_if< Dune::models<Imp::Concept::HasDynamicIndexAccess<I>, C>(), int>::type = 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 typename std::enable_if< not Dune::models<Imp::Concept::HasDynamicIndexAccess<I>, C>(), int>::type = 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 private:
148 const Index& index_;
149 };
150
151 template<class Index, std::size_t offset=1>
152 class ShiftedStaticMultiIndex
153 {
154 public:
155 ShiftedStaticMultiIndex(const Index& index) :
156 index_(index)
157 {}
158
159 template<std::size_t i>
160 auto operator[](Dune::index_constant<i>) const
161 {
162 if constexpr (i<size()) {
163 return index_[Dune::index_constant<i+offset>{}];
164 } else {
165 return Dune::index_constant<0>{};
166 }
167 }
168
172 ShiftedStaticMultiIndex<Index, offset+1> pop() const
173 {
174 return {index_};
175 }
176
177 static constexpr std::size_t size()
178 {
179 auto fullSize = decltype(Hybrid::size(std::declval<Index>()))::value;
180 if (offset < fullSize)
181 return fullSize - offset;
182 else
183 return 0;
184 }
185
186 private:
187 const Index& index_;
188 };
189
195 template<std::size_t offset, class Index>
196 ShiftedDynamicMultiIndex<Index, offset> shiftedDynamicMultiIndex(const Index& index)
197 {
198 return {index};
199 }
200
201 template<std::size_t offset, class Index>
202 ShiftedStaticMultiIndex<Index, offset> shiftedStaticMultiIndex(const Index& index)
203 {
204 return {index};
205 }
206
207} // namespace Imp
208
209
210
211
212namespace Imp {
213
214template<class Result, class Index>
215struct MultiIndexResolver
216{
217 MultiIndexResolver(const Index& index) :
218 index_(index)
219 {}
220
221 template<class C,
222 typename std::enable_if<not std::is_convertible<C&, Result>::value, int>::type = 0>
223 Result operator()(C&& c)
224 {
225 auto&& subIndex = Imp::shiftedDynamicMultiIndex<1>(index_);
226 auto&& subIndexResolver = MultiIndexResolver<Result, decltype(subIndex)>(subIndex);
227 return (Result)(hybridIndexAccess(c, index_[Dune::Indices::_0], subIndexResolver));
228 }
229
230 template<class C,
231 typename std::enable_if<std::is_convertible<C&, Result>::value, int>::type = 0>
232 Result operator()(C&& c)
233 {
234 return (Result)(std::forward<C>(c));
235 }
236
237 const Index& index_;
238};
239
240} // namespace Imp
241
242
243
262template<class Result, class C, class MultiIndex>
263Result hybridMultiIndexAccess(C&& c, const MultiIndex& index)
264{
265
266 Imp::MultiIndexResolver<Result, MultiIndex> multiIndexResolver(index);
267 return multiIndexResolver(c);
268}
269
270
271
272
273
274
275namespace Imp {
276
277 template<class C, class MultiIndex, class IsFinal>
278 constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex, const IsFinal& isFinal)
279 {
280 // If c is already considered final simply return it,
281 // else resolve the next multiIndex entry.
282 return Hybrid::ifElse(isFinal(c), [&, c = forwardCapture(std::forward<C>(c))](auto) -> decltype(auto) {
283 assert(multiIndex.size() == 0);
284 return c.forward();
285 }, [&](auto) -> decltype(auto) {
286 auto hasDynamicAccess = callableCheck([](auto&& cc) -> std::void_t<decltype(cc[0])> {});
287
288 // Split multiIndex into first entry and remaining ones.
289 auto i = multiIndex[0];
290 auto tail = multiIndex.pop();
291
292 // Resolve first multiIndex entry by c[multiIndex[0]] and
293 // continue resolving with the remaining remaining ones.
294 // If c has a dynamic operator[] this is straight forward.
295 // Else the dynamic multiIndex[0] has to be translated into
296 // a static one using hybridIndexAccess.
297 return Hybrid::ifElse(hasDynamicAccess(c), [&](auto id) -> decltype(auto) {
298 return Imp::resolveDynamicMultiIndex(id(c)[i], tail, isFinal);
299 }, [&](auto id) -> decltype(auto) {
300 // auto indexRange = range(Hybrid::size(id(c)));
301 auto indexRange = typename decltype(range(Hybrid::size(id(c))))::integer_sequence();
302 return Hybrid::switchCases(indexRange, i, [&](auto static_i) -> decltype(auto){
303 // Do rescursion with static version of i
304 return Imp::resolveDynamicMultiIndex(id(c)[static_i], tail, isFinal);
305 }, [&]() -> decltype(auto){
306 // As fallback we use c[0] this is needed, because there must be one branch that matches.
307 return Imp::resolveDynamicMultiIndex(id(c)[Dune::Indices::_0], tail, isFinal);
308 });
309 });
310 });
311 }
312
313 template<class C, class MultiIndex>
314 constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
315 {
316 auto isExhausted = Hybrid::equals(Hybrid::size(multiIndex), Dune::Indices::_0);
317 return Hybrid::ifElse(isExhausted, [&, c = forwardCapture(std::forward<C>(c))](auto) -> decltype(auto) {
318 return c.forward();
319 }, [&](auto id) -> decltype(auto) {
320 auto head = multiIndex[Dune::Indices::_0];
321 auto tail = multiIndex.pop();
322
323 return Imp::resolveStaticMultiIndex(id(c)[head], tail);
324 });
325 }
326
327} // namespace Imp
328
329
330
353template<class C, class MultiIndex, class IsFinal>
354constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex, const IsFinal& isFinal)
355{
356 return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), isFinal);
357}
358
375template<class C, class MultiIndex>
376constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex)
377{
378 auto hasNoIndexAccess = negatePredicate(callableCheck([](auto&& cc) -> std::void_t<decltype(cc[Dune::Indices::_0])> {}));
379 return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), hasNoIndexAccess);
380}
381
397template<class C, class MultiIndex>
398constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
399{
400 return Imp::resolveStaticMultiIndex(std::forward<C>(c), Imp::shiftedStaticMultiIndex<0>(multiIndex));
401}
402
403
404
405} // namespace Dune::Functions
406} // namespace Dune
407
408
409
410#endif // DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH
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:398
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:376
constexpr decltype(auto) resolveDynamicMultiIndex(C &&c, const MultiIndex &multiIndex, const IsFinal &isFinal)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:354
Result hybridMultiIndexAccess(C &&c, const MultiIndex &index)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:263
auto negatePredicate(Check check)
Negate given predicate.
Definition: utility.hh:304
Definition: polynomial.hh:10
auto forwardCapture(T &&t)
Create a capture object for perfect forwarding.
Definition: utility.hh:372