From ceffd1cf79047fa262d74b13a148352e5ce4e9f5 Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Wed, 26 Feb 2014 21:17:29 +0000 Subject: [PATCH] strided adaptor rewritten to correct defects and optimise performance. --- include/boost/range/adaptor/strided.hpp | 609 ++++++++++++++---- .../boost/range/detail/has_member_size.hpp | 66 ++ include/boost/range/irange.hpp | 10 +- include/boost/range/iterator_range_core.hpp | 8 +- include/boost/range/size.hpp | 25 +- test/Jamfile.v2 | 1 + test/adaptor_test/strided.cpp | 11 +- .../ticket_9519_strided_reversed.cpp | 67 ++ 8 files changed, 653 insertions(+), 144 deletions(-) create mode 100644 include/boost/range/detail/has_member_size.hpp create mode 100644 test/adaptor_test/ticket_9519_strided_reversed.cpp diff --git a/include/boost/range/adaptor/strided.hpp b/include/boost/range/adaptor/strided.hpp index e843f62..c5fea86 100755 --- a/include/boost/range/adaptor/strided.hpp +++ b/include/boost/range/adaptor/strided.hpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include namespace boost @@ -23,59 +23,102 @@ namespace boost // strided_iterator for wrapping a forward traversal iterator template class strided_iterator - : public iterator_adaptor< + : public iterator_facade< strided_iterator - , BaseIterator - , use_default - , boost::forward_traversal_tag + , typename iterator_value::type + , forward_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type > { friend class ::boost::iterator_core_access; - typedef iterator_adaptor< - strided_iterator - , BaseIterator - , use_default - , boost::forward_traversal_tag - > super_t; + typedef iterator_facade< + strided_iterator + , typename iterator_value::type + , forward_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type + > super_t; public: - typedef BOOST_DEDUCED_TYPENAME std::iterator_traits::difference_type difference_type; + typedef typename super_t::difference_type difference_type; + typedef typename super_t::reference reference; typedef BaseIterator base_iterator; + typedef std::forward_iterator_tag iterator_category; strided_iterator() - : m_last() + : m_it() + , m_last() , m_stride() { } - strided_iterator(base_iterator first, base_iterator it, base_iterator last, difference_type stride) - : super_t(it) + strided_iterator(base_iterator it, + base_iterator last, + difference_type stride) + : m_it(it) , m_last(last) , m_stride(stride) { } template - strided_iterator(const strided_iterator& other, - BOOST_DEDUCED_TYPENAME enable_if_convertible::type* = 0) - : super_t(other) + strided_iterator( + const strided_iterator& other, + typename enable_if_convertible< + OtherIterator, + base_iterator + >::type* = 0 + ) + : m_it(other.base()) , m_last(other.base_end()) , m_stride(other.get_stride()) { } - base_iterator base_end() const { return m_last; } - difference_type get_stride() const { return m_stride; } + base_iterator base() const + { + return m_it; + } + + base_iterator base_end() const + { + return m_last; + } + + difference_type get_stride() const + { + return m_stride; + } private: void increment() { - base_iterator& it = this->base_reference(); - for (difference_type i = 0; (it != m_last) && (i < m_stride); ++i) - ++it; + for (difference_type i = 0; + (m_it != m_last) && (i < m_stride); ++i) + { + ++m_it; + } } + reference dereference() const + { + return *m_it; + } + + template + bool equal( + const strided_iterator& other, + typename enable_if_convertible< + OtherIterator, + base_iterator + >::type* = 0) const + { + return m_it == other.m_it; + } + + base_iterator m_it; base_iterator m_last; difference_type m_stride; }; @@ -83,214 +126,514 @@ namespace boost // strided_iterator for wrapping a bidirectional iterator template class strided_iterator - : public iterator_adaptor< + : public iterator_facade< strided_iterator - , BaseIterator - , use_default - , bidirectional_traversal_tag + , typename iterator_value::type + , bidirectional_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type > { friend class ::boost::iterator_core_access; - typedef iterator_adaptor< - strided_iterator - , BaseIterator - , use_default - , bidirectional_traversal_tag - > super_t; + typedef iterator_facade< + strided_iterator + , typename iterator_value::type + , bidirectional_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type + > super_t; public: - typedef BOOST_DEDUCED_TYPENAME std::iterator_traits::difference_type difference_type; + typedef typename super_t::difference_type difference_type; + typedef typename super_t::reference reference; typedef BaseIterator base_iterator; + typedef typename boost::make_unsigned::type + size_type; + typedef std::bidirectional_iterator_tag iterator_category; strided_iterator() - : m_first() - , m_last() + : m_it() + , m_offset() + , m_index() , m_stride() { } - strided_iterator(base_iterator first, base_iterator it, base_iterator last, difference_type stride) - : super_t(it) - , m_first(first) - , m_last(last) + strided_iterator(base_iterator it, + size_type index, + difference_type stride) + : m_it(it) + , m_offset() + , m_index(index) , m_stride(stride) { + if (stride && ((m_index % stride) != 0)) + m_index += (stride - (m_index % stride)); } template - strided_iterator(const strided_iterator& other, - BOOST_DEDUCED_TYPENAME enable_if_convertible::type* = 0) - : super_t(other.base()) - , m_first(other.base_begin()) - , m_last(other.base_end()) + strided_iterator( + const strided_iterator< + OtherIterator, + bidirectional_traversal_tag + >& other, + typename enable_if_convertible< + OtherIterator, + base_iterator + >::type* = 0 + ) + : m_it(other.base()) + , m_offset(other.get_offset()) + , m_index(other.get_index()) , m_stride(other.get_stride()) { } - base_iterator base_begin() const { return m_first; } - base_iterator base_end() const { return m_last; } - difference_type get_stride() const { return m_stride; } + base_iterator base() const + { + return m_it; + } + + difference_type get_offset() const + { + return m_offset; + } + + size_type get_index() const + { + return m_index; + } + + difference_type get_stride() const + { + return m_stride; + } private: void increment() { - base_iterator& it = this->base_reference(); - for (difference_type i = 0; (it != m_last) && (i < m_stride); ++i) - ++it; + m_offset += m_stride; } void decrement() { - base_iterator& it = this->base_reference(); - for (difference_type i = 0; (it != m_first) && (i < m_stride); ++i) - --it; + m_offset -= m_stride; } - base_iterator m_first; - base_iterator m_last; + reference dereference() const + { + update(); + return *m_it; + } + + void update() const + { + std::advance(m_it, m_offset); + m_index += m_offset; + m_offset = 0; + } + + template + bool equal( + const strided_iterator< + OtherIterator, + bidirectional_traversal_tag + >& other, + typename enable_if_convertible< + OtherIterator, + base_iterator + >::type* = 0) const + { + return (m_index + m_offset) == + (other.get_index() + other.get_offset()); + } + + mutable base_iterator m_it; + mutable difference_type m_offset; + mutable size_type m_index; difference_type m_stride; }; // strided_iterator implementation for wrapping a random access iterator template class strided_iterator - : public iterator_adaptor< - strided_iterator - , BaseIterator - , use_default - , random_access_traversal_tag - > + : public iterator_facade< + strided_iterator + , typename iterator_value::type + , random_access_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type + > { friend class ::boost::iterator_core_access; - typedef iterator_adaptor< - strided_iterator - , BaseIterator - , use_default - , random_access_traversal_tag - > super_t; + typedef iterator_facade< + strided_iterator + , typename iterator_value::type + , random_access_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type + > super_t; public: - typedef BOOST_DEDUCED_TYPENAME super_t::difference_type difference_type; + typedef typename super_t::difference_type difference_type; + typedef typename super_t::reference reference; typedef BaseIterator base_iterator; + typedef std::random_access_iterator_tag iterator_category; strided_iterator() - : m_first() - , m_last() + : m_it() + , m_first() , m_index(0) , m_stride() { } - strided_iterator(BaseIterator first, BaseIterator it, BaseIterator last, difference_type stride) - : super_t(it) + strided_iterator( + base_iterator first, + base_iterator it, + difference_type stride + ) + : m_it(it) , m_first(first) - , m_last(last) - , m_index(stride ? (it - first) / stride : 0) + , m_index(stride ? (it - first) : difference_type()) , m_stride(stride) { + if (stride && ((m_index % stride) != 0)) + m_index += (stride - (m_index % stride)); } template - strided_iterator(const strided_iterator& other, - BOOST_DEDUCED_TYPENAME enable_if_convertible::type* = 0) - : super_t(other.base()) + strided_iterator( + const strided_iterator< + OtherIterator, + random_access_traversal_tag + >& other, + typename enable_if_convertible< + OtherIterator, + base_iterator + >::type* = 0 + ) + : m_it(other.base()) , m_first(other.base_begin()) - , m_last(other.base_end()) , m_index(other.get_index()) , m_stride(other.get_stride()) { } - base_iterator base_begin() const { return m_first; } - base_iterator base_end() const { return m_last; } - difference_type get_stride() const { return m_stride; } - difference_type get_index() const { return m_index; } + base_iterator base_begin() const + { + return m_first; + } + + base_iterator base() const + { + return m_it; + } + + difference_type get_stride() const + { + return m_stride; + } + + difference_type get_index() const + { + return m_index; + } private: void increment() { m_index += m_stride; - if (m_index < (m_last - m_first)) - this->base_reference() = m_first + m_index; - else - this->base_reference() = m_last; } void decrement() { m_index -= m_stride; - if (m_index >= 0) - this->base_reference() = m_first + m_index; - else - this->base_reference() = m_first; } void advance(difference_type offset) { - offset *= m_stride; - m_index += offset; - if (m_index < 0) - this->base_reference() = m_first; - else if (m_index > (m_last - m_first)) - this->base_reference() = m_last; - else - this->base_reference() = m_first + m_index; + m_index += (m_stride * offset); + } + + // Implementation detail: only update the actual underlying iterator + // at the point of dereference. This is done so that the increment + // and decrement can overshoot the valid sequence as is required + // by striding. Since we can do all comparisons just with the index + // simply, and all dereferences must be within the valid range. + void update() const + { + m_it = m_first + m_index; } template - difference_type distance_to(const strided_iterator& other, - BOOST_DEDUCED_TYPENAME enable_if_convertible::type* = 0) const + difference_type distance_to( + const strided_iterator< + OtherIterator, + random_access_traversal_tag + >& other, + typename enable_if_convertible< + OtherIterator, base_iterator>::type* = 0) const { - if (other.base() >= this->base()) - return (other.base() - this->base() + (m_stride - 1)) / m_stride; - return (other.base() - this->base() - (m_stride - 1)) / m_stride; + BOOST_ASSERT((other.m_index - m_index) % m_stride == difference_type()); + return (other.m_index - m_index) / m_stride; } - bool equal(const strided_iterator& other) const + template + bool equal( + const strided_iterator< + OtherIterator, + random_access_traversal_tag + >& other, + typename enable_if_convertible< + OtherIterator, base_iterator>::type* = 0) const { - return this->base() == other.base(); + return m_index == other.m_index; + } + + reference dereference() const + { + update(); + return *m_it; } private: + mutable base_iterator m_it; base_iterator m_first; - base_iterator m_last; difference_type m_index; difference_type m_stride; }; - template inline - strided_iterator::type> - make_strided_iterator(BaseIterator first, BaseIterator it, - BaseIterator last, Difference stride) + template inline + strided_iterator< + typename range_iterator::type, + forward_traversal_tag + > + make_begin_strided_iterator( + Rng& rng, + Difference stride, + forward_traversal_tag) { - BOOST_ASSERT( stride >= 0 ); - typedef BOOST_DEDUCED_TYPENAME iterator_traversal::type traversal_tag; - return strided_iterator(first, it, last, stride); + return strided_iterator< + typename range_iterator::type, + forward_traversal_tag + >(boost::begin(rng), boost::end(rng), stride); } - template< class Rng - , class Category = BOOST_DEDUCED_TYPENAME iterator_traversal< - BOOST_DEDUCED_TYPENAME range_iterator::type - >::type - > + template inline + strided_iterator< + typename range_iterator::type, + forward_traversal_tag + > + make_begin_strided_iterator( + const Rng& rng, + Difference stride, + forward_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + forward_traversal_tag + >(boost::begin(rng), boost::end(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + forward_traversal_tag + > + make_end_strided_iterator( + Rng& rng, + Difference stride, + forward_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + forward_traversal_tag + >(boost::end(rng), boost::end(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + forward_traversal_tag + > + make_end_strided_iterator( + const Rng& rng, + Difference stride, + forward_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + forward_traversal_tag + >(boost::end(rng), boost::end(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + > + make_begin_strided_iterator( + Rng& rng, + Difference stride, + bidirectional_traversal_tag) + { + typedef typename range_difference::type difference_type; + + return strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + >(boost::begin(rng), difference_type(), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + > + make_begin_strided_iterator( + const Rng& rng, + Difference stride, + bidirectional_traversal_tag) + { + typedef typename range_difference::type difference_type; + + return strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + >(boost::begin(rng), difference_type(), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + > + make_end_strided_iterator( + Rng& rng, + Difference stride, + bidirectional_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + >(boost::end(rng), boost::size(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + > + make_end_strided_iterator( + const Rng& rng, + Difference stride, + bidirectional_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + >(boost::end(rng), boost::size(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + > + make_begin_strided_iterator( + Rng& rng, + Difference stride, + random_access_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + >(boost::begin(rng), boost::begin(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + > + make_begin_strided_iterator( + const Rng& rng, + Difference stride, + random_access_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + >(boost::begin(rng), boost::begin(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + > + make_end_strided_iterator( + Rng& rng, + Difference stride, + random_access_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + >(boost::begin(rng), boost::end(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + > + make_end_strided_iterator( + const Rng& rng, + Difference stride, + random_access_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + >(boost::begin(rng), boost::end(rng), stride); + } + + template< + class Rng, + class Category = + typename iterator_traversal< + typename range_iterator::type + >::type + > class strided_range : public iterator_range< - range_detail::strided_iterator< - BOOST_DEDUCED_TYPENAME range_iterator::type, - Category - > - > + range_detail::strided_iterator< + typename range_iterator::type, + Category + > + > { typedef range_detail::strided_iterator< - BOOST_DEDUCED_TYPENAME range_iterator::type, - Category - > iter_type; + typename range_iterator::type, + Category + > iter_type; typedef iterator_range super_t; public: template strided_range(Difference stride, Rng& rng) - : super_t(make_strided_iterator(boost::begin(rng), boost::begin(rng), boost::end(rng), stride), - make_strided_iterator(boost::begin(rng), boost::end(rng), boost::end(rng), stride)) + : super_t( + range_detail::make_begin_strided_iterator( + rng, stride, + typename iterator_traversal< + typename range_iterator::type + >::type()), + range_detail::make_end_strided_iterator( + rng, stride, + typename iterator_traversal< + typename range_iterator::type + >::type())) { BOOST_ASSERT( stride >= 0 ); } @@ -300,7 +643,10 @@ namespace boost class strided_holder : public holder { public: - explicit strided_holder(Difference value) : holder(value) {} + explicit strided_holder(Difference value) + : holder(value) + { + } }; template @@ -327,7 +673,8 @@ namespace boost namespace { const range_detail::forwarder - strided = range_detail::forwarder(); + strided = range_detail::forwarder< + range_detail::strided_holder>(); } template diff --git a/include/boost/range/detail/has_member_size.hpp b/include/boost/range/detail/has_member_size.hpp new file mode 100644 index 0000000..0c639aa --- /dev/null +++ b/include/boost/range/detail/has_member_size.hpp @@ -0,0 +1,66 @@ +// Boost.Range library +// +// Copyright Neil Groves 2014. +// +// Use, modification and distribution are 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). +// +// For more information, see http://www.boost.org/libs/range/ +// +#ifndef BOOST_RANGE_DETAIL_HAS_MEMBER_SIZE_HPP +#define BOOST_RANGE_DETAIL_HAS_MEMBER_SIZE_HPP + +#include +#include +#include +#include +#include + +namespace boost +{ + namespace range_detail + { + +template +class has_member_size_impl +{ +private: + template + class check + { + }; + + template + static boost::uint8_t f(check*); + + template + static boost::uint16_t f(...); + +public: + static const bool value = + (sizeof(f(0)) == sizeof(boost::uint8_t)); + + typedef typename mpl::if_c< + (sizeof(f(0)) == sizeof(boost::uint8_t)), + mpl::true_, + mpl::false_ + >::type type; +}; + +template +struct has_member_size +{ + typedef typename mpl::and_< + typename is_class::type, + typename has_member_size_impl::type + >::type type; + + static const bool value = + is_class::value && has_member_size_impl::value; +}; + + } // namespace range_detail +}// namespace boost + +#endif // include guard diff --git a/include/boost/range/irange.hpp b/include/boost/range/irange.hpp index f35df47..b1a1240 100644 --- a/include/boost/range/irange.hpp +++ b/include/boost/range/irange.hpp @@ -51,6 +51,7 @@ namespace boost typedef typename base_t::value_type value_type; typedef typename base_t::difference_type difference_type; typedef typename base_t::reference reference; + typedef std::random_access_iterator_tag iterator_category; integer_iterator() : m_value() {} explicit integer_iterator(value_type x) : m_value(x) {} @@ -73,7 +74,11 @@ namespace boost difference_type distance_to(const integer_iterator& other) const { - return other.m_value - m_value; + return is_signed::value + ? (other.m_value - m_value) + : (other.m_value >= m_value) + ? static_cast(other.m_value - m_value) + : -static_cast(m_value - other.m_value); } bool equal(const integer_iterator& other) const @@ -123,6 +128,7 @@ namespace boost typedef typename base_t::value_type value_type; typedef typename base_t::difference_type difference_type; typedef typename base_t::reference reference; + typedef std::random_access_iterator_tag iterator_category; integer_iterator_with_step(value_type first, difference_type step, value_type step_size) : m_first(first) @@ -164,7 +170,7 @@ namespace boost friend class ::boost::iterator_core_access; value_type m_first; - value_type m_step; + difference_type m_step; difference_type m_step_size; }; diff --git a/include/boost/range/iterator_range_core.hpp b/include/boost/range/iterator_range_core.hpp index 1e671fc..1e63b7e 100644 --- a/include/boost/range/iterator_range_core.hpp +++ b/include/boost/range/iterator_range_core.hpp @@ -371,13 +371,13 @@ public: template class iterator_range : public iterator_range_detail::iterator_range_base< - IteratorT, - typename iterator_traversal::type + IteratorT, + BOOST_DEDUCED_TYPENAME iterator_traversal::type > { typedef iterator_range_detail::iterator_range_base< - IteratorT, - typename iterator_traversal::type + IteratorT, + BOOST_DEDUCED_TYPENAME iterator_traversal::type > base_type; protected: diff --git a/include/boost/range/size.hpp b/include/boost/range/size.hpp index 9b63aff..cd7a90e 100644 --- a/include/boost/range/size.hpp +++ b/include/boost/range/size.hpp @@ -19,24 +19,39 @@ #include #include #include +#include #include +#include +#include namespace boost { namespace range_detail { + template - inline BOOST_DEDUCED_TYPENAME range_size::type + inline typename enable_if< + has_member_size, + typename range_size::type + >::type range_calculate_size(const SinglePassRange& rng) { - BOOST_ASSERT( (boost::end(rng) - boost::begin(rng)) >= 0 && - "reachability invariant broken!" ); - return boost::end(rng) - boost::begin(rng); + return rng.size(); + } + + template + inline typename disable_if< + has_member_size, + typename range_size::type + >::type + range_calculate_size(const SinglePassRange& rng) + { + return std::distance(boost::begin(rng), boost::end(rng)); } } template - inline BOOST_DEDUCED_TYPENAME range_size::type + inline typename range_size::type size(const SinglePassRange& rng) { #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) && \ diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0871332..ef3d0cd 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -44,6 +44,7 @@ test-suite range : [ range-test adaptor_test/sliced ] [ range-test adaptor_test/strided ] [ range-test adaptor_test/strided2 ] + [ range-test adaptor_test/ticket_9519_strided_reversed ] [ range-test adaptor_test/tokenized ] [ range-test adaptor_test/transformed ] [ range-test adaptor_test/type_erased ] diff --git a/test/adaptor_test/strided.cpp b/test/adaptor_test/strided.cpp index ad9e9e4..6c8475d 100644 --- a/test/adaptor_test/strided.cpp +++ b/test/adaptor_test/strided.cpp @@ -137,8 +137,15 @@ namespace boost boost::ignore_unused_variable_warning(rng); typedef BOOST_DEDUCED_TYPENAME boost::range_iterator::type iter_t; - iter_t first(boost::begin(c), boost::begin(c), boost::end(c), 0); - iter_t last(boost::begin(c), boost::end(c), boost::end(c), 0); + typedef BOOST_DEDUCED_TYPENAME boost::iterator_traversal< + BOOST_DEDUCED_TYPENAME Container::const_iterator + >::type container_traversal_tag; + + iter_t first = boost::range_detail::make_begin_strided_iterator( + c, 0, container_traversal_tag()); + + iter_t last = boost::range_detail::make_end_strided_iterator( + c, 0, container_traversal_tag()); iter_t it = first; for (int i = 0; i < 10; ++i, ++it) diff --git a/test/adaptor_test/ticket_9519_strided_reversed.cpp b/test/adaptor_test/ticket_9519_strided_reversed.cpp new file mode 100644 index 0000000..0c91598 --- /dev/null +++ b/test/adaptor_test/ticket_9519_strided_reversed.cpp @@ -0,0 +1,67 @@ +// Boost.Range library +// +// Copyright Neil Groves 2014. 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) +// +// +// For more information, see http://www.boost.org/libs/range/ +// +// Credit goes to Eric Niebler for providing an example to demonstrate this +// issue. This has been trivially modified to create this test case. +// +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace boost +{ + namespace + { + +void ticket_9519_strided_reversed_test() +{ + using namespace boost::adaptors; + + std::vector vi; + for (int i = 0; i < 50; ++i) + { + vi.push_back(i); + } + + std::vector output; + boost::push_back(output, vi | strided(3) | reversed); + + std::list reference; + for (int i = 0; i < 50; i += 3) + { + reference.push_front(i); + } + + BOOST_CHECK_EQUAL_COLLECTIONS(output.begin(), output.end(), + reference.begin(), reference.end()); +} + + } // anonymous namespace +} // namespace boost + +boost::unit_test::test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + boost::unit_test::test_suite* test + = BOOST_TEST_SUITE( + "RangeTestSuite.adaptor.ticket_9519_strided_reversed"); + + test->add(BOOST_TEST_CASE(&boost::ticket_9519_strided_reversed_test)); + + return test; +} +