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