Merge branch 'pr/zip_iterator/fusionize' of https://github.com/Flast/iterator into Flast-pr/zip_iterator/fusionize

This commit is contained in:
Edward Diener 2015-08-21 22:09:37 -04:00
commit a0533d97f5
6 changed files with 245 additions and 315 deletions

View File

@ -1,6 +1,8 @@
// Copyright David Abrahams and Thomas Becker 2000-2006. Distributed // Copyright David Abrahams and Thomas Becker 2000-2006.
// under the Boost Software License, Version 1.0. (See accompanying // Copyright Kohei Takahashi 2012-2014.
// file LICENSE_1_0.txt or copy at //
// 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) // http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_ZIP_ITERATOR_TMB_07_13_2003_HPP_ #ifndef BOOST_ZIP_ITERATOR_TMB_07_13_2003_HPP_
@ -12,19 +14,26 @@
#include <boost/iterator/iterator_facade.hpp> #include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/iterator_adaptor.hpp> // for enable_if_convertible #include <boost/iterator/iterator_adaptor.hpp> // for enable_if_convertible
#include <boost/iterator/iterator_categories.hpp> #include <boost/iterator/iterator_categories.hpp>
#include <boost/detail/iterator.hpp>
#include <boost/iterator/minimum_category.hpp> #include <boost/iterator/minimum_category.hpp>
#include <boost/tuple/tuple.hpp> #include <utility> // for std::pair
#include <boost/fusion/adapted/boost_tuple.hpp> // for backward compatibility
#include <boost/type_traits/is_same.hpp> #include <boost/type_traits/remove_reference.hpp>
#include <boost/mpl/and.hpp> #include <boost/type_traits/remove_cv.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/eval_if.hpp> #include <boost/mpl/at.hpp>
#include <boost/mpl/lambda.hpp> #include <boost/mpl/fold.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/placeholders.hpp> #include <boost/mpl/placeholders.hpp>
#include <boost/mpl/aux_/lambda_support.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/sequence/convert.hpp>
#include <boost/fusion/sequence/intrinsic/at_c.hpp>
#include <boost/fusion/sequence/comparison/equal_to.hpp>
#include <boost/fusion/support/tag_of_fwd.hpp>
namespace boost { namespace boost {
namespace iterators { namespace iterators {
@ -33,24 +42,6 @@ namespace iterators {
template<typename IteratorTuple> template<typename IteratorTuple>
class zip_iterator; class zip_iterator;
// One important design goal of the zip_iterator is to isolate all
// functionality whose implementation relies on the current tuple
// implementation. This goal has been achieved as follows: Inside
// the namespace detail there is a namespace tuple_impl_specific.
// This namespace encapsulates all functionality that is specific
// to the current Boost tuple implementation. More precisely, the
// namespace tuple_impl_specific provides the following tuple
// algorithms and meta-algorithms for the current Boost tuple
// implementation:
//
// tuple_meta_transform
// tuple_meta_accumulate
// tuple_transform
// tuple_for_each
//
// If the tuple implementation changes, all that needs to be
// replaced is the implementation of these four (meta-)algorithms.
namespace detail namespace detail
{ {
@ -73,313 +64,96 @@ namespace iterators {
struct increment_iterator struct increment_iterator
{ {
template<typename Iterator> template<typename Iterator>
void operator()(Iterator& it) void operator()(Iterator& it) const
{ ++it; } { ++it; }
}; };
// //
struct decrement_iterator struct decrement_iterator
{ {
template<typename Iterator> template<typename Iterator>
void operator()(Iterator& it) void operator()(Iterator& it) const
{ --it; } { --it; }
}; };
// //
struct dereference_iterator struct dereference_iterator
{ {
template<typename Iterator> template<typename>
struct apply struct result;
template<typename This, typename Iterator>
struct result<This(Iterator)>
{ {
typedef typename typedef typename
boost::detail::iterator_traits<Iterator>::reference remove_reference<typename remove_cv<Iterator>::type>::type
type; iterator;
typedef typename iterator_reference<iterator>::type type;
}; };
template<typename Iterator> template<typename Iterator>
typename apply<Iterator>::type operator()(Iterator const& it) typename result<dereference_iterator(Iterator)>::type
operator()(Iterator const& it) const
{ return *it; } { return *it; }
}; };
// The namespace tuple_impl_specific provides two meta-
// algorithms and two algorithms for tuples.
//
namespace tuple_impl_specific
{
// Meta-transform algorithm for tuples
//
template<typename Tuple, class UnaryMetaFun>
struct tuple_meta_transform;
template<typename Tuple, class UnaryMetaFun>
struct tuple_meta_transform_impl
{
typedef tuples::cons<
typename mpl::apply1<
typename mpl::lambda<UnaryMetaFun>::type
, typename Tuple::head_type
>::type
, typename tuple_meta_transform<
typename Tuple::tail_type
, UnaryMetaFun
>::type
> type;
};
template<typename Tuple, class UnaryMetaFun>
struct tuple_meta_transform
: mpl::eval_if<
boost::is_same<Tuple, tuples::null_type>
, mpl::identity<tuples::null_type>
, tuple_meta_transform_impl<Tuple, UnaryMetaFun>
>
{
};
// Meta-accumulate algorithm for tuples. Note: The template
// parameter StartType corresponds to the initial value in
// ordinary accumulation.
//
template<class Tuple, class BinaryMetaFun, class StartType>
struct tuple_meta_accumulate;
template<
typename Tuple
, class BinaryMetaFun
, typename StartType
>
struct tuple_meta_accumulate_impl
{
typedef typename mpl::apply2<
typename mpl::lambda<BinaryMetaFun>::type
, typename Tuple::head_type
, typename tuple_meta_accumulate<
typename Tuple::tail_type
, BinaryMetaFun
, StartType
>::type
>::type type;
};
template<
typename Tuple
, class BinaryMetaFun
, typename StartType
>
struct tuple_meta_accumulate
: mpl::eval_if<
boost::is_same<Tuple, tuples::null_type>
, mpl::identity<StartType>
, tuple_meta_accumulate_impl<
Tuple
, BinaryMetaFun
, StartType
>
>
{
};
#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \
|| ( \
BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, != 0) && defined(_MSC_VER) \
)
// Not sure why intel's partial ordering fails in this case, but I'm
// assuming int's an MSVC bug-compatibility feature.
# define BOOST_TUPLE_ALGO_DISPATCH
# define BOOST_TUPLE_ALGO(algo) algo##_impl
# define BOOST_TUPLE_ALGO_TERMINATOR , int
# define BOOST_TUPLE_ALGO_RECURSE , ...
#else
# define BOOST_TUPLE_ALGO(algo) algo
# define BOOST_TUPLE_ALGO_TERMINATOR
# define BOOST_TUPLE_ALGO_RECURSE
#endif
// transform algorithm for tuples. The template parameter Fun
// must be a unary functor which is also a unary metafunction
// class that computes its return type based on its argument
// type. For example:
//
// struct to_ptr
// {
// template <class Arg>
// struct apply
// {
// typedef Arg* type;
// }
//
// template <class Arg>
// Arg* operator()(Arg x);
// };
template<typename Fun>
inline tuples::null_type BOOST_TUPLE_ALGO(tuple_transform)
(tuples::null_type const&, Fun BOOST_TUPLE_ALGO_TERMINATOR)
{ return tuples::null_type(); }
template<typename Tuple, typename Fun>
inline typename tuple_meta_transform<
Tuple
, Fun
>::type
BOOST_TUPLE_ALGO(tuple_transform)(
const Tuple& t,
Fun f
BOOST_TUPLE_ALGO_RECURSE
)
{
typedef typename tuple_meta_transform<
BOOST_DEDUCED_TYPENAME Tuple::tail_type
, Fun
>::type transformed_tail_type;
return tuples::cons<
BOOST_DEDUCED_TYPENAME mpl::apply1<
Fun, BOOST_DEDUCED_TYPENAME Tuple::head_type
>::type
, transformed_tail_type
>(
f(boost::tuples::get<0>(t)), tuple_transform(t.get_tail(), f)
);
}
#ifdef BOOST_TUPLE_ALGO_DISPATCH
template<typename Tuple, typename Fun>
inline typename tuple_meta_transform<
Tuple
, Fun
>::type
tuple_transform(
const Tuple& t,
Fun f
)
{
return tuple_transform_impl(t, f, 1);
}
#endif
// for_each algorithm for tuples.
//
template<typename Fun>
inline Fun BOOST_TUPLE_ALGO(tuple_for_each)(
tuples::null_type
, Fun f BOOST_TUPLE_ALGO_TERMINATOR
)
{ return f; }
template<typename Tuple, typename Fun>
inline Fun BOOST_TUPLE_ALGO(tuple_for_each)(
Tuple& t
, Fun f BOOST_TUPLE_ALGO_RECURSE)
{
f( t.get_head() );
return tuple_for_each(t.get_tail(), f);
}
#ifdef BOOST_TUPLE_ALGO_DISPATCH
template<typename Tuple, typename Fun>
inline Fun
tuple_for_each(
Tuple& t,
Fun f
)
{
return tuple_for_each_impl(t, f, 1);
}
#endif
// Equality of tuples. NOTE: "==" for tuples currently (7/2003)
// has problems under some compilers, so I just do my own.
// No point in bringing in a bunch of #ifdefs here. This is
// going to go away with the next tuple implementation anyway.
//
inline bool tuple_equal(tuples::null_type, tuples::null_type)
{ return true; }
template<typename Tuple1, typename Tuple2>
inline bool tuple_equal(Tuple1 const& t1, Tuple2 const& t2)
{
return t1.get_head() == t2.get_head() &&
tuple_equal(t1.get_tail(), t2.get_tail());
}
}
//
// end namespace tuple_impl_specific
template<typename Iterator>
struct iterator_reference
{
typedef typename boost::detail::iterator_traits<Iterator>::reference type;
};
#ifdef BOOST_MPL_CFG_NO_FULL_LAMBDA_SUPPORT
// Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work
// out well. Instantiating the nested apply template also
// requires instantiating iterator_traits on the
// placeholder. Instead we just specialize it as a metafunction
// class.
template<>
struct iterator_reference<mpl::_1>
{
template <class T>
struct apply : iterator_reference<T> {};
};
#endif
// Metafunction to obtain the type of the tuple whose element types // Metafunction to obtain the type of the tuple whose element types
// are the reference types of an iterator tuple. // are the reference types of an iterator tuple.
// //
template<typename IteratorTuple> template<typename IteratorTuple>
struct tuple_of_references struct tuple_of_references
: tuple_impl_specific::tuple_meta_transform< : mpl::transform<
IteratorTuple, IteratorTuple,
iterator_reference<mpl::_1> iterator_reference<mpl::_1>
> >
{ {
}; };
// Specialization for std::pair
template<typename Iterator1, typename Iterator2>
struct tuple_of_references<std::pair<Iterator1, Iterator2> >
{
typedef std::pair<
typename iterator_reference<Iterator1>::type
, typename iterator_reference<Iterator2>::type
> type;
};
// Metafunction to obtain the minimal traversal tag in a tuple // Metafunction to obtain the minimal traversal tag in a tuple
// of iterators. // of iterators.
// //
template<typename IteratorTuple> template<typename IteratorTuple>
struct minimum_traversal_category_in_iterator_tuple struct minimum_traversal_category_in_iterator_tuple
{ {
typedef typename tuple_impl_specific::tuple_meta_transform< typedef typename mpl::transform<
IteratorTuple IteratorTuple
, pure_traversal_tag<iterator_traversal<> > , pure_traversal_tag<iterator_traversal<> >
>::type tuple_of_traversal_tags; >::type tuple_of_traversal_tags;
typedef typename tuple_impl_specific::tuple_meta_accumulate< typedef typename mpl::fold<
tuple_of_traversal_tags tuple_of_traversal_tags
, minimum_category<>
, random_access_traversal_tag , random_access_traversal_tag
, minimum_category<>
>::type type; >::type type;
}; };
// We need to call tuple_meta_accumulate with mpl::and_ as the template<typename Iterator1, typename Iterator2>
// accumulating functor. To this end, we need to wrap it into struct minimum_traversal_category_in_iterator_tuple<std::pair<Iterator1, Iterator2> >
// a struct that has exactly two arguments (that is, template {
// parameters) and not five, like mpl::and_ does. typedef typename pure_traversal_tag<
// typename iterator_traversal<Iterator1>::type
template<typename Arg1, typename Arg2> >::type iterator1_traversal;
struct and_with_two_args typedef typename pure_traversal_tag<
: mpl::and_<Arg1, Arg2> typename iterator_traversal<Iterator2>::type
{ >::type iterator2_traversal;
};
# ifdef BOOST_MPL_CFG_NO_FULL_LAMBDA_SUPPORT typedef typename minimum_category<
// Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work iterator1_traversal
// out well. In this case I think it's an MPL bug , typename minimum_category<
template<> iterator2_traversal
struct and_with_two_args<mpl::_1,mpl::_2> , random_access_traversal_tag
{ >::type
template <class A1, class A2> >::type type;
struct apply : mpl::and_<A1,A2> };
{};
};
# endif
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
// //
@ -401,9 +175,9 @@ namespace iterators {
typedef reference value_type; typedef reference value_type;
// Difference type is the first iterator's difference type // Difference type is the first iterator's difference type
typedef typename boost::detail::iterator_traits< typedef typename iterator_difference<
typename tuples::element<0, IteratorTuple>::type typename mpl::at_c<IteratorTuple, 0>::type
>::difference_type difference_type; >::type difference_type;
// Traversal catetgory is the minimum traversal category in the // Traversal catetgory is the minimum traversal category in the
// iterator tuple. // iterator tuple.
@ -429,6 +203,30 @@ namespace iterators {
{ {
typedef int type; typedef int type;
}; };
template <typename reference>
struct converter
{
template <typename Seq>
static reference call(Seq seq)
{
typedef typename fusion::traits::tag_of<reference>::type tag;
return fusion::convert<tag>(seq);
}
};
template <typename Reference1, typename Reference2>
struct converter<std::pair<Reference1, Reference2> >
{
typedef std::pair<Reference1, Reference2> reference;
template <typename Seq>
static reference call(Seq seq)
{
return reference(
fusion::at_c<0>(seq)
, fusion::at_c<1>(seq));
}
};
} }
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@ -484,10 +282,11 @@ namespace iterators {
// iterators in the iterator tuple. // iterators in the iterator tuple.
typename super_t::reference dereference() const typename super_t::reference dereference() const
{ {
return detail::tuple_impl_specific::tuple_transform( typedef typename super_t::reference reference;
get_iterator_tuple(), typedef detail::converter<reference> gen;
detail::dereference_iterator() return gen::call(fusion::transform(
); get_iterator_tuple(),
detail::dereference_iterator()));
} }
// Two zip iterators are equal if all iterators in the iterator // Two zip iterators are equal if all iterators in the iterator
@ -503,39 +302,35 @@ namespace iterators {
template<typename OtherIteratorTuple> template<typename OtherIteratorTuple>
bool equal(const zip_iterator<OtherIteratorTuple>& other) const bool equal(const zip_iterator<OtherIteratorTuple>& other) const
{ {
return detail::tuple_impl_specific::tuple_equal( return fusion::equal_to(
get_iterator_tuple(), get_iterator_tuple(),
other.get_iterator_tuple() other.get_iterator_tuple());
);
} }
// Advancing a zip iterator means to advance all iterators in the // Advancing a zip iterator means to advance all iterators in the
// iterator tuple. // iterator tuple.
void advance(typename super_t::difference_type n) void advance(typename super_t::difference_type n)
{ {
detail::tuple_impl_specific::tuple_for_each( fusion::for_each(
m_iterator_tuple, m_iterator_tuple,
detail::advance_iterator<BOOST_DEDUCED_TYPENAME super_t::difference_type>(n) detail::advance_iterator<BOOST_DEDUCED_TYPENAME super_t::difference_type>(n));
);
} }
// Incrementing a zip iterator means to increment all iterators in // Incrementing a zip iterator means to increment all iterators in
// the iterator tuple. // the iterator tuple.
void increment() void increment()
{ {
detail::tuple_impl_specific::tuple_for_each( fusion::for_each(
m_iterator_tuple, m_iterator_tuple,
detail::increment_iterator() detail::increment_iterator());
);
} }
// Decrementing a zip iterator means to decrement all iterators in // Decrementing a zip iterator means to decrement all iterators in
// the iterator tuple. // the iterator tuple.
void decrement() void decrement()
{ {
detail::tuple_impl_specific::tuple_for_each( fusion::for_each(
m_iterator_tuple, m_iterator_tuple,
detail::decrement_iterator() detail::decrement_iterator());
);
} }
// Distance is calculated using the first iterator in the tuple. // Distance is calculated using the first iterator in the tuple.
@ -544,8 +339,8 @@ namespace iterators {
const zip_iterator<OtherIteratorTuple>& other const zip_iterator<OtherIteratorTuple>& other
) const ) const
{ {
return boost::tuples::get<0>(other.get_iterator_tuple()) - return fusion::at_c<0>(other.get_iterator_tuple()) -
boost::tuples::get<0>(this->get_iterator_tuple()); fusion::at_c<0>(this->get_iterator_tuple());
} }
// Data Members // Data Members

View File

@ -14,11 +14,13 @@ test-suite iterator
[ run zip_iterator_test.cpp [ run zip_iterator_test.cpp
: : : : : :
# stlport's debug mode generates long symbols which overwhelm # stlport's debug mode generates long symbols which overwhelm
# vc6 # vc6
#<msvc-stlport><*><runtime-build>release #<msvc-stlport><*><runtime-build>release
] ]
[ run zip_iterator_test_fusion.cpp ]
[ run zip_iterator_test_std_tuple.cpp ]
[ run zip_iterator_test_std_pair.cpp ]
# These tests should work for just about everything. # These tests should work for just about everything.
[ compile is_lvalue_iterator.cpp ] [ compile is_lvalue_iterator.cpp ]

View File

@ -0,0 +1,73 @@
// Copyright (c) 2014 Kohei Takahashi.
//
// 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)
//
// See http://www.boost.org for most recent version including documentation.
#include <boost/detail/lightweight_test.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/fusion/include/at.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <vector>
#include <string>
int main()
{
typedef TUPLE<
std::vector<int>::iterator,
std::vector<std::string>::iterator
> iterator_tuple;
std::vector<int> vi = boost::assign::list_of(42)(72);
std::vector<std::string> vs = boost::assign::list_of("kokoro")("pyonpyon");
{
boost::zip_iterator<iterator_tuple> i1(MAKE_TUPLE(vi.begin(), vs.begin()));
boost::zip_iterator<iterator_tuple> i2 = i1;
BOOST_TEST( i1 == i2);
BOOST_TEST( i1++ == i2);
BOOST_TEST( i1 == (i2 + 1));
BOOST_TEST((i1 - 1) == i2);
BOOST_TEST( i1-- == ++i2);
BOOST_TEST( i1 == --i2);
}
{
boost::zip_iterator<iterator_tuple> i1(MAKE_TUPLE(vi.begin(), vs.begin()));
boost::zip_iterator<iterator_tuple> i2 = i1 + 1;
BOOST_TEST( i1 != i2);
BOOST_TEST( i1++ != i2);
BOOST_TEST( i1 != (i2 + 1));
BOOST_TEST((i1 - 1) != i2);
BOOST_TEST( i1-- != ++i2);
BOOST_TEST( i1 != --i2);
}
{
boost::zip_iterator<iterator_tuple> i(MAKE_TUPLE(vi.begin(), vs.begin()));
BOOST_TEST(boost::fusion::at_c<0>(* i ) == 42);
BOOST_TEST(boost::fusion::at_c<1>(* i ) == "kokoro");
BOOST_TEST(boost::fusion::at_c<0>(*(i + 1)) == 72);
BOOST_TEST(boost::fusion::at_c<1>(*(i + 1)) == "pyonpyon");
}
{
boost::zip_iterator<iterator_tuple> i1(MAKE_TUPLE(vi.begin(), vs.begin()));
boost::zip_iterator<iterator_tuple> i2(MAKE_TUPLE(vi.end(), vs.end()));
BOOST_TEST((i2 - i1) == 2);
++i1;
BOOST_TEST((i2 - i1) == 1);
--i2;
BOOST_TEST((i2 - i1) == 0);
}
return boost::report_errors();
}

View File

@ -0,0 +1,15 @@
// Copyright (c) 2014 Kohei Takahashi.
//
// 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)
//
// See http://www.boost.org for most recent version including documentation.
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/make_vector.hpp>
#define TUPLE boost::fusion::vector
#define MAKE_TUPLE boost::fusion::make_vector
#include "detail/zip_iterator_test.ipp"

View File

@ -0,0 +1,16 @@
// Copyright (c) 2014 Kohei Takahashi.
//
// 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)
//
// See http://www.boost.org for most recent version including documentation.
#include <utility>
#include <boost/fusion/adapted/std_pair.hpp>
#define TUPLE std::pair
#define MAKE_TUPLE std::make_pair
#include "detail/zip_iterator_test.ipp"

View File

@ -0,0 +1,29 @@
// Copyright (c) 2014 Kohei Takahashi.
//
// 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)
//
// See http://www.boost.org for most recent version including documentation.
#include <boost/config.hpp>
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#include <tuple>
#include <boost/fusion/adapted/std_tuple.hpp>
#define TUPLE std::tuple
#define MAKE_TUPLE std::make_tuple
#include "detail/zip_iterator_test.ipp"
#else
int main()
{
return 0;
}
#endif