| // Copyright (C) 2013-2021 Free Software Foundation, Inc. |
| // |
| // This file is part of the GNU ISO C++ Library. This library is free |
| // software; you can redistribute it and/or modify it under the |
| // terms of the GNU General Public License as published by the |
| // Free Software Foundation; either version 3, or (at your option) |
| // any later version. |
| |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| |
| // You should have received a copy of the GNU General Public License along |
| // with this library; see the file COPYING3. If not see |
| // <http://www.gnu.org/licenses/>. |
| |
| namespace assign_1 { |
| |
| struct exception {}; |
| |
| static int counter = 0; |
| |
| struct mixin_counter |
| { |
| mixin_counter() { ++counter; } |
| mixin_counter(mixin_counter const&) { ++counter; } |
| ~mixin_counter() { --counter; } |
| }; |
| |
| struct value_type : private mixin_counter |
| { |
| enum state_type |
| { |
| zero, |
| moved_from, |
| throwing_construction, |
| throwing_copy, |
| throwing_copy_assignment, |
| throwing_move, |
| throwing_move_assignment, |
| threw, |
| }; |
| |
| value_type() = default; |
| |
| explicit value_type(state_type state_) |
| : state(state_) |
| { |
| throw_if(throwing_construction); |
| } |
| |
| value_type(value_type const& other) |
| : state(other.state) |
| { |
| throw_if(throwing_copy); |
| } |
| |
| value_type& |
| operator=(value_type const& other) |
| { |
| state = other.state; |
| throw_if(throwing_copy_assignment); |
| return *this; |
| } |
| |
| value_type(value_type&& other) |
| : state(other.state) |
| { |
| other.state = moved_from; |
| throw_if(throwing_move); |
| } |
| |
| value_type& |
| operator=(value_type&& other) |
| { |
| state = other.state; |
| other.state = moved_from; |
| throw_if(throwing_move_assignment); |
| return *this; |
| } |
| |
| void throw_if(state_type match) |
| { |
| if(state == match) |
| { |
| state = threw; |
| throw exception {}; |
| } |
| } |
| |
| state_type state = zero; |
| }; |
| |
| static void |
| test () |
| { |
| using O = gdb::optional<value_type>; |
| using S = value_type::state_type; |
| auto const make = [](S s = S::zero) { return O { gdb::in_place, s }; }; |
| |
| enum outcome_type { nothrow, caught, bad_catch }; |
| |
| // Check copy/move assignment for disengaged optional |
| |
| // From disengaged optional |
| { |
| O o; |
| VERIFY( !o ); |
| O p; |
| o = p; |
| VERIFY( !o ); |
| VERIFY( !p ); |
| } |
| |
| { |
| O o; |
| VERIFY( !o ); |
| O p; |
| o = std::move(p); |
| VERIFY( !o ); |
| VERIFY( !p ); |
| } |
| |
| #ifndef GDB_OPTIONAL |
| { |
| O o; |
| VERIFY( !o ); |
| o = {}; |
| VERIFY( !o ); |
| } |
| #endif |
| |
| // From engaged optional |
| { |
| O o; |
| VERIFY( !o ); |
| O p = make(S::throwing_copy_assignment); |
| o = p; |
| VERIFY( o && o->state == S::throwing_copy_assignment ); |
| VERIFY( p && p->state == S::throwing_copy_assignment ); |
| } |
| |
| { |
| O o; |
| VERIFY( !o ); |
| O p = make(S::throwing_move_assignment); |
| o = std::move(p); |
| VERIFY( o && o->state == S::throwing_move_assignment ); |
| VERIFY( p && p->state == S::moved_from ); |
| } |
| |
| { |
| outcome_type outcome {}; |
| O o; |
| VERIFY( !o ); |
| O p = make(S::throwing_copy); |
| |
| try |
| { |
| o = p; |
| } |
| catch(exception const&) |
| { outcome = caught; } |
| catch(...) |
| { outcome = bad_catch; } |
| |
| VERIFY( outcome == caught ); |
| VERIFY( !o ); |
| VERIFY( p && p->state == S::throwing_copy ); |
| } |
| |
| { |
| outcome_type outcome {}; |
| O o; |
| VERIFY( !o ); |
| O p = make(S::throwing_move); |
| |
| try |
| { |
| o = std::move(p); |
| } |
| catch(exception const&) |
| { outcome = caught; } |
| catch(...) |
| { outcome = bad_catch; } |
| |
| VERIFY( outcome == caught ); |
| VERIFY( !o ); |
| VERIFY( p && p->state == S::moved_from ); |
| } |
| |
| VERIFY( counter == 0 ); |
| } |
| |
| } // namespace assign_1 |