//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// <copyable-box>& operator=(<copyable-box> const&)
// ADDITIONAL_COMPILE_FLAGS: -Wno-self-assign-overloaded
#include <ranges>
#include <cassert>
#include <type_traits>
#include <utility> // in_place_t
#include "test_macros.h"
#include "types.h"
constexpr bool test() {
// Test the primary template
{
using Box = std::ranges::__movable_box<CopyConstructible>;
static_assert(std::is_copy_assignable_v<Box>);
static_assert(!std::is_nothrow_copy_assignable_v<Box>);
{
Box x(std::in_place, 5);
Box const y(std::in_place, 10);
Box& result = (x = y);
assert(&result == &x);
assert(x.__has_value());
assert(y.__has_value());
assert((*x).value == 10);
}
// check self-assignment
{
Box x(std::in_place, 5);
Box& result = (x = x);
assert(&result == &x);
assert(x.__has_value());
assert((*x).value == 5);
}
}
// Test optimization #1 for copy-assignment
{
using Box = std::ranges::__movable_box<Copyable>;
static_assert(std::is_copy_assignable_v<Box>);
static_assert(!std::is_nothrow_copy_assignable_v<Box>);
{
Box x(std::in_place, 5);
Box const y(std::in_place, 10);
Box& result = (x = y);
assert(&result == &x);
assert(x.__has_value());
assert(y.__has_value());
assert((*x).value == 10);
assert((*x).did_copy_assign);
}
// check self-assignment (should use the underlying type's assignment too)
{
Box x(std::in_place, 5);
Box& result = (x = x);
assert(&result == &x);
assert(x.__has_value());
assert((*x).value == 5);
assert((*x).did_copy_assign);
}
}
// Test optimization #2 for copy-assignment
{
using Box = std::ranges::__movable_box<NothrowCopyConstructible>;
static_assert(std::is_copy_assignable_v<Box>);
static_assert(std::is_nothrow_copy_assignable_v<Box>);
{
Box x(std::in_place, 5);
Box const y(std::in_place, 10);
Box& result = (x = y);
assert(&result == &x);
assert(x.__has_value());
assert(y.__has_value());
assert((*x).value == 10);
}
// check self-assignment
{
Box x(std::in_place, 5);
Box& result = (x = x);
assert(&result == &x);
assert(x.__has_value());
assert((*x).value == 5);
}
}
return true;
}
// Tests for the empty state. Those can't be constexpr, since they are only reached
// through throwing an exception.
#if !defined(TEST_HAS_NO_EXCEPTIONS)
void test_empty_state() {
using Box = std::ranges::__movable_box<ThrowsOnCopy>;
// assign non-empty to empty
{
Box x = create_empty_box();
Box const y(std::in_place, 10);
Box& result = (x = y);
assert(&result == &x);
assert(x.__has_value());
assert(y.__has_value());
assert((*x).value == 10);
}
// assign empty to non-empty
{
Box x(std::in_place, 5);
Box const y = create_empty_box();
Box& result = (x = y);
assert(&result == &x);
assert(!x.__has_value());
assert(!y.__has_value());
}
// assign empty to empty
{
Box x = create_empty_box();
Box const y = create_empty_box();
Box& result = (x = y);
assert(&result == &x);
assert(!x.__has_value());
assert(!y.__has_value());
}
// check self-assignment in empty case
{
Box x = create_empty_box();
Box& result = (x = x);
assert(&result == &x);
assert(!x.__has_value());
}
}
#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
int main(int, char**) {
assert(test());
static_assert(test());
#if !defined(TEST_HAS_NO_EXCEPTIONS)
test_empty_state();
#endif
return 0;
}