clean up fc::optional
This commit is contained in:
parent
ad3e5b1337
commit
5226987305
1 changed files with 61 additions and 37 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue