DUNE-FUNCTIONS (unstable)

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
4// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file AUTHORS.md
5// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
6
7#ifndef DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH
8#define DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH
9
10
11#include <utility>
12#include <type_traits>
13
14#include <dune/common/typetraits.hh>
15#include <dune/common/concept.hh>
16#include <dune/common/hybridutilities.hh>
17
18#include <dune/functions/common/utility.hh>
19
20
21
22namespace Dune {
23namespace Functions {
24
25
26namespace Imp {
27
28namespace Concept {
29
30template<class size_type>
31struct HasDynamicIndexAccess
32{
33 template<class C>
34 auto require(C&& c) -> decltype(
35 c[std::declval<size_type>()]
36 );
37};
38
39struct HasStaticIndexAccess
40{
41 template<class C>
42 auto require(C&& c) -> decltype(
43 c[Dune::Indices::_0]
44 );
45};
46
47} // namespace Concept
48
49} // namespace Imp
50
51
52
65template<class C, class I, class F,
66 std::enable_if_t< Dune::models<Imp::Concept::HasDynamicIndexAccess<I>, C>(), int> = 0>
67auto hybridIndexAccess(C&& c, const I& i, F&& f)
68 -> decltype(f(c[i]))
69{
70 return f(c[i]);
71}
72
90template<class C, class I, class F,
91 std::enable_if_t< not Dune::models<Imp::Concept::HasDynamicIndexAccess<I>, C>(), int> = 0>
92decltype(auto) hybridIndexAccess(C&& c, const I& i, F&& f)
93{
94 using Size = decltype(Hybrid::size(c));
95 return Hybrid::switchCases(std::make_index_sequence<Size::value>(), i,
96 [&](const auto& ii) -> decltype(auto){
97 return f(c[ii]);
98 }, [&]() -> decltype(auto){
99 return f(c[Dune::Indices::_0]);
100 });
101}
102
103
104namespace Imp {
105
119 template<class Index, std::size_t offset=1>
120 class ShiftedDynamicMultiIndex
121 {
122 public:
123 ShiftedDynamicMultiIndex(const Index& index) :
124 index_(index)
125 {}
126
127 std::size_t operator[](std::size_t position) const
128 {
129 if (position<size())
130 return index_[position+offset];
131 else
132 return 0;
133 }
134
138 ShiftedDynamicMultiIndex<Index, offset+1> pop() const
139 {
140 return {index_};
141 }
142
143 std::size_t size() const
144 {
145 if (offset < index_.size())
146 return index_.size() - offset;
147 else
148 return 0;
149 }
150
151 const Index& originalIndex() const
152 {
153 return index_;
154 }
155
156 private:
157 const Index& index_;
158 };
159
160 template<class Index, std::size_t offset=1>
161 class ShiftedStaticMultiIndex
162 {
163 public:
164 ShiftedStaticMultiIndex(const Index& index) :
165 index_(index)
166 {}
167
168 template<std::size_t i>
169 auto operator[](Dune::index_constant<i>) const
170 {
171 if constexpr (i<size()) {
172 return index_[Dune::index_constant<i+offset>{}];
173 } else {
174 return Dune::index_constant<0>{};
175 }
176 }
177
181 ShiftedStaticMultiIndex<Index, offset+1> pop() const
182 {
183 return {index_};
184 }
185
186 static constexpr std::size_t size()
187 {
188 auto fullSize = decltype(Hybrid::size(std::declval<Index>()))::value;
189 if (offset < fullSize)
190 return fullSize - offset;
191 else
192 return 0;
193 }
194
195 private:
196 const Index& index_;
197 };
198
204 template<std::size_t offset, class Index>
205 ShiftedDynamicMultiIndex<Index, offset> shiftedDynamicMultiIndex(const Index& index)
206 {
207 return {index};
208 }
209
218 template<std::size_t offset, class Index, std::size_t oldOffset>
219 ShiftedDynamicMultiIndex<Index, offset+oldOffset> shiftedDynamicMultiIndex(const ShiftedDynamicMultiIndex<Index, oldOffset>& index)
220 {
221 return {index.originalIndex()};
222 }
223
224 template<std::size_t offset, class Index>
225 ShiftedStaticMultiIndex<Index, offset> shiftedStaticMultiIndex(const Index& index)
226 {
227 return {index};
228 }
229
230} // namespace Imp
231
232
233
234
235namespace Imp {
236
237template<class Result, class Index>
238struct MultiIndexResolver
239{
240 MultiIndexResolver(const Index& index) :
241 index_(index)
242 {}
243
244 template<class C,
245 std::enable_if_t<not std::is_convertible_v<C&, Result>, int> = 0>
246 Result operator()(C&& c)
247 {
248 auto&& subIndex = Imp::shiftedDynamicMultiIndex<1>(index_);
249 auto&& subIndexResolver = MultiIndexResolver<Result, decltype(subIndex)>(subIndex);
250 return (Result)(hybridIndexAccess(c, index_[Dune::Indices::_0], subIndexResolver));
251 }
252
253 template<class C,
254 std::enable_if_t<std::is_convertible_v<C&, Result>, int> = 0>
255 Result operator()(C&& c)
256 {
257 return (Result)(std::forward<C>(c));
258 }
259
260 const Index& index_;
261};
262
263} // namespace Imp
264
265
266
285template<class Result, class C, class MultiIndex>
286Result hybridMultiIndexAccess(C&& c, const MultiIndex& index)
287{
288
289 Imp::MultiIndexResolver<Result, MultiIndex> multiIndexResolver(index);
290 return multiIndexResolver(c);
291}
292
293
294
295
296
297
298namespace Imp {
299
300 template<class C, class MultiIndex, class IsFinal>
301 constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex, const IsFinal& isFinal)
302 {
303 // If c is already considered final simply return it,
304 // else resolve the next multiIndex entry.
305 return Hybrid::ifElse(isFinal(c), [&, c = forwardCapture(std::forward<C>(c))](auto) -> decltype(auto) {
306 assert(multiIndex.size() == 0);
307 return c.forward();
308 }, [&](auto) -> decltype(auto) {
309 auto hasDynamicAccess = callableCheck([](auto&& cc) -> std::void_t<decltype(cc[0])> {});
310
311 // Split multiIndex into first entry and remaining ones.
312 auto i = multiIndex[0];
313 auto tail = multiIndex.pop();
314
315 // Resolve first multiIndex entry by c[multiIndex[0]] and
316 // continue resolving with the remaining remaining ones.
317 // If c has a dynamic operator[] this is straight forward.
318 // Else the dynamic multiIndex[0] has to be translated into
319 // a static one using hybridIndexAccess.
320 return Hybrid::ifElse(hasDynamicAccess(c), [&](auto id) -> decltype(auto) {
321 return Imp::resolveDynamicMultiIndex(id(c)[i], tail, isFinal);
322 }, [&](auto id) -> decltype(auto) {
323 // auto indexRange = range(Hybrid::size(id(c)));
324 auto indexRange = typename decltype(range(Hybrid::size(id(c))))::integer_sequence();
325 return Hybrid::switchCases(indexRange, i, [&](auto static_i) -> decltype(auto){
326 // Do rescursion with static version of i
327 return Imp::resolveDynamicMultiIndex(id(c)[static_i], tail, isFinal);
328 }, [&]() -> decltype(auto){
329 // As fallback we use c[0] this is needed, because there must be one branch that matches.
330 return Imp::resolveDynamicMultiIndex(id(c)[Dune::Indices::_0], tail, isFinal);
331 });
332 });
333 });
334 }
335
336 template<class C, class MultiIndex>
337 constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
338 {
339 auto isExhausted = Hybrid::equals(Hybrid::size(multiIndex), Dune::Indices::_0);
340 return Hybrid::ifElse(isExhausted, [&, c = forwardCapture(std::forward<C>(c))](auto) -> decltype(auto) {
341 return c.forward();
342 }, [&](auto id) -> decltype(auto) {
343 auto head = multiIndex[Dune::Indices::_0];
344 auto tail = multiIndex.pop();
345
346 return Imp::resolveStaticMultiIndex(id(c)[head], tail);
347 });
348 }
349
350} // namespace Imp
351
352
353
376template<class C, class MultiIndex, class IsFinal>
377constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex, const IsFinal& isFinal)
378{
379 return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), isFinal);
380}
381
398template<class C, class MultiIndex>
399constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex)
400{
401 auto hasNoIndexAccess = negatePredicate(callableCheck([](auto&& cc) -> std::void_t<decltype(cc[Dune::Indices::_0])> {}));
402 return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), hasNoIndexAccess);
403}
404
420template<class C, class MultiIndex>
421constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
422{
423 return Imp::resolveStaticMultiIndex(std::forward<C>(c), Imp::shiftedStaticMultiIndex<0>(multiIndex));
424}
425
426
427
428} // namespace Dune::Functions
429} // namespace Dune
430
431
432
433#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:67
constexpr decltype(auto) resolveStaticMultiIndex(C &&c, const MultiIndex &multiIndex)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:421
auto callableCheck(Expression f)
Create a predicate for checking validity of expressions.
Definition: utility.hh:283
constexpr decltype(auto) resolveDynamicMultiIndex(C &&c, const MultiIndex &multiIndex)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:399
Result hybridMultiIndexAccess(C &&c, const MultiIndex &index)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:286
auto negatePredicate(Check check)
Negate given predicate.
Definition: utility.hh:308
Definition: polynomial.hh:17
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Aug 14, 22:29, 2024)