From 9fe2b3c8f8d5b32ed9dd1f8e6a94b16002fed3b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carsten=20Gr=C3=A4ser?= <graeser@dune-project.org> Date: Tue, 8 Mar 2016 14:31:42 +0100 Subject: [PATCH] Add header for basic algorithms Currently it contains a hybrid for loop over ranges of integral values begin,begin+1,...,end-1. Using generic lambdas this allows to write for loops that work with dynamically sized or statically sized multitype containers. --- dune/solvers/common/CMakeLists.txt | 1 + dune/solvers/common/algorithm.hh | 117 +++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 dune/solvers/common/algorithm.hh diff --git a/dune/solvers/common/CMakeLists.txt b/dune/solvers/common/CMakeLists.txt index 7451cd6c..07d57c75 100644 --- a/dune/solvers/common/CMakeLists.txt +++ b/dune/solvers/common/CMakeLists.txt @@ -1,4 +1,5 @@ install(FILES + algorithm.hh arithmetic.hh boxconstraint.hh canignore.hh diff --git a/dune/solvers/common/algorithm.hh b/dune/solvers/common/algorithm.hh new file mode 100644 index 00000000..c5155fa7 --- /dev/null +++ b/dune/solvers/common/algorithm.hh @@ -0,0 +1,117 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifndef DUNE_SOLVERS_COMMON_ALGORITHM_HH +#define DUNE_SOLVERS_COMMON_ALGORITHM_HH + + + +namespace Dune { +namespace Solvers { + + +namespace Imp { + +template<class ST, ST begin, ST end> +struct StaticForLoop +{ + template<class F, class...Args> + static void apply(F&& f, Args&&... args) + { + f(std::integral_constant<ST, begin>(), std::forward<Args>(args)...); + StaticForLoop<ST, begin+1, end>::apply(std::forward<F>(f), std::forward<Args>(args)...); + } +}; + +template<class ST, ST end> +struct StaticForLoop<ST, end, end> +{ + template<class F, class...Args> + static void apply(F&& f, Args&&...) + {} +}; + +// Check if T is an integral constant +template<class T> +struct IsIntegralConstant +{ + static const bool value = false; +}; + +template<class T, T t> +struct IsIntegralConstant<std::integral_constant<T, t>> +{ + static const bool value = true; +}; + +} //end namespace Imp + + + +/** + * \brief Hybrid for loop over integral range + * + * \tparam Index Raw type of used indices + * \tparam Begin Type of begin index + * \tparam End Type of end index + * \tparam F Type of functor containing the loop body + * \tparam Args Types of further arguments to the loop body + * + * \param begin Initial index + * \param end One past last index + * \param f Functor to call in each loop instance + * \param args Additional arguments to be passed to the functor + * + * This is a hybrid for loop that can work on statically and dynamically + * sized containers. The functor is called with index as first argument + * and all additional arguments. + * + * This is the static-size overload which is selected if begin and + * end are both static indices, i.e., integral constants. The loop + * body is called with std::integral_constant<Index,i> where i + * is the static index. + */ +template<class Index, class Begin, class End, class F, class... Args, + std::enable_if_t<Imp::IsIntegralConstant<Begin>::value and Imp::IsIntegralConstant<End>::value, int> = 0> +void integralRangeFor(Begin&& begin, End&& end, F&& f, Args&&... args) +{ + static const Index begin_t = begin; + static const Index end_t = end; + Imp::StaticForLoop<Index, begin_t, end_t>::apply(std::forward<F>(f), std::forward<Args>(args)...); +} + +/** + * \brief Hybrid for loop over integral range + * + * \tparam Index Raw type of used indices + * \tparam Begin Type of begin index + * \tparam End Type of end index + * \tparam F Type of functor containing the loop body + * \tparam Args Types of further arguments to the loop body + * + * \param begin Initial index + * \param end One past last index + * \param f Functor to call in each loop instance + * \param args Additional arguments to be passed to the functor + * + * This is a hybrid for loop that can work on statically and dynamically + * sized containers. The functor is called with index as first argument + * and all additional arguments. + * + * This is the dynamic-size overload which is selected if either begin or + * end is a dynamic index, i.e., not an integral constant. The loop + * body is called with indices of type Index. + */ +template<class Index, class Begin, class End, class F, class... Args, + std::enable_if_t<not(Imp::IsIntegralConstant<Begin>::value and Imp::IsIntegralConstant<End>::value), int> = 0> +void integralRangeFor(Begin&& begin, End&& end, F&& f, Args&&... args) +{ + for(Index i=begin; i != end; ++i) + f(i, std::forward<Args>(args)...); +} + + +} // namespace Solvers +} // namespace Dune + + +#endif// DUNE_SOLVERS_COMMON_FORLOOP_HH -- GitLab