Skip to content

Commit ecb8bfa

Browse files
authored
Merge pull request boostorg#47 from tzlaine/develop
Add find() variants.
2 parents ea7d35d + 3f2a962 commit ecb8bfa

File tree

8 files changed

+895
-1
lines changed

8 files changed

+895
-1
lines changed

doc/algorithm.qbk

+2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ Thanks to all the people who have reviewed this library and made suggestions for
6464

6565
[section:Misc Other Algorithms]
6666
[include clamp-hpp.qbk]
67+
[include find_not.qbk]
68+
[include find_backward.qbk]
6769
[include gather.qbk]
6870
[include hex.qbk]
6971
[include is_palindrome.qbk]

doc/find_backward.qbk

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
[/ File find_backward.qbk]
2+
3+
[section:find_backward find_backward ]
4+
5+
[/license
6+
Copyright (c) 2018 T. Zachary Laine
7+
8+
Distributed under the Boost Software License, Version 1.0.
9+
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10+
]
11+
12+
The header file 'find_backward.hpp' contains variants of the stl algorithm
13+
`find`. These variants are like `find`, except that the evaluate the elements
14+
of the given sequence in reverse order.
15+
16+
Consider how finding the last element that is equal to `x` in a range is
17+
typically done:
18+
19+
// Assume a valid range if elements delimited by [first, last).
20+
while (last-- != first) {
21+
if (*last == x) {
22+
// Use last here...
23+
}
24+
}
25+
26+
Raw loops are icky though. Perhaps we should do a bit of extra work to allow
27+
the use of `std::find()`:
28+
29+
auto rfirst = std::make_reverse_iterator(last);
30+
auto rlast = std::make_reverse_iterator(first);
31+
auto it = std::find(rfirst, rlast);
32+
// Use it here...
33+
34+
That seems nicer in that there is no raw loop, but it has two major drawbacks.
35+
First, it requires an unpleasant amount of typing. Second, it is less
36+
efficient than forward-iterator `find` , since `std::reverse_iterator` calls
37+
its base-iterator's `operator--()` in most of its member functions before
38+
doing the work that the member function requires.
39+
40+
[heading interface]
41+
42+
template<typename BidiIter, typename T>
43+
BidiIter find_backward(BidiIter first, BidiIter last, const T & x);
44+
45+
template<typename Range, typename T>
46+
boost::range_iterator<Range> find_backward(Range & range, const T & x);
47+
48+
These overloads of `find_backward` return an iterator to the last element that
49+
is equal to `x` in `[first, last)` or `r`, respectively.
50+
51+
template<typename BidiIter, typename T>
52+
BidiIter find_not_backward(BidiIter first, BidiIter last, const T & x);
53+
54+
template<typename Range, typename T>
55+
boost::range_iterator<Range> find_not_backward(Range & range, const T & x);
56+
57+
These overloads of `find_not_backward` return an iterator to the last element
58+
that is not equal to `x` in `[first, last)` or `r`, respectively.
59+
60+
template<typename BidiIter, typename Pred>
61+
BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p);
62+
63+
template<typename Range, typename Pred>
64+
boost::range_iterator<Range> find_if_backward(Range & range, Pred p);
65+
66+
These overloads of `find_if_backward` return an iterator to the last element
67+
for which `pred` returns `true` in `[first, last)` or `r`, respectively.
68+
69+
template<typename BidiIter, typename Pred>
70+
BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p);
71+
72+
template<typename Range, typename Pred>
73+
boost::range_iterator<Range> find_if_not_backward(Range & range, Pred p);
74+
75+
These overloads of `find_if_not_backward` return an iterator to the last
76+
element for which `pred` returns `false` in `[first, last)` or `r`,
77+
respectively.
78+
79+
[heading Examples]
80+
81+
Given the container `c1` containing `{ 2, 1, 2 }`, then
82+
83+
find_backward ( c1.begin(), c1.end(), 2 ) --> --c1.end()
84+
find_backward ( c1.begin(), c1.end(), 3 ) --> c1.end()
85+
find_if_backward ( c1.begin(), c1.end(), [](int i) {return i == 2;} ) --> --c1.end()
86+
find_if_backward ( c1.begin(), c1.end(), [](int i) {return i == 3;} ) --> c1.end()
87+
find_not_backward ( c1.begin(), c1.end(), 2 ) --> std::prev(c1.end(), 2)
88+
find_not_backward ( c1.begin(), c1.end(), 1 ) --> c1.end()
89+
find_if_not_backward ( c1.begin(), c1.end(), [](int i) {return i == 2;} ) --> std::prev(c1.end(), 2)
90+
find_if_not_backward ( c1.begin(), c1.end(), [](int i) {return i == 1;} ) --> c1.end()
91+
92+
[heading Iterator Requirements]
93+
94+
All variants work on bidirectional iterators.
95+
96+
[heading Complexity]
97+
98+
Linear.
99+
100+
[heading Exception Safety]
101+
102+
All of the variants take their parameters by value and do not depend upon any
103+
global state. Therefore, all the routines in this file provide the strong
104+
exception guarantee.
105+
106+
[heading Notes]
107+
108+
All variants are `constexpr` in C++14 or later.
109+
110+
[endsect]
111+
112+
[/ File equal.qbk
113+
Copyright 2018 T. Zachary Laine
114+
Distributed under the Boost Software License, Version 1.0.
115+
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
116+
]

doc/find_not.qbk

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
[/ File find_not.qbk]
2+
3+
[section:find_not find_not ]
4+
5+
[/license
6+
Copyright (c) 2018 T. Zachary Laine
7+
8+
Distributed under the Boost Software License, Version 1.0.
9+
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10+
]
11+
12+
The header file 'find_not.hpp' contains a variants of a the stl algorithm
13+
`find`. The algorithm finds the first value in the given sequence that is not
14+
equal to the given value.
15+
16+
Consider this use of `find()`:
17+
18+
auto std::vector<int> vec = { 1, 1, 2 };
19+
auto it = std::find(vec.begin(), vec.end(), 1);
20+
21+
This gives us the first occurance of `1` in `vec`. What if we want to find
22+
the first occurrance of any number besides `1` in `vec`? We have to write an
23+
unfortunate amount of code:
24+
25+
auto std::vector<int> vec = { 1, 1, 2 };
26+
auto it = std::find_if(vec.begin(), vec.end(), [](int i) { return i != 1; });
27+
28+
With `find_not()` the code gets much more terse:
29+
30+
auto std::vector<int> vec = { 1, 1, 2 };
31+
auto it = find_not(vec.begin(), vec.end(), 1);
32+
33+
The existing `find` variants are: `find()`, `find_if()`, and `find_if_not()`.
34+
It seems natural to also have `find_not()`, for the very reason that we have
35+
`find_if_not()` -- to avoid having to write a lambda to wrap the negation of
36+
the find condition.
37+
38+
[heading interface]
39+
40+
template<typename InputIter, typename Sentinel, typename T>
41+
InputIter find_not(InputIter first, Sentinel last, const T & x);
42+
43+
template<typename Range, typename T>
44+
boost::range_iterator<Range> find_not(Range & r, const T & x);
45+
46+
These overloads of `find_not` return the first value that is not equal to `x`
47+
in the sequence `[first, last)` or `r`, respectively.
48+
49+
[heading Examples]
50+
51+
Given the container `c1` containing `{ 0, 1, 2 }`, then
52+
53+
find_not ( c1.begin(), c1.end(), 1 ) --> c1.begin()
54+
find_not ( c1.begin(), c1.end(), 0 ) --> std::next(c1.begin())
55+
56+
[heading Iterator Requirements]
57+
58+
`find_not` works on all iterators except output iterators.
59+
60+
The template parameter `Sentinel` is allowed to be different from `InputIter`,
61+
or they may be the same. For an `InputIter` `it` and a `Sentinel` `end`, `it
62+
== end` and `it != end` must be well-formed expressions.
63+
64+
[heading Complexity]
65+
66+
Linear.
67+
68+
[heading Exception Safety]
69+
70+
`find_not` takes its parameters by value and do not depend upon any global
71+
state. Therefore, it provides the strong exception guarantee.
72+
73+
[heading Notes]
74+
75+
`constexpr` in C++14 or later.
76+
77+
[endsect]
78+
79+
[/ File equal.qbk
80+
Copyright 2018 T. Zachary Laine
81+
Distributed under the Boost Software License, Version 1.0.
82+
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
83+
]
+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
Copyright (c) T. Zachary Laine 2018.
3+
4+
Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt)
6+
*/
7+
#ifndef BOOST_ALGORITHM_FIND_BACKWARD_HPP
8+
#define BOOST_ALGORITHM_FIND_BACKWARD_HPP
9+
10+
#include <boost/config.hpp>
11+
#include <boost/range/begin.hpp>
12+
#include <boost/range/end.hpp>
13+
14+
#include <utility>
15+
16+
17+
namespace boost { namespace algorithm {
18+
19+
template<typename BidiIter, typename T>
20+
BOOST_CXX14_CONSTEXPR
21+
BidiIter find_backward(BidiIter first, BidiIter last, const T & x)
22+
{
23+
BidiIter it = last;
24+
while (it != first) {
25+
if (*--it == x)
26+
return it;
27+
}
28+
return last;
29+
}
30+
31+
template<typename Range, typename T>
32+
BOOST_CXX14_CONSTEXPR
33+
typename boost::range_iterator<Range>::type find_backward(Range & range, const T & x)
34+
{
35+
return ::boost::algorithm::find_backward(boost::begin(range), boost::end(range), x);
36+
}
37+
38+
template<typename BidiIter, typename T>
39+
BOOST_CXX14_CONSTEXPR
40+
BidiIter find_not_backward(BidiIter first, BidiIter last, const T & x)
41+
{
42+
BidiIter it = last;
43+
while (it != first) {
44+
if (*--it != x)
45+
return it;
46+
}
47+
return last;
48+
}
49+
50+
template<typename Range, typename T>
51+
BOOST_CXX14_CONSTEXPR
52+
typename boost::range_iterator<Range>::type find_not_backward(Range & range, const T & x)
53+
{
54+
return ::boost::algorithm::find_not_backward(boost::begin(range), boost::end(range), x);
55+
}
56+
57+
template<typename BidiIter, typename Pred>
58+
BOOST_CXX14_CONSTEXPR
59+
BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p)
60+
{
61+
BidiIter it = last;
62+
while (it != first) {
63+
if (p(*--it))
64+
return it;
65+
}
66+
return last;
67+
}
68+
69+
template<typename Range, typename Pred>
70+
BOOST_CXX14_CONSTEXPR
71+
typename boost::range_iterator<Range>::type find_if_backward(Range & range, Pred p)
72+
{
73+
return ::boost::algorithm::find_if_backward(boost::begin(range), boost::end(range), p);
74+
}
75+
76+
template<typename BidiIter, typename Pred>
77+
BOOST_CXX14_CONSTEXPR
78+
BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p)
79+
{
80+
BidiIter it = last;
81+
while (it != first) {
82+
if (!p(*--it))
83+
return it;
84+
}
85+
return last;
86+
}
87+
88+
template<typename Range, typename Pred>
89+
BOOST_CXX14_CONSTEXPR
90+
typename boost::range_iterator<Range>::type find_if_not_backward(Range & range, Pred p)
91+
{
92+
return ::boost::algorithm::find_if_not_backward(boost::begin(range), boost::end(range), p);
93+
}
94+
95+
}} // namespace boost and algorithm
96+
97+
#endif // BOOST_ALGORITHM_FIND_BACKWARD_HPP

include/boost/algorithm/find_not.hpp

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
Copyright (c) T. Zachary Laine 2018.
3+
4+
Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt)
6+
*/
7+
#ifndef BOOST_ALGORITHM_FIND_NOT_HPP
8+
#define BOOST_ALGORITHM_FIND_NOT_HPP
9+
10+
#include <boost/config.hpp>
11+
#include <boost/range/begin.hpp>
12+
#include <boost/range/end.hpp>
13+
14+
#include <utility>
15+
16+
17+
namespace boost { namespace algorithm {
18+
19+
template<typename InputIter, typename Sentinel, typename T>
20+
BOOST_CXX14_CONSTEXPR
21+
InputIter find_not(InputIter first, Sentinel last, const T & x)
22+
{
23+
for (; first != last; ++first) {
24+
if (*first != x)
25+
break;
26+
}
27+
return first;
28+
}
29+
30+
template<typename Range, typename T>
31+
BOOST_CXX14_CONSTEXPR
32+
typename boost::range_iterator<Range>::type find_not(Range & r, const T & x)
33+
{
34+
return ::boost::algorithm::find_not(boost::begin(r), boost::end(r), x);
35+
}
36+
37+
}} // namespace boost and algorithm
38+
39+
#endif // BOOST_ALGORITHM_FIND_NOT_HPP

test/Jamfile.v2

+4-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ alias unit_test_framework
8585
[ run is_partitioned_until_test.cpp unit_test_framework : : : : is_partitioned_until_test ]
8686

8787
# Apply_permutation tests
88-
[ run apply_permutation_test.cpp unit_test_framework : : : : apply_permutation_test ]
88+
[ run apply_permutation_test.cpp unit_test_framework : : : : apply_permutation_test ]
89+
# Find tests
90+
[ run find_not_test.cpp unit_test_framework : : : : find_not_test ]
91+
[ run find_backward_test.cpp unit_test_framework : : : : find_backward_test ]
8992
;
9093
}
9194

0 commit comments

Comments
 (0)