diff --git a/dune/common/hybridutilities.hh b/dune/common/hybridutilities.hh index db7b9c1b616724c45f63b04645dd71b5dc109a15..9984f6964e9cce1cf21432196705934054506458 100644 --- a/dune/common/hybridutilities.hh +++ b/dune/common/hybridutilities.hh @@ -6,6 +6,7 @@ #include <tuple> #include <utility> +#include <dune/common/typetraits.hh> #include <dune/common/typeutilities.hh> #include <dune/common/fvector.hh> #include <dune/common/indices.hh> @@ -99,9 +100,9 @@ namespace Impl { } template<class T, T... t, class Index> - constexpr decltype(auto) elementAt(std::integer_sequence<T, t...> c, Index&&, PriorityTag<1>) + constexpr decltype(auto) elementAt(std::integer_sequence<T, t...> c, Index, PriorityTag<1>) { - return std::get<std::decay_t<Index>::value>(std::make_tuple(std::integral_constant<T, t>()...)); + return Dune::integerSequenceEntry(c, std::integral_constant<std::size_t, Index::value>()); } template<class Container, class Index> diff --git a/dune/common/test/hybridutilitiestest.cc b/dune/common/test/hybridutilitiestest.cc index f275296f72e6df95877e56880c11074abe465a9e..d11cf7ea55c66c16f88127e19ca8e72f135bb580 100644 --- a/dune/common/test/hybridutilitiestest.cc +++ b/dune/common/test/hybridutilitiestest.cc @@ -46,6 +46,28 @@ auto incAndAppendToFirst(C&& c) }); } +template<class C> +auto sum(C&& c) +{ + using namespace Dune::Hybrid; + using namespace Dune::Indices; + return accumulate(c, 0.0, [](auto&& a, auto&& b) { + return a+b; + }); +} + +template<class C, class I> +auto sumSubsequence(C&& c, I&& indices) +{ + using namespace Dune::Hybrid; + using namespace Dune::Indices; + double result = 0; + forEach(indices, [&](auto i) { + result += elementAt(c, i); + }); + return result; +} + int main() @@ -77,5 +99,12 @@ int main() test.check(mixedTuple == Dune::makeTupleVector(std::string("1+1"), 3, 4)) << "Adding indices to vector entries with Hybrid::forEach failed."; + auto values = std::make_integer_sequence<std::size_t, 30>(); + test.check((30*29)/2 == sum(values)) + << "accumulate() yields incorrect result."; + + test.check((29*28)/2 == sumSubsequence(values, std::make_integer_sequence<std::size_t, 29>())) + << "Summing up subsequence failed."; + return test.exit(); } diff --git a/dune/common/typetraits.hh b/dune/common/typetraits.hh index fa69536c53ac23ce04f2995b10ea1c98ca3429fc..8b7f2ee73ef7665c882a383e3e014554f9f46d7c 100644 --- a/dune/common/typetraits.hh +++ b/dune/common/typetraits.hh @@ -5,6 +5,7 @@ #include <complex> #include <type_traits> +#include <utility> #include <dune/common/deprecated.hh> @@ -552,6 +553,79 @@ namespace Dune + namespace Impl { + + template<class T, T...> + struct IntegerSequenceHelper; + + // Helper struct to compute the i-th entry of a std::integer_sequence + // + // This could also be implemented using std::get<index>(std::make_tuple(t...)). + // However, the gcc-6 implementation of std::make_tuple increases the instantiation + // depth by 15 levels for each argument, such that the maximal instantiation depth + // is easily hit, especially with clang where it is set to 256. + template<class T, T head, T... tail> + struct IntegerSequenceHelper<T, head, tail...> + { + + // get first entry + static constexpr auto get(std::integral_constant<std::size_t, 0>) + { + return std::integral_constant<T, head>(); + } + + // call get with first entry cut off and decremented index + template<std::size_t index, + std::enable_if_t<(index > 0) and (index < sizeof...(tail)+1), int> = 0> + static constexpr auto get(std::integral_constant<std::size_t, index>) + { + return IntegerSequenceHelper<T, tail...>::get(std::integral_constant<std::size_t, index-1>()); + } + + // use static assertion if index exceeds size + template<std::size_t index, + std::enable_if_t<(index >= sizeof...(tail)+1), int> = 0> + static constexpr auto get(std::integral_constant<std::size_t, index>) + { + static_assert(index < sizeof...(tail)+1, "index used in IntegerSequenceEntry exceed size"); + } + }; + + } // end namespace Impl + + + /** + * \brief Get entry of std::integer_sequence + * + * \param seq An object of type std::integer_sequence<...> + * \param i Index + * + * \return The i-th entry of the integer_sequence encoded as std::integral_constant<std::size_t, entry>. + * + */ + template<class T, T... t, std::size_t index> + constexpr auto integerSequenceEntry(std::integer_sequence<T, t...> seq, std::integral_constant<std::size_t, index> i) + { + static_assert(index < sizeof...(t), "index used in IntegerSequenceEntry exceed size"); + return Impl::IntegerSequenceHelper<T, t...>::get(i); + } + + template<class IntegerSequence, std::size_t index> + struct IntegerSequenceEntry; + + /** + * \brief Get entry of std::integer_sequence + * + * Computes the i-th entry of the integer_sequence. The result + * is exported as ::value by deriving form std::integral_constant<std::size_t, entry>. + */ + template<class T, T... t, std::size_t i> + struct IntegerSequenceEntry<std::integer_sequence<T, t...>, i> + : public decltype(Impl::IntegerSequenceHelper<T, t...>::get(std::integral_constant<std::size_t, i>())) + {}; + + + /** @} */ } #endif