diff --git a/doc/algorithm.qbk b/doc/algorithm.qbk index 64e8dfb70..391a198e5 100644 --- a/doc/algorithm.qbk +++ b/doc/algorithm.qbk @@ -206,14 +206,24 @@ See below [section:copy_until copy_until ] [*[^[link header.boost.algorithm.cxx11.copy_if_hpp copy_until] ] ] -Copy all the elements at the start of the input range that do not satisfy the predicate to the output range +Copy all the elements from the start of the input range to the output range until the predicate is satisfied [endsect:copy_until] [section:copy_while copy_while ] [*[^[link header.boost.algorithm.cxx11.copy_if_hpp copy_while] ] ] -Copy all the elements at the start of the input range that satisfy the predicate to the output range +Copy all the elements from the start of the input range to the output range while the predicate is satisfied [endsect:copy_while] +[section:copy_if_until copy_if_until ] +[*[^[link header.boost.algorithm.cxx11.copy_if_hpp copy_if_until ] ] +Copy all elements that satisfy the element predicate from the start of the input range to the output range until the termination predicate is satisfied +[endsect:copy_if_until] + +[section:copy_if_while copy_if_while ] +[*[^[link header.boost.algorithm.cxx11.copy_if_hpp copy_if_while ] ] +Copy all elements that satisfy the element predicate from the start of the input range to the output range while the termination predicate is satisfied +[endsect:copy_if_while] + [section:iota_n iota_n ] [*[^[link boost.algorithm.iota_n iota_n] ] ] Write a sequence of n increasing values to an output iterator diff --git a/include/boost/algorithm/cxx11/copy_if.hpp b/include/boost/algorithm/cxx11/copy_if.hpp index d3914bf20..307c21310 100644 --- a/include/boost/algorithm/cxx11/copy_if.hpp +++ b/include/boost/algorithm/cxx11/copy_if.hpp @@ -126,6 +126,86 @@ copy_until ( const Range &r, OutputIterator result, Predicate p ) return boost::algorithm::copy_until (boost::begin (r), boost::end(r), result, p); } +/// \fn copy_if_while ( InputIterator first, InputIterator last, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred ) +/// \brief Copies all the elements from the input range that satisfy the +/// copy predicate to the output range while the termination predicate is +/// satisfied. +/// \return The updated output iterator +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param result An output iterator to write the results into +/// \param copy_pred A predicate for testing whether to the current element +/// \param term_pred A predicate for testing whether to end the copy operation +template +BOOST_CXX14_CONSTEXPR std::pair +copy_if_while ( InputIterator first, InputIterator last, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred) +{ + for ( ; first != last && term_pred(*first); ++first ) { + if (copy_pred(*first)) { + *result++ = *first; + } + } + return std::make_pair(first, result); +} + +/// \fn copy_if_while ( const Range& r, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred ) +/// \brief Copies all the elements from the input range that satisfy the +/// copy predicate to the output range while the termination predicate is +/// satisfied. +/// \return The updated output iterator +/// +/// \param r The input range +/// \param result An output iterator to write the results into +/// \param copy_pred A predicate for testing whether to the current element +/// \param term_pred A predicate for testing whether to end the copy operation +template +BOOST_CXX14_CONSTEXPR std::pair::type, OutputIterator> +copy_if_while ( const Range& r, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred) +{ + return boost::algorithm::copy_if_while(boost::begin(r), boost::end(r), result, copy_pred, term_pred); +} + +/// \fn copy_if_until ( InputIterator first, InputIterator last, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred ) +/// \brief Copies all the elements from the input range that satisfy the +/// copy predicate to the output range until the termination predicate is +/// satisfied. +/// \return The updated output iterator +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param result An output iterator to write the results into +/// \param copy_pred A predicate for testing whether to the current element +/// \param term_pred A predicate for testing whether to end the copy operation +template +BOOST_CXX14_CONSTEXPR std::pair +copy_if_until ( InputIterator first, InputIterator last, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred) +{ + for ( ; first != last && !term_pred(*first); ++first ) { + if (copy_pred(*first)) { + *result++ = *first; + } + } + return std::make_pair(first, result); +} + +/// \fn copy_if_until ( const Range& r, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred ) +/// \brief Copies all the elements from the input range that satisfy the +/// copy predicate to the output range until the termination predicate is +/// satisfied. +/// \return The updated output iterator +/// +/// \param r The input range +/// \param result An output iterator to write the results into +/// \param copy_pred A predicate for testing whether to the current element +/// \param term_pred A predicate for testing whether to end the copy operation +template +BOOST_CXX14_CONSTEXPR std::pair::type, OutputIterator> +copy_if_until ( const Range& r, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred) +{ + return boost::algorithm::copy_if_until(boost::begin(r), boost::end(r), result, copy_pred, term_pred); +} + }} // namespace boost and algorithm #endif // BOOST_ALGORITHM_COPY_IF_HPP diff --git a/test/copy_if_test1.cpp b/test/copy_if_test1.cpp index b275f5f5d..574a17528 100644 --- a/test/copy_if_test1.cpp +++ b/test/copy_if_test1.cpp @@ -34,13 +34,15 @@ BOOST_CXX14_CONSTEXPR bool is_even ( int v ) { return v % 2 == 0; } BOOST_CXX14_CONSTEXPR bool is_odd ( int v ) { return v % 2 == 1; } BOOST_CXX14_CONSTEXPR bool is_zero ( int v ) { return v == 0; } +BOOST_CXX14_CONSTEXPR bool less_than_ten ( int v ) { return v < 10; } +BOOST_CXX14_CONSTEXPR bool greater_than_ten ( int v ) { return v > 10; } template void test_copy_if ( Container const &c ) { typedef typename Container::value_type value_type; std::vector v; - + // None of the elements v.clear (); ba::copy_if ( c.begin (), c.end (), back_inserter ( v ), is_false); @@ -118,6 +120,160 @@ void test_copy_while ( Container const &c ) { BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); } +template +void test_copy_if_while ( Container const &c ) { + + typedef typename Container::value_type value_type; + typename Container::const_iterator it; + +// Terminate immediately + { + std::vector v; + ba::copy_if_while ( c.begin (), c.end (), back_inserter ( v ), is_true, is_false); + BOOST_CHECK ( v.size () == 0 ); + } + { + std::vector v; + ba::copy_if_while ( c, back_inserter ( v ), is_true, is_false); + BOOST_CHECK ( v.size () == 0 ); + } + +// Copy nothing - never terminate + { + std::vector v; + ba::copy_if_while ( c.begin (), c.end (), back_inserter ( v ), is_false, is_true); + BOOST_CHECK ( v.size () == 0 ); + } + { + std::vector v; + ba::copy_if_while ( c, back_inserter ( v ), is_false, is_true); + BOOST_CHECK ( v.size () == 0 ); + } + +// Copy everything + { + std::vector v; + ba::copy_if_while ( c.begin (), c.end (), back_inserter ( v ), is_true, is_true); + BOOST_CHECK ( v.size () == c.size() ); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + } + { + std::vector v; + ba::copy_if_while ( c, back_inserter ( v ), is_true, is_true); + BOOST_CHECK ( v.size () == c.size() ); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + } + +// Copy all evens + { + std::vector v; + ba::copy_if_while ( c.begin (), c.end (), back_inserter ( v ), is_even, is_true); + BOOST_CHECK ( v.size () == (size_t) std::count_if ( c.begin (), c.end (), is_even )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even )); + } + { + std::vector v; + ba::copy_if_while ( c, back_inserter ( v ), is_even, is_true); + BOOST_CHECK ( v.size () == (size_t) std::count_if ( c.begin (), c.end (), is_even )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even )); + } + +// Copy some until termination + { + std::vector v; + typename Container::const_iterator it = ba::copy_if_while ( + c.begin (), c.end (), back_inserter ( v ), is_even, less_than_ten).first; + BOOST_CHECK ( it == std::find_if ( c.begin(), c.end(), greater_than_ten )); + BOOST_CHECK ( v.size () == std::count_if ( c.begin(), it, is_even )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even )); + } + { + std::vector v; + typename Container::const_iterator it = ba::copy_if_while ( + c, back_inserter ( v ), is_even, less_than_ten).first; + BOOST_CHECK ( it == std::find_if ( c.begin(), c.end(), greater_than_ten )); + BOOST_CHECK ( v.size () == std::count_if ( c.begin(), it, is_even )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even )); + } + } + +template +void test_copy_if_until ( Container const &c ) { + + typedef typename Container::value_type value_type; + typename Container::const_iterator it; + +// Terminate immediately + { + std::vector v; + ba::copy_if_until ( c.begin (), c.end (), back_inserter ( v ), is_true, is_true); + BOOST_CHECK ( v.size () == 0 ); + } + { + std::vector v; + ba::copy_if_until ( c, back_inserter ( v ), is_true, is_true); + BOOST_CHECK ( v.size () == 0 ); + } + +// Copy nothing - never terminate + { + std::vector v; + ba::copy_if_until ( c.begin (), c.end (), back_inserter ( v ), is_false, is_false); + BOOST_CHECK ( v.size () == 0 ); + } + { + std::vector v; + ba::copy_if_until ( c, back_inserter ( v ), is_false, is_false); + BOOST_CHECK ( v.size () == 0 ); + } + +// Copy everything + { + std::vector v; + ba::copy_if_until ( c.begin (), c.end (), back_inserter ( v ), is_true, is_false); + BOOST_CHECK ( v.size () == c.size() ); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + } + { + std::vector v; + ba::copy_if_until ( c, back_inserter ( v ), is_true, is_false); + BOOST_CHECK ( v.size () == c.size() ); + BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ())); + } + +// Copy all evens + { + std::vector v; + ba::copy_if_until ( c.begin (), c.end (), back_inserter ( v ), is_even, is_false); + BOOST_CHECK ( v.size () == (size_t) std::count_if ( c.begin (), c.end (), is_even )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even )); + } + { + std::vector v; + ba::copy_if_until ( c, back_inserter ( v ), is_even, is_false); + BOOST_CHECK ( v.size () == (size_t) std::count_if ( c.begin (), c.end (), is_even )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even )); + } + +// Copy some until termination + { + std::vector v; + typename Container::const_iterator it = ba::copy_if_until ( + c.begin (), c.end (), back_inserter ( v ), is_even, greater_than_ten).first; + BOOST_CHECK ( it == std::find_if ( c.begin(), c.end(), greater_than_ten )); + BOOST_CHECK ( v.size () == std::count_if ( c.begin(), it, is_even )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even )); + } + { + std::vector v; + typename Container::const_iterator it = ba::copy_if_until ( + c, back_inserter ( v ), is_even, greater_than_ten).first; + BOOST_CHECK ( it == std::find_if ( c.begin(), c.end(), greater_than_ten )); + BOOST_CHECK ( v.size () == std::count_if ( c.begin(), it, is_even )); + BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even )); + } + } + template void test_copy_until ( Container const &c ) { @@ -224,8 +380,77 @@ BOOST_CXX14_CONSTEXPR inline bool constexpr_test_copy_until() { return res; } - - + +BOOST_CXX14_CONSTEXPR inline bool constexpr_test_copy_if_while() { + const int sz = 64; + int in_data[sz] = {0}; + bool res = true; + + const int* from = in_data; + const int* to = in_data + sz; + +// Terminate immediately + { + int out_data[sz] = {0}; + int* out = out_data; + out = ba::copy_if_while ( from, to, out, is_true, is_false ).second; + res = (res && out == out_data && ba::all_of(out, out + sz, is_zero)); + } +// Copy nothing + { + int out_data[sz] = {0}; + int* out = out_data; + out = ba::copy_if_while ( from, to, out, is_false, is_true ).second; + res = (res && out == out_data && ba::all_of(out, out + sz, is_zero)); + } +// Copy everything + { + int out_data[sz] = {0}; + int* out = out_data; + out = ba::copy_if_while ( from, to, out, is_true, is_true ).second; + res = (res && out == out_data + sz + && ba::equal( input_iterator(out_data), input_iterator(out_data + sz), + input_iterator(from), input_iterator(to))); + } + + return res; + } + +BOOST_CXX14_CONSTEXPR inline bool constexpr_test_copy_if_until() { + const int sz = 64; + int in_data[sz] = {0}; + bool res = true; + + const int* from = in_data; + const int* to = in_data + sz; + +// Terminate immediately + { + int out_data[sz] = {0}; + int* out = out_data; + out = ba::copy_if_until ( from, to, out, is_true, is_true ).second; + res = (res && out == out_data && ba::all_of(out, out + sz, is_zero)); + } +// Copy nothing + { + int out_data[sz] = {0}; + int* out = out_data; + out = ba::copy_if_until ( from, to, out, is_false, is_false ).second; + res = (res && out == out_data && ba::all_of(out, out + sz, is_zero)); + } +// Copy everything + { + int out_data[sz] = {0}; + int* out = out_data; + out = ba::copy_if_until ( from, to, out, is_true, is_false ).second; + res = (res && out == out_data + sz + && ba::equal( input_iterator(out_data), input_iterator(out_data + sz), + input_iterator(from), input_iterator(to))); + } + + return res; + } + void test_sequence1 () { std::vector v; for ( int i = 5; i < 15; ++i ) @@ -233,20 +458,26 @@ void test_sequence1 () { test_copy_if ( v ); test_copy_while ( v ); test_copy_until ( v ); - + BOOST_CXX14_CONSTEXPR bool constexpr_res_if = constexpr_test_copy_if(); BOOST_CHECK ( constexpr_res_if ); BOOST_CXX14_CONSTEXPR bool constexpr_res_while = constexpr_test_copy_while(); BOOST_CHECK ( constexpr_res_while ); BOOST_CXX14_CONSTEXPR bool constexpr_res_until = constexpr_test_copy_until(); BOOST_CHECK ( constexpr_res_until ); - + BOOST_CXX14_CONSTEXPR bool constexpr_res_if_while = constexpr_test_copy_if_while(); + BOOST_CHECK ( constexpr_res_if_while ); + BOOST_CXX14_CONSTEXPR bool constexpr_res_if_until = constexpr_test_copy_if_until(); + BOOST_CHECK ( constexpr_res_if_until ); + std::list l; for ( int i = 25; i > 15; --i ) l.push_back ( i ); test_copy_if ( l ); test_copy_while ( l ); test_copy_until ( l ); + test_copy_if_while ( l ); + test_copy_if_until ( l ); }