From d7d91d431a53efdc5d6c555cb1e76a79ae16e0af Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Tue, 8 May 2018 16:33:25 -0500 Subject: [PATCH 1/9] Add find_not() and the four find_*_backward overloads from Boost.Text. Needs tests. --- include/boost/algorithm/find_backward.hpp | 62 +++++++++++++++++++++++ include/boost/algorithm/find_not.hpp | 28 ++++++++++ 2 files changed, 90 insertions(+) create mode 100644 include/boost/algorithm/find_backward.hpp create mode 100644 include/boost/algorithm/find_not.hpp diff --git a/include/boost/algorithm/find_backward.hpp b/include/boost/algorithm/find_backward.hpp new file mode 100644 index 0000000..6bf102c --- /dev/null +++ b/include/boost/algorithm/find_backward.hpp @@ -0,0 +1,62 @@ +/* + 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 +#include + + +namespace boost { namespace algorithm { + +template +BOOST_CXX14_CONSTEXPR BidiIter find_backward(BidiIter first, BidiIter last, T const & x) +{ + auto it = last; + while (it != first) { + if (*--it == x) + return it; + } + return last; +} + +template +BOOST_CXX14_CONSTEXPR BidiIter find_not_backward(BidiIter first, BidiIter last, T const & x) +{ + auto it = last; + while (it != first) { + if (*--it != x) + return it; + } + return last; +} + +template +BOOST_CXX14_CONSTEXPR BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p) +{ + auto it = last; + while (it != first) { + if (p(*--it)) + return it; + } + return last; +} + +template +BOOST_CXX14_CONSTEXPR BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p) +{ + auto it = last; + while (it != first) { + if (!p(*--it)) + return it; + } + return last; +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_FIND_BACKWARD_HPP diff --git a/include/boost/algorithm/find_not.hpp b/include/boost/algorithm/find_not.hpp new file mode 100644 index 0000000..420372b --- /dev/null +++ b/include/boost/algorithm/find_not.hpp @@ -0,0 +1,28 @@ +/* + 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 +#include + + +namespace boost { namespace algorithm { + +template +BOOST_CXX14_CONSTEXPR InputIter find_not(InputIter first, Sentinel last, T const & x) +{ + for (; first != last; ++first) { + if (*first != x) + break; + } + return first; +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_FIND_NOT_HPP From 45a4d2580c51b0d3935e854b891d8c9aa72fffd6 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Thu, 10 May 2018 12:32:09 -0500 Subject: [PATCH 2/9] Add tests for find_not.hpp. --- test/Jamfile.v2 | 4 +- test/find_not_test.cpp | 109 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 test/find_not_test.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 813be2c..942294d 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -85,7 +85,9 @@ 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 ] ; } diff --git a/test/find_not_test.cpp b/test/find_not_test.cpp new file mode 100644 index 0000000..40b0b71 --- /dev/null +++ b/test/find_not_test.cpp @@ -0,0 +1,109 @@ +/* + 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 + +#include + +#define BOOST_TEST_MAIN +#include + +#include +#include + + +namespace ba = boost::algorithm; + +template +struct dist_t +{ + dist_t(Container & cont) : cont_(cont) {} + template + 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); + + 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); + + const int* three = ba::find_not(from, to, 2); // stops on third element + res = (res && three == in_data + 2); + + return res; +} + +void test_sequence() +{ + { + std::vector v1; + dist_t > const 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); + + v1 = std::vector(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()); + } + + // With bidirectional iterators. + { + std::list l1; + dist_t > const 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); + + 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_CXX14_CONSTEXPR bool ce_result = check_constexpr(); + BOOST_CHECK(ce_result); +} + + +BOOST_AUTO_TEST_CASE(test_main) +{ + test_sequence(); +} From 94460b0ca54b8a0bddc38625ac3fc2fad38ad9c3 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Thu, 10 May 2018 13:22:53 -0500 Subject: [PATCH 3/9] Add tests for find_backward.hpp. --- include/boost/algorithm/find_backward.hpp | 8 +- test/Jamfile.v2 | 1 + test/find_backward_test.cpp | 327 ++++++++++++++++++++++ 3 files changed, 332 insertions(+), 4 deletions(-) create mode 100644 test/find_backward_test.cpp diff --git a/include/boost/algorithm/find_backward.hpp b/include/boost/algorithm/find_backward.hpp index 6bf102c..1a2bff7 100644 --- a/include/boost/algorithm/find_backward.hpp +++ b/include/boost/algorithm/find_backward.hpp @@ -16,7 +16,7 @@ namespace boost { namespace algorithm { template BOOST_CXX14_CONSTEXPR BidiIter find_backward(BidiIter first, BidiIter last, T const & x) { - auto it = last; + BidiIter it = last; while (it != first) { if (*--it == x) return it; @@ -27,7 +27,7 @@ BOOST_CXX14_CONSTEXPR BidiIter find_backward(BidiIter first, BidiIter last, T co template BOOST_CXX14_CONSTEXPR BidiIter find_not_backward(BidiIter first, BidiIter last, T const & x) { - auto it = last; + BidiIter it = last; while (it != first) { if (*--it != x) return it; @@ -38,7 +38,7 @@ BOOST_CXX14_CONSTEXPR BidiIter find_not_backward(BidiIter first, BidiIter last, template BOOST_CXX14_CONSTEXPR BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p) { - auto it = last; + BidiIter it = last; while (it != first) { if (p(*--it)) return it; @@ -49,7 +49,7 @@ BOOST_CXX14_CONSTEXPR BidiIter find_if_backward(BidiIter first, BidiIter last, P template BOOST_CXX14_CONSTEXPR BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p) { - auto it = last; + BidiIter it = last; while (it != first) { if (!p(*--it)) return it; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 942294d..30cb786 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -88,6 +88,7 @@ alias unit_test_framework [ 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 ] ; } diff --git a/test/find_backward_test.cpp b/test/find_backward_test.cpp new file mode 100644 index 0000000..9a51281 --- /dev/null +++ b/test/find_backward_test.cpp @@ -0,0 +1,327 @@ +/* + 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 + +#include + +#define BOOST_TEST_MAIN +#include + +#include +#include + + +namespace ba = boost::algorithm; + +template +struct dist_t +{ + dist_t(Container & cont) : cont_(cont) {} + template + 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); + + const int* end = ba::find_backward(from, to, 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); + + return res; +} + +void test_find_backward() +{ + { + std::vector v1; + dist_t > const 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); + } + + // With bidirectional iterators. + { + std::list l1; + dist_t > const 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_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); + + const int* end = ba::find_if_backward(from, to, 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); + + return res; +} + +void test_find_if_backward() +{ + { + std::vector v1; + dist_t > const 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); + } + + // With bidirectional iterators. + { + std::list l1; + dist_t > const 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_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); + + const int* end = ba::find_if_not_backward(from, to, 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); + + return res; +} + +void test_find_if_not_backward() +{ + { + std::vector v1; + dist_t > const 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); + } + + // With bidirectional iterators. + { + std::list l1; + dist_t > const 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_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); + + 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); + + return res; +} + +void test_find_not_backward() +{ + { + std::vector v1; + dist_t > const 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); + + v1.resize(5); + BOOST_CHECK_EQUAL( + dist(ba::find_not_backward(v1.begin(), v1.end(), 0)), v1.size()); + } + + // With bidirectional iterators. + { + std::list l1; + dist_t > const 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); + + l1.resize(5); + BOOST_CHECK_EQUAL( + dist(ba::find_not_backward(l1.begin(), l1.end(), 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(); +} From 86d26e7e2ed529e5b550f49170077f15c0e1ee44 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Thu, 10 May 2018 19:01:12 -0500 Subject: [PATCH 4/9] Add docs for find_not.hpp. --- doc/algorithm.qbk | 1 + doc/find.qbk | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 doc/find.qbk diff --git a/doc/algorithm.qbk b/doc/algorithm.qbk index 8ce6685..9e015df 100644 --- a/doc/algorithm.qbk +++ b/doc/algorithm.qbk @@ -64,6 +64,7 @@ Thanks to all the people who have reviewed this library and made suggestions for [section:Misc Other Algorithms] [include clamp-hpp.qbk] +[include find.qbk] [include gather.qbk] [include hex.qbk] [include is_palindrome.qbk] diff --git a/doc/find.qbk b/doc/find.qbk new file mode 100644 index 0000000..35cd189 --- /dev/null +++ b/doc/find.qbk @@ -0,0 +1,80 @@ +[/ File equal.qbk] + +[section:equal equal ] + +[/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 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 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 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 +our find condition. + +[heading interface] + +`` +template +InputIter find_not(InputIter first, Sentinel last, T const & x); +`` + +The function `find_not` returns the first value in the sequence `[first, +last)` that is not equal to `x`. + +[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] + +`equal` 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. + +[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). +] From 8c9d5e858c545d0d5286d65c189fd9563381da65 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Fri, 11 May 2018 15:14:49 -0500 Subject: [PATCH 5/9] Add docs for find_backward.hpp. --- doc/algorithm.qbk | 3 +- doc/find_backward.qbk | 99 ++++++++++++++++++++++++++++++++++ doc/{find.qbk => find_not.qbk} | 14 +++-- 3 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 doc/find_backward.qbk rename doc/{find.qbk => find_not.qbk} (86%) diff --git a/doc/algorithm.qbk b/doc/algorithm.qbk index 9e015df..3d1230f 100644 --- a/doc/algorithm.qbk +++ b/doc/algorithm.qbk @@ -64,7 +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.qbk] +[include find_not.qbk] +[include find_backward.qbk] [include gather.qbk] [include hex.qbk] [include is_palindrome.qbk] diff --git a/doc/find_backward.qbk b/doc/find_backward.qbk new file mode 100644 index 0000000..820a3fc --- /dev/null +++ b/doc/find_backward.qbk @@ -0,0 +1,99 @@ +[/ 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 if 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, but it has two major drawbacks. First, it requires an +unpleasant amount of typing. Second, it is considerably less efficient than +forward-iterator `find` , since `std::reverse_iterator` calls its +base-iterator's `operator--()` in most of its members before doing the work +that the member requires. + +[heading interface] + + template + BidiIter find_backward(BidiIter first, BidiIter last, T const & x); + +The function `find_backward` returns an iterator to the last element of +`[first, last)` that is equal to `x`. + + template + BidiIter find_not_backward(BidiIter first, BidiIter last, T const & x); + +The function `find_not_backward` returns an iterator to the last element of +`[first, last)` that is not equal to `x`. + + template + BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p); + +The function `find_if_backward` returns an iterator to the last element of +`[first, last)` for which `pred` returns `true`. + + template + BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p); + +The function `find_if_not_backward` returns an iterator to the last element of +`[first, last)` for which `pred` returns `false`. + +[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. + +[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). +] diff --git a/doc/find.qbk b/doc/find_not.qbk similarity index 86% rename from doc/find.qbk rename to doc/find_not.qbk index 35cd189..146f8c9 100644 --- a/doc/find.qbk +++ b/doc/find_not.qbk @@ -1,6 +1,6 @@ -[/ File equal.qbk] +[/ File find_not.qbk] -[section:equal equal ] +[section:find_not find_not ] [/license Copyright (c) 2018 T. Zachary Laine @@ -39,10 +39,8 @@ our find condition. [heading interface] -`` -template -InputIter find_not(InputIter first, Sentinel last, T const & x); -`` + template + InputIter find_not(InputIter first, Sentinel last, T const & x); The function `find_not` returns the first value in the sequence `[first, last)` that is not equal to `x`. @@ -51,8 +49,8 @@ last)` that is not equal to `x`. 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()) + find_not ( c1.begin(), c1.end(), 1 ) --> c1.begin() + find_not ( c1.begin(), c1.end(), 0 ) --> std::next(c1.begin()) [heading Iterator Requirements] From 6c68cf8624c7f25041f3e7dd5ce7488c06a7e3b9 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Sat, 12 May 2018 15:25:37 -0500 Subject: [PATCH 6/9] Add range-based overload of find_not(). --- doc/find_not.qbk | 3 +++ include/boost/algorithm/find_not.hpp | 13 ++++++++++++- test/find_not_test.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/doc/find_not.qbk b/doc/find_not.qbk index 146f8c9..8d26185 100644 --- a/doc/find_not.qbk +++ b/doc/find_not.qbk @@ -42,6 +42,9 @@ our find condition. template InputIter find_not(InputIter first, Sentinel last, T const & x); + template + typename boost::range_iterator::type find_not(Range & r, T const & x); + The function `find_not` returns the first value in the sequence `[first, last)` that is not equal to `x`. diff --git a/include/boost/algorithm/find_not.hpp b/include/boost/algorithm/find_not.hpp index 420372b..8934738 100644 --- a/include/boost/algorithm/find_not.hpp +++ b/include/boost/algorithm/find_not.hpp @@ -8,13 +8,17 @@ #define BOOST_ALGORITHM_FIND_NOT_HPP #include +#include +#include + #include namespace boost { namespace algorithm { template -BOOST_CXX14_CONSTEXPR InputIter find_not(InputIter first, Sentinel last, T const & x) +BOOST_CXX14_CONSTEXPR +InputIter find_not(InputIter first, Sentinel last, T const & x) { for (; first != last; ++first) { if (*first != x) @@ -23,6 +27,13 @@ BOOST_CXX14_CONSTEXPR InputIter find_not(InputIter first, Sentinel last, T const return first; } +template +BOOST_CXX14_CONSTEXPR +typename boost::range_iterator::type find_not(Range & r, T const & x) +{ + return ::boost::algorithm::find_not(boost::begin(r), boost::end(r), x); +} + }} // namespace boost and algorithm #endif // BOOST_ALGORITHM_FIND_NOT_HPP diff --git a/test/find_not_test.cpp b/test/find_not_test.cpp index 40b0b71..6b4c2f3 100644 --- a/test/find_not_test.cpp +++ b/test/find_not_test.cpp @@ -43,13 +43,22 @@ BOOST_CXX14_CONSTEXPR bool check_constexpr() 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; } @@ -67,12 +76,20 @@ void test_sequence() 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(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. @@ -88,6 +105,10 @@ void test_sequence() 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); @@ -96,6 +117,10 @@ void test_sequence() 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(); From c5c5d24ff3984c18bea795b4638b0f7f62680056 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Sat, 12 May 2018 16:03:41 -0500 Subject: [PATCH 7/9] Add range-based overloads of find*_backward(). --- doc/find_backward.qbk | 32 ++++++-- doc/find_not.qbk | 10 ++- include/boost/algorithm/find_backward.hpp | 43 ++++++++++- test/find_backward_test.cpp | 93 +++++++++++++++++++++++ 4 files changed, 163 insertions(+), 15 deletions(-) diff --git a/doc/find_backward.qbk b/doc/find_backward.qbk index 820a3fc..81cec0c 100644 --- a/doc/find_backward.qbk +++ b/doc/find_backward.qbk @@ -42,26 +42,38 @@ that the member requires. template BidiIter find_backward(BidiIter first, BidiIter last, T const & x); -The function `find_backward` returns an iterator to the last element of -`[first, last)` that is equal to `x`. + template + boost::range_iterator find_backward(Range & range, T const & x); + +The function `find_backward` returns an iterator to the last element that is +equal to `x` in `[first, last)` or `r`, respectively. template BidiIter find_not_backward(BidiIter first, BidiIter last, T const & x); -The function `find_not_backward` returns an iterator to the last element of -`[first, last)` that is not equal to `x`. + template + boost::range_iterator find_not_backward(Range & range, T const & x); + +The function `find_not_backward` returns an iterator to the last element that +is not equal to `x` in `[first, last)` or `r`, respectively. template BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p); -The function `find_if_backward` returns an iterator to the last element of -`[first, last)` for which `pred` returns `true`. + template + boost::range_iterator find_if_backward(Range & range, Pred p); + +The function `find_if_backward` returns an iterator to the last element for +which `pred` returns `true` in `[first, last)` or `r`, respectively. template BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p); -The function `find_if_not_backward` returns an iterator to the last element of -`[first, last)` for which `pred` returns `false`. + template + boost::range_iterator find_if_not_backward(Range & range, Pred p); + +The function `find_if_not_backward` returns an iterator to the last element +for which `pred` returns `false` in `[first, last)` or `r`, respectively. [heading Examples] @@ -90,6 +102,10 @@ 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 diff --git a/doc/find_not.qbk b/doc/find_not.qbk index 8d26185..a5a17cf 100644 --- a/doc/find_not.qbk +++ b/doc/find_not.qbk @@ -43,10 +43,10 @@ our find condition. InputIter find_not(InputIter first, Sentinel last, T const & x); template - typename boost::range_iterator::type find_not(Range & r, T const & x); + boost::range_iterator find_not(Range & r, T const & x); -The function `find_not` returns the first value in the sequence `[first, -last)` that is not equal to `x`. +The function `find_not` returns the first value that is not equal to `x` in +the sequence `[first, last)` or `r`, respectively. [heading Examples] @@ -72,6 +72,10 @@ Linear. `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 diff --git a/include/boost/algorithm/find_backward.hpp b/include/boost/algorithm/find_backward.hpp index 1a2bff7..ffa7e03 100644 --- a/include/boost/algorithm/find_backward.hpp +++ b/include/boost/algorithm/find_backward.hpp @@ -8,13 +8,17 @@ #define BOOST_ALGORITHM_FIND_BACKWARD_HPP #include +#include +#include + #include namespace boost { namespace algorithm { template -BOOST_CXX14_CONSTEXPR BidiIter find_backward(BidiIter first, BidiIter last, T const & x) +BOOST_CXX14_CONSTEXPR +BidiIter find_backward(BidiIter first, BidiIter last, T const & x) { BidiIter it = last; while (it != first) { @@ -24,8 +28,16 @@ BOOST_CXX14_CONSTEXPR BidiIter find_backward(BidiIter first, BidiIter last, T co return last; } +template +BOOST_CXX14_CONSTEXPR +typename boost::range_iterator::type find_backward(Range & range, T const & x) +{ + return ::boost::algorithm::find_backward(boost::begin(range), boost::end(range), x); +} + template -BOOST_CXX14_CONSTEXPR BidiIter find_not_backward(BidiIter first, BidiIter last, T const & x) +BOOST_CXX14_CONSTEXPR +BidiIter find_not_backward(BidiIter first, BidiIter last, T const & x) { BidiIter it = last; while (it != first) { @@ -35,8 +47,16 @@ BOOST_CXX14_CONSTEXPR BidiIter find_not_backward(BidiIter first, BidiIter last, return last; } +template +BOOST_CXX14_CONSTEXPR +typename boost::range_iterator::type find_not_backward(Range & range, T const & x) +{ + return ::boost::algorithm::find_not_backward(boost::begin(range), boost::end(range), x); +} + template -BOOST_CXX14_CONSTEXPR BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p) +BOOST_CXX14_CONSTEXPR +BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p) { BidiIter it = last; while (it != first) { @@ -46,8 +66,16 @@ BOOST_CXX14_CONSTEXPR BidiIter find_if_backward(BidiIter first, BidiIter last, P return last; } +template +BOOST_CXX14_CONSTEXPR +typename boost::range_iterator::type find_if_backward(Range & range, Pred p) +{ + return ::boost::algorithm::find_if_backward(boost::begin(range), boost::end(range), p); +} + template -BOOST_CXX14_CONSTEXPR BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p) +BOOST_CXX14_CONSTEXPR +BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p) { BidiIter it = last; while (it != first) { @@ -57,6 +85,13 @@ BOOST_CXX14_CONSTEXPR BidiIter find_if_not_backward(BidiIter first, BidiIter las return last; } +template +BOOST_CXX14_CONSTEXPR +typename boost::range_iterator::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 diff --git a/test/find_backward_test.cpp b/test/find_backward_test.cpp index 9a51281..721c728 100644 --- a/test/find_backward_test.cpp +++ b/test/find_backward_test.cpp @@ -43,12 +43,21 @@ BOOST_CXX14_CONSTEXPR bool check_constexpr_backward() 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; } @@ -69,6 +78,12 @@ void test_find_backward() 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. @@ -87,6 +102,12 @@ void test_find_backward() 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(); @@ -111,12 +132,21 @@ BOOST_CXX14_CONSTEXPR bool check_constexpr_if_backward() 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; } @@ -141,6 +171,14 @@ void test_find_if_backward() 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. @@ -163,6 +201,14 @@ void test_find_if_backward() 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(); @@ -187,12 +233,21 @@ BOOST_CXX14_CONSTEXPR bool check_constexpr_if_not_backward() 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; } @@ -219,6 +274,16 @@ void test_find_if_not_backward() 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. @@ -243,6 +308,16 @@ void test_find_if_not_backward() 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(); @@ -260,10 +335,16 @@ BOOST_CXX14_CONSTEXPR bool check_constexpr_not_backward() 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; } @@ -286,9 +367,15 @@ void test_find_not_backward() 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. @@ -309,9 +396,15 @@ void test_find_not_backward() 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(); From 6b2246468e7ac1cca396cbf3e1f2dbb4529e0527 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Sat, 12 May 2018 16:47:47 -0500 Subject: [PATCH 8/9] find_{not,*backward} docs copy editing. --- doc/find_backward.qbk | 39 ++++++++++++++++++++------------------- doc/find_not.qbk | 16 +++++++--------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/doc/find_backward.qbk b/doc/find_backward.qbk index 81cec0c..838dbc9 100644 --- a/doc/find_backward.qbk +++ b/doc/find_backward.qbk @@ -11,7 +11,7 @@ Distributed under the Boost Software License, Version 1.0. 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 if reverse order. +of the given sequence in reverse order. Consider how finding the last element that is equal to `x` in a range is typically done: @@ -23,7 +23,7 @@ typically done: } } -Raw loops are icky though. PErhaps we should do a bit of extra work to allow +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); @@ -31,31 +31,31 @@ the use of `std::find()`: auto it = std::find(rfirst, rlast); // Use it here... -That seems nicer, but it has two major drawbacks. First, it requires an -unpleasant amount of typing. Second, it is considerably less efficient than -forward-iterator `find` , since `std::reverse_iterator` calls its -base-iterator's `operator--()` in most of its members before doing the work -that the member requires. +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 - BidiIter find_backward(BidiIter first, BidiIter last, T const & x); + BidiIter find_backward(BidiIter first, BidiIter last, const T & x); template - boost::range_iterator find_backward(Range & range, T const & x); + boost::range_iterator find_backward(Range & range, const T & x); -The function `find_backward` returns an iterator to the last element that is -equal to `x` in `[first, last)` or `r`, respectively. +These overloads of `find_backward` return an iterator to the last element that +is equal to `x` in `[first, last)` or `r`, respectively. template - BidiIter find_not_backward(BidiIter first, BidiIter last, T const & x); + BidiIter find_not_backward(BidiIter first, BidiIter last, const T & x); template - boost::range_iterator find_not_backward(Range & range, T const & x); + boost::range_iterator find_not_backward(Range & range, const T & x); -The function `find_not_backward` returns an iterator to the last element that -is not equal to `x` in `[first, last)` or `r`, respectively. +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 BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p); @@ -63,8 +63,8 @@ is not equal to `x` in `[first, last)` or `r`, respectively. template boost::range_iterator find_if_backward(Range & range, Pred p); -The function `find_if_backward` returns an iterator to the last element for -which `pred` returns `true` in `[first, last)` or `r`, respectively. +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 BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p); @@ -72,8 +72,9 @@ which `pred` returns `true` in `[first, last)` or `r`, respectively. template boost::range_iterator find_if_not_backward(Range & range, Pred p); -The function `find_if_not_backward` returns an iterator to the last element -for which `pred` returns `false` in `[first, last)` or `r`, respectively. +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] diff --git a/doc/find_not.qbk b/doc/find_not.qbk index a5a17cf..6df0482 100644 --- a/doc/find_not.qbk +++ b/doc/find_not.qbk @@ -23,9 +23,7 @@ the first occurrance of any number besides `1` in `vec`? We have to write an unfortunate amount of code: auto std::vector vec = { 1, 1, 2 }; - auto it = std::find_if( - vec.begin(), vec.end(), - [](int i) { return i != 1; }); + auto it = std::find_if(vec.begin(), vec.end(), [](int i) { return i != 1; }); With `find_not()` the code gets much more terse: @@ -35,18 +33,18 @@ With `find_not()` the code gets much more terse: 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 -our find condition. +the find condition. [heading interface] template - InputIter find_not(InputIter first, Sentinel last, T const & x); + InputIter find_not(InputIter first, Sentinel last, const T & x); template - boost::range_iterator find_not(Range & r, T const & x); + boost::range_iterator find_not(Range & r, const T & x); -The function `find_not` returns the first value that is not equal to `x` in -the sequence `[first, last)` or `r`, respectively. +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] @@ -57,7 +55,7 @@ Given the container `c1` containing `{ 0, 1, 2 }`, then [heading Iterator Requirements] -`equal` works on all iterators except output iterators. +`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 From 3f2a962ace2d0a58eed757bed5c5def4008c3c85 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Mon, 14 May 2018 19:17:00 -0500 Subject: [PATCH 9/9] East const -> west const. I regret nothing! --- include/boost/algorithm/find_backward.hpp | 8 ++++---- include/boost/algorithm/find_not.hpp | 4 ++-- test/find_backward_test.cpp | 16 ++++++++-------- test/find_not_test.cpp | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/boost/algorithm/find_backward.hpp b/include/boost/algorithm/find_backward.hpp index ffa7e03..66901a1 100644 --- a/include/boost/algorithm/find_backward.hpp +++ b/include/boost/algorithm/find_backward.hpp @@ -18,7 +18,7 @@ namespace boost { namespace algorithm { template BOOST_CXX14_CONSTEXPR -BidiIter find_backward(BidiIter first, BidiIter last, T const & x) +BidiIter find_backward(BidiIter first, BidiIter last, const T & x) { BidiIter it = last; while (it != first) { @@ -30,14 +30,14 @@ BidiIter find_backward(BidiIter first, BidiIter last, T const & x) template BOOST_CXX14_CONSTEXPR -typename boost::range_iterator::type find_backward(Range & range, T const & x) +typename boost::range_iterator::type find_backward(Range & range, const T & x) { return ::boost::algorithm::find_backward(boost::begin(range), boost::end(range), x); } template BOOST_CXX14_CONSTEXPR -BidiIter find_not_backward(BidiIter first, BidiIter last, T const & x) +BidiIter find_not_backward(BidiIter first, BidiIter last, const T & x) { BidiIter it = last; while (it != first) { @@ -49,7 +49,7 @@ BidiIter find_not_backward(BidiIter first, BidiIter last, T const & x) template BOOST_CXX14_CONSTEXPR -typename boost::range_iterator::type find_not_backward(Range & range, T const & x) +typename boost::range_iterator::type find_not_backward(Range & range, const T & x) { return ::boost::algorithm::find_not_backward(boost::begin(range), boost::end(range), x); } diff --git a/include/boost/algorithm/find_not.hpp b/include/boost/algorithm/find_not.hpp index 8934738..ef4df00 100644 --- a/include/boost/algorithm/find_not.hpp +++ b/include/boost/algorithm/find_not.hpp @@ -18,7 +18,7 @@ namespace boost { namespace algorithm { template BOOST_CXX14_CONSTEXPR -InputIter find_not(InputIter first, Sentinel last, T const & x) +InputIter find_not(InputIter first, Sentinel last, const T & x) { for (; first != last; ++first) { if (*first != x) @@ -29,7 +29,7 @@ InputIter find_not(InputIter first, Sentinel last, T const & x) template BOOST_CXX14_CONSTEXPR -typename boost::range_iterator::type find_not(Range & r, T const & x) +typename boost::range_iterator::type find_not(Range & r, const T & x) { return ::boost::algorithm::find_not(boost::begin(r), boost::end(r), x); } diff --git a/test/find_backward_test.cpp b/test/find_backward_test.cpp index 721c728..f78fadb 100644 --- a/test/find_backward_test.cpp +++ b/test/find_backward_test.cpp @@ -65,7 +65,7 @@ void test_find_backward() { { std::vector v1; - dist_t > const dist(v1); + const dist_t > dist(v1); for (int i = 5; i < 15; ++i) v1.push_back(i); @@ -89,7 +89,7 @@ void test_find_backward() // With bidirectional iterators. { std::list l1; - dist_t > const dist(l1); + const dist_t > dist(l1); for (int i = 5; i < 15; ++i) l1.push_back(i); @@ -154,7 +154,7 @@ void test_find_if_backward() { { std::vector v1; - dist_t > const dist(v1); + const dist_t > dist(v1); for (int i = 5; i < 15; ++i) v1.push_back(i); @@ -184,7 +184,7 @@ void test_find_if_backward() // With bidirectional iterators. { std::list l1; - dist_t > const dist(l1); + const dist_t > dist(l1); for (int i = 5; i < 15; ++i) l1.push_back(i); @@ -255,7 +255,7 @@ void test_find_if_not_backward() { { std::vector v1; - dist_t > const dist(v1); + const dist_t > dist(v1); for (int i = 5; i < 15; ++i) v1.push_back(i); @@ -289,7 +289,7 @@ void test_find_if_not_backward() // With bidirectional iterators. { std::list l1; - dist_t > const dist(l1); + const dist_t > dist(l1); for (int i = 5; i < 15; ++i) l1.push_back(i); @@ -352,7 +352,7 @@ void test_find_not_backward() { { std::vector v1; - dist_t > const dist(v1); + const dist_t > dist(v1); for (int i = 0; i < 5; ++i) v1.push_back(0); @@ -381,7 +381,7 @@ void test_find_not_backward() // With bidirectional iterators. { std::list l1; - dist_t > const dist(l1); + const dist_t > dist(l1); for (int i = 0; i < 5; ++i) l1.push_back(0); diff --git a/test/find_not_test.cpp b/test/find_not_test.cpp index 6b4c2f3..ef7529f 100644 --- a/test/find_not_test.cpp +++ b/test/find_not_test.cpp @@ -66,7 +66,7 @@ void test_sequence() { { std::vector v1; - dist_t > const dist(v1); + const dist_t > dist(v1); for (int i = 5; i < 15; ++i) v1.push_back(i); @@ -95,7 +95,7 @@ void test_sequence() // With bidirectional iterators. { std::list l1; - dist_t > const dist(l1); + const dist_t > dist(l1); for (int i = 5; i < 15; ++i) l1.push_back(i);