371 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			371 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| //  Copyright 2014 Neil Groves
 | |
| //
 | |
| //  Copyright (c) 2010 Ilya Murav'jov
 | |
| // 
 | |
| //  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)
 | |
| //
 | |
| // Credits:
 | |
| //  My (Neil's) first indexed adaptor was hindered by having the underlying
 | |
| //  iterator return the same reference as the wrapped iterator. This meant that
 | |
| //  to obtain the index one had to get to the index_iterator and call the
 | |
| //  index() function on it. Ilya politely pointed out that this was useless in
 | |
| //  a number of scenarios since one naturally hides the use of iterators in
 | |
| //  good range-based code. Ilya provided a new interface (which has remained)
 | |
| //  and a first implementation. Much of this original implementation has
 | |
| //  been simplified and now supports more compilers and platforms.
 | |
| //
 | |
| #ifndef BOOST_RANGE_ADAPTOR_INDEXED_HPP_INCLUDED
 | |
| #define BOOST_RANGE_ADAPTOR_INDEXED_HPP_INCLUDED
 | |
| 
 | |
| #include <boost/range/config.hpp>
 | |
| #include <boost/range/adaptor/argument_fwd.hpp>
 | |
| #include <boost/range/iterator_range.hpp>
 | |
| #include <boost/range/traversal.hpp>
 | |
| #include <boost/range/size.hpp>
 | |
| #include <boost/range/begin.hpp>
 | |
| #include <boost/range/end.hpp>
 | |
| #include <boost/mpl/if.hpp>
 | |
| #include <boost/type_traits/is_convertible.hpp>
 | |
| 
 | |
| #include <boost/iterator/iterator_traits.hpp>
 | |
| #include <boost/iterator/iterator_facade.hpp>
 | |
| 
 | |
| #include <boost/tuple/tuple.hpp>
 | |
| 
 | |
| namespace boost
 | |
| {
 | |
|     namespace adaptors
 | |
|     {
 | |
| 
 | |
| struct indexed
 | |
| {
 | |
|     explicit indexed(std::ptrdiff_t x = 0)
 | |
|         : val(x)
 | |
|     {
 | |
|     }
 | |
|     std::ptrdiff_t val;
 | |
| };
 | |
| 
 | |
|     } // namespace adaptors
 | |
| 
 | |
|     namespace range
 | |
|     {
 | |
| 
 | |
| // Why yet another "pair" class:
 | |
| // - std::pair can't store references
 | |
| // - no need for typing for index type (default to "std::ptrdiff_t"); this is
 | |
| // useful in BOOST_FOREACH() expressions that have pitfalls with commas
 | |
| //   ( see http://www.boost.org/doc/libs/1_44_0/doc/html/foreach/pitfalls.html )
 | |
| // - meaningful access functions index(), value()
 | |
| template<class T, class Indexable = std::ptrdiff_t>
 | |
| class index_value
 | |
|     : public tuple<Indexable, T>
 | |
| {
 | |
|     typedef tuple<Indexable, T> base_t;
 | |
| 
 | |
|     template<int N>
 | |
|     struct iv_types
 | |
|     {
 | |
|         typedef typename tuples::element<N, base_t>::type n_type;
 | |
| 
 | |
|         typedef typename tuples::access_traits<n_type>::non_const_type non_const_type;
 | |
|         typedef typename tuples::access_traits<n_type>::const_type const_type;
 | |
|     };
 | |
| 
 | |
| public:
 | |
|     typedef typename iv_types<0>::non_const_type index_type;
 | |
|     typedef typename iv_types<0>::const_type const_index_type;
 | |
|     typedef typename iv_types<1>::non_const_type value_type;
 | |
|     typedef typename iv_types<1>::const_type const_value_type;
 | |
| 
 | |
|     index_value()
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     index_value(typename tuples::access_traits<Indexable>::parameter_type t0,
 | |
|                 typename tuples::access_traits<T>::parameter_type t1)
 | |
|         : base_t(t0, t1)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     // member functions index(), value() (non-const and const)
 | |
|     index_type index()
 | |
|     {
 | |
|         return boost::tuples::get<0>(*this);
 | |
|     }
 | |
| 
 | |
|     const_index_type index() const
 | |
|     {
 | |
|         return boost::tuples::get<0>(*this);
 | |
|     }
 | |
| 
 | |
|     value_type value()
 | |
|     {
 | |
|         return boost::tuples::get<1>(*this);
 | |
|     }
 | |
| 
 | |
|     const_value_type value() const
 | |
|     {
 | |
|         return boost::tuples::get<1>(*this);
 | |
|     }
 | |
| };
 | |
| 
 | |
|     } // namespace range
 | |
| 
 | |
| namespace range_detail
 | |
| {
 | |
| 
 | |
| template<typename Iter>
 | |
| struct indexed_iterator_value_type
 | |
| {
 | |
|     typedef ::boost::range::index_value<
 | |
|         typename iterator_reference<Iter>::type,
 | |
|         typename iterator_difference<Iter>::type
 | |
|     > type;
 | |
| };
 | |
| 
 | |
| // Meta-function to get the traversal for the range and therefore iterator
 | |
| // returned by the indexed adaptor for a specified iterator type.
 | |
| //
 | |
| // Random access -> Random access
 | |
| // Bidirectional -> Forward
 | |
| // Forward -> Forward
 | |
| // SinglePass -> SinglePass
 | |
| //
 | |
| // The rationale for demoting a Bidirectional input to Forward is that the end
 | |
| // iterator cannot cheaply have an index computed for it. Therefore I chose to
 | |
| // demote to forward traversal. I can maintain the ability to traverse randomly
 | |
| // when the input is Random Access since the index for the end iterator is cheap
 | |
| // to compute.
 | |
| template<typename Iter>
 | |
| struct indexed_traversal
 | |
| {
 | |
| private:
 | |
|     typedef typename iterator_traversal<Iter>::type wrapped_traversal;
 | |
| 
 | |
| public:
 | |
| 
 | |
|     typedef typename mpl::if_<
 | |
|         is_convertible<wrapped_traversal, random_access_traversal_tag>,
 | |
|         random_access_traversal_tag,
 | |
|         typename mpl::if_<
 | |
|             is_convertible<wrapped_traversal, bidirectional_traversal_tag>,
 | |
|             forward_traversal_tag,
 | |
|             wrapped_traversal
 | |
|         >::type
 | |
|     >::type type;
 | |
| };
 | |
| 
 | |
| template<typename Iter>
 | |
| class indexed_iterator
 | |
|     : public iterator_facade<
 | |
|             indexed_iterator<Iter>,
 | |
|             typename indexed_iterator_value_type<Iter>::type,
 | |
|             typename indexed_traversal<Iter>::type,
 | |
|             typename indexed_iterator_value_type<Iter>::type,
 | |
|             typename iterator_difference<Iter>::type
 | |
|         >
 | |
| {
 | |
| public:
 | |
|     typedef Iter wrapped;
 | |
| 
 | |
| private:
 | |
|     typedef iterator_facade<
 | |
|         indexed_iterator<wrapped>,
 | |
|         typename indexed_iterator_value_type<wrapped>::type,
 | |
|         typename indexed_traversal<wrapped>::type,
 | |
|         typename indexed_iterator_value_type<wrapped>::type,
 | |
|         typename iterator_difference<wrapped>::type
 | |
|     > base_t;
 | |
| 
 | |
| public:
 | |
|     typedef typename base_t::difference_type difference_type;
 | |
|     typedef typename base_t::reference reference;
 | |
|     typedef typename base_t::difference_type index_type;
 | |
| 
 | |
|     indexed_iterator()
 | |
|         : m_it()
 | |
|         , m_index()
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     template<typename OtherWrapped>
 | |
|     indexed_iterator(
 | |
|         const indexed_iterator<OtherWrapped>& other,
 | |
|         typename enable_if<is_convertible<OtherWrapped, wrapped> >::type* = 0
 | |
|     )
 | |
|         : m_it(other.get())
 | |
|         , m_index(other.get_index())
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     explicit indexed_iterator(wrapped it, index_type index)
 | |
|         : m_it(it)
 | |
|         , m_index(index)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     wrapped get() const
 | |
|     {
 | |
|         return m_it;
 | |
|     }
 | |
| 
 | |
|     index_type get_index() const
 | |
|     {
 | |
|         return m_index;
 | |
|     }
 | |
| 
 | |
|  private:
 | |
|     friend class boost::iterator_core_access;
 | |
| 
 | |
|     reference dereference() const
 | |
|     {
 | |
|         return reference(m_index, *m_it);
 | |
|     }
 | |
| 
 | |
|     bool equal(const indexed_iterator& other) const
 | |
|     {
 | |
|         return m_it == other.m_it;
 | |
|     }
 | |
| 
 | |
|     void increment()
 | |
|     {
 | |
|         ++m_index;
 | |
|         ++m_it;
 | |
|     }
 | |
| 
 | |
|     void decrement()
 | |
|     {
 | |
|         BOOST_ASSERT_MSG(m_index > 0, "indexed Iterator out of bounds");
 | |
|         --m_index;
 | |
|         --m_it;
 | |
|     }
 | |
| 
 | |
|     void advance(index_type n)
 | |
|     {
 | |
|         m_index += n;
 | |
|         BOOST_ASSERT_MSG(m_index >= 0, "indexed Iterator out of bounds");
 | |
|         m_it += n;
 | |
|     }
 | |
| 
 | |
|     difference_type distance_to(const indexed_iterator& other) const
 | |
|     {
 | |
|         return other.m_it - m_it;
 | |
|     }
 | |
| 
 | |
|     wrapped m_it;
 | |
|     index_type m_index;
 | |
| };
 | |
| 
 | |
| template<typename SinglePassRange>
 | |
| struct indexed_range
 | |
|     : iterator_range<
 | |
|         indexed_iterator<
 | |
|             typename range_iterator<SinglePassRange>::type
 | |
|         >
 | |
|     >
 | |
| {
 | |
|     typedef iterator_range<
 | |
|         indexed_iterator<
 | |
|             typename range_iterator<SinglePassRange>::type
 | |
|         >
 | |
|     > base_t;
 | |
| 
 | |
|     BOOST_RANGE_CONCEPT_ASSERT((
 | |
|         boost::SinglePassRangeConcept<SinglePassRange>));
 | |
| public:
 | |
|     typedef indexed_iterator<
 | |
|         typename range_iterator<SinglePassRange>::type
 | |
|     > iterator;
 | |
| 
 | |
|     // Constructor for non-random access iterators.
 | |
|     // This sets the end iterator index to i despite this being incorrect it
 | |
|     // is never observable since bidirectional iterators are demoted to
 | |
|     // forward iterators.
 | |
|     indexed_range(
 | |
|         typename base_t::difference_type i,
 | |
|         SinglePassRange& r,
 | |
|         single_pass_traversal_tag
 | |
|         )
 | |
|         : base_t(iterator(boost::begin(r), i),
 | |
|                  iterator(boost::end(r), i))
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     indexed_range(
 | |
|         typename base_t::difference_type i,
 | |
|         SinglePassRange& r,
 | |
|         random_access_traversal_tag
 | |
|         )
 | |
|         : base_t(iterator(boost::begin(r), i),
 | |
|                  iterator(boost::end(r), i + boost::size(r)))
 | |
|     {
 | |
|     }
 | |
| };
 | |
| 
 | |
|     } // namespace range_detail 
 | |
| 
 | |
|     using range_detail::indexed_range;
 | |
| 
 | |
|     namespace adaptors
 | |
|     {
 | |
| 
 | |
| template<class SinglePassRange>
 | |
| inline indexed_range<SinglePassRange>
 | |
| operator|(SinglePassRange& r, indexed e)
 | |
| {
 | |
|     BOOST_RANGE_CONCEPT_ASSERT((
 | |
|         boost::SinglePassRangeConcept<SinglePassRange>
 | |
|     ));
 | |
|     return indexed_range<SinglePassRange>(
 | |
|                 e.val, r,
 | |
|                 typename range_traversal<SinglePassRange>::type());
 | |
| }
 | |
| 
 | |
| template<class SinglePassRange>
 | |
| inline indexed_range<const SinglePassRange>
 | |
| operator|(const SinglePassRange& r, indexed e)
 | |
| {
 | |
|     BOOST_RANGE_CONCEPT_ASSERT((
 | |
|         boost::SinglePassRangeConcept<const SinglePassRange>
 | |
|     ));
 | |
|     return indexed_range<const SinglePassRange>(
 | |
|                 e.val, r,
 | |
|                 typename range_traversal<const SinglePassRange>::type());
 | |
| }
 | |
| 
 | |
| template<class SinglePassRange>
 | |
| inline indexed_range<SinglePassRange>
 | |
| index(
 | |
|     SinglePassRange& rng,
 | |
|     typename range_difference<SinglePassRange>::type index_value = 0)
 | |
| {
 | |
|     BOOST_RANGE_CONCEPT_ASSERT((
 | |
|         boost::SinglePassRangeConcept<SinglePassRange>
 | |
|     ));
 | |
|     return indexed_range<SinglePassRange>(
 | |
|                 index_value, rng,
 | |
|                 typename range_traversal<SinglePassRange>::type());
 | |
| }
 | |
| 
 | |
| template<class SinglePassRange>
 | |
| inline indexed_range<const SinglePassRange>
 | |
| index(
 | |
|     const SinglePassRange& rng,
 | |
|     typename range_difference<const SinglePassRange>::type index_value = 0)
 | |
| {
 | |
|     BOOST_RANGE_CONCEPT_ASSERT((
 | |
|         boost::SinglePassRangeConcept<SinglePassRange>
 | |
|     ));
 | |
|     return indexed_range<const SinglePassRange>(
 | |
|                 index_value, rng,
 | |
|                 typename range_traversal<const SinglePassRange>::type());
 | |
| }
 | |
| 
 | |
|     } // namespace adaptors
 | |
| } // namespace boost
 | |
| 
 | |
| #endif // include guard
 | 
