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 | |
27 | namespace Poco { |
28 | |
29 | |
30 | enum NullType |
31 | { |
32 | NULL_GENERIC = 0 |
33 | }; |
34 | |
35 | |
36 | template <typename C> |
37 | class 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 | { |
57 | public: |
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 | |
270 | private: |
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 | |
302 | template <typename C> |
303 | inline void swap(Nullable<C>& n1, Nullable<C>& n2) |
304 | { |
305 | n1.swap(n2); |
306 | } |
307 | |
308 | |
309 | template <typename C> |
310 | std::ostream& operator<<(std::ostream& out, const Nullable<C>& obj) |
311 | { |
312 | if (!obj.isNull()) out << obj.value(); |
313 | return out; |
314 | } |
315 | |
316 | |
317 | template <typename C> |
318 | bool operator == (const NullType&, const Nullable<C>& n) |
319 | /// Returns true if this Nullable is null. |
320 | { |
321 | return n.isNull(); |
322 | } |
323 | |
324 | |
325 | template <typename C> |
326 | bool operator != (const C& c, const Nullable<C>& n) |
327 | /// Compares Nullable with value for non equality |
328 | { |
329 | return !(n == c); |
330 | } |
331 | |
332 | |
333 | template <typename C> |
334 | bool operator == (const C& c, const Nullable<C>& n) |
335 | /// Compares Nullable with NullData for equality |
336 | { |
337 | return (n == c); |
338 | } |
339 | |
340 | |
341 | template <typename C> |
342 | bool 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 | |