From 8b60f2c768521226bf9fe0bb6edcd0e2919f2702 Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Sun, 2 Mar 2014 22:50:24 +0000 Subject: [PATCH] iterator_range interop with variant. --- include/boost/range/iterator_range_core.hpp | 28 +++- include/boost/range/sub_range.hpp | 147 ++++++++------------ test/Jamfile.v2 | 1 + test/iterator_range_variant.cpp | 60 ++++++++ 4 files changed, 144 insertions(+), 92 deletions(-) create mode 100644 test/iterator_range_variant.cpp diff --git a/include/boost/range/iterator_range_core.hpp b/include/boost/range/iterator_range_core.hpp index 1e63b7e..59a7b8c 100644 --- a/include/boost/range/iterator_range_core.hpp +++ b/include/boost/range/iterator_range_core.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -380,6 +381,19 @@ public: BOOST_DEDUCED_TYPENAME iterator_traversal::type > base_type; + template + struct is_compatible_range + : is_convertible< + BOOST_DEDUCED_TYPENAME mpl::eval_if< + has_range_iterator, + range_iterator, + mpl::identity + >::type, + BOOST_DEDUCED_TYPENAME base_type::iterator + > + { + }; + protected: typedef iterator_range_detail::iterator_range_impl impl; @@ -397,13 +411,23 @@ public: } template - iterator_range(const SinglePassRange& r) + iterator_range( + const SinglePassRange& r, + BOOST_DEDUCED_TYPENAME enable_if< + is_compatible_range + >::type* = 0 + ) : base_type(impl::adl_begin(r), impl::adl_end(r)) { } template - iterator_range(SinglePassRange& r) + iterator_range( + SinglePassRange& r, + BOOST_DEDUCED_TYPENAME enable_if< + is_compatible_range + >::type* = 0 + ) : base_type(impl::adl_begin(r), impl::adl_end(r)) { } diff --git a/include/boost/range/sub_range.hpp b/include/boost/range/sub_range.hpp index 0b00086..69b13a9 100644 --- a/include/boost/range/sub_range.hpp +++ b/include/boost/range/sub_range.hpp @@ -31,14 +31,18 @@ namespace boost { - + template< class ForwardRange > - class sub_range : public iterator_range< BOOST_DEDUCED_TYPENAME range_iterator::type > + class sub_range + : public iterator_range< + BOOST_DEDUCED_TYPENAME range_iterator::type + > { typedef BOOST_DEDUCED_TYPENAME range_iterator::type iterator_t; typedef iterator_range< iterator_t > 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; @@ -46,17 +50,25 @@ namespace boost 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; - - public: // for return value of front/back - typedef BOOST_DEDUCED_TYPENAME - boost::mpl::if_< boost::is_reference, - const BOOST_DEDUCED_TYPENAME boost::remove_reference::type&, - reference >::type const_reference; + + private: + template + struct is_compatible_range + : is_convertible< + BOOST_DEDUCED_TYPENAME mpl::eval_if< + has_range_iterator, + range_iterator, + mpl::identity + >::type, + iterator + > + { + }; public: - sub_range() : base() + sub_range() { } - + #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500) ) sub_range( const sub_range& r ) : base( static_cast( r ) ) @@ -64,39 +76,57 @@ namespace boost #endif template< class ForwardRange2 > - sub_range( ForwardRange2& 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 > - sub_range( const ForwardRange2& r ) : + sub_range( + ForwardRange2& r, + 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 +#endif + { } + + template< class ForwardRange2 > + sub_range( + const ForwardRange2& r, + 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 { } template< class Iter > sub_range( Iter first, Iter last ) : base( first, last ) { } - - template< class ForwardRange2 > - sub_range& operator=( ForwardRange2& r ) + + template + BOOST_DEDUCED_TYPENAME enable_if< + is_compatible_range, + sub_range& + >::type + operator=(ForwardRange2& r) { base::operator=( r ); return *this; } - template< class ForwardRange2 > - sub_range& operator=( const ForwardRange2& r ) + template + BOOST_DEDUCED_TYPENAME enable_if< + is_compatible_range, + sub_range& + >::type + operator=( const ForwardRange2& r ) { base::operator=( r ); return *this; @@ -107,71 +137,8 @@ namespace boost base::operator=( static_cast(r) ); return *this; } - - public: - - iterator begin() { return base::begin(); } - const_iterator begin() const { return base::begin(); } - iterator end() { return base::end(); } - const_iterator end() const { return base::end(); } - difference_type size() const { return base::size(); } - - - public: // convenience - reference front() - { - return base::front(); - } - - const_reference front() const - { - return base::front(); - } - - reference back() - { - return base::back(); - } - - const_reference back() const - { - return base::back(); - } - - reference operator[]( difference_type sz ) - { - return base::operator[](sz); - } - - const_reference operator[]( difference_type sz ) const - { - return base::operator[](sz); - } - }; - template< class ForwardRange, class ForwardRange2 > - inline bool operator==( const sub_range& l, - const sub_range& r ) - { - return boost::equal( l, r ); - } - - template< class ForwardRange, class ForwardRange2 > - inline bool operator!=( const sub_range& l, - const sub_range& r ) - { - return !boost::equal( l, r ); - } - - template< class ForwardRange, class ForwardRange2 > - inline bool operator<( const sub_range& l, - const sub_range& r ) - { - return iterator_range_detail::less_than( l, r ); - } - - } // namespace 'boost' #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ef3d0cd..3c57250 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -150,6 +150,7 @@ test-suite range : [ range-test istream_range ] [ range-test iterator_pair ] [ range-test iterator_range ] + [ range-test iterator_range_variant ] # [ range-test mfc : $(VC71_ROOT)/atlmfc/include ] [ range-test join ] [ range-test partial_workaround ] diff --git a/test/iterator_range_variant.cpp b/test/iterator_range_variant.cpp new file mode 100644 index 0000000..d55ae85 --- /dev/null +++ b/test/iterator_range_variant.cpp @@ -0,0 +1,60 @@ +// 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 +#include +#include +#include + +namespace +{ + enum E + { + e1, e2, e3 + }; + + void test_variant_report() + { + typedef boost::mpl::vector< + E, + std::string, + boost::iterator_range + >::type args; + + typedef boost::make_variant_over::type variant_t; + + variant_t v; + std::string s; + v = boost::iterator_range(s.begin(), s.end()); + v = e2; + v = std::string(); + + // Rationale: + // This is cast to const char* to guard against ambiguity in the case + // where std::string::iterator it a char* + v = static_cast(""); + } +} + +boost::unit_test::test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE("iterator range and variant interoperability"); + + test->add(BOOST_TEST_CASE(&test_variant_report)); + + return test; +}