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; }