diff --git a/include/boost/fusion/algorithm/iteration/detail/for_each.hpp b/include/boost/fusion/algorithm/iteration/detail/for_each.hpp index c674511eb..dfd3ca599 100644 --- a/include/boost/fusion/algorithm/iteration/detail/for_each.hpp +++ b/include/boost/fusion/algorithm/iteration/detail/for_each.hpp @@ -15,26 +15,83 @@ #include #include #include +#include +#include #include namespace boost { namespace fusion { namespace detail { - template +#if defined(BOOST_FUSION_HAS_INDEXED_FOREACH) +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template()(boost::declval(), I{}))> BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED inline void - for_each_linear(First const&, Last const&, F const&, mpl::true_) + for_each_apply(T& value, F& f, I i, long) { + f(value, i); } - template + template()(boost::declval(), I{}))> BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED inline void - for_each_linear(First const& first, Last const& last, F& f, mpl::false_) + for_each_apply(T const& value, F& f, I i, long) { - f(*first); + f(value, i); + } +#else + template()(boost::declval(), I{}))> + BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED + inline void + for_each_apply(T&& value, F& f, I i, long) + { + f(std::forward(value), i); + } +#endif +#endif + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED + inline void + for_each_apply(T& value, F& f, I /*i*/, int) + { + f(value); + } + + template + BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED + inline void + for_each_apply(T const& value, F& f, I /*i*/, int) + { + f(value); + } +#else + template + BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED + inline void + for_each_apply(T&& value, F& f, I /*i*/, int) + { + f(std::forward(value)); + } +#endif + + template + BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED + inline void + for_each_linear(First const&, Last const&, F const&, mpl::true_, I /*i*/) + { + } + + template + BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED + inline void + for_each_linear(First const& first, Last const& last, F& f, mpl::false_, I i) + { + for_each_apply(*first, f, i, 1L); detail::for_each_linear(fusion::next(first), last, f, - result_of::equal_to::type, Last>()); + result_of::equal_to::type, Last>(), + boost::integral_constant()); } @@ -49,74 +106,75 @@ namespace detail , f , result_of::equal_to< typename result_of::begin::type - , typename result_of::end::type>()); + , typename result_of::end::type>() + , boost::integral_constant()); } - template + template struct for_each_unrolled { template BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED static void call(I0 const& i0, F& f) { - f(*i0); + for_each_apply(*i0, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I1; I1 i1(fusion::next(i0)); - f(*i1); + for_each_apply(*i1, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I2; I2 i2(fusion::next(i1)); - f(*i2); + for_each_apply(*i2, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I3; I3 i3(fusion::next(i2)); - f(*i3); - for_each_unrolled::call(fusion::next(i3), f); + for_each_apply(*i3, f, boost::integral_constant(), 1L); + for_each_unrolled::call(fusion::next(i3), f); } }; - template<> - struct for_each_unrolled<3> + template + struct for_each_unrolled<3, S> { template BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED static void call(I0 const& i0, F& f) { - f(*i0); + for_each_apply(*i0, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I1; I1 i1(fusion::next(i0)); - f(*i1); + for_each_apply(*i1, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I2; I2 i2(fusion::next(i1)); - f(*i2); + for_each_apply(*i2, f, boost::integral_constant(), 1L); } }; - template<> - struct for_each_unrolled<2> + template + struct for_each_unrolled<2, S> { template BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED static void call(I0 const& i0, F& f) { - f(*i0); + for_each_apply(*i0, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I1; I1 i1(fusion::next(i0)); - f(*i1); + for_each_apply(*i1, f, boost::integral_constant(), 1L); } }; - template<> - struct for_each_unrolled<1> + template + struct for_each_unrolled<1, S> { template BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED static void call(I0 const& i0, F& f) { - f(*i0); + for_each_apply(*i0, f, boost::integral_constant(), 1L); } }; - template<> - struct for_each_unrolled<0> + template + struct for_each_unrolled<0, S> { template BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED diff --git a/include/boost/fusion/algorithm/iteration/for_each.hpp b/include/boost/fusion/algorithm/iteration/for_each.hpp index 349966751..59a4ebd4e 100644 --- a/include/boost/fusion/algorithm/iteration/for_each.hpp +++ b/include/boost/fusion/algorithm/iteration/for_each.hpp @@ -10,6 +10,7 @@ #define BOOST_FUSION_FOR_EACH_20070527_0943 #include +#include #include #include #include diff --git a/include/boost/fusion/algorithm/iteration/for_each_fwd.hpp b/include/boost/fusion/algorithm/iteration/for_each_fwd.hpp index c3ffaa42d..c21be4de6 100644 --- a/include/boost/fusion/algorithm/iteration/for_each_fwd.hpp +++ b/include/boost/fusion/algorithm/iteration/for_each_fwd.hpp @@ -9,6 +9,18 @@ #define BOOST_FUSION_FOR_EACH_FWD_HPP_INCLUDED #include +#include + +#if defined(BOOST_NO_CXX11_DECLTYPE) +# if defined(BOOST_FUSION_HAS_INDEXED_FOREACH) +# undef BOOST_FUSION_HAS_INDEXED_FOREACH +# endif +#else +# if !defined(BOOST_FUSION_HAS_INDEXED_FOREACH) +# define BOOST_FUSION_HAS_INDEXED_FOREACH +# endif +#endif + #include #include diff --git a/test/Jamfile b/test/Jamfile index e55b15ad2..db2439a83 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -42,6 +42,8 @@ project [ run algorithm/insert.cpp ] [ run algorithm/insert_range.cpp ] [ run algorithm/iter_fold.cpp ] + [ run algorithm/indexed_for_each.cpp : : + : [ requires cxx11_decltype ] ] [ run algorithm/move.cpp : : : [ requires cxx11_rvalue_references ] ] [ run algorithm/none.cpp ] diff --git a/test/algorithm/indexed_for_each.cpp b/test/algorithm/indexed_for_each.cpp new file mode 100644 index 000000000..4df5eb1bb --- /dev/null +++ b/test/algorithm/indexed_for_each.cpp @@ -0,0 +1,170 @@ +/*============================================================================= + Copyright (c) 2021 Denis Mikhailov + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +==============================================================================*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct print +{ + template + void operator()(T const& v, I) const + { + BOOST_STATIC_ASSERT(I::value >= 0); + std::cout << "[ " << I::value << " : " << v << " ] "; + } +}; + +struct increment_control +{ + int& control; + + increment_control(int& control) + : control(control) + {} + + template + void operator()(T const& val, int i) + { + BOOST_TEST_EQ(i, control); + (void)val; + ++ control; + } +}; + +struct apply_index_addition +{ + template + void operator()(T& v, int i) const + { + v += i; + } +}; + +struct mutable_apply_index_addition : apply_index_addition +{ + template + void operator()(T& v, int i) + { + return apply_index_addition::operator()(v, i); + } +}; + +template +struct apply_compile_time_index +{ + template + void operator()(T, I) const + { + using boost::mpl::at; + typedef typename at::type element_type; + BOOST_STATIC_ASSERT(T::value == element_type::value); + } +}; + +int +main() +{ + int control = 0; + + using namespace boost::fusion; + using boost::mpl::vector_c; + namespace fusion = boost::fusion; + + { + typedef vector vector_type; + vector_type v(1, 'x', 3.3, "Ruby"); + for_each(v, print()); + std::cout << std::endl; + } + + { + typedef vector<> vector_type; + vector_type unrolled; + for_each(unrolled, increment_control(control)); + BOOST_TEST_EQ(control, 0); + + typedef list<> list_type; + list_type linear; + for_each(linear, increment_control(control)); + BOOST_TEST_EQ(control, 0); + } + + { + control = 0; + typedef vector vector_type; + vector_type unrolled ; + for_each(unrolled, increment_control(control)); + BOOST_TEST_EQ(control, 1); + + control = 0; + typedef list list_type; + list_type linear ; + for_each(linear, increment_control(control)); + BOOST_TEST_EQ(control, 1); + } + + { + control = 0; + typedef vector vector_type; + vector_type unrolled(1, 'x', 3.3, "Ruby"); + for_each(unrolled, increment_control(control)); + BOOST_TEST_EQ(control, 4); + + control = 0; + typedef list list_type; + list_type linear(1, 'x', 3.3, "Ruby"); + for_each(linear, increment_control(control)); + BOOST_TEST_EQ(control, 4); + } + + { + control = 0; + int array[100] = {}; + for_each(array, increment_control(control)); + BOOST_TEST_EQ(control, 100); + } + + { + char const ruby_long[] = "RubyLong"; + typedef vector vector_type; + vector_type v(1, 'x', 3.3, ruby_long); + for_each(v, apply_index_addition()); + BOOST_TEST_EQ(v, vector_type(1, 'y', 5.3, ruby_long + 3)); + std::cout << v << std::endl; + } + + { + char const ruby_long[] = "RubyLong"; + typedef vector vector_type; + vector_type v(1, 'x', 3.3, ruby_long); + for_each(v, mutable_apply_index_addition()); + BOOST_TEST_EQ(v, vector_type(1, 'y', 5.3, ruby_long + 3)); + std::cout << v << std::endl; + } + + { + typedef vector_c mpl_vec; + fusion::for_each(mpl_vec(), print()); + std::cout << std::endl; + } + + { + typedef vector_c mpl_vec; + fusion::for_each(mpl_vec(), apply_compile_time_index()); + std::cout << std::endl; + } + + return boost::report_errors(); +} +