Skip to content

Commit c38885e

Browse files
committed
Implement copy_if_while and copy_if_until
Problem: - There is no way to signal that a copy should proceed, selecting elements by a predicate until some condition is met. This is useful for patterns along the lines of "copy selected elements until there are n total elements in the output". Solution: - Introduce `copy_if_while()` and `copy_if_until()`.
1 parent da8ea58 commit c38885e

File tree

3 files changed

+324
-7
lines changed

3 files changed

+324
-7
lines changed

Diff for: doc/algorithm.qbk

+12-2
Original file line numberDiff line numberDiff line change
@@ -206,14 +206,24 @@ See below
206206

207207
[section:copy_until copy_until ]
208208
[*[^[link header.boost.algorithm.cxx11.copy_if_hpp copy_until] ] ]
209-
Copy all the elements at the start of the input range that do not satisfy the predicate to the output range
209+
Copy all the elements from the start of the input range to the output range until the predicate is satisfied
210210
[endsect:copy_until]
211211

212212
[section:copy_while copy_while ]
213213
[*[^[link header.boost.algorithm.cxx11.copy_if_hpp copy_while] ] ]
214-
Copy all the elements at the start of the input range that satisfy the predicate to the output range
214+
Copy all the elements from the start of the input range to the output range while the predicate is satisfied
215215
[endsect:copy_while]
216216

217+
[section:copy_if_until copy_if_until ]
218+
[*[^[link header.boost.algorithm.cxx11.copy_if_hpp copy_if_until ] ]
219+
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
220+
[endsect:copy_if_until]
221+
222+
[section:copy_if_while copy_if_while ]
223+
[*[^[link header.boost.algorithm.cxx11.copy_if_hpp copy_if_while ] ]
224+
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
225+
[endsect:copy_if_while]
226+
217227
[section:iota_n iota_n ]
218228
[*[^[link boost.algorithm.iota_n iota_n] ] ]
219229
Write a sequence of n increasing values to an output iterator

Diff for: include/boost/algorithm/cxx11/copy_if.hpp

+76
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,82 @@ copy_until ( const Range &r, OutputIterator result, Predicate p )
126126
return boost::algorithm::copy_until (boost::begin (r), boost::end(r), result, p);
127127
}
128128

129+
/// \fn copy_if_while ( InputIterator first, InputIterator last, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred )
130+
/// \brief Copies all the elements from the input range that satisfy the
131+
/// predicate to the output range.
132+
/// \return The updated output iterator
133+
///
134+
/// \param first The start of the input sequence
135+
/// \param last One past the end of the input sequence
136+
/// \param result An output iterator to write the results into
137+
/// \param copy_pred A predicate for testing whether to the current element
138+
/// \param term_pred A predicate for testing whether to end the copy operation
139+
template<typename InputIterator, typename OutputIterator, typename CopyPredicate, typename TerminatePred>
140+
BOOST_CXX14_CONSTEXPR std::pair<InputIterator, OutputIterator>
141+
copy_if_while ( InputIterator first, InputIterator last, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred)
142+
{
143+
for ( ; first != last and term_pred(*first); ++first ) {
144+
if (copy_pred(*first)) {
145+
*result++ = *first;
146+
}
147+
}
148+
return std::make_pair(first, result);
149+
}
150+
151+
/// \fn copy_if_while ( const Range& r, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred )
152+
/// \brief Copies all the elements from the input range that satisfy the
153+
/// predicate to the output range.
154+
/// \return The updated output iterator
155+
///
156+
/// \param r The input range
157+
/// \param result An output iterator to write the results into
158+
/// \param copy_pred A predicate for testing whether to the current element
159+
/// \param term_pred A predicate for testing whether to end the copy operation
160+
template<typename Range, typename OutputIterator, typename CopyPredicate, typename TerminatePred>
161+
BOOST_CXX14_CONSTEXPR std::pair<typename boost::range_iterator<const Range>::type, OutputIterator>
162+
copy_if_while ( const Range& r, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred)
163+
{
164+
return boost::algorithm::copy_if_while(boost::begin(r), boost::end(r), result, copy_pred, term_pred);
165+
}
166+
167+
/// \fn copy_if_until ( InputIterator first, InputIterator last, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred )
168+
/// \brief Copies all the elements from the input range that satisfy the
169+
/// predicate to the output range.
170+
/// \return The updated output iterator
171+
///
172+
/// \param first The start of the input sequence
173+
/// \param last One past the end of the input sequence
174+
/// \param result An output iterator to write the results into
175+
/// \param copy_pred A predicate for testing whether to the current element
176+
/// \param term_pred A predicate for testing whether to end the copy operation
177+
template<typename InputIterator, typename OutputIterator, typename CopyPredicate, typename TerminatePred>
178+
BOOST_CXX14_CONSTEXPR std::pair<InputIterator, OutputIterator>
179+
copy_if_until ( InputIterator first, InputIterator last, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred)
180+
{
181+
for ( ; first != last and not term_pred(*first); ++first ) {
182+
if (copy_pred(*first)) {
183+
*result++ = *first;
184+
}
185+
}
186+
return std::make_pair(first, result);
187+
}
188+
189+
/// \fn copy_if_until ( const Range& r, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred )
190+
/// \brief Copies all the elements from the input range that satisfy the
191+
/// predicate to the output range.
192+
/// \return The updated output iterator
193+
///
194+
/// \param r The input range
195+
/// \param result An output iterator to write the results into
196+
/// \param copy_pred A predicate for testing whether to the current element
197+
/// \param term_pred A predicate for testing whether to end the copy operation
198+
template<typename Range, typename OutputIterator, typename CopyPredicate, typename TerminatePred>
199+
BOOST_CXX14_CONSTEXPR std::pair<typename boost::range_iterator<const Range>::type, OutputIterator>
200+
copy_if_until ( const Range& r, OutputIterator result, CopyPredicate copy_pred, TerminatePred term_pred)
201+
{
202+
return boost::algorithm::copy_if_until(boost::begin(r), boost::end(r), result, copy_pred, term_pred);
203+
}
204+
129205
}} // namespace boost and algorithm
130206

131207
#endif // BOOST_ALGORITHM_COPY_IF_HPP

Diff for: test/copy_if_test1.cpp

+236-5
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ BOOST_CXX14_CONSTEXPR bool is_even ( int v ) { return v % 2 == 0; }
3434
BOOST_CXX14_CONSTEXPR bool is_odd ( int v ) { return v % 2 == 1; }
3535
BOOST_CXX14_CONSTEXPR bool is_zero ( int v ) { return v == 0; }
3636

37+
BOOST_CXX14_CONSTEXPR bool less_than_ten ( int v ) { return v < 10; }
38+
BOOST_CXX14_CONSTEXPR bool greater_than_ten ( int v ) { return v > 10; }
3739

3840
template <typename Container>
3941
void test_copy_if ( Container const &c ) {
4042

4143
typedef typename Container::value_type value_type;
4244
std::vector<value_type> v;
43-
45+
4446
// None of the elements
4547
v.clear ();
4648
ba::copy_if ( c.begin (), c.end (), back_inserter ( v ), is_false);
@@ -118,6 +120,160 @@ void test_copy_while ( Container const &c ) {
118120
BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ()));
119121
}
120122

123+
template <typename Container>
124+
void test_copy_if_while ( Container const &c ) {
125+
126+
typedef typename Container::value_type value_type;
127+
typename Container::const_iterator it;
128+
129+
// Terminate immediately
130+
{
131+
std::vector<value_type> v;
132+
ba::copy_if_while ( c.begin (), c.end (), back_inserter ( v ), is_true, is_false);
133+
BOOST_CHECK ( v.size () == 0 );
134+
}
135+
{
136+
std::vector<value_type> v;
137+
ba::copy_if_while ( c, back_inserter ( v ), is_true, is_false);
138+
BOOST_CHECK ( v.size () == 0 );
139+
}
140+
141+
// Copy nothing - never terminate
142+
{
143+
std::vector<value_type> v;
144+
ba::copy_if_while ( c.begin (), c.end (), back_inserter ( v ), is_false, is_true);
145+
BOOST_CHECK ( v.size () == 0 );
146+
}
147+
{
148+
std::vector<value_type> v;
149+
ba::copy_if_while ( c, back_inserter ( v ), is_false, is_true);
150+
BOOST_CHECK ( v.size () == 0 );
151+
}
152+
153+
// Copy everything
154+
{
155+
std::vector<value_type> v;
156+
ba::copy_if_while ( c.begin (), c.end (), back_inserter ( v ), is_true, is_true);
157+
BOOST_CHECK ( v.size () == c.size() );
158+
BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ()));
159+
}
160+
{
161+
std::vector<value_type> v;
162+
ba::copy_if_while ( c, back_inserter ( v ), is_true, is_true);
163+
BOOST_CHECK ( v.size () == c.size() );
164+
BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ()));
165+
}
166+
167+
// Copy all evens
168+
{
169+
std::vector<value_type> v;
170+
ba::copy_if_while ( c.begin (), c.end (), back_inserter ( v ), is_even, is_true);
171+
BOOST_CHECK ( v.size () == (size_t) std::count_if ( c.begin (), c.end (), is_even ));
172+
BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even ));
173+
}
174+
{
175+
std::vector<value_type> v;
176+
ba::copy_if_while ( c, back_inserter ( v ), is_even, is_true);
177+
BOOST_CHECK ( v.size () == (size_t) std::count_if ( c.begin (), c.end (), is_even ));
178+
BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even ));
179+
}
180+
181+
// Copy some until termination
182+
{
183+
std::vector<value_type> v;
184+
typename Container::const_iterator it = ba::copy_if_while (
185+
c.begin (), c.end (), back_inserter ( v ), is_even, less_than_ten).first;
186+
BOOST_CHECK ( it == std::find_if ( c.begin(), c.end(), greater_than_ten ));
187+
BOOST_CHECK ( v.size () == std::count_if ( c.begin(), it, is_even ));
188+
BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even ));
189+
}
190+
{
191+
std::vector<value_type> v;
192+
typename Container::const_iterator it = ba::copy_if_while (
193+
c, back_inserter ( v ), is_even, less_than_ten).first;
194+
BOOST_CHECK ( it == std::find_if ( c.begin(), c.end(), greater_than_ten ));
195+
BOOST_CHECK ( v.size () == std::count_if ( c.begin(), it, is_even ));
196+
BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even ));
197+
}
198+
}
199+
200+
template <typename Container>
201+
void test_copy_if_until ( Container const &c ) {
202+
203+
typedef typename Container::value_type value_type;
204+
typename Container::const_iterator it;
205+
206+
// Terminate immediately
207+
{
208+
std::vector<value_type> v;
209+
ba::copy_if_until ( c.begin (), c.end (), back_inserter ( v ), is_true, is_true);
210+
BOOST_CHECK ( v.size () == 0 );
211+
}
212+
{
213+
std::vector<value_type> v;
214+
ba::copy_if_until ( c, back_inserter ( v ), is_true, is_true);
215+
BOOST_CHECK ( v.size () == 0 );
216+
}
217+
218+
// Copy nothing - never terminate
219+
{
220+
std::vector<value_type> v;
221+
ba::copy_if_until ( c.begin (), c.end (), back_inserter ( v ), is_false, is_false);
222+
BOOST_CHECK ( v.size () == 0 );
223+
}
224+
{
225+
std::vector<value_type> v;
226+
ba::copy_if_until ( c, back_inserter ( v ), is_false, is_false);
227+
BOOST_CHECK ( v.size () == 0 );
228+
}
229+
230+
// Copy everything
231+
{
232+
std::vector<value_type> v;
233+
ba::copy_if_until ( c.begin (), c.end (), back_inserter ( v ), is_true, is_false);
234+
BOOST_CHECK ( v.size () == c.size() );
235+
BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ()));
236+
}
237+
{
238+
std::vector<value_type> v;
239+
ba::copy_if_until ( c, back_inserter ( v ), is_true, is_false);
240+
BOOST_CHECK ( v.size () == c.size() );
241+
BOOST_CHECK ( std::equal ( v.begin (), v.end (), c.begin ()));
242+
}
243+
244+
// Copy all evens
245+
{
246+
std::vector<value_type> v;
247+
ba::copy_if_until ( c.begin (), c.end (), back_inserter ( v ), is_even, is_false);
248+
BOOST_CHECK ( v.size () == (size_t) std::count_if ( c.begin (), c.end (), is_even ));
249+
BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even ));
250+
}
251+
{
252+
std::vector<value_type> v;
253+
ba::copy_if_until ( c, back_inserter ( v ), is_even, is_false);
254+
BOOST_CHECK ( v.size () == (size_t) std::count_if ( c.begin (), c.end (), is_even ));
255+
BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even ));
256+
}
257+
258+
// Copy some until termination
259+
{
260+
std::vector<value_type> v;
261+
typename Container::const_iterator it = ba::copy_if_until (
262+
c.begin (), c.end (), back_inserter ( v ), is_even, greater_than_ten).first;
263+
BOOST_CHECK ( it == std::find_if ( c.begin(), c.end(), greater_than_ten ));
264+
BOOST_CHECK ( v.size () == std::count_if ( c.begin(), it, is_even ));
265+
BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even ));
266+
}
267+
{
268+
std::vector<value_type> v;
269+
typename Container::const_iterator it = ba::copy_if_until (
270+
c, back_inserter ( v ), is_even, greater_than_ten).first;
271+
BOOST_CHECK ( it == std::find_if ( c.begin(), c.end(), greater_than_ten ));
272+
BOOST_CHECK ( v.size () == std::count_if ( c.begin(), it, is_even ));
273+
BOOST_CHECK ( ba::all_of ( v.begin (), v.end (), is_even ));
274+
}
275+
}
276+
121277
template <typename Container>
122278
void test_copy_until ( Container const &c ) {
123279

@@ -224,29 +380,104 @@ BOOST_CXX14_CONSTEXPR inline bool constexpr_test_copy_until() {
224380

225381
return res;
226382
}
227-
228-
383+
384+
BOOST_CXX14_CONSTEXPR inline bool constexpr_test_copy_if_while() {
385+
const int sz = 64;
386+
int in_data[sz] = {0};
387+
bool res = true;
388+
389+
const int* from = in_data;
390+
const int* to = in_data + sz;
391+
392+
// Terminate immediately
393+
{
394+
int out_data[sz] = {0};
395+
int* out = out_data;
396+
out = ba::copy_if_while ( from, to, out, is_true, is_false ).second;
397+
res = (res && out == out_data && ba::all_of(out, out + sz, is_zero));
398+
}
399+
// Copy nothing
400+
{
401+
int out_data[sz] = {0};
402+
int* out = out_data;
403+
out = ba::copy_if_while ( from, to, out, is_false, is_true ).second;
404+
res = (res && out == out_data && ba::all_of(out, out + sz, is_zero));
405+
}
406+
// Copy everything
407+
{
408+
int out_data[sz] = {0};
409+
int* out = out_data;
410+
out = ba::copy_if_while ( from, to, out, is_true, is_true ).second;
411+
res = (res && out == out_data + sz
412+
&& ba::equal( input_iterator<const int *>(out_data), input_iterator<const int *>(out_data + sz),
413+
input_iterator<const int *>(from), input_iterator<const int *>(to)));
414+
}
415+
416+
return res;
417+
}
418+
419+
BOOST_CXX14_CONSTEXPR inline bool constexpr_test_copy_if_until() {
420+
const int sz = 64;
421+
int in_data[sz] = {0};
422+
bool res = true;
423+
424+
const int* from = in_data;
425+
const int* to = in_data + sz;
426+
427+
// Terminate immediately
428+
{
429+
int out_data[sz] = {0};
430+
int* out = out_data;
431+
out = ba::copy_if_until ( from, to, out, is_true, is_true ).second;
432+
res = (res && out == out_data && ba::all_of(out, out + sz, is_zero));
433+
}
434+
// Copy nothing
435+
{
436+
int out_data[sz] = {0};
437+
int* out = out_data;
438+
out = ba::copy_if_until ( from, to, out, is_false, is_false ).second;
439+
res = (res && out == out_data && ba::all_of(out, out + sz, is_zero));
440+
}
441+
// Copy everything
442+
{
443+
int out_data[sz] = {0};
444+
int* out = out_data;
445+
out = ba::copy_if_until ( from, to, out, is_true, is_false ).second;
446+
res = (res && out == out_data + sz
447+
&& ba::equal( input_iterator<const int *>(out_data), input_iterator<const int *>(out_data + sz),
448+
input_iterator<const int *>(from), input_iterator<const int *>(to)));
449+
}
450+
451+
return res;
452+
}
453+
229454
void test_sequence1 () {
230455
std::vector<int> v;
231456
for ( int i = 5; i < 15; ++i )
232457
v.push_back ( i );
233458
test_copy_if ( v );
234459
test_copy_while ( v );
235460
test_copy_until ( v );
236-
461+
237462
BOOST_CXX14_CONSTEXPR bool constexpr_res_if = constexpr_test_copy_if();
238463
BOOST_CHECK ( constexpr_res_if );
239464
BOOST_CXX14_CONSTEXPR bool constexpr_res_while = constexpr_test_copy_while();
240465
BOOST_CHECK ( constexpr_res_while );
241466
BOOST_CXX14_CONSTEXPR bool constexpr_res_until = constexpr_test_copy_until();
242467
BOOST_CHECK ( constexpr_res_until );
243-
468+
BOOST_CXX14_CONSTEXPR bool constexpr_res_if_while = constexpr_test_copy_if_while();
469+
BOOST_CHECK ( constexpr_res_if_while );
470+
BOOST_CXX14_CONSTEXPR bool constexpr_res_if_until = constexpr_test_copy_if_until();
471+
BOOST_CHECK ( constexpr_res_if_until );
472+
244473
std::list<int> l;
245474
for ( int i = 25; i > 15; --i )
246475
l.push_back ( i );
247476
test_copy_if ( l );
248477
test_copy_while ( l );
249478
test_copy_until ( l );
479+
test_copy_if_while ( l );
480+
test_copy_if_until ( l );
250481
}
251482

252483

0 commit comments

Comments
 (0)