From d26eebcd23b4000d643f6221e3c3ab64f2707b1a Mon Sep 17 00:00:00 2001 From: denzor200 Date: Sat, 6 Mar 2021 22:10:35 +0400 Subject: [PATCH 1/5] INDEXED: working variant without C++03 capability --- .../algorithm/iteration/detail/for_each.hpp | 74 ++++++---- test/Jamfile | 1 + test/algorithm/indexed_for_each.cpp | 135 ++++++++++++++++++ 3 files changed, 183 insertions(+), 27 deletions(-) create mode 100644 test/algorithm/indexed_for_each.cpp diff --git a/include/boost/fusion/algorithm/iteration/detail/for_each.hpp b/include/boost/fusion/algorithm/iteration/detail/for_each.hpp index c674511eb..aff5676bc 100644 --- a/include/boost/fusion/algorithm/iteration/detail/for_each.hpp +++ b/include/boost/fusion/algorithm/iteration/detail/for_each.hpp @@ -15,26 +15,45 @@ #include #include #include +#include +#include #include namespace boost { namespace fusion { namespace detail { - template + 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) { + std::forward(f)(std::forward(value), i); // TODO: disable rvalue && forward } - template + template 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&& value, F&& f, I /*i*/, int) { - f(*first); + std::forward(f)(std::forward(value)); + } + + 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 +68,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/test/Jamfile b/test/Jamfile index e55b15ad2..dc3b7e533 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -42,6 +42,7 @@ project [ run algorithm/insert.cpp ] [ run algorithm/insert_range.cpp ] [ run algorithm/iter_fold.cpp ] + [ run algorithm/indexed_for_each.cpp ] #TODO [ 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..bc45ea24a --- /dev/null +++ b/test/algorithm/indexed_for_each.cpp @@ -0,0 +1,135 @@ +/*============================================================================= + 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 + +struct print +{ + template + void operator()(T const& v, I) const + { + static_assert((I::value >= 0), ""); + std::cout << "[ " << I::value << " : " << v << " ] "; + } +}; + +struct increment_control +{ + int& 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); + } +}; + +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; + } + + { + vector<> unrolled = {}; + for_each(unrolled, increment_control{control}); + BOOST_TEST_EQ(control, 0); + + list<> linear = {}; + for_each(linear, increment_control{control}); + BOOST_TEST_EQ(control, 0); + } + + { + control = 0; + vector unrolled = {}; + for_each(unrolled, increment_control{control}); + BOOST_TEST_EQ(control, 1); + + control = 0; + list 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); + } + + { + 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; + } + + return boost::report_errors(); +} + From 708ed23595d00d403b6c765d2e58b0a23084aab9 Mon Sep 17 00:00:00 2001 From: denzor200 Date: Sat, 6 Mar 2021 23:00:52 +0400 Subject: [PATCH 2/5] Migrated to C++03 backward --- .../algorithm/iteration/detail/for_each.hpp | 44 ++++++++++++------- .../fusion/algorithm/iteration/for_each.hpp | 1 + .../algorithm/iteration/for_each_fwd.hpp | 12 +++++ test/Jamfile | 3 +- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/include/boost/fusion/algorithm/iteration/detail/for_each.hpp b/include/boost/fusion/algorithm/iteration/detail/for_each.hpp index aff5676bc..8eb5f285a 100644 --- a/include/boost/fusion/algorithm/iteration/detail/for_each.hpp +++ b/include/boost/fusion/algorithm/iteration/detail/for_each.hpp @@ -22,20 +22,30 @@ namespace boost { namespace fusion { namespace detail { +#if defined(BOOST_FUSION_HAS_INDEXED_FOREACH) template()(boost::declval(), I{}))> BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED inline void - for_each_apply(T&& value, F&& f, I i, long) + for_each_apply(T& value, F& f, I i, long) { - std::forward(f)(std::forward(value), i); // TODO: disable rvalue && forward + f(value, i); + } +#endif + + 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&& value, F&& f, I /*i*/, int) + for_each_apply(T const& value, F& f, I /*i*/, int) { - std::forward(f)(std::forward(value)); + f(value); } template @@ -45,7 +55,7 @@ namespace detail { } - template > + 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) @@ -53,7 +63,7 @@ namespace detail for_each_apply(*first, f, i, 1L); detail::for_each_linear(fusion::next(first), last, f, result_of::equal_to::type, Last>(), - boost::integral_constant{}); + boost::integral_constant()); } @@ -69,7 +79,7 @@ namespace detail , result_of::equal_to< typename result_of::begin::type , typename result_of::end::type>() - , boost::integral_constant{}); + , boost::integral_constant()); } template @@ -79,16 +89,16 @@ namespace detail BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED static void call(I0 const& i0, F& f) { - for_each_apply(*i0, f, boost::integral_constant{}, 1L); + for_each_apply(*i0, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I1; I1 i1(fusion::next(i0)); - for_each_apply(*i1, f, boost::integral_constant{}, 1L); + for_each_apply(*i1, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I2; I2 i2(fusion::next(i1)); - for_each_apply(*i2, f, boost::integral_constant{}, 1L); + for_each_apply(*i2, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I3; I3 i3(fusion::next(i2)); - for_each_apply(*i3, f, boost::integral_constant{}, 1L); + for_each_apply(*i3, f, boost::integral_constant(), 1L); for_each_unrolled::call(fusion::next(i3), f); } }; @@ -100,13 +110,13 @@ namespace detail BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED static void call(I0 const& i0, F& f) { - for_each_apply(*i0, f, boost::integral_constant{}, 1L); + for_each_apply(*i0, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I1; I1 i1(fusion::next(i0)); - for_each_apply(*i1, f, boost::integral_constant{}, 1L); + for_each_apply(*i1, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I2; I2 i2(fusion::next(i1)); - for_each_apply(*i2, f, boost::integral_constant{}, 1L); + for_each_apply(*i2, f, boost::integral_constant(), 1L); } }; @@ -117,10 +127,10 @@ namespace detail BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED static void call(I0 const& i0, F& f) { - for_each_apply(*i0, f, boost::integral_constant{}, 1L); + for_each_apply(*i0, f, boost::integral_constant(), 1L); typedef typename result_of::next::type I1; I1 i1(fusion::next(i0)); - for_each_apply(*i1, f, boost::integral_constant{}, 1L); + for_each_apply(*i1, f, boost::integral_constant(), 1L); } }; @@ -131,7 +141,7 @@ namespace detail BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED static void call(I0 const& i0, F& f) { - for_each_apply(*i0, f, boost::integral_constant{}, 1L); + for_each_apply(*i0, f, boost::integral_constant(), 1L); } }; 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 dc3b7e533..db2439a83 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -42,7 +42,8 @@ project [ run algorithm/insert.cpp ] [ run algorithm/insert_range.cpp ] [ run algorithm/iter_fold.cpp ] - [ run algorithm/indexed_for_each.cpp ] #TODO + [ run algorithm/indexed_for_each.cpp : : + : [ requires cxx11_decltype ] ] [ run algorithm/move.cpp : : : [ requires cxx11_rvalue_references ] ] [ run algorithm/none.cpp ] From 1a52996f4c321502beeeda314a414d33c44442ea Mon Sep 17 00:00:00 2001 From: denzor200 Date: Sat, 6 Mar 2021 23:38:51 +0400 Subject: [PATCH 3/5] Fix for building on C++11 --- .../algorithm/iteration/detail/for_each.hpp | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/boost/fusion/algorithm/iteration/detail/for_each.hpp b/include/boost/fusion/algorithm/iteration/detail/for_each.hpp index 8eb5f285a..dfd3ca599 100644 --- a/include/boost/fusion/algorithm/iteration/detail/for_each.hpp +++ b/include/boost/fusion/algorithm/iteration/detail/for_each.hpp @@ -23,6 +23,7 @@ namespace boost { namespace fusion { namespace detail { #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 @@ -30,8 +31,26 @@ namespace detail { f(value, i); } + + template()(boost::declval(), I{}))> + BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED + inline void + for_each_apply(T const& value, F& f, I i, long) + { + 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 @@ -47,6 +66,15 @@ namespace detail { 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 From 4af544ce580075b415cfbbbf1d80397463fe6706 Mon Sep 17 00:00:00 2001 From: denzor200 Date: Sat, 6 Mar 2021 23:41:57 +0400 Subject: [PATCH 4/5] Removed all unnecessary C++11 features from test --- test/algorithm/indexed_for_each.cpp | 35 ++++++++++++++++++----------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/test/algorithm/indexed_for_each.cpp b/test/algorithm/indexed_for_each.cpp index bc45ea24a..04c8fcdea 100644 --- a/test/algorithm/indexed_for_each.cpp +++ b/test/algorithm/indexed_for_each.cpp @@ -12,20 +12,25 @@ #include #include #include +#include struct print { template void operator()(T const& v, I) const { - static_assert((I::value >= 0), ""); + BOOST_STATIC_ASSERT(I::value >= 0); std::cout << "[ " << I::value << " : " << v << " ] "; } }; struct increment_control { - int& control; + int& control; + + increment_control(int& control) + : control(control) + {} template void operator()(T const& val, int i) @@ -71,24 +76,28 @@ main() } { - vector<> unrolled = {}; - for_each(unrolled, increment_control{control}); + typedef vector<> vector_type; + vector_type unrolled; + for_each(unrolled, increment_control(control)); BOOST_TEST_EQ(control, 0); - list<> linear = {}; - for_each(linear, increment_control{control}); + typedef list<> list_type; + list_type linear; + for_each(linear, increment_control(control)); BOOST_TEST_EQ(control, 0); } { control = 0; - vector unrolled = {}; - for_each(unrolled, increment_control{control}); + typedef vector vector_type; + vector_type unrolled ; + for_each(unrolled, increment_control(control)); BOOST_TEST_EQ(control, 1); control = 0; - list linear = {}; - for_each(linear, increment_control{control}); + typedef list list_type; + list_type linear ; + for_each(linear, increment_control(control)); BOOST_TEST_EQ(control, 1); } @@ -96,13 +105,13 @@ main() control = 0; typedef vector vector_type; vector_type unrolled(1, 'x', 3.3, "Ruby"); - for_each(unrolled, increment_control{control}); + 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}); + for_each(linear, increment_control(control)); BOOST_TEST_EQ(control, 4); } @@ -110,7 +119,7 @@ main() char const ruby_long[] = "RubyLong"; typedef vector vector_type; vector_type v(1, 'x', 3.3, ruby_long); - for_each(v, apply_index_addition{}); + for_each(v, apply_index_addition()); BOOST_TEST_EQ(v, vector_type(1, 'y', 5.3, ruby_long + 3)); std::cout << v << std::endl; } From a412b8df2ce5a9d55a549746fe928dbcdc70a1b8 Mon Sep 17 00:00:00 2001 From: denzor200 Date: Sun, 7 Mar 2021 00:21:46 +0400 Subject: [PATCH 5/5] Added important test cases --- test/algorithm/indexed_for_each.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/algorithm/indexed_for_each.cpp b/test/algorithm/indexed_for_each.cpp index 04c8fcdea..4df5eb1bb 100644 --- a/test/algorithm/indexed_for_each.cpp +++ b/test/algorithm/indexed_for_each.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,18 @@ struct mutable_apply_index_addition : apply_index_addition } }; +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() { @@ -115,6 +128,13 @@ main() 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; @@ -139,6 +159,12 @@ main() 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(); }