//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. // //===----------------------------------------------------------------------===// // template // concept swappable = // see below #include "type_classification/swappable.h" #include #include #include "test_macros.h" #include "type_classification/moveconstructible.h" using cuda::std::swappable; template struct expected { T x; T y; }; // clang-format off // Checks [concept.swappable]/2.1 _CCCL_TEMPLATE(class T, class U) _CCCL_REQUIRES( cuda::std::same_as, cuda::std::remove_cvref_t > && swappable >) // __host__ __device__ constexpr bool check_swap_21(T&& x, U&& y) { expected > const e{y, x}; cuda::std::ranges::swap(cuda::std::forward(x), cuda::std::forward(y)); return x == e.x && y == e.y; } // Checks [concept.swappable]/2.2 _CCCL_TEMPLATE(class T, cuda::std::size_t N) _CCCL_REQUIRES( swappable) __host__ __device__ constexpr bool check_swap_22(T (&x)[N], T (&y)[N]) { expected e{}; for (cuda::std::size_t i = 0; i < N; ++i) { e.x[i] = y[i]; e.y[i] = x[i]; } cuda::std::ranges::swap(x, y); for (cuda::std::size_t i = 0; i < N; ++i) { if (x[i] == e.x[i] && y[i] == e.y[i]) { continue; } return false; } return true; } // Checks [concept.swappable]/2.3 _CCCL_TEMPLATE(class T) _CCCL_REQUIRES( swappable && cuda::std::copy_constructible >) __host__ __device__ constexpr bool check_swap_23(T x, T y) { expected > const e{y, x}; cuda::std::ranges::swap(x, y); return x == e.x && y == e.y; } // clang-format on __host__ __device__ constexpr bool check_lvalue_adl_swappable() { auto x = lvalue_adl_swappable(0); auto y = lvalue_adl_swappable(1); static_assert(noexcept(cuda::std::ranges::swap(x, y))); assert(check_swap_21(x, y)); return true; } __host__ __device__ constexpr bool check_rvalue_adl_swappable() { static_assert(noexcept(cuda::std::ranges::swap(rvalue_adl_swappable(0), rvalue_adl_swappable(1)))); #if !TEST_COMPILER(GCC, <, 10) assert(check_swap_21(rvalue_adl_swappable(0), rvalue_adl_swappable(1))); #endif // !TEST_COMPILER(GCC, <, 10) return true; } __host__ __device__ constexpr bool check_lvalue_rvalue_adl_swappable() { auto x = lvalue_rvalue_adl_swappable(0); static_assert(noexcept(cuda::std::ranges::swap(x, lvalue_rvalue_adl_swappable(1)))); assert(check_swap_21(x, lvalue_rvalue_adl_swappable(1))); return true; } __host__ __device__ constexpr bool check_rvalue_lvalue_adl_swappable() { auto x = rvalue_lvalue_adl_swappable(0); static_assert(noexcept(cuda::std::ranges::swap(rvalue_lvalue_adl_swappable(1), x))); assert(check_swap_21(rvalue_lvalue_adl_swappable(1), x)); return true; } __host__ __device__ constexpr bool check_throwable_swappable() { auto x = throwable_adl_swappable{0}; auto y = throwable_adl_swappable{1}; #if !TEST_COMPILER(NVHPC) static_assert(!noexcept(cuda::std::ranges::swap(x, y))); #endif // !TEST_COMPILER(NVHPC) assert(check_swap_21(x, y)); return true; } __host__ __device__ constexpr bool check_non_move_constructible_adl_swappable() { auto x = non_move_constructible_adl_swappable{0}; auto y = non_move_constructible_adl_swappable{1}; static_assert(noexcept(cuda::std::ranges::swap(x, y))); assert(check_swap_21(x, y)); return true; } __host__ __device__ constexpr bool check_non_move_assignable_adl_swappable() { auto x = non_move_assignable_adl_swappable{0}; auto y = non_move_assignable_adl_swappable{1}; static_assert(noexcept(cuda::std::ranges::swap(x, y))); assert(check_swap_21(x, y)); return true; } namespace swappable_namespace { enum unscoped { hello, world }; __host__ __device__ void swap(unscoped&, unscoped&); enum class scoped { hello, world }; __host__ __device__ void swap(scoped&, scoped&); } // namespace swappable_namespace static_assert(swappable, ""); static_assert(swappable, ""); __host__ __device__ constexpr bool check_swap_arrays() { int x[] = {0, 1, 2, 3, 4}; int y[] = {5, 6, 7, 8, 9}; static_assert(noexcept(cuda::std::ranges::swap(x, y))); assert(check_swap_22(x, y)); return true; } __host__ __device__ constexpr bool check_lvalue_adl_swappable_arrays() { lvalue_adl_swappable x[] = {{0}, {1}, {2}, {3}}; lvalue_adl_swappable y[] = {{4}, {5}, {6}, {7}}; static_assert(noexcept(cuda::std::ranges::swap(x, y))); assert(check_swap_22(x, y)); return true; } __host__ __device__ constexpr bool check_throwable_adl_swappable_arrays() { throwable_adl_swappable x[] = {{0}, {1}, {2}, {3}}; throwable_adl_swappable y[] = {{4}, {5}, {6}, {7}}; #if !TEST_COMPILER(NVHPC) static_assert(!noexcept(cuda::std::ranges::swap(x, y))); #endif // !TEST_COMPILER(NVHPC) assert(check_swap_22(x, y)); return true; } __device__ auto global_x = 0; static_assert(noexcept(cuda::std::ranges::swap(global_x, global_x))); static_assert(check_swap_23(0, 0), ""); static_assert(check_swap_23(0, 1), ""); static_assert(check_swap_23(1, 0), ""); __host__ __device__ constexpr bool check_swappable_references() { int x = 42; int y = 64; static_assert(noexcept(cuda::std::ranges::swap(x, y))); assert(check_swap_23(x, y)); return true; } __host__ __device__ constexpr bool check_swappable_pointers() { char const* x = "hello"; static_assert(noexcept(cuda::std::ranges::swap(x, x))); assert(check_swap_23(x, {})); return true; } namespace union_swap { union adl_swappable { int x; double y; }; __host__ __device__ void swap(adl_swappable&, adl_swappable&); __host__ __device__ void swap(adl_swappable&&, adl_swappable&&); } // namespace union_swap static_assert(swappable, ""); static_assert(swappable, ""); static_assert(swappable, ""); // All tests for swappable are implicitly confirmed by `check_swap`, so we only need to // sanity check for a few positive cases. static_assert(swappable, ""); static_assert(swappable, ""); static_assert(swappable, ""); static_assert(swappable, ""); static_assert(swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); static_assert(!swappable, ""); using swap_type = cuda::std::remove_const_t; static_assert(cuda::std::default_initializable, ""); static_assert(cuda::std::move_constructible, ""); static_assert(cuda::std::copy_constructible, ""); static_assert(cuda::std::assignable_from, ""); static_assert(cuda::std::assignable_from, ""); static_assert(cuda::std::assignable_from, ""); static_assert(cuda::std::assignable_from, ""); static_assert(swappable, ""); int main(int, char**) { assert(check_lvalue_adl_swappable()); #if !TEST_COMPILER(GCC, <, 10) assert(check_rvalue_adl_swappable()); #endif // !TEST_COMPILER(GCC, <, 10) assert(check_lvalue_rvalue_adl_swappable()); assert(check_rvalue_lvalue_adl_swappable()); assert(check_throwable_swappable()); assert(check_non_move_constructible_adl_swappable()); assert(check_non_move_assignable_adl_swappable()); assert(check_swap_arrays()); assert(check_lvalue_adl_swappable_arrays()); assert(check_throwable_adl_swappable_arrays()); assert(check_swappable_references()); assert(check_swappable_pointers()); #if !TEST_COMPILER(GCC, <, 10) static_assert(check_lvalue_adl_swappable(), ""); static_assert(check_rvalue_adl_swappable(), ""); static_assert(check_lvalue_rvalue_adl_swappable(), ""); static_assert(check_rvalue_lvalue_adl_swappable(), ""); static_assert(check_throwable_swappable(), ""); static_assert(check_non_move_constructible_adl_swappable(), ""); static_assert(check_non_move_assignable_adl_swappable(), ""); static_assert(check_swap_arrays(), ""); static_assert(check_lvalue_adl_swappable_arrays(), ""); static_assert(check_throwable_adl_swappable_arrays(), ""); static_assert(check_swappable_references(), ""); static_assert(check_swappable_pointers(), ""); #endif // !TEST_COMPILER(GCC, <, 10) return 0; }