diff --git a/libcxx/include/__algorithm/find.h b/libcxx/include/__algorithm/find.h --- a/libcxx/include/__algorithm/find.h +++ b/libcxx/include/__algorithm/find.h @@ -10,7 +10,9 @@ #ifndef _LIBCPP___ALGORITHM_FIND_H #define _LIBCPP___ALGORITHM_FIND_H +#include <__algorithm/find_if.h> #include <__config> +#include <__utility/forward.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -18,13 +20,20 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +struct __is_equal_to { + _Tp const& __value_; + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR + bool operator()(_Up&& __other) const { + return __value_ == _VSTD::forward<_Up>(__other); + } +}; + template -_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _InputIterator -find(_InputIterator __first, _InputIterator __last, const _Tp& __value_) { - for (; __first != __last; ++__first) - if (*__first == __value_) - break; - return __first; +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 +_InputIterator find(_InputIterator __first, _InputIterator __last, const _Tp& __value) { + return _VSTD::find_if(__first, __last, __is_equal_to<_Tp>{__value}); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/find_if.h b/libcxx/include/__algorithm/find_if.h --- a/libcxx/include/__algorithm/find_if.h +++ b/libcxx/include/__algorithm/find_if.h @@ -19,14 +19,74 @@ _LIBCPP_BEGIN_NAMESPACE_STD template -_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _InputIterator -find_if(_InputIterator __first, _InputIterator __last, _Predicate __pred) { +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 +_InputIterator __find_if_impl(_InputIterator __first, _InputIterator __last, _Predicate __pred, + input_iterator_tag) +{ for (; __first != __last; ++__first) if (__pred(*__first)) break; return __first; } +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 +_RandomAccessIter __find_if_impl(_RandomAccessIter __first, _RandomAccessIter __last, _Predicate __pred, + random_access_iterator_tag) +{ + using _Difference = typename iterator_traits<_RandomAccessIter>::difference_type; + _Difference __n = __last - __first; + for (_Difference __chunks = __n / 4; __chunks != 0; --__chunks) { + if (__pred(*__first)) + break; + ++__first; + + if (__pred(*__first)) + break; + ++__first; + + if (__pred(*__first)) + break; + ++__first; + + if (__pred(*__first)) + break; + ++__first; + } + + switch (__last - __first) { + case 3: + if (__pred(*__first)) + break; + ++__first; + _LIBCPP_FALLTHROUGH(); + + case 2: + if (__pred(*__first)) + break; + ++__first; + _LIBCPP_FALLTHROUGH(); + + case 1: + if (__pred(*__first)) + break; + ++__first; + _LIBCPP_FALLTHROUGH(); + + default: + break; + } + + return __first; +} + +template +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 +_InputIterator find_if(_InputIterator __first, _InputIterator __last, _Predicate __pred) { + using _Tag = typename iterator_traits<_InputIterator>::iterator_category; + return _VSTD::__find_if_impl(__first, __last, __pred, _Tag()); +} + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___ALGORITHM_FIND_IF_H diff --git a/libcxx/include/__algorithm/find_if_not.h b/libcxx/include/__algorithm/find_if_not.h --- a/libcxx/include/__algorithm/find_if_not.h +++ b/libcxx/include/__algorithm/find_if_not.h @@ -10,6 +10,7 @@ #ifndef _LIBCPP___ALGORITHM_FIND_IF_NOT_H #define _LIBCPP___ALGORITHM_FIND_IF_NOT_H +#include <__algorithm/find_if.h> #include <__config> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -18,13 +19,20 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +struct __negate_pred { + _Pred& __pred_; + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR + bool operator()(_Tp&& __value) const { + return !__pred_(_VSTD::forward<_Tp>(__value)); + } +}; + template -_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _InputIterator -find_if_not(_InputIterator __first, _InputIterator __last, _Predicate __pred) { - for (; __first != __last; ++__first) - if (!__pred(*__first)) - break; - return __first; +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 +_InputIterator find_if_not(_InputIterator __first, _InputIterator __last, _Predicate __pred) { + return _VSTD::find_if(__first, __last, __negate_pred<_Predicate>{__pred}); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -19,28 +19,43 @@ #include "test_macros.h" #include "test_iterators.h" -#if TEST_STD_VER > 17 -TEST_CONSTEXPR bool test_constexpr() { - int ia[] = {1, 3, 5, 2, 4, 6}; - int ib[] = {1, 2, 3, 4, 5, 6}; - return (std::find(std::begin(ia), std::end(ia), 5) == ia+2) - && (std::find(std::begin(ib), std::end(ib), 9) == ib+6) - ; +template +TEST_CONSTEXPR_CXX17 void test_iter() { + int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + // We don't find what we're looking for in the range + { + { + Iter result = std::find(Iter(range), Iter(range), 0); + assert(result == Iter(range)); } -#endif + { + Iter result = std::find(Iter(range), Iter(std::end(range)), 999); + assert(result == Iter(std::end(range))); + } + } -int main(int, char**) -{ - int ia[] = {0, 1, 2, 3, 4, 5}; - const unsigned s = sizeof(ia)/sizeof(ia[0]); - cpp17_input_iterator r = std::find(cpp17_input_iterator(ia), - cpp17_input_iterator(ia+s), 3); - assert(*r == 3); - r = std::find(cpp17_input_iterator(ia), cpp17_input_iterator(ia+s), 10); - assert(r == cpp17_input_iterator(ia+s)); + // Tests with sub-ranges of various sizes + for (int size = 1; size != 10; ++size) { + for (int toFind = 0; toFind != size-1; ++toFind) { + Iter result = std::find(Iter(range), Iter(range + size), toFind); + assert(result == Iter(range + toFind)); + } + } +} + +TEST_CONSTEXPR_CXX17 bool test() { + test_iter>(); + test_iter>(); + test_iter>(); + test_iter>(); + return true; +} +int main(int, char**) { + test(); #if TEST_STD_VER > 17 - static_assert(test_constexpr()); + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find_if.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find_if.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find_if.pass.cpp @@ -20,38 +20,49 @@ #include "test_macros.h" #include "test_iterators.h" -struct eq { - TEST_CONSTEXPR eq (int val) : v(val) {} - TEST_CONSTEXPR bool operator () (int v2) const { return v == v2; } - int v; - }; +struct EqualTo { + int v; + TEST_CONSTEXPR EqualTo(int val) : v(val) {} + TEST_CONSTEXPR bool operator()(int v2) const { return v == v2; } +}; -#if TEST_STD_VER > 17 -TEST_CONSTEXPR bool test_constexpr() { - int ia[] = {1, 3, 5, 2, 4, 6}; - int ib[] = {1, 2, 3, 7, 5, 6}; - eq c(4); - return (std::find_if(std::begin(ia), std::end(ia), c) == ia+4) - && (std::find_if(std::begin(ib), std::end(ib), c) == ib+6) - ; +template +TEST_CONSTEXPR_CXX17 void test_iter() { + int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + // We don't find what we're looking for in the range + { + { + Iter result = std::find_if(Iter(range), Iter(range), EqualTo(0)); + assert(result == Iter(range)); } -#endif + { + Iter result = std::find_if(Iter(range), Iter(std::end(range)), EqualTo(999)); + assert(result == Iter(std::end(range))); + } + } -int main(int, char**) -{ - int ia[] = {0, 1, 2, 3, 4, 5}; - const unsigned s = sizeof(ia)/sizeof(ia[0]); - cpp17_input_iterator r = std::find_if(cpp17_input_iterator(ia), - cpp17_input_iterator(ia+s), - eq(3)); - assert(*r == 3); - r = std::find_if(cpp17_input_iterator(ia), - cpp17_input_iterator(ia+s), - eq(10)); - assert(r == cpp17_input_iterator(ia+s)); + // Tests with sub-ranges of various sizes + for (int size = 1; size != 10; ++size) { + for (int toFind = 0; toFind != size-1; ++toFind) { + Iter result = std::find_if(Iter(range), Iter(range + size), EqualTo(toFind)); + assert(result == Iter(range + toFind)); + } + } +} + +TEST_CONSTEXPR_CXX17 bool test() { + test_iter>(); + test_iter>(); + test_iter>(); + test_iter>(); + return true; +} +int main(int, char**) { + test(); #if TEST_STD_VER > 17 - static_assert(test_constexpr()); + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find_if_not.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find_if_not.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find_if_not.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find_if_not.pass.cpp @@ -20,38 +20,49 @@ #include "test_macros.h" #include "test_iterators.h" -struct ne { - TEST_CONSTEXPR ne (int val) : v(val) {} - TEST_CONSTEXPR bool operator () (int v2) const { return v != v2; } - int v; - }; +struct DifferentFrom { + int v; + TEST_CONSTEXPR DifferentFrom(int val) : v(val) {} + TEST_CONSTEXPR bool operator()(int v2) const { return v != v2; } +}; -#if TEST_STD_VER > 17 -TEST_CONSTEXPR bool test_constexpr() { - int ia[] = {1, 3, 5, 2, 4, 6}; - int ib[] = {1, 2, 3, 7, 5, 6}; - ne c(4); - return (std::find_if_not(std::begin(ia), std::end(ia), c) == ia+4) - && (std::find_if_not(std::begin(ib), std::end(ib), c) == ib+6) - ; +template +TEST_CONSTEXPR_CXX17 void test_iter() { + int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + // We don't find what we're looking for in the range + { + { + Iter result = std::find_if_not(Iter(range), Iter(range), DifferentFrom(0)); + assert(result == Iter(range)); } -#endif + { + Iter result = std::find_if_not(Iter(range), Iter(std::end(range)), DifferentFrom(999)); + assert(result == Iter(std::end(range))); + } + } -int main(int, char**) -{ - int ia[] = {0, 1, 2, 3, 4, 5}; - const unsigned s = sizeof(ia)/sizeof(ia[0]); - cpp17_input_iterator r = std::find_if_not(cpp17_input_iterator(ia), - cpp17_input_iterator(ia+s), - ne(3)); - assert(*r == 3); - r = std::find_if_not(cpp17_input_iterator(ia), - cpp17_input_iterator(ia+s), - ne(10)); - assert(r == cpp17_input_iterator(ia+s)); + // Tests with sub-ranges of various sizes + for (int size = 1; size != 10; ++size) { + for (int toFind = 0; toFind != size-1; ++toFind) { + Iter result = std::find_if_not(Iter(range), Iter(range + size), DifferentFrom(toFind)); + assert(result == Iter(range + toFind)); + } + } +} + +TEST_CONSTEXPR_CXX17 bool test() { + test_iter>(); + test_iter>(); + test_iter>(); + test_iter>(); + return true; +} +int main(int, char**) { + test(); #if TEST_STD_VER > 17 - static_assert(test_constexpr()); + static_assert(test()); #endif return 0;