// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_MATRIX_VECTOR_ALGORITHM_HH
#define DUNE_MATRIX_VECTOR_ALGORITHM_HH

#include <dune/common/hybridutilities.hh>
#include <dune/matrix-vector/traitutilities.hh>

namespace Dune {
namespace MatrixVector {

//! \brief Hybrid for loop over sparse range (static/tuple-like candidate)
template <class Range, class F, std::enable_if_t<isTupleOrDerived<Range>(), int> = 0>
void sparseRangeFor(Range&& range, F&& f) {
  using namespace Dune::Hybrid;
  forEach(integralRange(size(range)), [&](auto&& i) {
      f(range[i], i);
  });
}

//! \brief Hybrid for loop over sparse range (dynamic/sparse candidate)
template<class Range, class F, std::enable_if_t<not isTupleOrDerived<Range>(), int> = 0>
void sparseRangeFor(Range&& range, F&& f)
{
  auto it = range.begin();
  auto end = range.end();
  for (; it != end; ++it)
    f(*it, it.index());
}

//! \brief Hybrid access to first sparse range element (static/tuple-like candiate)
template <class Range, class F, std::enable_if_t<isTupleOrDerived<Range>(), int> = 0>
void sparseRangeFirst(Range&& range, F&& f) {
  f(range[Indices::_0]);
}
//! \brief Hybrid access to first sparse range element (dynamic/sparse candiate)
template<class Range, class F, std::enable_if_t<not isTupleOrDerived<Range>(), int> = 0>
void sparseRangeFirst(Range&& range, F&& f)
{
  f(*range.begin());
}

} // namespace MatrixVector
} // namespace Dune


#endif // DUNE_MATRIX_VECTOR_ALGORITHM_HH