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 |