text: // Copyright 2002 The Trustees of Indiana University.
  
  // Use, modification and distribution is subject to the Boost Software
  // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  // http://www.boost.org/LICENSE_1_0.txt)
  
  //  Boost.MultiArray Library
  //  Authors: Ronald Garcia
  //           Jeremy Siek
  //           Andrew Lumsdaine
  //  See http://www.boost.org/libs/multi_array for documentation.
  
  //
  // iterators.cpp - checking out iterator stuffs.
  //    The tests assume that the array has shape 2x3x4
  //
  
  #define MULTIARRAY_TEST_ASSIGN
  #include "generative_tests.hpp"
  #include "boost/concept_check.hpp" // for ignore_unused_variable_warning
  #include "boost/mpl/if.hpp"
  #include "boost/type_traits/is_same.hpp"
  
  // iterator-test-specific code
  
  template <typename Array>
  void assign_if_not_const(Array& A, const mutable_array_tag&) {
  
    typedef typename Array::iterator iterator3;
    typedef typename Array::template subarray<2>::type::iterator iterator2;
    typedef typename Array::template subarray<1>::type::iterator iterator1;
  
    int num = 0;
    for (iterator3 i = A.begin(); i != A.end(); ++i)
      for(iterator2 ii = (*i).begin(); ii != (*i).end(); ++ii)
        for(iterator1  iii = (*ii).begin(); iii != (*ii).end(); ++iii)
          *iii = num++;
  }
  
  
  template <typename Array>
  struct ittraits_const {
    typedef typename Array::const_iterator iterator3;
    typedef typename boost::subarray_gen<Array,2>::type::const_iterator
    iterator2;
    typedef typename boost::subarray_gen<Array,1>::type::const_iterator
    iterator1;
  
    typedef typename Array::const_reverse_iterator riterator3;
    typedef typename boost::subarray_gen<Array,2>::type::const_reverse_iterator
    riterator2;
    typedef typename boost::subarray_gen<Array,1>::type::const_reverse_iterator
    riterator1;
  };
  
  template <typename Array>
  struct ittraits_mutable {
    typedef typename Array::iterator iterator3;
    typedef typename boost::subarray_gen<Array,2>::type::iterator iterator2;
    typedef typename boost::subarray_gen<Array,1>::type::iterator iterator1;
  
    typedef typename Array::reverse_iterator riterator3;
    typedef typename boost::subarray_gen<Array,2>::type::reverse_iterator
    riterator2;
    typedef typename boost::subarray_gen<Array,1>::type::reverse_iterator
    riterator1;
  };
  
  
  // Meta-program chooses ittraits implementation.
  template <typename Array, typename ConstTag>
  struct ittraits_generator :
    boost::mpl::if_< boost::is_same<ConstTag,const_array_tag>,
                     ittraits_const<Array>,
                     ittraits_mutable<Array> >
  {};
  
  
  template <typename Array>
  void construct_iterators(Array&) {
  
    // Default constructed iterators and
    // const iterators constructed from iterators.
    {
      typename Array::iterator i1;
      typename Array::const_iterator ci1;
      typename Array::reverse_iterator r1;
      typename Array::const_reverse_iterator cr1;
  
  #if 0 // RG - MSVC fails to compile these
      typename Array::const_iterator ci2 =
        typename Array::iterator();
      typename Array::const_reverse_iterator cr2 =
        typename Array::reverse_iterator();
  #endif
      typename Array::const_iterator ci2 = i1;
      typename Array::const_reverse_iterator cr2 = cr1;
      boost::ignore_unused_variable_warning(cr2);
    }
  }
  
  template <typename Array, typename IterTraits>
  void test_iterators(Array& A, const IterTraits&) {
  
    // Iterator comparison and arithmetic
    {
      typedef typename IterTraits::iterator3 iterator;
      iterator i1 = A.begin();
      iterator i2 = A.end();
      BOOST_CHECK(i1 < i2);
      BOOST_CHECK((i2 - i1) == typename iterator::difference_type(2));
    }
  
    // Standard Array Iteration
    {
      typedef typename IterTraits::iterator3 iterator3;
      typedef typename IterTraits::iterator2 iterator2;
      typedef typename IterTraits::iterator1 iterator1;
  
      int vals = 0;
      for (iterator3 i = A.begin(); i != A.end(); ++i)
        for(iterator2 ii = (*i).begin(); ii != (*i).end(); ++ii)
          for(iterator1  iii = (*ii).begin(); iii != (*ii).end(); ++iii)
            BOOST_CHECK(*iii == vals++);
    }
  
    // Using operator->() on iterators
    {
      typedef typename IterTraits::iterator3 iterator3;
      typedef typename IterTraits::iterator2 iterator2;
      typedef typename IterTraits::iterator1 iterator1;
  
      int vals = 0;
      for (iterator3 i = A.begin(); i != A.end(); ++i)
        for(iterator2 ii = i->begin(); ii != i->end(); ++ii)
          for(iterator1  iii = ii->begin(); iii != ii->end(); ++iii)
            BOOST_CHECK(*iii == vals++);
    }
  
    // Reverse Iterator Hierarchy Test
    {
      typedef typename IterTraits::riterator3 riterator3;
      typedef typename IterTraits::riterator2 riterator2;
      typedef typename IterTraits::riterator1 riterator1;
  
      int check_iter_val = A.num_elements()-1;
      for (riterator3 i = A.rbegin(); i != (riterator3)A.rend(); ++i)
        for(riterator2 ii = (*i).rbegin(); ii != (riterator2)(*i).rend(); ++ii)
          for(riterator1 iii = (*ii).rbegin(); iii != (riterator1)(*ii).rend();
              ++iii)
            BOOST_CHECK(*iii == check_iter_val--);
    }
    ++tests_run;
  }
  
  
  template <typename Array>
  void access(Array& A, const mutable_array_tag&) {
    assign(A);
  
    construct_iterators(A);
  
    typedef typename ittraits_generator<Array,mutable_array_tag>::type
      m_iter_traits;
  
    typedef typename ittraits_generator<Array,const_array_tag>::type
      c_iter_traits;
    test_iterators(A,m_iter_traits());
    test_iterators(A,c_iter_traits());
  
    const Array& CA = A;
    test_iterators(CA,c_iter_traits());
  }
  
  template <typename Array>
  void access(Array& A, const const_array_tag&) {
    construct_iterators(A);
    typedef typename ittraits_generator<Array,const_array_tag>::type
      c_iter_traits;
    test_iterators(A,c_iter_traits());
  }
  
  
  int
  test_main(int, char*[])
  {
    return run_generative_tests();
  }
  