clean up fc::optional

This commit is contained in:
Daniel Larimer 2013-07-02 14:59:05 -04:00
parent ad3e5b1337
commit 5226987305

View file

@ -1,84 +1,88 @@
#pragma once #pragma once
#include <fc/utility.hpp> #include <fc/utility.hpp>
#include <assert.h>
namespace fc { namespace fc {
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4521) /* multiple copy ctors */
#endif
/** /**
* @brief provides stack-based nullable value similar to boost::optional * @brief provides stack-based nullable value similar to boost::optional
* *
* Simply including boost::optional adds 35,000 lines to each object file, using * Simply including boost::optional adds 35,000 lines to each object file, using
* fc::optional adds less than 400. * fc::optional adds less than 400.
*/ */
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4521) /* multiple copy ctors */
#endif
template<typename T> template<typename T>
class optional { class optional
{
public: public:
optional():_valid(0){} optional():_valid(false){}
~optional(){ if( _valid ) (**this).~T(); } ~optional(){ reset(); }
optional( const optional& o ) optional( const optional& o )
:_valid(false) { :_valid(false)
if( o._valid ) new (&**this) T( *o ); {
if( o._valid ) new (ptr()) T( *o );
_valid = o._valid; _valid = o._valid;
} }
optional( optional& o ) optional( optional& o )
:_valid(false) { :_valid(false)
if( o._valid ) new (&**this) T( *o ); {
if( o._valid ) new (ptr()) T( *o );
_valid = o._valid; _valid = o._valid;
} }
optional( optional&& o ) optional( optional&& o )
:_valid(false) { :_valid(false)
if( o._valid ) new (&**this) T( fc::move(*o) ); {
if( o._valid ) new (ptr()) T( fc::move(*o) );
_valid = o._valid; _valid = o._valid;
o.reset();
} }
template<typename U> template<typename U>
optional( U&& u ) optional( U&& u )
:_valid(false) { :_valid(false)
new (&**this) T( fc::forward<U>(u) ); {
new (ptr()) T( fc::forward<U>(u) );
_valid = true; _valid = true;
} }
template<typename U> template<typename U>
optional& operator=( U&& u ) { optional& operator=( U&& u )
if( !_valid ) { {
new (&**this) T( fc::forward<U>(u) ); reset();
_valid = true; new (ptr()) T( fc::forward<U>(u) );
} else {
**this = static_cast<T>(fc::forward<U>(u));
}
return *this; return *this;
} }
optional& operator=( const optional& o ) { optional& operator=( const optional& o ) {
if (this != &o) { if (this != &o) {
if( _valid && o._valid ) { if( _valid && o._valid ) {
**this = *o; ref() = *o;
} else if( !_valid && o._valid ) { } else if( !_valid && o._valid ) {
*this = *o; new (ptr()) T( *o );
_valid = true;
} else if (_valid) { } else if (_valid) {
(**this).~T(); reset();
_valid = false;
} }
} }
return *this; return *this;
} }
optional& operator=( optional&& o ) { optional& operator=( optional&& o )
if (this != &o) { {
if (this != &o)
{
if( _valid && o._valid ) { if( _valid && o._valid ) {
**this = fc::move(*o); ref() = fc::move(*o);
} else if ( !_valid && o._valid ) { } else if ( !_valid && o._valid ) {
*this = fc::move(*o); *this = fc::move(*o);
} else if (_valid) { } else if (_valid) {
(**this).~T(); reset();
_valid = false;
} }
} }
return *this; return *this;
@ -87,13 +91,33 @@ namespace fc {
bool operator!()const { return !_valid; } bool operator!()const { return !_valid; }
operator bool()const { return _valid; } operator bool()const { return _valid; }
T& operator*() { void* v = &_value[0]; return *static_cast<T*>(v); } T& operator*() { assert(_valid); return ref(); }
const T& operator*()const { const void* v = &_value[0]; return *static_cast<const T*>(v); } const T& operator*()const { assert(_valid); return ref(); }
T* operator->() { void* v = &_value[0]; return static_cast<T*>(v); } T* operator->()
const T* operator->()const { const void* v = &_value[0]; return static_cast<const T*>(v); } {
assert( _valid );
return ptr();
}
const T* operator->()const
{
assert( _valid );
return ptr();
}
private: private:
void reset()
{
if( _valid )
{
ref().~T(); // cal destructor
}
}
T& ref() { return *ptr(); }
const T& ref()const { return *ptr(); }
T* ptr() { void* v = &_value[0]; return static_cast<T*>(v); }
const T* ptr()const { const void* v = &_value[0]; return static_cast<const T*>(v); }
// force alignment... to 8 byte boundaries // force alignment... to 8 byte boundaries
double _value[8 * ((sizeof(T)+7)/8)]; double _value[8 * ((sizeof(T)+7)/8)];
bool _valid; bool _valid;