Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 85 additions & 27 deletions include/boost/fusion/algorithm/iteration/detail/for_each.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,83 @@
#include <boost/fusion/iterator/deref.hpp>
#include <boost/fusion/iterator/distance.hpp>
#include <boost/fusion/support/category_of.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/utility/declval.hpp>
#include <boost/mpl/bool.hpp>

namespace boost { namespace fusion {
namespace detail
{
template <typename First, typename Last, typename F>
#if defined(BOOST_FUSION_HAS_INDEXED_FOREACH)
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template<typename T, typename F, typename I, typename = decltype(boost::declval<F>()(boost::declval<T>(), 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 <typename First, typename Last, typename F>
template<typename T, typename F, typename I, typename = decltype(boost::declval<F>()(boost::declval<T>(), 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<typename T, typename F, typename I, typename = decltype(boost::declval<F>()(boost::declval<T>(), I{}))>
BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED
inline void
for_each_apply(T&& value, F& f, I i, long)
{
f(std::forward<T>(value), i);
}
#endif
#endif

#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template<typename T, typename F, typename I>
BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED
inline void
for_each_apply(T& value, F& f, I /*i*/, int)
{
f(value);
}

template<typename T, typename F, typename I>
BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED
inline void
for_each_apply(T const& value, F& f, I /*i*/, int)
{
f(value);
}
#else
template<typename T, typename F, typename I>
BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED
inline void
for_each_apply(T&& value, F& f, I /*i*/, int)
{
f(std::forward<T>(value));
}
#endif

template <typename First, typename Last, typename F, typename I>
BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED
inline void
for_each_linear(First const&, Last const&, F const&, mpl::true_, I /*i*/)
{
}

template <typename First, typename Last, typename F, typename I>
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<typename result_of::next<First>::type, Last>());
result_of::equal_to<typename result_of::next<First>::type, Last>(),
boost::integral_constant<int, I::value + 1>());
}


Expand All @@ -49,74 +106,75 @@ namespace detail
, f
, result_of::equal_to<
typename result_of::begin<Sequence>::type
, typename result_of::end<Sequence>::type>());
, typename result_of::end<Sequence>::type>()
, boost::integral_constant<int, 0>());
}

template<int N>
template<int N, int S=0>
struct for_each_unrolled
{
template<typename I0, typename F>
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<int, S + 0>(), 1L);
typedef typename result_of::next<I0>::type I1;
I1 i1(fusion::next(i0));
f(*i1);
for_each_apply(*i1, f, boost::integral_constant<int, S + 1>(), 1L);
typedef typename result_of::next<I1>::type I2;
I2 i2(fusion::next(i1));
f(*i2);
for_each_apply(*i2, f, boost::integral_constant<int, S + 2>(), 1L);
typedef typename result_of::next<I2>::type I3;
I3 i3(fusion::next(i2));
f(*i3);
for_each_unrolled<N-4>::call(fusion::next(i3), f);
for_each_apply(*i3, f, boost::integral_constant<int, S + 3>(), 1L);
for_each_unrolled<N-4, S+4>::call(fusion::next(i3), f);
}
};

template<>
struct for_each_unrolled<3>
template<int S>
struct for_each_unrolled<3, S>
{
template<typename I0, typename F>
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<int, S + 0>(), 1L);
typedef typename result_of::next<I0>::type I1;
I1 i1(fusion::next(i0));
f(*i1);
for_each_apply(*i1, f, boost::integral_constant<int, S + 1>(), 1L);
typedef typename result_of::next<I1>::type I2;
I2 i2(fusion::next(i1));
f(*i2);
for_each_apply(*i2, f, boost::integral_constant<int, S + 2>(), 1L);
}
};

template<>
struct for_each_unrolled<2>
template<int S>
struct for_each_unrolled<2, S>
{
template<typename I0, typename F>
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<int, S + 0>(), 1L);
typedef typename result_of::next<I0>::type I1;
I1 i1(fusion::next(i0));
f(*i1);
for_each_apply(*i1, f, boost::integral_constant<int, S + 1>(), 1L);
}
};

template<>
struct for_each_unrolled<1>
template<int S>
struct for_each_unrolled<1, S>
{
template<typename I0, typename F>
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<int, S + 0>(), 1L);
}
};

template<>
struct for_each_unrolled<0>
template<int S>
struct for_each_unrolled<0, S>
{
template<typename It, typename F>
BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED
Expand Down
1 change: 1 addition & 0 deletions include/boost/fusion/algorithm/iteration/for_each.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define BOOST_FUSION_FOR_EACH_20070527_0943

#include <boost/fusion/support/config.hpp>
#include <boost/fusion/algorithm/iteration/for_each_fwd.hpp>
#include <boost/fusion/algorithm/iteration/detail/for_each.hpp>
#include <boost/fusion/algorithm/iteration/detail/segmented_for_each.hpp>
#include <boost/fusion/support/is_segmented.hpp>
Expand Down
12 changes: 12 additions & 0 deletions include/boost/fusion/algorithm/iteration/for_each_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@
#define BOOST_FUSION_FOR_EACH_FWD_HPP_INCLUDED

#include <boost/fusion/support/config.hpp>
#include <boost/config.hpp>

#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 <boost/fusion/support/is_sequence.hpp>
#include <boost/core/enable_if.hpp>

Expand Down
2 changes: 2 additions & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -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 ]
Expand Down
170 changes: 170 additions & 0 deletions test/algorithm/indexed_for_each.cpp
Original file line number Diff line number Diff line change
@@ -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 <boost/core/lightweight_test.hpp>
#include <boost/fusion/container/vector/vector.hpp>
#include <boost/fusion/container/list/list.hpp>
#include <boost/fusion/adapted/mpl.hpp>
#include <boost/fusion/adapted/array.hpp>
#include <boost/fusion/sequence/io/out.hpp>
#include <boost/fusion/sequence/comparison/equal_to.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/static_assert.hpp>

struct print
{
template <typename T, typename I>
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<typename T>
void operator()(T const& val, int i)
{
BOOST_TEST_EQ(i, control);
(void)val;
++ control;
}
};

struct apply_index_addition
{
template <typename T>
void operator()(T& v, int i) const
{
v += i;
}
};

struct mutable_apply_index_addition : apply_index_addition
{
template <typename T>
void operator()(T& v, int i)
{
return apply_index_addition::operator()(v, i);
}
};

template<typename V>
struct apply_compile_time_index
{
template <typename T, typename I>
void operator()(T, I) const
{
using boost::mpl::at;
typedef typename at<V,I>::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<int, char, double, char const*> 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<int> vector_type;
vector_type unrolled ;
for_each(unrolled, increment_control(control));
BOOST_TEST_EQ(control, 1);

control = 0;
typedef list<int> list_type;
list_type linear ;
for_each(linear, increment_control(control));
BOOST_TEST_EQ(control, 1);
}

{
control = 0;
typedef vector<int, char, double, char const*> 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<int, char, double, char const*> 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<int, char, double, char const*> 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<int, char, double, char const*> 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<int, 2, 3, 4, 5, 6> mpl_vec;
fusion::for_each(mpl_vec(), print());
std::cout << std::endl;
}

{
typedef vector_c<int, 45, 1, 34, 8, 95> mpl_vec;
fusion::for_each(mpl_vec(), apply_compile_time_index<mpl_vec>());
std::cout << std::endl;
}

return boost::report_errors();
}