Skip to content

Commit

Permalink
nullable SOO, redone #617
Browse files Browse the repository at this point in the history
  • Loading branch information
aleks-f committed Oct 14, 2017
1 parent 68b688c commit 071cdd1
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 57 deletions.
4 changes: 2 additions & 2 deletions Data/MySQL/src/MySQLStatementImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ bool MySQLStatementImpl::hasNext()
return false;
}


std::size_t MySQLStatementImpl::next()
{
if (!hasNext())
throw StatementException("No data received");
throw StatementException("No data received");

Poco::Data::AbstractExtractionVec::iterator it = extractions().begin();
Poco::Data::AbstractExtractionVec::iterator itEnd = extractions().end();
Expand Down
1 change: 1 addition & 0 deletions Data/MySQL/testsuite/src/MySQLTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,7 @@ void MySQLTest::testTupleWithNullable()

*_pSession << "SELECT Id, Address, Age FROM NullableStringTest", into(result), now;

assert (result.size() == 6);
assert(result[0].get<1>() == std::string("Address"));
assert(result[0].get<2>() == 10);

Expand Down
135 changes: 82 additions & 53 deletions Foundation/include/Poco/Nullable.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ 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
/// when parameters are optional and no default values
/// when parameters are optional and no default values
/// should be used or when a non-assigned state is needed,
/// such as in e.g. fetching null values from database.
///
/// A Nullable can be default constructed. In this case,
/// A Nullable can be default constructed. In this case,
/// the Nullable will have a Null value and isNull() will
/// return true. Calling value() (without default value) on
/// a Null object will throw a NullValueException.
Expand All @@ -53,71 +53,59 @@ class Nullable
/// It is possible to assign a value to a Nullable, and
/// to reset a Nullable to contain a Null value by calling
/// clear().
///
/// For use with Nullable, the value type should support
/// default construction.
{
public:
Nullable():
Nullable(): _isNull(true)
/// Creates an empty Nullable.
_value(),
_isNull(true),
_null()
{
construct();
}

Nullable(const NullType&):
Nullable(const NullType&): _isNull(true)
/// Creates an empty Nullable.
_value(),
_isNull(true),
_null()
{
construct();
}

Nullable(const C& value):
Nullable(const C& val): _isNull(true)
/// Creates a Nullable with the given value.
_value(value),
_isNull(false),
_null()
{
construct(&val);
}
Nullable(const Nullable& other):

Nullable(const Nullable& other): _isNull(true)
/// Creates a Nullable by copying another one.
_value(other._value),
_isNull(other._isNull),
_null()
{
construct(other);
}

~Nullable()
/// Destroys the Nullable.
{
destruct();
}

Nullable& assign(const C& value)
Nullable& assign(const C& val)
/// Assigns a value to the Nullable.
{
_value = value;
_isNull = false;
construct(&val);
return *this;
}

Nullable& assign(const Nullable& other)
/// Assigns another Nullable.
{
Nullable tmp(other);
swap(tmp);
if (&other != this) construct(other);
return *this;
}

Nullable& assign(NullType)
/// Sets value to null.
{
_isNull = true;
destruct();
return *this;
}

Nullable& operator = (const C& value)
/// Assigns a value to the Nullable.
{
Expand All @@ -133,27 +121,21 @@ class Nullable
Nullable& operator = (NullType)
/// Assigns another Nullable.
{
_isNull = true;
destruct();
return *this;
}

void swap(Nullable& other)
/// Swaps this Nullable with other.
{
std::swap(_value, other._value);
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
Expand All @@ -162,10 +144,10 @@ class Nullable
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
Expand All @@ -188,7 +170,22 @@ class Nullable
if (_isNull && other._isNull) return false;

if (!_isNull && !other._isNull)
return (_value < other._value);
return (value() < other.value());

if (_isNull && !other._isNull) return true;

return false;
}

bool operator <= (const Nullable<C>& other) const
/// Compares two Nullable objects. Return true if this object's
/// value is smaller or equal than the other object's value.
/// Null value is smaller than a non-null value.
{
if (_isNull && other._isNull) return true;

if (!_isNull && !other._isNull)
return ((value() < other.value()) || (value() == other.value()));

if (_isNull && !other._isNull) return true;

Expand All @@ -203,13 +200,21 @@ class Nullable
return !(*this == other) && !(*this < other);
}

bool operator >= (const Nullable<C>& other) const
/// Compares two Nullable objects. Return true if this object's
/// value is greater or equal than the other object's value.
/// A non-null value is greater than a null value.
{
return (*this > other) || (*this == other);
}

C& value()
/// Returns the Nullable's value.
///
/// Throws a NullValueException if the Nullable is empty.
{
if (!_isNull)
return _value;
return *reinterpret_cast<C*>(_value);
else
throw NullValueException();
}
Expand All @@ -220,7 +225,7 @@ class Nullable
/// Throws a NullValueException if the Nullable is empty.
{
if (!_isNull)
return _value;
return *reinterpret_cast<const C*>(_value);
else
throw NullValueException();
}
Expand All @@ -229,7 +234,7 @@ class Nullable
/// 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& ()
Expand All @@ -247,7 +252,6 @@ class Nullable
operator NullType& ()
/// Get reference to the value
{

return _null;
}

Expand All @@ -256,15 +260,40 @@ class Nullable
{
return _isNull;
}

void clear()
/// Clears the Nullable.
{
_isNull = true;
destruct();
}

private:
C _value;
void construct(const Nullable& val)
{
if (!val._isNull) construct(&val.value());
else destruct();
}

void construct(const C* pVal = 0)
{
destruct();
if (pVal)
{
new(_value) C(*pVal);
_isNull = false;
}
}

void destruct(bool init = true)
{
if (!_isNull)
{
value().~C();
_isNull = true;
}
}

char _value[sizeof(C)];
bool _isNull;
NullType _null;
};
Expand Down
4 changes: 2 additions & 2 deletions Foundation/include/Poco/TypeList.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ namespace Poco {
template <class Head, class Tail>
struct TypeList;


struct NullTypeList
{
enum
Expand Down Expand Up @@ -116,7 +116,7 @@ struct TypeList
std::swap(head, tl.head);
std::swap(tail, tl.tail);
}

HeadType head;
TailType tail;
};
Expand Down
47 changes: 47 additions & 0 deletions Foundation/testsuite/src/CoreTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,38 @@ namespace
private:
AtomicCounter& _counter;
};

class NonDefaultConstructible
{
public:
NonDefaultConstructible(int val) : _val(val)
{
}

NonDefaultConstructible operator=(int val)
{
_val = val;
}

bool operator == (const NonDefaultConstructible& other) const
{
return (_val == other._val);
}

bool operator < (const NonDefaultConstructible& other) const
{
return (_val < other._val);
}

int value() const
{
return _val;
}

private:
NonDefaultConstructible();
int _val;
};
}


Expand Down Expand Up @@ -362,6 +394,21 @@ void CoreTest::testAtomicCounter()

void CoreTest::testNullable()
{
Nullable<NonDefaultConstructible> ndc1;
Nullable<NonDefaultConstructible> ndc2;
assert (ndc1.isNull());
assert (ndc2.isNull());
assert (ndc1 == ndc2);
assert (!(ndc1 != ndc2));
assert (!(ndc1 > ndc2));
bool ge = (ndc1 >= ndc2);
assert (ndc1 >= ndc2);
assert (!(ndc1 < ndc2));
assert (ndc1 <= ndc2);
ndc1 = 42;
assert (!ndc1.isNull());
assert (ndc1.value() == 42);

Nullable<int> i;
Nullable<double> f;
Nullable<std::string> s;
Expand Down
Loading

0 comments on commit 071cdd1

Please sign in to comment.