| /* An optional object. | 
 |  | 
 |    Copyright (C) 2017-2021 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program 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 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program 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 program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #ifndef COMMON_GDB_OPTIONAL_H | 
 | #define COMMON_GDB_OPTIONAL_H | 
 |  | 
 | #include "gdbsupport/traits.h" | 
 |  | 
 | namespace gdb | 
 | { | 
 |  | 
 | struct in_place_t | 
 | { | 
 |   explicit in_place_t () = default; | 
 | }; | 
 |  | 
 | constexpr gdb::in_place_t in_place {}; | 
 |  | 
 | /* This class attempts to be a compatible subset of std::optional, | 
 |    which is slated to be available in C++17.  This class optionally | 
 |    holds an object of some type -- by default it is constructed not | 
 |    holding an object, but later the object can be "emplaced".  This is | 
 |    similar to using std::unique_ptr, but in-object allocation is | 
 |    guaranteed. | 
 |  | 
 |    Unlike std::optional, we currently only support copy/move | 
 |    construction/assignment of an optional<T> from either exactly | 
 |    optional<T> or T.  I.e., we don't support copy/move | 
 |    construction/assignment from optional<U> or U, when U is a type | 
 |    convertible to T.  Making that work depending on the definitions of | 
 |    T and U is somewhat complicated, and currently the users of this | 
 |    class don't need it.  */ | 
 |  | 
 | template<typename T> | 
 | class optional | 
 | { | 
 | public: | 
 |  | 
 |   constexpr optional () | 
 |     : m_dummy () | 
 |   {} | 
 |  | 
 |   template<typename... Args> | 
 |   constexpr optional (in_place_t, Args &&... args) | 
 |     : m_item (std::forward<Args> (args)...), | 
 |       m_instantiated (true) | 
 |   {} | 
 |  | 
 |   ~optional () | 
 |   { this->reset (); } | 
 |  | 
 |   /* Copy and move constructors.  */ | 
 |  | 
 |   optional (const optional &other) | 
 |   { | 
 |     if (other.m_instantiated) | 
 |       this->emplace (other.get ()); | 
 |   } | 
 |  | 
 |   optional (optional &&other) | 
 |     noexcept(std::is_nothrow_move_constructible<T> ()) | 
 |   { | 
 |     if (other.m_instantiated) | 
 |       this->emplace (std::move (other.get ())); | 
 |   } | 
 |  | 
 |   constexpr optional (const T &other) | 
 |     : m_item (other), | 
 |       m_instantiated (true) | 
 |   {} | 
 |  | 
 |   constexpr optional (T &&other) | 
 |     noexcept (std::is_nothrow_move_constructible<T> ()) | 
 |     : m_item (std::move (other)), | 
 |       m_instantiated (true) | 
 |   {} | 
 |  | 
 |   /* Assignment operators.  */ | 
 |  | 
 |   optional & | 
 |   operator= (const optional &other) | 
 |   { | 
 |     if (m_instantiated && other.m_instantiated) | 
 |       this->get () = other.get (); | 
 |     else | 
 |       { | 
 | 	if (other.m_instantiated) | 
 | 	  this->emplace (other.get ()); | 
 | 	else | 
 | 	  this->reset (); | 
 |       } | 
 |  | 
 |     return *this; | 
 |   } | 
 |  | 
 |   optional & | 
 |   operator= (optional &&other) | 
 |     noexcept (And<std::is_nothrow_move_constructible<T>, | 
 | 	      std::is_nothrow_move_assignable<T>> ()) | 
 |   { | 
 |     if (m_instantiated && other.m_instantiated) | 
 |       this->get () = std::move (other.get ()); | 
 |     else | 
 |       { | 
 | 	if (other.m_instantiated) | 
 | 	  this->emplace (std::move (other.get ())); | 
 | 	else | 
 | 	  this->reset (); | 
 |       } | 
 |     return *this; | 
 |   } | 
 |  | 
 |   optional & | 
 |   operator= (const T &other) | 
 |   { | 
 |     if (m_instantiated) | 
 |       this->get () = other; | 
 |     else | 
 |       this->emplace (other); | 
 |     return *this; | 
 |   } | 
 |  | 
 |   optional & | 
 |   operator= (T &&other) | 
 |     noexcept (And<std::is_nothrow_move_constructible<T>, | 
 | 	      std::is_nothrow_move_assignable<T>> ()) | 
 |   { | 
 |     if (m_instantiated) | 
 |       this->get () = std::move (other); | 
 |     else | 
 |       this->emplace (std::move (other)); | 
 |     return *this; | 
 |   } | 
 |  | 
 |   template<typename... Args> | 
 |   T &emplace (Args &&... args) | 
 |   { | 
 |     this->reset (); | 
 |     new (&m_item) T (std::forward<Args>(args)...); | 
 |     m_instantiated = true; | 
 |     return this->get (); | 
 |   } | 
 |  | 
 |   /* Observers.  */ | 
 |   constexpr const T *operator-> () const | 
 |   { return std::addressof (this->get ()); } | 
 |  | 
 |   T *operator-> () | 
 |   { return std::addressof (this->get ()); } | 
 |  | 
 |   constexpr const T &operator* () const & | 
 |   { return this->get (); } | 
 |  | 
 |   T &operator* () & | 
 |   { return this->get (); } | 
 |  | 
 |   T &&operator* () && | 
 |   { return std::move (this->get ()); } | 
 |  | 
 |   constexpr const T &&operator* () const && | 
 |   { return std::move (this->get ()); } | 
 |  | 
 |   constexpr explicit operator bool () const noexcept | 
 |   { return m_instantiated; } | 
 |  | 
 |   constexpr bool has_value () const noexcept | 
 |   { return m_instantiated; } | 
 |  | 
 |   /* 'reset' is a 'safe' operation with no precondition.  */ | 
 |   void reset () noexcept | 
 |   { | 
 |     if (m_instantiated) | 
 |       this->destroy (); | 
 |   } | 
 |  | 
 | private: | 
 |  | 
 |   /* Destroy the object.  */ | 
 |   void destroy () | 
 |   { | 
 |     gdb_assert (m_instantiated); | 
 |     m_instantiated = false; | 
 |     m_item.~T (); | 
 |   } | 
 |  | 
 |   /* The get operations have m_instantiated as a precondition.  */ | 
 |   T &get () noexcept | 
 |   { | 
 | #if defined(_GLIBCXX_DEBUG) | 
 |     gdb_assert (this->has_value ()); | 
 | #endif | 
 |     return m_item; | 
 |   } | 
 |   constexpr const T &get () const noexcept | 
 |   { | 
 | #if defined(_GLIBCXX_DEBUG) | 
 |     gdb_assert (this->has_value ()); | 
 | #endif | 
 |     return m_item; | 
 |   } | 
 |  | 
 |   /* The object.  */ | 
 |   union | 
 |   { | 
 |     struct { } m_dummy; | 
 |     T m_item; | 
 |     volatile char dont_use; /* Silences -Wmaybe-uninitialized warning, see | 
 | 			       PR gcc/80635.  */ | 
 |   }; | 
 |  | 
 |   /* True if the object was ever emplaced.  */ | 
 |   bool m_instantiated = false; | 
 | }; | 
 |  | 
 | } | 
 |  | 
 | #endif /* COMMON_GDB_OPTIONAL_H */ |