#pragma once #include #include namespace fc { #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable:4521) /* multiple copy ctors */ # pragma warning(disable:4522) /* multiple assignment operators */ #endif bool assert_optional(bool is_valid ); // defined in exception.cpp /** * @brief provides stack-based nullable value similar to boost::optional * * Simply including boost::optional adds 35,000 lines to each object file, using * fc::optional adds less than 400. */ template class optional { public: typedef T value_type; optional():_valid(false){} ~optional(){ reset(); } optional( optional& o ) :_valid(false) { if( o._valid ) new (ptr()) T( *o ); _valid = o._valid; } optional( const optional& o ) :_valid(false) { if( o._valid ) new (ptr()) T( *o ); _valid = o._valid; } optional( optional&& o ) :_valid(false) { if( o._valid ) new (ptr()) T( fc::move(*o) ); _valid = o._valid; o.reset(); } template optional( const optional& o ) :_valid(false) { if( o._valid ) new (ptr()) T( *o ); _valid = o._valid; } template optional( optional& o ) :_valid(false) { if( o._valid ) { new (ptr()) T( *o ); } _valid = o._valid; } template optional( optional&& o ) :_valid(false) { if( o._valid ) new (ptr()) T( fc::move(*o) ); _valid = o._valid; o.reset(); } template optional( U&& u ) :_valid(true) { new ((char*)ptr()) T( fc::forward(u) ); } template optional& operator=( U&& u ) { reset(); new (ptr()) T( fc::forward(u) ); _valid = true; return *this; } template optional& operator=( optional& o ) { if (this != &o) { if( _valid && o._valid ) { ref() = *o; } else if( !_valid && o._valid ) { new (ptr()) T( *o ); _valid = true; } else if (_valid) { reset(); } } return *this; } template optional& operator=( const optional& o ) { if (this != &o) { if( _valid && o._valid ) { ref() = *o; } else if( !_valid && o._valid ) { new (ptr()) T( *o ); _valid = true; } else if (_valid) { reset(); } } return *this; } optional& operator=( optional& o ) { if (this != &o) { if( _valid && o._valid ) { ref() = *o; } else if( !_valid && o._valid ) { new (ptr()) T( *o ); _valid = true; } else if (_valid) { reset(); } } return *this; } optional& operator=( const optional& o ) { if (this != &o) { if( _valid && o._valid ) { ref() = *o; } else if( !_valid && o._valid ) { new (ptr()) T( *o ); _valid = true; } else if (_valid) { reset(); } } return *this; } template optional& operator=( optional&& o ) { if (this != &o) { if( _valid && o._valid ) { ref() = fc::move(*o); o.reset(); } else if ( !_valid && o._valid ) { *this = fc::move(*o); } else if (_valid) { reset(); } } return *this; } optional& operator=( optional&& o ) { if (this != &o) { if( _valid && o._valid ) { ref() = fc::move(*o); o.reset(); } else if ( !_valid && o._valid ) { *this = fc::move(*o); } else if (_valid) { reset(); } } return *this; } bool valid()const { return _valid; } bool operator!()const { return !_valid; } // this operation is not safe and can result in unintential // casts and comparisons, use valid() or !! explicit operator bool()const { return _valid; } T& operator*() { assert(_valid); return ref(); } const T& operator*()const { assert(_valid); return ref(); } T* operator->() { assert(_valid); return ptr(); } const T* operator->()const { assert(_valid); return ptr(); } optional& operator=(std::nullptr_t) { reset(); return *this; } friend bool operator < ( const optional a, optional b ) { if( a.valid() && b.valid() ) return *a < *b; return a.valid() < b.valid(); } friend bool operator == ( const optional a, optional b ) { if( a.valid() && b.valid() ) return *a == *b; return a.valid() == b.valid(); } void reset() { if( _valid ) { ref().~T(); // cal destructor } _valid = false; } private: template friend class optional; T& ref() { return *ptr(); } const T& ref()const { return *ptr(); } T* ptr() { void* v = &_value[0]; return static_cast(v); } const T* ptr()const { const void* v = &_value[0]; return static_cast(v); } // force alignment... to 8 byte boundaries double _value[((sizeof(T)+7)/8)]; bool _valid; }; template bool operator == ( const optional& left, const optional& right ) { return (!left == !right) || (!!left && *left == *right); } template bool operator == ( const optional& left, const U& u ) { return !!left && *left == u; } template bool operator != ( const optional& left, const optional& right ) { return (!left != !right) || (!!left && *left != *right); } template bool operator != ( const optional& left, const U& u ) { return !left || *left != u; } #ifdef _MSC_VER # pragma warning(pop) #endif } // namespace fc