// (C) 2002, Fernando Luis Cacciola Carballal. // // This material is provided "as is", with absolutely no warranty expressed // or implied. Any use is at your own risk. // // Permission to use or copy this software for any purpose is hereby granted // without fee, provided the above notices are retained on all copies. // Permission to modify the code and to distribute modified code is granted, // provided the above notices are retained, and a notice that the code was // modified is included with the above copyright notice. // // See http://www.boost.org/lib/optional for documentation. // // You are welcome to contact the author at: // fernando_cacciola@hotmail.com // #ifndef BOOST_OPTIONAL_FLC_19NOV2002_HPP #define BOOST_OPTIONAL_FLC_19NOV2002_HPP #include #include #include "boost/assert.hpp" #include "boost/utility/aligned_storage.hpp" namespace boost { template class optional { typedef optional this_type ; typedef typename make_aligned_storage::type storage_type ; typedef void (this_type::*unspecified_bool_type)(); public : typedef T value_type ; // Creates an optional uninitialized. // No-throw optional () : m_initialized(false) {} // Creates an optional initialized with 'val'. // Can throw if T::T(T const&) does explicit optional ( T const& val ) : m_initialized(false) { construct(val); } // Creates a deep copy of another optional // Can throw if T::T(T const&) does optional ( optional const& rhs ) : m_initialized(false) { if ( rhs ) construct(*rhs); } // Creates a deep copy of another convertible optional // Requires a valid conversion from U to T. // Can throw if T::T(U const&) does template explicit optional ( optional const& rhs ) : m_initialized(false) { if ( rhs ) construct(*rhs); } // No-throw (assuming T::~T() doesn't) ~optional() { destroy() ; } // Assigns from another optional (deep-copies the rhs value) // Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED optional& operator= ( optional const& rhs ) { destroy(); // no-throw if ( rhs ) { // An exception can be thrown here. // It it happens, THIS will be left uninitialized. construct(*rhs); } return *this ; } // Assigns from another convertible optional (converts && deep-copies the rhs value) // Requires a valid conversion from U to T. // Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED template optional& operator= ( optional const& rhs ) { destroy(); // no-throw if ( rhs ) { // An exception can be thrown here. // It it happens, THIS will be left uninitialized. construct(*rhs); } return *this ; } // Destroys the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) void reset() { destroy(); } // Replaces the current value -if any- with 'val' // Basic Guarantee: If T::T( T const& ) throws this is left UNINITIALIZED. void reset ( T const& val ) { destroy(); construct(val); } // Returns a pointer to the value if this is initialized, otherwise, // returns NULL. // No-throw T const* get() const { return m_initialized ? static_cast(m_storage.address()) : 0 ; } T* get() { return m_initialized ? static_cast (m_storage.address()) : 0 ; } // Returns a pointer to the value if this is initialized, otherwise, // the behaviour is UNDEFINED // No-throw T const* operator->() const { BOOST_ASSERT(m_initialized) ; return get() ; } T* operator->() { BOOST_ASSERT(m_initialized) ; return get() ; } // Returns a reference to the value if this is initialized, otherwise, // the behaviour is UNDEFINED // No-throw T const& operator *() const { BOOST_ASSERT(m_initialized) ; return *get() ; } T& operator *() { BOOST_ASSERT(m_initialized) ; return *get() ; } // implicit conversion to "bool" // No-throw operator unspecified_bool_type() const { return m_initialized ? &this_type::destroy : 0 ; } // This is provided for those compilers which don't like the conversion to bool // on some contexts. bool operator!() const { return !m_initialized ; } private : void construct ( T const& val ) { new (m_storage.address()) T(val) ; m_initialized = true ; } void destroy() { if ( m_initialized ) { get()->~T() ; m_initialized = false ; } } bool m_initialized ; storage_type m_storage ; } ; // Returns a pointer to the value if this is initialized, otherwise, returns NULL. // No-throw template inline T const* get_pointer ( optional const& opt ) { return opt.get() ; } template inline T* get_pointer ( optional& opt ) { return opt.get() ; } // template bool equal_pointees(OP const& x, OP const& y); // // Being OP a model of OptionalPointee (either a pointer or an optional): // // If both x and y have valid pointees, returns the result of (*x == *y) // If only one has a valid pointee, returns false. // If none have valid pointees, returns true. // No-throw template inline bool equal_pointees ( OptionalPointee const& x, OptionalPointee const& y ) { return (!x) != (!y) ? false : ( !x ? true : (*x) == (*y) ) ; } // optional's operator == and != have deep-semantics (compare values). // WARNING: This is UNLIKE pointers. Use equal_pointees() in generic code instead. template inline bool operator == ( optional const& x, optional const& y ) { return equal_pointees(x,y); } template inline bool operator != ( optional const& x, optional const& y ) { return !( x == y ) ; } // optional's swap: // If both are initialized, calls swap(T&, T&), with whatever exception guarantess are given there. // If only one is initialized, calls I.reset() and U.reset(*I), with the Basic Guarantee // If both are uninitialized, do nothing (no-throw) template inline void swap ( optional& x, optional& y ) { if ( !x && !!y ) { x.reset(*y); // Basic guarantee. y.reset(); } else if ( !!x && !y ) { y.reset(*x); // Basic guarantee. x.reset(); } else if ( !!x && !!y ) { using std::swap ; swap(*x,*y); } } } // namespace boost #endif