Merge pull request #47 from tzlaine/develop

Add find() variants.
This commit is contained in:
Marshall Clow
2018-05-18 07:37:36 -07:00
committed by GitHub
8 changed files with 895 additions and 1 deletions

View File

@ -64,6 +64,8 @@ Thanks to all the people who have reviewed this library and made suggestions for
[section:Misc Other Algorithms]
[include clamp-hpp.qbk]
[include find_not.qbk]
[include find_backward.qbk]
[include gather.qbk]
[include hex.qbk]
[include is_palindrome.qbk]

116
doc/find_backward.qbk Normal file
View File

@ -0,0 +1,116 @@
[/ File find_backward.qbk]
[section:find_backward find_backward ]
[/license
Copyright (c) 2018 T. Zachary Laine
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
]
The header file 'find_backward.hpp' contains variants of the stl algorithm
`find`. These variants are like `find`, except that the evaluate the elements
of the given sequence in reverse order.
Consider how finding the last element that is equal to `x` in a range is
typically done:
// Assume a valid range if elements delimited by [first, last).
while (last-- != first) {
if (*last == x) {
// Use last here...
}
}
Raw loops are icky though. Perhaps we should do a bit of extra work to allow
the use of `std::find()`:
auto rfirst = std::make_reverse_iterator(last);
auto rlast = std::make_reverse_iterator(first);
auto it = std::find(rfirst, rlast);
// Use it here...
That seems nicer in that there is no raw loop, but it has two major drawbacks.
First, it requires an unpleasant amount of typing. Second, it is less
efficient than forward-iterator `find` , since `std::reverse_iterator` calls
its base-iterator's `operator--()` in most of its member functions before
doing the work that the member function requires.
[heading interface]
template<typename BidiIter, typename T>
BidiIter find_backward(BidiIter first, BidiIter last, const T & x);
template<typename Range, typename T>
boost::range_iterator<Range> find_backward(Range & range, const T & x);
These overloads of `find_backward` return an iterator to the last element that
is equal to `x` in `[first, last)` or `r`, respectively.
template<typename BidiIter, typename T>
BidiIter find_not_backward(BidiIter first, BidiIter last, const T & x);
template<typename Range, typename T>
boost::range_iterator<Range> find_not_backward(Range & range, const T & x);
These overloads of `find_not_backward` return an iterator to the last element
that is not equal to `x` in `[first, last)` or `r`, respectively.
template<typename BidiIter, typename Pred>
BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p);
template<typename Range, typename Pred>
boost::range_iterator<Range> find_if_backward(Range & range, Pred p);
These overloads of `find_if_backward` return an iterator to the last element
for which `pred` returns `true` in `[first, last)` or `r`, respectively.
template<typename BidiIter, typename Pred>
BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p);
template<typename Range, typename Pred>
boost::range_iterator<Range> find_if_not_backward(Range & range, Pred p);
These overloads of `find_if_not_backward` return an iterator to the last
element for which `pred` returns `false` in `[first, last)` or `r`,
respectively.
[heading Examples]
Given the container `c1` containing `{ 2, 1, 2 }`, then
find_backward ( c1.begin(), c1.end(), 2 ) --> --c1.end()
find_backward ( c1.begin(), c1.end(), 3 ) --> c1.end()
find_if_backward ( c1.begin(), c1.end(), [](int i) {return i == 2;} ) --> --c1.end()
find_if_backward ( c1.begin(), c1.end(), [](int i) {return i == 3;} ) --> c1.end()
find_not_backward ( c1.begin(), c1.end(), 2 ) --> std::prev(c1.end(), 2)
find_not_backward ( c1.begin(), c1.end(), 1 ) --> c1.end()
find_if_not_backward ( c1.begin(), c1.end(), [](int i) {return i == 2;} ) --> std::prev(c1.end(), 2)
find_if_not_backward ( c1.begin(), c1.end(), [](int i) {return i == 1;} ) --> c1.end()
[heading Iterator Requirements]
All variants work on bidirectional iterators.
[heading Complexity]
Linear.
[heading Exception Safety]
All of the variants take their parameters by value and do not depend upon any
global state. Therefore, all the routines in this file provide the strong
exception guarantee.
[heading Notes]
All variants are `constexpr` in C++14 or later.
[endsect]
[/ File equal.qbk
Copyright 2018 T. Zachary Laine
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
]

83
doc/find_not.qbk Normal file
View File

@ -0,0 +1,83 @@
[/ File find_not.qbk]
[section:find_not find_not ]
[/license
Copyright (c) 2018 T. Zachary Laine
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
]
The header file 'find_not.hpp' contains a variants of a the stl algorithm
`find`. The algorithm finds the first value in the given sequence that is not
equal to the given value.
Consider this use of `find()`:
auto std::vector<int> vec = { 1, 1, 2 };
auto it = std::find(vec.begin(), vec.end(), 1);
This gives us the first occurance of `1` in `vec`. What if we want to find
the first occurrance of any number besides `1` in `vec`? We have to write an
unfortunate amount of code:
auto std::vector<int> vec = { 1, 1, 2 };
auto it = std::find_if(vec.begin(), vec.end(), [](int i) { return i != 1; });
With `find_not()` the code gets much more terse:
auto std::vector<int> vec = { 1, 1, 2 };
auto it = find_not(vec.begin(), vec.end(), 1);
The existing `find` variants are: `find()`, `find_if()`, and `find_if_not()`.
It seems natural to also have `find_not()`, for the very reason that we have
`find_if_not()` -- to avoid having to write a lambda to wrap the negation of
the find condition.
[heading interface]
template<typename InputIter, typename Sentinel, typename T>
InputIter find_not(InputIter first, Sentinel last, const T & x);
template<typename Range, typename T>
boost::range_iterator<Range> find_not(Range & r, const T & x);
These overloads of `find_not` return the first value that is not equal to `x`
in the sequence `[first, last)` or `r`, respectively.
[heading Examples]
Given the container `c1` containing `{ 0, 1, 2 }`, then
find_not ( c1.begin(), c1.end(), 1 ) --> c1.begin()
find_not ( c1.begin(), c1.end(), 0 ) --> std::next(c1.begin())
[heading Iterator Requirements]
`find_not` works on all iterators except output iterators.
The template parameter `Sentinel` is allowed to be different from `InputIter`,
or they may be the same. For an `InputIter` `it` and a `Sentinel` `end`, `it
== end` and `it != end` must be well-formed expressions.
[heading Complexity]
Linear.
[heading Exception Safety]
`find_not` takes its parameters by value and do not depend upon any global
state. Therefore, it provides the strong exception guarantee.
[heading Notes]
`constexpr` in C++14 or later.
[endsect]
[/ File equal.qbk
Copyright 2018 T. Zachary Laine
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
]

View File

@ -0,0 +1,97 @@
/*
Copyright (c) T. Zachary Laine 2018.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt)
*/
#ifndef BOOST_ALGORITHM_FIND_BACKWARD_HPP
#define BOOST_ALGORITHM_FIND_BACKWARD_HPP
#include <boost/config.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <utility>
namespace boost { namespace algorithm {
template<typename BidiIter, typename T>
BOOST_CXX14_CONSTEXPR
BidiIter find_backward(BidiIter first, BidiIter last, const T & x)
{
BidiIter it = last;
while (it != first) {
if (*--it == x)
return it;
}
return last;
}
template<typename Range, typename T>
BOOST_CXX14_CONSTEXPR
typename boost::range_iterator<Range>::type find_backward(Range & range, const T & x)
{
return ::boost::algorithm::find_backward(boost::begin(range), boost::end(range), x);
}
template<typename BidiIter, typename T>
BOOST_CXX14_CONSTEXPR
BidiIter find_not_backward(BidiIter first, BidiIter last, const T & x)
{
BidiIter it = last;
while (it != first) {
if (*--it != x)
return it;
}
return last;
}
template<typename Range, typename T>
BOOST_CXX14_CONSTEXPR
typename boost::range_iterator<Range>::type find_not_backward(Range & range, const T & x)
{
return ::boost::algorithm::find_not_backward(boost::begin(range), boost::end(range), x);
}
template<typename BidiIter, typename Pred>
BOOST_CXX14_CONSTEXPR
BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p)
{
BidiIter it = last;
while (it != first) {
if (p(*--it))
return it;
}
return last;
}
template<typename Range, typename Pred>
BOOST_CXX14_CONSTEXPR
typename boost::range_iterator<Range>::type find_if_backward(Range & range, Pred p)
{
return ::boost::algorithm::find_if_backward(boost::begin(range), boost::end(range), p);
}
template<typename BidiIter, typename Pred>
BOOST_CXX14_CONSTEXPR
BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p)
{
BidiIter it = last;
while (it != first) {
if (!p(*--it))
return it;
}
return last;
}
template<typename Range, typename Pred>
BOOST_CXX14_CONSTEXPR
typename boost::range_iterator<Range>::type find_if_not_backward(Range & range, Pred p)
{
return ::boost::algorithm::find_if_not_backward(boost::begin(range), boost::end(range), p);
}
}} // namespace boost and algorithm
#endif // BOOST_ALGORITHM_FIND_BACKWARD_HPP

View File

@ -0,0 +1,39 @@
/*
Copyright (c) T. Zachary Laine 2018.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt)
*/
#ifndef BOOST_ALGORITHM_FIND_NOT_HPP
#define BOOST_ALGORITHM_FIND_NOT_HPP
#include <boost/config.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <utility>
namespace boost { namespace algorithm {
template<typename InputIter, typename Sentinel, typename T>
BOOST_CXX14_CONSTEXPR
InputIter find_not(InputIter first, Sentinel last, const T & x)
{
for (; first != last; ++first) {
if (*first != x)
break;
}
return first;
}
template<typename Range, typename T>
BOOST_CXX14_CONSTEXPR
typename boost::range_iterator<Range>::type find_not(Range & r, const T & x)
{
return ::boost::algorithm::find_not(boost::begin(r), boost::end(r), x);
}
}} // namespace boost and algorithm
#endif // BOOST_ALGORITHM_FIND_NOT_HPP

View File

@ -85,7 +85,10 @@ alias unit_test_framework
[ run is_partitioned_until_test.cpp unit_test_framework : : : : is_partitioned_until_test ]
# Apply_permutation tests
[ run apply_permutation_test.cpp unit_test_framework : : : : apply_permutation_test ]
[ run apply_permutation_test.cpp unit_test_framework : : : : apply_permutation_test ]
# Find tests
[ run find_not_test.cpp unit_test_framework : : : : find_not_test ]
[ run find_backward_test.cpp unit_test_framework : : : : find_backward_test ]
;
}

420
test/find_backward_test.cpp Normal file
View File

@ -0,0 +1,420 @@
/*
Copyright (c) T. Zachary Laine 2018.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#include <iostream>
#include <boost/algorithm/find_backward.hpp>
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <vector>
#include <list>
namespace ba = boost::algorithm;
template <typename Container>
struct dist_t
{
dist_t(Container & cont) : cont_(cont) {}
template<typename Iter>
std::ptrdiff_t operator()(Iter it) const
{
return std::distance(cont_.begin(), it);
}
Container & cont_;
};
BOOST_CXX14_CONSTEXPR bool check_constexpr_backward()
{
int in_data[] = {1, 2, 3, 4, 5};
bool res = true;
const int* from = in_data;
const int* to = in_data + 5;
const int* start = ba::find_backward(from, to, 1); // stops on first
res = (res && start == from);
start = ba::find_backward(in_data, 1); // stops on first
res = (res && start == from);
const int* end = ba::find_backward(from, to, 6); // stops on the end
res = (res && end == to);
end = ba::find_backward(in_data, 6); // stops on the end
res = (res && end == to);
const int* three = ba::find_backward(from, to, 3); // stops on third element
res = (res && three == in_data + 2);
three = ba::find_backward(in_data, 3); // stops on third element
res = (res && three == in_data + 2);
return res;
}
void test_find_backward()
{
{
std::vector<int> v1;
const dist_t<std::vector<int> > dist(v1);
for (int i = 5; i < 15; ++i)
v1.push_back(i);
BOOST_CHECK_EQUAL(
dist(ba::find_backward(v1.begin(), v1.end(), 0)), v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_backward(v1.begin(), v1.end(), 100)), v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_backward(v1.begin(), v1.end(), v1.back())),
v1.size() - 1);
BOOST_CHECK_EQUAL(
dist(ba::find_backward(v1.begin(), v1.end(), v1.front())), 0);
BOOST_CHECK_EQUAL(dist(ba::find_backward(v1, 0)), v1.size());
BOOST_CHECK_EQUAL(dist(ba::find_backward(v1, 100)), v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_backward(v1, v1.back())), v1.size() - 1);
BOOST_CHECK_EQUAL(dist(ba::find_backward(v1, v1.front())), 0);
}
// With bidirectional iterators.
{
std::list<int> l1;
const dist_t<std::list<int> > dist(l1);
for (int i = 5; i < 15; ++i)
l1.push_back(i);
BOOST_CHECK_EQUAL(
dist(ba::find_backward(l1.begin(), l1.end(), 0)), l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_backward(l1.begin(), l1.end(), 100)), l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_backward(l1.begin(), l1.end(), l1.back())),
l1.size() - 1);
BOOST_CHECK_EQUAL(
dist(ba::find_backward(l1.begin(), l1.end(), l1.front())), 0);
BOOST_CHECK_EQUAL(dist(ba::find_backward(l1, 0)), l1.size());
BOOST_CHECK_EQUAL(dist(ba::find_backward(l1, 100)), l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_backward(l1, l1.back())), l1.size() - 1);
BOOST_CHECK_EQUAL(dist(ba::find_backward(l1, l1.front())), 0);
}
BOOST_CXX14_CONSTEXPR bool ce_result = check_constexpr_backward();
BOOST_CHECK(ce_result);
}
struct equals
{
BOOST_CXX14_CONSTEXPR equals(int n) : n_(n) {}
BOOST_CXX14_CONSTEXPR bool operator()(int i) { return i == n_; }
int n_;
};
BOOST_CXX14_CONSTEXPR bool check_constexpr_if_backward()
{
int in_data[] = {1, 2, 3, 4, 5};
bool res = true;
const int* from = in_data;
const int* to = in_data + 5;
const int* start = ba::find_if_backward(from, to, equals(1)); // stops on first
res = (res && start == from);
start = ba::find_if_backward(in_data, equals(1)); // stops on first
res = (res && start == from);
const int* end = ba::find_if_backward(from, to, equals(6)); // stops on the end
res = (res && end == to);
end = ba::find_if_backward(in_data, equals(6)); // stops on the end
res = (res && end == to);
const int* three = ba::find_if_backward(from, to, equals(3)); // stops on third element
res = (res && three == in_data + 2);
three = ba::find_if_backward(in_data, equals(3)); // stops on third element
res = (res && three == in_data + 2);
return res;
}
void test_find_if_backward()
{
{
std::vector<int> v1;
const dist_t<std::vector<int> > dist(v1);
for (int i = 5; i < 15; ++i)
v1.push_back(i);
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(v1.begin(), v1.end(), equals(0))),
v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(v1.begin(), v1.end(), equals(100))),
v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(v1.begin(), v1.end(), equals(v1.back()))),
v1.size() - 1);
BOOST_CHECK_EQUAL(
dist(
ba::find_if_backward(v1.begin(), v1.end(), equals(v1.front()))),
0);
BOOST_CHECK_EQUAL(dist(ba::find_if_backward(v1, equals(0))), v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(v1, equals(100))), v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(v1, equals(v1.back()))), v1.size() - 1);
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(v1, equals(v1.front()))), 0);
}
// With bidirectional iterators.
{
std::list<int> l1;
const dist_t<std::list<int> > dist(l1);
for (int i = 5; i < 15; ++i)
l1.push_back(i);
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(l1.begin(), l1.end(), equals(0))),
l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(l1.begin(), l1.end(), equals(100))),
l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(l1.begin(), l1.end(), equals(l1.back()))),
l1.size() - 1);
BOOST_CHECK_EQUAL(
dist(
ba::find_if_backward(l1.begin(), l1.end(), equals(l1.front()))),
0);
BOOST_CHECK_EQUAL(dist(ba::find_if_backward(l1, equals(0))), l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(l1, equals(100))), l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(l1, equals(l1.back()))), l1.size() - 1);
BOOST_CHECK_EQUAL(
dist(ba::find_if_backward(l1, equals(l1.front()))), 0);
}
BOOST_CXX14_CONSTEXPR bool ce_result = check_constexpr_if_backward();
BOOST_CHECK(ce_result);
}
struct not_equals
{
BOOST_CXX14_CONSTEXPR not_equals(int n) : n_(n) {}
BOOST_CXX14_CONSTEXPR bool operator()(int i) { return i != n_; }
int n_;
};
BOOST_CXX14_CONSTEXPR bool check_constexpr_if_not_backward()
{
int in_data[] = {1, 2, 3, 4, 5};
bool res = true;
const int* from = in_data;
const int* to = in_data + 5;
const int* start = ba::find_if_not_backward(from, to, not_equals(1)); // stops on first
res = (res && start == from);
start = ba::find_if_not_backward(in_data, not_equals(1)); // stops on first
res = (res && start == from);
const int* end = ba::find_if_not_backward(from, to, not_equals(6)); // stops on the end
res = (res && end == to);
end = ba::find_if_not_backward(in_data, not_equals(6)); // stops on the end
res = (res && end == to);
const int* three = ba::find_if_not_backward(from, to, not_equals(3)); // stops on third element
res = (res && three == in_data + 2);
three = ba::find_if_not_backward(in_data, not_equals(3)); // stops on third element
res = (res && three == in_data + 2);
return res;
}
void test_find_if_not_backward()
{
{
std::vector<int> v1;
const dist_t<std::vector<int> > dist(v1);
for (int i = 5; i < 15; ++i)
v1.push_back(i);
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(v1.begin(), v1.end(), not_equals(0))),
v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(
v1.begin(), v1.end(), not_equals(100))),
v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(
v1.begin(), v1.end(), not_equals(v1.back()))),
v1.size() - 1);
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(
v1.begin(), v1.end(), not_equals(v1.front()))),
0);
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(v1, not_equals(0))), v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(v1, not_equals(100))), v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(v1, not_equals(v1.back()))),
v1.size() - 1);
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(v1, not_equals(v1.front()))), 0);
}
// With bidirectional iterators.
{
std::list<int> l1;
const dist_t<std::list<int> > dist(l1);
for (int i = 5; i < 15; ++i)
l1.push_back(i);
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(l1.begin(), l1.end(), not_equals(0))),
l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(
l1.begin(), l1.end(), not_equals(100))),
l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(
l1.begin(), l1.end(), not_equals(l1.back()))),
l1.size() - 1);
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(
l1.begin(), l1.end(), not_equals(l1.front()))),
0);
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(l1, not_equals(0))), l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(l1, not_equals(100))), l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(l1, not_equals(l1.back()))),
l1.size() - 1);
BOOST_CHECK_EQUAL(
dist(ba::find_if_not_backward(l1, not_equals(l1.front()))), 0);
}
BOOST_CXX14_CONSTEXPR bool ce_result = check_constexpr_if_not_backward();
BOOST_CHECK(ce_result);
}
BOOST_CXX14_CONSTEXPR bool check_constexpr_not_backward()
{
int in_data[] = {1, 5, 5, 5, 5};
bool res = true;
const int* from = in_data;
const int* to = in_data + 5;
const int* start = ba::find_not_backward(from, to, 5); // stops on first
res = (res && start == from);
start = ba::find_not_backward(in_data, 5); // stops on first
res = (res && start == from);
const int in_data_2[] = {6, 6, 6, 6, 6};
const int* end = ba::find_not_backward(in_data_2, in_data_2 + 5, 6); // stops on the end
res = (res && end == in_data_2 + 5);
end = ba::find_not_backward(in_data_2, 6); // stops on the end
res = (res && end == in_data_2 + 5);
return res;
}
void test_find_not_backward()
{
{
std::vector<int> v1;
const dist_t<std::vector<int> > dist(v1);
for (int i = 0; i < 5; ++i)
v1.push_back(0);
for (int i = 0; i < 5; ++i)
v1.push_back(1);
BOOST_CHECK_EQUAL(
dist(ba::find_not_backward(v1.begin(), v1.end(), 1)), 4);
BOOST_CHECK_EQUAL(
dist(ba::find_not_backward(v1.begin(), v1.end(), 0)),
v1.size() - 1);
BOOST_CHECK_EQUAL(
dist(ba::find_not_backward(v1.begin(), v1.end(), 2)),
v1.size() - 1);
BOOST_CHECK_EQUAL(dist(ba::find_not_backward(v1, 1)), 4);
BOOST_CHECK_EQUAL(dist(ba::find_not_backward(v1, 0)), v1.size() - 1);
BOOST_CHECK_EQUAL(dist(ba::find_not_backward(v1, 2)), v1.size() - 1);
v1.resize(5);
BOOST_CHECK_EQUAL(
dist(ba::find_not_backward(v1.begin(), v1.end(), 0)), v1.size());
BOOST_CHECK_EQUAL(dist(ba::find_not_backward(v1, 0)), v1.size());
}
// With bidirectional iterators.
{
std::list<int> l1;
const dist_t<std::list<int> > dist(l1);
for (int i = 0; i < 5; ++i)
l1.push_back(0);
for (int i = 0; i < 5; ++i)
l1.push_back(1);
BOOST_CHECK_EQUAL(
dist(ba::find_not_backward(l1.begin(), l1.end(), 1)), 4);
BOOST_CHECK_EQUAL(
dist(ba::find_not_backward(l1.begin(), l1.end(), 0)),
l1.size() - 1);
BOOST_CHECK_EQUAL(
dist(ba::find_not_backward(l1.begin(), l1.end(), 2)),
l1.size() - 1);
BOOST_CHECK_EQUAL(dist(ba::find_not_backward(l1, 1)), 4);
BOOST_CHECK_EQUAL(dist(ba::find_not_backward(l1, 0)), l1.size() - 1);
BOOST_CHECK_EQUAL(dist(ba::find_not_backward(l1, 2)), l1.size() - 1);
l1.resize(5);
BOOST_CHECK_EQUAL(
dist(ba::find_not_backward(l1.begin(), l1.end(), 0)), l1.size());
BOOST_CHECK_EQUAL(dist(ba::find_not_backward(l1, 0)), l1.size());
}
BOOST_CXX14_CONSTEXPR bool ce_result = check_constexpr_not_backward();
BOOST_CHECK(ce_result);
}
BOOST_AUTO_TEST_CASE(test_main)
{
test_find_backward();
test_find_if_backward();
test_find_if_not_backward();
test_find_not_backward();
}

134
test/find_not_test.cpp Normal file
View File

@ -0,0 +1,134 @@
/*
Copyright (c) T. Zachary Laine 2018.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#include <iostream>
#include <boost/algorithm/find_not.hpp>
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <vector>
#include <list>
namespace ba = boost::algorithm;
template <typename Container>
struct dist_t
{
dist_t(Container & cont) : cont_(cont) {}
template<typename Iter>
std::ptrdiff_t operator()(Iter it) const
{
return std::distance(cont_.begin(), it);
}
Container & cont_;
};
BOOST_CXX14_CONSTEXPR bool check_constexpr()
{
int in_data[] = {2, 2, 3, 4, 5};
bool res = true;
const int* from = in_data;
const int* to = in_data + 5;
const int* start = ba::find_not(from, to, 1); // stops on first
res = (res && start == from);
start = ba::find_not(in_data, 1); // stops on first
res = (res && start == from);
int in_data_2[] = {6, 6, 6, 6, 6};
const int* end = ba::find_not(in_data_2, in_data_2 + 5, 6); // stops on the end
res = (res && end == in_data_2 + 5);
end = ba::find_not(in_data_2, 6); // stops on the end
res = (res && end == in_data_2 + 5);
const int* three = ba::find_not(from, to, 2); // stops on third element
res = (res && three == in_data + 2);
three = ba::find_not(in_data, 2); // stops on third element
res = (res && three == in_data + 2);
return res;
}
void test_sequence()
{
{
std::vector<int> v1;
const dist_t<std::vector<int> > dist(v1);
for (int i = 5; i < 15; ++i)
v1.push_back(i);
BOOST_CHECK_EQUAL(dist(ba::find_not(v1.begin(), v1.end(), 0)), 0);
BOOST_CHECK_EQUAL(
dist(ba::find_not(v1.begin(), v1.end(), v1.back())), 0);
BOOST_CHECK_EQUAL(
dist(ba::find_not(v1.begin(), v1.end(), v1.front())), 1);
BOOST_CHECK_EQUAL(dist(ba::find_not(v1, 0)), 0);
BOOST_CHECK_EQUAL(dist(ba::find_not(v1, v1.back())), 0);
BOOST_CHECK_EQUAL(dist(ba::find_not(v1, v1.front())), 1);
v1 = std::vector<int>(10, 2);
BOOST_CHECK_EQUAL(dist(ba::find_not(v1.begin(), v1.end(), 0)), 0);
BOOST_CHECK_EQUAL(
dist(ba::find_not(v1.begin(), v1.end(), v1.back())), v1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_not(v1.begin(), v1.end(), v1.front())), v1.size());
BOOST_CHECK_EQUAL(dist(ba::find_not(v1, 0)), 0);
BOOST_CHECK_EQUAL(dist(ba::find_not(v1, v1.back())), v1.size());
BOOST_CHECK_EQUAL(dist(ba::find_not(v1, v1.front())), v1.size());
}
// With bidirectional iterators.
{
std::list<int> l1;
const dist_t<std::list<int> > dist(l1);
for (int i = 5; i < 15; ++i)
l1.push_back(i);
BOOST_CHECK_EQUAL(dist(ba::find_not(l1.begin(), l1.end(), 0)), 0);
BOOST_CHECK_EQUAL(
dist(ba::find_not(l1.begin(), l1.end(), l1.back())), 0);
BOOST_CHECK_EQUAL(
dist(ba::find_not(l1.begin(), l1.end(), l1.front())), 1);
BOOST_CHECK_EQUAL(dist(ba::find_not(l1, 0)), 0);
BOOST_CHECK_EQUAL(dist(ba::find_not(l1, l1.back())), 0);
BOOST_CHECK_EQUAL(dist(ba::find_not(l1, l1.front())), 1);
l1.clear();
for (int i = 0; i < 10; ++i)
l1.push_back(2);
BOOST_CHECK_EQUAL(dist(ba::find_not(l1.begin(), l1.end(), 0)), 0);
BOOST_CHECK_EQUAL(
dist(ba::find_not(l1.begin(), l1.end(), l1.back())), l1.size());
BOOST_CHECK_EQUAL(
dist(ba::find_not(l1.begin(), l1.end(), l1.front())), l1.size());
BOOST_CHECK_EQUAL(dist(ba::find_not(l1, 0)), 0);
BOOST_CHECK_EQUAL(dist(ba::find_not(l1, l1.back())), l1.size());
BOOST_CHECK_EQUAL(dist(ba::find_not(l1, l1.front())), l1.size());
}
BOOST_CXX14_CONSTEXPR bool ce_result = check_constexpr();
BOOST_CHECK(ce_result);
}
BOOST_AUTO_TEST_CASE(test_main)
{
test_sequence();
}