Skip to content
Snippets Groups Projects
Commit 9e63c2bd authored by Carsten Gräser's avatar Carsten Gräser
Browse files

Merge branch 'feature/add-integersequenceentry' into 'master'

Feature/add integersequenceentry

The traits class `IntegerSequenceEntry` computes the i-th entry
of an `std::integer_sequence`. The `integerSequenceEntry` helper
function does the same with function syntax.
    
 This allows to avoid the hight template instantiation depth
 of `std::make_tuple` when using the "natural" implementation

```cpp    
std::get<index>(std::make_tuple(t...));
```
    
The latter adds 15 instantiation levels per argument whereas
the still recursive implementation in this MR adds only one.

See merge request !170
parents 9af12b69 3048dbb6
No related branches found
No related tags found
No related merge requests found
......@@ -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>
......
......@@ -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();
}
......@@ -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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment