Merge Algorithm changes to release; hex code cleanups; gather iterator requirements; copy_while and copy_until interface changes

[SVN r83347]
This commit is contained in:
Marshall Clow
2013-03-07 15:37:08 +00:00
parent 2381d0bdac
commit 63da6f5713
8 changed files with 141 additions and 54 deletions

View File

@ -22,13 +22,13 @@ There are two versions; one takes two iterators, and the other takes a range.
`` ``
namespace boost { namespace algorithm { namespace boost { namespace algorithm {
template <typename ForwardIterator, typename Pred> template <typename BidirectionalIterator, typename Pred>
std::pair<ForwardIterator,ForwardIterator> std::pair<BidirectionalIterator,BidirectionalIterator>
gather ( ForwardIterator first, ForwardIterator last, ForwardIterator pivot, Pred pred ); gather ( BidirectionalIterator first, BidirectionalIterator last, BidirectionalIterator pivot, Pred pred );
template <typename ForwardRange, typename Pred> template <typename BidirectionalRange, typename Pred>
std::pair<typename boost::range_iterator<ForwardRange>::type, typename boost::range_iterator<ForwardRange>::type> std::pair<typename boost::range_iterator<const BidirectionalRange>::type, typename boost::range_iterator<const BidirectionalRange>::type>
gather ( ForwardRange &range, typename boost::range_iterator<ForwardRange>::type pivot, Pred pred ); gather ( const BidirectionalRange &range, typename boost::range_iterator<const BidirectionalRange>::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] [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] [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] [heading Complexity]

View File

@ -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 ) /// \fn copy_while ( InputIterator first, InputIterator last, OutputIterator result, Predicate p )
/// \brief Copies all the elements at the start of the input range that /// \brief Copies all the elements at the start of the input range that
/// satisfy the predicate to the output range. /// 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 first The start of the input sequence
/// \param last One past the end 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 /// \param p A predicate for testing the elements of the range
/// ///
template<typename InputIterator, typename OutputIterator, typename Predicate> template<typename InputIterator, typename OutputIterator, typename Predicate>
OutputIterator copy_while ( InputIterator first, InputIterator last, std::pair<InputIterator, OutputIterator>
OutputIterator result, Predicate p ) copy_while ( InputIterator first, InputIterator last, OutputIterator result, Predicate p )
{ {
for ( ; first != last && p(*first); ++first ) for ( ; first != last && p(*first); ++first )
*result++ = *first; *result++ = *first;
return result; return std::make_pair(first, result);
} }
/// \fn copy_while ( const Range &r, OutputIterator result, Predicate p ) /// \fn copy_while ( const Range &r, OutputIterator result, Predicate p )
/// \brief Copies all the elements at the start of the input range that /// \brief Copies all the elements at the start of the input range that
/// satisfy the predicate to the output range. /// 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 r The input range
/// \param result An output iterator to write the results into /// \param result An output iterator to write the results into
/// \param p A predicate for testing the elements of the range /// \param p A predicate for testing the elements of the range
/// ///
template<typename Range, typename OutputIterator, typename Predicate> template<typename Range, typename OutputIterator, typename Predicate>
OutputIterator copy_while ( const Range &r, OutputIterator result, Predicate p ) std::pair<typename boost::range_iterator<const Range>::type, OutputIterator>
copy_while ( const Range &r, OutputIterator result, Predicate p )
{ {
return boost::algorithm::copy_while (boost::begin (r), boost::end(r), result, 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 /// \param p A predicate for testing the elements of the range
/// ///
template<typename InputIterator, typename OutputIterator, typename Predicate> template<typename InputIterator, typename OutputIterator, typename Predicate>
OutputIterator copy_until ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) std::pair<InputIterator, OutputIterator>
copy_until ( InputIterator first, InputIterator last, OutputIterator result, Predicate p )
{ {
for ( ; first != last && !p(*first); ++first ) for ( ; first != last && !p(*first); ++first )
*result++ = *first; *result++ = *first;
return result; return std::make_pair(first, result);
} }
/// \fn copy_until ( const Range &r, OutputIterator result, Predicate p ) /// \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 /// \param p A predicate for testing the elements of the range
/// ///
template<typename Range, typename OutputIterator, typename Predicate> template<typename Range, typename OutputIterator, typename Predicate>
OutputIterator copy_until ( const Range &r, OutputIterator result, Predicate p ) std::pair<typename boost::range_iterator<const Range>::type, OutputIterator>
copy_until ( const Range &r, OutputIterator result, Predicate p )
{ {
return boost::algorithm::copy_until (boost::begin (r), boost::end(r), result, p); return boost::algorithm::copy_until (boost::begin (r), boost::end(r), result, p);
} }

View File

@ -18,7 +18,7 @@
*/ */
#ifndef BOOST_ALGORITHM_GATHER_HPP #ifndef BOOST_ALGORITHM_GATHER_HPP
#define ADOBE_ALGORITHM_GATHER_HPP #define BOOST_ALGORITHM_GATHER_HPP
#include <algorithm> // for std::stable_partition #include <algorithm> // for std::stable_partition
#include <functional> #include <functional>
@ -80,9 +80,10 @@ namespace boost { namespace algorithm {
*/ */
template < template <
typename ForwardIterator, // Iter models ForwardIterator typename BidirectionalIterator, // Iter models BidirectionalIterator
typename Pred> // Pred models UnaryPredicate typename Pred> // Pred models UnaryPredicate
std::pair<ForwardIterator,ForwardIterator> gather ( ForwardIterator first, ForwardIterator last, ForwardIterator pivot, Pred pred ) std::pair<BidirectionalIterator, BidirectionalIterator> gather
( BidirectionalIterator first, BidirectionalIterator last, BidirectionalIterator pivot, Pred pred )
{ {
// The first call partitions everything up to (but not including) the pivot element, // The first call partitions everything up to (but not including) the pivot element,
// while the second call partitions the rest of the sequence. // while the second call partitions the rest of the sequence.
@ -99,14 +100,14 @@ std::pair<ForwardIterator,ForwardIterator> gather ( ForwardIterator first, Forwa
*/ */
template < template <
typename ForwardRange, // typename BidirectionalRange, //
typename Pred> // Pred models UnaryPredicate typename Pred> // Pred models UnaryPredicate
std::pair< std::pair<
typename boost::range_iterator<ForwardRange>::type, typename boost::range_iterator<const BidirectionalRange>::type,
typename boost::range_iterator<ForwardRange>::type> typename boost::range_iterator<const BidirectionalRange>::type>
gather ( gather (
ForwardRange &range, const BidirectionalRange &range,
typename boost::range_iterator<ForwardRange>::type pivot, typename boost::range_iterator<const BidirectionalRange>::type pivot,
Pred pred ) Pred pred )
{ {
return boost::algorithm::gather ( boost::begin ( range ), boost::end ( range ), pivot, pred ); return boost::algorithm::gather ( boost::begin ( range ), boost::end ( range ), pivot, pred );

View File

@ -10,12 +10,6 @@
/* /*
General problem - turn a sequence of integral types into a sequence of hexadecimal characters. General problem - turn a sequence of integral types into a sequence of hexadecimal characters.
- and back. - 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 /// \file hex.hpp
@ -42,11 +36,11 @@ namespace boost { namespace algorithm {
/*! /*!
\struct hex_decode_error \struct hex_decode_error
\brief Base exception class for all hex decoding errors \brief Base exception class for all hex decoding errors
*/ /*!
\struct non_hex_input \struct non_hex_input
\brief Thrown when a non-hex value (0-9, A-F) encountered when decoding. \brief Thrown when a non-hex value (0-9, A-F) encountered when decoding.
Contains the offending character Contains the offending character
*/ /*!
\struct not_enough_input \struct not_enough_input
\brief Thrown when the input sequence unexpectedly ends \brief Thrown when the input sequence unexpectedly ends
@ -69,17 +63,15 @@ namespace detail {
return std::copy ( res, res + num_hex_digits, out ); return std::copy ( res, res + num_hex_digits, out );
} }
// this needs to be in an un-named namespace because it is not a template template <typename T>
// and might get included in several compilation units. This could cause unsigned char hex_char_to_int ( T val ) {
// multiple definition errors at link time. char c = static_cast<char> ( val );
namespace { unsigned retval = 0;
unsigned hex_char_to_int ( char c ) { if ( c >= '0' && c <= '9' ) retval = c - '0';
if ( c >= '0' && c <= '9' ) return c - '0'; else if ( c >= 'A' && c <= 'F' ) retval = c - 'A' + 10;
if ( c >= 'A' && c <= 'F' ) return c - 'A' + 10; else if ( c >= 'a' && c <= 'f' ) retval = c - 'a' + 10;
if ( c >= 'a' && c <= 'f' ) return c - 'a' + 10; else BOOST_THROW_EXCEPTION (non_hex_input() << bad_char (c));
BOOST_THROW_EXCEPTION (non_hex_input() << bad_char (c)); return retval;
return 0; // keep dumb compilers happy
}
} }
// My own iterator_traits class. // My own iterator_traits class.
@ -134,7 +126,7 @@ namespace detail {
for ( std::size_t i = 0; i < 2 * sizeof ( T ); ++i, ++first ) { for ( std::size_t i = 0; i < 2 * sizeof ( T ); ++i, ++first ) {
if ( pred ( first, last )) if ( pred ( first, last ))
BOOST_THROW_EXCEPTION (not_enough_input ()); BOOST_THROW_EXCEPTION (not_enough_input ());
res = ( 16 * res ) + hex_char_to_int (static_cast<char> (*first)); res = ( 16 * res ) + hex_char_to_int (*first);
} }
*out = res; *out = res;

View File

@ -20,6 +20,7 @@
#include <list> #include <list>
#include <boost/algorithm/cxx11/all_of.hpp> #include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/algorithm/cxx11/none_of.hpp>
namespace ba = boost::algorithm; namespace ba = boost::algorithm;
// namespace ba = boost; // 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; } bool is_odd ( int v ) { return v % 2 == 1; }
template <typename Container> template <typename Container>
void test_sequence ( Container const &c ) { void test_copy_if ( Container const &c ) {
typedef typename Container::value_type value_type; typedef typename Container::value_type value_type;
std::vector<value_type> v; std::vector<value_type> v;
@ -48,13 +49,13 @@ void test_sequence ( Container const &c ) {
v.clear (); v.clear ();
ba::copy_if ( c.begin (), c.end (), back_inserter ( v ), is_true); ba::copy_if ( c.begin (), c.end (), 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 ()));
v.clear (); v.clear ();
ba::copy_if ( c, back_inserter ( v ), is_true); ba::copy_if ( c, back_inserter ( v ), is_true);
BOOST_CHECK ( v.size () == c.size ()); BOOST_CHECK ( v.size () == c.size ());
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 // Some of the elements
v.clear (); v.clear ();
@ -69,16 +70,106 @@ void test_sequence ( Container const &c ) {
} }
template <typename Container>
void test_copy_while ( Container const &c ) {
typedef typename Container::value_type value_type;
typename Container::const_iterator it;
std::vector<value_type> 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 <typename Container>
void test_copy_until ( Container const &c ) {
typedef typename Container::value_type value_type;
typename Container::const_iterator it;
std::vector<value_type> 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 () { void test_sequence1 () {
std::vector<int> v; std::vector<int> v;
for ( int i = 5; i < 15; ++i ) for ( int i = 5; i < 15; ++i )
v.push_back ( i ); v.push_back ( i );
test_sequence ( v ); test_copy_if ( v );
test_copy_while ( v );
test_copy_until ( v );
std::list<int> l; std::list<int> l;
for ( int i = 25; i > 15; --i ) for ( int i = 25; i > 15; --i )
l.push_back ( i ); l.push_back ( i );
test_sequence ( l ); test_copy_if ( l );
test_copy_while ( l );
test_copy_until ( l );
} }

View File

@ -55,14 +55,12 @@ void test_iterators ( Iterator first, Iterator last, Predicate comp, std::size_t
template <typename Container, typename Predicate> template <typename Container, typename Predicate>
void test_iterator_types ( const Container &c, Predicate comp, std::size_t offset ) { void test_iterator_types ( const Container &c, Predicate comp, std::size_t offset ) {
typedef std::vector<typename Container::value_type> vec; typedef std::vector<typename Container::value_type> vec;
typedef forward_iterator<typename vec::iterator> FI;
typedef bidirectional_iterator<typename vec::iterator> BDI; typedef bidirectional_iterator<typename vec::iterator> BDI;
typedef random_access_iterator<typename vec::iterator> RAI; typedef random_access_iterator<typename vec::iterator> RAI;
vec v; vec v;
v.assign ( c.begin (), c.end ()); 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 ); test_iterators ( BDI ( v.begin ()), BDI ( v.end ()), comp, offset );
v.assign ( c.begin (), c.end ()); v.assign ( c.begin (), c.end ());
test_iterators ( RAI ( v.begin ()), RAI ( v.end ()), comp, offset ); test_iterators ( RAI ( v.begin ()), RAI ( v.end ()), comp, offset );

View File

@ -14,6 +14,7 @@
#define BOOST_TEST_MAIN #define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <ctime> // for clock_t
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>

View File

@ -14,6 +14,7 @@
#define BOOST_TEST_MAIN #define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <ctime> // for clock_t
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>