From d574d1edd7cbf13fedf73d4ede96a568e98bdbd2 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Tue, 1 May 2018 19:10:47 -0700 Subject: [PATCH 01/15] Fuzzing targets for minmax --- minmax/fuzzing/minmax.fuzz.cpp | 52 +++++++++++++++++++ minmax/fuzzing/minmax_element.fuzz.cpp | 71 ++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 minmax/fuzzing/minmax.fuzz.cpp create mode 100644 minmax/fuzzing/minmax_element.fuzz.cpp diff --git a/minmax/fuzzing/minmax.fuzz.cpp b/minmax/fuzzing/minmax.fuzz.cpp new file mode 100644 index 0000000..06c0448 --- /dev/null +++ b/minmax/fuzzing/minmax.fuzz.cpp @@ -0,0 +1,52 @@ +// (C) Copyright Marshall Clow 2018 +// Use, modification and distribution are subject to 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) + +#include + +// Fuzzing tests for: +// +// template +// tuple +// minmax(const T& a, const T& b); +// +// template +// tuple +// minmax(const T& a, const T& b, BinaryPredicate comp); + + +bool greater(uint8_t lhs, uint8_t rhs) { return lhs > rhs; } + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { + typedef boost::tuple result_t; + if (sz < 2) return 0; // we only need two elements + + { + result_t result = boost::minmax(data[0], data[1]); + uint8_t const& first = result.get<0>(); + uint8_t const& second = result.get<1>(); + +// first must be <= second + if (second < first) return 1; + +// The references returned must be data[0] and data[1] + if (&first != data && &first != data + 1) return 2; + if (&second != data && &second != data + 1) return 2; + } + + { + result_t result = boost::minmax(data[0], data[1], greater); + uint8_t const& first = result.get<0>(); + uint8_t const& second = result.get<1>(); + +// first must be <= second + if (greater(second, first)) return 1; + +// The references returned must be data[0] and data[1] + if (&first != data && &first != data + 1) return 2; + if (&second != data && &second != data + 1) return 2; + } + + return 0; +} \ No newline at end of file diff --git a/minmax/fuzzing/minmax_element.fuzz.cpp b/minmax/fuzzing/minmax_element.fuzz.cpp new file mode 100644 index 0000000..d2cb073 --- /dev/null +++ b/minmax/fuzzing/minmax_element.fuzz.cpp @@ -0,0 +1,71 @@ +// (C) Copyright Marshall Clow 2018 +// Use, modification and distribution are subject to 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) + +#include // for std::distance + +#include + +// Fuzzing tests for: +// +// template +// std::pair +// minmax_element(ForwardIterator first, ForwardIterator last); +// +// template +// std::pair +// minmax_element(ForwardIterator first, ForwardIterator last, +// BinaryPredicate comp); + + +bool greater(uint8_t lhs, uint8_t rhs) { return lhs > rhs; } + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { + typedef std::pair result_t; + if (sz == 0) return 0; // we need at least one element + + { +// Find the min and max + result_t result = boost::minmax_element(data, data + sz); + +// The iterators have to be in the sequence + if (std::distance(data, result.first) >= sz) return 1; + if (std::distance(data, result.second) >= sz) return 1; + +// the minimum element can't be bigger than the max element + uint8_t min_value = *result.first; + uint8_t max_value = *result.second; + + if (max_value < min_value) return 2; + +// None of the elements in the sequence can be less than the min, nor greater than the max + for (size_t i = 0; i < sz; ++i) { + if (data[i] < min_value) return 3; + if (max_value < data[i]) return 3; + } + } + + { +// Find the min and max + result_t result = boost::minmax_element(data, data + sz, greater); + +// The iterators have to be in the sequence + if (std::distance(data, result.first) >= sz) return 1; + if (std::distance(data, result.second) >= sz) return 1; + +// the minimum element can't be bigger than the max element + uint8_t min_value = *result.first; + uint8_t max_value = *result.second; + + if (greater(max_value, min_value)) return 2; + +// None of the elements in the sequence can be less than the min, nor greater than the max + for (size_t i = 0; i < sz; ++i) { + if (greater(data[i], min_value)) return 3; + if (greater(max_value, data[i])) return 3; + } + } + + return 0; +} \ No newline at end of file From 7ec1c5c413cd81d11584f329af8a3cb36c9fa770 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 2 May 2018 11:41:16 -0700 Subject: [PATCH 02/15] Remove too-simple test, add tests for the variants of minmax_element --- minmax/fuzzing/minmax.fuzz.cpp | 52 ------- minmax/fuzzing/minmax_element.fuzz.cpp | 34 +++-- .../fuzzing/minmax_element_variants.fuzz.cpp | 139 ++++++++++++++++++ 3 files changed, 161 insertions(+), 64 deletions(-) delete mode 100644 minmax/fuzzing/minmax.fuzz.cpp create mode 100644 minmax/fuzzing/minmax_element_variants.fuzz.cpp diff --git a/minmax/fuzzing/minmax.fuzz.cpp b/minmax/fuzzing/minmax.fuzz.cpp deleted file mode 100644 index 06c0448..0000000 --- a/minmax/fuzzing/minmax.fuzz.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// (C) Copyright Marshall Clow 2018 -// Use, modification and distribution are subject to 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) - -#include - -// Fuzzing tests for: -// -// template -// tuple -// minmax(const T& a, const T& b); -// -// template -// tuple -// minmax(const T& a, const T& b, BinaryPredicate comp); - - -bool greater(uint8_t lhs, uint8_t rhs) { return lhs > rhs; } - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { - typedef boost::tuple result_t; - if (sz < 2) return 0; // we only need two elements - - { - result_t result = boost::minmax(data[0], data[1]); - uint8_t const& first = result.get<0>(); - uint8_t const& second = result.get<1>(); - -// first must be <= second - if (second < first) return 1; - -// The references returned must be data[0] and data[1] - if (&first != data && &first != data + 1) return 2; - if (&second != data && &second != data + 1) return 2; - } - - { - result_t result = boost::minmax(data[0], data[1], greater); - uint8_t const& first = result.get<0>(); - uint8_t const& second = result.get<1>(); - -// first must be <= second - if (greater(second, first)) return 1; - -// The references returned must be data[0] and data[1] - if (&first != data && &first != data + 1) return 2; - if (&second != data && &second != data + 1) return 2; - } - - return 0; -} \ No newline at end of file diff --git a/minmax/fuzzing/minmax_element.fuzz.cpp b/minmax/fuzzing/minmax_element.fuzz.cpp index d2cb073..25c5570 100644 --- a/minmax/fuzzing/minmax_element.fuzz.cpp +++ b/minmax/fuzzing/minmax_element.fuzz.cpp @@ -4,8 +4,10 @@ // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include // for std::distance +#include // for assert #include +#include // Fuzzing tests for: // @@ -29,42 +31,50 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { // Find the min and max result_t result = boost::minmax_element(data, data + sz); -// The iterators have to be in the sequence - if (std::distance(data, result.first) >= sz) return 1; - if (std::distance(data, result.second) >= sz) return 1; +// The iterators have to be in the sequence - and not at the end! + assert(std::distance(data, result.first) < sz); + assert(std::distance(data, result.second) < sz); // the minimum element can't be bigger than the max element uint8_t min_value = *result.first; uint8_t max_value = *result.second; - if (max_value < min_value) return 2; + assert(min_value <= max_value); // None of the elements in the sequence can be less than the min, nor greater than the max for (size_t i = 0; i < sz; ++i) { - if (data[i] < min_value) return 3; - if (max_value < data[i]) return 3; + assert(min_value <= data[i]); + assert(data[i] <= max_value); } + +// We returned the first min element, and the first max element + assert(boost::algorithm::none_of_equal(data, result.first, min_value)); + assert(boost::algorithm::none_of_equal(data, result.second, max_value)); } { // Find the min and max result_t result = boost::minmax_element(data, data + sz, greater); -// The iterators have to be in the sequence - if (std::distance(data, result.first) >= sz) return 1; - if (std::distance(data, result.second) >= sz) return 1; +// The iterators have to be in the sequence - and not at the end! + assert(std::distance(data, result.first) < sz); + assert(std::distance(data, result.second) < sz); // the minimum element can't be bigger than the max element uint8_t min_value = *result.first; uint8_t max_value = *result.second; - if (greater(max_value, min_value)) return 2; + assert (!greater(max_value, min_value)); // None of the elements in the sequence can be less than the min, nor greater than the max for (size_t i = 0; i < sz; ++i) { - if (greater(data[i], min_value)) return 3; - if (greater(max_value, data[i])) return 3; + assert(!greater(data[i], min_value)); + assert(!greater(max_value, data[i])); } + +// We returned the first min element, and the first max element + assert(boost::algorithm::none_of_equal(data, result.first, min_value)); + assert(boost::algorithm::none_of_equal(data, result.second, max_value)); } return 0; diff --git a/minmax/fuzzing/minmax_element_variants.fuzz.cpp b/minmax/fuzzing/minmax_element_variants.fuzz.cpp new file mode 100644 index 0000000..397a11f --- /dev/null +++ b/minmax/fuzzing/minmax_element_variants.fuzz.cpp @@ -0,0 +1,139 @@ +// (C) Copyright Marshall Clow 2018 +// Use, modification and distribution are subject to 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) + +#include // for std::distance +#include // for assert + +#include +#include + +// Fuzzing tests for: +// +// template +// std::pair +// first_min_first_max_element(ForwardIterator first, ForwardIterator last); +// +// template +// std::pair +// first_min_first_max_element(ForwardIterator first, ForwardIterator last, +// BinaryPredicate comp); +// +// identical signatures for: +// first_min_last_max_element +// last_min_first_max_element +// last_min_last_max_element + +bool greater(uint8_t lhs, uint8_t rhs) { return lhs > rhs; } + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { + typedef std::pair result_t; + const uint8_t * const dend = data + sz; + if (sz == 0) return 0; // we need at least one element + + { +// Find the min and max + result_t resultff = boost::first_min_first_max_element(data, dend); + result_t resultfl = boost::first_min_last_max_element (data, dend); + result_t resultlf = boost::last_min_first_max_element (data, dend); + result_t resultll = boost::last_min_last_max_element (data, dend); + +// The iterators have to be in the sequence - and not at the end! + assert(std::distance(data, resultff.first) < sz); + assert(std::distance(data, resultff.second) < sz); + assert(std::distance(data, resultfl.first) < sz); + assert(std::distance(data, resultfl.second) < sz); + assert(std::distance(data, resultlf.first) < sz); + assert(std::distance(data, resultlf.second) < sz); + assert(std::distance(data, resultll.first) < sz); + assert(std::distance(data, resultll.second) < sz); + +// the minimum element can't be bigger than the max element + +// Did we find the same min value and max value? + uint8_t min_value = *resultff.first; + uint8_t max_value = *resultff.second; + assert(min_value <= max_value); + + assert(*resultff.first == min_value); + assert(*resultfl.first == min_value); + assert(*resultlf.first == min_value); + assert(*resultll.first == min_value); + + assert(*resultff.second == max_value); + assert(*resultfl.second == max_value); + assert(*resultlf.second == max_value); + assert(*resultll.second == max_value); + +// None of the elements in the sequence can be less than the min, nor greater than the max + for (size_t i = 0; i < sz; ++i) { + assert(min_value <= data[i]); + assert(data[i] <= max_value); + } + +// Make sure we returned the "right" first and last element + assert(boost::algorithm::none_of_equal(data, resultff.first, min_value)); + assert(boost::algorithm::none_of_equal(data, resultfl.first, min_value)); + assert(boost::algorithm::none_of_equal(resultlf.first + 1, dend, min_value)); + assert(boost::algorithm::none_of_equal(resultll.first + 1, dend, min_value)); + + assert(boost::algorithm::none_of_equal(data, resultff.second, max_value)); + assert(boost::algorithm::none_of_equal(resultfl.second + 1, dend, max_value)); + assert(boost::algorithm::none_of_equal(data, resultlf.second, max_value)); + assert(boost::algorithm::none_of_equal(resultll.second + 1, dend, max_value)); + } + + { +// Find the min and max + result_t resultff = boost::first_min_first_max_element(data, dend, greater); + result_t resultfl = boost::first_min_last_max_element (data, dend, greater); + result_t resultlf = boost::last_min_first_max_element (data, dend, greater); + result_t resultll = boost::last_min_last_max_element (data, dend, greater); + +// The iterators have to be in the sequence - and not at the end! + assert(std::distance(data, resultff.first) < sz); + assert(std::distance(data, resultff.second) < sz); + assert(std::distance(data, resultfl.first) < sz); + assert(std::distance(data, resultfl.second) < sz); + assert(std::distance(data, resultlf.first) < sz); + assert(std::distance(data, resultlf.second) < sz); + assert(std::distance(data, resultll.first) < sz); + assert(std::distance(data, resultll.second) < sz); + +// the minimum element can't be bigger than the max element + uint8_t min_value = *resultff.first; + uint8_t max_value = *resultff.second; + + assert (!greater(max_value, min_value)); + + assert(*resultff.first == min_value); + assert(*resultfl.first == min_value); + assert(*resultlf.first == min_value); + assert(*resultll.first == min_value); + + assert(*resultff.second == max_value); + assert(*resultfl.second == max_value); + assert(*resultlf.second == max_value); + assert(*resultll.second == max_value); + +// None of the elements in the sequence can be less than the min, nor greater than the max + for (size_t i = 0; i < sz; ++i) { + assert(!greater(data[i], min_value)); + assert(!greater(max_value, data[i])); + } + +// We returned the first min element, and the first max element + assert(boost::algorithm::none_of_equal(data, resultff.first, min_value)); + assert(boost::algorithm::none_of_equal(data, resultfl.first, min_value)); + assert(boost::algorithm::none_of_equal(resultlf.first + 1, dend, min_value)); + assert(boost::algorithm::none_of_equal(resultll.first + 1, dend, min_value)); + + assert(boost::algorithm::none_of_equal(data, resultff.second, max_value)); + assert(boost::algorithm::none_of_equal(resultfl.second + 1, dend, max_value)); + assert(boost::algorithm::none_of_equal(data, resultlf.second, max_value)); + assert(boost::algorithm::none_of_equal(resultll.second + 1, dend, max_value)); + } + + return 0; +} \ No newline at end of file From d7d91d431a53efdc5d6c555cb1e76a79ae16e0af Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Tue, 8 May 2018 16:33:25 -0500 Subject: [PATCH 03/15] 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 04/15] 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 05/15] 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 06/15] 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 07/15] 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 08/15] 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 09/15] 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 ea7d35d949b02e72ef7f90acc56d1df7858c86b9 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Sun, 13 May 2018 17:24:36 -0700 Subject: [PATCH 10/15] Added some comments --- minmax/fuzzing/minmax_element_variants.fuzz.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/minmax/fuzzing/minmax_element_variants.fuzz.cpp b/minmax/fuzzing/minmax_element_variants.fuzz.cpp index 397a11f..8b06ccf 100644 --- a/minmax/fuzzing/minmax_element_variants.fuzz.cpp +++ b/minmax/fuzzing/minmax_element_variants.fuzz.cpp @@ -56,6 +56,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { uint8_t max_value = *resultff.second; assert(min_value <= max_value); +// Each variant should have found the same min/max values assert(*resultff.first == min_value); assert(*resultfl.first == min_value); assert(*resultlf.first == min_value); @@ -107,6 +108,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { assert (!greater(max_value, min_value)); +// Each variant should have found the same min/max values assert(*resultff.first == min_value); assert(*resultfl.first == min_value); assert(*resultlf.first == min_value); From 6b2246468e7ac1cca396cbf3e1f2dbb4529e0527 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Sat, 12 May 2018 16:47:47 -0500 Subject: [PATCH 11/15] 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 12/15] 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); From d1b0024aade6c52dcc22dfbd7291df018e221e80 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Sat, 19 May 2018 11:42:56 -0500 Subject: [PATCH 13/15] Add Travis and Appveyor CI config files. --- .travis.yml | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 93 ++++++++++++++++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 .travis.yml create mode 100644 appveyor.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..11961b1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,171 @@ +# Copyright 2016, 2017, 2018 Peter Dimov +# 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://boost.org/LICENSE_1_0.txt) + +language: cpp + +sudo: false + +branches: + only: + - master + - develop + - /feature\/.*/ + +env: + matrix: + - BOGUS_JOB=true + +matrix: + + exclude: + - env: BOGUS_JOB=true + + include: + - os: linux + env: TOOLSET=gcc COMPILER=g++ CXXSTD=11 + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.7 CXXSTD=11 + addons: + apt: + packages: + - g++-4.7 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD=11 + addons: + apt: + packages: + - g++-4.8 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD=11 + addons: + apt: + packages: + - g++-4.9 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=11,14,1z + addons: + apt: + packages: + - g++-5 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=11,14,1z + addons: + apt: + packages: + - g++-6 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=11,14,1z CXXSTD_DIALECT=cxxstd-dialect=gnu + addons: + apt: + packages: + - g++-6 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=11,14,17 + addons: + apt: + packages: + - g++-7 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=clang COMPILER=clang++ CXXSTD=11 + + - os: linux + compiler: clang++-libc++ + env: TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=11,14,1z + addons: + apt: + packages: + - libc++-dev + + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z + osx_image: xcode9.1 + + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z + osx_image: xcode9 + + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z + osx_image: xcode8.3 + + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z + osx_image: xcode8 + + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z + osx_image: xcode7.3 + + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z + osx_image: xcode6.4 + +install: + - BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true + - cd .. + - git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + - cd boost-root + - git submodule update --init tools/build + - git submodule update --init libs/config + - git submodule update --init libs/predef + - git submodule update --init libs/core + - git submodule update --init libs/detail + - git submodule update --init libs/range + - git submodule update --init libs/assert + - git submodule update --init libs/array + - git submodule update --init libs/type_traits + - git submodule update --init libs/static_assert + - git submodule update --init libs/iterator + - git submodule update --init libs/preprocessor + - git submodule update --init libs/mpl + - git submodule update --init libs/smart_ptr + - git submodule update --init libs/callable_traits + - git submodule update --init libs/type_index + - git submodule update --init libs/exception + - git submodule update --init libs/throw_exception + - git submodule update --init libs/utility + - git submodule update --init libs/bind + - git submodule update --init libs/ratio + - git submodule update --init libs/function + - git submodule update --init libs/integer + - git submodule update --init libs/numeric + - git submodule update --init libs/move + - git submodule update --init libs/container_hash + - git submodule update --init libs/io + - git submodule update --init libs/concept_check + - git submodule update --init libs/test + - git submodule update --init libs/timer + - git submodule update --init libs/chrono + - git submodule update --init libs/system + - cp -r $TRAVIS_BUILD_DIR/* libs/algorithm + - ./bootstrap.sh + - ./b2 headers + +script: + - |- + echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam + - ./b2 -j3 libs/algorithm/test toolset=$TOOLSET cxxstd=$CXXSTD $CXXSTD_DIALECT diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..6cdae88 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,93 @@ +# Copyright 2016 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +version: 1.0.{build}-{branch} + +shallow_clone: true + +branches: + only: + - master + - develop + +platform: + - x64 + +environment: + matrix: + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + ARGS: --toolset=msvc-14.1 address-model=64 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + ARGS: --toolset=msvc-14.1 address-model=32 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + ARGS: --toolset=msvc-14.1 address-model=64 cxxflags=-std:c++latest cxxflags=-permissive- + - ARGS: --toolset=msvc-9.0 address-model=32 + - ARGS: --toolset=msvc-10.0 address-model=32 + - ARGS: --toolset=msvc-11.0 address-model=32 + - ARGS: --toolset=msvc-12.0 address-model=32 + - ARGS: --toolset=msvc-14.0 address-model=32 + - ARGS: --toolset=msvc-12.0 address-model=64 + - ARGS: --toolset=msvc-14.0 address-model=64 + - ARGS: --toolset=msvc-14.0 address-model=64 cxxflags=-std:c++latest + - ARGS: --toolset=gcc address-model=64 + CXXSTD: 03,11,14,1z + PATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;%PATH% + - ARGS: --toolset=gcc address-model=64 + CXXSTD: 03,11,14,1z + PATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin;%PATH% + - ARGS: --toolset=gcc address-model=32 linkflags=-Wl,-allow-multiple-definition + CXXSTD: 03,11,14,1z + PATH: C:\MinGW\bin;%PATH% + - ARGS: --toolset=gcc address-model=64 + CXXSTD: 03,11,14,1z + PATH: C:\cygwin64\bin;%PATH% + - ARGS: --toolset=gcc address-model=32 + CXXSTD: 03,11,14,1z + PATH: C:\cygwin\bin;%PATH% + +install: + - cd .. + - git clone -b %APPVEYOR_REPO_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root + - cd boost-root + - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\algorithm + - git submodule update --init tools/build + - git submodule update --init libs/config + - git submodule update --init libs/predef + - git submodule update --init libs/core + - git submodule update --init libs/detail + - git submodule update --init libs/range + - git submodule update --init libs/assert + - git submodule update --init libs/array + - git submodule update --init libs/type_traits + - git submodule update --init libs/static_assert + - git submodule update --init libs/iterator + - git submodule update --init libs/preprocessor + - git submodule update --init libs/mpl + - git submodule update --init libs/smart_ptr + - git submodule update --init libs/callable_traits + - git submodule update --init libs/type_index + - git submodule update --init libs/exception + - git submodule update --init libs/throw_exception + - git submodule update --init libs/utility + - git submodule update --init libs/bind + - git submodule update --init libs/ratio + - git submodule update --init libs/function + - git submodule update --init libs/integer + - git submodule update --init libs/numeric + - git submodule update --init libs/move + - git submodule update --init libs/container_hash + - git submodule update --init libs/io + - git submodule update --init libs/concept_check + - git submodule update --init libs/test + - git submodule update --init libs/timer + - git submodule update --init libs/chrono + - git submodule update --init libs/system + - bootstrap + - b2 headers + +build: off + +test_script: + - cd libs\config\test + - ..\..\..\b2 -j3 %ARGS% cxxstd=%CXXSTD% From 6bb5fa5ee0c9680cc30163a5f8cd9f70054dd7a8 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 4 Jul 2018 11:24:01 -0700 Subject: [PATCH 14/15] Remove 'wrappers' --- include/boost/algorithm/wrappers.hpp | 52 ------------------- test/wrapper_test1.cpp | 76 ---------------------------- 2 files changed, 128 deletions(-) delete mode 100644 include/boost/algorithm/wrappers.hpp delete mode 100644 test/wrapper_test1.cpp diff --git a/include/boost/algorithm/wrappers.hpp b/include/boost/algorithm/wrappers.hpp deleted file mode 100644 index 98f8249..0000000 --- a/include/boost/algorithm/wrappers.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright (c) Marshall Clow 2012. - - 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) - - Alternate interfaces (aka "wrappers") for algorithms. -*/ - -#ifndef BOOST_ALGORITHM_WRAPPERS_HPP -#define BOOST_ALGORITHM_WRAPPERS_HPP - -namespace boost { namespace algorithm { - -/// \fn find_ptr ( Container &c, Key k ) -/// \return a pointer to the value matching the key in the container, -/// or NULL if the key does not exist in the container. -/// -/// \note: This is a wrapper around Container::find, with a useful interface. -/// Suggested by Olaf van der Spek -/// -/// \param c The container to be searched -/// \param k The key value to search with -template -typename Container::value_type::second_type* -find_ptr ( Container &c, Key k ) -{ - typename Container::iterator iter = c.find ( k ); - return iter == c.end() ? NULL : &iter->second; -} - -/// \fn find_ptr ( const Container &c, Key k ) -/// \return a pointer to the value matching the key in the container, -/// or NULL if the key does not exist in the container. -/// -/// \note: This is a wrapper around Container::find, with a useful interface. -/// Suggested by Olaf van der Spek -/// -/// \param c The container to be searched -/// \param k The key value to search with -template -const typename Container::value_type::second_type* -find_ptr ( const Container &c, Key k ) -{ - typename Container::const_iterator iter = c.find ( k ); - return iter == c.end() ? NULL : &iter->second; -} - - -}} - -#endif diff --git a/test/wrapper_test1.cpp b/test/wrapper_test1.cpp deleted file mode 100644 index 913d592..0000000 --- a/test/wrapper_test1.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - Copyright (c) Marshall Clow 2012. - - 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 -#include - -namespace ba = boost::algorithm; - -void test_int () -{ - std::map m; - std::multimap mm; - - int *ptr; - -// try with an empty map - BOOST_CHECK ( ba::find_ptr ( m , 3 ) == NULL ); - BOOST_CHECK ( ba::find_ptr ( mm, 3 ) == NULL ); - - m.insert ( std::make_pair ( 5, 5 )); - mm.insert ( std::make_pair ( 9, 9 )); - BOOST_CHECK ( ba::find_ptr ( m , 3 ) == NULL ); - BOOST_CHECK ( ba::find_ptr ( mm, 3 ) == NULL ); - - ptr = ba::find_ptr ( m, 5 ); - BOOST_CHECK ( ptr != NULL && *ptr == 5 ); - BOOST_CHECK ( ba::find_ptr ( m , 9 ) == NULL ); - - ptr = ba::find_ptr ( mm, 9 ); - BOOST_CHECK ( ptr != NULL && *ptr == 9 ); - BOOST_CHECK ( ba::find_ptr ( mm, 5 ) == NULL ); - -} - -void test_str () -{ - std::map m; - std::multimap mm; - std::string *ptr; - -// try with an empty map - BOOST_CHECK ( ba::find_ptr ( m , 31 ) == NULL ); - BOOST_CHECK ( ba::find_ptr ( mm, 31 ) == NULL ); - - m.insert ( std::make_pair ( 55, "fifty-five" )); - mm.insert ( std::make_pair ( 66, "sixty-six" )); - BOOST_CHECK ( ba::find_ptr ( m , 3 ) == NULL ); - BOOST_CHECK ( ba::find_ptr ( mm, 3 ) == NULL ); - - ptr = ba::find_ptr ( m, 55 ); - BOOST_CHECK ( ptr != NULL && *ptr == "fifty-five" ); - BOOST_CHECK ( ba::find_ptr ( m , 66 ) == NULL ); - - ptr = ba::find_ptr ( mm, 66 ); - BOOST_CHECK ( ptr != NULL && *ptr == "sixty-six" ); - BOOST_CHECK ( ba::find_ptr ( mm, 55 ) == NULL ); -} - -BOOST_AUTO_TEST_CASE( test_main ) -{ - test_int (); - test_str (); -} From 3659b18846679c9d64a26be37f67a58b3d766251 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 4 Jul 2018 11:26:52 -0700 Subject: [PATCH 15/15] Add newlines at the end of the fuzzing files --- minmax/fuzzing/minmax_element.fuzz.cpp | 2 +- minmax/fuzzing/minmax_element_variants.fuzz.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/minmax/fuzzing/minmax_element.fuzz.cpp b/minmax/fuzzing/minmax_element.fuzz.cpp index 25c5570..63b6a9b 100644 --- a/minmax/fuzzing/minmax_element.fuzz.cpp +++ b/minmax/fuzzing/minmax_element.fuzz.cpp @@ -78,4 +78,4 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { } return 0; -} \ No newline at end of file +} diff --git a/minmax/fuzzing/minmax_element_variants.fuzz.cpp b/minmax/fuzzing/minmax_element_variants.fuzz.cpp index 8b06ccf..ba517e2 100644 --- a/minmax/fuzzing/minmax_element_variants.fuzz.cpp +++ b/minmax/fuzzing/minmax_element_variants.fuzz.cpp @@ -138,4 +138,4 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { } return 0; -} \ No newline at end of file +}