/*============================================================================= | |
Copyright (c) 2001-2006 Joel de Guzman | |
Copyright (c) 2007 Dan Marsden | |
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) | |
==============================================================================*/ | |
#if !defined(BOOST_FUSION_COUNT_IF_09162005_0141) | |
#define BOOST_FUSION_COUNT_IF_09162005_0141 | |
#include <boost/mpl/bool.hpp> | |
#include <boost/fusion/sequence/intrinsic/begin.hpp> | |
#include <boost/fusion/sequence/intrinsic/end.hpp> | |
#include <boost/fusion/iterator/equal_to.hpp> | |
#include <boost/fusion/iterator/next.hpp> | |
#include <boost/fusion/iterator/deref.hpp> | |
#include <boost/fusion/iterator/equal_to.hpp> | |
#include <boost/fusion/iterator/distance.hpp> | |
#include <boost/fusion/iterator/advance.hpp> | |
namespace boost { namespace fusion { | |
struct random_access_traversal_tag; | |
namespace detail | |
{ | |
template <typename First, typename Last, typename F> | |
inline int | |
linear_count_if(First const&, Last const&, F const&, mpl::true_) | |
{ | |
return 0; | |
} | |
template <typename First, typename Last, typename F> | |
inline int | |
linear_count_if(First const& first, Last const& last, F& f, mpl::false_) | |
{ | |
int n = | |
detail::linear_count_if( | |
fusion::next(first) | |
, last | |
, f | |
, result_of::equal_to<typename result_of::next<First>::type, Last>()); | |
if (f(*first)) | |
++n; | |
return n; | |
} | |
template <typename Sequence, typename F, typename Tag> | |
inline int | |
count_if(Sequence const& seq, F f, Tag) | |
{ | |
return detail::linear_count_if( | |
fusion::begin(seq) | |
, fusion::end(seq) | |
, f | |
, result_of::equal_to< | |
typename result_of::begin<Sequence>::type | |
, typename result_of::end<Sequence>::type>()); | |
} | |
template<int n> | |
struct unrolled_count_if | |
{ | |
template<typename I0, typename F> | |
static int call(I0 const& i0, F f) | |
{ | |
int ct = unrolled_count_if<n-4>:: | |
call(fusion::advance_c<4>(i0), f); | |
if(f(*i0)) | |
++ct; | |
typedef typename result_of::next<I0>::type I1; | |
I1 i1(fusion::next(i0)); | |
if(f(*i1)) | |
++ct; | |
typedef typename result_of::next<I1>::type I2; | |
I2 i2(fusion::next(i1)); | |
if(f(*i2)) | |
++ct; | |
typedef typename result_of::next<I2>::type I3; | |
I3 i3(fusion::next(i2)); | |
if(f(*i3)) | |
++ct; | |
return ct; | |
} | |
}; | |
template<> | |
struct unrolled_count_if<3> | |
{ | |
template<typename I0, typename F> | |
static int call(I0 const& i0, F f) | |
{ | |
int ct = 0; | |
if(f(*i0)) | |
++ct; | |
typedef typename result_of::next<I0>::type I1; | |
I1 i1(fusion::next(i0)); | |
if(f(*i1)) | |
++ct; | |
typedef typename result_of::next<I1>::type I2; | |
I2 i2(fusion::next(i1)); | |
if(f(*i2)) | |
++ct; | |
return ct; | |
} | |
}; | |
template<> | |
struct unrolled_count_if<2> | |
{ | |
template<typename I0, typename F> | |
static int call(I0 const& i0, F f) | |
{ | |
int ct = 0; | |
if(f(*i0)) | |
++ct; | |
typedef typename result_of::next<I0>::type I1; | |
I1 i1(fusion::next(i0)); | |
if(f(*i1)) | |
++ct; | |
return ct; | |
} | |
}; | |
template<> | |
struct unrolled_count_if<1> | |
{ | |
template<typename I0, typename F> | |
static int call(I0 const& i0, F f) | |
{ | |
int ct = 0; | |
if(f(*i0)) | |
++ct; | |
return ct; | |
} | |
}; | |
template<> | |
struct unrolled_count_if<0> | |
{ | |
template<typename I0, typename F> | |
static int call(I0 const&, F) | |
{ | |
return 0; | |
} | |
}; | |
template <typename Sequence, typename F> | |
inline int | |
count_if(Sequence const& seq, F f, random_access_traversal_tag) | |
{ | |
typedef typename result_of::begin<Sequence>::type begin; | |
typedef typename result_of::end<Sequence>::type end; | |
return detail::unrolled_count_if<result_of::distance<begin, end>::type::value>:: | |
call(fusion::begin(seq), f); | |
} | |
}}} | |
#endif | |