diff --git a/include/boost/iterator/zip_iterator.hpp b/include/boost/iterator/zip_iterator.hpp new file mode 100755 index 0000000..7d7c41e --- /dev/null +++ b/include/boost/iterator/zip_iterator.hpp @@ -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 +#include +#include +#include +#include // for enable_if_convertible +#include + +#include + +#if BOOST_WORKAROUND(__GNUC__, == 2) || BOOST_WORKAROUND(__MWERKS__, <= 0x2407) +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { + + // Zip iterator forward declaration for zip_iterator_base + template + 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 + class advance_iterator + { + public: + advance_iterator(DiffType step) : m_step(step) {} + + template + void operator()(Iterator& it) const + { it += m_step; } + + private: + DiffType m_step; + }; + // + struct increment_iterator + { + template + void operator()(Iterator& it) + { ++it; } + }; + // + struct decrement_iterator + { + template + void operator()(Iterator& it) + { --it; } + }; + // + struct dereference_iterator + { + template + struct apply + { +#if BOOST_WORKAROUND(__GNUC__, == 2) || BOOST_WORKAROUND(__MWERKS__, <= 0x2407) + typedef typename + std::iterator_traits< + typename boost::remove_cv::type + >::reference + type; +#else + typedef typename + std::iterator_traits::reference + type; +#endif + }; + + template + typename apply::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 + struct tuple_meta_transform; + + template + struct tuple_meta_transform_impl + { + typedef tuples::cons< + typename mpl::apply1< + typename mpl::lambda::type + , typename Tuple::head_type + >::type + , typename tuple_meta_transform< + typename Tuple::tail_type + , UnaryMetaFun + >::type + > type; + }; + + template + struct tuple_meta_transform + : mpl::apply_if< + boost::is_same + , mpl::identity + , tuple_meta_transform_impl + > + { + }; + + // Meta-accumulate algorithm for tuples. Note: The template + // parameter StartType corresponds to the initial value in + // ordinary accumulation. + // + template + struct tuple_meta_accumulate; + + template< + typename Tuple + , class BinaryMetaFun + , typename StartType + > + struct tuple_meta_accumulate_impl + { + typedef typename mpl::apply2< + typename mpl::lambda::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 +#if BOOST_WORKAROUND(BOOST_MSVC, == 1200) + , boost::is_same + > +#endif + , mpl::identity + , 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 + // struct apply + // { + // typedef Arg* type; + // } + // + // template + // Arg* operator()(Arg x); + // }; + template + tuples::null_type BOOST_TUPLE_ALGO(tuple_transform) + (tuples::null_type const&, Fun BOOST_TUPLE_ALGO_TERMINATOR) + { return tuples::null_type(); } + + template + 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::type + , transformed_tail_type + >( + f(boost::tuples::get<0>(t)), + tuple_transform(t.get_tail(), f) + ); + } + +#ifdef BOOST_TUPLE_ALGO_DISPATCH + template + 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 + Fun BOOST_TUPLE_ALGO(tuple_for_each)( + tuples::null_type + , Fun f BOOST_TUPLE_ALGO_TERMINATOR + ) + { return f; } + + + template + 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 + 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 + 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 + struct iterator_reference + { + typedef typename iterator_traits::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 + { + template + struct apply : iterator_reference {}; + }; +#endif + + // Metafunction to obtain the type of the tuple whose element types + // are the reference types of an iterator tuple. + // + template + struct tuple_of_references + : tuple_impl_specific::tuple_meta_transform< + IteratorTuple, + iterator_reference + > + { + }; + + // Metafunction to obtain the minimal traversal tag in a tuple + // of iterators. + // + template + struct minimum_traversal_category_in_iterator_tuple + { + typedef typename tuple_impl_specific::tuple_meta_transform< + IteratorTuple + , traversal_category + >::type tuple_of_traversal_tags; + + typedef typename tuple_impl_specific::tuple_meta_accumulate< + tuple_of_traversal_tags + , minimum_category + , random_access_traversal_tag + >::type type; + }; + +#if BOOST_WORKAROUND(BOOST_MSVC, == 1200) // ETI workaround + template <> + struct minimum_traversal_category_in_iterator_tuple + { + typedef int type; + }; +#endif + + template + struct iterator_is_readable + : is_tag< + readable_iterator_tag + , typename access_category::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 + { + template + struct apply : iterator_is_readable + {}; + }; +# 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 + struct and_with_two_args + : mpl::and_ + { + }; + +# 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 + { + template + struct apply : mpl::and_ + {}; + }; +# 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 + struct all_iterators_in_tuple_readable + { + + typedef typename tuple_impl_specific::tuple_meta_transform< + IteratorTuple, + iterator_is_readable + >::type tuple_of_readability_bools; + + typedef typename tuple_impl_specific::tuple_meta_accumulate< + tuple_of_readability_bools, + and_with_two_args + , mpl::bool_ + >::type type; + }; + + /////////////////////////////////////////////////////////////////// + // + // Class zip_iterator_base + // + // Builds and exposes the iterator facade type from which the zip + // iterator will be derived. + // + template + 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::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, + value_type, + access_category, + traversal_category, + reference, + difference_type + > type; + }; + + template <> + struct zip_iterator_base + { + typedef int type; + }; + } + + ///////////////////////////////////////////////////////////////////// + // + // zip_iterator class definition + // + template + class zip_iterator : + public detail::zip_iterator_base::type + { + + // Typedef super_t as our base class. + typedef typename + detail::zip_iterator_base::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 + zip_iterator( + const zip_iterator& 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 + bool equal(const zip_iterator& 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(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 super_t::difference_type distance_to( + const zip_iterator& 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 + zip_iterator + make_zip_iterator(IteratorTuple t) + { return zip_iterator(t); } + +} + +#endif diff --git a/test/zip_iterator_test.cpp b/test/zip_iterator_test.cpp new file mode 100755 index 0000000..d6fcc2b --- /dev/null +++ b/test/zip_iterator_test.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 mytuple; + mytuple t1; + boost::tuples::get<0>(t1) = 42; + boost::tuples::get<1>(t1) = 42.1; + + if( 2 == boost::tuples::length::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 s; + s.insert(42); + s.insert(43); + s.insert(44); + + typedef boost::transform_iterator< + std::binder1st >, + std::set::iterator + > + add_seven_iterator; + + typedef boost::transform_iterator< + std::binder1st >, + std::set::const_iterator + > + const_add_seven_iterator; + + add_seven_iterator set_run(s.begin(), std::bind1st(std::plus(), 7)); + add_seven_iterator set_end(s.end(), std::bind1st(std::plus(), 7)); + + const_add_seven_iterator const_set_run(s.begin(), std::bind1st(std::plus(), 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 vect1(3); + vect1[0] = 42.; + vect1[1] = 43.; + vect1[2] = 44.; + + std::set intset; + intset.insert(52); + intset.insert(53); + intset.insert(54); + // + + boost::zip_iterator< + boost::tuples::tuple< + std::set::iterator + , std::vector::iterator + > + > + zip_it_mixed( + boost::make_tuple( + intset.begin() + , vect1.begin() + ) + ); + + boost::tuples::tuple val_tuple( + *zip_it_mixed); + + boost::tuples::tuple 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 li1; + li1.push_back(1); + std::set se1; + se1.insert(2); + std::vector ve1; + ve1.push_back(3); + // + std::list li2; + li2.push_back(4); + std::set se2; + se2.insert(5); + std::vector ve2; + ve2.push_back(6); + // + std::list li3; + li3.push_back(7); + std::set se3; + se3.insert(8); + std::vector ve3; + ve3.push_back(9); + // + std::list li4; + li4.push_back(10); + std::set se4; + se4.insert(11); + std::vector ve4; + ve4.push_back(12); + + // typedefs for cons lists of iterators. + typedef boost::tuples::cons< + std::set::iterator, + boost::tuples::tuple< + std::vector::iterator, + std::list::iterator, + std::set::iterator, + std::vector::iterator, + std::list::iterator, + std::set::iterator, + std::vector::iterator, + std::list::iterator, + std::set::iterator, + std::vector::const_iterator + >::inherited + > cons_11_its_type; + // + typedef boost::tuples::cons< + std::list::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 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 vect2(3); + vect2[0] = 2.2; + vect2[1] = 3.3; + vect2[2] = 4.4; + + boost::zip_iterator< + boost::tuples::tuple< + std::vector::const_iterator, + std::vector::const_iterator + > + > + zip_it_begin( + boost::make_tuple( + vect1.begin(), + vect2.begin() + ) + ); + + boost::zip_iterator< + boost::tuples::tuple< + std::vector::const_iterator, + std::vector::const_iterator + > + > + zip_it_run( + boost::make_tuple( + vect1.begin(), + vect2.begin() + ) + ); + + boost::zip_iterator< + boost::tuples::tuple< + std::vector::const_iterator, + std::vector::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::const_iterator, + std::vector::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 > + 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::const_iterator, + std::vector::const_iterator + > + > + zip_it_const( + boost::make_tuple( + intset.begin(), + vect2.begin() + ) + ); + // + boost::zip_iterator< + boost::tuples::tuple< + std::set::iterator, + std::vector::const_iterator + > + > + zip_it_half_const( + boost::make_tuple( + intset.begin(), + vect2.begin() + ) + ); + // + boost::zip_iterator< + boost::tuples::tuple< + std::set::iterator, + std::vector::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::type + >::value; + // + bool bBigItIsRandomAccessIterator = boost::is_same< + boost::random_access_traversal_tag, + boost::traversal_category::type + >::value; + // + bool bBigItIsReadableIterator = boost::is_same< + boost::readable_iterator_tag, + boost::access_category::type + >::value; + // + bool bBigItIsReadableLValueIterator = boost::is_same< + boost::readable_lvalue_iterator_tag, + boost::access_category::type + >::value; + + // A combining iterator with all vector iterators must have random access + // traversal. + // + typedef boost::zip_iterator< + boost::tuples::tuple< + std::vector::const_iterator, + std::vector::const_iterator + > + > all_vects_type; + + bool bAllVectsIsRandomAccessIterator = boost::is_same< + boost::random_access_traversal_tag, + boost::traversal_category::type + >::value; + // + bool bAllVectsIsReadableIterator = boost::is_same< + boost::readable_iterator_tag, + boost::access_category::type + >::value; + // + bool bAllVectsIsReadableLValueIterator = boost::is_same< + boost::readable_lvalue_iterator_tag, + boost::access_category::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::const_iterator, + std::set::iterator + > + >::type::value; + + bool bAllIteratorsReadable2 = + boost::detail::all_iterators_in_tuple_readable< + boost::tuples::tuple< + std::vector::const_iterator, + fake_writable_iterator, + std::set::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(num_successful_tests) + << "\nNumber of failed tests: " << static_cast(num_failed_tests) + << std::endl; + + return 0; +} +