1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// <algorithm>
10
11// UNSUPPORTED: c++03, c++11, c++14, c++17
12
13// template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2>
14// requires indirectly_swappable<I1, I2>
15// constexpr ranges::swap_ranges_result<I1, I2>
16// ranges::swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2);
17// template<input_range R1, input_range R2>
18// requires indirectly_swappable<iterator_t<R1>, iterator_t<R2>>
19// constexpr ranges::swap_ranges_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
20// ranges::swap_ranges(R1&& r1, R2&& r2);
21
22#include <algorithm>
23#include <array>
24#include <cassert>
25#include <ranges>
26#include <vector>
27
28#include <cstdio>
29
30#include "test_iterators.h"
31#include "type_algorithms.h"
32
33template <class Iter1, class Iter2>
34TEST_CONSTEXPR_CXX20 void test_iterators() {
35 using Expected = std::ranges::swap_ranges_result<Iter1, Iter2>;
36 { // Basic test case: swapping three elements between two arrays
37 int a[3] = {1, 2, 3};
38 int b[3] = {4, 5, 6};
39 std::same_as<Expected> auto r =
40 std::ranges::swap_ranges(Iter1(a), sentinel_wrapper(Iter1(a + 3)), Iter2(b), sentinel_wrapper(Iter2(b + 3)));
41 assert(base(r.in1) == a + 3);
42 assert(base(r.in2) == b + 3);
43 assert(std::ranges::equal(a, std::array{4, 5, 6}));
44 assert(std::ranges::equal(b, std::array{1, 2, 3}));
45 }
46 { // Large-scale test: swapping 100 elements between two different containers
47 const int N = 100;
48 std::array<int, N> a;
49 std::vector<int> b(N + 2, 42);
50 b.front() = 1;
51 b.back() = -1;
52 for (int i = 0; i < N; ++i)
53 a[i] = i * i + 1;
54 std::same_as<Expected> auto r = std::ranges::swap_ranges(
55 Iter1(a.data()),
56 sentinel_wrapper(Iter1(a.data() + N)),
57 Iter2(b.data() + 1),
58 sentinel_wrapper(Iter2(b.data() + b.size())));
59 assert(base(r.in1) == a.data() + N);
60 assert(base(r.in2) == b.data() + N + 1);
61 assert(b.front() == 1); // Ensure that the unswapped portion remains unchanged
62 assert(b.back() == -1);
63 for (int i = 0; i < N; ++i) {
64 assert(a[i] == 42);
65 assert(b[i + 1] == i * i + 1);
66 }
67 }
68}
69
70template <std::size_t N>
71constexpr void test_vector_bool() {
72 { // Test swap_ranges() with aligned bytes
73 std::vector<bool> f(N, false), t(N, true);
74 std::ranges::swap_ranges(f, t);
75 assert(std::all_of(f.begin(), f.end(), [](bool b) { return b; }));
76 assert(std::all_of(t.begin(), t.end(), [](bool b) { return !b; }));
77 }
78 { // Test swap_ranges() with unaligned bytes
79 std::vector<bool> f(N, false), t(N + 8, true);
80 std::ranges::swap_ranges(f.begin(), f.end(), t.begin() + 4, t.end() - 4);
81 assert(std::all_of(f.begin(), f.end(), [](bool b) { return b; }));
82 assert(std::all_of(t.begin() + 4, t.end() - 4, [](bool b) { return !b; }));
83 }
84}
85
86constexpr bool test() {
87 { // Validate swapping ranges directly
88 std::array r1 = {1, 2, 3};
89 std::array r2 = {4, 5, 6};
90
91 std::same_as<std::ranges::in_in_result<std::array<int, 3>::iterator, std::array<int, 3>::iterator>> auto r =
92 std::ranges::swap_ranges(r1, r2);
93 assert(r.in1 == r1.end());
94 assert(r.in2 == r2.end());
95 assert((r1 == std::array{4, 5, 6}));
96 assert((r2 == std::array{1, 2, 3}));
97 }
98
99 { // Validate swapping ranges using iterator and sentinels
100 int i[3] = {1, 2, 3};
101 int j[3] = {4, 5, 6};
102 using It = cpp17_input_iterator<int*>;
103 using Sent = sentinel_wrapper<It>;
104 using Expected = std::ranges::swap_ranges_result<It, It>;
105 std::same_as<Expected> auto r = std::ranges::swap_ranges(It(i), Sent(It(i + 3)), It(j), Sent(It(j + 3)));
106 assert(base(r.in1) == i + 3);
107 assert(base(r.in2) == j + 3);
108 assert(std::ranges::equal(i, std::array{4, 5, 6}));
109 assert(std::ranges::equal(j, std::array{1, 2, 3}));
110 }
111
112 { // Validate swapping ranges of different lengths
113 using Expected = std::ranges::swap_ranges_result<int*, int*>;
114 int i[3] = {1, 2, 3};
115 int j[1] = {4};
116 std::same_as<Expected> auto r = std::ranges::swap_ranges(i, i + 3, j, j + 1);
117 assert(r.in1 == i + 1);
118 assert(r.in2 == j + 1);
119 assert(std::ranges::equal(i, std::array{4, 2, 3}));
120 assert(std::ranges::equal(j, std::array{1}));
121 std::same_as<Expected> auto r2 = std::ranges::swap_ranges(i, j);
122 assert(r2.in1 == i + 1);
123 assert(r2.in2 == j + 1);
124 assert(std::ranges::equal(i, std::array{1, 2, 3}));
125 assert(std::ranges::equal(j, std::array{4}));
126 std::same_as<Expected> auto r3 = std::ranges::swap_ranges(j, j + 1, i, i + 3);
127 assert(r3.in1 == j + 1);
128 assert(r3.in2 == i + 1);
129 assert(std::ranges::equal(i, std::array{4, 2, 3}));
130 assert(std::ranges::equal(j, std::array{1}));
131 std::same_as<Expected> auto r4 = std::ranges::swap_ranges(j, i);
132 assert(r4.in1 == j + 1);
133 assert(r4.in2 == i + 1);
134 assert(std::ranges::equal(i, std::array{1, 2, 3}));
135 assert(std::ranges::equal(j, std::array{4}));
136 }
137
138 { // Validate swapping when one or both are borrowed input ranges (views)
139 {
140 int r1[] = {1, 2, 3};
141 int r2[] = {4, 5, 6};
142 std::ranges::swap_ranges(std::views::all(r1), r2);
143 assert(std::ranges::equal(r1, std::array{4, 5, 6}));
144 assert(std::ranges::equal(r2, std::array{1, 2, 3}));
145 }
146 {
147 int r1[] = {1, 2, 3};
148 int r2[] = {4, 5, 6};
149 std::ranges::swap_ranges(r1, std::views::all(r2));
150 assert(std::ranges::equal(r1, std::array{4, 5, 6}));
151 assert(std::ranges::equal(r2, std::array{1, 2, 3}));
152 }
153 {
154 int r1[] = {1, 2, 3};
155 int r2[] = {4, 5, 6};
156 std::ranges::swap_ranges(std::views::all(r1), std::views::all(r2));
157 assert(std::ranges::equal(r1, std::array{4, 5, 6}));
158 assert(std::ranges::equal(r2, std::array{1, 2, 3}));
159 }
160 }
161
162 { // Validate swapping involving rvalue ranges
163 {
164 using Expected = std::ranges::swap_ranges_result<std::array<int, 3>::iterator, std::ranges::dangling>;
165 std::array<int, 3> r = {1, 2, 3};
166 std::same_as<Expected> auto a = std::ranges::swap_ranges(r, std::array{4, 5, 6});
167 assert((r == std::array{4, 5, 6}));
168 assert(a.in1 == r.begin() + 3);
169 }
170 {
171 std::array<int, 3> r = {1, 2, 3};
172 using Expected = std::ranges::swap_ranges_result<std::ranges::dangling, std::array<int, 3>::iterator>;
173 std::same_as<Expected> auto b = std::ranges::swap_ranges(std::array{4, 5, 6}, r);
174 assert((r == std::array{4, 5, 6}));
175 assert(b.in2 == r.begin() + 3);
176 }
177 }
178
179 types::for_each(types::cpp20_input_iterator_list<int*>(), []<class Iter1>() {
180 types::for_each(types::cpp20_input_iterator_list<int*>(), []<class Iter2>() {
181 test_iterators<Iter1, Iter2>();
182 test_iterators<ProxyIterator<Iter1>, ProxyIterator<Iter2>>();
183 });
184 });
185
186 { // Test vector<bool>::iterator optimization
187 test_vector_bool<8>();
188 test_vector_bool<19>();
189 test_vector_bool<32>();
190 test_vector_bool<49>();
191 test_vector_bool<64>();
192 test_vector_bool<199>();
193 test_vector_bool<256>();
194 }
195 return true;
196}
197
198static_assert(std::same_as<std::ranges::swap_ranges_result<int, char>, std::ranges::in_in_result<int, char>>);
199
200int main(int, char**) {
201 test();
202 static_assert(test());
203
204 return 0;
205}
206

source code of libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp