dune-functions  2.7.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  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 
213 namespace Imp {
214 
215 template<class Result, class Index>
216 struct 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 
263 template<class Result, class C, class MultiIndex>
264 Result 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 
276 namespace 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 
354 template<class C, class MultiIndex, class IsFinal>
355 constexpr 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 
376 template<class C, class MultiIndex>
377 constexpr 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 
398 template<class C, class MultiIndex>
399 constexpr 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
Dune::Functions::callableCheck
auto callableCheck(Expression f)
Create a predicate for checking validity of expressions.
Definition: utility.hh:279
Dune::Functions::resolveDynamicMultiIndex
constexpr decltype(auto) resolveDynamicMultiIndex(C &&c, const MultiIndex &multiIndex, const IsFinal &isFinal)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:355
Dune::Functions::hybridMultiIndexAccess
Result hybridMultiIndexAccess(C &&c, const MultiIndex &index)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:264
Dune::Functions::hybridIndexAccess
auto hybridIndexAccess(C &&c, const I &i, F &&f) -> decltype(f(c[i]))
Provide operator[] index-access for containers.
Definition: indexaccess.hh:63
Dune::Functions::resolveDynamicMultiIndex
constexpr decltype(auto) resolveDynamicMultiIndex(C &&c, const MultiIndex &multiIndex)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:377
Dune::Functions::resolveStaticMultiIndex
constexpr decltype(auto) resolveStaticMultiIndex(C &&c, const MultiIndex &multiIndex)
Provide multi-index access by chaining operator[].
Definition: indexaccess.hh:399
Dune::Functions::forwardCapture
auto forwardCapture(T &&t)
Create a capture object for perfect forwarding.
Definition: utility.hh:372
Dune
Definition: polynomial.hh:10
utility.hh
Dune::Functions::negatePredicate
auto negatePredicate(Check check)
Negate given predicate.
Definition: utility.hh:304