Loading...
Searching...
No Matches
indexaccess.hh
Go to the documentation of this file.
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file AUTHORS.md
// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
#ifndef DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH
#define DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH
#include <utility>
#include <type_traits>
#include <dune/common/typetraits.hh>
#include <dune/common/concept.hh>
#include <dune/common/hybridutilities.hh>
#include <dune/functions/common/utility.hh>
namespace Dune {
namespace Functions {
namespace Imp {
namespace Concept {
template<class size_type>
struct HasDynamicIndexAccess
{
template<class C>
auto require(C&& c) -> decltype(
c[std::declval<size_type>()]
);
};
struct HasStaticIndexAccess
{
template<class C>
auto require(C&& c) -> decltype(
c[Dune::Indices::_0]
);
};
} // namespace Concept
} // namespace Imp
template<class C, class I, class F,
std::enable_if_t< Dune::models<Imp::Concept::HasDynamicIndexAccess<I>, C>(), int> = 0>
auto hybridIndexAccess(C&& c, const I& i, F&& f)
-> decltype(f(c[i]))
{
return f(c[i]);
}
template<class C, class I, class F,
std::enable_if_t< not Dune::models<Imp::Concept::HasDynamicIndexAccess<I>, C>(), int> = 0>
decltype(auto) hybridIndexAccess(C&& c, const I& i, F&& f)
{
using Size = decltype(Hybrid::size(c));
return Hybrid::switchCases(std::make_index_sequence<Size::value>(), i,
[&](const auto& ii) -> decltype(auto){
return f(c[ii]);
}, [&]() -> decltype(auto){
return f(c[Dune::Indices::_0]);
});
}
namespace Imp {
template<class Index, std::size_t offset=1>
class ShiftedDynamicMultiIndex
{
public:
ShiftedDynamicMultiIndex(const Index& index) :
index_(index)
{}
std::size_t operator[](std::size_t position) const
{
if (position<size())
return index_[position+offset];
else
return 0;
}
ShiftedDynamicMultiIndex<Index, offset+1> pop() const
{
return {index_};
}
std::size_t size() const
{
if (offset < index_.size())
return index_.size() - offset;
else
return 0;
}
const Index& originalIndex() const
{
return index_;
}
private:
const Index& index_;
};
template<class Index, std::size_t offset=1>
class ShiftedStaticMultiIndex
{
public:
ShiftedStaticMultiIndex(const Index& index) :
index_(index)
{}
template<std::size_t i>
auto operator[](Dune::index_constant<i>) const
{
if constexpr (i<size()) {
return index_[Dune::index_constant<i+offset>{}];
} else {
return Dune::index_constant<0>{};
}
}
ShiftedStaticMultiIndex<Index, offset+1> pop() const
{
return {index_};
}
static constexpr std::size_t size()
{
auto fullSize = decltype(Hybrid::size(std::declval<Index>()))::value;
if (offset < fullSize)
return fullSize - offset;
else
return 0;
}
private:
const Index& index_;
};
template<std::size_t offset, class Index>
ShiftedDynamicMultiIndex<Index, offset> shiftedDynamicMultiIndex(const Index& index)
{
return {index};
}
template<std::size_t offset, class Index, std::size_t oldOffset>
ShiftedDynamicMultiIndex<Index, offset+oldOffset> shiftedDynamicMultiIndex(const ShiftedDynamicMultiIndex<Index, oldOffset>& index)
{
return {index.originalIndex()};
}
template<std::size_t offset, class Index>
ShiftedStaticMultiIndex<Index, offset> shiftedStaticMultiIndex(const Index& index)
{
return {index};
}
} // namespace Imp
namespace Imp {
template<class Result, class Index>
struct MultiIndexResolver
{
MultiIndexResolver(const Index& index) :
index_(index)
{}
template<class C,
std::enable_if_t<not std::is_convertible_v<C&, Result>, int> = 0>
Result operator()(C&& c)
{
auto&& subIndex = Imp::shiftedDynamicMultiIndex<1>(index_);
auto&& subIndexResolver = MultiIndexResolver<Result, decltype(subIndex)>(subIndex);
return (Result)(hybridIndexAccess(c, index_[Dune::Indices::_0], subIndexResolver));
}
template<class C,
std::enable_if_t<std::is_convertible_v<C&, Result>, int> = 0>
Result operator()(C&& c)
{
return (Result)(std::forward<C>(c));
}
const Index& index_;
};
} // namespace Imp
template<class Result, class C, class MultiIndex>
Result hybridMultiIndexAccess(C&& c, const MultiIndex& index)
{
Imp::MultiIndexResolver<Result, MultiIndex> multiIndexResolver(index);
return multiIndexResolver(c);
}
namespace Imp {
template<class C, class MultiIndex, class IsFinal>
constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex, const IsFinal& isFinal)
{
// If c is already considered final simply return it,
// else resolve the next multiIndex entry.
return Hybrid::ifElse(isFinal(c), [&, c = forwardCapture(std::forward<C>(c))](auto) -> decltype(auto) {
assert(multiIndex.size() == 0);
return c.forward();
}, [&](auto) -> decltype(auto) {
auto hasDynamicAccess = callableCheck([](auto&& cc) -> std::void_t<decltype(cc[0])> {});
// Split multiIndex into first entry and remaining ones.
auto i = multiIndex[0];
auto tail = multiIndex.pop();
// Resolve first multiIndex entry by c[multiIndex[0]] and
// continue resolving with the remaining remaining ones.
// If c has a dynamic operator[] this is straight forward.
// Else the dynamic multiIndex[0] has to be translated into
// a static one using hybridIndexAccess.
return Hybrid::ifElse(hasDynamicAccess(c), [&](auto id) -> decltype(auto) {
return Imp::resolveDynamicMultiIndex(id(c)[i], tail, isFinal);
}, [&](auto id) -> decltype(auto) {
// auto indexRange = range(Hybrid::size(id(c)));
auto indexRange = typename decltype(range(Hybrid::size(id(c))))::integer_sequence();
return Hybrid::switchCases(indexRange, i, [&](auto static_i) -> decltype(auto){
// Do rescursion with static version of i
return Imp::resolveDynamicMultiIndex(id(c)[static_i], tail, isFinal);
}, [&]() -> decltype(auto){
// As fallback we use c[0] this is needed, because there must be one branch that matches.
return Imp::resolveDynamicMultiIndex(id(c)[Dune::Indices::_0], tail, isFinal);
});
});
});
}
template<class C, class MultiIndex>
constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
{
auto isExhausted = Hybrid::equal_to(Hybrid::size(multiIndex), Dune::Indices::_0);
return Hybrid::ifElse(isExhausted, [&, c = forwardCapture(std::forward<C>(c))](auto) -> decltype(auto) {
return c.forward();
}, [&](auto id) -> decltype(auto) {
auto head = multiIndex[Dune::Indices::_0];
auto tail = multiIndex.pop();
return Imp::resolveStaticMultiIndex(id(c)[head], tail);
});
}
} // namespace Imp
template<class C, class MultiIndex, class IsFinal>
constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex, const IsFinal& isFinal)
{
return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), isFinal);
}
template<class C, class MultiIndex>
constexpr decltype(auto) resolveDynamicMultiIndex(C&& c, const MultiIndex& multiIndex)
{
auto hasNoIndexAccess = negatePredicate(callableCheck([](auto&& cc) -> std::void_t<decltype(cc[Dune::Indices::_0])> {}));
return Imp::resolveDynamicMultiIndex(std::forward<C>(c), Imp::shiftedDynamicMultiIndex<0>(multiIndex), hasNoIndexAccess);
}
template<class C, class MultiIndex>
constexpr decltype(auto) resolveStaticMultiIndex(C&& c, const MultiIndex& multiIndex)
{
return Imp::resolveStaticMultiIndex(std::forward<C>(c), Imp::shiftedStaticMultiIndex<0>(multiIndex));
}
} // namespace Dune::Functions
} // namespace Dune
#endif // DUNE_FUNCTIONS_COMMON_INDEX_ACCESS_HH
utility.hh
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:67
Dune::Functions::resolveStaticMultiIndex
constexpr decltype(auto) resolveStaticMultiIndex(C &&c, const MultiIndex &multiIndex)
Provide multi-index access by chaining operator[].
Definition indexaccess.hh:421
Dune::Functions::callableCheck
auto callableCheck(Expression f)
Create a predicate for checking validity of expressions.
Definition utility.hh:287
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:377
Dune::Functions::hybridMultiIndexAccess
Result hybridMultiIndexAccess(C &&c, const MultiIndex &index)
Provide multi-index access by chaining operator[].
Definition indexaccess.hh:286
Dune::Functions::negatePredicate
auto negatePredicate(Check check)
Negate given predicate.
Definition utility.hh:312
Dune
Definition monomialset.hh:19
Dune::Functions
Definition monomialset.hh:19
Dune::Functions::forwardCapture
auto forwardCapture(T &&t)
Create a capture object for perfect forwarding.
Definition utility.hh:380