353 lines
6.9 KiB
C
Raw Normal View History

//
// Nullable.h
//
// Library: Foundation
// Package: Core
// Module: Nullable
//
// Definition of the Nullable template class.
//
// Copyright (c) 2010, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Foundation_Nullable_INCLUDED
#define Foundation_Nullable_INCLUDED
#include "Poco/Foundation.h"
#include "Poco/Exception.h"
#include <algorithm>
2012-09-12 02:10:31 +00:00
#include <iostream>
namespace Poco {
enum NullType
{
NULL_GENERIC = 0
};
template <typename C>
class Nullable
/// Nullable is a simple wrapper class for value types
2017-10-13 19:04:30 -05:00
/// that allows objects or native type variables
2012-09-12 03:20:24 +00:00
/// to have "null" value.
///
/// The class is useful for passing parameters to functions
2017-10-13 19:04:30 -05:00
/// when parameters are optional and no default values
2012-09-12 03:20:24 +00:00
/// should be used or when a non-assigned state is needed,
/// such as in e.g. fetching null values from database.
///
2017-10-13 19:04:30 -05:00
/// 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.
///
/// A Nullable can also be constructed from a value.
/// It is possible to assign a value to a Nullable, and
/// to reset a Nullable to contain a Null value by calling
/// clear().
{
public:
2017-10-13 19:04:30 -05:00
Nullable(): _isNull(true)
/// Creates an empty Nullable.
{
2017-10-13 19:04:30 -05:00
construct();
}
2017-10-13 19:04:30 -05:00
Nullable(const NullType&): _isNull(true)
/// Creates an empty Nullable.
{
2017-10-13 19:04:30 -05:00
construct();
}
2017-10-13 19:04:30 -05:00
Nullable(const C& val): _isNull(true)
/// Creates a Nullable with the given value.
{
2017-10-13 19:04:30 -05:00
construct(&val);
}
2017-10-13 19:04:30 -05:00
Nullable(const Nullable& other): _isNull(true)
/// Creates a Nullable by copying another one.
{
2017-10-13 19:04:30 -05:00
construct(other);
}
~Nullable()
/// Destroys the Nullable.
{
2017-10-13 19:04:30 -05:00
destruct();
}
2017-10-13 19:04:30 -05:00
Nullable& assign(const C& val)
/// Assigns a value to the Nullable.
{
2017-10-13 19:04:30 -05:00
construct(&val);
return *this;
}
2017-10-13 19:04:30 -05:00
Nullable& assign(const Nullable& other)
/// Assigns another Nullable.
{
2017-10-13 19:04:30 -05:00
if (&other != this) construct(other);
return *this;
}
2017-10-13 19:04:30 -05:00
Nullable& assign(NullType)
/// Sets value to null.
{
2017-10-13 19:04:30 -05:00
destruct();
return *this;
}
2017-10-13 19:04:30 -05:00
Nullable& operator = (const C& value)
2012-09-12 03:20:24 +00:00
/// Assigns a value to the Nullable.
{
return assign(value);
}
Nullable& operator = (const Nullable& other)
2012-09-12 03:20:24 +00:00
/// Assigns another Nullable.
{
return assign(other);
}
Nullable& operator = (NullType)
/// Assigns another Nullable.
{
2017-10-13 19:04:30 -05:00
destruct();
return *this;
}
bool operator == (const Nullable<C>& other) const
2012-09-12 02:10:31 +00:00
/// Compares two Nullables for equality
{
2017-10-13 19:04:30 -05:00
return (_isNull && other._isNull) ||
(!_isNull && !other._isNull && value() == other.value());
2012-09-12 02:10:31 +00:00
}
2017-10-13 19:04:30 -05:00
bool operator == (const C& val) const
2012-09-12 02:10:31 +00:00
/// Compares Nullable with value for equality
{
2017-10-13 19:04:30 -05:00
return (!_isNull && value() == val);
2012-09-12 02:10:31 +00:00
}
bool operator == (const NullType&) const
/// Compares Nullable with NullData for equality
{
return _isNull;
}
2017-10-13 19:04:30 -05:00
bool operator != (const C& val) const
2012-09-12 02:10:31 +00:00
/// Compares Nullable with value for non equality
{
2017-10-13 19:04:30 -05:00
return !(*this == val);
2012-09-12 02:10:31 +00:00
}
bool operator != (const Nullable<C>& other) const
2012-09-12 02:10:31 +00:00
/// Compares two Nullables for non equality
{
return !(*this == other);
}
bool operator != (const NullType&) const
/// Compares with NullData for non equality
{
return !_isNull;
}
2012-09-12 02:10:31 +00:00
bool operator < (const Nullable<C>& other) const
/// Compares two Nullable objects. Return true if this object's
2015-04-10 11:31:12 +01:00
/// value is smaller than the other object's value.
2012-09-12 03:20:24 +00:00
/// Null value is smaller than a non-null value.
2012-09-12 02:10:31 +00:00
{
if (_isNull && other._isNull) return false;
if (!_isNull && !other._isNull)
2017-10-13 19:04:30 -05:00
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()));
2012-09-12 02:10:31 +00:00
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 greater than the other object's value.
2012-09-12 03:20:24 +00:00
/// A non-null value is greater than a null value.
2012-09-12 02:10:31 +00:00
{
return !(*this == other) && !(*this < other);
}
2017-10-13 19:04:30 -05:00
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)
2017-10-13 19:04:30 -05:00
return *reinterpret_cast<C*>(_value);
else
throw NullValueException();
}
const C& value() const
/// Returns the Nullable's value.
///
/// Throws a NullValueException if the Nullable is empty.
{
if (!_isNull)
2017-10-13 19:04:30 -05:00
return *reinterpret_cast<const C*>(_value);
else
throw NullValueException();
}
const C& value(const C& deflt) const
/// Returns the Nullable's value, or the
/// given default value if the Nullable is empty.
{
2017-10-13 19:04:30 -05:00
return _isNull ? deflt : *reinterpret_cast<const C*>(_value);
}
2012-09-12 02:10:31 +00:00
operator C& ()
/// Get reference to the value
{
return value();
}
operator const C& () const
/// Get const reference to the value
{
return value();
}
operator NullType& ()
/// Get reference to the value
{
return _null;
}
bool isNull() const
2012-10-06 17:04:30 +00:00
/// Returns true if the Nullable is empty.
{
return _isNull;
}
2017-10-13 19:04:30 -05:00
void clear()
/// Clears the Nullable.
{
2017-10-13 19:04:30 -05:00
destruct();
}
private:
2017-10-13 19:04:30 -05:00
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;
};
template <typename C>
inline void swap(Nullable<C>& n1, Nullable<C>& n2)
{
n1.swap(n2);
}
2012-09-12 02:10:31 +00:00
template <typename C>
2017-10-20 15:37:19 -05:00
std::ostream& operator<<(std::ostream& out, const Nullable<C>& obj)
2012-09-12 02:10:31 +00:00
{
if (!obj.isNull()) out << obj.value();
return out;
}
template <typename C>
bool operator == (const NullType&, const Nullable<C>& n)
/// Returns true if this Nullable is null.
{
return n.isNull();
}
template <typename C>
bool operator != (const C& c, const Nullable<C>& n)
/// Compares Nullable with value for non equality
{
return !(n == c);
}
template <typename C>
bool operator == (const C& c, const Nullable<C>& n)
/// Compares Nullable with NullData for equality
{
return (n == c);
}
template <typename C>
bool operator != (const NullType&, const Nullable<C>& n)
/// Returns true if this Nullable is not null.
{
return !n.isNull();
}
} // namespace Poco
#endif // Foundation_Nullable_INCLUDED