//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef TEST_SUPPORT_TYPE_CLASSIFICATION_SWAPPABLE_H
#define TEST_SUPPORT_TYPE_CLASSIFICATION_SWAPPABLE_H
#include <concepts>
// `adl_swappable` indicates it's been swapped using ADL by maintaining a pointer to itself that
// isn't a part of the exchange. This is well-formed since we say that two `adl_swappable` objects
// are equal only if their respective `value` subobjects are equal and their respective `this`
// subobjects store the addresses of those respective `adl_swappable` objects.
class lvalue_adl_swappable {
public:
lvalue_adl_swappable() = default;
constexpr lvalue_adl_swappable(int value) noexcept : value_(value) {}
constexpr lvalue_adl_swappable(lvalue_adl_swappable&& other) noexcept
: value_(std::move(other.value_)),
this_(this) {}
constexpr lvalue_adl_swappable(lvalue_adl_swappable const& other) noexcept
: value_(other.value_),
this_(this) {}
constexpr lvalue_adl_swappable&
operator=(lvalue_adl_swappable other) noexcept {
value_ = other.value_;
return *this;
}
friend constexpr void swap(lvalue_adl_swappable& x,
lvalue_adl_swappable& y) noexcept {
std::ranges::swap(x.value_, y.value_);
}
constexpr bool operator==(lvalue_adl_swappable const& other) const noexcept {
return value_ == other.value_ && this_ == this && other.this_ == &other;
}
private:
int value_{};
lvalue_adl_swappable* this_ = this;
};
class lvalue_rvalue_adl_swappable {
public:
lvalue_rvalue_adl_swappable() = default;
constexpr lvalue_rvalue_adl_swappable(int value) noexcept : value_(value) {}
constexpr
lvalue_rvalue_adl_swappable(lvalue_rvalue_adl_swappable&& other) noexcept
: value_(std::move(other.value_)),
this_(this) {}
constexpr
lvalue_rvalue_adl_swappable(lvalue_rvalue_adl_swappable const& other) noexcept
: value_(other.value_),
this_(this) {}
constexpr lvalue_rvalue_adl_swappable&
operator=(lvalue_rvalue_adl_swappable other) noexcept {
value_ = other.value_;
return *this;
}
friend constexpr void swap(lvalue_rvalue_adl_swappable& x,
lvalue_rvalue_adl_swappable&& y) noexcept {
std::ranges::swap(x.value_, y.value_);
}
constexpr bool
operator==(lvalue_rvalue_adl_swappable const& other) const noexcept {
return value_ == other.value_ && this_ == this && other.this_ == &other;
}
private:
int value_{};
lvalue_rvalue_adl_swappable* this_ = this;
};
class rvalue_lvalue_adl_swappable {
public:
rvalue_lvalue_adl_swappable() = default;
constexpr rvalue_lvalue_adl_swappable(int value) noexcept : value_(value) {}
constexpr
rvalue_lvalue_adl_swappable(rvalue_lvalue_adl_swappable&& other) noexcept
: value_(std::move(other.value_)),
this_(this) {}
constexpr
rvalue_lvalue_adl_swappable(rvalue_lvalue_adl_swappable const& other) noexcept
: value_(other.value_),
this_(this) {}
constexpr rvalue_lvalue_adl_swappable&
operator=(rvalue_lvalue_adl_swappable other) noexcept {
value_ = other.value_;
return *this;
}
friend constexpr void swap(rvalue_lvalue_adl_swappable&& x,
rvalue_lvalue_adl_swappable& y) noexcept {
std::ranges::swap(x.value_, y.value_);
}
constexpr bool
operator==(rvalue_lvalue_adl_swappable const& other) const noexcept {
return value_ == other.value_ && this_ == this && other.this_ == &other;
}
private:
int value_{};
rvalue_lvalue_adl_swappable* this_ = this;
};
class rvalue_adl_swappable {
public:
rvalue_adl_swappable() = default;
constexpr rvalue_adl_swappable(int value) noexcept : value_(value) {}
constexpr rvalue_adl_swappable(rvalue_adl_swappable&& other) noexcept
: value_(std::move(other.value_)),
this_(this) {}
constexpr rvalue_adl_swappable(rvalue_adl_swappable const& other) noexcept
: value_(other.value_),
this_(this) {}
constexpr rvalue_adl_swappable&
operator=(rvalue_adl_swappable other) noexcept {
value_ = other.value_;
return *this;
}
friend constexpr void swap(rvalue_adl_swappable&& x,
rvalue_adl_swappable&& y) noexcept {
std::ranges::swap(x.value_, y.value_);
}
constexpr bool operator==(rvalue_adl_swappable const& other) const noexcept {
return value_ == other.value_ && this_ == this && other.this_ == &other;
}
private:
int value_{};
rvalue_adl_swappable* this_ = this;
};
class non_move_constructible_adl_swappable {
public:
non_move_constructible_adl_swappable() = default;
constexpr non_move_constructible_adl_swappable(int value) noexcept
: value_(value) {}
constexpr non_move_constructible_adl_swappable(
non_move_constructible_adl_swappable&& other) noexcept
: value_(std::move(other.value_)),
this_(this) {}
constexpr non_move_constructible_adl_swappable(
non_move_constructible_adl_swappable const& other) noexcept
: value_(other.value_),
this_(this) {}
constexpr non_move_constructible_adl_swappable&
operator=(non_move_constructible_adl_swappable other) noexcept {
value_ = other.value_;
return *this;
}
friend constexpr void swap(non_move_constructible_adl_swappable& x,
non_move_constructible_adl_swappable& y) noexcept {
std::ranges::swap(x.value_, y.value_);
}
constexpr bool
operator==(non_move_constructible_adl_swappable const& other) const noexcept {
return value_ == other.value_ && this_ == this && other.this_ == &other;
}
private:
int value_{};
non_move_constructible_adl_swappable* this_ = this;
};
class non_move_assignable_adl_swappable {
public:
non_move_assignable_adl_swappable() = default;
constexpr non_move_assignable_adl_swappable(int value) noexcept
: value_(value) {}
non_move_assignable_adl_swappable(non_move_assignable_adl_swappable&& other) =
delete;
constexpr non_move_assignable_adl_swappable(
non_move_assignable_adl_swappable const& other) noexcept
: value_(other.value_),
this_(this) {}
constexpr non_move_assignable_adl_swappable&
operator=(non_move_assignable_adl_swappable&& other) noexcept = delete;
friend constexpr void swap(non_move_assignable_adl_swappable& x,
non_move_assignable_adl_swappable& y) noexcept {
std::ranges::swap(x.value_, y.value_);
}
constexpr bool
operator==(non_move_assignable_adl_swappable const& other) const noexcept {
return value_ == other.value_ && this_ == this && other.this_ == &other;
}
private:
int value_{};
non_move_assignable_adl_swappable* this_ = this;
};
class throwable_adl_swappable {
public:
throwable_adl_swappable() = default;
constexpr throwable_adl_swappable(int value) noexcept : value_(value) {}
constexpr throwable_adl_swappable(throwable_adl_swappable&& other) noexcept
: value_(std::move(other.value_)),
this_(this) {}
constexpr
throwable_adl_swappable(throwable_adl_swappable const& other) noexcept
: value_(other.value_),
this_(this) {}
constexpr throwable_adl_swappable&
operator=(throwable_adl_swappable other) noexcept {
value_ = other.value_;
return *this;
}
friend constexpr void swap(throwable_adl_swappable& X,
throwable_adl_swappable& Y) noexcept(false) {
std::ranges::swap(X.value_, Y.value_);
}
constexpr bool
operator==(throwable_adl_swappable const& other) const noexcept {
return value_ == other.value_ && this_ == this && other.this_ == &other;
}
private:
int value_{};
throwable_adl_swappable* this_ = this;
};
#endif // TEST_SUPPORT_TYPE_CLASSIFICATION_SWAPPABLE_H