forked from mirror/libcxx
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
255 lines
6.7 KiB
C++
255 lines
6.7 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is dual licensed under the MIT and the University of Illinois Open
|
|
// Source Licenses. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// UNSUPPORTED: c++98, c++03, c++11, c++14
|
|
// <optional>
|
|
|
|
// From LWG2451:
|
|
// template<class U>
|
|
// optional<T>& operator=(const optional<U>& rhs);
|
|
|
|
#include <optional>
|
|
#include <type_traits>
|
|
#include <cassert>
|
|
|
|
#include "test_macros.h"
|
|
#include "archetypes.hpp"
|
|
|
|
using std::optional;
|
|
|
|
struct X
|
|
{
|
|
static bool throw_now;
|
|
|
|
X() = default;
|
|
X(int)
|
|
{
|
|
if (throw_now)
|
|
TEST_THROW(6);
|
|
}
|
|
};
|
|
|
|
bool X::throw_now = false;
|
|
|
|
struct Y1
|
|
{
|
|
Y1() = default;
|
|
Y1(const int&) {}
|
|
Y1& operator=(const Y1&) = delete;
|
|
};
|
|
|
|
struct Y2
|
|
{
|
|
Y2() = default;
|
|
Y2(const int&) = delete;
|
|
Y2& operator=(const int&) { return *this; }
|
|
};
|
|
|
|
template <class T>
|
|
struct AssignableFrom {
|
|
static int type_constructed;
|
|
static int type_assigned;
|
|
static int int_constructed;
|
|
static int int_assigned;
|
|
|
|
static void reset() {
|
|
type_constructed = int_constructed = 0;
|
|
type_assigned = int_assigned = 0;
|
|
}
|
|
|
|
AssignableFrom() = default;
|
|
|
|
explicit AssignableFrom(T) { ++type_constructed; }
|
|
AssignableFrom& operator=(T) { ++type_assigned; return *this; }
|
|
|
|
AssignableFrom(int) { ++int_constructed; }
|
|
AssignableFrom& operator=(int) { ++int_assigned; return *this; }
|
|
private:
|
|
AssignableFrom(AssignableFrom const&) = delete;
|
|
AssignableFrom& operator=(AssignableFrom const&) = delete;
|
|
};
|
|
|
|
template <class T> int AssignableFrom<T>::type_constructed = 0;
|
|
template <class T> int AssignableFrom<T>::type_assigned = 0;
|
|
template <class T> int AssignableFrom<T>::int_constructed = 0;
|
|
template <class T> int AssignableFrom<T>::int_assigned = 0;
|
|
|
|
|
|
void test_with_test_type() {
|
|
using T = TestTypes::TestType;
|
|
T::reset();
|
|
{ // non-empty to empty
|
|
T::reset_constructors();
|
|
optional<T> opt;
|
|
const optional<int> other(42);
|
|
opt = other;
|
|
assert(T::alive == 1);
|
|
assert(T::constructed == 1);
|
|
assert(T::value_constructed == 1);
|
|
assert(T::assigned == 0);
|
|
assert(T::destroyed == 0);
|
|
assert(static_cast<bool>(other) == true);
|
|
assert(*other == 42);
|
|
assert(static_cast<bool>(opt) == true);
|
|
assert(*opt == T(42));
|
|
}
|
|
assert(T::alive == 0);
|
|
{ // non-empty to non-empty
|
|
optional<T> opt(101);
|
|
const optional<int> other(42);
|
|
T::reset_constructors();
|
|
opt = other;
|
|
assert(T::alive == 1);
|
|
assert(T::constructed == 0);
|
|
assert(T::assigned == 1);
|
|
assert(T::value_assigned == 1);
|
|
assert(T::destroyed == 0);
|
|
assert(static_cast<bool>(other) == true);
|
|
assert(*other == 42);
|
|
assert(static_cast<bool>(opt) == true);
|
|
assert(*opt == T(42));
|
|
}
|
|
assert(T::alive == 0);
|
|
{ // empty to non-empty
|
|
optional<T> opt(101);
|
|
const optional<int> other;
|
|
T::reset_constructors();
|
|
opt = other;
|
|
assert(T::alive == 0);
|
|
assert(T::constructed == 0);
|
|
assert(T::assigned == 0);
|
|
assert(T::destroyed == 1);
|
|
assert(static_cast<bool>(other) == false);
|
|
assert(static_cast<bool>(opt) == false);
|
|
}
|
|
assert(T::alive == 0);
|
|
{ // empty to empty
|
|
optional<T> opt;
|
|
const optional<int> other;
|
|
T::reset_constructors();
|
|
opt = other;
|
|
assert(T::alive == 0);
|
|
assert(T::constructed == 0);
|
|
assert(T::assigned == 0);
|
|
assert(T::destroyed == 0);
|
|
assert(static_cast<bool>(other) == false);
|
|
assert(static_cast<bool>(opt) == false);
|
|
}
|
|
assert(T::alive == 0);
|
|
}
|
|
|
|
void test_ambigious_assign() {
|
|
using OptInt = std::optional<int>;
|
|
{
|
|
using T = AssignableFrom<OptInt const&>;
|
|
const OptInt a(42);
|
|
T::reset();
|
|
{
|
|
std::optional<T> t;
|
|
t = a;
|
|
assert(T::type_constructed == 1);
|
|
assert(T::type_assigned == 0);
|
|
assert(T::int_constructed == 0);
|
|
assert(T::int_assigned == 0);
|
|
}
|
|
T::reset();
|
|
{
|
|
std::optional<T> t(42);
|
|
t = a;
|
|
assert(T::type_constructed == 0);
|
|
assert(T::type_assigned == 1);
|
|
assert(T::int_constructed == 1);
|
|
assert(T::int_assigned == 0);
|
|
}
|
|
T::reset();
|
|
{
|
|
std::optional<T> t(42);
|
|
t = std::move(a);
|
|
assert(T::type_constructed == 0);
|
|
assert(T::type_assigned == 1);
|
|
assert(T::int_constructed == 1);
|
|
assert(T::int_assigned == 0);
|
|
}
|
|
}
|
|
{
|
|
using T = AssignableFrom<OptInt&>;
|
|
OptInt a(42);
|
|
T::reset();
|
|
{
|
|
std::optional<T> t;
|
|
t = a;
|
|
assert(T::type_constructed == 1);
|
|
assert(T::type_assigned == 0);
|
|
assert(T::int_constructed == 0);
|
|
assert(T::int_assigned == 0);
|
|
}
|
|
{
|
|
using Opt = std::optional<T>;
|
|
static_assert(!std::is_assignable_v<Opt&, OptInt const&>, "");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int main()
|
|
{
|
|
test_with_test_type();
|
|
test_ambigious_assign();
|
|
{
|
|
optional<int> opt;
|
|
constexpr optional<short> opt2;
|
|
opt = opt2;
|
|
static_assert(static_cast<bool>(opt2) == false, "");
|
|
assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
|
|
}
|
|
{
|
|
optional<int> opt;
|
|
constexpr optional<short> opt2(short{2});
|
|
opt = opt2;
|
|
static_assert(static_cast<bool>(opt2) == true, "");
|
|
static_assert(*opt2 == 2, "");
|
|
assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
|
|
assert(*opt == *opt2);
|
|
}
|
|
{
|
|
optional<int> opt(3);
|
|
constexpr optional<short> opt2;
|
|
opt = opt2;
|
|
static_assert(static_cast<bool>(opt2) == false, "");
|
|
assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
|
|
}
|
|
{
|
|
optional<int> opt(3);
|
|
constexpr optional<short> opt2(short{2});
|
|
opt = opt2;
|
|
static_assert(static_cast<bool>(opt2) == true, "");
|
|
static_assert(*opt2 == 2, "");
|
|
assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
|
|
assert(*opt == *opt2);
|
|
}
|
|
#ifndef TEST_HAS_NO_EXCEPTIONS
|
|
{
|
|
optional<X> opt;
|
|
optional<int> opt2(42);
|
|
assert(static_cast<bool>(opt2) == true);
|
|
try
|
|
{
|
|
X::throw_now = true;
|
|
opt = opt2;
|
|
assert(false);
|
|
}
|
|
catch (int i)
|
|
{
|
|
assert(i == 6);
|
|
assert(static_cast<bool>(opt) == false);
|
|
}
|
|
}
|
|
#endif
|
|
}
|