Dune-Functions 2.12-git
Loading...
Searching...
No Matches
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
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
17
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(
44 );
45};
46
47} // namespace Concept
48
49} // namespace Imp
50
51
52
65template<class C, class I, class F,
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,
92decltype(auto) hybridIndexAccess(C&& c, const I& i, F&& f)
93{
94 using Size = decltype(Hybrid::size(c));
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>
170 {
171 if constexpr (i<size()) {
172 return index_[Dune::index_constant<i+offset>{}];
173 } else {
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,
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,
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>
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 constexpr bool stopRecursion = decltype(isFinal(c))::value;
304 constexpr bool hasDynamicAccess = requires { c[0]; };
305
306 // If c is already considered final simply return it,
307 // else resolve the next multiIndex entry.
308 if constexpr (stopRecursion)
309 {
310 assert(multiIndex.size() == 0);
311 // There are two possibilities for the result:
312 // If c is an l-value reference, then C is of the form C=RawC& and we return an l-value reference.
313 // If c is an r-value reference, then C is of the form C=RawC and we return a copy of c by value.
314 // Notice that we should neither return plain c nor std::forward<C>(c) here.
315 // The former would bind a returned r-value reference to an r-value reference (which is an l-value!).
316 // The latter would deduce C&& as return value and thus return an r-value reference to the temporary
317 // which is gone after the function call.
318 return static_cast<C>(c);
319 }
320 else
321 {
322 // Split multiIndex into first entry and remaining ones.
323 auto i = multiIndex[0];
324 auto tail = multiIndex.pop();
325
326 // Resolve first multiIndex entry by c[multiIndex[0]] and
327 // continue resolving with the remaining remaining ones.
328 // If c has a dynamic operator[] this is straight forward.
329 // Else the dynamic multiIndex[0] has to be translated into
330 // a static one using hybridIndexAccess.
331 if constexpr (hasDynamicAccess)
332 return Imp::resolveDynamicMultiIndex(c[i], tail, isFinal);
333 else
334 {
335 // auto indexRange = range(Hybrid::size(id(c)));
336 auto indexRange = typename decltype(range(Hybrid::size(c)))::integer_sequence();
337 return Hybrid::switchCases(indexRange, i, [&](auto static_i) -> decltype(auto){
338 // Do rescursion with static version of i
339 return Imp::resolveDynamicMultiIndex(c[static_i], tail, isFinal);
340 }, [&]() -> decltype(auto){
341 // As fallback we use c[0] this is needed, because there must be one branch that matches.
342 return Imp::resolveDynamicMultiIndex(c[Dune::Indices::_0], tail, isFinal);
343 });
344 }
345 }
346 }
347
348 template<class C, class MultiIndex>
349 constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
350 {
351 constexpr bool stopRecursion = (decltype(Hybrid::size(multiIndex))::value == 0);
352 // Cf. resolveDynamicMultiIndex() for the explanation of the static_cast used in the first branch.
353 if constexpr (stopRecursion)
354 return static_cast<C>(c);
355 else
356 return Imp::resolveStaticMultiIndex(c[multiIndex[Dune::Indices::_0]], multiIndex.pop());
357 }
358
359} // namespace Imp
360
361
362
385template<class C, class MultiIndex, class IsFinal>
386constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex, const IsFinal& isFinal)
387{
388 return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), isFinal);
389}
390
407template<class C, class MultiIndex>
408constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex)
409{
410 auto hasNoIndexAccess = [](auto&& cc ) { return std::bool_constant<not requires { cc[Dune::Indices::_0]; }>{}; };
411 return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), hasNoIndexAccess);
412}
413
429template<class C, class MultiIndex>
430constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
431{
432 return Imp::resolveStaticMultiIndex(std::forward<C>(c), Imp::shiftedStaticMultiIndex<0>(multiIndex));
433}
434
435
436
437} // namespace Dune::Functions
438} // namespace Dune
439
440
441
442#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:430
constexpr decltype(auto) resolveDynamicMultiIndex(C &&c, const MultiIndex &multiIndex, const IsFinal &isFinal)
Provide multi-index access by chaining operator[].
Definition indexaccess.hh:386
Result hybridMultiIndexAccess(C &&c, const MultiIndex &index)
Provide multi-index access by chaining operator[].
Definition indexaccess.hh:286
reference operator[](size_type i)
static constexpr IntegralRange< std::decay_t< T > > range(T &&from, U &&to) noexcept
constexpr auto size(const T &t)
constexpr decltype(auto) switchCases(const Cases &cases, const Value &value, Branches &&branches, ElseBranch &&elseBranch)
void pop()
std::ptrdiff_t index() const
virtual void operator()()=0
constexpr std::integer_sequence< T, II... > tail(std::integer_sequence< T, I0, II... >)
constexpr index_constant< 0 > _0