brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.1 KiB · ee82835 Raw
308 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// UNSUPPORTED: c++03, c++11, c++14, c++1710 11// template<class T>12// concept swappable = // see below13 14#include <concepts>15 16#include <algorithm>17#include <cassert>18#include <deque>19#include <map>20#include <memory>21#include <string>22#include <optional>23#include <unordered_map>24#include <vector>25 26#include "test_macros.h"27#include "type_classification/moveconstructible.h"28#include "type_classification/swappable.h"29 30template <class T>31struct expected {32  T x;33  T y;34};35 36// clang-format off37// Checks [concept.swappable]/2.138template <class T, class U>39requires std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<U> > &&40         std::swappable<std::remove_cvref_t<T> >41constexpr bool check_swap_21(T&& x, U&& y) {42  expected<std::remove_cvref_t<T> > const e{y, x};43  std::ranges::swap(std::forward<T>(x), std::forward<U>(y));44  return x == e.x && y == e.y;45}46 47// Checks [concept.swappable]/2.248template <std::swappable T, std::size_t N>49constexpr bool check_swap_22(T (&x)[N], T (&y)[N]) {50  expected<T[N]> e;51  std::copy(y, y + N, e.x);52  std::copy(x, x + N, e.y);53 54  std::ranges::swap(x, y);55  return std::equal(x, x + N, e.x, e.x + N) &&56         std::equal(y, y + N, e.y, e.y + N);57}58 59// Checks [concept.swappable]/2.360template <std::swappable T>61requires std::copy_constructible<std::remove_cvref_t<T> >62constexpr bool check_swap_23(T x, T y) {63  expected<std::remove_cvref_t<T> > const e{y, x};64  std::ranges::swap(x, y);65  return x == e.x && y == e.y;66}67// clang-format on68 69constexpr bool check_lvalue_adl_swappable() {70  auto x = lvalue_adl_swappable(0);71  auto y = lvalue_adl_swappable(1);72  ASSERT_NOEXCEPT(std::ranges::swap(x, y));73  assert(check_swap_21(x, y));74  return true;75}76static_assert(check_lvalue_adl_swappable());77 78constexpr bool check_rvalue_adl_swappable() {79  ASSERT_NOEXCEPT(std::ranges::swap(rvalue_adl_swappable(0), rvalue_adl_swappable(1)));80  assert(check_swap_21(rvalue_adl_swappable(0), rvalue_adl_swappable(1)));81  return true;82}83static_assert(check_rvalue_adl_swappable());84 85constexpr bool check_lvalue_rvalue_adl_swappable() {86  auto x = lvalue_rvalue_adl_swappable(0);87  ASSERT_NOEXCEPT(std::ranges::swap(x, lvalue_rvalue_adl_swappable(1)));88  assert(check_swap_21(x, lvalue_rvalue_adl_swappable(1)));89  return true;90}91static_assert(check_lvalue_rvalue_adl_swappable());92 93constexpr bool check_rvalue_lvalue_adl_swappable() {94  auto x = rvalue_lvalue_adl_swappable(0);95  ASSERT_NOEXCEPT(std::ranges::swap(rvalue_lvalue_adl_swappable(1), x));96  assert(check_swap_21(rvalue_lvalue_adl_swappable(1), x));97  return true;98}99static_assert(check_rvalue_lvalue_adl_swappable());100 101constexpr bool check_throwable_swappable() {102  auto x = throwable_adl_swappable{0};103  auto y = throwable_adl_swappable{1};104  ASSERT_NOT_NOEXCEPT(std::ranges::swap(x, y));105  assert(check_swap_21(x, y));106  return true;107}108static_assert(check_throwable_swappable());109 110constexpr bool check_non_move_constructible_adl_swappable() {111  auto x = non_move_constructible_adl_swappable{0};112  auto y = non_move_constructible_adl_swappable{1};113  ASSERT_NOEXCEPT(std::ranges::swap(x, y));114  assert(check_swap_21(x, y));115  return true;116}117static_assert(check_non_move_constructible_adl_swappable());118 119constexpr bool check_non_move_assignable_adl_swappable() {120  auto x = non_move_assignable_adl_swappable{0};121  auto y = non_move_assignable_adl_swappable{1};122  ASSERT_NOEXCEPT(std::ranges::swap(x, y));123  assert(check_swap_21(x, y));124  return true;125}126static_assert(check_non_move_assignable_adl_swappable());127 128namespace swappable_namespace {129enum unscoped { hello, world };130void swap(unscoped&, unscoped&);131 132enum class scoped { hello, world };133void swap(scoped&, scoped&);134} // namespace swappable_namespace135 136static_assert(std::swappable<swappable_namespace::unscoped>);137static_assert(std::swappable<swappable_namespace::scoped>);138 139constexpr bool check_swap_arrays() {140  int x[] = {0, 1, 2, 3, 4};141  int y[] = {5, 6, 7, 8, 9};142  ASSERT_NOEXCEPT(std::ranges::swap(x, y));143  assert(check_swap_22(x, y));144  return true;145}146static_assert(check_swap_arrays());147 148constexpr bool check_lvalue_adl_swappable_arrays() {149  lvalue_adl_swappable x[] = {{0}, {1}, {2}, {3}};150  lvalue_adl_swappable y[] = {{4}, {5}, {6}, {7}};151  ASSERT_NOEXCEPT(std::ranges::swap(x, y));152  assert(check_swap_22(x, y));153  return true;154}155static_assert(check_lvalue_adl_swappable_arrays());156 157constexpr bool check_throwable_adl_swappable_arrays() {158  throwable_adl_swappable x[] = {{0}, {1}, {2}, {3}};159  throwable_adl_swappable y[] = {{4}, {5}, {6}, {7}};160  ASSERT_NOT_NOEXCEPT(std::ranges::swap(x, y));161  assert(check_swap_22(x, y));162  return true;163}164static_assert(check_throwable_adl_swappable_arrays());165 166auto global_x = 0;167ASSERT_NOEXCEPT(std::ranges::swap(global_x, global_x));168static_assert(check_swap_23(0, 0));169static_assert(check_swap_23(0, 1));170static_assert(check_swap_23(1, 0));171 172constexpr bool check_swappable_references() {173  int x = 42;174  int y = 64;175  ASSERT_NOEXCEPT(std::ranges::swap(x, y));176  assert(check_swap_23(x, y));177  return true;178}179static_assert(check_swappable_references());180 181constexpr bool check_swappable_pointers() {182  char const* x = "hello";183  ASSERT_NOEXCEPT(std::ranges::swap(x, x));184  assert(check_swap_23(x, {}));185  return true;186}187static_assert(check_swappable_pointers());188 189namespace union_swap {190union adl_swappable {191  int x;192  double y;193};194 195void swap(adl_swappable&, adl_swappable&);196void swap(adl_swappable&&, adl_swappable&&);197} // namespace union_swap198static_assert(std::swappable<union_swap::adl_swappable>);199static_assert(std::swappable<union_swap::adl_swappable&>);200static_assert(std::swappable<union_swap::adl_swappable&&>);201 202// All tests for std::swappable<T> are implicitly confirmed by `check_swap`, so we only need to203// sanity check for a few positive cases.204static_assert(std::swappable<int volatile&>);205static_assert(std::swappable<int&&>);206static_assert(std::swappable<int (*)()>);207static_assert(std::swappable<int rvalue_adl_swappable::*>);208static_assert(std::swappable<int (rvalue_adl_swappable::*)()>);209static_assert(std::swappable<std::unique_ptr<int> >);210 211static_assert(!std::swappable<void>);212static_assert(!std::swappable<int const>);213static_assert(!std::swappable<int const&>);214static_assert(!std::swappable<int const&&>);215static_assert(!std::swappable<int const volatile>);216static_assert(!std::swappable<int const volatile&>);217static_assert(!std::swappable<int const volatile&&>);218static_assert(!std::swappable<int (&)()>);219static_assert(!std::swappable<DeletedMoveCtor>);220static_assert(!std::swappable<ImplicitlyDeletedMoveCtor>);221static_assert(!std::swappable<DeletedMoveAssign>);222static_assert(!std::swappable<ImplicitlyDeletedMoveAssign>);223static_assert(!std::swappable<NonMovable>);224static_assert(!std::swappable<DerivedFromNonMovable>);225static_assert(!std::swappable<HasANonMovable>);226 227using swap_type = std::remove_const_t<decltype(std::ranges::swap)>;228static_assert(std::default_initializable<swap_type>);229static_assert(std::move_constructible<swap_type>);230static_assert(std::copy_constructible<swap_type>);231static_assert(std::assignable_from<swap_type&, swap_type>);232static_assert(std::assignable_from<swap_type&, swap_type&>);233static_assert(std::assignable_from<swap_type&, swap_type const&>);234static_assert(std::assignable_from<swap_type&, swap_type const>);235static_assert(std::swappable<swap_type>);236 237enum class nothrow { no, yes };238 239template <nothrow is_noexcept, std::swappable T>240void check_swap(expected<T> const& e) {241  auto a = e.y;242  auto b = e.x;243 244  std::ranges::swap(a, b);245  assert(a == e.x);246  assert(b == e.y);247 248  std::ranges::swap(a, b);249  assert(a == e.y);250  assert(b == e.x);251 252  static_assert(noexcept(std::ranges::swap(a, b)) == bool(is_noexcept));253}254 255int main(int, char**) {256  {257    auto const e = expected<std::deque<int> >{258        .x = {6, 7, 8, 9},259        .y = {0, 1, 2, 3, 4, 5},260    };261    check_swap<nothrow::yes>(e);262  }263  {264    auto const e = expected<std::map<int, std::string> >{265        .x = {{0, "whole"}, {1, "cashews"}},266        .y = {{-1, "roasted"}, {2, "&"}, {-3, "salted"}},267    };268    check_swap<nothrow::yes>(e);269  }270  {271    auto const e = expected<std::string>{272        .x = "hello there",273        .y = "general kenobi",274    };275    check_swap<nothrow::yes>(e);276  }277  {278    auto const e = expected<std::optional<lvalue_adl_swappable> >{279        .x = {10},280        .y = {20},281    };282    check_swap<nothrow::yes>(e);283  }284  {285    auto const e = expected<std::optional<throwable_adl_swappable> >{286        .x = {10},287        .y = {20},288    };289    check_swap<nothrow::no>(e);290  }291  {292    auto const e = expected<std::unordered_map<int, std::string> >{293        .x = {{0, "whole"}, {1, "cashews"}},294        .y = {{-1, "roasted"}, {2, "&"}, {-3, "salted"}},295    };296    check_swap<nothrow::yes>(e);297  }298  {299    auto const e = expected<std::vector<int> >{300        .x = {0, 1, 2, 3, 4, 5},301        .y = {6, 7, 8, 9},302    };303 304    check_swap<nothrow::yes>(e);305  }306  return 0;307}308