xref: /llvm-project/libcxx/test/std/concepts/concepts.lang/concept.swappable/swappable.pass.cpp (revision d2baefae6846765eef6a6dd69d4fdf1082ce29ad)
124dd2d2fSChristopher Di Bella //===----------------------------------------------------------------------===//
224dd2d2fSChristopher Di Bella //
324dd2d2fSChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
424dd2d2fSChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information.
524dd2d2fSChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
624dd2d2fSChristopher Di Bella //
724dd2d2fSChristopher Di Bella //===----------------------------------------------------------------------===//
824dd2d2fSChristopher Di Bella 
924dd2d2fSChristopher Di Bella // UNSUPPORTED: c++03, c++11, c++14, c++17
1024dd2d2fSChristopher Di Bella 
1124dd2d2fSChristopher Di Bella // template<class T>
1224dd2d2fSChristopher Di Bella // concept swappable = // see below
1324dd2d2fSChristopher Di Bella 
1424dd2d2fSChristopher Di Bella #include <concepts>
1524dd2d2fSChristopher Di Bella 
1624dd2d2fSChristopher Di Bella #include <algorithm>
1724dd2d2fSChristopher Di Bella #include <cassert>
1824dd2d2fSChristopher Di Bella #include <deque>
1924dd2d2fSChristopher Di Bella #include <map>
2024dd2d2fSChristopher Di Bella #include <memory>
2124dd2d2fSChristopher Di Bella #include <string>
2224dd2d2fSChristopher Di Bella #include <optional>
2324dd2d2fSChristopher Di Bella #include <unordered_map>
2424dd2d2fSChristopher Di Bella #include <vector>
2524dd2d2fSChristopher Di Bella 
2624dd2d2fSChristopher Di Bella #include "test_macros.h"
2724dd2d2fSChristopher Di Bella #include "type_classification/moveconstructible.h"
2824dd2d2fSChristopher Di Bella #include "type_classification/swappable.h"
2924dd2d2fSChristopher Di Bella 
3024dd2d2fSChristopher Di Bella template <class T>
3124dd2d2fSChristopher Di Bella struct expected {
3224dd2d2fSChristopher Di Bella   T x;
3324dd2d2fSChristopher Di Bella   T y;
3424dd2d2fSChristopher Di Bella };
3524dd2d2fSChristopher Di Bella 
3624dd2d2fSChristopher Di Bella // clang-format off
3724dd2d2fSChristopher Di Bella // Checks [concept.swappable]/2.1
3824dd2d2fSChristopher Di Bella template <class T, class U>
3924dd2d2fSChristopher Di Bella requires std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<U> > &&
4024dd2d2fSChristopher Di Bella          std::swappable<std::remove_cvref_t<T> >
check_swap_21(T && x,U && y)4124dd2d2fSChristopher Di Bella constexpr bool check_swap_21(T&& x, U&& y) {
4224dd2d2fSChristopher Di Bella   expected<std::remove_cvref_t<T> > const e{y, x};
4324dd2d2fSChristopher Di Bella   std::ranges::swap(std::forward<T>(x), std::forward<U>(y));
4424dd2d2fSChristopher Di Bella   return x == e.x && y == e.y;
4524dd2d2fSChristopher Di Bella }
4624dd2d2fSChristopher Di Bella 
4724dd2d2fSChristopher Di Bella // Checks [concept.swappable]/2.2
4824dd2d2fSChristopher Di Bella template <std::swappable T, std::size_t N>
check_swap_22(T (& x)[N],T (& y)[N])4924dd2d2fSChristopher Di Bella constexpr bool check_swap_22(T (&x)[N], T (&y)[N]) {
5024dd2d2fSChristopher Di Bella   expected<T[N]> e;
5124dd2d2fSChristopher Di Bella   std::copy(y, y + N, e.x);
5224dd2d2fSChristopher Di Bella   std::copy(x, x + N, e.y);
5324dd2d2fSChristopher Di Bella 
5424dd2d2fSChristopher Di Bella   std::ranges::swap(x, y);
5524dd2d2fSChristopher Di Bella   return std::equal(x, x + N, e.x, e.x + N) &&
5624dd2d2fSChristopher Di Bella          std::equal(y, y + N, e.y, e.y + N);
5724dd2d2fSChristopher Di Bella }
5824dd2d2fSChristopher Di Bella 
5924dd2d2fSChristopher Di Bella // Checks [concept.swappable]/2.3
6024dd2d2fSChristopher Di Bella template <std::swappable T>
6124dd2d2fSChristopher Di Bella requires std::copy_constructible<std::remove_cvref_t<T> >
check_swap_23(T x,T y)6224dd2d2fSChristopher Di Bella constexpr bool check_swap_23(T x, T y) {
6324dd2d2fSChristopher Di Bella   expected<std::remove_cvref_t<T> > const e{y, x};
6424dd2d2fSChristopher Di Bella   std::ranges::swap(x, y);
6524dd2d2fSChristopher Di Bella   return x == e.x && y == e.y;
6624dd2d2fSChristopher Di Bella }
6724dd2d2fSChristopher Di Bella // clang-format on
6824dd2d2fSChristopher Di Bella 
check_lvalue_adl_swappable()6924dd2d2fSChristopher Di Bella constexpr bool check_lvalue_adl_swappable() {
7024dd2d2fSChristopher Di Bella   auto x = lvalue_adl_swappable(0);
7124dd2d2fSChristopher Di Bella   auto y = lvalue_adl_swappable(1);
72*cb71d77cSCasey Carter   ASSERT_NOEXCEPT(std::ranges::swap(x, y));
73*cb71d77cSCasey Carter   assert(check_swap_21(x, y));
74*cb71d77cSCasey Carter   return true;
7524dd2d2fSChristopher Di Bella }
7624dd2d2fSChristopher Di Bella static_assert(check_lvalue_adl_swappable());
7724dd2d2fSChristopher Di Bella 
check_rvalue_adl_swappable()7824dd2d2fSChristopher Di Bella constexpr bool check_rvalue_adl_swappable() {
79*cb71d77cSCasey Carter   ASSERT_NOEXCEPT(std::ranges::swap(rvalue_adl_swappable(0), rvalue_adl_swappable(1)));
80*cb71d77cSCasey Carter   assert(check_swap_21(rvalue_adl_swappable(0), rvalue_adl_swappable(1)));
81*cb71d77cSCasey Carter   return true;
8224dd2d2fSChristopher Di Bella }
8324dd2d2fSChristopher Di Bella static_assert(check_rvalue_adl_swappable());
8424dd2d2fSChristopher Di Bella 
check_lvalue_rvalue_adl_swappable()8524dd2d2fSChristopher Di Bella constexpr bool check_lvalue_rvalue_adl_swappable() {
8624dd2d2fSChristopher Di Bella   auto x = lvalue_rvalue_adl_swappable(0);
87*cb71d77cSCasey Carter   ASSERT_NOEXCEPT(std::ranges::swap(x, lvalue_rvalue_adl_swappable(1)));
88*cb71d77cSCasey Carter   assert(check_swap_21(x, lvalue_rvalue_adl_swappable(1)));
89*cb71d77cSCasey Carter   return true;
9024dd2d2fSChristopher Di Bella }
9124dd2d2fSChristopher Di Bella static_assert(check_lvalue_rvalue_adl_swappable());
9224dd2d2fSChristopher Di Bella 
check_rvalue_lvalue_adl_swappable()9324dd2d2fSChristopher Di Bella constexpr bool check_rvalue_lvalue_adl_swappable() {
9424dd2d2fSChristopher Di Bella   auto x = rvalue_lvalue_adl_swappable(0);
95*cb71d77cSCasey Carter   ASSERT_NOEXCEPT(std::ranges::swap(rvalue_lvalue_adl_swappable(1), x));
96*cb71d77cSCasey Carter   assert(check_swap_21(rvalue_lvalue_adl_swappable(1), x));
97*cb71d77cSCasey Carter   return true;
9824dd2d2fSChristopher Di Bella }
9924dd2d2fSChristopher Di Bella static_assert(check_rvalue_lvalue_adl_swappable());
10024dd2d2fSChristopher Di Bella 
check_throwable_swappable()10124dd2d2fSChristopher Di Bella constexpr bool check_throwable_swappable() {
10224dd2d2fSChristopher Di Bella   auto x = throwable_adl_swappable{0};
10324dd2d2fSChristopher Di Bella   auto y = throwable_adl_swappable{1};
104*cb71d77cSCasey Carter   ASSERT_NOT_NOEXCEPT(std::ranges::swap(x, y));
105*cb71d77cSCasey Carter   assert(check_swap_21(x, y));
106*cb71d77cSCasey Carter   return true;
10724dd2d2fSChristopher Di Bella }
10824dd2d2fSChristopher Di Bella static_assert(check_throwable_swappable());
10924dd2d2fSChristopher Di Bella 
check_non_move_constructible_adl_swappable()11024dd2d2fSChristopher Di Bella constexpr bool check_non_move_constructible_adl_swappable() {
11124dd2d2fSChristopher Di Bella   auto x = non_move_constructible_adl_swappable{0};
11224dd2d2fSChristopher Di Bella   auto y = non_move_constructible_adl_swappable{1};
113*cb71d77cSCasey Carter   ASSERT_NOEXCEPT(std::ranges::swap(x, y));
114*cb71d77cSCasey Carter   assert(check_swap_21(x, y));
115*cb71d77cSCasey Carter   return true;
11624dd2d2fSChristopher Di Bella }
11724dd2d2fSChristopher Di Bella static_assert(check_non_move_constructible_adl_swappable());
11824dd2d2fSChristopher Di Bella 
check_non_move_assignable_adl_swappable()11924dd2d2fSChristopher Di Bella constexpr bool check_non_move_assignable_adl_swappable() {
12024dd2d2fSChristopher Di Bella   auto x = non_move_assignable_adl_swappable{0};
12124dd2d2fSChristopher Di Bella   auto y = non_move_assignable_adl_swappable{1};
122*cb71d77cSCasey Carter   ASSERT_NOEXCEPT(std::ranges::swap(x, y));
123*cb71d77cSCasey Carter   assert(check_swap_21(x, y));
124*cb71d77cSCasey Carter   return true;
12524dd2d2fSChristopher Di Bella }
12624dd2d2fSChristopher Di Bella static_assert(check_non_move_assignable_adl_swappable());
12724dd2d2fSChristopher Di Bella 
12824dd2d2fSChristopher Di Bella namespace swappable_namespace {
12924dd2d2fSChristopher Di Bella enum unscoped { hello, world };
13024dd2d2fSChristopher Di Bella void swap(unscoped&, unscoped&);
13124dd2d2fSChristopher Di Bella 
13224dd2d2fSChristopher Di Bella enum class scoped { hello, world };
13324dd2d2fSChristopher Di Bella void swap(scoped&, scoped&);
13424dd2d2fSChristopher Di Bella } // namespace swappable_namespace
13524dd2d2fSChristopher Di Bella 
13624dd2d2fSChristopher Di Bella static_assert(std::swappable<swappable_namespace::unscoped>);
13724dd2d2fSChristopher Di Bella static_assert(std::swappable<swappable_namespace::scoped>);
13824dd2d2fSChristopher Di Bella 
check_swap_arrays()13924dd2d2fSChristopher Di Bella constexpr bool check_swap_arrays() {
14024dd2d2fSChristopher Di Bella   int x[] = {0, 1, 2, 3, 4};
14124dd2d2fSChristopher Di Bella   int y[] = {5, 6, 7, 8, 9};
142*cb71d77cSCasey Carter   ASSERT_NOEXCEPT(std::ranges::swap(x, y));
143*cb71d77cSCasey Carter   assert(check_swap_22(x, y));
144*cb71d77cSCasey Carter   return true;
14524dd2d2fSChristopher Di Bella }
14624dd2d2fSChristopher Di Bella static_assert(check_swap_arrays());
14724dd2d2fSChristopher Di Bella 
check_lvalue_adl_swappable_arrays()14824dd2d2fSChristopher Di Bella constexpr bool check_lvalue_adl_swappable_arrays() {
14924dd2d2fSChristopher Di Bella   lvalue_adl_swappable x[] = {{0}, {1}, {2}, {3}};
15024dd2d2fSChristopher Di Bella   lvalue_adl_swappable y[] = {{4}, {5}, {6}, {7}};
151*cb71d77cSCasey Carter   ASSERT_NOEXCEPT(std::ranges::swap(x, y));
152*cb71d77cSCasey Carter   assert(check_swap_22(x, y));
153*cb71d77cSCasey Carter   return true;
15424dd2d2fSChristopher Di Bella }
15524dd2d2fSChristopher Di Bella static_assert(check_lvalue_adl_swappable_arrays());
15624dd2d2fSChristopher Di Bella 
check_throwable_adl_swappable_arrays()15724dd2d2fSChristopher Di Bella constexpr bool check_throwable_adl_swappable_arrays() {
15824dd2d2fSChristopher Di Bella   throwable_adl_swappable x[] = {{0}, {1}, {2}, {3}};
15924dd2d2fSChristopher Di Bella   throwable_adl_swappable y[] = {{4}, {5}, {6}, {7}};
160*cb71d77cSCasey Carter   ASSERT_NOT_NOEXCEPT(std::ranges::swap(x, y));
161*cb71d77cSCasey Carter   assert(check_swap_22(x, y));
162*cb71d77cSCasey Carter   return true;
16324dd2d2fSChristopher Di Bella }
16424dd2d2fSChristopher Di Bella static_assert(check_throwable_adl_swappable_arrays());
16524dd2d2fSChristopher Di Bella 
166*cb71d77cSCasey Carter auto global_x = 0;
167*cb71d77cSCasey Carter ASSERT_NOEXCEPT(std::ranges::swap(global_x, global_x));
168*cb71d77cSCasey Carter static_assert(check_swap_23(0, 0));
169*cb71d77cSCasey Carter static_assert(check_swap_23(0, 1));
170*cb71d77cSCasey Carter static_assert(check_swap_23(1, 0));
17124dd2d2fSChristopher Di Bella 
check_swappable_references()17224dd2d2fSChristopher Di Bella constexpr bool check_swappable_references() {
17324dd2d2fSChristopher Di Bella   int x = 42;
17424dd2d2fSChristopher Di Bella   int y = 64;
175*cb71d77cSCasey Carter   ASSERT_NOEXCEPT(std::ranges::swap(x, y));
176*cb71d77cSCasey Carter   assert(check_swap_23(x, y));
177*cb71d77cSCasey Carter   return true;
17824dd2d2fSChristopher Di Bella }
17924dd2d2fSChristopher Di Bella static_assert(check_swappable_references());
18024dd2d2fSChristopher Di Bella 
check_swappable_pointers()18124dd2d2fSChristopher Di Bella constexpr bool check_swappable_pointers() {
18224dd2d2fSChristopher Di Bella   char const* x = "hello";
183*cb71d77cSCasey Carter   ASSERT_NOEXCEPT(std::ranges::swap(x, x));
184*cb71d77cSCasey Carter   assert(check_swap_23(x, {}));
185*cb71d77cSCasey Carter   return true;
18624dd2d2fSChristopher Di Bella }
18724dd2d2fSChristopher Di Bella static_assert(check_swappable_pointers());
18824dd2d2fSChristopher Di Bella 
18924dd2d2fSChristopher Di Bella namespace union_swap {
19024dd2d2fSChristopher Di Bella union adl_swappable {
19124dd2d2fSChristopher Di Bella   int x;
19224dd2d2fSChristopher Di Bella   double y;
19324dd2d2fSChristopher Di Bella };
19424dd2d2fSChristopher Di Bella 
19524dd2d2fSChristopher Di Bella void swap(adl_swappable&, adl_swappable&);
19624dd2d2fSChristopher Di Bella void swap(adl_swappable&&, adl_swappable&&);
197*cb71d77cSCasey Carter } // namespace union_swap
19824dd2d2fSChristopher Di Bella static_assert(std::swappable<union_swap::adl_swappable>);
19924dd2d2fSChristopher Di Bella static_assert(std::swappable<union_swap::adl_swappable&>);
20024dd2d2fSChristopher Di Bella static_assert(std::swappable<union_swap::adl_swappable&&>);
20124dd2d2fSChristopher Di Bella 
20224dd2d2fSChristopher Di Bella // All tests for std::swappable<T> are implicitly confirmed by `check_swap`, so we only need to
20324dd2d2fSChristopher Di Bella // sanity check for a few positive cases.
20424dd2d2fSChristopher Di Bella static_assert(std::swappable<int volatile&>);
20524dd2d2fSChristopher Di Bella static_assert(std::swappable<int&&>);
20624dd2d2fSChristopher Di Bella static_assert(std::swappable<int (*)()>);
20724dd2d2fSChristopher Di Bella static_assert(std::swappable<int rvalue_adl_swappable::*>);
20824dd2d2fSChristopher Di Bella static_assert(std::swappable<int (rvalue_adl_swappable::*)()>);
20924dd2d2fSChristopher Di Bella static_assert(std::swappable<std::unique_ptr<int> >);
21024dd2d2fSChristopher Di Bella 
21124dd2d2fSChristopher Di Bella static_assert(!std::swappable<void>);
21224dd2d2fSChristopher Di Bella static_assert(!std::swappable<int const>);
21324dd2d2fSChristopher Di Bella static_assert(!std::swappable<int const&>);
21424dd2d2fSChristopher Di Bella static_assert(!std::swappable<int const&&>);
21524dd2d2fSChristopher Di Bella static_assert(!std::swappable<int const volatile>);
21624dd2d2fSChristopher Di Bella static_assert(!std::swappable<int const volatile&>);
21724dd2d2fSChristopher Di Bella static_assert(!std::swappable<int const volatile&&>);
21824dd2d2fSChristopher Di Bella static_assert(!std::swappable<int (&)()>);
21924dd2d2fSChristopher Di Bella static_assert(!std::swappable<DeletedMoveCtor>);
22024dd2d2fSChristopher Di Bella static_assert(!std::swappable<ImplicitlyDeletedMoveCtor>);
22124dd2d2fSChristopher Di Bella static_assert(!std::swappable<DeletedMoveAssign>);
22224dd2d2fSChristopher Di Bella static_assert(!std::swappable<ImplicitlyDeletedMoveAssign>);
22324dd2d2fSChristopher Di Bella static_assert(!std::swappable<NonMovable>);
22424dd2d2fSChristopher Di Bella static_assert(!std::swappable<DerivedFromNonMovable>);
22524dd2d2fSChristopher Di Bella static_assert(!std::swappable<HasANonMovable>);
22624dd2d2fSChristopher Di Bella 
22724dd2d2fSChristopher Di Bella using swap_type = std::remove_const_t<decltype(std::ranges::swap)>;
22824dd2d2fSChristopher Di Bella static_assert(std::default_initializable<swap_type>);
22924dd2d2fSChristopher Di Bella static_assert(std::move_constructible<swap_type>);
23024dd2d2fSChristopher Di Bella static_assert(std::copy_constructible<swap_type>);
23124dd2d2fSChristopher Di Bella static_assert(std::assignable_from<swap_type&, swap_type>);
23224dd2d2fSChristopher Di Bella static_assert(std::assignable_from<swap_type&, swap_type&>);
23324dd2d2fSChristopher Di Bella static_assert(std::assignable_from<swap_type&, swap_type const&>);
23424dd2d2fSChristopher Di Bella static_assert(std::assignable_from<swap_type&, swap_type const>);
23524dd2d2fSChristopher Di Bella static_assert(std::swappable<swap_type>);
23624dd2d2fSChristopher Di Bella 
237*cb71d77cSCasey Carter enum class nothrow { no, yes };
238*cb71d77cSCasey Carter 
239*cb71d77cSCasey Carter template <nothrow is_noexcept, std::swappable T>
check_swap(expected<T> const & e)24024dd2d2fSChristopher Di Bella void check_swap(expected<T> const& e) {
24124dd2d2fSChristopher Di Bella   auto a = e.y;
24224dd2d2fSChristopher Di Bella   auto b = e.x;
24324dd2d2fSChristopher Di Bella 
24424dd2d2fSChristopher Di Bella   std::ranges::swap(a, b);
24524dd2d2fSChristopher Di Bella   assert(a == e.x);
24624dd2d2fSChristopher Di Bella   assert(b == e.y);
24724dd2d2fSChristopher Di Bella 
24824dd2d2fSChristopher Di Bella   std::ranges::swap(a, b);
24924dd2d2fSChristopher Di Bella   assert(a == e.y);
25024dd2d2fSChristopher Di Bella   assert(b == e.x);
25124dd2d2fSChristopher Di Bella 
252*cb71d77cSCasey Carter   static_assert(noexcept(std::ranges::swap(a, b)) == bool(is_noexcept));
25324dd2d2fSChristopher Di Bella }
25424dd2d2fSChristopher Di Bella 
main(int,char **)25524dd2d2fSChristopher Di Bella int main(int, char**) {
25624dd2d2fSChristopher Di Bella   {
25724dd2d2fSChristopher Di Bella     auto const e = expected<std::deque<int> >{
25824dd2d2fSChristopher Di Bella         .x = {6, 7, 8, 9},
25924dd2d2fSChristopher Di Bella         .y = {0, 1, 2, 3, 4, 5},
26024dd2d2fSChristopher Di Bella     };
261*cb71d77cSCasey Carter     check_swap<nothrow::yes>(e);
26224dd2d2fSChristopher Di Bella   }
26324dd2d2fSChristopher Di Bella   {
26424dd2d2fSChristopher Di Bella     auto const e = expected<std::map<int, std::string> >{
26524dd2d2fSChristopher Di Bella         .x = {{0, "whole"}, {1, "cashews"}},
26624dd2d2fSChristopher Di Bella         .y = {{-1, "roasted"}, {2, "&"}, {-3, "salted"}},
26724dd2d2fSChristopher Di Bella     };
268*cb71d77cSCasey Carter     check_swap<nothrow::yes>(e);
26924dd2d2fSChristopher Di Bella   }
27024dd2d2fSChristopher Di Bella   {
27124dd2d2fSChristopher Di Bella     auto const e = expected<std::string>{
27224dd2d2fSChristopher Di Bella         .x = "hello there",
27324dd2d2fSChristopher Di Bella         .y = "general kenobi",
27424dd2d2fSChristopher Di Bella     };
275*cb71d77cSCasey Carter     check_swap<nothrow::yes>(e);
27624dd2d2fSChristopher Di Bella   }
27724dd2d2fSChristopher Di Bella   {
27824dd2d2fSChristopher Di Bella     auto const e = expected<std::optional<lvalue_adl_swappable> >{
27924dd2d2fSChristopher Di Bella         .x = {10},
28024dd2d2fSChristopher Di Bella         .y = {20},
28124dd2d2fSChristopher Di Bella     };
282*cb71d77cSCasey Carter     check_swap<nothrow::yes>(e);
28324dd2d2fSChristopher Di Bella   }
28424dd2d2fSChristopher Di Bella   {
28524dd2d2fSChristopher Di Bella     auto const e = expected<std::optional<throwable_adl_swappable> >{
28624dd2d2fSChristopher Di Bella         .x = {10},
28724dd2d2fSChristopher Di Bella         .y = {20},
28824dd2d2fSChristopher Di Bella     };
289*cb71d77cSCasey Carter     check_swap<nothrow::no>(e);
29024dd2d2fSChristopher Di Bella   }
29124dd2d2fSChristopher Di Bella   {
29224dd2d2fSChristopher Di Bella     auto const e = expected<std::unordered_map<int, std::string> >{
29324dd2d2fSChristopher Di Bella         .x = {{0, "whole"}, {1, "cashews"}},
29424dd2d2fSChristopher Di Bella         .y = {{-1, "roasted"}, {2, "&"}, {-3, "salted"}},
29524dd2d2fSChristopher Di Bella     };
296*cb71d77cSCasey Carter     check_swap<nothrow::yes>(e);
29724dd2d2fSChristopher Di Bella   }
29824dd2d2fSChristopher Di Bella   {
29924dd2d2fSChristopher Di Bella     auto const e = expected<std::vector<int> >{
30024dd2d2fSChristopher Di Bella         .x = {0, 1, 2, 3, 4, 5},
30124dd2d2fSChristopher Di Bella         .y = {6, 7, 8, 9},
30224dd2d2fSChristopher Di Bella     };
30324dd2d2fSChristopher Di Bella 
304*cb71d77cSCasey Carter     check_swap<nothrow::yes>(e);
30524dd2d2fSChristopher Di Bella   }
30624dd2d2fSChristopher Di Bella   return 0;
30724dd2d2fSChristopher Di Bella }
308