DUNE-FUNCTIONS (2.7)

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
10#include <dune/common/typetraits.hh>
11#include <dune/common/concept.hh>
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(
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 auto isContained = Dune::Std::bool_constant<(i<size())>{};
163 return Hybrid::ifElse(isContained, [&](auto id) {
164 return id(index_)[Dune::index_constant<i+offset>{}];
165 }, [](auto id) {
166 return Dune::Indices::_0;
167 });
168 }
169
173 ShiftedStaticMultiIndex<Index, offset+1> pop() const
174 {
175 return {index_};
176 }
177
178 static constexpr std::size_t size()
179 {
180 auto fullSize = decltype(Hybrid::size(std::declval<Index>()))::value;
181 if (offset < fullSize)
182 return fullSize - offset;
183 else
184 return 0;
185 }
186
187 private:
188 const Index& index_;
189 };
190
196 template<std::size_t offset, class Index>
197 ShiftedDynamicMultiIndex<Index, offset> shiftedDynamicMultiIndex(const Index& index)
198 {
199 return {index};
200 }
201
202 template<std::size_t offset, class Index>
203 ShiftedStaticMultiIndex<Index, offset> shiftedStaticMultiIndex(const Index& index)
204 {
205 return {index};
206 }
207
208} // namespace Imp
209
210
211
212
213namespace Imp {
214
215template<class Result, class Index>
216struct MultiIndexResolver
217{
218 MultiIndexResolver(const Index& index) :
219 index_(index)
220 {}
221
222 template<class C,
223 typename std::enable_if<not std::is_convertible<C&, Result>::value, int>::type = 0>
224 Result operator()(C&& c)
225 {
226 auto&& subIndex = Imp::shiftedDynamicMultiIndex<1>(index_);
227 auto&& subIndexResolver = MultiIndexResolver<Result, decltype(subIndex)>(subIndex);
228 return (Result)(hybridIndexAccess(c, index_[Dune::Indices::_0], subIndexResolver));
229 }
230
231 template<class C,
232 typename std::enable_if<std::is_convertible<C&, Result>::value, int>::type = 0>
233 Result operator()(C&& c)
234 {
235 return (Result)(std::forward<C>(c));
236 }
237
238 const Index& index_;
239};
240
241} // namespace Imp
242
243
244
263template<class Result, class C, class MultiIndex>
264Result hybridMultiIndexAccess(C&& c, const MultiIndex& index)
265{
266
267 Imp::MultiIndexResolver<Result, MultiIndex> multiIndexResolver(index);
268 return multiIndexResolver(c);
269}
270
271
272
273
274
275
276namespace Imp {
277
278 template<class C, class MultiIndex, class IsFinal>
279 constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex, const IsFinal& isFinal)
280 {
281 // If c is already considered final simply return it,
282 // else resolve the next multiIndex entry.
283 return Hybrid::ifElse(isFinal(c), [&, c = forwardCapture(std::forward<C>(c))](auto id) -> decltype(auto) {
284 assert(multiIndex.size() == 0);
285 return c.forward();
286 }, [&](auto id) -> decltype(auto) {
287 auto hasDynamicAccess = callableCheck([](auto&& cc) -> void_t<decltype(cc[0])> {});
288
289 // Split multiIndex into first entry and remaining ones.
290 auto i = multiIndex[0];
291 auto tail = multiIndex.pop();
292
293 // Resolve first multiIndex entry by c[multiIndex[0]] and
294 // continue resolving with the remaining remaining ones.
295 // If c has a dynamic operator[] this is straight forward.
296 // Else the dynamic multiIndex[0] has to be translated into
297 // a static one using hybridIndexAccess.
298 return Hybrid::ifElse(hasDynamicAccess(c), [&](auto id) -> decltype(auto) {
299 return Imp::resolveDynamicMultiIndex(id(c)[i], tail, isFinal);
300 }, [&](auto id) -> decltype(auto) {
301 // auto indexRange = range(Hybrid::size(id(c)));
302 auto indexRange = typename decltype(range(Hybrid::size(id(c))))::integer_sequence();
303 return Hybrid::switchCases(indexRange, i, [&](auto static_i) -> decltype(auto){
304 // Do rescursion with static version of i
305 return Imp::resolveDynamicMultiIndex(id(c)[static_i], tail, isFinal);
306 }, [&]() -> decltype(auto){
307 // As fallback we use c[0] this is needed, because there must be one branch that matches.
308 return Imp::resolveDynamicMultiIndex(id(c)[Dune::Indices::_0], tail, isFinal);
309 });
310 });
311 });
312 }
313
314 template<class C, class MultiIndex>
315 constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
316 {
317 auto isExhausted = Hybrid::equals(Hybrid::size(multiIndex), Dune::Indices::_0);
318 return Hybrid::ifElse(isExhausted, [&, c = forwardCapture(std::forward<C>(c))](auto id) -> decltype(auto) {
319 return c.forward();
320 }, [&](auto id) -> decltype(auto) {
321 auto head = multiIndex[Dune::Indices::_0];
322 auto tail = multiIndex.pop();
323
324 return Imp::resolveStaticMultiIndex(id(c)[head], tail);
325 });
326 }
327
328} // namespace Imp
329
330
331
354template<class C, class MultiIndex, class IsFinal>
355constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex, const IsFinal& isFinal)
356{
357 return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), isFinal);
358}
359
376template<class C, class MultiIndex>
377constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex)
378{
379 auto hasNoIndexAccess = negatePredicate(callableCheck([](auto&& cc) -> void_t<decltype(cc[Dune::Indices::_0])> {}));
380 return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), hasNoIndexAccess);
381}
382
398template<class C, class MultiIndex>
399constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
400{
401 return Imp::resolveStaticMultiIndex(std::forward<C>(c), Imp::shiftedStaticMultiIndex<0>(multiIndex));
402}
403
404
405
406} // namespace Dune::Functions
407} // namespace Dune
408
409
410
411#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:399
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:377
Result hybridMultiIndexAccess(C &&c, const MultiIndex &index)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:264
auto negatePredicate(Check check)
Negate given predicate.
Definition: utility.hh:304
Definition: polynomial.hh:10
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)