mirror of
https://github.com/boostorg/algorithm.git
synced 2025-07-29 12:07:18 +02:00
@ -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
116
doc/find_backward.qbk
Normal 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
83
doc/find_not.qbk
Normal 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).
|
||||
]
|
97
include/boost/algorithm/find_backward.hpp
Normal file
97
include/boost/algorithm/find_backward.hpp
Normal 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
|
39
include/boost/algorithm/find_not.hpp
Normal file
39
include/boost/algorithm/find_not.hpp
Normal 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
|
@ -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
420
test/find_backward_test.cpp
Normal 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
134
test/find_not_test.cpp
Normal 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();
|
||||
}
|
Reference in New Issue
Block a user