From 014fdb8ace11d1f18066b838a708a83eba067ce0 Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Fri, 24 Dec 2010 15:00:08 +0000 Subject: [PATCH] [boost][range] - Corrected yesterdays erroneous modifications to the strided adaptor. [SVN r67445] --- include/boost/range/adaptor/strided.hpp | 123 +++++++++++++++++------- test/adaptor_test/strided.cpp | 118 +++++++++++++++++++++-- 2 files changed, 197 insertions(+), 44 deletions(-) diff --git a/include/boost/range/adaptor/strided.hpp b/include/boost/range/adaptor/strided.hpp index ab86e46..9bbd8ca 100755 --- a/include/boost/range/adaptor/strided.hpp +++ b/include/boost/range/adaptor/strided.hpp @@ -16,68 +16,119 @@ #include #include +#include + namespace boost { namespace range_detail { - template + template class strided_iterator : public iterator_adaptor< - strided_iterator, - BaseIterator> + strided_iterator + , BaseIterator + > { friend class iterator_core_access; typedef iterator_adaptor, BaseIterator> super_t; public: - typedef BOOST_DEDUCED_TYPENAME std::iterator_traits::difference_type difference_type; + typedef BOOST_DEDUCED_TYPENAME std::iterator_traits::difference_type difference_type; - strided_iterator() : m_stride() { } + strided_iterator() + : m_stride(), m_offset(), m_max_offset() + { + } - strided_iterator(const strided_iterator& other) - : super_t(other), m_stride(other.m_stride) { } + explicit strided_iterator(BaseIterator base_it, + difference_type stride, + difference_type offset, + difference_type max_offset) + : super_t(base_it) + , m_stride(stride) + , m_offset(offset) + , m_max_offset(max_offset) + { + } - explicit strided_iterator(BaseIterator base_it, difference_type stride) - : super_t(base_it), m_stride(stride) { } + template + strided_iterator(const strided_iterator& other, + BOOST_DEDUCED_TYPENAME enable_if_convertible::type* = 0) + : super_t(other) + , m_stride(other.m_stride) + , m_offset(other.m_offset) + , m_max_offset(other.m_max_offset) + { + } strided_iterator& operator=(const strided_iterator& other) { super_t::operator=(other); - - // Is the interoperation of the stride safe? m_stride = other.m_stride; + m_offset = other.m_offset; + m_max_offset = other.m_max_offset; return *this; } - void increment() { std::advance(this->base_reference(), m_stride); } + void increment() + { + m_offset += m_stride; + if (m_offset <= m_max_offset) + std::advance(this->base_reference(), m_stride); + } - void decrement() { std::advance(this->base_reference(), -m_stride); } + void decrement() + { + m_offset -= m_stride; + if (m_offset >= 0) + std::advance(this->base_reference(), -m_stride); + } - void advance(difference_type n) { std::advance(this->base_reference(), n * m_stride); } + void advance(difference_type n) + { + n *= m_stride; + m_offset += n; + + if (m_offset >= 0 && m_offset <= m_max_offset) + std::advance(this->base_reference(), n); + } + + template + bool equal(const strided_iterator& other, + BOOST_DEDUCED_TYPENAME enable_if_convertible::type* = 0) const + { + return m_offset == other.m_offset; + } difference_type distance_to(const strided_iterator& other) const { - return std::distance(this->base_reference(), other.base_reference()) / m_stride; + return (other.m_offset - m_offset) / m_stride; } - // Using the compiler generated copy constructor and - // and assignment operator - private: difference_type m_stride; + difference_type m_offset; + difference_type m_max_offset; }; - template inline + template inline strided_iterator make_strided_iterator( const BaseIterator& first, - BOOST_DEDUCED_TYPENAME std::iterator_traits::difference_type stride) + Difference stride, + typename std::iterator_traits::difference_type offset, + typename std::iterator_traits::difference_type max_offset + ) { - return strided_iterator(first, stride); + BOOST_ASSERT( stride >= 0 ); + BOOST_ASSERT( (stride == 0) || (offset % stride == 0) ); + BOOST_ASSERT( (stride == 0) || (max_offset % stride == 0) ); + BOOST_ASSERT( offset <= max_offset ); + return strided_iterator(first, stride, offset, max_offset); } template< class Rng > @@ -87,33 +138,33 @@ namespace boost typedef range_detail::strided_iterator::type> iter_type; typedef iterator_range super_t; public: - template< typename Difference > + template strided_range(Difference stride, Rng& rng) - : super_t(make_first(rng, stride), make_last(rng, stride)) + : super_t(make_super(stride, rng)) { BOOST_ASSERT( stride >= 0 ); } + private: - template - static iter_type make_first(Rng& rng, Difference stride) + template + static super_t make_super(const Difference stride, Rng& rng) { - return make_strided_iterator(boost::begin(rng), stride); + const Difference count = boost::size(rng); + const Difference max_count = max_offset(count, stride); + return super_t(make_strided_iterator(boost::begin(rng), stride, 0, max_count), + make_strided_iterator(boost::end(rng), stride, max_count, max_count)); } - template - static iter_type make_last(Rng& rng, Difference stride) + template + static Difference max_offset(Difference sz, const Stride stride) { - typedef BOOST_DEDUCED_TYPENAME range_iterator::type raw_iter_t; - typedef BOOST_DEDUCED_TYPENAME range_difference::type diff_t; - if (stride > 0) { - raw_iter_t it = boost::end(rng); - const diff_t count = boost::size(rng); - std::advance(it, -(count % stride)); - return iter_type(it, stride); + sz += stride - 1; + sz /= stride; + sz *= stride; } - return make_strided_iterator(boost::end(rng), stride); + return sz; } }; diff --git a/test/adaptor_test/strided.cpp b/test/adaptor_test/strided.cpp index 6f4d1ef..2131cd7 100644 --- a/test/adaptor_test/strided.cpp +++ b/test/adaptor_test/strided.cpp @@ -44,15 +44,13 @@ namespace boost typedef BOOST_DEDUCED_TYPENAME Container::size_type size_type; iterator_t it = c.begin(); - size_type count = c.size(); - size_type unreachable_element_count = c.size() - ((count / stride_size) * stride_size); - diff_t offset = -static_cast(unreachable_element_count); iterator_t last = c.end(); - std::advance(last, offset); - - for (; it != last; std::advance(it, stride_size)) + for (; it != last; ) { reference.push_back(*it); + + for (int i = 0; (it != last) && (i < stride_size); ++i) + ++it; } } @@ -129,8 +127,8 @@ namespace boost strided_range_t rng( boost::adaptors::stride(c, 0) ); typedef typename boost::range_iterator::type iter_t; - iter_t first(boost::begin(c), 0); - iter_t last(boost::end(c), 0); + iter_t first(boost::begin(c), 0, 0, boost::size(c)); + iter_t last(boost::end(c), 0, boost::size(c), boost::size(c)); iter_t it = first; for (int i = 0; i < 10; ++i, ++it) @@ -157,6 +155,108 @@ namespace boost strided_test_impl< std::deque >(); strided_test_impl< std::list >(); } + + void strided_defect_Trac5014() + { + using namespace boost::assign; + + std::vector v; + for (int i = 0; i < 30; ++i) + v.push_back(i); + + std::vector reference; + reference += 0,4,8,12,16,20,24,28; + + std::vector output; + boost::push_back(output, v | boost::adaptors::strided(4)); + + BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(), + output.begin(), output.end() ); + + BOOST_CHECK_EQUAL( output.back(), 28 ); + } + + template + class strided_mock_iterator + : public boost::iterator_adaptor< + strided_mock_iterator + , BaseIterator + , boost::use_default + , Category + > + { + typedef boost::iterator_adaptor< + strided_mock_iterator + , BaseIterator + , boost::use_default + , Category + > super_t; + public: + explicit strided_mock_iterator(BaseIterator it) + : super_t(it) + { + } + + private: + void increment() + { + ++(this->base_reference()); + } + + bool equal(const strided_mock_iterator& other) const + { + return this->base() == other.base(); + } + + BOOST_DEDUCED_TYPENAME super_t::reference dereference() const + { + return *(this->base()); + } + + friend class boost::iterator_core_access; + }; + + template + boost::iterator_range::type, Category> > + as_mock_range(Range& rng) + { + typedef BOOST_DEDUCED_TYPENAME boost::range_iterator::type range_iter_t; + typedef strided_mock_iterator mock_iter_t; + + return boost::iterator_range( + mock_iter_t(boost::begin(rng)), + mock_iter_t(boost::end(rng))); + } + + void strided_test_traversal() + { + using namespace boost::assign; + + std::vector v; + for (int i = 0; i < 30; ++i) + v.push_back(i); + + std::vector reference; + reference += 0,4,8,12,16,20,24,28; + + std::vector output; + boost::push_back(output, as_mock_range(v) | boost::adaptors::strided(4)); + + BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(), + output.begin(), output.end() ); + + output.clear(); + boost::push_back(output, as_mock_range(v) | boost::adaptors::strided(4)); + + BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(), + output.begin(), output.end() ); + + output.clear(); + boost::push_back(output, as_mock_range(v) | boost::adaptors::strided(4)); + + BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(), + output.begin(), output.end() ); + } } } @@ -167,6 +267,8 @@ init_unit_test_suite(int argc, char* argv[]) = BOOST_TEST_SUITE( "RangeTestSuite.adaptor.strided" ); test->add( BOOST_TEST_CASE( &boost::strided_test ) ); + test->add( BOOST_TEST_CASE( &boost::strided_defect_Trac5014 ) ); + test->add( BOOST_TEST_CASE( &boost::strided_test_traversal ) ); return test; }