Home | History | Annotate | Download | only in optional.object.assign
      1 //===----------------------------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 // UNSUPPORTED: c++98, c++03, c++11, c++14
     11 // <optional>
     12 
     13 // template <class U> optional<T>& operator=(U&& v);
     14 
     15 #include <optional>
     16 #include <type_traits>
     17 #include <cassert>
     18 #include <memory>
     19 
     20 #include "test_macros.h"
     21 #include "archetypes.hpp"
     22 
     23 using std::optional;
     24 
     25 struct ThrowAssign {
     26   static int dtor_called;
     27   ThrowAssign() = default;
     28   ThrowAssign(int) { TEST_THROW(42); }
     29   ThrowAssign& operator=(int) {
     30       TEST_THROW(42);
     31   }
     32   ~ThrowAssign() { ++dtor_called; }
     33 };
     34 int ThrowAssign::dtor_called = 0;
     35 
     36 template <class T, class Arg = T, bool Expect = true>
     37 void assert_assignable() {
     38     static_assert(std::is_assignable<optional<T>&, Arg>::value == Expect, "");
     39     static_assert(!std::is_assignable<const optional<T>&, Arg>::value, "");
     40 }
     41 
     42 struct MismatchType {
     43   explicit MismatchType(int) {}
     44   explicit MismatchType(char*) {}
     45   explicit MismatchType(int*) = delete;
     46   MismatchType& operator=(int) { return *this; }
     47   MismatchType& operator=(int*) { return *this; }
     48   MismatchType& operator=(char*) = delete;
     49 };
     50 
     51 struct FromOptionalType {
     52   using Opt = std::optional<FromOptionalType>;
     53   FromOptionalType() = default;
     54   FromOptionalType(FromOptionalType const&) = delete;
     55   template <class Dummy = void>
     56   constexpr FromOptionalType(Opt&) { Dummy::BARK; }
     57   template <class Dummy = void>
     58   constexpr FromOptionalType& operator=(Opt&) { Dummy::BARK; return *this; }
     59 };
     60 
     61 void test_sfinae() {
     62     using I = TestTypes::TestType;
     63     using E = ExplicitTestTypes::TestType;
     64     assert_assignable<int>();
     65     assert_assignable<int, int&>();
     66     assert_assignable<int, int const&>();
     67     // Implicit test type
     68     assert_assignable<I, I const&>();
     69     assert_assignable<I, I&&>();
     70     assert_assignable<I, int>();
     71     assert_assignable<I, void*, false>();
     72     // Explicit test type
     73     assert_assignable<E, E const&>();
     74     assert_assignable<E, E &&>();
     75     assert_assignable<E, int>();
     76     assert_assignable<E, void*, false>();
     77     // Mismatch type
     78     assert_assignable<MismatchType, int>();
     79     assert_assignable<MismatchType, int*, false>();
     80     assert_assignable<MismatchType, char*, false>();
     81     // Type constructible from optional
     82     assert_assignable<FromOptionalType, std::optional<FromOptionalType>&, false>();
     83 }
     84 
     85 void test_with_test_type()
     86 {
     87     using T = TestTypes::TestType;
     88     T::reset();
     89     { // to empty
     90         optional<T> opt;
     91         opt = 3;
     92         assert(T::alive == 1);
     93         assert(T::constructed == 1);
     94         assert(T::value_constructed == 1);
     95         assert(T::assigned == 0);
     96         assert(T::destroyed == 0);
     97         assert(static_cast<bool>(opt) == true);
     98         assert(*opt == T(3));
     99     }
    100     { // to existing
    101         optional<T> opt(42);
    102         T::reset_constructors();
    103         opt = 3;
    104         assert(T::alive == 1);
    105         assert(T::constructed == 0);
    106         assert(T::assigned == 1);
    107         assert(T::value_assigned == 1);
    108         assert(T::destroyed == 0);
    109         assert(static_cast<bool>(opt) == true);
    110         assert(*opt == T(3));
    111     }
    112     { // test default argument
    113         optional<T> opt;
    114         T::reset_constructors();
    115         opt = {1, 2};
    116         assert(T::alive == 1);
    117         assert(T::constructed == 2);
    118         assert(T::value_constructed == 1);
    119         assert(T::move_constructed == 1);
    120         assert(T::assigned == 0);
    121         assert(T::destroyed == 1);
    122         assert(static_cast<bool>(opt) == true);
    123         assert(*opt == T(1, 2));
    124     }
    125     { // test default argument
    126         optional<T> opt(42);
    127         T::reset_constructors();
    128         opt = {1, 2};
    129         assert(T::alive == 1);
    130         assert(T::constructed == 1);
    131         assert(T::value_constructed == 1);
    132         assert(T::assigned == 1);
    133         assert(T::move_assigned == 1);
    134         assert(T::destroyed == 1);
    135         assert(static_cast<bool>(opt) == true);
    136         assert(*opt == T(1, 2));
    137     }
    138     { // test default argument
    139         optional<T> opt;
    140         T::reset_constructors();
    141         opt = {1};
    142         assert(T::alive == 1);
    143         assert(T::constructed == 2);
    144         assert(T::value_constructed == 1);
    145         assert(T::move_constructed == 1);
    146         assert(T::assigned == 0);
    147         assert(T::destroyed == 1);
    148         assert(static_cast<bool>(opt) == true);
    149         assert(*opt == T(1));
    150     }
    151     { // test default argument
    152         optional<T> opt(42);
    153         T::reset_constructors();
    154         opt = {};
    155         assert(static_cast<bool>(opt) == false);
    156         assert(T::alive == 0);
    157         assert(T::constructed == 0);
    158         assert(T::assigned == 0);
    159         assert(T::destroyed == 1);
    160     }
    161 }
    162 
    163 template <class T, class Value = int>
    164 void test_with_type() {
    165     { // to empty
    166         optional<T> opt;
    167         opt = Value(3);
    168         assert(static_cast<bool>(opt) == true);
    169         assert(*opt == T(3));
    170     }
    171     { // to existing
    172         optional<T> opt(Value(42));
    173         opt = Value(3);
    174         assert(static_cast<bool>(opt) == true);
    175         assert(*opt == T(3));
    176     }
    177     { // test const
    178         optional<T> opt(Value(42));
    179         const T t(Value(3));
    180         opt = t;
    181         assert(static_cast<bool>(opt) == true);
    182         assert(*opt == T(3));
    183     }
    184     { // test default argument
    185         optional<T> opt;
    186         opt = {Value(1)};
    187         assert(static_cast<bool>(opt) == true);
    188         assert(*opt == T(1));
    189     }
    190     { // test default argument
    191         optional<T> opt(Value(42));
    192         opt = {};
    193         assert(static_cast<bool>(opt) == false);
    194     }
    195 }
    196 
    197 template <class T>
    198 void test_with_type_multi() {
    199     test_with_type<T>();
    200     { // test default argument
    201         optional<T> opt;
    202         opt = {1, 2};
    203         assert(static_cast<bool>(opt) == true);
    204         assert(*opt == T(1, 2));
    205     }
    206     { // test default argument
    207         optional<T> opt(42);
    208         opt = {1, 2};
    209         assert(static_cast<bool>(opt) == true);
    210         assert(*opt == T(1, 2));
    211     }
    212 }
    213 
    214 void test_throws()
    215 {
    216 #ifndef TEST_HAS_NO_EXCEPTIONS
    217     using T = ThrowAssign;
    218     {
    219         using T = ThrowAssign;
    220         optional<T> opt;
    221         try {
    222             opt = 42;
    223             assert(false);
    224         } catch (int) {}
    225         assert(static_cast<bool>(opt) == false);
    226     }
    227     assert(T::dtor_called == 0);
    228     {
    229         T::dtor_called = 0;
    230         optional<T> opt(std::in_place);
    231         try {
    232             opt = 42;
    233             assert(false);
    234         } catch (int) {}
    235         assert(static_cast<bool>(opt) == true);
    236         assert(T::dtor_called == 0);
    237     }
    238     assert(T::dtor_called == 1);
    239 #endif
    240 }
    241 
    242 enum MyEnum { Zero, One, Two, Three, FortyTwo = 42 };
    243 
    244 using Fn = void(*)();
    245 
    246 int main()
    247 {
    248     test_sfinae();
    249     // Test with instrumented type
    250     test_with_test_type();
    251     // Test with various scalar types
    252     test_with_type<int>();
    253     test_with_type<MyEnum, MyEnum>();
    254     test_with_type<int, MyEnum>();
    255     test_with_type<Fn, Fn>();
    256     // Test types with multi argument constructors
    257     test_with_type_multi<ConstexprTestTypes::TestType>();
    258     test_with_type_multi<TrivialTestTypes::TestType>();
    259     // Test move only types
    260     {
    261         optional<std::unique_ptr<int>> opt;
    262         opt = std::unique_ptr<int>(new int(3));
    263         assert(static_cast<bool>(opt) == true);
    264         assert(**opt == 3);
    265     }
    266     {
    267         optional<std::unique_ptr<int>> opt(std::unique_ptr<int>(new int(2)));
    268         opt = std::unique_ptr<int>(new int(3));
    269         assert(static_cast<bool>(opt) == true);
    270         assert(**opt == 3);
    271     }
    272     test_throws();
    273 }
    274