Skip to content

[libc++] Bring std::{any,all,none}_of tests up to current standards#209266

Open
ldionne wants to merge 1 commit into
llvm:mainfrom
ldionne:review/any-of-tests
Open

[libc++] Bring std::{any,all,none}_of tests up to current standards#209266
ldionne wants to merge 1 commit into
llvm:mainfrom
ldionne:review/any-of-tests

Conversation

@ldionne

@ldionne ldionne commented Jul 13, 2026

Copy link
Copy Markdown
Member

The tests for these algorithms were minimal, didn't test all iterator categories, and the constexpr coverage didn't follow our current practice. This patch brings all three tests (which are very similar) up to our current standards.

Assisted by Claude

The tests for these algorithms were minimal, didn't test all iterator
categories, and the constexpr coverage didn't follow our current
practice. This patch brings all three tests (which are very similar)
up to our current standards.

Assisted by Claude
@ldionne ldionne requested a review from a team as a code owner July 13, 2026 18:25
@llvmorg-github-actions llvmorg-github-actions Bot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jul 13, 2026
@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-libcxx

Author: Louis Dionne (ldionne)

Changes

The tests for these algorithms were minimal, didn't test all iterator categories, and the constexpr coverage didn't follow our current practice. This patch brings all three tests (which are very similar) up to our current standards.

Assisted by Claude


Full diff: https://github.com/llvm/llvm-project/pull/209266.diff

3 Files Affected:

  • (modified) libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/all_of.pass.cpp (+70-35)
  • (modified) libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/any_of.pass.cpp (+69-42)
  • (modified) libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/none_of.pass.cpp (+69-42)
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/all_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/all_of.pass.cpp
index f9377fb10277f..acbdeda0f82e6 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/all_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/all_of.pass.cpp
@@ -9,55 +9,90 @@
 // <algorithm>
 
 // template <class InputIterator, class Predicate>
-//     constexpr bool       // constexpr after C++17
-//   all_of(InputIterator first, InputIterator last, Predicate pred);
+// constexpr bool all_of(InputIterator first, InputIterator last, Predicate pred); // constexpr since C++20
 
 #include <algorithm>
 #include <cassert>
-#include <iterator>
 
 #include "test_macros.h"
 #include "test_iterators.h"
+#include "type_algorithms.h"
 
-struct test1
-{
-    TEST_CONSTEXPR bool operator()(const int& i) const
-    {
-        return i % 2 == 0;
-    }
+struct is_odd {
+  TEST_CONSTEXPR bool operator()(const int& i) const { return i % 2 != 0; }
+};
+
+struct counting_predicate {
+  int* times_applied;
+  bool result;
+  TEST_CONSTEXPR counting_predicate(int* counter, bool r) : times_applied(counter), result(r) {}
+  TEST_CONSTEXPR_CXX14 bool operator()(int) const {
+    ++*times_applied;
+    return result;
+  }
 };
 
-#if TEST_STD_VER > 17
-TEST_CONSTEXPR bool test_constexpr() {
-    int ia[] = {2, 4, 6, 8};
-    int ib[] = {2, 4, 5, 8};
-    return  std::all_of(std::begin(ia), std::end(ia), test1())
-        && !std::all_of(std::begin(ib), std::end(ib), test1())
-        ;
+struct Test {
+  template <class Iter>
+  TEST_CONSTEXPR_CXX20 void operator()() {
+    { // an empty range vacuously satisfies the predicate
+      int a[] = {2, 4, 6, 8};
+      // The return type is always `bool`, regardless of the iterator category.
+      ASSERT_SAME_TYPE(bool, decltype(std::all_of(Iter(a), Iter(a), is_odd())));
+      assert(std::all_of(Iter(a), Iter(a), is_odd()));
+    }
+
+    { // every element satisfies the predicate
+      int a[] = {1, 3, 5, 7};
+      assert(std::all_of(Iter(a), Iter(a + 4), is_odd()));
+    }
+
+    { // no element satisfies the predicate
+      int a[] = {2, 4, 6, 8};
+      assert(!std::all_of(Iter(a), Iter(a + 4), is_odd()));
+    }
+
+    { // the only non-satisfying element is the first one
+      int a[] = {2, 1, 3, 5};
+      assert(!std::all_of(Iter(a), Iter(a + 4), is_odd()));
     }
-#endif
 
-int main(int, char**)
-{
-    {
-        int ia[] = {2, 4, 6, 8};
-        const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-        assert(std::all_of(cpp17_input_iterator<const int*>(ia),
-                           cpp17_input_iterator<const int*>(ia + sa), test1()) == true);
-        assert(std::all_of(cpp17_input_iterator<const int*>(ia),
-                           cpp17_input_iterator<const int*>(ia), test1()) == true);
+    { // the only non-satisfying element is in the middle
+      int a[] = {1, 3, 4, 5};
+      assert(!std::all_of(Iter(a), Iter(a + 4), is_odd()));
     }
-    {
-        const int ia[] = {2, 4, 5, 8};
-        const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-        assert(std::all_of(cpp17_input_iterator<const int*>(ia),
-                           cpp17_input_iterator<const int*>(ia + sa), test1()) == false);
-        assert(std::all_of(cpp17_input_iterator<const int*>(ia),
-                           cpp17_input_iterator<const int*>(ia), test1()) == true);
+
+    { // the only non-satisfying element is the last one
+      int a[] = {1, 3, 5, 8};
+      assert(!std::all_of(Iter(a), Iter(a + 4), is_odd()));
     }
 
-#if TEST_STD_VER > 17
-    static_assert(test_constexpr());
+    { // a single-element range, satisfying and not satisfying the predicate
+      int satisfies     = 1;
+      int not_satisfies = 2;
+      assert(std::all_of(Iter(&satisfies), Iter(&satisfies + 1), is_odd()));
+      assert(!std::all_of(Iter(&not_satisfies), Iter(&not_satisfies + 1), is_odd()));
+    }
+  }
+};
+
+TEST_CONSTEXPR_CXX20 bool test() {
+  types::for_each(types::cpp17_input_iterator_list<int*>(), Test());
+
+  { // the predicate is applied at most `last - first` times (complexity requirement)
+    int a[]     = {1, 2, 3, 4, 5};
+    int applied = 0;
+    assert(std::all_of(a, a + 5, counting_predicate(&applied, true)));
+    assert(applied == 5);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 20
+  static_assert(test());
 #endif
 
   return 0;
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/any_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/any_of.pass.cpp
index c0b659304db8b..6eb815d4bf652 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/any_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/any_of.pass.cpp
@@ -9,63 +9,90 @@
 // <algorithm>
 
 // template <class InputIterator, class Predicate>
-//     constexpr bool       // constexpr after C++17
-//   any_of(InputIterator first, InputIterator last, Predicate pred);
+// constexpr bool any_of(InputIterator first, InputIterator last, Predicate pred); // constexpr since C++20
 
 #include <algorithm>
 #include <cassert>
-#include <iterator>
 
 #include "test_macros.h"
 #include "test_iterators.h"
+#include "type_algorithms.h"
 
-struct test1
-{
-    TEST_CONSTEXPR bool operator()(const int& i) const
-    {
-        return i % 2 == 0;
-    }
+struct is_odd {
+  TEST_CONSTEXPR bool operator()(const int& i) const { return i % 2 != 0; }
+};
+
+struct counting_predicate {
+  int* times_applied;
+  bool result;
+  TEST_CONSTEXPR counting_predicate(int* counter, bool r) : times_applied(counter), result(r) {}
+  TEST_CONSTEXPR_CXX14 bool operator()(int) const {
+    ++*times_applied;
+    return result;
+  }
 };
 
-#if TEST_STD_VER > 17
-TEST_CONSTEXPR bool test_constexpr() {
-    int ia[] = {2, 4, 6, 8};
-    int ib[] = {1, 3, 5, 7};
-    return  std::any_of(std::begin(ia), std::end(ia), test1())
-        && !std::any_of(std::begin(ib), std::end(ib), test1())
-        ;
+struct Test {
+  template <class Iter>
+  TEST_CONSTEXPR_CXX20 void operator()() {
+    { // an empty range never contains a matching element
+      int a[] = {1, 2, 3, 4};
+      // The return type is always `bool`, regardless of the iterator category.
+      ASSERT_SAME_TYPE(bool, decltype(std::any_of(Iter(a), Iter(a), is_odd())));
+      assert(!std::any_of(Iter(a), Iter(a), is_odd()));
     }
-#endif
 
-int main(int, char**)
-{
-    {
-        int ia[] = {2, 4, 6, 8};
-        const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-        assert(std::any_of(cpp17_input_iterator<const int*>(ia),
-                           cpp17_input_iterator<const int*>(ia + sa), test1()) == true);
-        assert(std::any_of(cpp17_input_iterator<const int*>(ia),
-                           cpp17_input_iterator<const int*>(ia), test1()) == false);
+    { // no element matches the predicate
+      int a[] = {2, 4, 6, 8};
+      assert(!std::any_of(Iter(a), Iter(a + 4), is_odd()));
     }
-    {
-        const int ia[] = {2, 4, 5, 8};
-        const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-        assert(std::any_of(cpp17_input_iterator<const int*>(ia),
-                           cpp17_input_iterator<const int*>(ia + sa), test1()) == true);
-        assert(std::any_of(cpp17_input_iterator<const int*>(ia),
-                           cpp17_input_iterator<const int*>(ia), test1()) == false);
+
+    { // every element matches the predicate
+      int a[] = {1, 3, 5, 7};
+      assert(std::any_of(Iter(a), Iter(a + 4), is_odd()));
     }
-    {
-        const int ia[] = {1, 3, 5, 7};
-        const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-        assert(std::any_of(cpp17_input_iterator<const int*>(ia),
-                           cpp17_input_iterator<const int*>(ia + sa), test1()) == false);
-        assert(std::any_of(cpp17_input_iterator<const int*>(ia),
-                           cpp17_input_iterator<const int*>(ia), test1()) == false);
+
+    { // the only matching element is the first one
+      int a[] = {1, 2, 4, 6};
+      assert(std::any_of(Iter(a), Iter(a + 4), is_odd()));
+    }
+
+    { // the only matching element is in the middle
+      int a[] = {2, 4, 5, 8};
+      assert(std::any_of(Iter(a), Iter(a + 4), is_odd()));
     }
 
-#if TEST_STD_VER > 17
-    static_assert(test_constexpr());
+    { // the only matching element is the last one
+      int a[] = {2, 4, 6, 7};
+      assert(std::any_of(Iter(a), Iter(a + 4), is_odd()));
+    }
+
+    { // a single-element range, with and without a match
+      int match    = 1;
+      int no_match = 2;
+      assert(std::any_of(Iter(&match), Iter(&match + 1), is_odd()));
+      assert(!std::any_of(Iter(&no_match), Iter(&no_match + 1), is_odd()));
+    }
+  }
+};
+
+TEST_CONSTEXPR_CXX20 bool test() {
+  types::for_each(types::cpp17_input_iterator_list<int*>(), Test());
+
+  { // the predicate is applied at most `last - first` times (complexity requirement)
+    int a[]     = {1, 2, 3, 4, 5};
+    int applied = 0;
+    assert(!std::any_of(a, a + 5, counting_predicate(&applied, false)));
+    assert(applied == 5);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 20
+  static_assert(test());
 #endif
 
   return 0;
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/none_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/none_of.pass.cpp
index 8d63ecb6c17a5..4a1c5c5bd5c4d 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/none_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/none_of.pass.cpp
@@ -9,63 +9,90 @@
 // <algorithm>
 
 // template <class InputIterator, class Predicate>
-//   bool
-//   none_of(InputIterator first, InputIterator last, Predicate pred);
+// constexpr bool none_of(InputIterator first, InputIterator last, Predicate pred); // constexpr since C++20
 
 #include <algorithm>
 #include <cassert>
-#include <iterator>
 
 #include "test_macros.h"
 #include "test_iterators.h"
+#include "type_algorithms.h"
 
-struct test1
-{
-    TEST_CONSTEXPR bool operator()(const int& i) const
-    {
-        return i % 2 == 0;
-    }
+struct is_odd {
+  TEST_CONSTEXPR bool operator()(const int& i) const { return i % 2 != 0; }
+};
+
+struct counting_predicate {
+  int* times_applied;
+  bool result;
+  TEST_CONSTEXPR counting_predicate(int* counter, bool r) : times_applied(counter), result(r) {}
+  TEST_CONSTEXPR_CXX14 bool operator()(int) const {
+    ++*times_applied;
+    return result;
+  }
 };
 
-#if TEST_STD_VER > 17
-TEST_CONSTEXPR bool test_constexpr() {
-    int ia[] = {1, 3, 6, 7};
-    int ib[] = {1, 3, 5, 7};
-    return !std::none_of(std::begin(ia), std::end(ia), test1())
-        &&  std::none_of(std::begin(ib), std::end(ib), test1())
-        ;
+struct Test {
+  template <class Iter>
+  TEST_CONSTEXPR_CXX20 void operator()() {
+    { // an empty range vacuously satisfies none_of
+      int a[] = {1, 3, 5, 7};
+      // The return type is always `bool`, regardless of the iterator category.
+      ASSERT_SAME_TYPE(bool, decltype(std::none_of(Iter(a), Iter(a), is_odd())));
+      assert(std::none_of(Iter(a), Iter(a), is_odd()));
     }
-#endif
 
-int main(int, char**)
-{
-    {
-        int ia[] = {2, 4, 6, 8};
-        const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-        assert(std::none_of(cpp17_input_iterator<const int*>(ia),
-                            cpp17_input_iterator<const int*>(ia + sa), test1()) == false);
-        assert(std::none_of(cpp17_input_iterator<const int*>(ia),
-                            cpp17_input_iterator<const int*>(ia), test1()) == true);
+    { // no element satisfies the predicate
+      int a[] = {2, 4, 6, 8};
+      assert(std::none_of(Iter(a), Iter(a + 4), is_odd()));
     }
-    {
-        const int ia[] = {2, 4, 5, 8};
-        const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-        assert(std::none_of(cpp17_input_iterator<const int*>(ia),
-                            cpp17_input_iterator<const int*>(ia + sa), test1()) == false);
-        assert(std::none_of(cpp17_input_iterator<const int*>(ia),
-                            cpp17_input_iterator<const int*>(ia), test1()) == true);
+
+    { // every element satisfies the predicate
+      int a[] = {1, 3, 5, 7};
+      assert(!std::none_of(Iter(a), Iter(a + 4), is_odd()));
     }
-    {
-        const int ia[] = {1, 3, 5, 7};
-        const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-        assert(std::none_of(cpp17_input_iterator<const int*>(ia),
-                            cpp17_input_iterator<const int*>(ia + sa), test1()) == true);
-        assert(std::none_of(cpp17_input_iterator<const int*>(ia),
-                            cpp17_input_iterator<const int*>(ia), test1()) == true);
+
+    { // the only satisfying element is the first one
+      int a[] = {1, 2, 4, 6};
+      assert(!std::none_of(Iter(a), Iter(a + 4), is_odd()));
+    }
+
+    { // the only satisfying element is in the middle
+      int a[] = {2, 4, 5, 8};
+      assert(!std::none_of(Iter(a), Iter(a + 4), is_odd()));
     }
 
-#if TEST_STD_VER > 17
-    static_assert(test_constexpr());
+    { // the only satisfying element is the last one
+      int a[] = {2, 4, 6, 7};
+      assert(!std::none_of(Iter(a), Iter(a + 4), is_odd()));
+    }
+
+    { // a single-element range, satisfying and not satisfying the predicate
+      int satisfies     = 1;
+      int not_satisfies = 2;
+      assert(!std::none_of(Iter(&satisfies), Iter(&satisfies + 1), is_odd()));
+      assert(std::none_of(Iter(&not_satisfies), Iter(&not_satisfies + 1), is_odd()));
+    }
+  }
+};
+
+TEST_CONSTEXPR_CXX20 bool test() {
+  types::for_each(types::cpp17_input_iterator_list<int*>(), Test());
+
+  { // the predicate is applied at most `last - first` times (complexity requirement)
+    int a[]     = {1, 2, 3, 4, 5};
+    int applied = 0;
+    assert(std::none_of(a, a + 5, counting_predicate(&applied, false)));
+    assert(applied == 5);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 20
+  static_assert(test());
 #endif
 
   return 0;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant