1 // (C) 2003, Fernando Luis Cacciola Carballal.
3 // This material is provided "as is", with absolutely no warranty expressed
4 // or implied. Any use is at your own risk.
6 // Permission to use or copy this software for any purpose is hereby granted
7 // without fee, provided the above notices are retained on all copies.
8 // Permission to modify the code and to distribute modified code is granted,
9 // provided the above notices are retained, and a notice that the code was
10 // modified is included with the above copyright notice.
12 // See http://www.boost.org/lib/optional for documentation.
14 // You are welcome to contact the author at:
15 // fernando_cacciola@hotmail.com
17 #ifndef BOOST_OPTIONAL_FLC_19NOV2002_HPP
18 #define BOOST_OPTIONAL_FLC_19NOV2002_HPP
23 #include "boost/config.hpp"
24 #include "boost/assert.hpp"
25 #include "boost/type_traits/alignment_of.hpp"
26 #include "boost/type_traits/type_with_alignment.hpp"
28 #if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
29 // VC6.0 has the following bug:
30 // When a templated assignment operator exist, an implicit conversion
31 // constructing an optional<T> is used when assigment of the form:
32 // optional<T> opt ; opt = T(...);
34 // However, optional's ctor is _explicit_ and the assignemt shouldn't compile.
35 // Therefore, for VC6.0 templated assignment is disabled.
37 #define BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT
40 #if BOOST_WORKAROUND(BOOST_MSVC, == 1300)
41 // VC7.0 has the following bug:
42 // When both a non-template and a template copy-ctor exist
43 // and the templated version is made 'explicit', the explicit is also
44 // given to the non-templated version, making the class non-implicitely-copyable.
46 #define BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR
51 namespace optional_detail
56 // Borland ICEs if unnamed unions are used for this!
59 char data[ sizeof(T) ];
60 BOOST_DEDUCED_TYPENAME type_with_alignment<
61 ::boost::alignment_of<T>::value >::type aligner_;
66 void const* address() const { return &dummy_.data[0]; }
67 void * address() { return &dummy_.data[0]; }
74 typedef optional<T> this_type ;
76 typedef optional_detail::aligned_storage<T> storage_type ;
78 typedef void (this_type::*unspecified_bool_type)();
82 typedef T value_type ;
84 // Creates an optional<T> uninitialized.
88 m_initialized(false) {}
90 // Creates an optional<T> initialized with 'val'.
91 // Can throw if T::T(T const&) does
92 explicit optional ( T const& val )
99 #ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR
100 // NOTE: MSVC needs templated versions first
102 // Creates a deep copy of another convertible optional<U>
103 // Requires a valid conversion from U to T.
104 // Can throw if T::T(U const&) does
106 explicit optional ( optional<U> const& rhs )
115 // Creates a deep copy of another optional<T>
116 // Can throw if T::T(T const&) does
117 optional ( optional const& rhs )
125 // No-throw (assuming T::~T() doesn't)
126 ~optional() { destroy() ; }
128 #ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT
129 // Assigns from another convertible optional<U> (converts && deep-copies the rhs value)
130 // Requires a valid conversion from U to T.
131 // Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED
133 optional& operator= ( optional<U> const& rhs )
135 destroy(); // no-throw
139 // An exception can be thrown here.
140 // It it happens, THIS will be left uninitialized.
147 // Assigns from another optional<T> (deep-copies the rhs value)
148 // Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED
149 optional& operator= ( optional const& rhs )
151 destroy(); // no-throw
155 // An exception can be thrown here.
156 // It it happens, THIS will be left uninitialized.
162 // Destroys the current value, if any, leaving this UNINITIALIZED
163 // No-throw (assuming T::~T() doesn't)
169 // Replaces the current value -if any- with 'val'
170 // Basic Guarantee: If T::T( T const& ) throws this is left UNINITIALIZED.
171 void reset ( T const& val )
177 // Returns a pointer to the value if this is initialized, otherwise,
180 T const* get() const { return m_initialized ? static_cast<T const*>(m_storage.address()) : 0 ; }
181 T* get() { return m_initialized ? static_cast<T*> (m_storage.address()) : 0 ; }
183 // Returns a pointer to the value if this is initialized, otherwise,
184 // the behaviour is UNDEFINED
186 T const* operator->() const { BOOST_ASSERT(m_initialized) ; return static_cast<T const*>(m_storage.address()) ; }
187 T* operator->() { BOOST_ASSERT(m_initialized) ; return static_cast<T*> (m_storage.address()) ; }
189 // Returns a reference to the value if this is initialized, otherwise,
190 // the behaviour is UNDEFINED
192 T const& operator *() const { BOOST_ASSERT(m_initialized) ; return *static_cast<T const*>(m_storage.address()) ; }
193 T& operator *() { BOOST_ASSERT(m_initialized) ; return *static_cast<T*> (m_storage.address()) ; }
195 // implicit conversion to "bool"
197 operator unspecified_bool_type() const { return m_initialized ? &this_type::destroy : 0 ; }
199 // This is provided for those compilers which don't like the conversion to bool
201 bool operator!() const { return !m_initialized ; }
205 void construct ( T const& val )
207 new (m_storage.address()) T(val) ;
208 m_initialized = true ;
216 m_initialized = false ;
221 storage_type m_storage ;
224 // Returns a pointer to the value if this is initialized, otherwise, returns NULL.
228 T const* get_pointer ( optional<T> const& opt )
235 T* get_pointer ( optional<T>& opt )
240 // template<class OP> bool equal_pointees(OP const& x, OP const& y);
242 // Being OP a model of OptionalPointee (either a pointer or an optional):
244 // If both x and y have valid pointees, returns the result of (*x == *y)
245 // If only one has a valid pointee, returns false.
246 // If none have valid pointees, returns true.
248 template<class OptionalPointee>
250 bool equal_pointees ( OptionalPointee const& x, OptionalPointee const& y )
252 return (!x) != (!y) ? false : ( !x ? true : (*x) == (*y) ) ;
255 // optional's operator == and != have deep-semantics (compare values).
256 // WARNING: This is UNLIKE pointers. Use equal_pointees() in generic code instead.
259 bool operator == ( optional<T> const& x, optional<T> const& y )
260 { return equal_pointees(x,y); }
264 bool operator != ( optional<T> const& x, optional<T> const& y )
265 { return !( x == y ) ; }
269 // The following swap implementation follows the GCC workaround as found in
270 // "boost/detail/compressed_pair.hpp"
272 namespace optional_detail {
275 // workaround for GCC (JM):
280 // If both are initialized, calls swap(T&, T&), with whatever exception guarantess are given there.
281 // If only one is initialized, calls I.reset() and U.reset(*I), with the Basic Guarantee
282 // If both are uninitialized, do nothing (no-throw)
285 void optional_swap ( optional<T>& x, optional<T>& y )
289 x.reset(*y); // Basic guarantee.
292 else if ( !!x && !y )
294 y.reset(*x); // Basic guarantee.
297 else if ( !!x && !!y )
306 } // namespace optional_detail
308 template<class T> inline void swap ( optional<T>& x, optional<T>& y )
310 optional_detail::optional_swap(x,y);