1 // Copyright (C) 2013-2020 Free Software Foundation, Inc. 2 // 3 // This file is part of the GNU ISO C++ Library. This library is free 4 // software; you can redistribute it and/or modify it under the 5 // terms of the GNU General Public License as published by the 6 // Free Software Foundation; either version 3, or (at your option) 7 // any later version. 8 9 // This library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 14 // You should have received a copy of the GNU General Public License along 15 // with this library; see the file COPYING3. If not see 16 // <http://www.gnu.org/licenses/>. 17 18 namespace assign_2 { 19 20 struct exception {}; 21 22 int counter = 0; 23 24 struct mixin_counter 25 { 26 mixin_counter() { ++counter; } 27 mixin_counter(mixin_counter const&) { ++counter; } 28 ~mixin_counter() { --counter; } 29 }; 30 31 struct value_type : private mixin_counter 32 { 33 enum state_type 34 { 35 zero, 36 moved_from, 37 throwing_construction, 38 throwing_copy, 39 throwing_copy_assignment, 40 throwing_move, 41 throwing_move_assignment, 42 threw, 43 }; 44 45 value_type() = default; 46 47 explicit value_type(state_type state_) 48 : state(state_) 49 { 50 throw_if(throwing_construction); 51 } 52 53 value_type(value_type const& other) 54 : state(other.state) 55 { 56 throw_if(throwing_copy); 57 } 58 59 value_type& 60 operator=(value_type const& other) 61 { 62 state = other.state; 63 throw_if(throwing_copy_assignment); 64 return *this; 65 } 66 67 value_type(value_type&& other) 68 : state(other.state) 69 { 70 other.state = moved_from; 71 throw_if(throwing_move); 72 } 73 74 value_type& 75 operator=(value_type&& other) 76 { 77 state = other.state; 78 other.state = moved_from; 79 throw_if(throwing_move_assignment); 80 return *this; 81 } 82 83 void throw_if(state_type match) 84 { 85 if(state == match) 86 { 87 state = threw; 88 throw exception {}; 89 } 90 } 91 92 state_type state = zero; 93 }; 94 95 static void 96 test () 97 { 98 using O = gdb::optional<value_type>; 99 using S = value_type::state_type; 100 auto const make = [](S s = S::zero) { return O { gdb::in_place, s }; }; 101 102 enum outcome_type { nothrow, caught, bad_catch }; 103 104 // Check copy/move assignment for engaged optional 105 106 // From disengaged optional 107 { 108 O o = make(S::zero); 109 VERIFY( o ); 110 O p; 111 o = p; 112 VERIFY( !o ); 113 VERIFY( !p ); 114 } 115 116 { 117 O o = make(S::zero); 118 VERIFY( o ); 119 O p; 120 o = std::move(p); 121 VERIFY( !o ); 122 VERIFY( !p ); 123 } 124 125 #ifndef GDB_OPTIONAL 126 { 127 O o = make(S::zero); 128 VERIFY( o ); 129 o = {}; 130 VERIFY( !o ); 131 } 132 #endif 133 134 // From engaged optional 135 { 136 O o = make(S::zero); 137 VERIFY( o ); 138 O p = make(S::throwing_copy); 139 o = p; 140 VERIFY( o && o->state == S::throwing_copy); 141 VERIFY( p && p->state == S::throwing_copy); 142 } 143 144 { 145 O o = make(S::zero); 146 VERIFY( o ); 147 O p = make(S::throwing_move); 148 o = std::move(p); 149 VERIFY( o && o->state == S::throwing_move); 150 VERIFY( p && p->state == S::moved_from); 151 } 152 153 { 154 ATTRIBUTE_UNUSED outcome_type outcome {}; 155 O o = make(S::zero); 156 VERIFY( o ); 157 O p = make(S::throwing_copy_assignment); 158 159 try 160 { 161 o = p; 162 } 163 catch(exception const&) 164 { outcome = caught; } 165 catch(...) 166 { outcome = bad_catch; } 167 168 VERIFY( o && o->state == S::threw); 169 VERIFY( p && p->state == S::throwing_copy_assignment); 170 } 171 172 { 173 ATTRIBUTE_UNUSED outcome_type outcome {}; 174 O o = make(S::zero); 175 VERIFY( o ); 176 O p = make(S::throwing_move_assignment); 177 178 try 179 { 180 o = std::move(p); 181 } 182 catch(exception const&) 183 { outcome = caught; } 184 catch(...) 185 { outcome = bad_catch; } 186 187 VERIFY( o && o->state == S::threw); 188 VERIFY( p && p->state == S::moved_from); 189 } 190 191 VERIFY( counter == 0 ); 192 } 193 194 } // namespace assign_2 195