| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 | //  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 rangenamespace 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
 |