191 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// <algorithm>10 11// template<ForwardIterator Iter1, ForwardIterator Iter2>12// requires HasSwap<Iter1::reference, Iter2::reference>13// Iter214// swap_ranges(Iter1 first1, Iter1 last1, Iter2 first2);15 16#include <algorithm>17#include <array>18#include <cassert>19#include <memory>20#include <type_traits>21#include <utility>22#include <vector>23 24#include "test_macros.h"25#include "test_iterators.h"26#include "type_algorithms.h"27 28struct TestPtr {29 template <class Iter>30 TEST_CONSTEXPR_CXX20 void operator()() {31 types::for_each(types::forward_iterator_list<int*>(), TestImpl<Iter>());32 }33 34 template <class Iter1>35 struct TestImpl {36 template <class Iter2>37 TEST_CONSTEXPR_CXX20 void operator()() {38 { // Basic test case: swapping three elements between two arrays39 int a[] = {1, 2, 3};40 int b[] = {4, 5, 6};41 Iter2 r = std::swap_ranges(Iter1(a), Iter1(a + 3), Iter2(b));42 assert(base(r) == b + 3);43 assert(a[0] == 4 && a[1] == 5 && a[2] == 6);44 assert(b[0] == 1 && b[1] == 2 && b[2] == 3);45 }46 { // Large-scale test: swapping 100 elements between two different containers47 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 Iter2 r = std::swap_ranges(Iter1(a.data()), Iter1(a.data() + N), Iter2(b.data() + 1));55 assert(base(r) == b.data() + N + 1);56 assert(b.front() == 1); // Ensure that the unswapped portion remains unchanged57 assert(b.back() == -1);58 for (int i = 0; i < N; ++i) {59 assert(a[i] == 42);60 assert(b[i + 1] == i * i + 1);61 }62 }63 }64 };65};66 67#if TEST_STD_VER >= 1168struct TestUniquePtr {69 template <class Iter>70 TEST_CONSTEXPR_CXX23 void operator()() {71 types::for_each(types::forward_iterator_list<std::unique_ptr<int>*>(), TestImpl<Iter>());72 }73 74 template <class Iter1>75 struct TestImpl {76 template <class Iter2>77 TEST_CONSTEXPR_CXX23 void operator()() {78 std::unique_ptr<int> a[3];79 for (int k = 0; k < 3; ++k)80 a[k].reset(new int(k + 1));81 std::unique_ptr<int> b[3];82 for (int k = 0; k < 3; ++k)83 b[k].reset(new int(k + 4));84 Iter2 r = std::swap_ranges(Iter1(a), Iter1(a + 3), Iter2(b));85 assert(base(r) == b + 3);86 assert(*a[0] == 4 && *a[1] == 5 && *a[2] == 6);87 assert(*b[0] == 1 && *b[1] == 2 && *b[2] == 3);88 }89 };90};91#endif92 93template <template <class> class Iter1, template <class> class Iter2>94TEST_CONSTEXPR_CXX20 bool test_simple_cases() {95 {96 int a[2] = {1, 2};97 int b[2] = {4, 5};98 std::swap_ranges(Iter1<int*>(a), Iter1<int*>(a + 2), Iter2<int*>(b));99 assert(a[0] == 4 && a[1] == 5);100 assert(b[0] == 1 && b[1] == 2);101 }102 {103 std::array<int, 3> a = {1, 2, 3}, a0 = a;104 std::array<int, 3> b = {4, 5, 6}, b0 = b;105 using It1 = Iter1<std::array<int, 3>::iterator>;106 using It2 = Iter2<std::array<int, 3>::iterator>;107 std::swap_ranges(It1(a.begin()), It1(a.end()), It2(b.begin()));108 assert(a == b0);109 assert(b == a0);110 }111 {112 std::array<std::array<int, 2>, 2> a = {{{0, 1}, {2, 3}}}, a0 = a;113 std::array<std::array<int, 2>, 2> b = {{{9, 8}, {7, 6}}}, b0 = b;114 using It1 = Iter1<std::array<std::array<int, 2>, 2>::iterator>;115 using It2 = Iter2<std::array<std::array<int, 2>, 2>::iterator>;116 std::swap_ranges(It1(a.begin()), It1(a.end()), It2(b.begin()));117 assert(a == b0);118 assert(b == a0);119 }120 {121 std::array<std::array<int, 3>, 3> a = {{{0, 1, 2}, {3, 4, 5}, {6, 7, 8}}}, a0 = a;122 std::array<std::array<int, 3>, 3> b = {{{9, 8, 7}, {6, 5, 4}, {3, 2, 1}}}, b0 = b;123 using It1 = Iter1<std::array<std::array<int, 3>, 3>::iterator>;124 using It2 = Iter2<std::array<std::array<int, 3>, 3>::iterator>;125 std::swap_ranges(It1(a.begin()), It1(a.end()), It2(b.begin()));126 assert(a == b0);127 assert(b == a0);128 }129 130 return true;131}132 133template <std::size_t N>134TEST_CONSTEXPR_CXX20 void test_vector_bool() {135 std::vector<bool> f(N, false), t(N, true);136 { // Test swap_ranges() with aligned bytes137 std::vector<bool> f1 = f, t1 = t;138 std::swap_ranges(f1.begin(), f1.end(), t1.begin());139 assert(f1 == t);140 assert(t1 == f);141 }142 { // Test swap_ranges() with unaligned bytes143 std::vector<bool> f1(N, false), t1(N + 8, true);144 std::swap_ranges(f1.begin(), f1.end(), t1.begin() + 4);145 assert(std::equal(f1.begin(), f1.end(), t.begin()));146 assert(std::equal(t1.begin() + 4, t1.end() - 4, f.begin()));147 }148}149 150TEST_CONSTEXPR_CXX20 bool test() {151 test_simple_cases<forward_iterator, forward_iterator>();152 test_simple_cases<forward_iterator, bidirectional_iterator>();153 test_simple_cases<forward_iterator, random_access_iterator>();154 test_simple_cases<bidirectional_iterator, forward_iterator>();155 test_simple_cases<bidirectional_iterator, bidirectional_iterator>();156 test_simple_cases<bidirectional_iterator, random_access_iterator>();157 test_simple_cases<random_access_iterator, random_access_iterator>();158#if TEST_STD_VER >= 20159 test_simple_cases<std::type_identity_t, std::type_identity_t>();160#endif161 162 types::for_each(types::forward_iterator_list<int*>(), TestPtr());163 164#if TEST_STD_VER >= 11165 // We can't test unique_ptr in constant evaluation before C++23 as it's constexpr only since C++23.166 if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED)167 types::for_each(types::forward_iterator_list<std::unique_ptr<int>*>(), TestUniquePtr());168#endif169 170 { // Test vector<bool>::iterator optimization171 test_vector_bool<8>();172 test_vector_bool<19>();173 test_vector_bool<32>();174 test_vector_bool<49>();175 test_vector_bool<64>();176 test_vector_bool<199>();177 test_vector_bool<256>();178 }179 180 return true;181}182 183int main(int, char**) {184 test();185#if TEST_STD_VER >= 20186 static_assert(test());187#endif188 189 return 0;190}191