[libcxx-commits] [libcxx] [libc++] Improve test coverage and readability for swap_ranges (PR #133752)

Peng Liu via libcxx-commits libcxx-commits at lists.llvm.org
Wed Apr 2 19:38:18 PDT 2025


https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/133752

>From 1068ac19977dc78213f9dc35a49d90595fd87893 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Mon, 31 Mar 2025 12:50:39 -0400
Subject: [PATCH] Improve test coverage and inline standalone tests

---
 .../alg.swap/ranges.swap_ranges.pass.cpp      | 224 ++++++++++--------
 .../alg.swap/swap_ranges.pass.cpp             |  31 ++-
 2 files changed, 146 insertions(+), 109 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp
index 93090ed6138f8..85557ecbbfabc 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp
@@ -30,108 +30,40 @@
 #include "test_iterators.h"
 #include "type_algorithms.h"
 
-constexpr void test_different_lengths() {
-  using Expected                = std::ranges::swap_ranges_result<int*, int*>;
-  int i[3]                      = {1, 2, 3};
-  int j[1]                      = {4};
-  std::same_as<Expected> auto r = std::ranges::swap_ranges(i, i + 3, j, j + 1);
-  assert(r.in1 == i + 1);
-  assert(r.in2 == j + 1);
-  assert(std::ranges::equal(i, std::array{4, 2, 3}));
-  assert(std::ranges::equal(j, std::array{1}));
-  std::same_as<Expected> auto r2 = std::ranges::swap_ranges(i, j);
-  assert(r2.in1 == i + 1);
-  assert(r2.in2 == j + 1);
-  assert(std::ranges::equal(i, std::array{1, 2, 3}));
-  assert(std::ranges::equal(j, std::array{4}));
-  std::same_as<Expected> auto r3 = std::ranges::swap_ranges(j, j + 1, i, i + 3);
-  assert(r3.in1 == j + 1);
-  assert(r3.in2 == i + 1);
-  assert(std::ranges::equal(i, std::array{4, 2, 3}));
-  assert(std::ranges::equal(j, std::array{1}));
-  std::same_as<Expected> auto r4 = std::ranges::swap_ranges(j, i);
-  assert(r4.in1 == j + 1);
-  assert(r4.in2 == i + 1);
-  assert(std::ranges::equal(i, std::array{1, 2, 3}));
-  assert(std::ranges::equal(j, std::array{4}));
-}
-
-constexpr void test_range() {
-  std::array r1 = {1, 2, 3};
-  std::array r2 = {4, 5, 6};
-
-  std::same_as<std::ranges::in_in_result<std::array<int, 3>::iterator, std::array<int, 3>::iterator>> auto r =
-      std::ranges::swap_ranges(r1, r2);
-  assert(r.in1 == r1.end());
-  assert(r.in2 == r2.end());
-  assert((r1 == std::array{4, 5, 6}));
-  assert((r2 == std::array{1, 2, 3}));
-}
-
-constexpr void test_borrowed_input_range() {
-  {
-    int r1[] = {1, 2, 3};
-    int r2[] = {4, 5, 6};
-    std::ranges::swap_ranges(std::views::all(r1), r2);
-    assert(std::ranges::equal(r1, std::array{4, 5, 6}));
-    assert(std::ranges::equal(r2, std::array{1, 2, 3}));
-  }
-  {
-    int r1[] = {1, 2, 3};
-    int r2[] = {4, 5, 6};
-    std::ranges::swap_ranges(r1, std::views::all(r2));
-    assert(std::ranges::equal(r1, std::array{4, 5, 6}));
-    assert(std::ranges::equal(r2, std::array{1, 2, 3}));
-  }
-  {
-    int r1[] = {1, 2, 3};
-    int r2[] = {4, 5, 6};
-    std::ranges::swap_ranges(std::views::all(r1), std::views::all(r2));
-    assert(std::ranges::equal(r1, std::array{4, 5, 6}));
-    assert(std::ranges::equal(r2, std::array{1, 2, 3}));
-  }
-}
-
-constexpr void test_sentinel() {
-  int i[3]                      = {1, 2, 3};
-  int j[3]                      = {4, 5, 6};
-  using It                      = cpp17_input_iterator<int*>;
-  using Sent                    = sentinel_wrapper<It>;
-  using Expected                = std::ranges::swap_ranges_result<It, It>;
-  std::same_as<Expected> auto r = std::ranges::swap_ranges(It(i), Sent(It(i + 3)), It(j), Sent(It(j + 3)));
-  assert(base(r.in1) == i + 3);
-  assert(base(r.in2) == j + 3);
-  assert(std::ranges::equal(i, std::array{4, 5, 6}));
-  assert(std::ranges::equal(j, std::array{1, 2, 3}));
-}
-
 template <class Iter1, class Iter2>
 TEST_CONSTEXPR_CXX20 void test_iterators() {
   using Expected = std::ranges::swap_ranges_result<Iter1, Iter2>;
-  int a[3]       = {1, 2, 3};
-  int b[3]       = {4, 5, 6};
-  std::same_as<Expected> auto r =
-      std::ranges::swap_ranges(Iter1(a), sentinel_wrapper(Iter1(a + 3)), Iter2(b), sentinel_wrapper(Iter2(b + 3)));
-  assert(base(r.in1) == a + 3);
-  assert(base(r.in2) == b + 3);
-  assert(std::ranges::equal(a, std::array{4, 5, 6}));
-  assert(std::ranges::equal(b, std::array{1, 2, 3}));
-}
-
-constexpr void test_rval_range() {
-  {
-    using Expected       = std::ranges::swap_ranges_result<std::array<int, 3>::iterator, std::ranges::dangling>;
-    std::array<int, 3> r = {1, 2, 3};
-    std::same_as<Expected> auto a = std::ranges::swap_ranges(r, std::array{4, 5, 6});
-    assert((r == std::array{4, 5, 6}));
-    assert(a.in1 == r.begin() + 3);
+  { // Basic test case: swapping three elements between two arrays
+    int a[3] = {1, 2, 3};
+    int b[3] = {4, 5, 6};
+    std::same_as<Expected> auto r =
+        std::ranges::swap_ranges(Iter1(a), sentinel_wrapper(Iter1(a + 3)), Iter2(b), sentinel_wrapper(Iter2(b + 3)));
+    assert(base(r.in1) == a + 3);
+    assert(base(r.in2) == b + 3);
+    assert(std::ranges::equal(a, std::array{4, 5, 6}));
+    assert(std::ranges::equal(b, std::array{1, 2, 3}));
   }
-  {
-    std::array<int, 3> r = {1, 2, 3};
-    using Expected       = std::ranges::swap_ranges_result<std::ranges::dangling, std::array<int, 3>::iterator>;
-    std::same_as<Expected> auto b = std::ranges::swap_ranges(std::array{4, 5, 6}, r);
-    assert((r == std::array{4, 5, 6}));
-    assert(b.in2 == r.begin() + 3);
+  { // Large-scale test: swapping 100 elements between two different containers
+    const int N = 100;
+    std::array<int, N> a;
+    std::vector<int> b(N + 2, 42);
+    b.front() = 1;
+    b.back()  = -1;
+    for (int i = 0; i < N; ++i)
+      a[i] = i * i + 1;
+    std::same_as<Expected> auto r = std::ranges::swap_ranges(
+        Iter1(a.data()),
+        sentinel_wrapper(Iter1(a.data() + N)),
+        Iter2(b.data() + 1),
+        sentinel_wrapper(Iter2(b.data() + b.size())));
+    assert(base(r.in1) == a.data() + N);
+    assert(base(r.in2) == b.data() + N + 1);
+    assert(b.front() == 1); // Ensure that the unswapped portion remains unchanged
+    assert(b.back() == -1);
+    for (int i = 0; i < N; ++i) {
+      assert(a[i] == 42);
+      assert(b[i + 1] == i * i + 1);
+    }
   }
 }
 
@@ -152,11 +84,97 @@ constexpr void test_vector_bool() {
 }
 
 constexpr bool test() {
-  test_range();
-  test_sentinel();
-  test_different_lengths();
-  test_borrowed_input_range();
-  test_rval_range();
+  { // Validate swapping ranges directly
+    std::array r1 = {1, 2, 3};
+    std::array r2 = {4, 5, 6};
+
+    std::same_as<std::ranges::in_in_result<std::array<int, 3>::iterator, std::array<int, 3>::iterator>> auto r =
+        std::ranges::swap_ranges(r1, r2);
+    assert(r.in1 == r1.end());
+    assert(r.in2 == r2.end());
+    assert((r1 == std::array{4, 5, 6}));
+    assert((r2 == std::array{1, 2, 3}));
+  }
+
+  { // Validate swapping ranges using iterator and sentinels
+    int i[3]                      = {1, 2, 3};
+    int j[3]                      = {4, 5, 6};
+    using It                      = cpp17_input_iterator<int*>;
+    using Sent                    = sentinel_wrapper<It>;
+    using Expected                = std::ranges::swap_ranges_result<It, It>;
+    std::same_as<Expected> auto r = std::ranges::swap_ranges(It(i), Sent(It(i + 3)), It(j), Sent(It(j + 3)));
+    assert(base(r.in1) == i + 3);
+    assert(base(r.in2) == j + 3);
+    assert(std::ranges::equal(i, std::array{4, 5, 6}));
+    assert(std::ranges::equal(j, std::array{1, 2, 3}));
+  }
+
+  { // Validate swapping ranges of different lengths
+    using Expected                = std::ranges::swap_ranges_result<int*, int*>;
+    int i[3]                      = {1, 2, 3};
+    int j[1]                      = {4};
+    std::same_as<Expected> auto r = std::ranges::swap_ranges(i, i + 3, j, j + 1);
+    assert(r.in1 == i + 1);
+    assert(r.in2 == j + 1);
+    assert(std::ranges::equal(i, std::array{4, 2, 3}));
+    assert(std::ranges::equal(j, std::array{1}));
+    std::same_as<Expected> auto r2 = std::ranges::swap_ranges(i, j);
+    assert(r2.in1 == i + 1);
+    assert(r2.in2 == j + 1);
+    assert(std::ranges::equal(i, std::array{1, 2, 3}));
+    assert(std::ranges::equal(j, std::array{4}));
+    std::same_as<Expected> auto r3 = std::ranges::swap_ranges(j, j + 1, i, i + 3);
+    assert(r3.in1 == j + 1);
+    assert(r3.in2 == i + 1);
+    assert(std::ranges::equal(i, std::array{4, 2, 3}));
+    assert(std::ranges::equal(j, std::array{1}));
+    std::same_as<Expected> auto r4 = std::ranges::swap_ranges(j, i);
+    assert(r4.in1 == j + 1);
+    assert(r4.in2 == i + 1);
+    assert(std::ranges::equal(i, std::array{1, 2, 3}));
+    assert(std::ranges::equal(j, std::array{4}));
+  }
+
+  { // Validate swapping when one or both are borrowed input ranges (views)
+    {
+      int r1[] = {1, 2, 3};
+      int r2[] = {4, 5, 6};
+      std::ranges::swap_ranges(std::views::all(r1), r2);
+      assert(std::ranges::equal(r1, std::array{4, 5, 6}));
+      assert(std::ranges::equal(r2, std::array{1, 2, 3}));
+    }
+    {
+      int r1[] = {1, 2, 3};
+      int r2[] = {4, 5, 6};
+      std::ranges::swap_ranges(r1, std::views::all(r2));
+      assert(std::ranges::equal(r1, std::array{4, 5, 6}));
+      assert(std::ranges::equal(r2, std::array{1, 2, 3}));
+    }
+    {
+      int r1[] = {1, 2, 3};
+      int r2[] = {4, 5, 6};
+      std::ranges::swap_ranges(std::views::all(r1), std::views::all(r2));
+      assert(std::ranges::equal(r1, std::array{4, 5, 6}));
+      assert(std::ranges::equal(r2, std::array{1, 2, 3}));
+    }
+  }
+
+  { // Validate swapping involving rvalue ranges
+    {
+      using Expected       = std::ranges::swap_ranges_result<std::array<int, 3>::iterator, std::ranges::dangling>;
+      std::array<int, 3> r = {1, 2, 3};
+      std::same_as<Expected> auto a = std::ranges::swap_ranges(r, std::array{4, 5, 6});
+      assert((r == std::array{4, 5, 6}));
+      assert(a.in1 == r.begin() + 3);
+    }
+    {
+      std::array<int, 3> r = {1, 2, 3};
+      using Expected       = std::ranges::swap_ranges_result<std::ranges::dangling, std::array<int, 3>::iterator>;
+      std::same_as<Expected> auto b = std::ranges::swap_ranges(std::array{4, 5, 6}, r);
+      assert((r == std::array{4, 5, 6}));
+      assert(b.in2 == r.begin() + 3);
+    }
+  }
 
   types::for_each(types::cpp20_input_iterator_list<int*>(), []<class Iter1>() {
     types::for_each(types::cpp20_input_iterator_list<int*>(), []<class Iter2>() {
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/swap_ranges.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/swap_ranges.pass.cpp
index 01cd33150e236..84ebedf213f5b 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/swap_ranges.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/swap_ranges.pass.cpp
@@ -35,12 +35,31 @@ struct TestPtr {
   struct TestImpl {
     template <class Iter2>
     TEST_CONSTEXPR_CXX20 void operator()() {
-      int a[] = {1, 2, 3};
-      int b[] = {4, 5, 6};
-      Iter2 r = std::swap_ranges(Iter1(a), Iter1(a + 3), Iter2(b));
-      assert(base(r) == b + 3);
-      assert(a[0] == 4 && a[1] == 5 && a[2] == 6);
-      assert(b[0] == 1 && b[1] == 2 && b[2] == 3);
+      { // Basic test case: swapping three elements between two arrays
+        int a[] = {1, 2, 3};
+        int b[] = {4, 5, 6};
+        Iter2 r = std::swap_ranges(Iter1(a), Iter1(a + 3), Iter2(b));
+        assert(base(r) == b + 3);
+        assert(a[0] == 4 && a[1] == 5 && a[2] == 6);
+        assert(b[0] == 1 && b[1] == 2 && b[2] == 3);
+      }
+      { // Large-scale test: swapping 100 elements between two different containers
+        const int N = 100;
+        std::array<int, N> a;
+        std::vector<int> b(N + 2, 42);
+        b.front() = 1;
+        b.back()  = -1;
+        for (int i = 0; i < N; ++i)
+          a[i] = i * i + 1;
+        Iter2 r = std::swap_ranges(Iter1(a.data()), Iter1(a.data() + N), Iter2(b.data() + 1));
+        assert(base(r) == b.data() + N + 1);
+        assert(b.front() == 1); // Ensure that the unswapped portion remains unchanged
+        assert(b.back() == -1);
+        for (int i = 0; i < N; ++i) {
+          assert(a[i] == 42);
+          assert(b[i + 1] == i * i + 1);
+        }
+      }
     }
   };
 };



More information about the libcxx-commits mailing list