forked from boostorg/utility
		
	
		
			
				
	
	
		
			410 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			410 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //  Test boost/iterator_adaptors.hpp
 | |
| 
 | |
| //  (C) Copyright Jeremy Siek 1999. 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.
 | |
| 
 | |
| //  See http://www.boost.org for most recent version including documentation.
 | |
| 
 | |
| //  Revision History
 | |
| //  19 Nov 01 Added generator_iterator.  (Jens Maurer)
 | |
| //  04 Nov 01 Updated with respect to change in named parameters.
 | |
| //            (Jeremy Siek)
 | |
| //  08 Mar 01 Moved indirect and transform tests to separate files.
 | |
| //            (Jeremy Siek)
 | |
| //  19 Feb 01 Take adavantage of improved iterator_traits to do more tests
 | |
| //            on MSVC. Hack around an MSVC-with-STLport internal compiler
 | |
| //            error. (David Abrahams)
 | |
| //  11 Feb 01 Added test of operator-> for forward and input iterators.
 | |
| //            (Jeremy Siek)
 | |
| //  11 Feb 01 Borland fixes (David Abrahams)
 | |
| //  10 Feb 01 Use new adaptors interface. (David Abrahams)
 | |
| //  10 Feb 01 Use new filter_ interface. (David Abrahams)
 | |
| //  09 Feb 01 Use new reverse_ and indirect_ interfaces. Replace
 | |
| //            BOOST_NO_STD_ITERATOR_TRAITS with
 | |
| //            BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION to prove we've
 | |
| //            normalized to core compiler capabilities (David Abrahams)
 | |
| //  08 Feb 01 Use Jeremy's new make_reverse_iterator form; add more
 | |
| //            comprehensive testing. Force-decay array function arguments to
 | |
| //            pointers.
 | |
| //  07 Feb 01 Added tests for the make_xxx_iterator() helper functions.
 | |
| //            (Jeremy Siek)
 | |
| //  07 Feb 01 Replaced use of xxx_pair_generator with xxx_generator where
 | |
| //            possible (which was all but the projection iterator).
 | |
| //            (Jeremy Siek)
 | |
| //  06 Feb 01 Removed now-defaulted template arguments where possible
 | |
| //            Updated names to correspond to new generator naming convention.
 | |
| //            Added a trivial test for make_transform_iterator().
 | |
| //            Gave traits for const iterators a mutable value_type, per std.
 | |
| //            Resurrected my original tests for indirect iterators.
 | |
| //            (David Abrahams)
 | |
| //  04 Feb 01 Fix for compilers without standard iterator_traits
 | |
| //            (David Abrahams)
 | |
| //  13 Jun 00 Added const version of the iterator tests (Jeremy Siek)
 | |
| //  12 Dec 99 Initial version with iterator operators (Jeremy Siek)
 | |
| 
 | |
| #include <boost/config.hpp>
 | |
| #include <iostream>
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <functional>
 | |
| 
 | |
| #include <boost/iterator_adaptors.hpp>
 | |
| #include <boost/generator_iterator.hpp>
 | |
| #include <boost/pending/iterator_tests.hpp>
 | |
| #include <boost/pending/integer_range.hpp>
 | |
| #include <boost/concept_archetype.hpp>
 | |
| #include <boost/type_traits/same_traits.hpp>
 | |
| #include <stdlib.h>
 | |
| #include <vector>
 | |
| #include <deque>
 | |
| #include <set>
 | |
| #include <list>
 | |
| 
 | |
| struct my_iterator_tag : public std::random_access_iterator_tag { };
 | |
| 
 | |
| using boost::dummyT;
 | |
| 
 | |
| 
 | |
| struct mult_functor {
 | |
|   typedef int result_type;
 | |
|   typedef int argument_type;
 | |
|   // Functors used with transform_iterator must be
 | |
|   // DefaultConstructible, as the transform_iterator must be
 | |
|   // DefaultConstructible to satisfy the requirements for
 | |
|   // TrivialIterator.
 | |
|   mult_functor() { }
 | |
|   mult_functor(int aa) : a(aa) { }
 | |
|   int operator()(int b) const { return a * b; }
 | |
|   int a;
 | |
| };
 | |
| 
 | |
| template <class Pair>
 | |
| struct select1st_ 
 | |
|   : public std::unary_function<Pair, typename Pair::first_type>
 | |
| {
 | |
|   const typename Pair::first_type& operator()(const Pair& x) const {
 | |
|     return x.first;
 | |
|   }
 | |
|   typename Pair::first_type& operator()(Pair& x) const {
 | |
|     return x.first;
 | |
|   }
 | |
| };
 | |
| 
 | |
| struct one_or_four {
 | |
|   bool operator()(dummyT x) const {
 | |
|     return x.foo() == 1 || x.foo() == 4;
 | |
|   }
 | |
| };
 | |
| 
 | |
| typedef std::deque<int> storage;
 | |
| typedef std::deque<int*> pointer_deque;
 | |
| typedef std::set<storage::iterator> iterator_set;
 | |
| 
 | |
| template <class T> struct foo;
 | |
| 
 | |
| void blah(int) { }
 | |
| 
 | |
| struct my_gen
 | |
| {
 | |
|   typedef int result_type;
 | |
|   my_gen() : n(0) { }
 | |
|   int operator()() { return ++n; }
 | |
|   int n;
 | |
| };
 | |
| 
 | |
| int
 | |
| main()
 | |
| {
 | |
|   dummyT array[] = { dummyT(0), dummyT(1), dummyT(2), 
 | |
|                      dummyT(3), dummyT(4), dummyT(5) };
 | |
|   const int N = sizeof(array)/sizeof(dummyT);
 | |
| 
 | |
|   // sanity check, if this doesn't pass the test is buggy
 | |
|   boost::random_access_iterator_test(array, N, array);
 | |
| 
 | |
|   // Check that the policy concept checks and the default policy
 | |
|   // implementation match up.
 | |
|   boost::function_requires< 
 | |
|      boost::RandomAccessIteratorPoliciesConcept<
 | |
|        boost::default_iterator_policies,
 | |
|        boost::iterator_adaptor<int*, boost::default_iterator_policies>,
 | |
|        boost::iterator<std::random_access_iterator_tag, int, std::ptrdiff_t,
 | |
|                       int*, int&>
 | |
|       > >();
 | |
| 
 | |
|   // Test the named parameters
 | |
|   {
 | |
|     // Test computation of defaults
 | |
|     typedef boost::iterator_adaptor<int*, boost::default_iterator_policies,
 | |
|       boost::value_type_is<int> > Iter1;
 | |
|     // don't use std::iterator_traits here to avoid VC++ problems
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::value_type, int>::value));
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::reference, int&>::value));
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::pointer, int*>::value));
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::difference_type, std::ptrdiff_t>::value));
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::iterator_category, std::random_access_iterator_tag>::value));
 | |
|   }
 | |
|   {  
 | |
|     // Test computation of default when the Value is const
 | |
|     typedef boost::iterator_adaptor<std::list<int>::iterator,
 | |
|       boost::default_iterator_policies,
 | |
|       boost::value_type_is<const int> > Iter1;
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::value_type, int>::value));
 | |
| #if defined(__BORLANDC__) || defined(BOOST_MSVC)
 | |
|     // We currently don't know how to workaround this bug.
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::reference, int&>::value));
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::pointer, int*>::value));
 | |
| #else
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::reference, const int&>::value));
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::pointer, const int*>::value));
 | |
| #endif
 | |
|   }
 | |
|   {
 | |
|     // Test with no defaults
 | |
|     typedef boost::iterator_adaptor<int*, boost::default_iterator_policies,
 | |
|       boost::reference_is<long>,
 | |
|       boost::pointer_is<float*>,
 | |
|       boost::value_type_is<char>,
 | |
|       boost::iterator_category_is<std::input_iterator_tag>,
 | |
|       boost::difference_type_is<int>
 | |
|     > Iter1;
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::value_type, char>::value));
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::reference, long>::value));
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::pointer, float*>::value));
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::difference_type, int>::value));
 | |
|     BOOST_STATIC_ASSERT((boost::is_same<Iter1::iterator_category, std::input_iterator_tag>::value));
 | |
|   }
 | |
|   
 | |
|   // Test the iterator_adaptor
 | |
|   {
 | |
|     boost::iterator_adaptor<dummyT*, boost::default_iterator_policies, dummyT> i(array);
 | |
|     boost::random_access_iterator_test(i, N, array);
 | |
|     
 | |
|     boost::iterator_adaptor<const dummyT*, boost::default_iterator_policies, const dummyT> j(array);
 | |
|     boost::random_access_iterator_test(j, N, array);
 | |
|     boost::const_nonconst_iterator_test(i, ++j);
 | |
|   }
 | |
| 
 | |
|   // Test projection_iterator_pair_generator
 | |
|   {    
 | |
|     typedef std::pair<dummyT,dummyT> Pair;
 | |
|     Pair pair_array[N];
 | |
|     for (int k = 0; k < N; ++k)
 | |
|       pair_array[k].first = array[k];
 | |
| 
 | |
|     typedef boost::projection_iterator_pair_generator<select1st_<Pair>,
 | |
|       Pair*, const Pair*
 | |
|       > Projection;
 | |
|     
 | |
|     Projection::iterator i(pair_array);
 | |
|     boost::random_access_iterator_test(i, N, array);
 | |
| 
 | |
|     boost::random_access_iterator_test(boost::make_projection_iterator(pair_array, select1st_<Pair>()), N, array);    
 | |
|     boost::random_access_iterator_test(boost::make_projection_iterator< select1st_<Pair> >(pair_array), N, array);    
 | |
| 
 | |
|     Projection::const_iterator j(pair_array);
 | |
|     boost::random_access_iterator_test(j, N, array);
 | |
| 
 | |
|     boost::random_access_iterator_test(boost::make_const_projection_iterator(pair_array, select1st_<Pair>()), N, array);
 | |
|     boost::random_access_iterator_test(boost::make_const_projection_iterator<select1st_<Pair> >(pair_array), N, array);
 | |
| 
 | |
|     boost::const_nonconst_iterator_test(i, ++j);
 | |
|   }
 | |
| 
 | |
|   // Test reverse_iterator_generator
 | |
|   {
 | |
|     dummyT reversed[N];
 | |
|     std::copy(array, array + N, reversed);
 | |
|     std::reverse(reversed, reversed + N);
 | |
|     
 | |
|     typedef boost::reverse_iterator_generator<dummyT*
 | |
| #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | |
|         , dummyT
 | |
| #endif
 | |
|       >::type reverse_iterator;
 | |
|     
 | |
|     reverse_iterator i(reversed + N);
 | |
|     boost::random_access_iterator_test(i, N, array);
 | |
| 
 | |
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | |
|     boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array);
 | |
| #endif
 | |
| 
 | |
|     typedef boost::reverse_iterator_generator<const dummyT*
 | |
| #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | |
|       , dummyT, const dummyT&, const dummyT
 | |
| #endif
 | |
|       >::type const_reverse_iterator;
 | |
|     
 | |
|     const_reverse_iterator j(reversed + N);
 | |
|     boost::random_access_iterator_test(j, N, array);
 | |
| 
 | |
|     const dummyT* const_reversed = reversed;
 | |
|     
 | |
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | |
|     boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array);
 | |
| #endif
 | |
|     
 | |
|     boost::const_nonconst_iterator_test(i, ++j);    
 | |
|   }
 | |
| 
 | |
|   // Test reverse_iterator_generator again, with traits fully deducible on all platforms
 | |
|   {
 | |
|     std::deque<dummyT> reversed_container;
 | |
|     std::reverse_copy(array, array + N, std::back_inserter(reversed_container));
 | |
|     const std::deque<dummyT>::iterator reversed = reversed_container.begin();
 | |
| 
 | |
| 
 | |
|     typedef boost::reverse_iterator_generator<
 | |
|         std::deque<dummyT>::iterator>::type reverse_iterator;
 | |
|     typedef boost::reverse_iterator_generator<
 | |
|         std::deque<dummyT>::const_iterator, const dummyT>::type const_reverse_iterator;
 | |
| 
 | |
|     // MSVC/STLport gives an INTERNAL COMPILER ERROR when any computation
 | |
|     // (e.g. "reversed + N") is used in the constructor below.
 | |
|     const std::deque<dummyT>::iterator finish = reversed_container.end();
 | |
|     reverse_iterator i(finish);
 | |
|     
 | |
|     boost::random_access_iterator_test(i, N, array);
 | |
|     boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array);
 | |
| 
 | |
|     const_reverse_iterator j = reverse_iterator(finish);
 | |
|     boost::random_access_iterator_test(j, N, array);
 | |
| 
 | |
|     const std::deque<dummyT>::const_iterator const_reversed = reversed;
 | |
|     boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array);
 | |
|     
 | |
|     // Many compilers' builtin deque iterators don't interoperate well, though
 | |
|     // STLport fixes that problem.
 | |
| #if defined(__SGI_STL_PORT) || !defined(__GNUC__) && !defined(__BORLANDC__) && !defined(BOOST_MSVC)
 | |
|     boost::const_nonconst_iterator_test(i, ++j);
 | |
| #endif
 | |
|   }
 | |
|   
 | |
|   // Test integer_range's iterators
 | |
|   {
 | |
|     int int_array[] = { 0, 1, 2, 3, 4, 5 };
 | |
|     boost::integer_range<int> r(0, 5);
 | |
|     boost::random_access_iterator_test(r.begin(), r.size(), int_array);
 | |
|   }
 | |
| 
 | |
|   // Test filter iterator
 | |
|   {
 | |
|     // Using typedefs for filter_gen::type confused Borland terribly.
 | |
|     typedef boost::detail::non_bidirectional_category<dummyT*>::type category;
 | |
|     
 | |
|     typedef boost::filter_iterator_generator<one_or_four, dummyT*
 | |
| #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | |
|         , dummyT
 | |
| #endif
 | |
|         >::type filter_iter;
 | |
| 
 | |
| #if defined(__BORLANDC__)
 | |
|     // Borland is choking on accessing the policies_type explicitly
 | |
|     // from the filter_iter. 
 | |
|     boost::forward_iterator_test(make_filter_iterator(array, array+N, 
 | |
| 						      one_or_four()),
 | |
| 				 dummyT(1), dummyT(4));
 | |
| #else
 | |
|     filter_iter i(array, filter_iter::policies_type(one_or_four(), array + N));
 | |
|     boost::forward_iterator_test(i, dummyT(1), dummyT(4));
 | |
| #endif
 | |
| 
 | |
| #if !defined(__BORLANDC__)
 | |
|     // 
 | |
|     enum { is_forward = boost::is_same<
 | |
|            filter_iter::iterator_category,
 | |
|            std::forward_iterator_tag>::value };
 | |
|     BOOST_STATIC_ASSERT(is_forward);
 | |
| #endif
 | |
| 
 | |
|     // On compilers not supporting partial specialization, we can do more type
 | |
|     // deduction with deque iterators than with pointers... unless the library
 | |
|     // is broken ;-(
 | |
| #if !defined(BOOST_MSVC) || defined(__SGI_STL_PORT)
 | |
|     std::deque<dummyT> array2;
 | |
|     std::copy(array+0, array+N, std::back_inserter(array2));
 | |
|     boost::forward_iterator_test(
 | |
|         boost::make_filter_iterator(array2.begin(), array2.end(), one_or_four()),
 | |
|         dummyT(1), dummyT(4));
 | |
| 
 | |
|     boost::forward_iterator_test(
 | |
|         boost::make_filter_iterator<one_or_four>(array2.begin(), array2.end()),
 | |
|         dummyT(1), dummyT(4));
 | |
| #endif
 | |
| 
 | |
| #if !defined(BOOST_MSVC) // This just freaks MSVC out completely
 | |
|     boost::forward_iterator_test(
 | |
|         boost::make_filter_iterator<one_or_four>(
 | |
|             boost::make_reverse_iterator(array2.end()),
 | |
|             boost::make_reverse_iterator(array2.begin())
 | |
|             ),
 | |
|         dummyT(4), dummyT(1));
 | |
| #endif
 | |
|     
 | |
| #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
 | |
|     boost::forward_iterator_test(
 | |
|         boost::make_filter_iterator(array+0, array+N, one_or_four()),
 | |
|         dummyT(1), dummyT(4));
 | |
| 
 | |
|     boost::forward_iterator_test(
 | |
|         boost::make_filter_iterator<one_or_four>(array, array + N),
 | |
|         dummyT(1), dummyT(4));
 | |
| 
 | |
| #endif
 | |
|   }
 | |
| 
 | |
|   // check operator-> with a forward iterator
 | |
|   {
 | |
|     boost::forward_iterator_archetype<dummyT> forward_iter;
 | |
| #if defined(__BORLANDC__)
 | |
|     typedef boost::iterator_adaptor<boost::forward_iterator_archetype<dummyT>,
 | |
|       boost::default_iterator_policies,
 | |
|       dummyT, const dummyT&, const dummyT*, 
 | |
|       std::forward_iterator_tag, std::ptrdiff_t> adaptor_type;
 | |
| #else
 | |
|     typedef boost::iterator_adaptor<boost::forward_iterator_archetype<dummyT>,
 | |
|       boost::default_iterator_policies,
 | |
|       boost::reference_is<const dummyT&>,
 | |
|       boost::pointer_is<const dummyT*> ,
 | |
|       boost::iterator_category_is<std::forward_iterator_tag>,
 | |
|       boost::value_type_is<dummyT>,
 | |
|       boost::difference_type_is<std::ptrdiff_t>
 | |
|     > adaptor_type;
 | |
| #endif
 | |
|     adaptor_type i(forward_iter);
 | |
|     int zero = 0;
 | |
|     if (zero) // don't do this, just make sure it compiles
 | |
|       assert((*i).m_x == i->foo());      
 | |
|   }
 | |
|   // check operator-> with an input iterator
 | |
|   {
 | |
|     boost::input_iterator_archetype<dummyT> input_iter;
 | |
|     typedef boost::iterator_adaptor<boost::input_iterator_archetype<dummyT>,
 | |
|       boost::default_iterator_policies,
 | |
|       dummyT, const dummyT&, const dummyT*, 
 | |
|       std::input_iterator_tag, std::ptrdiff_t> adaptor_type;
 | |
|     adaptor_type i(input_iter);
 | |
|     int zero = 0;
 | |
|     if (zero) // don't do this, just make sure it compiles
 | |
|       assert((*i).m_x == i->foo());      
 | |
|   }
 | |
| 
 | |
|   {
 | |
|     // check generator_iterator
 | |
|     my_gen g1;
 | |
|     boost::generator_iterator_generator<my_gen>::type gen =
 | |
|       boost::make_generator_iterator(g1);
 | |
|     assert(*gen == 1);
 | |
|     ++gen;
 | |
|     gen++;
 | |
|     assert(*gen == 3);
 | |
|   }
 | |
| 
 | |
|   std::cout << "test successful " << std::endl;
 | |
|   return 0;
 | |
| }
 |