diff --git a/doc/mfc_atl.qbk b/doc/mfc_atl.qbk index de2e225..0056283 100644 --- a/doc/mfc_atl.qbk +++ b/doc/mfc_atl.qbk @@ -74,6 +74,10 @@ If the `` is included before or after Boost.Range headers, ] Other Boost.Range metafunctions are defined by the following. Let `Range` be any type listed above and `Ref` be the same as `range_reference::type`. `range_value::type` is the same as `remove_reference::type>::type`, `range_difference::type` is the same as `std::ptrdiff_t`, and `range_pointer::type` is the same as `add_pointer::type>::type`. As for `const Range`, see below. + +Adam Walling has provided the header `` to add support +for the map adaptor with MFC map types. + [endsect] [section:atl_ranges ATL Ranges] diff --git a/doc/reference/adaptors.qbk b/doc/reference/adaptors.qbk index 96f2ca3..b3efaee 100644 --- a/doc/reference/adaptors.qbk +++ b/doc/reference/adaptors.qbk @@ -69,7 +69,7 @@ What should we do if we only want to copy an element `a` if it satisfies some pr * `boost::copy_if( rng, pred, out )` * `boost::count_if( rng, pred )` -These algorithms are only defined to maintain a one to one relationship with the standard library algorithms. This approach of adding algorithm suffers a combinatorial explosion. Inevitably many algorithms are missing `_if` variants and there is redundant development overhead for each new algorithm. The Adaptor Generator is the design solution to this problem. +These algorithms are only defined to maintain a one to one relationship with the standard library algorithms. This approach of adding algorithm suffers a combinatorial explosion. Inevitably many algorithms are missing `_if` variants and there is redundant development overhead for each new algorithm. The Adaptor Generator is the design solution to this problem. It is conceivable that some algorithms are capable of optimization by tightly coupling the filter with the algorithm. The adaptors provide a more general solution with superior separation of orthogonal concerns. [heading Range Adaptor alternative to copy_if algorithm] `` @@ -86,10 +86,10 @@ boost::count_if( rng, pred ); `` can be expressed as `` -boost::count( rng | boost::adaptors::filtered(pred), out ); +boost::size( rng | boost::adaptors::filtered(pred) ); `` -What this means is that ['*no*] algorithm with the `_if` suffix is needed. Furthermore, it turns out that algorithms with the `_copy` suffix are not needed either. Consider the somewhat misdesigned `replace_copy_if()` which may be used as +What this means is that many algorithms no longer require nor benefit from an optimized implementation with an `_if` suffix. Furthermore, it turns out that algorithms with the `_copy` suffix are often not needed either. Consider `replace_copy_if()` which may be used as `` std::vector vec; @@ -116,7 +116,7 @@ boost::push_back(vec, rng | boost::adaptors::replaced_if(pred, new_value) In this manner, the ['*composition*] of Range Adaptors has the following consequences: -1. we no longer need `_if`, `_copy`, `_copy_if` and `_n` variants of algorithms. +1. we no longer need many of the `_if`, `_copy`, `_copy_if` and `_n` variants of algorithms. 2. we can generate a multitude of new algorithms on the fly, for example, above we generated `reverse_replace_copy_if()` diff --git a/doc/reference/adaptors/adjacent_filtered.qbk b/doc/reference/adaptors/adjacent_filtered.qbk index f8b4289..312646c 100644 --- a/doc/reference/adaptors/adjacent_filtered.qbk +++ b/doc/reference/adaptors/adjacent_filtered.qbk @@ -14,8 +14,8 @@ * [*Precondition:] The `value_type` of the range is convertible to both argument types of `bi_pred`. * [*Postcondition:] For all adjacent elements `[x,y]` in the returned range, `bi_pred(x,y)` is `true`. * [*Throws:] Whatever the copy constructor of `bi_pred` might throw. -* [*Range Category:] __single_pass_range__ -* [*Return Type:] `boost::adjacent_filtered_range` +* [*Range Category:] __forward_range__ +* [*Return Type:] `boost::adjacent_filtered_range` * [*Returned Range Category:] The minimum of the range category of `rng` and __forward_range__ [section:adjacent_filtered_example adjacent_filtered example] diff --git a/doc/reference/algorithm/partition.qbk b/doc/reference/algorithm/partition.qbk index 8ae28e5..a97a893 100644 --- a/doc/reference/algorithm/partition.qbk +++ b/doc/reference/algorithm/partition.qbk @@ -50,7 +50,7 @@ Defined in the header file `boost/range/algorithm/partition.hpp` [heading Requirements] -* `ForwardRange` is a model of the __forward_range__ Concept. +* `ForwardRange` is a model of the __forward_range__ Concept. For C++ versions prior to C++11 the underlying std::partition requires Bidirectional Iterators, hence the requirement for older library versions is for a __bidirectional_range__. * `UnaryPredicate` is a model of the `PredicateConcept`. * `ForwardRange`'s value type is convertible to `UnaryPredicate`'s argument type. diff --git a/doc/reference/synopsis.qbk b/doc/reference/synopsis.qbk index 76719df..bfef5c1 100644 --- a/doc/reference/synopsis.qbk +++ b/doc/reference/synopsis.qbk @@ -73,6 +73,10 @@ namespace boost typename range_difference::type distance( const T& r ); + template< class T > + typename range_size::type + size( const T& r ); + // // Bidirectional Range functions // @@ -93,14 +97,6 @@ namespace boost typename range_reverse_iterator::type rend( const T& r ); - // - // Random Access Range functions - // - - template< class T > - typename range_difference::type - size( const T& r ); - // // Special const Range functions // diff --git a/doc/upgrade.qbk b/doc/upgrade.qbk index 482a825..ef66325 100644 --- a/doc/upgrade.qbk +++ b/doc/upgrade.qbk @@ -5,6 +5,17 @@ /] [section:upgrade Upgrade version of Boost.Range] +[section:upgrade_from_1_55 Upgrade from version 1.55] +# __iterator_range__ is now implemented by implementing the member functions +`size()`, `operator[]` via inheritance of base-classes specialized by the +traversal type of the underlying iterator. This is normally requires no +alteration of code. It does mean that types that derive from iterator_range may +need to prefix `this->` to the various member functions. Additionally it has +been noted that some calling code was relying on member functions such as +`size()` being present despite the underlying iterators not being random-access +due to `iterator_reference::type` not being a reference. The suggested +refactoring is to use `boost::size(rng)`. + [section:upgrade_from_1_49 Upgrade from version 1.49] # __size__ now returns the type Rng::size_type if the range has size_type; diff --git a/include/boost/range/adaptor/adjacent_filtered.hpp b/include/boost/range/adaptor/adjacent_filtered.hpp index f717cb3..159d8ee 100644 --- a/include/boost/range/adaptor/adjacent_filtered.hpp +++ b/include/boost/range/adaptor/adjacent_filtered.hpp @@ -62,54 +62,44 @@ namespace boost , pred_t(pred) , m_last(last) { - move_to_next_valid(); } template skip_iterator( const skip_iterator& other ) : base_t(other.base()) , pred_t(other) - , m_last(other.m_last) {} - - void move_to_next_valid() + , m_last(other.m_last) { - iter_t& it = this->base_reference(); - pred_t& bi_pred = *this; - if (it != m_last) - { - if (default_pass) - { - iter_t nxt = ::boost::next(it); - while (nxt != m_last && !bi_pred(*it, *nxt)) - { - ++it; - ++nxt; - } - } - else - { - iter_t nxt = ::boost::next(it); - for(; nxt != m_last; ++it, ++nxt) - { - if (bi_pred(*it, *nxt)) - { - break; - } - } - if (nxt == m_last) - { - it = m_last; - } - } - } } void increment() { iter_t& it = this->base_reference(); BOOST_ASSERT( it != m_last ); + pred_t& bi_pred = *this; + iter_t prev = it; ++it; - move_to_next_valid(); + if (it != m_last) + { + if (default_pass) + { + while (it != m_last && !bi_pred(*prev, *it)) + { + ++it; + ++prev; + } + } + else + { + for (; it != m_last; ++it, ++prev) + { + if (bi_pred(*prev, *it)) + { + break; + } + } + } + } } iter_t m_last; diff --git a/include/boost/range/adaptor/sliced.hpp b/include/boost/range/adaptor/sliced.hpp index 14ad986..b88597d 100755 --- a/include/boost/range/adaptor/sliced.hpp +++ b/include/boost/range/adaptor/sliced.hpp @@ -34,7 +34,8 @@ namespace boost public: template sliced_range(Rng& rng, T t, U u) - : base_t(boost::make_iterator_range(rng, t, u - boost::size(rng))) + : base_t(boost::next(boost::begin(rng), t), + boost::next(boost::begin(rng), u)) { } }; diff --git a/include/boost/range/adaptor/strided.hpp b/include/boost/range/adaptor/strided.hpp index e843f62..c5fea86 100644 --- a/include/boost/range/adaptor/strided.hpp +++ b/include/boost/range/adaptor/strided.hpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include namespace boost @@ -23,59 +23,102 @@ namespace boost // strided_iterator for wrapping a forward traversal iterator template class strided_iterator - : public iterator_adaptor< + : public iterator_facade< strided_iterator - , BaseIterator - , use_default - , boost::forward_traversal_tag + , typename iterator_value::type + , forward_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type > { friend class ::boost::iterator_core_access; - typedef iterator_adaptor< - strided_iterator - , BaseIterator - , use_default - , boost::forward_traversal_tag - > super_t; + typedef iterator_facade< + strided_iterator + , typename iterator_value::type + , forward_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type + > super_t; public: - typedef BOOST_DEDUCED_TYPENAME std::iterator_traits::difference_type difference_type; + typedef typename super_t::difference_type difference_type; + typedef typename super_t::reference reference; typedef BaseIterator base_iterator; + typedef std::forward_iterator_tag iterator_category; strided_iterator() - : m_last() + : m_it() + , m_last() , m_stride() { } - strided_iterator(base_iterator first, base_iterator it, base_iterator last, difference_type stride) - : super_t(it) + strided_iterator(base_iterator it, + base_iterator last, + difference_type stride) + : m_it(it) , m_last(last) , m_stride(stride) { } template - strided_iterator(const strided_iterator& other, - BOOST_DEDUCED_TYPENAME enable_if_convertible::type* = 0) - : super_t(other) + strided_iterator( + const strided_iterator& other, + typename enable_if_convertible< + OtherIterator, + base_iterator + >::type* = 0 + ) + : m_it(other.base()) , m_last(other.base_end()) , m_stride(other.get_stride()) { } - base_iterator base_end() const { return m_last; } - difference_type get_stride() const { return m_stride; } + base_iterator base() const + { + return m_it; + } + + base_iterator base_end() const + { + return m_last; + } + + difference_type get_stride() const + { + return m_stride; + } private: void increment() { - base_iterator& it = this->base_reference(); - for (difference_type i = 0; (it != m_last) && (i < m_stride); ++i) - ++it; + for (difference_type i = 0; + (m_it != m_last) && (i < m_stride); ++i) + { + ++m_it; + } } + reference dereference() const + { + return *m_it; + } + + template + bool equal( + const strided_iterator& other, + typename enable_if_convertible< + OtherIterator, + base_iterator + >::type* = 0) const + { + return m_it == other.m_it; + } + + base_iterator m_it; base_iterator m_last; difference_type m_stride; }; @@ -83,214 +126,514 @@ namespace boost // strided_iterator for wrapping a bidirectional iterator template class strided_iterator - : public iterator_adaptor< + : public iterator_facade< strided_iterator - , BaseIterator - , use_default - , bidirectional_traversal_tag + , typename iterator_value::type + , bidirectional_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type > { friend class ::boost::iterator_core_access; - typedef iterator_adaptor< - strided_iterator - , BaseIterator - , use_default - , bidirectional_traversal_tag - > super_t; + typedef iterator_facade< + strided_iterator + , typename iterator_value::type + , bidirectional_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type + > super_t; public: - typedef BOOST_DEDUCED_TYPENAME std::iterator_traits::difference_type difference_type; + typedef typename super_t::difference_type difference_type; + typedef typename super_t::reference reference; typedef BaseIterator base_iterator; + typedef typename boost::make_unsigned::type + size_type; + typedef std::bidirectional_iterator_tag iterator_category; strided_iterator() - : m_first() - , m_last() + : m_it() + , m_offset() + , m_index() , m_stride() { } - strided_iterator(base_iterator first, base_iterator it, base_iterator last, difference_type stride) - : super_t(it) - , m_first(first) - , m_last(last) + strided_iterator(base_iterator it, + size_type index, + difference_type stride) + : m_it(it) + , m_offset() + , m_index(index) , m_stride(stride) { + if (stride && ((m_index % stride) != 0)) + m_index += (stride - (m_index % stride)); } template - strided_iterator(const strided_iterator& other, - BOOST_DEDUCED_TYPENAME enable_if_convertible::type* = 0) - : super_t(other.base()) - , m_first(other.base_begin()) - , m_last(other.base_end()) + strided_iterator( + const strided_iterator< + OtherIterator, + bidirectional_traversal_tag + >& other, + typename enable_if_convertible< + OtherIterator, + base_iterator + >::type* = 0 + ) + : m_it(other.base()) + , m_offset(other.get_offset()) + , m_index(other.get_index()) , m_stride(other.get_stride()) { } - base_iterator base_begin() const { return m_first; } - base_iterator base_end() const { return m_last; } - difference_type get_stride() const { return m_stride; } + base_iterator base() const + { + return m_it; + } + + difference_type get_offset() const + { + return m_offset; + } + + size_type get_index() const + { + return m_index; + } + + difference_type get_stride() const + { + return m_stride; + } private: void increment() { - base_iterator& it = this->base_reference(); - for (difference_type i = 0; (it != m_last) && (i < m_stride); ++i) - ++it; + m_offset += m_stride; } void decrement() { - base_iterator& it = this->base_reference(); - for (difference_type i = 0; (it != m_first) && (i < m_stride); ++i) - --it; + m_offset -= m_stride; } - base_iterator m_first; - base_iterator m_last; + reference dereference() const + { + update(); + return *m_it; + } + + void update() const + { + std::advance(m_it, m_offset); + m_index += m_offset; + m_offset = 0; + } + + template + bool equal( + const strided_iterator< + OtherIterator, + bidirectional_traversal_tag + >& other, + typename enable_if_convertible< + OtherIterator, + base_iterator + >::type* = 0) const + { + return (m_index + m_offset) == + (other.get_index() + other.get_offset()); + } + + mutable base_iterator m_it; + mutable difference_type m_offset; + mutable size_type m_index; difference_type m_stride; }; // strided_iterator implementation for wrapping a random access iterator template class strided_iterator - : public iterator_adaptor< - strided_iterator - , BaseIterator - , use_default - , random_access_traversal_tag - > + : public iterator_facade< + strided_iterator + , typename iterator_value::type + , random_access_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type + > { friend class ::boost::iterator_core_access; - typedef iterator_adaptor< - strided_iterator - , BaseIterator - , use_default - , random_access_traversal_tag - > super_t; + typedef iterator_facade< + strided_iterator + , typename iterator_value::type + , random_access_traversal_tag + , typename iterator_reference::type + , typename iterator_difference::type + > super_t; public: - typedef BOOST_DEDUCED_TYPENAME super_t::difference_type difference_type; + typedef typename super_t::difference_type difference_type; + typedef typename super_t::reference reference; typedef BaseIterator base_iterator; + typedef std::random_access_iterator_tag iterator_category; strided_iterator() - : m_first() - , m_last() + : m_it() + , m_first() , m_index(0) , m_stride() { } - strided_iterator(BaseIterator first, BaseIterator it, BaseIterator last, difference_type stride) - : super_t(it) + strided_iterator( + base_iterator first, + base_iterator it, + difference_type stride + ) + : m_it(it) , m_first(first) - , m_last(last) - , m_index(stride ? (it - first) / stride : 0) + , m_index(stride ? (it - first) : difference_type()) , m_stride(stride) { + if (stride && ((m_index % stride) != 0)) + m_index += (stride - (m_index % stride)); } template - strided_iterator(const strided_iterator& other, - BOOST_DEDUCED_TYPENAME enable_if_convertible::type* = 0) - : super_t(other.base()) + strided_iterator( + const strided_iterator< + OtherIterator, + random_access_traversal_tag + >& other, + typename enable_if_convertible< + OtherIterator, + base_iterator + >::type* = 0 + ) + : m_it(other.base()) , m_first(other.base_begin()) - , m_last(other.base_end()) , m_index(other.get_index()) , m_stride(other.get_stride()) { } - base_iterator base_begin() const { return m_first; } - base_iterator base_end() const { return m_last; } - difference_type get_stride() const { return m_stride; } - difference_type get_index() const { return m_index; } + base_iterator base_begin() const + { + return m_first; + } + + base_iterator base() const + { + return m_it; + } + + difference_type get_stride() const + { + return m_stride; + } + + difference_type get_index() const + { + return m_index; + } private: void increment() { m_index += m_stride; - if (m_index < (m_last - m_first)) - this->base_reference() = m_first + m_index; - else - this->base_reference() = m_last; } void decrement() { m_index -= m_stride; - if (m_index >= 0) - this->base_reference() = m_first + m_index; - else - this->base_reference() = m_first; } void advance(difference_type offset) { - offset *= m_stride; - m_index += offset; - if (m_index < 0) - this->base_reference() = m_first; - else if (m_index > (m_last - m_first)) - this->base_reference() = m_last; - else - this->base_reference() = m_first + m_index; + m_index += (m_stride * offset); + } + + // Implementation detail: only update the actual underlying iterator + // at the point of dereference. This is done so that the increment + // and decrement can overshoot the valid sequence as is required + // by striding. Since we can do all comparisons just with the index + // simply, and all dereferences must be within the valid range. + void update() const + { + m_it = m_first + m_index; } template - difference_type distance_to(const strided_iterator& other, - BOOST_DEDUCED_TYPENAME enable_if_convertible::type* = 0) const + difference_type distance_to( + const strided_iterator< + OtherIterator, + random_access_traversal_tag + >& other, + typename enable_if_convertible< + OtherIterator, base_iterator>::type* = 0) const { - if (other.base() >= this->base()) - return (other.base() - this->base() + (m_stride - 1)) / m_stride; - return (other.base() - this->base() - (m_stride - 1)) / m_stride; + BOOST_ASSERT((other.m_index - m_index) % m_stride == difference_type()); + return (other.m_index - m_index) / m_stride; } - bool equal(const strided_iterator& other) const + template + bool equal( + const strided_iterator< + OtherIterator, + random_access_traversal_tag + >& other, + typename enable_if_convertible< + OtherIterator, base_iterator>::type* = 0) const { - return this->base() == other.base(); + return m_index == other.m_index; + } + + reference dereference() const + { + update(); + return *m_it; } private: + mutable base_iterator m_it; base_iterator m_first; - base_iterator m_last; difference_type m_index; difference_type m_stride; }; - template inline - strided_iterator::type> - make_strided_iterator(BaseIterator first, BaseIterator it, - BaseIterator last, Difference stride) + template inline + strided_iterator< + typename range_iterator::type, + forward_traversal_tag + > + make_begin_strided_iterator( + Rng& rng, + Difference stride, + forward_traversal_tag) { - BOOST_ASSERT( stride >= 0 ); - typedef BOOST_DEDUCED_TYPENAME iterator_traversal::type traversal_tag; - return strided_iterator(first, it, last, stride); + return strided_iterator< + typename range_iterator::type, + forward_traversal_tag + >(boost::begin(rng), boost::end(rng), stride); } - template< class Rng - , class Category = BOOST_DEDUCED_TYPENAME iterator_traversal< - BOOST_DEDUCED_TYPENAME range_iterator::type - >::type - > + template inline + strided_iterator< + typename range_iterator::type, + forward_traversal_tag + > + make_begin_strided_iterator( + const Rng& rng, + Difference stride, + forward_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + forward_traversal_tag + >(boost::begin(rng), boost::end(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + forward_traversal_tag + > + make_end_strided_iterator( + Rng& rng, + Difference stride, + forward_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + forward_traversal_tag + >(boost::end(rng), boost::end(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + forward_traversal_tag + > + make_end_strided_iterator( + const Rng& rng, + Difference stride, + forward_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + forward_traversal_tag + >(boost::end(rng), boost::end(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + > + make_begin_strided_iterator( + Rng& rng, + Difference stride, + bidirectional_traversal_tag) + { + typedef typename range_difference::type difference_type; + + return strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + >(boost::begin(rng), difference_type(), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + > + make_begin_strided_iterator( + const Rng& rng, + Difference stride, + bidirectional_traversal_tag) + { + typedef typename range_difference::type difference_type; + + return strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + >(boost::begin(rng), difference_type(), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + > + make_end_strided_iterator( + Rng& rng, + Difference stride, + bidirectional_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + >(boost::end(rng), boost::size(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + > + make_end_strided_iterator( + const Rng& rng, + Difference stride, + bidirectional_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + bidirectional_traversal_tag + >(boost::end(rng), boost::size(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + > + make_begin_strided_iterator( + Rng& rng, + Difference stride, + random_access_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + >(boost::begin(rng), boost::begin(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + > + make_begin_strided_iterator( + const Rng& rng, + Difference stride, + random_access_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + >(boost::begin(rng), boost::begin(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + > + make_end_strided_iterator( + Rng& rng, + Difference stride, + random_access_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + >(boost::begin(rng), boost::end(rng), stride); + } + + template inline + strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + > + make_end_strided_iterator( + const Rng& rng, + Difference stride, + random_access_traversal_tag) + { + return strided_iterator< + typename range_iterator::type, + random_access_traversal_tag + >(boost::begin(rng), boost::end(rng), stride); + } + + template< + class Rng, + class Category = + typename iterator_traversal< + typename range_iterator::type + >::type + > class strided_range : public iterator_range< - range_detail::strided_iterator< - BOOST_DEDUCED_TYPENAME range_iterator::type, - Category - > - > + range_detail::strided_iterator< + typename range_iterator::type, + Category + > + > { typedef range_detail::strided_iterator< - BOOST_DEDUCED_TYPENAME range_iterator::type, - Category - > iter_type; + typename range_iterator::type, + Category + > iter_type; typedef iterator_range super_t; public: template strided_range(Difference stride, Rng& rng) - : super_t(make_strided_iterator(boost::begin(rng), boost::begin(rng), boost::end(rng), stride), - make_strided_iterator(boost::begin(rng), boost::end(rng), boost::end(rng), stride)) + : super_t( + range_detail::make_begin_strided_iterator( + rng, stride, + typename iterator_traversal< + typename range_iterator::type + >::type()), + range_detail::make_end_strided_iterator( + rng, stride, + typename iterator_traversal< + typename range_iterator::type + >::type())) { BOOST_ASSERT( stride >= 0 ); } @@ -300,7 +643,10 @@ namespace boost class strided_holder : public holder { public: - explicit strided_holder(Difference value) : holder(value) {} + explicit strided_holder(Difference value) + : holder(value) + { + } }; template @@ -327,7 +673,8 @@ namespace boost namespace { const range_detail::forwarder - strided = range_detail::forwarder(); + strided = range_detail::forwarder< + range_detail::strided_holder>(); } template diff --git a/include/boost/range/algorithm/equal.hpp b/include/boost/range/algorithm/equal.hpp index 4472bb1..2b44f3b 100644 --- a/include/boost/range/algorithm/equal.hpp +++ b/include/boost/range/algorithm/equal.hpp @@ -31,7 +31,7 @@ namespace boost IteratorCategoryTag1, IteratorCategoryTag2 ) { - while (true) + for (;;) { // If we have reached the end of the left range then this is // the end of the loop. They are equal if and only if we have @@ -71,7 +71,7 @@ namespace boost IteratorCategoryTag1, IteratorCategoryTag2 ) { - while (true) + for (;;) { // If we have reached the end of the left range then this is // the end of the loop. They are equal if and only if we have @@ -120,7 +120,9 @@ namespace boost RandomAccessTraversalReadableIterator1 last1, RandomAccessTraversalReadableIterator2 first2, RandomAccessTraversalReadableIterator2 last2, - BinaryPredicate pred ) + BinaryPredicate pred, + std::random_access_iterator_tag, + std::random_access_iterator_tag ) { return ((last1 - first1) == (last2 - first2)) && std::equal(first1, last1, first2, pred); diff --git a/include/boost/range/algorithm_ext/push_back.hpp b/include/boost/range/algorithm_ext/push_back.hpp index 51a7a7b..6fb9b9b 100755 --- a/include/boost/range/algorithm_ext/push_back.hpp +++ b/include/boost/range/algorithm_ext/push_back.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace boost @@ -27,8 +28,8 @@ inline Container& push_back( Container& on, const Range& from ) { BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - BOOST_ASSERT( (void*)&on != (void*)&from && - "cannot copy from a container to itself" ); + BOOST_ASSERT_MSG(!range_detail::is_same_object(on, from), + "cannot copy from a container to itself"); on.insert( on.end(), boost::begin(from), boost::end(from) ); return on; } diff --git a/include/boost/range/algorithm_ext/push_front.hpp b/include/boost/range/algorithm_ext/push_front.hpp index 470d793..e893098 100755 --- a/include/boost/range/algorithm_ext/push_front.hpp +++ b/include/boost/range/algorithm_ext/push_front.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace boost @@ -27,8 +28,8 @@ inline Container& push_front( Container& on, const Range& from ) { BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - BOOST_ASSERT( (void*)&on != (void*)&from && - "cannot copy from a container to itself" ); + BOOST_ASSERT_MSG(!range_detail::is_same_object(on, from), + "cannot copy from a container to itself"); on.insert( on.begin(), boost::begin(from), boost::end(from) ); return on; } diff --git a/include/boost/range/counting_range.hpp b/include/boost/range/counting_range.hpp index b8e4e3a..d886a21 100644 --- a/include/boost/range/counting_range.hpp +++ b/include/boost/range/counting_range.hpp @@ -17,11 +17,11 @@ #include #include +#include #include namespace boost { - template inline iterator_range > counting_range(Value first, Value last) @@ -33,29 +33,39 @@ namespace boost } template - inline iterator_range::type> > + inline iterator_range< + counting_iterator< + BOOST_DEDUCED_TYPENAME range_iterator::type + > + > counting_range(const Range& rng) { - typedef counting_iterator::type> counting_iterator_t; + typedef counting_iterator< + BOOST_DEDUCED_TYPENAME range_iterator::type + > counting_iterator_t; + typedef iterator_range result_t; - return boost::empty(rng) - ? result_t() - : result_t( - counting_iterator_t(*boost::begin(rng)), - counting_iterator_t(*boost::prior(boost::end(rng)))); + + return result_t(counting_iterator_t(boost::begin(rng)), + counting_iterator_t(boost::end(rng))); } template - inline iterator_range::type> > + inline iterator_range< + counting_iterator< + BOOST_DEDUCED_TYPENAME range_iterator::type + > + > counting_range(Range& rng) { - typedef counting_iterator::type> counting_iterator_t; + typedef counting_iterator< + BOOST_DEDUCED_TYPENAME range_iterator::type + > counting_iterator_t; + typedef iterator_range result_t; - return boost::empty(rng) - ? result_t() - : result_t( - counting_iterator_t(*boost::begin(rng)), - counting_iterator_t(*boost::prior(boost::end(rng)))); + + return result_t(counting_iterator_t(boost::begin(rng)), + counting_iterator_t(boost::end(rng))); } } // namespace boost diff --git a/include/boost/range/detail/any_iterator_interface.hpp b/include/boost/range/detail/any_iterator_interface.hpp index 2451491..cd56714 100644 --- a/include/boost/range/detail/any_iterator_interface.hpp +++ b/include/boost/range/detail/any_iterator_interface.hpp @@ -27,25 +27,40 @@ namespace boost { typedef typename mpl::if_< typename is_reference::type, - typename add_reference< - typename add_const< - typename remove_reference::type - >::type - >::type, + typename add_const< + typename remove_reference::type + >::type&, T >::type type; }; + template + struct mutable_reference_type_generator + { + typedef typename mpl::if_< + typename mpl::and_< + typename is_const::type, + typename mpl::not_::type>::type + >::type, + T, + typename add_reference::type + >::type type; + }; + template< class Reference , class Buffer > struct any_incrementable_iterator_interface { - typedef Reference reference; + typedef typename mutable_reference_type_generator< + Reference + >::type reference; + typedef typename const_reference_type_generator< Reference >::type const_reference; + typedef typename remove_const< typename remove_reference::type >::type reference_as_value_type; @@ -87,7 +102,7 @@ namespace boost virtual any_single_pass_iterator_interface* clone_reference_as_value(buffer_type& buffer) const = 0; - virtual Reference dereference() const = 0; + virtual reference dereference() const = 0; virtual bool equal(const any_single_pass_iterator_interface& other) const = 0; }; diff --git a/include/boost/range/detail/any_iterator_wrapper.hpp b/include/boost/range/detail/any_iterator_wrapper.hpp index 502e3e8..2526aa8 100644 --- a/include/boost/range/detail/any_iterator_wrapper.hpp +++ b/include/boost/range/detail/any_iterator_wrapper.hpp @@ -19,6 +19,17 @@ namespace boost { namespace range_detail { + template + Reference dereference_cast(T& x) + { + return static_cast(x); + } + template + Reference dereference_cast(const T& x) + { + return static_cast(const_cast(x)); + } + template< class WrappedIterator , class Reference @@ -114,7 +125,13 @@ namespace boost { struct disabler {}; BOOST_RANGE_CONCEPT_ASSERT(( SinglePassIteratorConcept )); + typedef any_single_pass_iterator_interface< + Reference, + Buffer + > base_type; + public: + typedef typename base_type::reference reference; any_single_pass_iterator_wrapper() : m_it() @@ -178,9 +195,9 @@ namespace boost return m_it == boost::polymorphic_downcast(&other)->m_it; } - virtual Reference dereference() const + virtual reference dereference() const { - return *m_it; + return dereference_cast(*m_it); } private: @@ -199,7 +216,14 @@ namespace boost > { BOOST_RANGE_CONCEPT_ASSERT(( ForwardIteratorConcept )); + typedef any_forward_iterator_interface< + Reference, + Buffer + > base_type; + public: + typedef typename base_type::reference reference; + any_forward_iterator_wrapper() : m_it() {} @@ -263,9 +287,9 @@ namespace boost return m_it == boost::polymorphic_downcast(&other)->m_it; } - virtual Reference dereference() const + virtual reference dereference() const { - return *m_it; + return dereference_cast(*m_it); } private: WrappedIterator m_it; @@ -283,7 +307,14 @@ namespace boost > { BOOST_RANGE_CONCEPT_ASSERT(( BidirectionalIteratorConcept )); + typedef any_bidirectional_iterator_interface< + Reference, + Buffer + > base_type; + public: + typedef typename base_type::reference reference; + any_bidirectional_iterator_wrapper() : m_it() { @@ -353,9 +384,9 @@ namespace boost return m_it == boost::polymorphic_downcast(&other)->m_it; } - virtual Reference dereference() const + virtual reference dereference() const { - return *m_it; + return dereference_cast(*m_it); } private: @@ -376,7 +407,14 @@ namespace boost > { BOOST_RANGE_CONCEPT_ASSERT(( RandomAccessIteratorConcept )); + typedef any_random_access_iterator_interface< + Reference, + Difference, + Buffer + > base_type; + public: + typedef typename base_type::reference reference; typedef Difference difference_type; any_random_access_iterator_wrapper() @@ -457,9 +495,9 @@ namespace boost m_it += offset; } - virtual Reference dereference() const + virtual reference dereference() const { - return *m_it; + return dereference_cast(*m_it); } virtual Difference distance_to(const any_random_access_iterator_interface& other) const diff --git a/include/boost/range/detail/has_member_size.hpp b/include/boost/range/detail/has_member_size.hpp new file mode 100644 index 0000000..0c639aa --- /dev/null +++ b/include/boost/range/detail/has_member_size.hpp @@ -0,0 +1,66 @@ +// Boost.Range library +// +// Copyright Neil Groves 2014. +// +// Use, modification and distribution are 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/ +// +#ifndef BOOST_RANGE_DETAIL_HAS_MEMBER_SIZE_HPP +#define BOOST_RANGE_DETAIL_HAS_MEMBER_SIZE_HPP + +#include +#include +#include +#include +#include + +namespace boost +{ + namespace range_detail + { + +template +class has_member_size_impl +{ +private: + template + class check + { + }; + + template + static boost::uint8_t f(check*); + + template + static boost::uint16_t f(...); + +public: + static const bool value = + (sizeof(f(0)) == sizeof(boost::uint8_t)); + + typedef typename mpl::if_c< + (sizeof(f(0)) == sizeof(boost::uint8_t)), + mpl::true_, + mpl::false_ + >::type type; +}; + +template +struct has_member_size +{ + typedef typename mpl::and_< + typename is_class::type, + typename has_member_size_impl::type + >::type type; + + static const bool value = + is_class::value && has_member_size_impl::value; +}; + + } // namespace range_detail +}// namespace boost + +#endif // include guard diff --git a/include/boost/range/detail/implementation_help.hpp b/include/boost/range/detail/implementation_help.hpp index 1f7d163..f35953f 100644 --- a/include/boost/range/detail/implementation_help.hpp +++ b/include/boost/range/detail/implementation_help.hpp @@ -95,6 +95,17 @@ namespace boost return sz; } + inline bool is_same_address(const void* l, const void* r) + { + return l == r; + } + + template + inline bool is_same_object(const T1& l, const T2& r) + { + return range_detail::is_same_address(&l, &r); + } + } // namespace 'range_detail' } // namespace 'boost' diff --git a/include/boost/range/detail/join_iterator.hpp b/include/boost/range/detail/join_iterator.hpp index d025c81..1020ebf 100644 --- a/include/boost/range/detail/join_iterator.hpp +++ b/include/boost/range/detail/join_iterator.hpp @@ -9,6 +9,9 @@ // aschoedl contributed an improvement to the determination // of the Reference type parameter. // +// Leonid Gershanovich reported Trac ticket 7376 about the dereference operator +// requiring identical reference types due to using the ternary if. +// // For more information, see http://www.boost.org/libs/range/ // #ifndef BOOST_RANGE_DETAIL_JOIN_ITERATOR_HPP_INCLUDED @@ -117,7 +120,8 @@ public: return *m_it; } - bool equal(const join_iterator_union& other, unsigned int selected) const + bool equal(const join_iterator_union& other, + unsigned int /*selected*/) const { return m_it == other.m_it; } diff --git a/include/boost/range/irange.hpp b/include/boost/range/irange.hpp index f35df47..b1a1240 100644 --- a/include/boost/range/irange.hpp +++ b/include/boost/range/irange.hpp @@ -51,6 +51,7 @@ namespace boost typedef typename base_t::value_type value_type; typedef typename base_t::difference_type difference_type; typedef typename base_t::reference reference; + typedef std::random_access_iterator_tag iterator_category; integer_iterator() : m_value() {} explicit integer_iterator(value_type x) : m_value(x) {} @@ -73,7 +74,11 @@ namespace boost difference_type distance_to(const integer_iterator& other) const { - return other.m_value - m_value; + return is_signed::value + ? (other.m_value - m_value) + : (other.m_value >= m_value) + ? static_cast(other.m_value - m_value) + : -static_cast(m_value - other.m_value); } bool equal(const integer_iterator& other) const @@ -123,6 +128,7 @@ namespace boost typedef typename base_t::value_type value_type; typedef typename base_t::difference_type difference_type; typedef typename base_t::reference reference; + typedef std::random_access_iterator_tag iterator_category; integer_iterator_with_step(value_type first, difference_type step, value_type step_size) : m_first(first) @@ -164,7 +170,7 @@ namespace boost friend class ::boost::iterator_core_access; value_type m_first; - value_type m_step; + difference_type m_step; difference_type m_step_size; }; diff --git a/include/boost/range/iterator.hpp b/include/boost/range/iterator.hpp index 4ba9122..2966bdf 100644 --- a/include/boost/range/iterator.hpp +++ b/include/boost/range/iterator.hpp @@ -25,46 +25,46 @@ namespace boost { -#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) +#if BOOST_WORKAROUND(BOOST_MSVC, == 1310) - namespace range_detail_vc7_1 - { - template< typename C, typename Sig = void(C) > - struct range_iterator - { - typedef BOOST_RANGE_DEDUCED_TYPENAME - mpl::eval_if_c< is_const::value, - range_const_iterator< typename remove_const::type >, - range_mutable_iterator >::type type; - }; - - template< typename C, typename T > - struct range_iterator< C, void(T[]) > - { - typedef T* type; - }; - } - -#endif + namespace range_detail_vc7_1 + { + template< typename C, typename Sig = void(C) > + struct range_iterator + { + typedef BOOST_RANGE_DEDUCED_TYPENAME + mpl::eval_if_c< is_const::value, + range_const_iterator< typename remove_const::type >, + range_mutable_iterator >::type type; + }; + + template< typename C, typename T > + struct range_iterator< C, void(T[]) > + { + typedef T* type; + }; + } + +#endif template< typename C > struct range_iterator { #if BOOST_WORKAROUND(BOOST_MSVC, == 1310) + + typedef BOOST_RANGE_DEDUCED_TYPENAME + range_detail_vc7_1::range_iterator::type type; + +#else - typedef BOOST_RANGE_DEDUCED_TYPENAME - range_detail_vc7_1::range_iterator::type type; - -#else - - typedef BOOST_RANGE_DEDUCED_TYPENAME - mpl::eval_if_c< is_const::value, + typedef BOOST_RANGE_DEDUCED_TYPENAME + mpl::eval_if_c< is_const::value, range_const_iterator< typename remove_const::type >, range_mutable_iterator >::type type; - -#endif + +#endif }; - + } // namespace boost #endif diff --git a/include/boost/range/iterator_range_core.hpp b/include/boost/range/iterator_range_core.hpp index f985641..7bbae2a 100644 --- a/include/boost/range/iterator_range_core.hpp +++ b/include/boost/range/iterator_range_core.hpp @@ -24,10 +24,13 @@ #include #include #include +#include #include +#include #include #include #include +#include #include #include #include @@ -77,7 +80,7 @@ namespace boost template< class Left, class Right > inline bool greater_than( const Left& l, const Right& r ) { - return less_than(r,l); + return iterator_range_detail::less_than(r,l); } template< class Left, class Right > @@ -100,8 +103,251 @@ namespace boost return boost::equal(l, r); } - struct range_tag { }; - struct const_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 -----------------------------------------// @@ -125,251 +371,109 @@ namespace boost */ template class iterator_range + : public iterator_range_detail::iterator_range_base< + IteratorT, + BOOST_DEDUCED_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, + 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; + 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, + 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, + BOOST_DEDUCED_TYPENAME enable_if< + is_compatible_range + >::type* = 0 + ) + : 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; - } - - -#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING - - bool operator==( const iterator_range& r ) const - { - return boost::equal( *this, r ); - } - - bool operator!=( const iterator_range& r ) const - { - return !operator==(r); - } - - bool operator<( const iterator_range& r ) const - { - return iterator_range_detail::less_than( *this, r ); - } - - bool operator>( const iterator_range& r ) const - { - return iterator_range_detail::greater_than( *this, r ); - } - - bool operator<=( const iterator_range& r ) const - { - return iterator_range_detail::less_or_equal_than( *this, r ); - } - - bool operator>=( const iterator_range& r ) const - { - return iterator_range_detail::greater_or_equal_than( *this, r ); - } - -#endif - - 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 @@ -383,138 +487,143 @@ namespace boost ///////////////////////////////////////////////////////////////////// // comparison operators ///////////////////////////////////////////////////////////////////// - - template< class IteratorT, class ForwardRange > - inline bool operator==( const ForwardRange& l, - const iterator_range& r ) + template + inline BOOST_DEDUCED_TYPENAME enable_if< + mpl::or_< + is_convertible< + const SinglePassRange1&, + const iterator_range_detail::iterator_range_tag& + >, + is_convertible< + const SinglePassRange2&, + const iterator_range_detail::iterator_range_tag& + > + >, + bool + >::type + operator==(const SinglePassRange1& l, const SinglePassRange2& r) { - return boost::equal( l, r ); + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + return boost::equal(l, r); + } + + template + inline BOOST_DEDUCED_TYPENAME enable_if< + mpl::or_< + is_convertible< + const SinglePassRange1&, + const iterator_range_detail::iterator_range_tag& + >, + is_convertible< + const SinglePassRange2&, + const iterator_range_detail::iterator_range_tag& + > + >, + bool + >::type + operator!=(const SinglePassRange1& l, const SinglePassRange2& r) + { + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + return !boost::equal(l, r); } - template< class IteratorT, class ForwardRange > - inline bool operator!=( const ForwardRange& l, - const iterator_range& r ) + template + inline BOOST_DEDUCED_TYPENAME enable_if< + mpl::or_< + is_convertible< + const SinglePassRange1&, + const iterator_range_detail::iterator_range_tag& + >, + is_convertible< + const SinglePassRange2&, + const iterator_range_detail::iterator_range_tag& + > + >, + bool + >::type + operator<(const SinglePassRange1& l, const SinglePassRange2& r) { - return !boost::equal( l, r ); + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + return iterator_range_detail::less_than(l, r); } - - template< class IteratorT, class ForwardRange > - inline bool operator<( const ForwardRange& l, - const iterator_range& r ) + + template + inline BOOST_DEDUCED_TYPENAME enable_if< + mpl::or_< + is_convertible< + const SinglePassRange1&, + const iterator_range_detail::iterator_range_tag& + >, + is_convertible< + const SinglePassRange2&, + const iterator_range_detail::iterator_range_tag& + > + >, + bool + >::type + operator<=(const SinglePassRange1& l, const SinglePassRange2& r) { - return iterator_range_detail::less_than( l, r ); + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + return iterator_range_detail::less_or_equal_than(l, r); } - template< class IteratorT, class ForwardRange > - inline bool operator<=( const ForwardRange& l, - const iterator_range& r ) + template + inline BOOST_DEDUCED_TYPENAME enable_if< + mpl::or_< + is_convertible< + const SinglePassRange1&, + const iterator_range_detail::iterator_range_tag& + >, + is_convertible< + const SinglePassRange2&, + const iterator_range_detail::iterator_range_tag& + > + >, + bool + >::type + operator>(const SinglePassRange1& l, const SinglePassRange2& r) { - return iterator_range_detail::less_or_equal_than( l, r ); + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + return iterator_range_detail::greater_than(l, r); } - template< class IteratorT, class ForwardRange > - inline bool operator>( const ForwardRange& l, - const iterator_range& r ) + template + inline BOOST_DEDUCED_TYPENAME enable_if< + mpl::or_< + is_convertible< + const SinglePassRange1&, + const iterator_range_detail::iterator_range_tag& + >, + is_convertible< + const SinglePassRange2&, + const iterator_range_detail::iterator_range_tag& + > + >, + bool + >::type + operator>=(const SinglePassRange1& l, const SinglePassRange2& r) { - return iterator_range_detail::greater_than( l, r ); + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + BOOST_RANGE_CONCEPT_ASSERT(( + boost::SinglePassRangeConcept)); + return iterator_range_detail::greater_or_equal_than(l, r); } - - template< class IteratorT, class ForwardRange > - inline bool operator>=( const ForwardRange& l, - const iterator_range& r ) - { - return iterator_range_detail::greater_or_equal_than( l, r ); - } - -#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING -#else - template< class Iterator1T, class Iterator2T > - inline bool operator==( const iterator_range& l, - const iterator_range& r ) - { - return boost::equal( l, r ); - } - - template< class IteratorT, class ForwardRange > - inline bool operator==( const iterator_range& l, - const ForwardRange& r ) - { - return boost::equal( l, r ); - } - - - template< class Iterator1T, class Iterator2T > - inline bool operator!=( const iterator_range& l, - const iterator_range& r ) - { - return !boost::equal( l, r ); - } - - template< class IteratorT, class ForwardRange > - inline bool operator!=( const iterator_range& l, - const ForwardRange& r ) - { - return !boost::equal( l, r ); - } - - - template< class Iterator1T, class Iterator2T > - inline bool operator<( const iterator_range& l, - const iterator_range& r ) - { - return iterator_range_detail::less_than( l, r ); - } - - template< class IteratorT, class ForwardRange > - inline bool operator<( const iterator_range& l, - const ForwardRange& r ) - { - return iterator_range_detail::less_than( l, r ); - } - - template< class Iterator1T, class Iterator2T > - inline bool operator<=( const iterator_range& l, - const iterator_range& r ) - { - return iterator_range_detail::less_or_equal_than( l, r ); - } - - template< class IteratorT, class ForwardRange > - inline bool operator<=( const iterator_range& l, - const ForwardRange& r ) - { - return iterator_range_detail::less_or_equal_than( l, r ); - } - - template< class Iterator1T, class Iterator2T > - inline bool operator>( const iterator_range& l, - const iterator_range& r ) - { - return iterator_range_detail::greater_than( l, r ); - } - - template< class IteratorT, class ForwardRange > - inline bool operator>( const iterator_range& l, - const ForwardRange& r ) - { - return iterator_range_detail::greater_than( l, r ); - } - - template< class Iterator1T, class Iterator2T > - inline bool operator>=( const iterator_range& l, - const iterator_range& r ) - { - return iterator_range_detail::greater_or_equal_than( l, r ); - } - - template< class IteratorT, class ForwardRange > - inline bool operator>=( const iterator_range& l, - const ForwardRange& r ) - { - return iterator_range_detail::greater_or_equal_than( l, r ); - } - -#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING // iterator range utilities -----------------------------------------// @@ -599,7 +708,6 @@ namespace boost BOOST_DEDUCED_TYPENAME range_difference::type advance_begin, BOOST_DEDUCED_TYPENAME range_difference::type advance_end ) { - //BOOST_ASSERT( advance_begin - advance_end <= size(r) && "creating invalid range" ); return iterator_range_detail::make_range_impl( r, advance_begin, advance_end ); } @@ -611,7 +719,6 @@ namespace boost BOOST_DEDUCED_TYPENAME range_difference::type advance_begin, BOOST_DEDUCED_TYPENAME range_difference::type advance_end ) { - //BOOST_ASSERT( advance_begin - advance_end <= size(r) && "creating invalid range" ); return iterator_range_detail::make_range_impl( r, advance_begin, advance_end ); } @@ -621,7 +728,6 @@ namespace boost BOOST_DEDUCED_TYPENAME range_difference::type advance_begin, BOOST_DEDUCED_TYPENAME range_difference::type advance_end ) { - //BOOST_ASSERT( advance_begin - advance_end <= size(r) && "creating invalid range" ); return iterator_range_detail::make_range_impl( r, advance_begin, advance_end ); } diff --git a/include/boost/range/mfc_map.hpp b/include/boost/range/mfc_map.hpp new file mode 100644 index 0000000..2cd42b4 --- /dev/null +++ b/include/boost/range/mfc_map.hpp @@ -0,0 +1,114 @@ +// Boost.Range library +// +// Copyright Adam D. Walling 2012. 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/ +// + +#ifndef BOOST_RANGE_ADAPTOR_MFC_MAP_HPP +#define BOOST_RANGE_ADAPTOR_MFC_MAP_HPP + +#if !defined(BOOST_RANGE_MFC_NO_CPAIR) + +#include +#include + +namespace boost +{ + namespace range_detail + { + // CMap and CMapStringToString range iterators return CPair, + // which has a key and value member. Other MFC range iterators + // already return adapted std::pair objects. This allows usage + // of the map_keys and map_values range adaptors with CMap + // and CMapStringToString + + // CPair has a VALUE value member, and a KEY key member; we will + // use VALUE& as the result_type consistent with CMap::operator[] + + // specialization for CMap + template + struct select_first< CMap > + { + typedef BOOST_DEDUCED_TYPENAME CMap map_type; + typedef BOOST_DEDUCED_TYPENAME range_reference::type argument_type; + typedef BOOST_DEDUCED_TYPENAME const KEY& result_type; + + result_type operator()( argument_type r ) const + { + return r.key; + } + }; + + template + struct select_second_mutable< CMap > + { + typedef BOOST_DEDUCED_TYPENAME CMap map_type; + typedef BOOST_DEDUCED_TYPENAME range_reference::type argument_type; + typedef BOOST_DEDUCED_TYPENAME VALUE& result_type; + + result_type operator()( argument_type r ) const + { + return r.value; + } + }; + + template + struct select_second_const< CMap > + { + typedef BOOST_DEDUCED_TYPENAME CMap map_type; + typedef BOOST_DEDUCED_TYPENAME range_reference::type argument_type; + typedef BOOST_DEDUCED_TYPENAME const VALUE& result_type; + + result_type operator()( argument_type r ) const + { + return r.value; + } + }; + + + // specialization for CMapStringToString + template<> + struct select_first< CMapStringToString > + { + typedef range_reference::type argument_type; + typedef const CString& result_type; + + result_type operator()( argument_type r ) const + { + return r.key; + } + }; + + template<> + struct select_second_mutable< CMapStringToString > + { + typedef range_reference::type argument_type; + typedef CString& result_type; + + result_type operator()( argument_type r ) const + { + return r.value; + } + }; + + template<> + struct select_second_const< CMapStringToString > + { + typedef range_reference::type argument_type; + typedef const CString& result_type; + + result_type operator()( argument_type r ) const + { + return r.value; + } + }; + } // 'range_detail' +} // 'boost' + +#endif // !defined(BOOST_RANGE_MFC_NO_CPAIR) + +#endif diff --git a/include/boost/range/numeric.hpp b/include/boost/range/numeric.hpp index c70069f..d1510cd 100644 --- a/include/boost/range/numeric.hpp +++ b/include/boost/range/numeric.hpp @@ -1,14 +1,8 @@ -/////////////////////////////////////////////////////////////////////////////// -/// \file algorithm.hpp -/// Contains range-based versions of the std algorithms -// -///////////////////////////////////////////////////////////////////////////// -// Copyright 2009 Neil Groves. +// Copyright 2009-2014 Neil Groves. // Distributed under 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) // - // Copyright 2006 Thorsten Ottosen. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -18,7 +12,9 @@ // Distributed under 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) - +// +// Contains range-based versions of the numeric std algorithms +// #if defined(_MSC_VER) #pragma once #endif @@ -30,89 +26,163 @@ #include #include #include +#include #include #include +#include #include namespace boost { - template< class SinglePassRange, class Value > - inline Value accumulate( const SinglePassRange& rng, Value init ) + template + inline Value accumulate(const SinglePassRange& rng, Value init) { - BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - return std::accumulate( boost::begin(rng), boost::end(rng), init ); + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + return std::accumulate(boost::begin(rng), boost::end(rng), init); } - template< class SinglePassRange, class Value, class BinaryOperation > - inline Value accumulate( const SinglePassRange& rng, Value init, BinaryOperation op ) + template + inline Value accumulate(const SinglePassRange& rng, Value init, + BinaryOperation op) { - BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - return std::accumulate( boost::begin(rng), boost::end(rng), init, op ); + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept )); + + return std::accumulate(boost::begin(rng), boost::end(rng), init, op); } - - template< class SinglePassRange1, class SinglePassRange2, class Value > - inline Value inner_product( const SinglePassRange1& rng1, const SinglePassRange2& rng2, Value init ) + namespace range_detail { - BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - BOOST_ASSERT( boost::distance(rng2) >= boost::distance(rng1) ); - return std::inner_product( boost::begin(rng1), boost::end(rng1), - boost::begin(rng2), init ); + template + inline bool inner_product_precondition( + const SinglePassRange1&, + const SinglePassRange2&, + std::input_iterator_tag, + std::input_iterator_tag) + { + return true; + } + + template + inline bool inner_product_precondition( + const SinglePassRange1& rng1, + const SinglePassRange2& rng2, + std::forward_iterator_tag, + std::forward_iterator_tag) + { + return boost::size(rng2) >= boost::size(rng1); + } + + } // namespace range_detail + + template< + class SinglePassRange1, + class SinglePassRange2, + class Value + > + inline Value inner_product( + const SinglePassRange1& rng1, + const SinglePassRange2& rng2, + Value init) + { + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + BOOST_ASSERT( + range_detail::inner_product_precondition( + rng1, rng2, + typename range_category::type(), + typename range_category::type())); + + return std::inner_product( + boost::begin(rng1), boost::end(rng1), + boost::begin(rng2), init); } - template< class SinglePassRange1, - class SinglePassRange2, - class Value, - class BinaryOperation1, class BinaryOperation2 > - inline Value inner_product( const SinglePassRange1& rng1, const SinglePassRange2& rng2, - Value init, - BinaryOperation1 op1, BinaryOperation2 op2 ) + template< + class SinglePassRange1, + class SinglePassRange2, + class Value, + class BinaryOperation1, + class BinaryOperation2 + > + inline Value inner_product( + const SinglePassRange1& rng1, + const SinglePassRange2& rng2, + Value init, + BinaryOperation1 op1, + BinaryOperation2 op2) { - BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - BOOST_ASSERT( boost::distance(rng2) >= boost::distance(rng1) ); + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); - return std::inner_product( boost::begin(rng1), boost::end(rng1), - boost::begin(rng2), init, op1, op2 ); + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + BOOST_ASSERT( + range_detail::inner_product_precondition( + rng1, rng2, + typename range_category::type(), + typename range_category::type())); + + return std::inner_product( + boost::begin(rng1), boost::end(rng1), + boost::begin(rng2), init, op1, op2); } - template< class SinglePassRange, class OutputIterator > - inline OutputIterator partial_sum ( const SinglePassRange& rng, - OutputIterator result ) + template + inline OutputIterator partial_sum(const SinglePassRange& rng, + OutputIterator result) { - BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - return std::partial_sum( boost::begin(rng), boost::end(rng), result ); + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + return std::partial_sum(boost::begin(rng), boost::end(rng), result); } - template< class SinglePassRange, class OutputIterator, class BinaryOperation > - inline OutputIterator partial_sum ( const SinglePassRange& rng, OutputIterator result, - BinaryOperation op ) + template + inline OutputIterator partial_sum( + const SinglePassRange& rng, + OutputIterator result, + BinaryOperation op) { - BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - return std::partial_sum( boost::begin(rng), boost::end(rng), result, op ); + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + return std::partial_sum(boost::begin(rng), boost::end(rng), result, op); } - template< class SinglePassRange, class OutputIterator > - inline OutputIterator adjacent_difference ( const SinglePassRange& rng, - OutputIterator result ) + template + inline OutputIterator adjacent_difference( + const SinglePassRange& rng, + OutputIterator result) { - BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - return std::adjacent_difference( boost::begin(rng), boost::end(rng), - result ); + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + return std::adjacent_difference(boost::begin(rng), boost::end(rng), + result); } - template< class SinglePassRange, class OutputIterator, class BinaryOperation > - inline OutputIterator adjacent_difference ( const SinglePassRange& rng, - OutputIterator result, - BinaryOperation op ) + template + inline OutputIterator adjacent_difference( + const SinglePassRange& rng, + OutputIterator result, + BinaryOperation op) { - BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept )); - return std::adjacent_difference( boost::begin(rng), boost::end(rng), - result, op ); + BOOST_RANGE_CONCEPT_ASSERT(( + SinglePassRangeConcept)); + + return std::adjacent_difference(boost::begin(rng), boost::end(rng), + result, op); } -} +} // namespace boost #endif diff --git a/include/boost/range/size.hpp b/include/boost/range/size.hpp index 9b63aff..cd7a90e 100644 --- a/include/boost/range/size.hpp +++ b/include/boost/range/size.hpp @@ -19,24 +19,39 @@ #include #include #include +#include #include +#include +#include namespace boost { namespace range_detail { + template - inline BOOST_DEDUCED_TYPENAME range_size::type + inline typename enable_if< + has_member_size, + typename range_size::type + >::type range_calculate_size(const SinglePassRange& rng) { - BOOST_ASSERT( (boost::end(rng) - boost::begin(rng)) >= 0 && - "reachability invariant broken!" ); - return boost::end(rng) - boost::begin(rng); + return rng.size(); + } + + template + inline typename disable_if< + has_member_size, + typename range_size::type + >::type + range_calculate_size(const SinglePassRange& rng) + { + return std::distance(boost::begin(rng), boost::end(rng)); } } template - inline BOOST_DEDUCED_TYPENAME range_size::type + inline typename range_size::type size(const SinglePassRange& rng) { #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) && \ 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 bcaa772..a7b479a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -13,12 +13,12 @@ import testing ; project - : requirements - /boost/test//boost_unit_test_framework/ - /boost/regex//boost_regex/ - static - multi - ; + : requirements + /boost/test//boost_unit_test_framework/ + /boost/regex//boost_regex/ + static + multi + ; rule range-test ( name : includes * ) { @@ -31,136 +31,150 @@ rule range-test ( name : includes * ) } test-suite range : - [ compile-fail compile_fail/iterator_range1.cpp ] - [ range-test adaptor_test/adjacent_filtered ] - [ range-test adaptor_test/copied ] - [ range-test adaptor_test/filtered ] - [ range-test adaptor_test/indexed ] - [ range-test adaptor_test/indirected ] - [ range-test adaptor_test/map ] - [ range-test adaptor_test/replaced ] - [ range-test adaptor_test/replaced_if ] - [ range-test adaptor_test/reversed ] - [ range-test adaptor_test/sliced ] - [ range-test adaptor_test/strided ] - [ range-test adaptor_test/strided2 ] - [ range-test adaptor_test/tokenized ] - [ range-test adaptor_test/transformed ] - [ range-test adaptor_test/type_erased ] - [ range-test adaptor_test/uniqued ] - [ range-test adaptor_test/adjacent_filtered_example ] - [ range-test adaptor_test/copied_example ] - [ range-test adaptor_test/filtered_example ] - [ range-test adaptor_test/indexed_example ] - [ range-test adaptor_test/indirected_example ] - [ range-test adaptor_test/map_keys_example ] - [ range-test adaptor_test/map_values_example ] - [ range-test adaptor_test/replaced_example ] - [ range-test adaptor_test/replaced_if_example ] - [ range-test adaptor_test/reversed_example ] - [ range-test adaptor_test/sliced_example ] - [ range-test adaptor_test/strided_example ] - [ range-test adaptor_test/transformed_example ] - [ range-test adaptor_test/tokenized_example ] - [ range-test adaptor_test/type_erased_example ] - [ range-test adaptor_test/uniqued_example ] - [ range-test algorithm_test/adjacent_find ] - [ range-test algorithm_test/binary_search ] - [ range-test algorithm_test/copy ] - [ range-test algorithm_test/copy_backward ] - [ range-test algorithm_test/count ] - [ range-test algorithm_test/count_if ] - [ range-test algorithm_test/equal ] - [ range-test algorithm_test/equal_range ] - [ range-test algorithm_test/fill ] - [ range-test algorithm_test/find ] - [ range-test algorithm_test/find_if ] - [ range-test algorithm_test/find_end ] - [ range-test algorithm_test/find_first_of ] - [ range-test algorithm_test/for_each ] - [ range-test algorithm_test/generate ] - [ range-test algorithm_test/heap ] - [ range-test algorithm_test/includes ] - [ range-test algorithm_test/inplace_merge ] - [ range-test algorithm_test/lexicographical_compare ] - [ range-test algorithm_test/lower_bound ] - [ range-test algorithm_test/max_element ] - [ range-test algorithm_test/merge ] - [ range-test algorithm_test/min_element ] - [ range-test algorithm_test/mismatch ] - [ range-test algorithm_test/next_permutation ] - [ range-test algorithm_test/nth_element ] - [ range-test algorithm_test/partial_sort ] - [ range-test algorithm_test/partition ] - [ range-test algorithm_test/prev_permutation ] - [ range-test algorithm_test/random_shuffle ] - [ range-test algorithm_test/remove ] - [ range-test algorithm_test/remove_copy ] - [ range-test algorithm_test/remove_copy_if ] - [ range-test algorithm_test/remove_if ] - [ range-test algorithm_test/replace ] - [ range-test algorithm_test/replace_copy ] - [ range-test algorithm_test/replace_copy_if ] - [ range-test algorithm_test/replace_if ] - [ range-test algorithm_test/reverse ] - [ range-test algorithm_test/reverse_copy ] - [ range-test algorithm_test/rotate ] - [ range-test algorithm_test/rotate_copy ] - [ range-test algorithm_test/search ] - [ range-test algorithm_test/search_n ] - [ range-test algorithm_test/set_difference ] - [ range-test algorithm_test/set_intersection ] - [ range-test algorithm_test/set_symmetric_difference ] - [ range-test algorithm_test/set_union ] - [ range-test algorithm_test/sort ] - [ range-test algorithm_test/stable_partition ] - [ range-test algorithm_test/stable_sort ] - [ range-test algorithm_test/swap_ranges ] - [ range-test algorithm_test/transform ] - [ range-test algorithm_test/unique ] - [ range-test algorithm_test/unique_copy ] - [ range-test algorithm_test/upper_bound ] - [ range-test algorithm_ext_test/copy_n ] - [ range-test algorithm_ext_test/erase ] - [ range-test algorithm_ext_test/for_each_ext ] - [ range-test algorithm_ext_test/insert ] - [ range-test algorithm_ext_test/iota ] - [ range-test algorithm_ext_test/is_sorted ] - [ range-test algorithm_ext_test/overwrite ] - [ range-test algorithm_ext_test/push_back ] - [ range-test algorithm_ext_test/push_front ] - [ range-test adl_conformance ] - [ range-test adl_conformance_no_using ] - [ range-test algorithm ] - [ range-test algorithm_example ] - [ range-test array ] -# [ range-test atl : $(VC71_ROOT)/atlmfc/include ] + [ compile-fail compile_fail/iterator_range1.cpp ] + [ range-test adaptor_test/adjacent_filtered ] + [ range-test adaptor_test/copied ] + [ range-test adaptor_test/filtered ] + [ range-test adaptor_test/indexed ] + [ range-test adaptor_test/indirected ] + [ range-test adaptor_test/map ] + [ range-test adaptor_test/replaced ] + [ range-test adaptor_test/replaced_if ] + [ range-test adaptor_test/reversed ] + [ range-test adaptor_test/sliced ] + [ range-test adaptor_test/strided ] + [ range-test adaptor_test/strided2 ] + [ range-test adaptor_test/ticket_6742_transformed_c4789_warning ] + [ range-test adaptor_test/ticket_8676_sliced_transformed ] + [ range-test adaptor_test/ticket_9519_strided_reversed ] + [ range-test adaptor_test/tokenized ] + [ range-test adaptor_test/transformed ] + [ range-test adaptor_test/type_erased ] + [ range-test adaptor_test/type_erased_abstract ] + [ range-test adaptor_test/type_erased_brackets ] + [ range-test adaptor_test/type_erased_mix_values ] + [ range-test adaptor_test/type_erased_tparam_conv ] + [ range-test adaptor_test/type_erased_single_pass ] + [ range-test adaptor_test/type_erased_forward ] + [ range-test adaptor_test/type_erased_bidirectional ] + [ range-test adaptor_test/type_erased_random_access ] + [ range-test adaptor_test/uniqued ] + [ range-test adaptor_test/adjacent_filtered_example ] + [ range-test adaptor_test/copied_example ] + [ range-test adaptor_test/filtered_example ] + [ range-test adaptor_test/indexed_example ] + [ range-test adaptor_test/indirected_example ] + [ range-test adaptor_test/map_keys_example ] + [ range-test adaptor_test/map_values_example ] + [ range-test adaptor_test/replaced_example ] + [ range-test adaptor_test/replaced_if_example ] + [ range-test adaptor_test/reversed_example ] + [ range-test adaptor_test/sliced_example ] + [ range-test adaptor_test/strided_example ] + [ range-test adaptor_test/transformed_example ] + [ range-test adaptor_test/tokenized_example ] + [ range-test adaptor_test/type_erased_example ] + [ range-test adaptor_test/uniqued_example ] + [ range-test algorithm_test/adjacent_find ] + [ range-test algorithm_test/binary_search ] + [ range-test algorithm_test/copy ] + [ range-test algorithm_test/copy_backward ] + [ range-test algorithm_test/count ] + [ range-test algorithm_test/count_if ] + [ range-test algorithm_test/equal ] + [ range-test algorithm_test/equal_range ] + [ range-test algorithm_test/fill ] + [ range-test algorithm_test/find ] + [ range-test algorithm_test/find_if ] + [ range-test algorithm_test/find_end ] + [ range-test algorithm_test/find_first_of ] + [ range-test algorithm_test/for_each ] + [ range-test algorithm_test/generate ] + [ range-test algorithm_test/heap ] + [ range-test algorithm_test/includes ] + [ range-test algorithm_test/inplace_merge ] + [ range-test algorithm_test/lexicographical_compare ] + [ range-test algorithm_test/lower_bound ] + [ range-test algorithm_test/max_element ] + [ range-test algorithm_test/merge ] + [ range-test algorithm_test/min_element ] + [ range-test algorithm_test/mismatch ] + [ range-test algorithm_test/next_permutation ] + [ range-test algorithm_test/nth_element ] + [ range-test algorithm_test/partial_sort ] + [ range-test algorithm_test/partition ] + [ range-test algorithm_test/prev_permutation ] + [ range-test algorithm_test/random_shuffle ] + [ range-test algorithm_test/remove ] + [ range-test algorithm_test/remove_copy ] + [ range-test algorithm_test/remove_copy_if ] + [ range-test algorithm_test/remove_if ] + [ range-test algorithm_test/replace ] + [ range-test algorithm_test/replace_copy ] + [ range-test algorithm_test/replace_copy_if ] + [ range-test algorithm_test/replace_if ] + [ range-test algorithm_test/reverse ] + [ range-test algorithm_test/reverse_copy ] + [ range-test algorithm_test/rotate ] + [ range-test algorithm_test/rotate_copy ] + [ range-test algorithm_test/search ] + [ range-test algorithm_test/search_n ] + [ range-test algorithm_test/set_difference ] + [ range-test algorithm_test/set_intersection ] + [ range-test algorithm_test/set_symmetric_difference ] + [ range-test algorithm_test/set_union ] + [ range-test algorithm_test/sort ] + [ range-test algorithm_test/stable_partition ] + [ range-test algorithm_test/stable_sort ] + [ range-test algorithm_test/swap_ranges ] + [ range-test algorithm_test/transform ] + [ range-test algorithm_test/unique ] + [ range-test algorithm_test/unique_copy ] + [ range-test algorithm_test/upper_bound ] + [ range-test algorithm_ext_test/copy_n ] + [ range-test algorithm_ext_test/erase ] + [ range-test algorithm_ext_test/for_each_ext ] + [ range-test algorithm_ext_test/insert ] + [ range-test algorithm_ext_test/iota ] + [ range-test algorithm_ext_test/is_sorted ] + [ range-test algorithm_ext_test/overwrite ] + [ range-test algorithm_ext_test/push_back ] + [ range-test algorithm_ext_test/push_front ] + [ range-test adl_conformance ] + [ range-test adl_conformance_no_using ] + [ range-test algorithm ] + [ range-test algorithm_example ] + [ range-test array ] +# [ range-test atl : $(VC71_ROOT)/atlmfc/include ] [ range-test begin ] - [ range-test combine ] - [ range-test compat2 ] - [ range-test compat3 ] - [ range-test const_ranges ] - [ range-test counting_range ] - [ range-test end ] - [ range-test extension_mechanism ] - [ range-test extension_size ] - [ range-test has_range_iterator ] - [ range-test irange ] - [ range-test istream_range ] - [ range-test iterator_pair ] - [ range-test iterator_range ] -# [ range-test mfc : $(VC71_ROOT)/atlmfc/include ] + [ range-test combine ] + [ range-test compat2 ] + [ range-test compat3 ] + [ range-test const_ranges ] + [ range-test counting_range ] + [ range-test end ] + [ range-test extension_mechanism ] + [ range-test extension_size ] + [ range-test has_range_iterator ] + [ range-test irange ] + [ 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 ] - [ range-test pointer_as_iterator ] - [ range-test reversible_range ] - [ range-test std_container ] - [ range-test string ] - [ range-test sub_range ] - [ range-test ticket_5486 ] - [ range-test ticket_5544_terminate_irange ] - [ range-test ticket_5547 ] - [ range-test ticket_5556_is_sorted_namespace ] - [ range-test ticket_6944 ] + [ range-test partial_workaround ] + [ range-test pointer_as_iterator ] + [ range-test reversible_range ] + [ range-test std_container ] + [ range-test string ] + [ range-test sub_range ] + [ range-test ticket_5486 ] + [ range-test ticket_5544_terminate_irange ] + [ range-test ticket_5547 ] + [ range-test ticket_5556_is_sorted_namespace ] + [ range-test ticket_5811_indirected_optional ] + [ range-test ticket_6715_iterator_range_equality ] + [ range-test ticket_6944 ] ; diff --git a/test/adaptor_test/strided.cpp b/test/adaptor_test/strided.cpp index 290cd4b..6c8475d 100644 --- a/test/adaptor_test/strided.cpp +++ b/test/adaptor_test/strided.cpp @@ -11,6 +11,9 @@ // The strided_defect_Trac5014 test case is a modified version of a test case // contributed by Michel Morin as part of the trac ticket. // +// The deque test case has been removed due to erroneous standard library +// implementations causing test failures. +// #include #include @@ -21,7 +24,6 @@ #include #include -#include #include namespace boost @@ -135,8 +137,15 @@ namespace boost boost::ignore_unused_variable_warning(rng); typedef BOOST_DEDUCED_TYPENAME boost::range_iterator::type iter_t; - iter_t first(boost::begin(c), boost::begin(c), boost::end(c), 0); - iter_t last(boost::begin(c), boost::end(c), boost::end(c), 0); + typedef BOOST_DEDUCED_TYPENAME boost::iterator_traversal< + BOOST_DEDUCED_TYPENAME Container::const_iterator + >::type container_traversal_tag; + + iter_t first = boost::range_detail::make_begin_strided_iterator( + c, 0, container_traversal_tag()); + + iter_t last = boost::range_detail::make_end_strided_iterator( + c, 0, container_traversal_tag()); iter_t it = first; for (int i = 0; i < 10; ++i, ++it) @@ -160,7 +169,6 @@ namespace boost void strided_test() { strided_test_impl< std::vector >(); - strided_test_impl< std::deque >(); strided_test_impl< std::list >(); } diff --git a/test/adaptor_test/ticket_6742_transformed_c4789_warning.cpp b/test/adaptor_test/ticket_6742_transformed_c4789_warning.cpp new file mode 100644 index 0000000..fdd7118 --- /dev/null +++ b/test/adaptor_test/ticket_6742_transformed_c4789_warning.cpp @@ -0,0 +1,69 @@ +// 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 +{ + struct test_struct + { + double x; + double y; + }; + + struct get_x + { + typedef double result_type; + double operator()(const test_struct& s) const + { + return s.x; + } + }; + + void range_transformed_warning() + { + using namespace boost::phoenix::arg_names; + using namespace boost::adaptors; + + test_struct t; + t.x = 2.0; + t.y = -4.0; + std::vector v(10u, t); + + std::vector output1; + boost::push_back(output1, v | transformed((&arg1)->*& test_struct::x)); + + std::vector output2; + boost::push_back(output2, v | transformed(get_x())); + + BOOST_CHECK_EQUAL_COLLECTIONS( + output1.begin(), output1.end(), + output2.begin(), output2.end()); + } +} // anonymous namespace + +boost::unit_test::test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + boost::unit_test::test_suite* test + = BOOST_TEST_SUITE( "Range adaptors - transformed warning" ); + + test->add(BOOST_TEST_CASE(&range_transformed_warning)); + + return test; +} diff --git a/test/adaptor_test/ticket_8676_sliced_transformed.cpp b/test/adaptor_test/ticket_8676_sliced_transformed.cpp new file mode 100644 index 0000000..da0125e --- /dev/null +++ b/test/adaptor_test/ticket_8676_sliced_transformed.cpp @@ -0,0 +1,56 @@ +// 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 +{ + struct identity + { + typedef int result_type; + result_type operator()(int i) const { return i; } + }; + + void sliced_and_transformed() + { + using namespace boost::adaptors; + + std::vector input; + for (int i = 0; i < 10; ++i) + input.push_back(i); + + std::vector out1; + boost::push_back(out1, input | sliced(2, 8) + | transformed(identity())); + + std::vector out2; + boost::push_back(out2, input | transformed(identity()) + | sliced(2, 8)); + + BOOST_CHECK_EQUAL_COLLECTIONS(out1.begin(), out1.end(), + out2.begin(), out2.end()); + } +} // anonymous namespace + +boost::unit_test::test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + boost::unit_test::test_suite* test + = BOOST_TEST_SUITE( "Range adaptors - sliced and transformed" ); + + test->add(BOOST_TEST_CASE(&sliced_and_transformed)); + + return test; +} diff --git a/test/adaptor_test/ticket_9519_strided_reversed.cpp b/test/adaptor_test/ticket_9519_strided_reversed.cpp new file mode 100644 index 0000000..0c91598 --- /dev/null +++ b/test/adaptor_test/ticket_9519_strided_reversed.cpp @@ -0,0 +1,67 @@ +// 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/ +// +// Credit goes to Eric Niebler for providing an example to demonstrate this +// issue. This has been trivially modified to create this test case. +// +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace boost +{ + namespace + { + +void ticket_9519_strided_reversed_test() +{ + using namespace boost::adaptors; + + std::vector vi; + for (int i = 0; i < 50; ++i) + { + vi.push_back(i); + } + + std::vector output; + boost::push_back(output, vi | strided(3) | reversed); + + std::list reference; + for (int i = 0; i < 50; i += 3) + { + reference.push_front(i); + } + + BOOST_CHECK_EQUAL_COLLECTIONS(output.begin(), output.end(), + reference.begin(), reference.end()); +} + + } // anonymous namespace +} // namespace boost + +boost::unit_test::test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + boost::unit_test::test_suite* test + = BOOST_TEST_SUITE( + "RangeTestSuite.adaptor.ticket_9519_strided_reversed"); + + test->add(BOOST_TEST_CASE(&boost::ticket_9519_strided_reversed_test)); + + return test; +} + diff --git a/test/adaptor_test/type_erased.cpp b/test/adaptor_test/type_erased.cpp index fd3ee5f..edea1c4 100644 --- a/test/adaptor_test/type_erased.cpp +++ b/test/adaptor_test/type_erased.cpp @@ -6,476 +6,39 @@ // http://www.boost.org/LICENSE_1_0.txt) // #include +#include "type_erased_test.hpp" -#include #include -#include -#include -#include -#include - -#include #include -#include #include namespace boost_range_adaptor_type_erased_test { - class MockType + namespace { - public: - MockType() - : m_x(0) - { - } - MockType(int x) - : m_x(x) - { - } +void test_type_erased() +{ + test_driver< std::list >(); + test_driver< std::vector >(); - int get() const { return m_x; } - - inline bool operator==(const MockType& other) const - { - return m_x == other.m_x; - } - - inline bool operator!=(const MockType& other) const - { - return m_x != other.m_x; - } - - private: - int m_x; - }; - - inline std::ostream& operator<<(std::ostream& out, const MockType& obj) - { - out << obj.get(); - return out; - } - - template - void test_type_erased_impl(Container& c) - { - using namespace boost::adaptors; - typedef typename boost::range_value::type value_type; - typedef typename boost::adaptors::type_erased<> type_erased_t; - - - std::vector output; - - boost::push_back(output, boost::adaptors::type_erase(c, type_erased_t())); - - BOOST_CHECK_EQUAL_COLLECTIONS( output.begin(), output.end(), - c.begin(), c.end() ); - - output.clear(); - boost::push_back(output, c | type_erased_t()); - - BOOST_CHECK_EQUAL_COLLECTIONS( output.begin(), output.end(), - c.begin(), c.end() ); - } - - template - void test_const_and_mutable(Container& c) - { - test_type_erased_impl(c); - - const Container& const_c = c; - test_type_erased_impl(const_c); - } - - template - void test_driver() - { - using namespace boost::assign; - - typedef typename boost::range_value::type value_type; - - Container c; - test_const_and_mutable(c); - - c += value_type(1); - test_const_and_mutable(c); - - c += value_type(2); - test_const_and_mutable(c); - } - - void test_type_erased() - { - test_driver< std::list >(); - test_driver< std::vector >(); - - test_driver< std::list >(); - test_driver< std::vector >(); - } - - template< - class Traversal - , class Container - > - void test_writeable(Container&, boost::single_pass_traversal_tag) - {} - - template< - class Traversal - , class Container - > - void test_writeable(Container& source, boost::forward_traversal_tag) - { - using namespace boost::adaptors; - - typedef typename boost::range_value::type value_type; - typedef typename boost::range_difference::type difference_type; - typedef typename boost::range_reference::type mutable_reference_type; - typedef boost::any_range< - value_type - , Traversal - , mutable_reference_type - , difference_type - > mutable_any_range; - - mutable_any_range r = source | boost::adaptors::type_erased<>(); - std::vector output_test; - boost::fill(r, value_type(1)); - BOOST_CHECK_EQUAL( boost::distance(r), boost::distance(source) ); - std::vector reference_output(source.size(), value_type(1)); - BOOST_CHECK_EQUAL_COLLECTIONS( reference_output.begin(), reference_output.end(), - r.begin(), r.end() ); - - } - - template< - class Container - , class Traversal - , class Buffer - > - void test_type_erased_impl() - { - using namespace boost::adaptors; - - typedef Buffer buffer_type; - - typedef typename boost::range_value::type value_type; - - typedef typename boost::any_range_type_generator< - Container - , boost::use_default - , Traversal - , boost::use_default - , boost::use_default - , Buffer - >::type mutable_any_range; - - typedef typename boost::any_range_type_generator< - const Container - , boost::use_default - , Traversal - , boost::use_default - , boost::use_default - , Buffer - >::type const_any_range; - - typedef boost::adaptors::type_erased< - boost::use_default - , Traversal - , boost::use_default - , boost::use_default - , Buffer - > type_erased_t; - - Container source; - for (int i = 0; i < 10; ++i) - source.push_back(value_type(i)); - - mutable_any_range r(source); - BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(), - r.begin(), r.end() ); - - r = mutable_any_range(); - BOOST_CHECK_EQUAL( r.empty(), true ); - - r = source | type_erased_t(); - BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(), - r.begin(), r.end() ); - r = mutable_any_range(); - - r = boost::adaptors::type_erase(source, type_erased_t()); - BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(), - r.begin(), r.end() ); - r = mutable_any_range(); - - test_writeable(source, Traversal()); - - // convert and construct a const any_range from a mutable source - // range - const_any_range cr(source); - BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(), - cr.begin(), cr.end() ); - // assign an empty range and ensure that this correctly results - // in an empty range. This is important for the validity of - // the rest of the tests. - cr = const_any_range(); - BOOST_CHECK_EQUAL( cr.empty(), true ); - - // Test the pipe type_erased adaptor from a constant source - // range to a constant any_range - const Container& const_source = source; - cr = const_any_range(); - cr = const_source | type_erased_t(); - BOOST_CHECK_EQUAL_COLLECTIONS( const_source.begin(), const_source.end(), - cr.begin(), cr.end() ); - - // Test the pipe type erased adaptor from a mutable source - // range to a constant any_range - cr = const_any_range(); - cr = source | type_erased_t(); - BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(), - cr.begin(), cr.end() ); - - // Use the function form of the type_erase adaptor from a constant - // source range - cr = const_any_range(); - cr = boost::adaptors::type_erase(const_source, type_erased_t()); - BOOST_CHECK_EQUAL_COLLECTIONS( const_source.begin(), const_source.end(), - cr.begin(), cr.end() ); - - // Assignment from mutable to const... - cr = const_any_range(); - cr = r; - BOOST_CHECK_EQUAL_COLLECTIONS( cr.begin(), cr.end(), - r.begin(), r.end() ); - - // Converting copy from mutable to const... - cr = const_any_range(); - cr = const_any_range(r); - BOOST_CHECK_EQUAL_COLLECTIONS( cr.begin(), cr.end(), - r.begin(), r.end() ); - } - - template< - class Container - , class Traversal - , class Buffer - > - class test_type_erased_impl_fn - { - public: - typedef void result_type; - void operator()() - { - test_type_erased_impl< Container, Traversal, Buffer >(); - } - }; - - template< - class Container - , class Traversal - > - void test_type_erased_exercise_buffer_types() - { - using boost::any_iterator_default_buffer; - using boost::any_iterator_buffer; - using boost::any_iterator_heap_only_buffer; - using boost::any_iterator_stack_only_buffer; - - test_type_erased_impl_fn< Container, Traversal, any_iterator_default_buffer >()(); - test_type_erased_impl_fn< Container, Traversal, any_iterator_heap_only_buffer >()(); - test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<1> >()(); - test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<2> >()(); - test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<32> >()(); - test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<64> >()(); - test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<128> >()(); - test_type_erased_impl_fn< Container, Traversal, any_iterator_stack_only_buffer<128> >()(); - } - - void test_type_erased_single_pass() - { - test_type_erased_exercise_buffer_types< std::list, boost::single_pass_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::deque, boost::single_pass_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::vector, boost::single_pass_traversal_tag >(); - - test_type_erased_exercise_buffer_types< std::list, boost::single_pass_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::deque, boost::single_pass_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::vector, boost::single_pass_traversal_tag >(); - } - - void test_type_erased_forward() - { - test_type_erased_exercise_buffer_types< std::list, boost::forward_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::deque, boost::forward_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::vector, boost::forward_traversal_tag >(); - - test_type_erased_exercise_buffer_types< std::list, boost::forward_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::deque, boost::forward_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::vector, boost::forward_traversal_tag >(); - } - - void test_type_erased_bidirectional() - { - test_type_erased_exercise_buffer_types< std::list, boost::bidirectional_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::deque, boost::bidirectional_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::vector, boost::bidirectional_traversal_tag >(); - - test_type_erased_exercise_buffer_types< std::list, boost::bidirectional_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::deque, boost::bidirectional_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::vector, boost::bidirectional_traversal_tag >(); - } - - void test_type_erased_random_access() - { - test_type_erased_exercise_buffer_types< std::deque, boost::random_access_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::vector, boost::random_access_traversal_tag >(); - - test_type_erased_exercise_buffer_types< std::deque, boost::random_access_traversal_tag >(); - test_type_erased_exercise_buffer_types< std::vector, boost::random_access_traversal_tag >(); - } - - void test_type_erased_multiple_different_template_parameter_conversion() - { - typedef boost::any_range< - int - , boost::random_access_traversal_tag - , int& - , std::ptrdiff_t - > source_range_type; - - typedef boost::any_range< - int - , boost::single_pass_traversal_tag - , const int& - , std::ptrdiff_t - > target_range_type; - - source_range_type source; - - // Converting via construction - target_range_type t1(source); - - // Converting via assignment - target_range_type t2; - t2 = source; - - // Converting via construction to a type with a reference type - // that is a value - typedef boost::any_range< - int - , boost::single_pass_traversal_tag - , int - , std::ptrdiff_t - > target_range2_type; - - target_range2_type t3(source); - target_range2_type t4; - t4 = source; - } - - template< - class Traversal - , class ValueType - , class SourceValueType - , class SourceReference - , class TargetValueType - , class TargetReference - > - void test_type_erased_mix_values_impl() - { - typedef std::vector< ValueType > Container; - - typedef typename boost::any_range_type_generator< - Container - , SourceValueType - , Traversal - , SourceReference - >::type source_type; - - typedef typename boost::any_range_type_generator< - Container - , TargetValueType - , Traversal - , TargetReference - >::type target_type; - - Container test_data; - for (int i = 0; i < 10; ++i) - test_data.push_back(i); - - const source_type source_data(test_data); - target_type t1(source_data); - BOOST_CHECK_EQUAL_COLLECTIONS( source_data.begin(), source_data.end(), - t1.begin(), t1.end() ); - - target_type t2; - t2 = source_data; - BOOST_CHECK_EQUAL_COLLECTIONS( source_data.begin(), source_data.end(), - t2.begin(), t2.end() ); - } - - template - void test_type_erased_mix_values_driver() - { - test_type_erased_mix_values_impl< Traversal, int, char, const int&, short, const int& >(); - test_type_erased_mix_values_impl< Traversal, int, int*, const int&, char, const int& >(); - test_type_erased_mix_values_impl< Traversal, MockType, char, const MockType&, short, const MockType& >(); - - // In fact value type should have no effect in the eligibility - // for conversion, hence we should be able to convert it - // completely backwards! - test_type_erased_mix_values_impl< Traversal, int, short, const int&, char, const int& >(); - test_type_erased_mix_values_impl< Traversal, int, char, const int&, int*, const int& >(); - } - - void test_type_erased_mix_values() - { - test_type_erased_mix_values_driver< boost::single_pass_traversal_tag >(); - test_type_erased_mix_values_driver< boost::forward_traversal_tag >(); - test_type_erased_mix_values_driver< boost::bidirectional_traversal_tag >(); - test_type_erased_mix_values_driver< boost::random_access_traversal_tag >(); - } - - void test_type_erased_operator_brackets() - { - typedef boost::adaptors::type_erased<> type_erased_t; - - std::vector c; - 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; - - any_range_type rng = c | type_erased_t(); - - for (int i = 0; i < 10; ++i) - { - BOOST_CHECK_EQUAL( rng[i], i ); - } - } + test_driver< std::list >(); + test_driver< std::vector >(); } + } // anonymous namespace +} // namespace boost_range_adaptor_type_erased_test + boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { - boost::unit_test::test_suite* test - = BOOST_TEST_SUITE( "RangeTestSuite.adaptor.type_erased" ); + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE("RangeTestSuite.adaptor.type_erased"); - test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased ) ); - test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased_single_pass ) ); - test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased_forward ) ); - test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased_bidirectional ) ); - test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased_random_access ) ); - test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased_multiple_different_template_parameter_conversion ) ); - test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased_mix_values ) ); - test->add( BOOST_TEST_CASE( &boost_range_adaptor_type_erased_test::test_type_erased_operator_brackets ) ); + test->add(BOOST_TEST_CASE( + &boost_range_adaptor_type_erased_test::test_type_erased)); return test; } + diff --git a/test/adaptor_test/type_erased_abstract.cpp b/test/adaptor_test/type_erased_abstract.cpp new file mode 100644 index 0000000..dd54890 --- /dev/null +++ b/test/adaptor_test/type_erased_abstract.cpp @@ -0,0 +1,88 @@ +// 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) +// +#include +#include "type_erased_test.hpp" + +#include + +#include + +namespace boost_range_adaptor_type_erased_test +{ + namespace + { + +class dummy_interface +{ +public: + virtual ~dummy_interface() { } + virtual void test() = 0; +protected: + dummy_interface() { } +private: + dummy_interface(const dummy_interface&); + void operator=(const dummy_interface&); +}; + +class dummy_impl + : public dummy_interface +{ +public: + dummy_impl() { } + dummy_impl(const dummy_impl&) { } + dummy_impl& operator=(const dummy_impl&) { return *this; } + virtual void test() { } +}; + +typedef boost::any_range< + dummy_interface, + boost::random_access_traversal_tag, + dummy_interface&, + std::ptrdiff_t +> any_interface_range; + +struct foo_dummy_interface_fn +{ + void operator()(dummy_interface& iface) + { + iface.test(); + } +}; + +void foo_test_dummy_interface_range(any_interface_range rng) +{ + std::for_each(boost::begin(rng), boost::end(rng), + foo_dummy_interface_fn()); +} + +void test_type_erased_abstract() +{ + std::vector v(10); + + any_interface_range r(v); + + foo_test_dummy_interface_range(r); + + foo_test_dummy_interface_range(any_interface_range(v)); +} + + } // anonymous namespace +} // namespace boost_range_adaptor_type_erased_test + +boost::unit_test::test_suite* +init_unit_test_suite(int, char*[]) +{ + boost::unit_test::test_suite* test + = BOOST_TEST_SUITE("RangeTestSuite.adaptor.type_erased_abstract"); + + test->add( + BOOST_TEST_CASE( + &boost_range_adaptor_type_erased_test::test_type_erased_abstract)); + + return test; +} diff --git a/test/adaptor_test/type_erased_bidirectional.cpp b/test/adaptor_test/type_erased_bidirectional.cpp new file mode 100644 index 0000000..3dc86fe --- /dev/null +++ b/test/adaptor_test/type_erased_bidirectional.cpp @@ -0,0 +1,57 @@ +// 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) +// +#include +#include "type_erased_test.hpp" + +#include + +#include +#include +#include + +namespace boost_range_adaptor_type_erased_test +{ + namespace + { + +void test_bidirectional() +{ + test_type_erased_exercise_buffer_types< + std::list, boost::bidirectional_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::deque, boost::bidirectional_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::vector, boost::bidirectional_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::list, boost::bidirectional_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::deque, boost::bidirectional_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::vector, boost::bidirectional_traversal_tag >(); +} + + } // anonymous namespace +} // namespace boost_range_adaptor_type_erased_test + +boost::unit_test::test_suite* +init_unit_test_suite(int, char*[]) +{ + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE("RangeTestSuite.adaptor.type_erased_bidirectional"); + + test->add(BOOST_TEST_CASE( + &boost_range_adaptor_type_erased_test::test_bidirectional)); + + return test; +} + diff --git a/test/adaptor_test/type_erased_brackets.cpp b/test/adaptor_test/type_erased_brackets.cpp new file mode 100644 index 0000000..9d5c7dd --- /dev/null +++ b/test/adaptor_test/type_erased_brackets.cpp @@ -0,0 +1,70 @@ +// 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) +// +#include +#include "type_erased_test.hpp" + +#include + +#include + +namespace boost_range_adaptor_type_erased_test +{ + namespace + { + +void test_operator_brackets() +{ + typedef boost::adaptors::type_erased<> type_erased_t; + + std::vector c; + for (int i = 0; i < 10; ++i) + c.push_back(i); + + 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(); + + for (int i = 0; i < 10; ++i) + { + BOOST_CHECK_EQUAL(rng[i], i); + } +} + + } // anonymous namespace +} // namespace boost_range_adaptor_type_erased_test + +boost::unit_test::test_suite* +init_unit_test_suite(int, char*[]) +{ + boost::unit_test::test_suite* test + = BOOST_TEST_SUITE("RangeTestSuite.adaptor.type_erased_brackets"); + + test->add( + BOOST_TEST_CASE( + &boost_range_adaptor_type_erased_test::test_operator_brackets)); + + return test; +} + diff --git a/test/adaptor_test/type_erased_forward.cpp b/test/adaptor_test/type_erased_forward.cpp new file mode 100644 index 0000000..7f6540f --- /dev/null +++ b/test/adaptor_test/type_erased_forward.cpp @@ -0,0 +1,57 @@ +// 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) +// +#include +#include "type_erased_test.hpp" + +#include + +#include +#include +#include + +namespace boost_range_adaptor_type_erased_test +{ + namespace + { + +void test_forward() +{ + test_type_erased_exercise_buffer_types< + std::list, boost::forward_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::deque, boost::forward_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::vector, boost::forward_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::list, boost::forward_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::deque, boost::forward_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::vector, boost::forward_traversal_tag >(); +} + + } // anonymous namespace +} // namespace boost_range_adaptor_type_erased_test + +boost::unit_test::test_suite* +init_unit_test_suite(int, char*[]) +{ + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE( "RangeTestSuite.adaptor.type_erased_forward" ); + + test->add(BOOST_TEST_CASE( + &boost_range_adaptor_type_erased_test::test_forward)); + + return test; +} + diff --git a/test/adaptor_test/type_erased_mix_values.cpp b/test/adaptor_test/type_erased_mix_values.cpp new file mode 100644 index 0000000..e91644c --- /dev/null +++ b/test/adaptor_test/type_erased_mix_values.cpp @@ -0,0 +1,94 @@ +// 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) +// +#include +#include "type_erased_test.hpp" + +#include + +#include + +namespace boost_range_adaptor_type_erased_test +{ + namespace + { + +template< + class Traversal + , class ValueType + , class SourceValueType + , class SourceReference + , class TargetValueType + , class TargetReference +> +void mix_values_impl() +{ + typedef std::vector Container; + + typedef typename boost::any_range_type_generator< + Container + , SourceValueType + , Traversal + , SourceReference + >::type source_type; + + typedef typename boost::any_range_type_generator< + Container + , TargetValueType + , Traversal + , TargetReference + >::type target_type; + + Container test_data; + for (int i = 0; i < 10; ++i) + test_data.push_back(i); + + const source_type source_data(test_data); + target_type t1(source_data); + BOOST_CHECK_EQUAL_COLLECTIONS(source_data.begin(), source_data.end(), + t1.begin(), t1.end()); + + target_type t2; + t2 = source_data; + BOOST_CHECK_EQUAL_COLLECTIONS(source_data.begin(), source_data.end(), + t2.begin(), t2.end()); +} + +template +void mix_values_driver() +{ + mix_values_impl< + Traversal, + MockType, + MockType2, const MockType&, + MockType, const MockType& + >(); +} + +void mix_values() +{ + mix_values_driver(); + mix_values_driver(); + mix_values_driver(); + mix_values_driver(); +} + + } // anonymous namespace +} // namespace boost_range_adaptor_type_erased_test + +boost::unit_test::test_suite* +init_unit_test_suite(int, char*[]) +{ + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE("RangeTestSuite.adaptor.type_erased_mix_values"); + + test->add(BOOST_TEST_CASE( + &boost_range_adaptor_type_erased_test::mix_values)); + + return test; +} + diff --git a/test/adaptor_test/type_erased_random_access.cpp b/test/adaptor_test/type_erased_random_access.cpp new file mode 100644 index 0000000..39cf1c6 --- /dev/null +++ b/test/adaptor_test/type_erased_random_access.cpp @@ -0,0 +1,50 @@ +// 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) +// +#include +#include "type_erased_test.hpp" + +#include + +#include +#include + +namespace boost_range_adaptor_type_erased_test +{ + namespace + { + +void test_random_access() +{ + test_type_erased_exercise_buffer_types< + std::deque, boost::random_access_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::vector, boost::random_access_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::deque, boost::random_access_traversal_tag >(); + + test_type_erased_exercise_buffer_types< + std::vector, boost::random_access_traversal_tag >(); +} + + } // anonymous namespace +} // namespace boost_range_adaptor_type_erased_test + +boost::unit_test::test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE("RangeTestSuite.adaptor.type_erased_random_access"); + + test->add(BOOST_TEST_CASE( + &boost_range_adaptor_type_erased_test::test_random_access)); + + return test; +} + diff --git a/test/adaptor_test/type_erased_single_pass.cpp b/test/adaptor_test/type_erased_single_pass.cpp new file mode 100644 index 0000000..ad0c4ae --- /dev/null +++ b/test/adaptor_test/type_erased_single_pass.cpp @@ -0,0 +1,57 @@ +// Boost.Range library +// +// Copyright Neil Groves 2010. 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) +// +#include +#include "type_erased_test.hpp" + +#include + +#include +#include +#include + +namespace boost_range_adaptor_type_erased_test +{ + namespace + { + +void test_single_pass() +{ + test_type_erased_exercise_buffer_types< + std::list, boost::single_pass_traversal_tag>(); + + test_type_erased_exercise_buffer_types< + std::deque, boost::single_pass_traversal_tag>(); + + test_type_erased_exercise_buffer_types< + std::vector, boost::single_pass_traversal_tag>(); + + test_type_erased_exercise_buffer_types< + std::list, boost::single_pass_traversal_tag>(); + + test_type_erased_exercise_buffer_types< + std::deque, boost::single_pass_traversal_tag>(); + + test_type_erased_exercise_buffer_types< + std::vector, boost::single_pass_traversal_tag>(); +} + + } // anonymous namespace +} // namespace boost_range_adaptor_type_erased_test + +boost::unit_test::test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE("RangeTestSuite.adaptor.type_erased_single_pass"); + + test->add(BOOST_TEST_CASE( + &boost_range_adaptor_type_erased_test::test_single_pass)); + + return test; +} + diff --git a/test/adaptor_test/type_erased_test.hpp b/test/adaptor_test/type_erased_test.hpp new file mode 100644 index 0000000..9a42e81 --- /dev/null +++ b/test/adaptor_test/type_erased_test.hpp @@ -0,0 +1,289 @@ +// Boost.Range library +// +// Copyright Neil Groves 2010. 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) +// +#ifndef BOOST_RANGE_ADAPTOR_TEST_TYPE_ERASED_TEST_HPP +#define BOOST_RANGE_ADAPTOR_TEST_TYPE_ERASED_TEST_HPP + +#include +#include +#include +#include + +namespace boost_range_adaptor_type_erased_test +{ + +class MockType +{ +public: + MockType() + : m_x(0) + { + } + + MockType(boost::int32_t x) + : m_x(x) + { + } + + boost::int32_t get() const { return m_x; } + + inline bool operator==(const MockType& other) const + { + return m_x == other.m_x; + } + + inline bool operator!=(const MockType& other) const + { + return m_x != other.m_x; + } + +private: + boost::int32_t m_x; +}; + +class MockType2 : public MockType +{ +public: + MockType2() {} + MockType2(boost::int32_t x) : MockType(x) { } + MockType2(const MockType& other) : MockType(other) { } +}; + +inline std::ostream& operator<<(std::ostream& out, const MockType& obj) +{ + out << obj.get(); + return out; +} + +template +void test_type_erased_impl(Container& c) +{ + using namespace boost::adaptors; + typedef typename boost::range_value::type value_type; + typedef typename boost::adaptors::type_erased<> type_erased_t; + + + std::vector output; + + boost::push_back(output, boost::adaptors::type_erase(c, type_erased_t())); + + BOOST_CHECK_EQUAL_COLLECTIONS( output.begin(), output.end(), + c.begin(), c.end() ); + + output.clear(); + boost::push_back(output, c | type_erased_t()); + + BOOST_CHECK_EQUAL_COLLECTIONS( output.begin(), output.end(), + c.begin(), c.end() ); +} + +template +void test_const_and_mutable(Container& c) +{ + test_type_erased_impl(c); + + const Container& const_c = c; + test_type_erased_impl(const_c); +} + +template +void test_driver() +{ + using namespace boost::assign; + + typedef typename boost::range_value::type value_type; + + Container c; + test_const_and_mutable(c); + + c += value_type(1); + test_const_and_mutable(c); + + c += value_type(2); + test_const_and_mutable(c); +} + +template< + class Traversal + , class Container +> +void test_writeable(Container&, boost::single_pass_traversal_tag) +{} + +template< + class Traversal + , class Container +> +void test_writeable(Container& source, boost::forward_traversal_tag) +{ + using namespace boost::adaptors; + + typedef typename boost::range_value::type value_type; + typedef typename boost::range_difference::type difference_type; + typedef typename boost::range_reference::type mutable_reference_type; + typedef boost::any_range< + value_type + , Traversal + , mutable_reference_type + , difference_type + > mutable_any_range; + + mutable_any_range r = source | boost::adaptors::type_erased<>(); + std::vector output_test; + boost::fill(r, value_type(1)); + BOOST_CHECK_EQUAL( boost::distance(r), boost::distance(source) ); + std::vector reference_output(source.size(), value_type(1)); + BOOST_CHECK_EQUAL_COLLECTIONS( reference_output.begin(), reference_output.end(), + r.begin(), r.end() ); + +} + +template< + class Container + , class Traversal + , class Buffer +> +void test_type_erased_impl() +{ + using namespace boost::adaptors; + + typedef typename boost::range_value::type value_type; + + typedef typename boost::any_range_type_generator< + Container + , boost::use_default + , Traversal + , boost::use_default + , boost::use_default + , Buffer + >::type mutable_any_range; + + typedef typename boost::any_range_type_generator< + const Container + , boost::use_default + , Traversal + , boost::use_default + , boost::use_default + , Buffer + >::type const_any_range; + + typedef boost::adaptors::type_erased< + boost::use_default + , Traversal + , boost::use_default + , boost::use_default + , Buffer + > type_erased_t; + + Container source; + for (int i = 0; i < 10; ++i) + source.push_back(value_type(i)); + + mutable_any_range r(source); + BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(), + r.begin(), r.end() ); + + r = mutable_any_range(); + BOOST_CHECK_EQUAL( r.empty(), true ); + + r = source | type_erased_t(); + BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(), + r.begin(), r.end() ); + r = mutable_any_range(); + + r = boost::adaptors::type_erase(source, type_erased_t()); + BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(), + r.begin(), r.end() ); + r = mutable_any_range(); + + test_writeable(source, Traversal()); + + // convert and construct a const any_range from a mutable source + // range + const_any_range cr(source); + BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(), + cr.begin(), cr.end() ); + // assign an empty range and ensure that this correctly results + // in an empty range. This is important for the validity of + // the rest of the tests. + cr = const_any_range(); + BOOST_CHECK_EQUAL( cr.empty(), true ); + + // Test the pipe type_erased adaptor from a constant source + // range to a constant any_range + const Container& const_source = source; + cr = const_any_range(); + cr = const_source | type_erased_t(); + BOOST_CHECK_EQUAL_COLLECTIONS( const_source.begin(), const_source.end(), + cr.begin(), cr.end() ); + + // Test the pipe type erased adaptor from a mutable source + // range to a constant any_range + cr = const_any_range(); + cr = source | type_erased_t(); + BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(), + cr.begin(), cr.end() ); + + // Use the function form of the type_erase adaptor from a constant + // source range + cr = const_any_range(); + cr = boost::adaptors::type_erase(const_source, type_erased_t()); + BOOST_CHECK_EQUAL_COLLECTIONS( const_source.begin(), const_source.end(), + cr.begin(), cr.end() ); + + // Assignment from mutable to const... + cr = const_any_range(); + cr = r; + BOOST_CHECK_EQUAL_COLLECTIONS( cr.begin(), cr.end(), + r.begin(), r.end() ); + + // Converting copy from mutable to const... + cr = const_any_range(); + cr = const_any_range(r); + BOOST_CHECK_EQUAL_COLLECTIONS( cr.begin(), cr.end(), + r.begin(), r.end() ); +} + +template< + class Container + , class Traversal + , class Buffer +> +class test_type_erased_impl_fn +{ +public: + typedef void result_type; + void operator()() + { + test_type_erased_impl< Container, Traversal, Buffer >(); + } +}; + +template< + class Container + , class Traversal +> +void test_type_erased_exercise_buffer_types() +{ + using boost::any_iterator_default_buffer; + using boost::any_iterator_buffer; + using boost::any_iterator_heap_only_buffer; + using boost::any_iterator_stack_only_buffer; + + test_type_erased_impl_fn< Container, Traversal, any_iterator_default_buffer >()(); + test_type_erased_impl_fn< Container, Traversal, any_iterator_heap_only_buffer >()(); + test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<1> >()(); + test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<2> >()(); + test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<32> >()(); + test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<64> >()(); + test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<128> >()(); + test_type_erased_impl_fn< Container, Traversal, any_iterator_stack_only_buffer<128> >()(); +} + +} // namespace boost_range_adaptor_type_erased_test + +#endif // include guard diff --git a/test/adaptor_test/type_erased_tparam_conv.cpp b/test/adaptor_test/type_erased_tparam_conv.cpp new file mode 100644 index 0000000..e235ab3 --- /dev/null +++ b/test/adaptor_test/type_erased_tparam_conv.cpp @@ -0,0 +1,74 @@ +// 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) +// +#include +#include "type_erased_test.hpp" + +#include + +#include +#include + +namespace boost_range_adaptor_type_erased_test +{ + namespace + { + +void template_parameter_conversion() +{ + typedef boost::any_range< + int + , boost::random_access_traversal_tag + , int& + , std::ptrdiff_t + > source_range_type; + + typedef boost::any_range< + int + , boost::single_pass_traversal_tag + , const int& + , std::ptrdiff_t + > target_range_type; + + source_range_type source; + + // Converting via construction + target_range_type t1(source); + + // Converting via assignment + target_range_type t2; + t2 = source; + + // Converting via construction to a type with a reference type + // that is a value + typedef boost::any_range< + int + , boost::single_pass_traversal_tag + , int + , std::ptrdiff_t + > target_range2_type; + + target_range2_type t3(source); + target_range2_type t4; + t4 = source; +} + + } // anonymous namespace +} // namespace boost_range_adaptor_type_erased_test + +boost::unit_test::test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + boost::unit_test::test_suite* test = + BOOST_TEST_SUITE("RangeTestSuite.adaptor.type_erased_tparam_conv"); + + test->add(BOOST_TEST_CASE( + &boost_range_adaptor_type_erased_test::template_parameter_conversion)); + + return test; +} + diff --git a/test/adaptor_test/uniqued.cpp b/test/adaptor_test/uniqued.cpp index 9c96744..fdf5454 100644 --- a/test/adaptor_test/uniqued.cpp +++ b/test/adaptor_test/uniqued.cpp @@ -9,6 +9,10 @@ // For more information, see http://www.boost.org/libs/range/ // #include +#include +#include +#include +#include #include #include @@ -74,9 +78,82 @@ namespace boost uniqued_test_impl< std::set< int > >(); uniqued_test_impl< std::multiset< int > >(); } + +class istring +{ +public: + istring() + : m_value("") + { } + + explicit istring(const char* value) + : m_value(value) + { + } + + bool operator==(istring r) const + { + return boost::iequals(m_value, r.m_value); + } + + bool operator!=(istring r) const + { + return !operator==(r); + } + + inline friend std::ostream& operator<<(std::ostream& out, istring o) + { + return out << o.m_value; + } + + const char* get() const { return m_value; } + +private: + const char* m_value; +}; + +struct istring_to_string +{ + typedef std::string result_type; + + std::string operator()(istring s) const + { + return s.get(); + } +}; + +// This is based on a test-case provided by Eric Neibler. +void uniqued_return_first() +{ + using namespace boost::adaptors; + + std::vector strs; + strs.push_back(istring("hello")); + strs.push_back(istring("hElLo")); + strs.push_back(istring("HELLO")); + strs.push_back(istring("ZZZZ")); + + std::vector output1; + + boost::unique_copy(strs, std::back_inserter(output1)); + + std::vector output2; + boost::push_back(output2, strs | uniqued); + + std::vector test1; + boost::push_back(test1, output1 | transformed(istring_to_string())); + + std::vector test2; + boost::push_back(test2, output2 | transformed(istring_to_string())); + + BOOST_CHECK_EQUAL_COLLECTIONS(test1.begin(), test1.end(), + test2.begin(), test2.end()); } + } // anonymous namespace +} // namespace boost + boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { @@ -85,5 +162,7 @@ init_unit_test_suite(int argc, char* argv[]) test->add( BOOST_TEST_CASE( &boost::uniqued_test ) ); + test->add(BOOST_TEST_CASE(&boost::uniqued_return_first)); + return test; } diff --git a/test/algorithm.cpp b/test/algorithm.cpp index 2160eaf..ebe0496 100644 --- a/test/algorithm.cpp +++ b/test/algorithm.cpp @@ -107,12 +107,15 @@ template void test_random_algorithms(Rng & rng, std::random_access_iterator_tag) { typedef BOOST_DEDUCED_TYPENAME boost::range_iterator::type iterator; - typedef BOOST_DEDUCED_TYPENAME boost::range_value::type value_type; - typedef BOOST_DEDUCED_TYPENAME boost::range_size::type size_type BOOST_RANGE_UNUSED; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_category::type iterator_category; - - + typedef BOOST_DEDUCED_TYPENAME boost::range_value::type value_type; + + typedef BOOST_DEDUCED_TYPENAME boost::range_size::type + size_type BOOST_RANGE_UNUSED; + + typedef BOOST_DEDUCED_TYPENAME boost::iterator_category::type + iterator_category BOOST_RANGE_UNUSED; + // just make sure these compile (for now) if(0) { diff --git a/test/algorithm_test/inplace_merge.cpp b/test/algorithm_test/inplace_merge.cpp index d0cad73..948e95e 100644 --- a/test/algorithm_test/inplace_merge.cpp +++ b/test/algorithm_test/inplace_merge.cpp @@ -28,7 +28,9 @@ namespace boost void test(Container1& cont1, Container2& cont2) { typedef BOOST_DEDUCED_TYPENAME Container1::value_type value_t; - typedef BOOST_DEDUCED_TYPENAME std::vector::iterator iterator_t; + + typedef BOOST_DEDUCED_TYPENAME std::vector::iterator + iterator_t BOOST_RANGE_UNUSED; std::vector reference_target(cont1.begin(), cont1.end()); reference_target.insert(reference_target.end(), @@ -74,7 +76,8 @@ namespace boost void test_pred(Container1 cont1, Container2 cont2, BinaryPredicate pred) { typedef BOOST_DEDUCED_TYPENAME Container1::value_type value_t; - typedef BOOST_DEDUCED_TYPENAME std::vector::iterator iterator_t; + typedef BOOST_DEDUCED_TYPENAME std::vector::iterator + iterator_t BOOST_RANGE_UNUSED; sort_container(cont1, pred); sort_container(cont2, pred); diff --git a/test/algorithm_test/max_element.cpp b/test/algorithm_test/max_element.cpp index 9a26099..d4e87d5 100644 --- a/test/algorithm_test/max_element.cpp +++ b/test/algorithm_test/max_element.cpp @@ -106,8 +106,11 @@ namespace boost_range_test_algorithm_max_element { using namespace boost::assign; - typedef BOOST_DEDUCED_TYPENAME Container::value_type value_t; - typedef BOOST_DEDUCED_TYPENAME boost::remove_const::type container_t; + typedef BOOST_DEDUCED_TYPENAME Container::value_type + value_t BOOST_RANGE_UNUSED; + + typedef BOOST_DEDUCED_TYPENAME boost::remove_const::type + container_t; boost::range_test::range_return_test_driver test_driver; diff --git a/test/algorithm_test/min_element.cpp b/test/algorithm_test/min_element.cpp index 0f9fa68..bb92d2c 100644 --- a/test/algorithm_test/min_element.cpp +++ b/test/algorithm_test/min_element.cpp @@ -104,8 +104,11 @@ namespace boost_range_test_algorithm_min_element { using namespace boost::assign; - typedef BOOST_DEDUCED_TYPENAME Container::value_type value_t; - typedef BOOST_DEDUCED_TYPENAME boost::remove_const::type container_t; + typedef BOOST_DEDUCED_TYPENAME Container::value_type + value_t BOOST_RANGE_UNUSED; + + typedef BOOST_DEDUCED_TYPENAME boost::remove_const::type + container_t; boost::range_test::range_return_test_driver test_driver; diff --git a/test/algorithm_test/mismatch.cpp b/test/algorithm_test/mismatch.cpp index 2336e59..407b5fc 100644 --- a/test/algorithm_test/mismatch.cpp +++ b/test/algorithm_test/mismatch.cpp @@ -160,15 +160,17 @@ namespace boost MutableContainer2 cont2; const Container2& cref_cont2 = cont2; - typedef BOOST_DEDUCED_TYPENAME Container1::iterator iterator1_t; - typedef BOOST_DEDUCED_TYPENAME Container1::const_iterator const_iterator1_t; - typedef BOOST_DEDUCED_TYPENAME Container2::iterator iterator2_t; - typedef BOOST_DEDUCED_TYPENAME Container2::const_iterator const_iterator2_t; + typedef BOOST_DEDUCED_TYPENAME Container1::iterator + iterator1_t BOOST_RANGE_UNUSED; - typedef std::pair pair_mmit_t; - typedef std::pair pair_cmit_t; - typedef std::pair pair_mcit_t; - typedef std::pair pair_ccit_t; + typedef BOOST_DEDUCED_TYPENAME Container1::const_iterator + const_iterator1_t BOOST_RANGE_UNUSED; + + typedef BOOST_DEDUCED_TYPENAME Container2::iterator + iterator2_t BOOST_RANGE_UNUSED; + + typedef BOOST_DEDUCED_TYPENAME Container2::const_iterator + const_iterator2_t BOOST_RANGE_UNUSED; eval_mismatch(cont1, cont2, cont1.end(), cont2.end()); eval_mismatch(cont1, cont2, std::equal_to(), cont1.end(), cont2.end()); diff --git a/test/algorithm_test/random_shuffle.cpp b/test/algorithm_test/random_shuffle.cpp index 410749a..71915ee 100644 --- a/test/algorithm_test/random_shuffle.cpp +++ b/test/algorithm_test/random_shuffle.cpp @@ -90,7 +90,8 @@ namespace boost template void test_random_shuffle_nogen_impl(Container& cont) { - typedef BOOST_DEDUCED_TYPENAME range_iterator::type iterator_t; + typedef BOOST_DEDUCED_TYPENAME range_iterator::type + iterator_t BOOST_RANGE_UNUSED; const int MAX_RETRIES = 10000; diff --git a/test/algorithm_test/remove_copy.cpp b/test/algorithm_test/remove_copy.cpp index 4050ef4..b3eb8e2 100644 --- a/test/algorithm_test/remove_copy.cpp +++ b/test/algorithm_test/remove_copy.cpp @@ -36,7 +36,8 @@ namespace typedef typename boost::range_value::type value_type; std::vector reference; - typedef BOOST_DEDUCED_TYPENAME std::vector::iterator iterator_t; + typedef BOOST_DEDUCED_TYPENAME std::vector::iterator + iterator_t BOOST_RANGE_UNUSED; test_append( std::remove_copy(c.begin(), c.end(), diff --git a/test/algorithm_test/replace_copy.cpp b/test/algorithm_test/replace_copy.cpp index 6ae12e2..5629856 100644 --- a/test/algorithm_test/replace_copy.cpp +++ b/test/algorithm_test/replace_copy.cpp @@ -38,7 +38,8 @@ namespace typedef typename boost::range_value::type value_type; std::vector reference; - typedef BOOST_DEDUCED_TYPENAME std::vector::iterator iterator_t; + typedef BOOST_DEDUCED_TYPENAME std::vector::iterator + iterator_t BOOST_RANGE_UNUSED; test_append( std::replace_copy(c.begin(), c.end(), diff --git a/test/algorithm_test/rotate_copy.cpp b/test/algorithm_test/rotate_copy.cpp index 5615479..05aa4d2 100644 --- a/test/algorithm_test/rotate_copy.cpp +++ b/test/algorithm_test/rotate_copy.cpp @@ -31,11 +31,14 @@ namespace template void test_rotate_copy_impl(Container& cont, Iterator where_it) { - typedef BOOST_DEDUCED_TYPENAME boost::range_value::type value_type; + typedef BOOST_DEDUCED_TYPENAME boost::range_value::type + value_type; + std::vector reference; std::vector test; - typedef BOOST_DEDUCED_TYPENAME boost::range_iterator::type iterator_t; + typedef BOOST_DEDUCED_TYPENAME boost::range_iterator::type + iterator_t BOOST_RANGE_UNUSED; test_append( std::rotate_copy(cont.begin(), where_it, cont.end(), diff --git a/test/algorithm_test/search_n.cpp b/test/algorithm_test/search_n.cpp index 246d397..76f5b78 100644 --- a/test/algorithm_test/search_n.cpp +++ b/test/algorithm_test/search_n.cpp @@ -60,7 +60,9 @@ namespace Integer count, const Value& value, BinaryPredicate pred) { - typedef typename std::iterator_traits::iterator_category cat_t; + typedef typename std::iterator_traits< + ForwardIterator + >::iterator_category cat_t BOOST_RANGE_UNUSED; if (count <= 0) return first; diff --git a/test/compat3.cpp b/test/compat3.cpp index 5249c58..e4e4c83 100644 --- a/test/compat3.cpp +++ b/test/compat3.cpp @@ -10,6 +10,7 @@ #include #include +#include #include enum Container {}; @@ -51,6 +52,7 @@ void compat1() { std::vector v; iterator_of< std::vector >::type i = v.begin(); + boost::ignore_unused_variable_warning(i); } #include diff --git a/test/counting_range.cpp b/test/counting_range.cpp index 18aceba..d1f1d3f 100644 --- a/test/counting_range.cpp +++ b/test/counting_range.cpp @@ -11,6 +11,7 @@ // Disable a warning from since this noise might // stop us detecting a problem in our code. #include +#include #include #include @@ -51,6 +52,22 @@ namespace boost counting_range_test_impl(-100, 100); counting_range_test_impl(50, 55); } + + void counting_range_test_range() + { + std::vector v; + for (int i = 0; i < 10; ++i) + v.push_back(i); + + std::vector::iterator> x; + push_back(x, counting_range(v)); + + std::vector t; + push_back(t, x | boost::adaptors::indirected); + + BOOST_CHECK_EQUAL_COLLECTIONS(t.begin(), t.end(), + v.begin(), v.end()); + } } void counting_range_test() diff --git a/test/extension_size.cpp b/test/extension_size.cpp index 202f465..b9cc1b2 100644 --- a/test/extension_size.cpp +++ b/test/extension_size.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff --git a/test/iterator_pair.cpp b/test/iterator_pair.cpp index 997b5fb..ba13d75 100644 --- a/test/iterator_pair.cpp +++ b/test/iterator_pair.cpp @@ -63,18 +63,24 @@ void check_iterator_pair() BOOST_CHECK( boost::begin( pair ) == pair.first ); BOOST_CHECK( boost::end( pair ) == pair.second ); BOOST_CHECK( boost::empty( pair ) == (pair.first == pair.second) ); - BOOST_CHECK( boost::size( pair ) == std::distance( pair.first, pair.second ) ); + BOOST_CHECK( boost::size( pair ) == + static_cast( + std::distance(pair.first, pair.second)) ); BOOST_CHECK( boost::begin( const_pair ) == const_pair.first ); BOOST_CHECK( boost::end( const_pair ) == const_pair.second ); BOOST_CHECK( boost::empty( const_pair ) == (const_pair.first == const_pair.second) ); - BOOST_CHECK( boost::size( const_pair ) == std::distance( const_pair.first, const_pair.second ) ); + BOOST_CHECK( boost::size( const_pair ) == + static_cast( + std::distance(const_pair.first, const_pair.second)) ); BOOST_CHECK( boost::begin( constness_pair ) == constness_pair.first ); BOOST_CHECK( boost::end( constness_pair ) == constness_pair.second ); BOOST_CHECK( boost::empty( constness_pair ) == (constness_pair.first == const_pair.second) ); - BOOST_CHECK( boost::size( constness_pair ) == std::distance( constness_pair.first, constness_pair.second ) ); - + BOOST_CHECK( boost::size( constness_pair ) == + static_cast( + std::distance(constness_pair.first, + constness_pair.second)) ); } 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; +} diff --git a/test/join.cpp b/test/join.cpp index cff3f35..586f05c 100644 --- a/test/join.cpp +++ b/test/join.cpp @@ -8,7 +8,12 @@ // // For more information, see http://www.boost.org/libs/range/ // +// Credits: +// Trac 7376 - was raised by Leonid Gershanovich and his sample was used to +// make the test case to cover this condition. +// #include +#include #include #include @@ -274,6 +279,106 @@ namespace boost boost::push_back(joined, join(v1, v2)); } + namespace trac7376 + { + struct base_type + { + explicit base_type(boost::int32_t value) + : value(value) + { + } + + virtual boost::int32_t get() const = 0; + + boost::int32_t value; + }; + + struct derived_type1 + : base_type + { + derived_type1(boost::int32_t value) + : base_type(value) + { + } + + virtual boost::int32_t get() const + { + return value * 2; + } + }; + + struct derived_type2 + : base_type + { + derived_type2(boost::int32_t value) + : base_type(value) + { + } + + virtual boost::int32_t get() const + { + return value * 4; + } + }; + + struct apply_get + { + typedef boost::int32_t result_type; + result_type operator()(const base_type& arg) const + { + return arg.get(); + } + }; + + void test_reference_types() + { + using namespace boost::adaptors; + + typedef boost::range_detail::join_iterator< + std::vector::iterator, + std::vector::iterator, + const base_type&, + const base_type& + > join_iterator_t; + + std::vector reference_output; + + std::vector x; + for (boost::int32_t i = 0; i < 10; ++i) + { + x.push_back(derived_type1(i)); + reference_output.push_back(i * 2); + } + + std::vector y; + for (boost::int32_t i = 0; i < 10; ++i) + { + y.push_back(derived_type2(i)); + reference_output.push_back(i * 4); + } + + join_iterator_t it( + x, + y, + boost::range_detail::join_iterator_begin_tag()); + + std::vector output; + boost::push_back( + output, + boost::make_iterator_range( + join_iterator_t( + x, y, + boost::range_detail::join_iterator_begin_tag()), + join_iterator_t( + x, y, + boost::range_detail::join_iterator_end_tag())) + | transformed(apply_get())); + + BOOST_CHECK_EQUAL_COLLECTIONS( + output.begin(), output.end(), + reference_output.begin(), reference_output.end()); + } + } // namespace trac7376 } } @@ -285,6 +390,7 @@ init_unit_test_suite(int argc, char* argv[]) test->add( BOOST_TEST_CASE( &boost::join_test ) ); test->add( BOOST_TEST_CASE( &boost::test_join_iterator_reference_type_constness_ticket8483 ) ); + test->add( BOOST_TEST_CASE( &boost::trac7376::test_reference_types ) ); return test; } diff --git a/test/ticket_5811_indirected_optional.cpp b/test/ticket_5811_indirected_optional.cpp new file mode 100644 index 0000000..1279a4a --- /dev/null +++ b/test/ticket_5811_indirected_optional.cpp @@ -0,0 +1,48 @@ +// 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 +{ + namespace + { + void test_ticket_5811_indirected_optional() + { + std::vector > v; + std::vector r; + for (int i = 0; i < 10; ++i) + { + v.push_back(i); + r.push_back(i); + } + BOOST_CHECK_EQUAL_COLLECTIONS(r.begin(), r.end(), + v.begin(), v.end()); + } + } +} + +boost::unit_test::test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + boost::unit_test::test_suite* test + = BOOST_TEST_SUITE("RangeTestSuite.ticket_5811_indirected_optional"); + + test->add(BOOST_TEST_CASE(&boost::test_ticket_5811_indirected_optional)); + + return test; +} diff --git a/test/ticket_6715_iterator_range_equality.cpp b/test/ticket_6715_iterator_range_equality.cpp new file mode 100644 index 0000000..96a61a9 --- /dev/null +++ b/test/ticket_6715_iterator_range_equality.cpp @@ -0,0 +1,51 @@ +// 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 + +namespace boost +{ + namespace + { + class str_ref : public boost::iterator_range + { + public: + explicit str_ref(const std::string& str) + : boost::iterator_range( + str.c_str(), str.c_str() + str.size()) + { + } + }; + + void test_ticket_6715_iterator_range_equality() + { + str_ref a("test"); + str_ref b("test"); + BOOST_CHECK(a == b); + } + } +} + +boost::unit_test::test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + boost::unit_test::test_suite* test + = BOOST_TEST_SUITE( + "RangeTestSuite.ticket_6715_iterator_range_equality"); + + test->add(BOOST_TEST_CASE( + &boost::test_ticket_6715_iterator_range_equality)); + + return test; +}