Nullable for types without default constructor #617

This commit is contained in:
Alex Fabijanic 2017-10-12 20:20:26 -05:00
parent b0fd3db526
commit 896c1ad016
2 changed files with 55 additions and 18 deletions

View File

@ -36,7 +36,7 @@ enum NullType
template <typename C>
class Nullable
/// Nullable is a simple wrapper class for value types
/// that allows objects or native type variables
/// that allows objects or native type variables
/// to have "null" value.
///
/// The class is useful for passing parameters to functions
@ -60,34 +60,34 @@ class Nullable
public:
Nullable():
/// Creates an empty Nullable.
_value(),
_isNull(true),
_null()
{
std::memset(_value, 0, sizeof(C));
}
Nullable(const NullType&):
/// Creates an empty Nullable.
_value(),
_isNull(true),
_null()
{
std::memset(_value, 0, sizeof(C));
}
Nullable(const C& value):
/// Creates a Nullable with the given value.
_value(value),
_isNull(false),
_null()
{
new(_value) C(value);
}
Nullable(const Nullable& other):
/// Creates a Nullable by copying another one.
_value(other._value),
_isNull(other._isNull),
_null()
{
new(_value) C(other.value());
}
~Nullable()
@ -98,7 +98,7 @@ public:
Nullable& assign(const C& value)
/// Assigns a value to the Nullable.
{
_value = value;
new (_value) C(value);
_isNull = false;
return *this;
}
@ -140,20 +140,23 @@ public:
void swap(Nullable& other)
/// Swaps this Nullable with other.
{
std::swap(_value, other._value);
char tmp[sizeof(C)];
std::memcpy(tmp, _value, sizeof(C));
std::memcpy(_value, other._value, sizeof(C));
std::memcpy(other._value, tmp, sizeof(C));
std::swap(_isNull, other._isNull);
}
bool operator == (const Nullable<C>& other) const
/// Compares two Nullables for equality
{
return (_isNull && other._isNull) || (_isNull == other._isNull && _value == other._value);
return (_isNull && other._isNull) || (_isNull == other._isNull && value() == other.value());
}
bool operator == (const C& value) const
bool operator == (const C& val) const
/// Compares Nullable with value for equality
{
return (!_isNull && _value == value);
return (!_isNull && value() == val);
}
bool operator == (const NullType&) const
@ -162,10 +165,10 @@ public:
return _isNull;
}
bool operator != (const C& value) const
bool operator != (const C& val) const
/// Compares Nullable with value for non equality
{
return !(*this == value);
return !(*this == val);
}
bool operator != (const Nullable<C>& other) const
@ -188,7 +191,7 @@ public:
if (_isNull && other._isNull) return false;
if (!_isNull && !other._isNull)
return (_value < other._value);
return (value() < other.value());
if (_isNull && !other._isNull) return true;
@ -209,7 +212,7 @@ public:
/// Throws a NullValueException if the Nullable is empty.
{
if (!_isNull)
return _value;
return *reinterpret_cast<C*>(_value);
else
throw NullValueException();
}
@ -220,7 +223,7 @@ public:
/// Throws a NullValueException if the Nullable is empty.
{
if (!_isNull)
return _value;
return *reinterpret_cast<const C*>(_value);
else
throw NullValueException();
}
@ -229,7 +232,7 @@ public:
/// Returns the Nullable's value, or the
/// given default value if the Nullable is empty.
{
return _isNull ? deflt : _value;
return _isNull ? deflt : *reinterpret_cast<const C*>(_value);
}
operator C& ()
@ -256,7 +259,7 @@ public:
{
return _isNull;
}
void clear()
/// Clears the Nullable.
{
@ -264,7 +267,7 @@ public:
}
private:
C _value;
char _value[sizeof(C)];
bool _isNull;
NullType _null;
};

View File

@ -360,8 +360,42 @@ void CoreTest::testAtomicCounter()
}
class NonDefaultConstructible
{
public:
NonDefaultConstructible(int val): _val(val)
{
}
NonDefaultConstructible operator=(int val)
{
_val = val;
}
bool operator == (const NonDefaultConstructible& other) const
{
return (_val == other._val);
}
int value() const
{
return _val;
}
private:
NonDefaultConstructible();
int _val;
};
void CoreTest::testNullable()
{
Nullable<NonDefaultConstructible> ndc;
assert (ndc.isNull());
ndc = 42;
assert (!ndc.isNull());
assert (ndc.value() == 42);
Nullable<int> i;
Nullable<double> f;
Nullable<std::string> s;