initial commit

[SVN r19978]
This commit is contained in:
Dave Abrahams 2003-09-09 03:22:50 +00:00
parent 3f49409843
commit 2c89e2b15a
2 changed files with 1662 additions and 0 deletions

View File

@ -0,0 +1,680 @@
// (C) Copyright David Abrahams and Thomas Becker 2000. Permission to
// copy, use, modify, sell and distribute this software is granted
// provided this copyright notice appears in all copies. This software
// is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
// Compilers Tested:
// =================
// Metrowerks Codewarrior Pro 7.2, 8.3
// gcc 2.95.3
// gcc 3.2
// Microsoft VC 6sp5 (test fails due to some compiler bug)
// Microsoft VC 7 (works)
// Microsoft VC 7.1
// Intel 5
// Intel 6
// Intel 7.1
// Intel 8
// Borland 5.5.1 (broken due to lack of support from Boost.Tuples)
#ifndef BOOST_ZIP_ITERATOR_TMB_07_13_2003_HPP_
#include <stddef.h>
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_traits.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/iterator_adaptor.hpp> // for enable_if_convertible
#include <boost/iterator/iterator_categories.hpp>
#include <boost/tuple/tuple.hpp>
#if BOOST_WORKAROUND(__GNUC__, == 2) || BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
# include <boost/type_traits/remove_cv.hpp>
#endif
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/apply_if.hpp>
#include <boost/mpl/lambda.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/aux_/lambda_support.hpp>
namespace boost {
// Zip iterator forward declaration for zip_iterator_base
template<typename IteratorTuple>
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.
//
// Unfortunately, some compilers, including Metrowerks Codewarrior
// 4.2.5.766 and gcc 3.3, were unable to handle the template
// code involved (Metrowerks: internal compiler error, gcc 3.3:
// segmentation fault). Therefore, rather regrettably, for those
// compilers, the encapsulation of the tuple implementation-
// specific code is not nearly as nice and clean as it should be.
// In order to emphasize this point, I have provided the entire
// namespace detail in this file twice: the first version is the
// clean one with the nice encapsulation, the second one is the
// dirty one.
//
namespace detail
{
// Functors to be used with tuple algorithms
//
template<typename DiffType>
class advance_iterator
{
public:
advance_iterator(DiffType step) : m_step(step) {}
template<typename Iterator>
void operator()(Iterator& it) const
{ it += m_step; }
private:
DiffType m_step;
};
//
struct increment_iterator
{
template<typename Iterator>
void operator()(Iterator& it)
{ ++it; }
};
//
struct decrement_iterator
{
template<typename Iterator>
void operator()(Iterator& it)
{ --it; }
};
//
struct dereference_iterator
{
template<typename Iterator>
struct apply
{
#if BOOST_WORKAROUND(__GNUC__, == 2) || BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
typedef typename
std::iterator_traits<
typename boost::remove_cv<Iterator>::type
>::reference
type;
#else
typedef typename
std::iterator_traits<Iterator>::reference
type;
#endif
};
template<typename Iterator>
typename apply<Iterator>::type operator()(Iterator& 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::apply_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::apply_if<
#if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
mpl::or_<
#endif
boost::is_same<Tuple, tuples::null_type>
#if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
, boost::is_same<Tuple,int>
>
#endif
, 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>
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>
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<
typename Tuple::tail_type
, Fun
>::type transformed_tail_type;
return tuples::cons<
typename mpl::apply1<Fun, 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>
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>
Fun BOOST_TUPLE_ALGO(tuple_for_each)(
tuples::null_type
, Fun f BOOST_TUPLE_ALGO_TERMINATOR
)
{ return f; }
template<typename Tuple, typename Fun>
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>
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.
//
bool tuple_equal(tuples::null_type, tuples::null_type)
{ return true; }
template<typename Tuple1, typename Tuple2>
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 iterator_traits<Iterator>::reference type;
};
#ifdef BOOST_MPL_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
// are the reference types of an iterator tuple.
//
template<typename IteratorTuple>
struct tuple_of_references
: tuple_impl_specific::tuple_meta_transform<
IteratorTuple,
iterator_reference<mpl::_1>
>
{
};
// Metafunction to obtain the minimal traversal tag in a tuple
// of iterators.
//
template<typename IteratorTuple>
struct minimum_traversal_category_in_iterator_tuple
{
typedef typename tuple_impl_specific::tuple_meta_transform<
IteratorTuple
, traversal_category<mpl::_1>
>::type tuple_of_traversal_tags;
typedef typename tuple_impl_specific::tuple_meta_accumulate<
tuple_of_traversal_tags
, minimum_category<mpl::_1,mpl::_2>
, random_access_traversal_tag
>::type type;
};
#if BOOST_WORKAROUND(BOOST_MSVC, == 1200) // ETI workaround
template <>
struct minimum_traversal_category_in_iterator_tuple<int>
{
typedef int type;
};
#endif
template<typename Iterator>
struct iterator_is_readable
: is_tag<
readable_iterator_tag
, typename access_category<Iterator>::type
>
{
BOOST_MPL_AUX_LAMBDA_SUPPORT(1, iterator_is_readable, (Iterator))
};
# ifdef BOOST_MPL_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_is_readable<mpl::_1>
{
template <class T>
struct apply : iterator_is_readable<T>
{};
};
# endif
// We need to call tuple_meta_accumulate with mpl::and_ as the
// accumulating functor. To this end, we need to wrap it into
// a struct that has exactly two arguments (that is, template
// parameters) and not five, like mpl::and_ does.
//
template<typename Arg1, typename Arg2>
struct and_with_two_args
: mpl::and_<Arg1, Arg2>
{
};
# ifdef BOOST_MPL_NO_FULL_LAMBDA_SUPPORT
// Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work
// out well. In this case I think it's an MPL bug
template<>
struct and_with_two_args<mpl::_1,mpl::_2>
{
template <class A1, class A2>
struct apply : mpl::and_<A1,A2>
{};
};
# endif
// Metafunction to assert that all iterators in a tuple are
// readable.
//
// Probably not worth it, IMO. Why not a writable zip_iterator
// anyway? -- dwa.
//
template<typename IteratorTuple>
struct all_iterators_in_tuple_readable
{
typedef typename tuple_impl_specific::tuple_meta_transform<
IteratorTuple,
iterator_is_readable<mpl::_1>
>::type tuple_of_readability_bools;
typedef typename tuple_impl_specific::tuple_meta_accumulate<
tuple_of_readability_bools,
and_with_two_args<mpl::_1,mpl::_2>
, mpl::bool_<true>
>::type type;
};
///////////////////////////////////////////////////////////////////
//
// Class zip_iterator_base
//
// Builds and exposes the iterator facade type from which the zip
// iterator will be derived.
//
template<typename IteratorTuple>
struct zip_iterator_base
{
private:
#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
// seems to give vc7's parser fits, and vc6 needs help here too
BOOST_STATIC_ASSERT(
detail::all_iterators_in_tuple_readable<
IteratorTuple
>::type::value
);
#endif
// Reference type is the type of the tuple obtained from the
// iterators' reference types.
typedef typename
detail::tuple_of_references<IteratorTuple>::type reference;
// Value type is the same as reference type.
typedef reference value_type;
// Difference type is the first iterator's difference type
typedef typename iterator_traits<
typename tuples::element<0, IteratorTuple>::type
>::difference_type difference_type;
// Traversal catetgory is the minimum traversal category in the
// iterator tuple.
typedef typename
detail::minimum_traversal_category_in_iterator_tuple<
IteratorTuple
>::type traversal_category;
// Access category is readable_iterator_tag. It has been
// asserted that all iterators in the tuple are readable.
typedef readable_iterator_tag access_category;
public:
// The iterator facade type from which the zip iterator will
// be derived.
typedef iterator_facade<
zip_iterator<IteratorTuple>,
value_type,
access_category,
traversal_category,
reference,
difference_type
> type;
};
template <>
struct zip_iterator_base<int>
{
typedef int type;
};
}
/////////////////////////////////////////////////////////////////////
//
// zip_iterator class definition
//
template<typename IteratorTuple>
class zip_iterator :
public detail::zip_iterator_base<IteratorTuple>::type
{
// Typedef super_t as our base class.
typedef typename
detail::zip_iterator_base<IteratorTuple>::type super_t;
// iterator_core_access is the iterator's best friend.
friend class iterator_core_access;
public:
// Construction
// ============
// Default constructor
zip_iterator() { }
// Constructor from iterator tuple
zip_iterator(IteratorTuple iterator_tuple)
: m_iterator_tuple(iterator_tuple)
{ }
// Copy constructor
template<typename OtherIteratorTuple>
zip_iterator(
const zip_iterator<OtherIteratorTuple>& other,
typename enable_if_convertible<
OtherIteratorTuple,
IteratorTuple
>::type* = 0
) : m_iterator_tuple(other.get_iterator_tuple())
{}
// Get method for the iterator tuple.
const IteratorTuple& get_iterator_tuple() const
{ return m_iterator_tuple; }
private:
// Implementation of Iterator Operations
// =====================================
// Dereferencing returns a tuple built from the dereferenced
// iterators in the iterator tuple.
typename super_t::reference dereference() const
{
return detail::tuple_impl_specific::tuple_transform(
get_iterator_tuple(),
detail::dereference_iterator()
);
}
// Two zip iterators are equal if all iterators in the iterator
// tuple are equal. NOTE: It should be possible to implement this
// as
//
// return get_iterator_tuple() == other.get_iterator_tuple();
//
// but equality of tuples currently (7/2003) does not compile
// under several compilers. No point in bringing in a bunch
// of #ifdefs here.
//
template<typename OtherIteratorTuple>
bool equal(const zip_iterator<OtherIteratorTuple>& other) const
{
return detail::tuple_impl_specific::tuple_equal(
get_iterator_tuple(),
other.get_iterator_tuple()
);
}
// Advancing a zip iterator means to advance all iterators in the
// iterator tuple.
void advance(typename super_t::difference_type n)
{
detail::tuple_impl_specific::tuple_for_each(
m_iterator_tuple,
detail::advance_iterator<typename super_t::difference_type>(n)
);
}
// Incrementing a zip iterator means to increment all iterators in
// the iterator tuple.
void increment()
{
detail::tuple_impl_specific::tuple_for_each(
m_iterator_tuple,
detail::increment_iterator()
);
}
// Decrementing a zip iterator means to decrement all iterators in
// the iterator tuple.
void decrement()
{
detail::tuple_impl_specific::tuple_for_each(
m_iterator_tuple,
detail::decrement_iterator()
);
}
// Distance is calculated using the first iterator in the tuple.
template<typename OtherIteratorTuple>
typename super_t::difference_type distance_to(
const zip_iterator<OtherIteratorTuple>& other
) const
{
return boost::tuples::get<0>(other.get_iterator_tuple()) -
boost::tuples::get<0>(this->get_iterator_tuple());
}
// Data Members
// ============
// The iterator tuple.
IteratorTuple m_iterator_tuple;
};
// Make function for zip iterator
//
template<typename IteratorTuple>
zip_iterator<IteratorTuple>
make_zip_iterator(IteratorTuple t)
{ return zip_iterator<IteratorTuple>(t); }
}
#endif

982
test/zip_iterator_test.cpp Executable file
View File

@ -0,0 +1,982 @@
// (C) Copyright Dave Abrahams and Thomas Becker 2003. Permission to
// copy, use, modify, sell and distribute this software is granted
// provided this copyright notice appears in all copies. This software
// is provided "as is" without express or implied warranty, and with
// no claim as to its suitability for any purpose.
//
// File:
// =====
// zip_iterator_test_main.cpp
// Author:
// =======
// Thomas Becker
// Created:
// ========
// Jul 15, 2003
// Purpose:
// ========
// Test driver for zip_iterator.hpp
// Compilers Tested:
// =================
// Metrowerks Codewarrior Pro 7.2, 8.3
// gcc 2.95.3
// gcc 3.2
// Microsoft VC 6sp5 (test fails due to some compiler bug)
// Microsoft VC 7 (works)
// Microsoft VC 7.1
// Intel 5
// Intel 6
// Intel 7.1
// Intel 8
// Borland 5.5.1 (broken due to lack of support from Boost.Tuples)
/////////////////////////////////////////////////////////////////////////////
//
// Includes
//
/////////////////////////////////////////////////////////////////////////////
#include <boost/iterator/zip_iterator.hpp>
#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <boost/tuple/tuple.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/detail/workaround.hpp>
#include <stddef.h>
// Uncomment to see static assert.
// #define PROVOKE_STATIC_ASSERT
/////////////////////////////////////////////////////////////////////////////
//
// Fake iterator for testing zip iterator categories
//
/////////////////////////////////////////////////////////////////////////////
class fake_writable_iterator
{
public:
typedef int& reference;
typedef int value_type;
typedef int* pointer;
typedef ptrdiff_t difference_type;
typedef boost::iterator_tag<
boost::writable_iterator_tag,
boost::forward_traversal_tag
> iterator_category;
};
/////////////////////////////////////////////////////////////////////////////
//
// Das Main Funktion
//
/////////////////////////////////////////////////////////////////////////////
int main( void )
{
std::cout << "\n"
<< "***********************************************\n"
<< "* *\n"
<< "* Test driver for boost::zip_iterator *\n"
<< "* Copyright Thomas Becker 2003 *\n"
<< "* *\n"
<< "***********************************************\n\n"
<< std::flush;
size_t num_successful_tests = 0;
size_t num_failed_tests = 0;
/////////////////////////////////////////////////////////////////////////////
//
// Make sure tuples are supported
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Basic tuple support: "
<< std::flush;
typedef boost::tuples::tuple<int, double> mytuple;
mytuple t1;
boost::tuples::get<0>(t1) = 42;
boost::tuples::get<1>(t1) = 42.1;
if( 2 == boost::tuples::length<mytuple>::value &&
42 == boost::tuples::get<0>(t1) &&
42.1 == boost::tuples::get<1>(t1)
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Make sure iterator adaptor is supported
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Basic iterator adaptor support: "
<< std::flush;
std::set<int> s;
s.insert(42);
s.insert(43);
s.insert(44);
typedef boost::transform_iterator<
std::binder1st<std::plus<int> >,
std::set<int>::iterator
>
add_seven_iterator;
typedef boost::transform_iterator<
std::binder1st<std::plus<int> >,
std::set<int>::const_iterator
>
const_add_seven_iterator;
add_seven_iterator set_run(s.begin(), std::bind1st(std::plus<int>(), 7));
add_seven_iterator set_end(s.end(), std::bind1st(std::plus<int>(), 7));
const_add_seven_iterator const_set_run(s.begin(), std::bind1st(std::plus<int>(), 7));
// set_run = const_set_run; // Error: can't convert from const to non-const
const_set_run = set_run;
if( 49 == *set_run &&
50 == *++set_run &&
51 == *++set_run &&
set_end == ++set_run &&
49 == *const_set_run &&
50 == *++const_set_run &&
51 == *++const_set_run &&
set_end == ++const_set_run
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator construction and dereferencing
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator construction and dereferencing: "
<< std::flush;
std::vector<double> vect1(3);
vect1[0] = 42.;
vect1[1] = 43.;
vect1[2] = 44.;
std::set<int> intset;
intset.insert(52);
intset.insert(53);
intset.insert(54);
//
boost::zip_iterator<
boost::tuples::tuple<
std::set<int>::iterator
, std::vector<double>::iterator
>
>
zip_it_mixed(
boost::make_tuple(
intset.begin()
, vect1.begin()
)
);
boost::tuples::tuple<int, double> val_tuple(
*zip_it_mixed);
boost::tuples::tuple<const int&, double&> ref_tuple(
*zip_it_mixed);
double dblOldVal = boost::tuples::get<1>(ref_tuple);
boost::tuples::get<1>(ref_tuple) -= 41.;
if( 52 == boost::tuples::get<0>(val_tuple) &&
42. == boost::tuples::get<1>(val_tuple) &&
52 == boost::tuples::get<0>(ref_tuple) &&
1. == boost::tuples::get<1>(ref_tuple) &&
1. == *vect1.begin()
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
// Undo change to vect1
boost::tuples::get<1>(ref_tuple) = dblOldVal;
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator with 12 components
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterators with 12 components: "
<< std::flush;
// Declare 12 containers
//
std::list<int> li1;
li1.push_back(1);
std::set<int> se1;
se1.insert(2);
std::vector<int> ve1;
ve1.push_back(3);
//
std::list<int> li2;
li2.push_back(4);
std::set<int> se2;
se2.insert(5);
std::vector<int> ve2;
ve2.push_back(6);
//
std::list<int> li3;
li3.push_back(7);
std::set<int> se3;
se3.insert(8);
std::vector<int> ve3;
ve3.push_back(9);
//
std::list<int> li4;
li4.push_back(10);
std::set<int> se4;
se4.insert(11);
std::vector<int> ve4;
ve4.push_back(12);
// typedefs for cons lists of iterators.
typedef boost::tuples::cons<
std::set<int>::iterator,
boost::tuples::tuple<
std::vector<int>::iterator,
std::list<int>::iterator,
std::set<int>::iterator,
std::vector<int>::iterator,
std::list<int>::iterator,
std::set<int>::iterator,
std::vector<int>::iterator,
std::list<int>::iterator,
std::set<int>::iterator,
std::vector<int>::const_iterator
>::inherited
> cons_11_its_type;
//
typedef boost::tuples::cons<
std::list<int>::const_iterator,
cons_11_its_type
> cons_12_its_type;
// typedefs for cons lists for dereferencing the zip iterator
// made from the cons list above.
typedef boost::tuples::cons<
const int&,
boost::tuples::tuple<
int&,
int&,
const int&,
int&,
int&,
const int&,
int&,
int&,
const int&,
const int&
>::inherited
> cons_11_refs_type;
//
typedef boost::tuples::cons<
const int&,
cons_11_refs_type
> cons_12_refs_type;
// typedef for zip iterator with 12 elements
typedef boost::zip_iterator<cons_12_its_type> zip_it_12_type;
// Declare a 12-element zip iterator.
zip_it_12_type zip_it_12(
cons_12_its_type(
li1.begin(),
cons_11_its_type(
se1.begin(),
boost::make_tuple(
ve1.begin(),
li2.begin(),
se2.begin(),
ve2.begin(),
li3.begin(),
se3.begin(),
ve3.begin(),
li4.begin(),
se4.begin(),
ve4.begin()
)
)
)
);
// Dereference, mess with the result a little.
cons_12_refs_type zip_it_12_dereferenced(*zip_it_12);
boost::tuples::get<9>(zip_it_12_dereferenced) = 42;
// Make a copy and move it a little to force some instantiations.
zip_it_12_type zip_it_12_copy(zip_it_12);
++zip_it_12_copy;
if( boost::tuples::get<11>(zip_it_12.get_iterator_tuple()) == ve4.begin() &&
boost::tuples::get<11>(zip_it_12_copy.get_iterator_tuple()) == ve4.end() &&
1 == boost::tuples::get<0>(zip_it_12_dereferenced) &&
12 == boost::tuples::get<11>(zip_it_12_dereferenced) &&
42 == *(li4.begin())
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator incrementing and dereferencing
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator ++ and *: "
<< std::flush;
std::vector<double> vect2(3);
vect2[0] = 2.2;
vect2[1] = 3.3;
vect2[2] = 4.4;
boost::zip_iterator<
boost::tuples::tuple<
std::vector<double>::const_iterator,
std::vector<double>::const_iterator
>
>
zip_it_begin(
boost::make_tuple(
vect1.begin(),
vect2.begin()
)
);
boost::zip_iterator<
boost::tuples::tuple<
std::vector<double>::const_iterator,
std::vector<double>::const_iterator
>
>
zip_it_run(
boost::make_tuple(
vect1.begin(),
vect2.begin()
)
);
boost::zip_iterator<
boost::tuples::tuple<
std::vector<double>::const_iterator,
std::vector<double>::const_iterator
>
>
zip_it_end(
boost::make_tuple(
vect1.end(),
vect2.end()
)
);
if( zip_it_run == zip_it_begin &&
42. == boost::tuples::get<0>(*zip_it_run) &&
2.2 == boost::tuples::get<1>(*zip_it_run) &&
43. == boost::tuples::get<0>(*(++zip_it_run)) &&
3.3 == boost::tuples::get<1>(*zip_it_run) &&
44. == boost::tuples::get<0>(*(++zip_it_run)) &&
4.4 == boost::tuples::get<1>(*zip_it_run) &&
zip_it_end == ++zip_it_run
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator decrementing and dereferencing
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator -- and *: "
<< std::flush;
if( zip_it_run == zip_it_end &&
zip_it_end == zip_it_run-- &&
44. == boost::tuples::get<0>(*zip_it_run) &&
4.4 == boost::tuples::get<1>(*zip_it_run) &&
43. == boost::tuples::get<0>(*(--zip_it_run)) &&
3.3 == boost::tuples::get<1>(*zip_it_run) &&
42. == boost::tuples::get<0>(*(--zip_it_run)) &&
2.2 == boost::tuples::get<1>(*zip_it_run) &&
zip_it_begin == zip_it_run
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator copy construction and equality
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator copy construction and equality: "
<< std::flush;
boost::zip_iterator<
boost::tuples::tuple<
std::vector<double>::const_iterator,
std::vector<double>::const_iterator
>
> zip_it_run_copy(zip_it_run);
if(zip_it_run == zip_it_run && zip_it_run == zip_it_run_copy)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator inequality
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator inequality: "
<< std::flush;
if(!(zip_it_run != zip_it_run_copy) && zip_it_run != ++zip_it_run_copy)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator less than
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator less than: "
<< std::flush;
// Note: zip_it_run_copy == zip_it_run + 1
//
if( zip_it_run < zip_it_run_copy &&
!( zip_it_run < --zip_it_run_copy) &&
zip_it_run == zip_it_run_copy
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator less than or equal
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "zip iterator less than or equal: "
<< std::flush;
// Note: zip_it_run_copy == zip_it_run
//
++zip_it_run;
zip_it_run_copy += 2;
if( zip_it_run <= zip_it_run_copy &&
zip_it_run <= --zip_it_run_copy &&
!( zip_it_run <= --zip_it_run_copy) &&
zip_it_run <= zip_it_run
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator greater than
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator greater than: "
<< std::flush;
// Note: zip_it_run_copy == zip_it_run - 1
//
if( zip_it_run > zip_it_run_copy &&
!( zip_it_run > ++zip_it_run_copy) &&
zip_it_run == zip_it_run_copy
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator greater than or equal
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator greater than or equal: "
<< std::flush;
++zip_it_run;
// Note: zip_it_run == zip_it_run_copy + 1
//
if( zip_it_run >= zip_it_run_copy &&
--zip_it_run >= zip_it_run_copy &&
! (zip_it_run >= ++zip_it_run_copy)
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator + int
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator + int: "
<< std::flush;
// Note: zip_it_run == zip_it_run_copy - 1
//
zip_it_run = zip_it_run + 2;
++zip_it_run_copy;
if( zip_it_run == zip_it_run_copy && zip_it_run == zip_it_begin + 3 )
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator - int
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator - int: "
<< std::flush;
// Note: zip_it_run == zip_it_run_copy, and both are at end position
//
zip_it_run = zip_it_run - 2;
--zip_it_run_copy;
--zip_it_run_copy;
if( zip_it_run == zip_it_run_copy && (zip_it_run - 1) == zip_it_begin )
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator +=
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator +=: "
<< std::flush;
// Note: zip_it_run == zip_it_run_copy, and both are at begin + 1
//
zip_it_run += 2;
if( zip_it_run == zip_it_begin + 3 )
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator -=
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator -=: "
<< std::flush;
// Note: zip_it_run is at end position, zip_it_run_copy is at
// begin plus one.
//
zip_it_run -= 2;
if( zip_it_run == zip_it_run_copy )
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator getting member iterators
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator member iterators: "
<< std::flush;
// Note: zip_it_run and zip_it_run_copy are both at
// begin plus one.
//
if( boost::tuples::get<0>(zip_it_run.get_iterator_tuple()) == vect1.begin() + 1 &&
boost::tuples::get<1>(zip_it_run.get_iterator_tuple()) == vect2.begin() + 1
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Making zip iterators
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Making zip iterators: "
<< std::flush;
std::vector<boost::tuples::tuple<double, double> >
vect_of_tuples(3);
std::copy(
boost::make_zip_iterator(
boost::make_tuple(
vect1.begin(),
vect2.begin()
)
),
boost::make_zip_iterator(
boost::make_tuple(
vect1.end(),
vect2.end()
)
),
vect_of_tuples.begin()
);
if( 42. == boost::tuples::get<0>(*vect_of_tuples.begin()) &&
2.2 == boost::tuples::get<1>(*vect_of_tuples.begin()) &&
43. == boost::tuples::get<0>(*(vect_of_tuples.begin() + 1)) &&
3.3 == boost::tuples::get<1>(*(vect_of_tuples.begin() + 1)) &&
44. == boost::tuples::get<0>(*(vect_of_tuples.begin() + 2)) &&
4.4 == boost::tuples::get<1>(*(vect_of_tuples.begin() + 2))
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator non-const --> const conversion
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator non-const to const conversion: "
<< std::flush;
boost::zip_iterator<
boost::tuples::tuple<
std::set<int>::const_iterator,
std::vector<double>::const_iterator
>
>
zip_it_const(
boost::make_tuple(
intset.begin(),
vect2.begin()
)
);
//
boost::zip_iterator<
boost::tuples::tuple<
std::set<int>::iterator,
std::vector<double>::const_iterator
>
>
zip_it_half_const(
boost::make_tuple(
intset.begin(),
vect2.begin()
)
);
//
boost::zip_iterator<
boost::tuples::tuple<
std::set<int>::iterator,
std::vector<double>::iterator
>
>
zip_it_non_const(
boost::make_tuple(
intset.begin(),
vect2.begin()
)
);
zip_it_half_const = ++zip_it_non_const;
zip_it_const = zip_it_half_const;
++zip_it_const;
// zip_it_non_const = ++zip_it_const; // Error: can't convert from const to non-const
if( 54 == boost::tuples::get<0>(*zip_it_const) &&
4.4 == boost::tuples::get<1>(*zip_it_const) &&
53 == boost::tuples::get<0>(*zip_it_half_const) &&
3.3 == boost::tuples::get<1>(*zip_it_half_const)
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
//
// Zip iterator categories
//
/////////////////////////////////////////////////////////////////////////////
std::cout << "Zip iterator categories: "
<< std::flush;
// The big iterator of the previous test has vector, list, and set iterators.
// Therefore, it must be bidirectional, but not random access.
bool bBigItIsBidirectionalIterator = boost::is_same<
boost::bidirectional_traversal_tag,
boost::traversal_category<zip_it_12_type>::type
>::value;
//
bool bBigItIsRandomAccessIterator = boost::is_same<
boost::random_access_traversal_tag,
boost::traversal_category<zip_it_12_type>::type
>::value;
//
bool bBigItIsReadableIterator = boost::is_same<
boost::readable_iterator_tag,
boost::access_category<zip_it_12_type>::type
>::value;
//
bool bBigItIsReadableLValueIterator = boost::is_same<
boost::readable_lvalue_iterator_tag,
boost::access_category<zip_it_12_type>::type
>::value;
// A combining iterator with all vector iterators must have random access
// traversal.
//
typedef boost::zip_iterator<
boost::tuples::tuple<
std::vector<double>::const_iterator,
std::vector<double>::const_iterator
>
> all_vects_type;
bool bAllVectsIsRandomAccessIterator = boost::is_same<
boost::random_access_traversal_tag,
boost::traversal_category<all_vects_type>::type
>::value;
//
bool bAllVectsIsReadableIterator = boost::is_same<
boost::readable_iterator_tag,
boost::access_category<all_vects_type>::type
>::value;
//
bool bAllVectsIsReadableLValueIterator = boost::is_same<
boost::readable_lvalue_iterator_tag,
boost::access_category<all_vects_type>::type
>::value;
// Test if the meta function all_iterators_readable, which is used
// for compile-time asserting, works.
//
bool bAllIteratorsReadable1 =
boost::detail::all_iterators_in_tuple_readable<
boost::tuples::tuple<
std::vector<int>::const_iterator,
std::set<double>::iterator
>
>::type::value;
bool bAllIteratorsReadable2 =
boost::detail::all_iterators_in_tuple_readable<
boost::tuples::tuple<
std::vector<int>::const_iterator,
fake_writable_iterator,
std::set<double>::iterator
>
>::type::value;
// Compile-time assert because of non-readable iterator.
//
#ifdef PROVOKE_STATIC_ASSERT
typedef boost::zip_iterator<
boost::tuples::tuple<
fake_writable_iterator
>
>no_compile_type;
no_compile_type no_compile;
#endif
// The big test.
if( bBigItIsBidirectionalIterator &&
! bBigItIsRandomAccessIterator &&
bBigItIsReadableIterator &&
! bBigItIsReadableLValueIterator &&
bAllVectsIsRandomAccessIterator &&
! bAllVectsIsReadableLValueIterator &&
bAllVectsIsReadableIterator &&
bAllIteratorsReadable1 &&
! bAllIteratorsReadable2
)
{
++num_successful_tests;
std::cout << "OK" << std::endl;
}
else
{
++num_failed_tests = 0;
std::cout << "not OK" << std::endl;
}
// Done
//
std::cout << "\nTest Result:"
<< "\n============"
<< "\nNumber of successful tests: " << static_cast<unsigned int>(num_successful_tests)
<< "\nNumber of failed tests: " << static_cast<unsigned int>(num_failed_tests)
<< std::endl;
return 0;
}