//===----------------------------------------------------------------------===// // // 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> // template <class T> void swap(optional<T>& x, optional<T>& y) // noexcept(noexcept(x.swap(y))); #include <optional> #include <type_traits> #include <cassert> #include "test_macros.h" #include "archetypes.hpp" using std::optional; class X { int i_; public: static unsigned dtor_called; X(int i) : i_(i) {} X(X&& x) = default; X& operator=(X&&) = default; ~X() {++dtor_called;} friend bool operator==(const X& x, const X& y) {return x.i_ == y.i_;} }; unsigned X::dtor_called = 0; class Y { int i_; public: static unsigned dtor_called; Y(int i) : i_(i) {} Y(Y&&) = default; ~Y() {++dtor_called;} friend constexpr bool operator==(const Y& x, const Y& y) {return x.i_ == y.i_;} friend void swap(Y& x, Y& y) {std::swap(x.i_, y.i_);} }; unsigned Y::dtor_called = 0; class Z { int i_; public: Z(int i) : i_(i) {} Z(Z&&) { TEST_THROW(7);} friend constexpr bool operator==(const Z& x, const Z& y) {return x.i_ == y.i_;} friend void swap(Z&, Z&) { TEST_THROW(6);} }; struct NonSwappable { NonSwappable(NonSwappable const&) = delete; }; void swap(NonSwappable&, NonSwappable&) = delete; void test_swap_sfinae() { using std::optional; { using T = TestTypes::TestType; static_assert(std::is_swappable_v<optional<T>>, ""); } { using T = TestTypes::MoveOnly; static_assert(std::is_swappable_v<optional<T>>, ""); } { using T = TestTypes::Copyable; static_assert(std::is_swappable_v<optional<T>>, ""); } { using T = TestTypes::NoCtors; static_assert(!std::is_swappable_v<optional<T>>, ""); } { using T = NonSwappable; static_assert(!std::is_swappable_v<optional<T>>, ""); } { // Even thought CopyOnly has deleted move operations, those operations // cause optional<CopyOnly> to have implicitly deleted move operations // that decay into copies. using T = TestTypes::CopyOnly; using Opt = optional<T>; T::reset(); Opt L(101), R(42); T::reset_constructors(); std::swap(L, R); assert(L->value == 42); assert(R->value == 101); assert(T::copy_constructed == 1); assert(T::constructed == T::copy_constructed); assert(T::assigned == 2); assert(T::assigned == T::copy_assigned); } } int main() { test_swap_sfinae(); { optional<int> opt1; optional<int> opt2; static_assert(noexcept(swap(opt1, opt2)) == true, ""); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == false); swap(opt1, opt2); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == false); } { optional<int> opt1(1); optional<int> opt2; static_assert(noexcept(swap(opt1, opt2)) == true, ""); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 1); assert(static_cast<bool>(opt2) == false); swap(opt1, opt2); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 1); } { optional<int> opt1; optional<int> opt2(2); static_assert(noexcept(swap(opt1, opt2)) == true, ""); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 2); swap(opt1, opt2); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 2); assert(static_cast<bool>(opt2) == false); } { optional<int> opt1(1); optional<int> opt2(2); static_assert(noexcept(swap(opt1, opt2)) == true, ""); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 1); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 2); swap(opt1, opt2); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 2); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 1); } { optional<X> opt1; optional<X> opt2; static_assert(noexcept(swap(opt1, opt2)) == true, ""); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == false); swap(opt1, opt2); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == false); assert(X::dtor_called == 0); } { optional<X> opt1(1); optional<X> opt2; static_assert(noexcept(swap(opt1, opt2)) == true, ""); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 1); assert(static_cast<bool>(opt2) == false); X::dtor_called = 0; swap(opt1, opt2); assert(X::dtor_called == 1); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 1); } { optional<X> opt1; optional<X> opt2(2); static_assert(noexcept(swap(opt1, opt2)) == true, ""); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 2); X::dtor_called = 0; swap(opt1, opt2); assert(X::dtor_called == 1); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 2); assert(static_cast<bool>(opt2) == false); } { optional<X> opt1(1); optional<X> opt2(2); static_assert(noexcept(swap(opt1, opt2)) == true, ""); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 1); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 2); X::dtor_called = 0; swap(opt1, opt2); assert(X::dtor_called == 1); // from inside std::swap assert(static_cast<bool>(opt1) == true); assert(*opt1 == 2); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 1); } { optional<Y> opt1; optional<Y> opt2; static_assert(noexcept(swap(opt1, opt2)) == false, ""); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == false); swap(opt1, opt2); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == false); assert(Y::dtor_called == 0); } { optional<Y> opt1(1); optional<Y> opt2; static_assert(noexcept(swap(opt1, opt2)) == false, ""); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 1); assert(static_cast<bool>(opt2) == false); Y::dtor_called = 0; swap(opt1, opt2); assert(Y::dtor_called == 1); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 1); } { optional<Y> opt1; optional<Y> opt2(2); static_assert(noexcept(swap(opt1, opt2)) == false, ""); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 2); Y::dtor_called = 0; swap(opt1, opt2); assert(Y::dtor_called == 1); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 2); assert(static_cast<bool>(opt2) == false); } { optional<Y> opt1(1); optional<Y> opt2(2); static_assert(noexcept(swap(opt1, opt2)) == false, ""); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 1); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 2); Y::dtor_called = 0; swap(opt1, opt2); assert(Y::dtor_called == 0); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 2); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 1); } { optional<Z> opt1; optional<Z> opt2; static_assert(noexcept(swap(opt1, opt2)) == false, ""); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == false); swap(opt1, opt2); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == false); } #ifndef TEST_HAS_NO_EXCEPTIONS { optional<Z> opt1; opt1.emplace(1); optional<Z> opt2; static_assert(noexcept(swap(opt1, opt2)) == false, ""); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 1); assert(static_cast<bool>(opt2) == false); try { swap(opt1, opt2); assert(false); } catch (int i) { assert(i == 7); } assert(static_cast<bool>(opt1) == true); assert(*opt1 == 1); assert(static_cast<bool>(opt2) == false); } { optional<Z> opt1; optional<Z> opt2; opt2.emplace(2); static_assert(noexcept(swap(opt1, opt2)) == false, ""); assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 2); try { swap(opt1, opt2); assert(false); } catch (int i) { assert(i == 7); } assert(static_cast<bool>(opt1) == false); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 2); } { optional<Z> opt1; opt1.emplace(1); optional<Z> opt2; opt2.emplace(2); static_assert(noexcept(swap(opt1, opt2)) == false, ""); assert(static_cast<bool>(opt1) == true); assert(*opt1 == 1); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 2); try { swap(opt1, opt2); assert(false); } catch (int i) { assert(i == 6); } assert(static_cast<bool>(opt1) == true); assert(*opt1 == 1); assert(static_cast<bool>(opt2) == true); assert(*opt2 == 2); } #endif // TEST_HAS_NO_EXCEPTIONS }