123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- // 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
- #if !defined(BOOST_NO_CXX11_HDR_TUPLE)
- namespace std {
- #if defined(BOOST_CLANG)
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wmismatched-tags"
- #endif
- template<size_t N, class T, class Indexable>
- struct tuple_element<N, boost::range::index_value<T, Indexable>>:
- boost::tuples::element<N, boost::range::index_value<T, Indexable>> {};
- template<class T, class Indexable>
- struct tuple_size<boost::range::index_value<T, Indexable>>:
- std::integral_constant<std::size_t, 2> {};
- #if defined(BOOST_CLANG)
- #pragma clang diagnostic pop
- #endif
- } // namespace std
- #endif // !defined(BOOST_NO_CXX11_HDR_TUPLE)
- #endif // include guard
|