Chris@16: // Boost.Range library Chris@16: // Chris@16: // Copyright Neil Groves 2007. Use, modification and Chris@16: // distribution is subject to the Boost Software License, Version Chris@16: // 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // Chris@16: // For more information, see http://www.boost.org/libs/range/ Chris@16: // Chris@16: #ifndef BOOST_RANGE_ADAPTOR_STRIDED_HPP_INCLUDED Chris@16: #define BOOST_RANGE_ADAPTOR_STRIDED_HPP_INCLUDED Chris@16: Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: namespace range_detail Chris@16: { Chris@16: // strided_iterator for wrapping a forward traversal iterator Chris@16: template Chris@16: class strided_iterator Chris@101: : public iterator_facade< Chris@16: strided_iterator Chris@101: , typename iterator_value::type Chris@101: , forward_traversal_tag Chris@101: , typename iterator_reference::type Chris@101: , typename iterator_difference::type Chris@16: > Chris@16: { Chris@16: friend class ::boost::iterator_core_access; Chris@16: Chris@101: typedef iterator_facade< Chris@101: strided_iterator Chris@101: , typename iterator_value::type Chris@101: , forward_traversal_tag Chris@101: , typename iterator_reference::type Chris@101: , typename iterator_difference::type Chris@101: > super_t; Chris@16: Chris@16: public: Chris@101: typedef typename super_t::difference_type difference_type; Chris@101: typedef typename super_t::reference reference; Chris@16: typedef BaseIterator base_iterator; Chris@101: typedef std::forward_iterator_tag iterator_category; Chris@16: Chris@16: strided_iterator() Chris@101: : m_it() Chris@101: , m_last() Chris@16: , m_stride() Chris@16: { Chris@16: } Chris@16: Chris@101: strided_iterator(base_iterator it, Chris@101: base_iterator last, Chris@101: difference_type stride) Chris@101: : m_it(it) Chris@16: , m_last(last) Chris@16: , m_stride(stride) Chris@16: { Chris@16: } Chris@16: Chris@16: template Chris@101: strided_iterator( Chris@101: const strided_iterator& other, Chris@101: typename enable_if_convertible< Chris@101: OtherIterator, Chris@101: base_iterator Chris@101: >::type* = 0 Chris@101: ) Chris@101: : m_it(other.base()) Chris@16: , m_last(other.base_end()) Chris@16: , m_stride(other.get_stride()) Chris@16: { Chris@16: } Chris@16: Chris@101: base_iterator base() const Chris@101: { Chris@101: return m_it; Chris@101: } Chris@101: Chris@101: base_iterator base_end() const Chris@101: { Chris@101: return m_last; Chris@101: } Chris@101: Chris@101: difference_type get_stride() const Chris@101: { Chris@101: return m_stride; Chris@101: } Chris@16: Chris@16: private: Chris@16: void increment() Chris@16: { Chris@101: for (difference_type i = 0; Chris@101: (m_it != m_last) && (i < m_stride); ++i) Chris@101: { Chris@101: ++m_it; Chris@101: } Chris@16: } Chris@16: Chris@101: reference dereference() const Chris@101: { Chris@101: return *m_it; Chris@101: } Chris@101: Chris@101: template Chris@101: bool equal( Chris@101: const strided_iterator& other, Chris@101: typename enable_if_convertible< Chris@101: OtherIterator, Chris@101: base_iterator Chris@101: >::type* = 0) const Chris@101: { Chris@101: return m_it == other.m_it; Chris@101: } Chris@101: Chris@101: base_iterator m_it; Chris@16: base_iterator m_last; Chris@16: difference_type m_stride; Chris@16: }; Chris@16: Chris@16: // strided_iterator for wrapping a bidirectional iterator Chris@16: template Chris@16: class strided_iterator Chris@101: : public iterator_facade< Chris@16: strided_iterator Chris@101: , typename iterator_value::type Chris@101: , bidirectional_traversal_tag Chris@101: , typename iterator_reference::type Chris@101: , typename iterator_difference::type Chris@16: > Chris@16: { Chris@16: friend class ::boost::iterator_core_access; Chris@16: Chris@101: typedef iterator_facade< Chris@101: strided_iterator Chris@101: , typename iterator_value::type Chris@101: , bidirectional_traversal_tag Chris@101: , typename iterator_reference::type Chris@101: , typename iterator_difference::type Chris@101: > super_t; Chris@16: public: Chris@101: typedef typename super_t::difference_type difference_type; Chris@101: typedef typename super_t::reference reference; Chris@16: typedef BaseIterator base_iterator; Chris@101: typedef typename boost::make_unsigned::type Chris@101: size_type; Chris@101: typedef std::bidirectional_iterator_tag iterator_category; Chris@16: Chris@16: strided_iterator() Chris@101: : m_it() Chris@101: , m_offset() Chris@101: , m_index() Chris@16: , m_stride() Chris@16: { Chris@16: } Chris@16: Chris@101: strided_iterator(base_iterator it, Chris@101: size_type index, Chris@101: difference_type stride) Chris@101: : m_it(it) Chris@101: , m_offset() Chris@101: , m_index(index) Chris@16: , m_stride(stride) Chris@16: { Chris@101: if (stride && ((m_index % stride) != 0)) Chris@101: m_index += (stride - (m_index % stride)); Chris@16: } Chris@16: Chris@16: template Chris@101: strided_iterator( Chris@101: const strided_iterator< Chris@101: OtherIterator, Chris@101: bidirectional_traversal_tag Chris@101: >& other, Chris@101: typename enable_if_convertible< Chris@101: OtherIterator, Chris@101: base_iterator Chris@101: >::type* = 0 Chris@101: ) Chris@101: : m_it(other.base()) Chris@101: , m_offset(other.get_offset()) Chris@101: , m_index(other.get_index()) Chris@16: , m_stride(other.get_stride()) Chris@16: { Chris@16: } Chris@16: Chris@101: base_iterator base() const Chris@101: { Chris@101: return m_it; Chris@101: } Chris@101: Chris@101: difference_type get_offset() const Chris@101: { Chris@101: return m_offset; Chris@101: } Chris@101: Chris@101: size_type get_index() const Chris@101: { Chris@101: return m_index; Chris@101: } Chris@101: Chris@101: difference_type get_stride() const Chris@101: { Chris@101: return m_stride; Chris@101: } Chris@16: Chris@16: private: Chris@16: void increment() Chris@16: { Chris@101: m_offset += m_stride; Chris@16: } Chris@16: Chris@16: void decrement() Chris@16: { Chris@101: m_offset -= m_stride; Chris@16: } Chris@16: Chris@101: reference dereference() const Chris@101: { Chris@101: update(); Chris@101: return *m_it; Chris@101: } Chris@101: Chris@101: void update() const Chris@101: { Chris@101: std::advance(m_it, m_offset); Chris@101: m_index += m_offset; Chris@101: m_offset = 0; Chris@101: } Chris@101: Chris@101: template Chris@101: bool equal( Chris@101: const strided_iterator< Chris@101: OtherIterator, Chris@101: bidirectional_traversal_tag Chris@101: >& other, Chris@101: typename enable_if_convertible< Chris@101: OtherIterator, Chris@101: base_iterator Chris@101: >::type* = 0) const Chris@101: { Chris@101: return (m_index + m_offset) == Chris@101: (other.get_index() + other.get_offset()); Chris@101: } Chris@101: Chris@101: mutable base_iterator m_it; Chris@101: mutable difference_type m_offset; Chris@101: mutable size_type m_index; Chris@16: difference_type m_stride; Chris@16: }; Chris@16: Chris@16: // strided_iterator implementation for wrapping a random access iterator Chris@16: template Chris@16: class strided_iterator Chris@101: : public iterator_facade< Chris@101: strided_iterator Chris@101: , typename iterator_value::type Chris@101: , random_access_traversal_tag Chris@101: , typename iterator_reference::type Chris@101: , typename iterator_difference::type Chris@101: > Chris@16: { Chris@16: friend class ::boost::iterator_core_access; Chris@16: Chris@101: typedef iterator_facade< Chris@101: strided_iterator Chris@101: , typename iterator_value::type Chris@101: , random_access_traversal_tag Chris@101: , typename iterator_reference::type Chris@101: , typename iterator_difference::type Chris@101: > super_t; Chris@16: public: Chris@101: typedef typename super_t::difference_type difference_type; Chris@101: typedef typename super_t::reference reference; Chris@16: typedef BaseIterator base_iterator; Chris@101: typedef std::random_access_iterator_tag iterator_category; Chris@16: Chris@16: strided_iterator() Chris@101: : m_it() Chris@101: , m_first() Chris@16: , m_index(0) Chris@16: , m_stride() Chris@16: { Chris@16: } Chris@16: Chris@101: strided_iterator( Chris@101: base_iterator first, Chris@101: base_iterator it, Chris@101: difference_type stride Chris@101: ) Chris@101: : m_it(it) Chris@16: , m_first(first) Chris@101: , m_index(stride ? (it - first) : difference_type()) Chris@16: , m_stride(stride) Chris@16: { Chris@101: if (stride && ((m_index % stride) != 0)) Chris@101: m_index += (stride - (m_index % stride)); Chris@16: } Chris@16: Chris@16: template Chris@101: strided_iterator( Chris@101: const strided_iterator< Chris@101: OtherIterator, Chris@101: random_access_traversal_tag Chris@101: >& other, Chris@101: typename enable_if_convertible< Chris@101: OtherIterator, Chris@101: base_iterator Chris@101: >::type* = 0 Chris@101: ) Chris@101: : m_it(other.base()) Chris@16: , m_first(other.base_begin()) Chris@16: , m_index(other.get_index()) Chris@16: , m_stride(other.get_stride()) Chris@16: { Chris@16: } Chris@16: Chris@101: base_iterator base_begin() const Chris@101: { Chris@101: return m_first; Chris@101: } Chris@101: Chris@101: base_iterator base() const Chris@101: { Chris@101: return m_it; Chris@101: } Chris@101: Chris@101: difference_type get_stride() const Chris@101: { Chris@101: return m_stride; Chris@101: } Chris@101: Chris@101: difference_type get_index() const Chris@101: { Chris@101: return m_index; Chris@101: } Chris@16: Chris@16: private: Chris@16: void increment() Chris@16: { Chris@16: m_index += m_stride; Chris@16: } Chris@16: Chris@16: void decrement() Chris@16: { Chris@16: m_index -= m_stride; Chris@16: } Chris@16: Chris@16: void advance(difference_type offset) Chris@16: { Chris@101: m_index += (m_stride * offset); Chris@101: } Chris@101: Chris@101: // Implementation detail: only update the actual underlying iterator Chris@101: // at the point of dereference. This is done so that the increment Chris@101: // and decrement can overshoot the valid sequence as is required Chris@101: // by striding. Since we can do all comparisons just with the index Chris@101: // simply, and all dereferences must be within the valid range. Chris@101: void update() const Chris@101: { Chris@101: m_it = m_first + m_index; Chris@16: } Chris@16: Chris@16: template Chris@101: difference_type distance_to( Chris@101: const strided_iterator< Chris@101: OtherIterator, Chris@101: random_access_traversal_tag Chris@101: >& other, Chris@101: typename enable_if_convertible< Chris@101: OtherIterator, base_iterator>::type* = 0) const Chris@16: { Chris@101: BOOST_ASSERT((other.m_index - m_index) % m_stride == difference_type()); Chris@101: return (other.m_index - m_index) / m_stride; Chris@16: } Chris@16: Chris@101: template Chris@101: bool equal( Chris@101: const strided_iterator< Chris@101: OtherIterator, Chris@101: random_access_traversal_tag Chris@101: >& other, Chris@101: typename enable_if_convertible< Chris@101: OtherIterator, base_iterator>::type* = 0) const Chris@16: { Chris@101: return m_index == other.m_index; Chris@101: } Chris@101: Chris@101: reference dereference() const Chris@101: { Chris@101: update(); Chris@101: return *m_it; Chris@16: } Chris@16: Chris@16: private: Chris@101: mutable base_iterator m_it; Chris@16: base_iterator m_first; Chris@16: difference_type m_index; Chris@16: difference_type m_stride; Chris@16: }; Chris@16: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: forward_traversal_tag Chris@101: > Chris@101: make_begin_strided_iterator( Chris@101: Rng& rng, Chris@101: Difference stride, Chris@101: forward_traversal_tag) Chris@16: { Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: forward_traversal_tag Chris@101: >(boost::begin(rng), boost::end(rng), stride); Chris@16: } Chris@16: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: forward_traversal_tag Chris@101: > Chris@101: make_begin_strided_iterator( Chris@101: const Rng& rng, Chris@101: Difference stride, Chris@101: forward_traversal_tag) Chris@101: { Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: forward_traversal_tag Chris@101: >(boost::begin(rng), boost::end(rng), stride); Chris@101: } Chris@101: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: forward_traversal_tag Chris@101: > Chris@101: make_end_strided_iterator( Chris@101: Rng& rng, Chris@101: Difference stride, Chris@101: forward_traversal_tag) Chris@101: { Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: forward_traversal_tag Chris@101: >(boost::end(rng), boost::end(rng), stride); Chris@101: } Chris@101: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: forward_traversal_tag Chris@101: > Chris@101: make_end_strided_iterator( Chris@101: const Rng& rng, Chris@101: Difference stride, Chris@101: forward_traversal_tag) Chris@101: { Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: forward_traversal_tag Chris@101: >(boost::end(rng), boost::end(rng), stride); Chris@101: } Chris@101: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: bidirectional_traversal_tag Chris@101: > Chris@101: make_begin_strided_iterator( Chris@101: Rng& rng, Chris@101: Difference stride, Chris@101: bidirectional_traversal_tag) Chris@101: { Chris@101: typedef typename range_difference::type difference_type; Chris@101: Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: bidirectional_traversal_tag Chris@101: >(boost::begin(rng), difference_type(), stride); Chris@101: } Chris@101: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: bidirectional_traversal_tag Chris@101: > Chris@101: make_begin_strided_iterator( Chris@101: const Rng& rng, Chris@101: Difference stride, Chris@101: bidirectional_traversal_tag) Chris@101: { Chris@101: typedef typename range_difference::type difference_type; Chris@101: Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: bidirectional_traversal_tag Chris@101: >(boost::begin(rng), difference_type(), stride); Chris@101: } Chris@101: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: bidirectional_traversal_tag Chris@101: > Chris@101: make_end_strided_iterator( Chris@101: Rng& rng, Chris@101: Difference stride, Chris@101: bidirectional_traversal_tag) Chris@101: { Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: bidirectional_traversal_tag Chris@101: >(boost::end(rng), boost::size(rng), stride); Chris@101: } Chris@101: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: bidirectional_traversal_tag Chris@101: > Chris@101: make_end_strided_iterator( Chris@101: const Rng& rng, Chris@101: Difference stride, Chris@101: bidirectional_traversal_tag) Chris@101: { Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: bidirectional_traversal_tag Chris@101: >(boost::end(rng), boost::size(rng), stride); Chris@101: } Chris@101: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: random_access_traversal_tag Chris@101: > Chris@101: make_begin_strided_iterator( Chris@101: Rng& rng, Chris@101: Difference stride, Chris@101: random_access_traversal_tag) Chris@101: { Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: random_access_traversal_tag Chris@101: >(boost::begin(rng), boost::begin(rng), stride); Chris@101: } Chris@101: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: random_access_traversal_tag Chris@101: > Chris@101: make_begin_strided_iterator( Chris@101: const Rng& rng, Chris@101: Difference stride, Chris@101: random_access_traversal_tag) Chris@101: { Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: random_access_traversal_tag Chris@101: >(boost::begin(rng), boost::begin(rng), stride); Chris@101: } Chris@101: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: random_access_traversal_tag Chris@101: > Chris@101: make_end_strided_iterator( Chris@101: Rng& rng, Chris@101: Difference stride, Chris@101: random_access_traversal_tag) Chris@101: { Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: random_access_traversal_tag Chris@101: >(boost::begin(rng), boost::end(rng), stride); Chris@101: } Chris@101: Chris@101: template inline Chris@101: strided_iterator< Chris@101: typename range_iterator::type, Chris@101: random_access_traversal_tag Chris@101: > Chris@101: make_end_strided_iterator( Chris@101: const Rng& rng, Chris@101: Difference stride, Chris@101: random_access_traversal_tag) Chris@101: { Chris@101: return strided_iterator< Chris@101: typename range_iterator::type, Chris@101: random_access_traversal_tag Chris@101: >(boost::begin(rng), boost::end(rng), stride); Chris@101: } Chris@101: Chris@101: template< Chris@101: class Rng, Chris@101: class Category = Chris@101: typename iterator_traversal< Chris@101: typename range_iterator::type Chris@101: >::type Chris@101: > Chris@16: class strided_range Chris@16: : public iterator_range< Chris@101: range_detail::strided_iterator< Chris@101: typename range_iterator::type, Chris@101: Category Chris@101: > Chris@101: > Chris@16: { Chris@16: typedef range_detail::strided_iterator< Chris@101: typename range_iterator::type, Chris@101: Category Chris@101: > iter_type; Chris@16: typedef iterator_range super_t; Chris@16: public: Chris@16: template Chris@16: strided_range(Difference stride, Rng& rng) Chris@101: : super_t( Chris@101: range_detail::make_begin_strided_iterator( Chris@101: rng, stride, Chris@101: typename iterator_traversal< Chris@101: typename range_iterator::type Chris@101: >::type()), Chris@101: range_detail::make_end_strided_iterator( Chris@101: rng, stride, Chris@101: typename iterator_traversal< Chris@101: typename range_iterator::type Chris@101: >::type())) Chris@16: { Chris@16: BOOST_ASSERT( stride >= 0 ); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: class strided_holder : public holder Chris@16: { Chris@16: public: Chris@101: explicit strided_holder(Difference value) Chris@101: : holder(value) Chris@101: { Chris@101: } Chris@16: }; Chris@16: Chris@16: template Chris@16: inline strided_range Chris@16: operator|(Rng& rng, const strided_holder& stride) Chris@16: { Chris@16: return strided_range(stride.val, rng); Chris@16: } Chris@16: Chris@16: template Chris@16: inline strided_range Chris@16: operator|(const Rng& rng, const strided_holder& stride) Chris@16: { Chris@16: return strided_range(stride.val, rng); Chris@16: } Chris@16: Chris@16: } // namespace range_detail Chris@16: Chris@16: using range_detail::strided_range; Chris@16: Chris@16: namespace adaptors Chris@16: { Chris@16: Chris@16: namespace Chris@16: { Chris@16: const range_detail::forwarder Chris@101: strided = range_detail::forwarder< Chris@101: range_detail::strided_holder>(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline strided_range Chris@16: stride(Range& rng, Difference step) Chris@16: { Chris@16: return strided_range(step, rng); Chris@16: } Chris@16: Chris@16: template Chris@16: inline strided_range Chris@16: stride(const Range& rng, Difference step) Chris@16: { Chris@16: return strided_range(step, rng); Chris@16: } Chris@16: Chris@16: } // namespace 'adaptors' Chris@16: } // namespace 'boost' Chris@16: Chris@16: #endif