From 69759731bb5e55b92052e6f6d7d3efdb049f037b Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Tue, 4 Mar 2014 15:05:00 +0000 Subject: [PATCH 1/4] implemented drop_front and drop_back with test. --- include/boost/range/iterator_range_core.hpp | 35 ++-- test/Jamfile.v2 | 1 + test/iterator_range_drop.cpp | 200 ++++++++++++++++++++ 3 files changed, 219 insertions(+), 17 deletions(-) create mode 100644 test/iterator_range_drop.cpp diff --git a/include/boost/range/iterator_range_core.hpp b/include/boost/range/iterator_range_core.hpp index 7bbae2a..e30f1a6 100644 --- a/include/boost/range/iterator_range_core.hpp +++ b/include/boost/range/iterator_range_core.hpp @@ -206,12 +206,18 @@ public: return *m_Begin; } - void pop_front() + void drop_front() { BOOST_ASSERT(!empty()); ++m_Begin; } + void drop_front(difference_type n) + { + BOOST_ASSERT(n >= difference_type()); + std::advance(this->m_Begin, n); + } + protected: template void assign(Iterator first, Iterator last) @@ -256,17 +262,26 @@ protected: } public: - BOOST_DEDUCED_TYPENAME base_type::reference back() const + typedef BOOST_DEDUCED_TYPENAME base_type::difference_type difference_type; + typedef BOOST_DEDUCED_TYPENAME base_type::reference reference; + + reference back() const { BOOST_ASSERT(!this->empty()); return *boost::prior(this->m_End); } - void pop_back() + void drop_back() { BOOST_ASSERT(!this->empty()); --this->m_End; } + + void drop_back(difference_type n) + { + BOOST_ASSERT(n >= difference_type()); + std::advance(this->m_End, -n); + } }; template @@ -328,20 +343,6 @@ public: return this->m_Begin[at]; } - void pop_front(difference_type n) - { - BOOST_ASSERT(n >= difference_type()); - BOOST_ASSERT(size() >= static_cast(n)); - std::advance(this->m_Begin, n); - } - - void pop_back(difference_type n) - { - BOOST_ASSERT(n >= difference_type()); - BOOST_ASSERT(size() >= static_cast(n)); - std::advance(this->m_End, -n); - } - BOOST_DEDUCED_TYPENAME base_type::size_type size() const { return this->m_End - this->m_Begin; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a7b479a..8b9463e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -160,6 +160,7 @@ test-suite range : [ range-test istream_range ] [ range-test iterator_pair ] [ range-test iterator_range ] + [ range-test iterator_range_drop ] [ range-test iterator_range_variant ] # [ range-test mfc : $(VC71_ROOT)/atlmfc/include ] [ range-test join ] diff --git a/test/iterator_range_drop.cpp b/test/iterator_range_drop.cpp new file mode 100644 index 0000000..3b41041 --- /dev/null +++ b/test/iterator_range_drop.cpp @@ -0,0 +1,200 @@ +// 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/ +// + +#include +#include +#include + +#include +#include + +#include + +namespace boost_range_test +{ + namespace + { + +class single_pass_iterator + : public boost::iterator_facade< + single_pass_iterator, + boost::int32_t, + boost::single_pass_traversal_tag, + const boost::int32_t& + > +{ + friend class boost::iterator_core_access; + + typedef std::vector::const_iterator iterator_t; + +public: + single_pass_iterator() { } + + explicit single_pass_iterator(iterator_t it) + : m_it(it) + { + } + +private: + void increment() + { + ++m_it; + } + + bool equal(single_pass_iterator other) const + { + return m_it == other.m_it; + } + + boost::int32_t dereference() const + { + return *m_it; + } + + iterator_t m_it; +}; + +class bidirectional_iterator + : public boost::iterator_facade< + bidirectional_iterator, + boost::int32_t, + boost::bidirectional_traversal_tag, + const boost::int32_t& + > +{ + friend class boost::iterator_core_access; + + typedef std::vector::const_iterator iterator_t; + +public: + bidirectional_iterator() { } + + explicit bidirectional_iterator(iterator_t it) + : m_it(it) + { + } + +private: + void increment() + { + ++m_it; + } + + void decrement() + { + --m_it; + } + + bool equal(bidirectional_iterator other) const + { + return m_it == other.m_it; + } + + boost::int32_t dereference() const + { + return *m_it; + } + + iterator_t m_it; +}; + +template +boost::iterator_range +single_pass_range(const SinglePassRange& rng) +{ + return boost::iterator_range( + single_pass_iterator(boost::begin(rng)), + single_pass_iterator(boost::end(rng))); +} + +template +boost::iterator_range +bidirectional_range(const BidirectionalRange& rng) +{ + return boost::iterator_range( + bidirectional_iterator(boost::begin(rng)), + bidirectional_iterator(boost::end(rng))); +} + +void test_drop_front() +{ + std::vector v; + std::vector ref_output; + + for (boost::int32_t i = 0; i < 10; ++i) + { + v.push_back(i); + ref_output.push_back(i); + } + + boost::iterator_range rng = single_pass_range(v); + + BOOST_CHECK_EQUAL_COLLECTIONS(rng.begin(), rng.end(), + ref_output.begin(), ref_output.end()); + + rng.drop_front(); + + ref_output.erase(ref_output.begin()); + + BOOST_CHECK_EQUAL_COLLECTIONS(rng.begin(), rng.end(), + ref_output.begin(), ref_output.end()); + + rng.drop_front(5); + + ref_output.erase(ref_output.begin(), ref_output.begin() + 5); + + BOOST_CHECK_EQUAL_COLLECTIONS(rng.begin(), rng.end(), + ref_output.begin(), ref_output.end()); +} + +void test_drop_back() +{ + std::vector v; + std::vector ref_output; + + for (boost::int32_t i = 0; i < 10; ++i) + { + v.push_back(i); + ref_output.push_back(i); + } + + boost::iterator_range rng = bidirectional_range(v); + + BOOST_CHECK_EQUAL_COLLECTIONS(rng.begin(), rng.end(), + ref_output.begin(), ref_output.end()); + + rng.drop_back(); + + ref_output.pop_back(); + + BOOST_CHECK_EQUAL_COLLECTIONS(rng.begin(), rng.end(), + ref_output.begin(), ref_output.end()); + + rng.drop_back(5); + + ref_output.erase(ref_output.end() - 5, ref_output.end()); + + BOOST_CHECK_EQUAL_COLLECTIONS(rng.begin(), rng.end(), + ref_output.begin(), ref_output.end()); +} + + } // anonymous namespace +} // namespace boost_range_test + +boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE("Boost.Range iterator_range drop functions"); + + test->add(BOOST_TEST_CASE(&boost_range_test::test_drop_front)); + test->add(BOOST_TEST_CASE(&boost_range_test::test_drop_back)); + + return test; +} From 09cc98f60d355778330482f7416ebfdffe66bd32 Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Tue, 4 Mar 2014 16:19:51 +0000 Subject: [PATCH 2/4] drop_front and drop_back included in synopsis. --- doc/reference/utilities.qbk | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/doc/reference/utilities.qbk b/doc/reference/utilities.qbk index 0da1f52..b0d9f07 100644 --- a/doc/reference/utilities.qbk +++ b/doc/reference/utilities.qbk @@ -61,11 +61,14 @@ namespace boost operator unspecified_bool_type() const; bool equal( const iterator_range& ) const; value_type& front() const; - value_type& back() const; - iterator_range& advance_begin(difference_type n); - iterator_range& advance_end(difference_type n); + void drop_front(); + void drop_front(difference_type n); bool empty() const; - // for Random Access Range only: + // for Bidirectional: + value_type& back() const; + void drop_back(); + void drop_back(difference_type n); + // for Random Access only: reference operator[]( difference_type at ) const; value_type operator()( difference_type at ) const; size_type size() const; @@ -230,21 +233,6 @@ namespace boost template< class ForwardRange2 > sub_range& operator=( const ForwardRange2& r ); - public: // Forward Range functions - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; - - public: // convenience - value_type& front(); - const value_type& front() const; - value_type& back(); - const value_type& back() const; - // for Random Access Range only: - value_type& operator[]( size_type at ); - const value_type& operator[]( size_type at ) const; - public: // rest of interface inherited from iterator_range }; From e089e0748f33ee0d3c3337d3624bef1073c34ad3 Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Tue, 4 Mar 2014 20:22:57 +0000 Subject: [PATCH 3/4] fix for recently introduced regression to sub_range const propagation. --- doc/reference/utilities.qbk | 25 +++- include/boost/range/sub_range.hpp | 190 ++++++++++++++++++++++++------ test/sub_range.cpp | 110 ++++++++++++++++- 3 files changed, 286 insertions(+), 39 deletions(-) diff --git a/doc/reference/utilities.qbk b/doc/reference/utilities.qbk index b0d9f07..ccad7b0 100644 --- a/doc/reference/utilities.qbk +++ b/doc/reference/utilities.qbk @@ -213,11 +213,17 @@ namespace boost class sub_range : public iterator_range< typename range_iterator::type > { public: + typedef typename range_value::type value_type; typedef typename range_iterator::type iterator; typedef typename range_iterator::type const_iterator; - typedef typename iterator_difference::type difference_type; + typedef typename range_difference::type difference_type; + typedef typename range_size::type size_type; + typedef typename range_reference::type reference; + typedef typename range_reference::type const_reference; public: // construction, assignment + sub_range(); + template< class ForwardTraversalIterator > sub_range( ForwardTraversalIterator Begin, ForwardTraversalIterator End ); @@ -233,6 +239,23 @@ namespace boost template< class ForwardRange2 > sub_range& operator=( const ForwardRange2& r ); + // iterator accessors + const_iterator begin() const; + iterator begin(); + const_iterator end() const; + iterator end(); + + reference front(); + const_reference front() const; + + // If traversal >= bidirectional: + reference back(); + const_reference back(); + + // If traversal >= random-access: + reference operator[](difference_type n); + const_reference operator[](difference_type n) const; + public: // rest of interface inherited from iterator_range }; diff --git a/include/boost/range/sub_range.hpp b/include/boost/range/sub_range.hpp index 69b13a9..e2fc480 100644 --- a/include/boost/range/sub_range.hpp +++ b/include/boost/range/sub_range.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -31,25 +32,135 @@ namespace boost { + namespace range_detail + { - template< class ForwardRange > - class sub_range +template +class sub_range_base : public iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type - > + > +{ + typedef iterator_range< + BOOST_DEDUCED_TYPENAME range_iterator::type + > base; + +protected: + typedef BOOST_DEDUCED_TYPENAME base::iterator_range_ iterator_range_; + +public: + typedef BOOST_DEDUCED_TYPENAME range_value::type value_type; + typedef BOOST_DEDUCED_TYPENAME range_iterator::type iterator; + typedef BOOST_DEDUCED_TYPENAME range_iterator::type const_iterator; + typedef BOOST_DEDUCED_TYPENAME range_difference::type difference_type; + typedef BOOST_DEDUCED_TYPENAME range_size::type size_type; + typedef BOOST_DEDUCED_TYPENAME range_reference::type reference; + typedef BOOST_DEDUCED_TYPENAME range_reference::type const_reference; + + sub_range_base() { - typedef BOOST_DEDUCED_TYPENAME range_iterator::type iterator_t; - typedef iterator_range< iterator_t > base; + } + + template + sub_range_base(Iterator first, Iterator last) + : base(first, last) + { + } + + reference front() + { + return base::front(); + } + + const_reference front() const + { + return base::front(); + } +}; + +template +class sub_range_base + : public sub_range_base +{ + typedef sub_range_base base; +public: + sub_range_base() + { + } + + template + sub_range_base(Iterator first, Iterator last) + : base(first, last) + { + } + + BOOST_DEDUCED_TYPENAME base::reference back() + { + return base::back(); + } + + BOOST_DEDUCED_TYPENAME base::const_reference back() const + { + return base::back(); + } +}; + +template +class sub_range_base + : public sub_range_base +{ + typedef sub_range_base base; + +public: + sub_range_base() + { + } + + template + sub_range_base(Iterator first, Iterator last) + : base(first, last) + { + } + + BOOST_DEDUCED_TYPENAME base::reference + operator[](BOOST_DEDUCED_TYPENAME base::difference_type n) + { + return this->begin()[n]; + } + + BOOST_DEDUCED_TYPENAME base::const_reference + operator[](BOOST_DEDUCED_TYPENAME base::difference_type n) const + { + return this->begin()[n]; + } +}; + + } // namespace range_detail + + template + class sub_range + : public range_detail::sub_range_base< + ForwardRange, + BOOST_DEDUCED_TYPENAME iterator_traversal< + BOOST_DEDUCED_TYPENAME range_iterator::type + >::type + > + { + typedef BOOST_DEDUCED_TYPENAME range_iterator< + ForwardRange + >::type iterator_t; + + typedef range_detail::sub_range_base< + ForwardRange, + BOOST_DEDUCED_TYPENAME iterator_traversal< + BOOST_DEDUCED_TYPENAME range_iterator::type + >::type + > base; typedef BOOST_DEDUCED_TYPENAME base::impl impl; - public: - typedef BOOST_DEDUCED_TYPENAME range_value::type value_type; - typedef BOOST_DEDUCED_TYPENAME range_iterator::type iterator; - typedef BOOST_DEDUCED_TYPENAME range_iterator::type const_iterator; - typedef BOOST_DEDUCED_TYPENAME range_difference::type difference_type; - typedef BOOST_DEDUCED_TYPENAME range_size::type size_type; - typedef BOOST_DEDUCED_TYPENAME base::reference reference; + protected: + typedef BOOST_DEDUCED_TYPENAME base::iterator_range_ iterator_range_; private: template @@ -60,7 +171,7 @@ namespace boost range_iterator, mpl::identity >::type, - iterator + BOOST_DEDUCED_TYPENAME base::iterator > { }; @@ -70,8 +181,9 @@ namespace boost { } #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500) ) - sub_range( const sub_range& r ) - : base( static_cast( r ) ) + sub_range(const sub_range& r) + : base(impl::adl_begin(static_cast(r)), + impl::adl_end(static_cast(r))) { } #endif @@ -81,14 +193,10 @@ namespace boost BOOST_DEDUCED_TYPENAME enable_if< is_compatible_range >::type* = 0 - ) : - -#if BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, <= 800 ) - base( impl::adl_begin( r ), impl::adl_end( r ) ) -#else - base( r ) -#endif - { } + ) + : base(impl::adl_begin(r), impl::adl_end(r)) + { + } template< class ForwardRange2 > sub_range( @@ -96,14 +204,30 @@ namespace boost BOOST_DEDUCED_TYPENAME enable_if< is_compatible_range >::type* = 0 - ) : + ) + : base(impl::adl_begin(r), impl::adl_end(r)) + { + } -#if BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, <= 800 ) - base( impl::adl_begin( r ), impl::adl_end( r ) ) -#else - base( r ) -#endif - { } + BOOST_DEDUCED_TYPENAME base::const_iterator begin() const + { + return base::begin(); + } + + BOOST_DEDUCED_TYPENAME base::iterator begin() + { + return base::begin(); + } + + BOOST_DEDUCED_TYPENAME base::const_iterator end() const + { + return base::end(); + } + + BOOST_DEDUCED_TYPENAME base::iterator end() + { + return base::end(); + } template< class Iter > sub_range( Iter first, Iter last ) : @@ -117,7 +241,7 @@ namespace boost >::type operator=(ForwardRange2& r) { - base::operator=( r ); + iterator_range_::operator=( r ); return *this; } @@ -128,13 +252,13 @@ namespace boost >::type operator=( const ForwardRange2& r ) { - base::operator=( r ); + iterator_range_::operator=( r ); return *this; } sub_range& operator=( const sub_range& r ) { - base::operator=( static_cast(r) ); + iterator_range_::operator=( static_cast(r) ); return *this; } }; diff --git a/test/sub_range.cpp b/test/sub_range.cpp index e0a8330..0ea8fed 100644 --- a/test/sub_range.cpp +++ b/test/sub_range.cpp @@ -18,11 +18,17 @@ #include #include +#include #include #include #include #include +namespace boost_range_test +{ + namespace + { + void check_sub_range() { @@ -136,13 +142,107 @@ void check_sub_range() BOOST_CHECK( rrr == boost::as_literal("HEllo worlD") ); } -#include - -boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) +template +void check_mutable_type(T&) { - boost::unit_test::test_suite* test = BOOST_TEST_SUITE( "Range Test Suite" ); + BOOST_STATIC_ASSERT(!boost::is_const::value); +} - test->add( BOOST_TEST_CASE( &check_sub_range ) ); +template +void check_constant_type(T&) +{ + BOOST_STATIC_ASSERT(boost::is_const::value); +} + +template +void check_is_const_iterator(Iterator it) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + BOOST_DEDUCED_TYPENAME boost::range_iterator< + BOOST_DEDUCED_TYPENAME boost::add_const::type + >::type, + Iterator + >::value)); +} + +template +void check_is_iterator(Iterator it) +{ + BOOST_STATIC_ASSERT(( + boost::is_same< + BOOST_DEDUCED_TYPENAME boost::range_iterator< + BOOST_DEDUCED_TYPENAME boost::remove_const::type + >::type, + Iterator + >::value)); +} + +void const_propagation_mutable_collection(void) +{ + typedef std::vector coll_t; + typedef boost::sub_range sub_range_t; + + coll_t c; + c.push_back(0); + + sub_range_t rng(c); + const sub_range_t crng(c); + + check_is_iterator(rng.begin()); + check_is_iterator(rng.end()); + + check_is_const_iterator(crng.begin()); + check_is_const_iterator(crng.end()); + + check_mutable_type(rng[0]); + check_mutable_type(rng.front()); + check_mutable_type(rng.back()); + check_constant_type(crng[0]); + check_constant_type(crng.front()); + check_constant_type(crng.back()); +} + +void const_propagation_const_collection(void) +{ + typedef std::vector coll_t; + typedef boost::sub_range sub_range_t; + + coll_t c; + c.push_back(0); + + sub_range_t rng(c); + const sub_range_t crng(c); + + check_is_const_iterator(rng.begin()); + check_is_const_iterator(rng.end()); + + check_is_const_iterator(crng.begin()); + check_is_const_iterator(crng.end()); + + check_constant_type(rng[0]); + check_constant_type(rng.front()); + check_constant_type(rng.back()); + check_constant_type(crng[0]); + check_constant_type(crng.front()); + check_constant_type(crng.back()); +} + + } // anonymous namespace +} // namespace boost_range_test + +boost::unit_test::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE( "Boost.Range sub_range test suite" ); + + test->add(BOOST_TEST_CASE(&boost_range_test::check_sub_range)); + + test->add(BOOST_TEST_CASE( + &boost_range_test::const_propagation_const_collection)); + + test->add(BOOST_TEST_CASE( + &boost_range_test::const_propagation_mutable_collection)); return test; } From 4960d8dab2adc93a09760e39a701f419faffd75a Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Tue, 4 Mar 2014 20:29:34 +0000 Subject: [PATCH 4/4] fix lifetime issue with test case for ticket 6715. --- test/ticket_6715_iterator_range_equality.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/ticket_6715_iterator_range_equality.cpp b/test/ticket_6715_iterator_range_equality.cpp index 96a61a9..6c6972d 100644 --- a/test/ticket_6715_iterator_range_equality.cpp +++ b/test/ticket_6715_iterator_range_equality.cpp @@ -30,8 +30,9 @@ namespace boost void test_ticket_6715_iterator_range_equality() { - str_ref a("test"); - str_ref b("test"); + std::string src("test"); + str_ref a(src); + str_ref b(src); BOOST_CHECK(a == b); } }