From 63da6f571331a14f8ef2fe7bdafd209a3b107f4e Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Thu, 7 Mar 2013 15:37:08 +0000 Subject: [PATCH] Merge Algorithm changes to release; hex code cleanups; gather iterator requirements; copy_while and copy_until interface changes [SVN r83347] --- doc/gather.qbk | 16 ++-- include/boost/algorithm/cxx11/copy_if.hpp | 21 +++-- include/boost/algorithm/gather.hpp | 19 ++-- include/boost/algorithm/hex.hpp | 32 +++---- test/copy_if_test1.cpp | 101 ++++++++++++++++++++-- test/gather_test1.cpp | 4 +- test/search_test2.cpp | 1 + test/search_test3.cpp | 1 + 8 files changed, 141 insertions(+), 54 deletions(-) diff --git a/doc/gather.qbk b/doc/gather.qbk index f46429a..b50e85a 100644 --- a/doc/gather.qbk +++ b/doc/gather.qbk @@ -22,13 +22,13 @@ There are two versions; one takes two iterators, and the other takes a range. `` namespace boost { namespace algorithm { -template -std::pair -gather ( ForwardIterator first, ForwardIterator last, ForwardIterator pivot, Pred pred ); +template +std::pair +gather ( BidirectionalIterator first, BidirectionalIterator last, BidirectionalIterator pivot, Pred pred ); -template -std::pair::type, typename boost::range_iterator::type> -gather ( ForwardRange &range, typename boost::range_iterator::type pivot, Pred pred ); +template +std::pair::type, typename boost::range_iterator::type> +gather ( const BidirectionalRange &range, typename boost::range_iterator::type pivot, Pred pred ); }} `` @@ -53,11 +53,11 @@ where `first` and `second` are the fields of the pair that is returned by the ca [heading Iterator Requirements] -`gather` work on all iterators except input or output iterators. +`gather` work on bidirectional iterators or better. This requirement comes from the usage of `stable_partition`, which requires bidirectional iterators. Some standard libraries (libstdc++ and libc++, for example) have implementations of `stable_partition` that work with forward iterators. If that is the case, then `gather` will work with forward iterators as well. [heading Storage Requirements] -`gather` uses stable_partition, which will attempt to allocate temporary memory, but will work in-situ if there is none available. +`gather` uses `stable_partition`, which will attempt to allocate temporary memory, but will work in-situ if there is none available. [heading Complexity] diff --git a/include/boost/algorithm/cxx11/copy_if.hpp b/include/boost/algorithm/cxx11/copy_if.hpp index 8591cb5..88b79b5 100644 --- a/include/boost/algorithm/cxx11/copy_if.hpp +++ b/include/boost/algorithm/cxx11/copy_if.hpp @@ -63,7 +63,7 @@ OutputIterator copy_if ( const Range &r, OutputIterator result, Predicate p ) /// \fn copy_while ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) /// \brief Copies all the elements at the start of the input range that /// satisfy the predicate to the output range. -/// \return The updated output iterator +/// \return The updated input and output iterators /// /// \param first The start of the input sequence /// \param last One past the end of the input sequence @@ -71,25 +71,26 @@ OutputIterator copy_if ( const Range &r, OutputIterator result, Predicate p ) /// \param p A predicate for testing the elements of the range /// template -OutputIterator copy_while ( InputIterator first, InputIterator last, - OutputIterator result, Predicate p ) +std::pair +copy_while ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) { for ( ; first != last && p(*first); ++first ) *result++ = *first; - return result; + return std::make_pair(first, result); } /// \fn copy_while ( const Range &r, OutputIterator result, Predicate p ) /// \brief Copies all the elements at the start of the input range that /// satisfy the predicate to the output range. -/// \return The updated output iterator +/// \return The updated input and output iterators /// /// \param r The input range /// \param result An output iterator to write the results into /// \param p A predicate for testing the elements of the range /// template -OutputIterator copy_while ( const Range &r, OutputIterator result, Predicate p ) +std::pair::type, OutputIterator> +copy_while ( const Range &r, OutputIterator result, Predicate p ) { return boost::algorithm::copy_while (boost::begin (r), boost::end(r), result, p); } @@ -106,11 +107,12 @@ OutputIterator copy_while ( const Range &r, OutputIterator result, Predicate p ) /// \param p A predicate for testing the elements of the range /// template -OutputIterator copy_until ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) +std::pair +copy_until ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) { for ( ; first != last && !p(*first); ++first ) *result++ = *first; - return result; + return std::make_pair(first, result); } /// \fn copy_until ( const Range &r, OutputIterator result, Predicate p ) @@ -123,7 +125,8 @@ OutputIterator copy_until ( InputIterator first, InputIterator last, OutputItera /// \param p A predicate for testing the elements of the range /// template -OutputIterator copy_until ( const Range &r, OutputIterator result, Predicate p ) +std::pair::type, OutputIterator> +copy_until ( const Range &r, OutputIterator result, Predicate p ) { return boost::algorithm::copy_until (boost::begin (r), boost::end(r), result, p); } diff --git a/include/boost/algorithm/gather.hpp b/include/boost/algorithm/gather.hpp index 3624d33..944bc94 100644 --- a/include/boost/algorithm/gather.hpp +++ b/include/boost/algorithm/gather.hpp @@ -18,7 +18,7 @@ */ #ifndef BOOST_ALGORITHM_GATHER_HPP -#define ADOBE_ALGORITHM_GATHER_HPP +#define BOOST_ALGORITHM_GATHER_HPP #include // for std::stable_partition #include @@ -80,9 +80,10 @@ namespace boost { namespace algorithm { */ template < - typename ForwardIterator, // Iter models ForwardIterator - typename Pred> // Pred models UnaryPredicate -std::pair gather ( ForwardIterator first, ForwardIterator last, ForwardIterator pivot, Pred pred ) + typename BidirectionalIterator, // Iter models BidirectionalIterator + typename Pred> // Pred models UnaryPredicate +std::pair gather + ( BidirectionalIterator first, BidirectionalIterator last, BidirectionalIterator pivot, Pred pred ) { // The first call partitions everything up to (but not including) the pivot element, // while the second call partitions the rest of the sequence. @@ -99,14 +100,14 @@ std::pair gather ( ForwardIterator first, Forwa */ template < - typename ForwardRange, // + typename BidirectionalRange, // typename Pred> // Pred models UnaryPredicate std::pair< - typename boost::range_iterator::type, - typename boost::range_iterator::type> + typename boost::range_iterator::type, + typename boost::range_iterator::type> gather ( - ForwardRange &range, - typename boost::range_iterator::type pivot, + const BidirectionalRange &range, + typename boost::range_iterator::type pivot, Pred pred ) { return boost::algorithm::gather ( boost::begin ( range ), boost::end ( range ), pivot, pred ); diff --git a/include/boost/algorithm/hex.hpp b/include/boost/algorithm/hex.hpp index 439ec46..2adb0be 100644 --- a/include/boost/algorithm/hex.hpp +++ b/include/boost/algorithm/hex.hpp @@ -10,12 +10,6 @@ /* General problem - turn a sequence of integral types into a sequence of hexadecimal characters. - and back. - -TO DO: - 1. these should really only work on integral types. (see the >> and << operations) - -- this is done, I think. - 2. The 'value_type_or_char' struct is really a hack. - -- but it's a better hack now that it works with back_insert_iterators */ /// \file hex.hpp @@ -42,11 +36,11 @@ namespace boost { namespace algorithm { /*! \struct hex_decode_error \brief Base exception class for all hex decoding errors - +*/ /*! \struct non_hex_input \brief Thrown when a non-hex value (0-9, A-F) encountered when decoding. Contains the offending character - +*/ /*! \struct not_enough_input \brief Thrown when the input sequence unexpectedly ends @@ -69,18 +63,16 @@ namespace detail { return std::copy ( res, res + num_hex_digits, out ); } -// this needs to be in an un-named namespace because it is not a template -// and might get included in several compilation units. This could cause -// multiple definition errors at link time. - namespace { - unsigned hex_char_to_int ( char c ) { - if ( c >= '0' && c <= '9' ) return c - '0'; - if ( c >= 'A' && c <= 'F' ) return c - 'A' + 10; - if ( c >= 'a' && c <= 'f' ) return c - 'a' + 10; - BOOST_THROW_EXCEPTION (non_hex_input() << bad_char (c)); - return 0; // keep dumb compilers happy + template + unsigned char hex_char_to_int ( T val ) { + char c = static_cast ( val ); + unsigned retval = 0; + if ( c >= '0' && c <= '9' ) retval = c - '0'; + else if ( c >= 'A' && c <= 'F' ) retval = c - 'A' + 10; + else if ( c >= 'a' && c <= 'f' ) retval = c - 'a' + 10; + else BOOST_THROW_EXCEPTION (non_hex_input() << bad_char (c)); + return retval; } - } // My own iterator_traits class. // It is here so that I can "reach inside" some kinds of output iterators @@ -134,7 +126,7 @@ namespace detail { for ( std::size_t i = 0; i < 2 * sizeof ( T ); ++i, ++first ) { if ( pred ( first, last )) BOOST_THROW_EXCEPTION (not_enough_input ()); - res = ( 16 * res ) + hex_char_to_int (static_cast (*first)); + res = ( 16 * res ) + hex_char_to_int (*first); } *out = res; diff --git a/test/copy_if_test1.cpp b/test/copy_if_test1.cpp index b237055..59944bc 100644 --- a/test/copy_if_test1.cpp +++ b/test/copy_if_test1.cpp @@ -20,6 +20,7 @@ #include #include +#include namespace ba = boost::algorithm; // namespace ba = boost; @@ -30,7 +31,7 @@ bool is_even ( int v ) { return v % 2 == 0; } bool is_odd ( int v ) { return v % 2 == 1; } template -void test_sequence ( Container const &c ) { +void test_copy_if ( Container const &c ) { typedef typename Container::value_type value_type; std::vector v; @@ -48,13 +49,13 @@ void test_sequence ( Container const &c ) { v.clear (); ba::copy_if ( c.begin (), c.end (), back_inserter ( v ), is_true); BOOST_CHECK ( v.size () == c.size ()); - BOOST_CHECK ( std::equal ( c.begin (), c.end (), v.begin ())); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); v.clear (); ba::copy_if ( c, back_inserter ( v ), is_true); BOOST_CHECK ( v.size () == c.size ()); BOOST_CHECK ( v.size () == c.size ()); - BOOST_CHECK ( std::equal ( c.begin (), c.end (), v.begin ())); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); // Some of the elements v.clear (); @@ -69,16 +70,106 @@ void test_sequence ( Container const &c ) { } +template +void test_copy_while ( Container const &c ) { + + typedef typename Container::value_type value_type; + typename Container::const_iterator it; + std::vector v; + +// None of the elements + v.clear (); + ba::copy_while ( c.begin (), c.end (), back_inserter ( v ), is_false); + BOOST_CHECK ( v.size () == 0 ); + + v.clear (); + ba::copy_while ( c, back_inserter ( v ), is_false); + BOOST_CHECK ( v.size () == 0 ); + +// All the elements + v.clear (); + ba::copy_while ( c.begin (), c.end (), back_inserter ( v ), is_true); + BOOST_CHECK ( v.size () == c.size ()); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + + v.clear (); + ba::copy_while ( c, back_inserter ( v ), is_true); + BOOST_CHECK ( v.size () == c.size ()); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + +// Some of the elements + v.clear (); + it = ba::copy_while ( c.begin (), c.end (), back_inserter ( v ), is_even ).first; + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( it == c.end () || !is_even ( *it )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even )); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + + v.clear (); + it = ba::copy_while ( c, back_inserter ( v ), is_even ).first; + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( it == c.end () || !is_even ( *it )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even )); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + } + +template +void test_copy_until ( Container const &c ) { + + typedef typename Container::value_type value_type; + typename Container::const_iterator it; + std::vector v; + +// None of the elements + v.clear (); + ba::copy_until ( c.begin (), c.end (), back_inserter ( v ), is_true); + BOOST_CHECK ( v.size () == 0 ); + + v.clear (); + ba::copy_until ( c, back_inserter ( v ), is_true); + BOOST_CHECK ( v.size () == 0 ); + +// All the elements + v.clear (); + ba::copy_until ( c.begin (), c.end (), back_inserter ( v ), is_false); + BOOST_CHECK ( v.size () == c.size ()); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + + v.clear (); + ba::copy_until ( c, back_inserter ( v ), is_false); + BOOST_CHECK ( v.size () == c.size ()); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + +// Some of the elements + v.clear (); + it = ba::copy_until ( c.begin (), c.end (), back_inserter ( v ), is_even ).first; + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( it == c.end () || is_even ( *it )); + BOOST_CHECK ( ba::none_of ( v.begin (), v.end (), is_even )); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + + v.clear (); + it = ba::copy_until ( c, back_inserter ( v ), is_even ).first; + BOOST_CHECK ( v.size () == (size_t) std::distance ( c.begin (), it )); + BOOST_CHECK ( it == c.end () || is_even ( *it )); + BOOST_CHECK ( ba::none_of ( v.begin (), v.end (), is_even )); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + } + void test_sequence1 () { std::vector v; for ( int i = 5; i < 15; ++i ) v.push_back ( i ); - test_sequence ( v ); + test_copy_if ( v ); + test_copy_while ( v ); + test_copy_until ( v ); std::list l; for ( int i = 25; i > 15; --i ) l.push_back ( i ); - test_sequence ( l ); + test_copy_if ( l ); + test_copy_while ( l ); + test_copy_until ( l ); } diff --git a/test/gather_test1.cpp b/test/gather_test1.cpp index 0e57b6e..28f63b5 100644 --- a/test/gather_test1.cpp +++ b/test/gather_test1.cpp @@ -55,14 +55,12 @@ void test_iterators ( Iterator first, Iterator last, Predicate comp, std::size_t template void test_iterator_types ( const Container &c, Predicate comp, std::size_t offset ) { typedef std::vector vec; - typedef forward_iterator FI; + typedef bidirectional_iterator BDI; typedef random_access_iterator RAI; vec v; v.assign ( c.begin (), c.end ()); - test_iterators ( FI ( v.begin ()), FI ( v.end ()), comp, offset ); - v.assign ( c.begin (), c.end ()); test_iterators ( BDI ( v.begin ()), BDI ( v.end ()), comp, offset ); v.assign ( c.begin (), c.end ()); test_iterators ( RAI ( v.begin ()), RAI ( v.end ()), comp, offset ); diff --git a/test/search_test2.cpp b/test/search_test2.cpp index 4631105..4d772ca 100644 --- a/test/search_test2.cpp +++ b/test/search_test2.cpp @@ -14,6 +14,7 @@ #define BOOST_TEST_MAIN #include +#include // for clock_t #include #include #include diff --git a/test/search_test3.cpp b/test/search_test3.cpp index ee32f6a..96226cd 100644 --- a/test/search_test3.cpp +++ b/test/search_test3.cpp @@ -14,6 +14,7 @@ #define BOOST_TEST_MAIN #include +#include // for clock_t #include #include #include