From 654ae838ee5228eec9006146cd1562c46d90f9d2 Mon Sep 17 00:00:00 2001 From: Neil Groves Date: Mon, 24 Feb 2014 18:26:03 +0000 Subject: [PATCH] refactored iterator_range to better handle SFINAE. --- include/boost/range/iterator_range_core.hpp | 499 ++++++++++++-------- test/adaptor_test/type_erased.cpp | 28 +- 2 files changed, 324 insertions(+), 203 deletions(-) diff --git a/include/boost/range/iterator_range_core.hpp b/include/boost/range/iterator_range_core.hpp index 967a457..1e671fc 100644 --- a/include/boost/range/iterator_range_core.hpp +++ b/include/boost/range/iterator_range_core.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -101,10 +102,251 @@ namespace boost return boost::equal(l, r); } - struct range_tag { }; - struct const_range_tag { }; - - struct iterator_range_tag { }; +struct range_tag +{ +}; + +struct const_range_tag +{ +}; + +struct iterator_range_tag +{ +}; + +template +class iterator_range_base + : public iterator_range_tag +{ + typedef range_detail::safe_bool< + IteratorT iterator_range_base::* + > safe_bool_t; + + typedef iterator_range_base type; + +protected: + typedef iterator_range_impl impl; + +public: + typedef BOOST_DEDUCED_TYPENAME + safe_bool_t::unspecified_bool_type unspecified_bool_type; + + typedef BOOST_DEDUCED_TYPENAME + iterator_value::type value_type; + + typedef BOOST_DEDUCED_TYPENAME + iterator_difference::type difference_type; + + typedef std::size_t size_type; // note: must be unsigned + + // Needed because value-type is the same for + // const and non-const iterators + typedef BOOST_DEDUCED_TYPENAME + iterator_reference::type reference; + + //! const_iterator type + /*! + There is no distinction between const_iterator and iterator. + These typedefs are provides to fulfill container interface + */ + typedef IteratorT const_iterator; + //! iterator type + typedef IteratorT iterator; + +protected: + iterator_range_base() + : m_Begin() + , m_End() + { + } + + template + iterator_range_base(Iterator Begin, Iterator End) + : m_Begin(Begin) + , m_End(End) + { + } + +public: + IteratorT begin() const + { + return m_Begin; + } + + IteratorT end() const + { + return m_End; + } + + bool empty() const + { + return m_Begin == m_End; + } + + operator unspecified_bool_type() const + { + return safe_bool_t::to_unspecified_bool( + m_Begin != m_End, &iterator_range_base::m_Begin); + } + + bool operator!() const + { + return empty(); + } + + bool equal(const iterator_range_base& r) const + { + return m_Begin == r.m_Begin && m_End == r.m_End; + } + + reference front() const + { + BOOST_ASSERT(!empty()); + return *m_Begin; + } + + void pop_front() + { + BOOST_ASSERT(!empty()); + ++m_Begin; + } + +protected: + template + void assign(Iterator first, Iterator last) + { + m_Begin = first; + m_End = last; + } + + template + void assign(const SinglePassRange& r) + { + m_Begin = impl::adl_begin(r); + m_End = impl::adl_end(r); + } + + template + void assign(SinglePassRange& r) + { + m_Begin = impl::adl_begin(r); + m_End = impl::adl_end(r); + } + + IteratorT m_Begin; + IteratorT m_End; +}; + +template +class iterator_range_base + : public iterator_range_base +{ + typedef iterator_range_base base_type; + +protected: + iterator_range_base() + { + } + + template + iterator_range_base(Iterator first, Iterator last) + : iterator_range_base(first, last) + { + } + +public: + BOOST_DEDUCED_TYPENAME base_type::reference back() const + { + BOOST_ASSERT(!this->empty()); + return *boost::prior(this->m_End); + } + + void pop_back() + { + BOOST_ASSERT(!this->empty()); + --this->m_End; + } +}; + +template +class iterator_range_base + : public iterator_range_base +{ + typedef iterator_range_base< + IteratorT, bidirectional_traversal_tag> base_type; + +public: + typedef BOOST_DEDUCED_TYPENAME + boost::mpl::if_< + boost::mpl::or_< + boost::is_abstract< + BOOST_DEDUCED_TYPENAME base_type::value_type + >, + boost::is_array< + BOOST_DEDUCED_TYPENAME base_type::value_type + > + >, + BOOST_DEDUCED_TYPENAME base_type::reference, + BOOST_DEDUCED_TYPENAME base_type::value_type + >::type abstract_value_type; + + // Rationale: + // typedef these here to reduce verbiage in the implementation of this + // type. + typedef BOOST_DEDUCED_TYPENAME base_type::difference_type difference_type; + typedef BOOST_DEDUCED_TYPENAME base_type::size_type size_type; + typedef BOOST_DEDUCED_TYPENAME base_type::reference reference; + +protected: + iterator_range_base() + { + } + + template + iterator_range_base(Iterator first, Iterator last) + : iterator_range_base( + first, last) + { + } + +public: + reference operator[](difference_type at) const + { + BOOST_ASSERT(at >= 0 && at < size()); + return this->m_Begin[at]; + } + + // + // When storing transform iterators, operator[]() + // fails because it returns by reference. Therefore + // operator()() is provided for these cases. + // + abstract_value_type operator()(difference_type at) const + { + BOOST_ASSERT(at >= 0 && at < size()); + 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; + } +}; + } // iterator range template class -----------------------------------------// @@ -128,217 +370,86 @@ namespace boost */ template class iterator_range - : public iterator_range_detail::iterator_range_tag + : public iterator_range_detail::iterator_range_base< + IteratorT, + typename iterator_traversal::type + > { - typedef range_detail::safe_bool< IteratorT iterator_range::* > safe_bool_t; - protected: // Used by sub_range - //! implementation class + typedef iterator_range_detail::iterator_range_base< + IteratorT, + typename iterator_traversal::type + > base_type; + + protected: typedef iterator_range_detail::iterator_range_impl impl; + public: - //! this type typedef iterator_range type; - typedef BOOST_DEDUCED_TYPENAME safe_bool_t::unspecified_bool_type unspecified_bool_type; - //BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(value_type); - //! Encapsulated value type - typedef BOOST_DEDUCED_TYPENAME - iterator_value::type value_type; - - //! Difference type - typedef BOOST_DEDUCED_TYPENAME - iterator_difference::type difference_type; - - //! Size type - typedef std::size_t size_type; // note: must be unsigned - - //! This type - typedef iterator_range this_type; - - //! Reference type - // - // Needed because value-type is the same for - // const and non-const iterators - // - typedef BOOST_DEDUCED_TYPENAME - iterator_reference::type reference; - - //! const_iterator type - /*! - There is no distinction between const_iterator and iterator. - These typedefs are provides to fulfill container interface - */ - typedef IteratorT const_iterator; - //! iterator type - typedef IteratorT iterator; - - private: // for return value of operator()() - typedef BOOST_DEDUCED_TYPENAME - boost::mpl::if_< boost::mpl::or_< boost::is_abstract< value_type >, - boost::is_array< value_type > >, - reference, value_type >::type abstract_value_type; - - public: - iterator_range() : m_Begin( iterator() ), m_End( iterator() ) - { } - - //! Constructor from a pair of iterators - template< class Iterator > - iterator_range( Iterator Begin, Iterator End ) : - m_Begin(Begin), m_End(End) - {} - - //! Constructor from a Range - template< class Range > - iterator_range( const Range& r ) : - m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) - {} - - //! Constructor from a Range - template< class Range > - iterator_range( Range& r ) : - m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) - {} - - //! Constructor from a Range - template< class Range > - iterator_range( const Range& r, iterator_range_detail::const_range_tag ) : - m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) - {} - - //! Constructor from a Range - template< class Range > - iterator_range( Range& r, iterator_range_detail::range_tag ) : - m_Begin( impl::adl_begin( r ) ), m_End( impl::adl_end( r ) ) - {} - - this_type& operator=( const this_type& r ) + iterator_range() { - m_Begin = r.begin(); - m_End = r.end(); + } + + template + iterator_range(Iterator first, Iterator last) + : base_type(first, last) + { + } + + template + iterator_range(const SinglePassRange& r) + : base_type(impl::adl_begin(r), impl::adl_end(r)) + { + } + + template + iterator_range(SinglePassRange& r) + : base_type(impl::adl_begin(r), impl::adl_end(r)) + { + } + + template + iterator_range(const SinglePassRange& r, + iterator_range_detail::const_range_tag) + : base_type(impl::adl_begin(r), impl::adl_end(r)) + { + } + + template + iterator_range(SinglePassRange& r, + iterator_range_detail::range_tag) + : base_type(impl::adl_begin(r), impl::adl_end(r)) + { + } + + template + iterator_range& operator=(const iterator_range& other) + { + this->assign(other.begin(), other.end()); return *this; } - template< class Iterator > - iterator_range& operator=( const iterator_range& r ) + template + iterator_range& operator=(iterator_range& other) { - m_Begin = r.begin(); - m_End = r.end(); + this->assign(other.begin(), other.end()); return *this; } - template< class ForwardRange > - iterator_range& operator=( ForwardRange& r ) + template + iterator_range& operator=(SinglePassRange& r) { - m_Begin = impl::adl_begin( r ); - m_End = impl::adl_end( r ); + this->assign(r); return *this; } - template< class ForwardRange > - iterator_range& operator=( const ForwardRange& r ) + template + iterator_range& operator=(const SinglePassRange& r) { - m_Begin = impl::adl_begin( r ); - m_End = impl::adl_end( r ); + this->assign(r); return *this; } - IteratorT begin() const - { - return m_Begin; - } - - IteratorT end() const - { - return m_End; - } - - difference_type size() const - { - return m_End - m_Begin; - } - - bool empty() const - { - return m_Begin == m_End; - } - - operator unspecified_bool_type() const - { - return safe_bool_t::to_unspecified_bool(m_Begin != m_End, &iterator_range::m_Begin); - } - - bool operator!() const - { - return empty(); - } - - bool equal(const iterator_range& r) const - { - return m_Begin == r.m_Begin && m_End == r.m_End; - } - - public: // convenience - reference front() const - { - BOOST_ASSERT( !empty() ); - return *m_Begin; - } - - reference back() const - { - BOOST_ASSERT( !empty() ); - IteratorT last( m_End ); - return *--last; - } - - // pop_front() - added to model the SinglePassRangePrimitiveConcept - void pop_front() - { - BOOST_ASSERT( !empty() ); - ++m_Begin; - } - - // pop_back() - added to model the BidirectionalRangePrimitiveConcept - void pop_back() - { - BOOST_ASSERT( !empty() ); - --m_End; - } - - reference operator[]( difference_type at ) const - { - BOOST_ASSERT( at >= 0 && at < size() ); - return m_Begin[at]; - } - - // - // When storing transform iterators, operator[]() - // fails because it returns by reference. Therefore - // operator()() is provided for these cases. - // - abstract_value_type operator()( difference_type at ) const - { - BOOST_ASSERT( at >= 0 && at < size() ); - return m_Begin[at]; - } - - iterator_range& advance_begin( difference_type n ) - { - std::advance( m_Begin, n ); - return *this; - } - - iterator_range& advance_end( difference_type n ) - { - std::advance( m_End, n ); - return *this; - } - - private: - // begin and end iterators - IteratorT m_Begin; - IteratorT m_End; - protected: // // Allow subclasses an easy way to access the diff --git a/test/adaptor_test/type_erased.cpp b/test/adaptor_test/type_erased.cpp index 60e6e39..a3693dc 100644 --- a/test/adaptor_test/type_erased.cpp +++ b/test/adaptor_test/type_erased.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -167,8 +168,6 @@ namespace boost_range_adaptor_type_erased_test { using namespace boost::adaptors; - typedef Buffer buffer_type; - typedef typename boost::range_value::type value_type; typedef typename boost::any_range_type_generator< @@ -451,13 +450,24 @@ namespace boost_range_adaptor_type_erased_test for (int i = 0; i < 10; ++i) c.push_back(i); - typedef boost::any_range< - int - , boost::random_access_traversal_tag - , int - , boost::range_difference< std::vector >::type - , boost::use_default - > any_range_type; + typedef boost::any_range_type_generator< + std::vector >::type any_range_type; + + BOOST_STATIC_ASSERT( + boost::is_same< + int, + boost::range_value::type + >::value + ); + + BOOST_STATIC_ASSERT( + boost::is_same< + boost::random_access_traversal_tag, + boost::iterator_traversal< + boost::range_iterator::type + >::type + >::value + ); any_range_type rng = c | type_erased_t();