fix for recently introduced regression to sub_range const propagation.

This commit is contained in:
Neil Groves
2014-03-04 20:22:57 +00:00
parent e26866d3fa
commit e089e0748f
3 changed files with 286 additions and 39 deletions

View File

@ -213,11 +213,17 @@ namespace boost
class sub_range : public iterator_range< typename range_iterator<ForwardRange>::type > class sub_range : public iterator_range< typename range_iterator<ForwardRange>::type >
{ {
public: public:
typedef typename range_value<ForwardRange>::type value_type;
typedef typename range_iterator<ForwardRange>::type iterator; typedef typename range_iterator<ForwardRange>::type iterator;
typedef typename range_iterator<const ForwardRange>::type const_iterator; typedef typename range_iterator<const ForwardRange>::type const_iterator;
typedef typename iterator_difference<iterator>::type difference_type; typedef typename range_difference<ForwardRange>::type difference_type;
typedef typename range_size<ForwardRange>::type size_type;
typedef typename range_reference<ForwardRange>::type reference;
typedef typename range_reference<const ForwardRange>::type const_reference;
public: // construction, assignment public: // construction, assignment
sub_range();
template< class ForwardTraversalIterator > template< class ForwardTraversalIterator >
sub_range( ForwardTraversalIterator Begin, ForwardTraversalIterator End ); sub_range( ForwardTraversalIterator Begin, ForwardTraversalIterator End );
@ -233,6 +239,23 @@ namespace boost
template< class ForwardRange2 > template< class ForwardRange2 >
sub_range& operator=( const ForwardRange2& r ); 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: public:
// rest of interface inherited from iterator_range // rest of interface inherited from iterator_range
}; };

View File

@ -24,6 +24,7 @@
#include <boost/range/value_type.hpp> #include <boost/range/value_type.hpp>
#include <boost/range/size_type.hpp> #include <boost/range/size_type.hpp>
#include <boost/range/difference_type.hpp> #include <boost/range/difference_type.hpp>
#include <boost/range/reference.hpp>
#include <boost/range/algorithm/equal.hpp> #include <boost/range/algorithm/equal.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/type_traits/is_reference.hpp> #include <boost/type_traits/is_reference.hpp>
@ -31,25 +32,135 @@
namespace boost namespace boost
{ {
namespace range_detail
{
template< class ForwardRange > template<class ForwardRange, class TraversalTag>
class sub_range class sub_range_base
: public iterator_range< : public iterator_range<
BOOST_DEDUCED_TYPENAME range_iterator<ForwardRange>::type BOOST_DEDUCED_TYPENAME range_iterator<ForwardRange>::type
> >
{
typedef iterator_range<
BOOST_DEDUCED_TYPENAME range_iterator<ForwardRange>::type
> base;
protected:
typedef BOOST_DEDUCED_TYPENAME base::iterator_range_ iterator_range_;
public:
typedef BOOST_DEDUCED_TYPENAME range_value<ForwardRange>::type value_type;
typedef BOOST_DEDUCED_TYPENAME range_iterator<ForwardRange>::type iterator;
typedef BOOST_DEDUCED_TYPENAME range_iterator<const ForwardRange>::type const_iterator;
typedef BOOST_DEDUCED_TYPENAME range_difference<ForwardRange>::type difference_type;
typedef BOOST_DEDUCED_TYPENAME range_size<ForwardRange>::type size_type;
typedef BOOST_DEDUCED_TYPENAME range_reference<ForwardRange>::type reference;
typedef BOOST_DEDUCED_TYPENAME range_reference<const ForwardRange>::type const_reference;
sub_range_base()
{ {
typedef BOOST_DEDUCED_TYPENAME range_iterator<ForwardRange>::type iterator_t; }
typedef iterator_range< iterator_t > base;
template<class Iterator>
sub_range_base(Iterator first, Iterator last)
: base(first, last)
{
}
reference front()
{
return base::front();
}
const_reference front() const
{
return base::front();
}
};
template<class ForwardRange>
class sub_range_base<ForwardRange, bidirectional_traversal_tag>
: public sub_range_base<ForwardRange, forward_traversal_tag>
{
typedef sub_range_base<ForwardRange, forward_traversal_tag> base;
public:
sub_range_base()
{
}
template<class Iterator>
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 ForwardRange>
class sub_range_base<ForwardRange, random_access_traversal_tag>
: public sub_range_base<ForwardRange, bidirectional_traversal_tag>
{
typedef sub_range_base<ForwardRange, bidirectional_traversal_tag> base;
public:
sub_range_base()
{
}
template<class Iterator>
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 ForwardRange>
class sub_range
: public range_detail::sub_range_base<
ForwardRange,
BOOST_DEDUCED_TYPENAME iterator_traversal<
BOOST_DEDUCED_TYPENAME range_iterator<ForwardRange>::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<ForwardRange>::type
>::type
> base;
typedef BOOST_DEDUCED_TYPENAME base::impl impl; typedef BOOST_DEDUCED_TYPENAME base::impl impl;
public: protected:
typedef BOOST_DEDUCED_TYPENAME range_value<ForwardRange>::type value_type; typedef BOOST_DEDUCED_TYPENAME base::iterator_range_ iterator_range_;
typedef BOOST_DEDUCED_TYPENAME range_iterator<ForwardRange>::type iterator;
typedef BOOST_DEDUCED_TYPENAME range_iterator<const ForwardRange>::type const_iterator;
typedef BOOST_DEDUCED_TYPENAME range_difference<ForwardRange>::type difference_type;
typedef BOOST_DEDUCED_TYPENAME range_size<ForwardRange>::type size_type;
typedef BOOST_DEDUCED_TYPENAME base::reference reference;
private: private:
template<class Source> template<class Source>
@ -60,7 +171,7 @@ namespace boost
range_iterator<Source>, range_iterator<Source>,
mpl::identity<void> mpl::identity<void>
>::type, >::type,
iterator BOOST_DEDUCED_TYPENAME base::iterator
> >
{ {
}; };
@ -70,8 +181,9 @@ namespace boost
{ } { }
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500) ) #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500) )
sub_range( const sub_range& r ) sub_range(const sub_range& r)
: base( static_cast<const base&>( r ) ) : base(impl::adl_begin(static_cast<const base&>(r)),
impl::adl_end(static_cast<const base&>(r)))
{ } { }
#endif #endif
@ -81,14 +193,10 @@ namespace boost
BOOST_DEDUCED_TYPENAME enable_if< BOOST_DEDUCED_TYPENAME enable_if<
is_compatible_range<ForwardRange2> is_compatible_range<ForwardRange2>
>::type* = 0 >::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
{ }
template< class ForwardRange2 > template< class ForwardRange2 >
sub_range( sub_range(
@ -96,14 +204,30 @@ namespace boost
BOOST_DEDUCED_TYPENAME enable_if< BOOST_DEDUCED_TYPENAME enable_if<
is_compatible_range<const ForwardRange2> is_compatible_range<const ForwardRange2>
>::type* = 0 >::type* = 0
) : )
: base(impl::adl_begin(r), impl::adl_end(r))
{
}
#if BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, <= 800 ) BOOST_DEDUCED_TYPENAME base::const_iterator begin() const
base( impl::adl_begin( r ), impl::adl_end( r ) ) {
#else return base::begin();
base( r ) }
#endif
{ } 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 > template< class Iter >
sub_range( Iter first, Iter last ) : sub_range( Iter first, Iter last ) :
@ -117,7 +241,7 @@ namespace boost
>::type >::type
operator=(ForwardRange2& r) operator=(ForwardRange2& r)
{ {
base::operator=( r ); iterator_range_::operator=( r );
return *this; return *this;
} }
@ -128,13 +252,13 @@ namespace boost
>::type >::type
operator=( const ForwardRange2& r ) operator=( const ForwardRange2& r )
{ {
base::operator=( r ); iterator_range_::operator=( r );
return *this; return *this;
} }
sub_range& operator=( const sub_range& r ) sub_range& operator=( const sub_range& r )
{ {
base::operator=( static_cast<const base&>(r) ); iterator_range_::operator=( static_cast<const iterator_range_&>(r) );
return *this; return *this;
} }
}; };

View File

@ -18,11 +18,17 @@
#include <boost/range/sub_range.hpp> #include <boost/range/sub_range.hpp>
#include <boost/range/as_literal.hpp> #include <boost/range/as_literal.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/test_tools.hpp> #include <boost/test/test_tools.hpp>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <vector> #include <vector>
namespace boost_range_test
{
namespace
{
void check_sub_range() void check_sub_range()
{ {
@ -136,13 +142,107 @@ void check_sub_range()
BOOST_CHECK( rrr == boost::as_literal("HEllo worlD") ); BOOST_CHECK( rrr == boost::as_literal("HEllo worlD") );
} }
#include <boost/test/unit_test.hpp> template<class T>
void check_mutable_type(T&)
boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] )
{ {
boost::unit_test::test_suite* test = BOOST_TEST_SUITE( "Range Test Suite" ); BOOST_STATIC_ASSERT(!boost::is_const<T>::value);
}
test->add( BOOST_TEST_CASE( &check_sub_range ) ); template<class T>
void check_constant_type(T&)
{
BOOST_STATIC_ASSERT(boost::is_const<T>::value);
}
template<class Range, class Iterator>
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<Range>::type
>::type,
Iterator
>::value));
}
template<class Range, class Iterator>
void check_is_iterator(Iterator it)
{
BOOST_STATIC_ASSERT((
boost::is_same<
BOOST_DEDUCED_TYPENAME boost::range_iterator<
BOOST_DEDUCED_TYPENAME boost::remove_const<Range>::type
>::type,
Iterator
>::value));
}
void const_propagation_mutable_collection(void)
{
typedef std::vector<int> coll_t;
typedef boost::sub_range<coll_t> sub_range_t;
coll_t c;
c.push_back(0);
sub_range_t rng(c);
const sub_range_t crng(c);
check_is_iterator<sub_range_t>(rng.begin());
check_is_iterator<sub_range_t>(rng.end());
check_is_const_iterator<sub_range_t>(crng.begin());
check_is_const_iterator<sub_range_t>(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<int> coll_t;
typedef boost::sub_range<const coll_t> 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<sub_range_t>(rng.begin());
check_is_const_iterator<sub_range_t>(rng.end());
check_is_const_iterator<sub_range_t>(crng.begin());
check_is_const_iterator<sub_range_t>(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; return test;
} }