dune-functions  2.8.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 
18 namespace Dune {
19 namespace Functions {
20 
21 
22 namespace Imp {
23 
24 namespace Concept {
25 
26 template<class size_type>
27 struct HasDynamicIndexAccess
28 {
29  template<class C>
30  auto require(C&& c) -> decltype(
31  c[std::declval<size_type>()]
32  );
33 };
34 
35 struct 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 
61 template<class C, class I, class F,
62  typename std::enable_if< Dune::models<Imp::Concept::HasDynamicIndexAccess<I>, C>(), int>::type = 0>
63 auto hybridIndexAccess(C&& c, const I& i, F&& f)
64  -> decltype(f(c[i]))
65 {
66  return f(c[i]);
67 }
68 
86 template<class C, class I, class F,
87  typename std::enable_if< not Dune::models<Imp::Concept::HasDynamicIndexAccess<I>, C>(), int>::type = 0>
88 decltype(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 
100 namespace 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 
212 namespace Imp {
213 
214 template<class Result, class Index>
215 struct 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 
262 template<class Result, class C, class MultiIndex>
263 Result 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 
275 namespace 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 id) -> decltype(auto) {
283  assert(multiIndex.size() == 0);
284  return c.forward();
285  }, [&](auto id) -> 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 id) -> 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 
353 template<class C, class MultiIndex, class IsFinal>
354 constexpr 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 
375 template<class C, class MultiIndex>
376 constexpr 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 
397 template<class C, class MultiIndex>
398 constexpr 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