1//
2// Nullable.h
3//
4// Library: Foundation
5// Package: Core
6// Module: Nullable
7//
8// Definition of the Nullable template class.
9//
10// Copyright (c) 2010, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Foundation_Nullable_INCLUDED
18#define Foundation_Nullable_INCLUDED
19
20
21#include "Poco/Foundation.h"
22#include "Poco/Exception.h"
23#include <algorithm>
24#include <iostream>
25
26
27namespace Poco {
28
29
30enum NullType
31{
32 NULL_GENERIC = 0
33};
34
35
36template <typename C>
37class Nullable
38 /// Nullable is a simple wrapper class for value types
39 /// that allows objects or native type variables
40 /// to have "null" value.
41 ///
42 /// The class is useful for passing parameters to functions
43 /// when parameters are optional and no default values
44 /// should be used or when a non-assigned state is needed,
45 /// such as in e.g. fetching null values from database.
46 ///
47 /// A Nullable can be default constructed. In this case,
48 /// the Nullable will have a Null value and isNull() will
49 /// return true. Calling value() (without default value) on
50 /// a Null object will throw a NullValueException.
51 ///
52 /// A Nullable can also be constructed from a value.
53 /// It is possible to assign a value to a Nullable, and
54 /// to reset a Nullable to contain a Null value by calling
55 /// clear().
56{
57public:
58 Nullable(): _isNull(true)
59 /// Creates an empty Nullable.
60 {
61 construct();
62 }
63
64 Nullable(const NullType&): _isNull(true)
65 /// Creates an empty Nullable.
66 {
67 construct();
68 }
69
70 Nullable(const C& val): _isNull(true)
71 /// Creates a Nullable with the given value.
72 {
73 construct(&val);
74 }
75
76 Nullable(const Nullable& other): _isNull(true)
77 /// Creates a Nullable by copying another one.
78 {
79 construct(other);
80 }
81
82 ~Nullable()
83 /// Destroys the Nullable.
84 {
85 destruct();
86 }
87
88 Nullable& assign(const C& val)
89 /// Assigns a value to the Nullable.
90 {
91 construct(&val);
92 return *this;
93 }
94
95 Nullable& assign(const Nullable& other)
96 /// Assigns another Nullable.
97 {
98 if (&other != this) construct(other);
99 return *this;
100 }
101
102 Nullable& assign(NullType)
103 /// Sets value to null.
104 {
105 destruct();
106 return *this;
107 }
108
109 Nullable& operator = (const C& value)
110 /// Assigns a value to the Nullable.
111 {
112 return assign(value);
113 }
114
115 Nullable& operator = (const Nullable& other)
116 /// Assigns another Nullable.
117 {
118 return assign(other);
119 }
120
121 Nullable& operator = (NullType)
122 /// Assigns another Nullable.
123 {
124 destruct();
125 return *this;
126 }
127
128 bool operator == (const Nullable<C>& other) const
129 /// Compares two Nullables for equality
130 {
131 return (_isNull && other._isNull) ||
132 (!_isNull && !other._isNull && value() == other.value());
133 }
134
135 bool operator == (const C& val) const
136 /// Compares Nullable with value for equality
137 {
138 return (!_isNull && value() == val);
139 }
140
141 bool operator == (const NullType&) const
142 /// Compares Nullable with NullData for equality
143 {
144 return _isNull;
145 }
146
147 bool operator != (const C& val) const
148 /// Compares Nullable with value for non equality
149 {
150 return !(*this == val);
151 }
152
153 bool operator != (const Nullable<C>& other) const
154 /// Compares two Nullables for non equality
155 {
156 return !(*this == other);
157 }
158
159 bool operator != (const NullType&) const
160 /// Compares with NullData for non equality
161 {
162 return !_isNull;
163 }
164
165 bool operator < (const Nullable<C>& other) const
166 /// Compares two Nullable objects. Return true if this object's
167 /// value is smaller than the other object's value.
168 /// Null value is smaller than a non-null value.
169 {
170 if (_isNull && other._isNull) return false;
171
172 if (!_isNull && !other._isNull)
173 return (value() < other.value());
174
175 if (_isNull && !other._isNull) return true;
176
177 return false;
178 }
179
180 bool operator <= (const Nullable<C>& other) const
181 /// Compares two Nullable objects. Return true if this object's
182 /// value is smaller or equal than the other object's value.
183 /// Null value is smaller than a non-null value.
184 {
185 if (_isNull && other._isNull) return true;
186
187 if (!_isNull && !other._isNull)
188 return ((value() < other.value()) || (value() == other.value()));
189
190 if (_isNull && !other._isNull) return true;
191
192 return false;
193 }
194
195 bool operator > (const Nullable<C>& other) const
196 /// Compares two Nullable objects. Return true if this object's
197 /// value is greater than the other object's value.
198 /// A non-null value is greater than a null value.
199 {
200 return !(*this == other) && !(*this < other);
201 }
202
203 bool operator >= (const Nullable<C>& other) const
204 /// Compares two Nullable objects. Return true if this object's
205 /// value is greater or equal than the other object's value.
206 /// A non-null value is greater than a null value.
207 {
208 return (*this > other) || (*this == other);
209 }
210
211 C& value()
212 /// Returns the Nullable's value.
213 ///
214 /// Throws a NullValueException if the Nullable is empty.
215 {
216 if (!_isNull)
217 return *reinterpret_cast<C*>(_value);
218 else
219 throw NullValueException();
220 }
221
222 const C& value() const
223 /// Returns the Nullable's value.
224 ///
225 /// Throws a NullValueException if the Nullable is empty.
226 {
227 if (!_isNull)
228 return *reinterpret_cast<const C*>(_value);
229 else
230 throw NullValueException();
231 }
232
233 const C& value(const C& deflt) const
234 /// Returns the Nullable's value, or the
235 /// given default value if the Nullable is empty.
236 {
237 return _isNull ? deflt : *reinterpret_cast<const C*>(_value);
238 }
239
240 operator C& ()
241 /// Get reference to the value
242 {
243 return value();
244 }
245
246 operator const C& () const
247 /// Get const reference to the value
248 {
249 return value();
250 }
251
252 operator NullType& ()
253 /// Get reference to the value
254 {
255 return _null;
256 }
257
258 bool isNull() const
259 /// Returns true if the Nullable is empty.
260 {
261 return _isNull;
262 }
263
264 void clear()
265 /// Clears the Nullable.
266 {
267 destruct();
268 }
269
270private:
271 void construct(const Nullable& val)
272 {
273 if (!val._isNull) construct(&val.value());
274 else destruct();
275 }
276
277 void construct(const C* pVal = 0)
278 {
279 destruct();
280 if (pVal)
281 {
282 new(_value) C(*pVal);
283 _isNull = false;
284 }
285 }
286
287 void destruct(bool init = true)
288 {
289 if (!_isNull)
290 {
291 value().~C();
292 _isNull = true;
293 }
294 }
295
296 char _value[sizeof(C)];
297 bool _isNull;
298 NullType _null;
299};
300
301
302template <typename C>
303inline void swap(Nullable<C>& n1, Nullable<C>& n2)
304{
305 n1.swap(n2);
306}
307
308
309template <typename C>
310std::ostream& operator<<(std::ostream& out, const Nullable<C>& obj)
311{
312 if (!obj.isNull()) out << obj.value();
313 return out;
314}
315
316
317template <typename C>
318bool operator == (const NullType&, const Nullable<C>& n)
319 /// Returns true if this Nullable is null.
320{
321 return n.isNull();
322}
323
324
325template <typename C>
326bool operator != (const C& c, const Nullable<C>& n)
327 /// Compares Nullable with value for non equality
328{
329 return !(n == c);
330}
331
332
333template <typename C>
334bool operator == (const C& c, const Nullable<C>& n)
335 /// Compares Nullable with NullData for equality
336{
337 return (n == c);
338}
339
340
341template <typename C>
342bool operator != (const NullType&, const Nullable<C>& n)
343 /// Returns true if this Nullable is not null.
344{
345 return !n.isNull();
346}
347
348
349} // namespace Poco
350
351
352#endif // Foundation_Nullable_INCLUDED
353