1 | // |
2 | // Any.h |
3 | // |
4 | // Library: Foundation |
5 | // Package: Core |
6 | // Module: Any |
7 | // |
8 | // Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. |
9 | // Extracted from Boost 1.33.1 lib and adapted for poco: Peter Schojer/AppliedInformatics 2006-02-02 |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #ifndef Foundation_Any_INCLUDED |
16 | #define Foundation_Any_INCLUDED |
17 | |
18 | |
19 | #include "Poco/Exception.h" |
20 | #include "Poco/MetaProgramming.h" |
21 | #include <algorithm> |
22 | #include <typeinfo> |
23 | #include <cstring> |
24 | |
25 | |
26 | namespace Poco { |
27 | |
28 | |
29 | class Any; |
30 | |
31 | |
32 | namespace Dynamic { |
33 | |
34 | class Var; |
35 | class VarHolder; |
36 | template <class, class Enable = void> class VarHolderImpl; |
37 | |
38 | } |
39 | |
40 | #ifndef POCO_NO_SOO |
41 | |
42 | template <typename PlaceholderT, unsigned int SizeV = POCO_SMALL_OBJECT_SIZE> |
43 | union Placeholder |
44 | /// ValueHolder union (used by Poco::Any and Poco::Dynamic::Var for small |
45 | /// object optimization, when enabled). |
46 | /// |
47 | /// If Holder<Type> fits into POCO_SMALL_OBJECT_SIZE bytes of storage, |
48 | /// it will be placement-new-allocated into the local buffer |
49 | /// (i.e. there will be no heap-allocation). The local buffer size is one byte |
50 | /// larger - [POCO_SMALL_OBJECT_SIZE + 1], additional byte value indicating |
51 | /// where the object was allocated (0 => heap, 1 => local). |
52 | { |
53 | public: |
54 | struct Size |
55 | { |
56 | static const unsigned int value = SizeV; |
57 | }; |
58 | |
59 | Placeholder () |
60 | { |
61 | erase(); |
62 | } |
63 | |
64 | void erase() |
65 | { |
66 | std::memset(holder, 0, sizeof(Placeholder)); |
67 | } |
68 | |
69 | bool isLocal() const |
70 | { |
71 | return holder[SizeV] != 0; |
72 | } |
73 | |
74 | void setLocal(bool local) const |
75 | { |
76 | holder[SizeV] = local ? 1 : 0; |
77 | } |
78 | |
79 | PlaceholderT* content() const |
80 | { |
81 | if (isLocal()) |
82 | return reinterpret_cast<PlaceholderT*>(holder); |
83 | else |
84 | return pHolder; |
85 | } |
86 | |
87 | // MSVC71,80 won't extend friendship to nested class (Any::Holder) |
88 | #if !defined(POCO_MSVC_VERSION) || (defined(POCO_MSVC_VERSION) && (POCO_MSVC_VERSION > 80)) |
89 | private: |
90 | #endif |
91 | typedef typename std::aligned_storage<SizeV + 1>::type AlignerType; |
92 | |
93 | PlaceholderT* pHolder; |
94 | mutable char holder [SizeV + 1]; |
95 | AlignerType aligner; |
96 | |
97 | friend class Any; |
98 | friend class Dynamic::Var; |
99 | friend class Dynamic::VarHolder; |
100 | template <class> friend class Dynamic::VarHolderImpl; |
101 | }; |
102 | |
103 | |
104 | #else // !POCO_NO_SOO |
105 | |
106 | |
107 | template <typename PlaceholderT> |
108 | union Placeholder |
109 | /// ValueHolder union (used by Poco::Any and Poco::Dynamic::Var for small |
110 | /// object optimization, when enabled). |
111 | /// |
112 | /// If Holder<Type> fits into POCO_SMALL_OBJECT_SIZE bytes of storage, |
113 | /// it will be placement-new-allocated into the local buffer |
114 | /// (i.e. there will be no heap-allocation). The local buffer size is one byte |
115 | /// larger - [POCO_SMALL_OBJECT_SIZE + 1], additional byte value indicating |
116 | /// where the object was allocated (0 => heap, 1 => local). |
117 | { |
118 | public: |
119 | |
120 | Placeholder () |
121 | { |
122 | } |
123 | |
124 | PlaceholderT* content() const |
125 | { |
126 | return pHolder; |
127 | } |
128 | |
129 | // MSVC71,80 won't extend friendship to nested class (Any::Holder) |
130 | #if !defined(POCO_MSVC_VERSION) || (defined(POCO_MSVC_VERSION) && (POCO_MSVC_VERSION > 80)) |
131 | private: |
132 | #endif |
133 | |
134 | PlaceholderT* pHolder; |
135 | |
136 | friend class Any; |
137 | friend class Dynamic::Var; |
138 | friend class Dynamic::VarHolder; |
139 | template <class, class Enable> friend class Dynamic::VarHolderImpl; |
140 | }; |
141 | |
142 | |
143 | #endif // POCO_NO_SOO |
144 | |
145 | |
146 | class Any |
147 | /// An Any class represents a general type and is capable of storing any type, supporting type-safe extraction |
148 | /// of the internally stored data. |
149 | /// |
150 | /// Code taken from the Boost 1.33.1 library. Original copyright by Kevlin Henney. Modified for Poco |
151 | /// by Applied Informatics. |
152 | /// |
153 | /// Modified for small object optimization support (optionally supported through conditional compilation) |
154 | /// by Alex Fabijanic. |
155 | { |
156 | public: |
157 | |
158 | #ifndef POCO_NO_SOO |
159 | |
160 | Any() |
161 | /// Creates an empty any type. |
162 | { |
163 | } |
164 | |
165 | template<typename ValueType> |
166 | Any(const ValueType & value) |
167 | /// Creates an any which stores the init parameter inside. |
168 | /// |
169 | /// Example: |
170 | /// Any a(13); |
171 | /// Any a(string("12345")); |
172 | { |
173 | construct(value); |
174 | } |
175 | |
176 | Any(const Any& other) |
177 | /// Copy constructor, works with both empty and initialized Any values. |
178 | { |
179 | if ((this != &other) && !other.empty()) |
180 | construct(other); |
181 | } |
182 | |
183 | ~Any() |
184 | /// Destructor. If Any is locally held, calls ValueHolder destructor; |
185 | /// otherwise, deletes the placeholder from the heap. |
186 | { |
187 | if (!empty()) |
188 | { |
189 | if (_valueHolder.isLocal()) |
190 | destruct(); |
191 | else |
192 | delete content(); |
193 | } |
194 | } |
195 | |
196 | Any& swap(Any& other) |
197 | /// Swaps the content of the two Anys. |
198 | /// |
199 | /// When small object optimization is enabled, swap only |
200 | /// has no-throw guarantee when both (*this and other) |
201 | /// objects are allocated on the heap. |
202 | { |
203 | if (this == &other) return *this; |
204 | |
205 | if (!_valueHolder.isLocal() && !other._valueHolder.isLocal()) |
206 | { |
207 | std::swap(_valueHolder.pHolder, other._valueHolder.pHolder); |
208 | } |
209 | else |
210 | { |
211 | Any tmp(*this); |
212 | try |
213 | { |
214 | if (_valueHolder.isLocal()) destruct(); |
215 | construct(other); |
216 | other = tmp; |
217 | } |
218 | catch (...) |
219 | { |
220 | construct(tmp); |
221 | throw; |
222 | } |
223 | } |
224 | |
225 | return *this; |
226 | } |
227 | |
228 | template<typename ValueType> |
229 | Any& operator = (const ValueType& rhs) |
230 | /// Assignment operator for all types != Any. |
231 | /// |
232 | /// Example: |
233 | /// Any a = 13; |
234 | /// Any a = string("12345"); |
235 | { |
236 | construct(rhs); |
237 | return *this; |
238 | } |
239 | |
240 | Any& operator = (const Any& rhs) |
241 | /// Assignment operator for Any. |
242 | { |
243 | if ((this != &rhs) && !rhs.empty()) |
244 | construct(rhs); |
245 | else if ((this != &rhs) && rhs.empty()) |
246 | _valueHolder.erase(); |
247 | |
248 | return *this; |
249 | } |
250 | |
251 | bool empty() const |
252 | /// Returns true if the Any is empty. |
253 | { |
254 | char buf[POCO_SMALL_OBJECT_SIZE] = { 0 }; |
255 | return 0 == std::memcmp(_valueHolder.holder, buf, POCO_SMALL_OBJECT_SIZE); |
256 | } |
257 | |
258 | const std::type_info & type() const |
259 | /// Returns the type information of the stored content. |
260 | /// If the Any is empty typeid(void) is returned. |
261 | /// It is recommended to always query an Any for its type info before |
262 | /// trying to extract data via an AnyCast/RefAnyCast. |
263 | { |
264 | return empty() ? typeid(void) : content()->type(); |
265 | } |
266 | |
267 | private: |
268 | |
269 | class ValueHolder |
270 | { |
271 | public: |
272 | |
273 | virtual ~ValueHolder() |
274 | { |
275 | } |
276 | |
277 | virtual const std::type_info & type() const = 0; |
278 | virtual void clone(Placeholder<ValueHolder>*) const = 0; |
279 | }; |
280 | |
281 | template<typename ValueType> |
282 | class Holder : public ValueHolder |
283 | { |
284 | public: |
285 | Holder(const ValueType & value) : _held(value) |
286 | { |
287 | } |
288 | |
289 | virtual const std::type_info & type() const |
290 | { |
291 | return typeid(ValueType); |
292 | } |
293 | |
294 | virtual void clone(Placeholder<ValueHolder>* pPlaceholder) const |
295 | { |
296 | if ((sizeof(Holder<ValueType>) <= POCO_SMALL_OBJECT_SIZE)) |
297 | { |
298 | new ((ValueHolder*) pPlaceholder->holder) Holder(_held); |
299 | pPlaceholder->setLocal(true); |
300 | } |
301 | else |
302 | { |
303 | pPlaceholder->pHolder = new Holder(_held); |
304 | pPlaceholder->setLocal(false); |
305 | } |
306 | } |
307 | |
308 | ValueType _held; |
309 | |
310 | private: |
311 | Holder & operator = (const Holder &); |
312 | }; |
313 | |
314 | ValueHolder* content() const |
315 | { |
316 | return _valueHolder.content(); |
317 | } |
318 | |
319 | template<typename ValueType> |
320 | void construct(const ValueType& value) |
321 | { |
322 | if (sizeof(Holder<ValueType>) <= Placeholder<ValueType>::Size::value) |
323 | { |
324 | new (reinterpret_cast<ValueHolder*>(_valueHolder.holder)) Holder<ValueType>(value); |
325 | _valueHolder.setLocal(true); |
326 | } |
327 | else |
328 | { |
329 | _valueHolder.pHolder = new Holder<ValueType>(value); |
330 | _valueHolder.setLocal(false); |
331 | } |
332 | } |
333 | |
334 | void construct(const Any& other) |
335 | { |
336 | if (!other.empty()) |
337 | other.content()->clone(&_valueHolder); |
338 | else |
339 | _valueHolder.erase(); |
340 | } |
341 | |
342 | void destruct() |
343 | { |
344 | content()->~ValueHolder(); |
345 | } |
346 | |
347 | Placeholder<ValueHolder> _valueHolder; |
348 | |
349 | |
350 | #else // if POCO_NO_SOO |
351 | |
352 | |
353 | Any(): _pHolder(0) |
354 | /// Creates an empty any type. |
355 | { |
356 | } |
357 | |
358 | template <typename ValueType> |
359 | Any(const ValueType& value): |
360 | _pHolder(new Holder<ValueType>(value)) |
361 | /// Creates an any which stores the init parameter inside. |
362 | /// |
363 | /// Example: |
364 | /// Any a(13); |
365 | /// Any a(string("12345")); |
366 | { |
367 | } |
368 | |
369 | Any(const Any& other): |
370 | _pHolder(other._pHolder ? other._pHolder->clone() : 0) |
371 | /// Copy constructor, works with both empty and initialized Any values. |
372 | { |
373 | } |
374 | |
375 | ~Any() |
376 | { |
377 | delete _pHolder; |
378 | } |
379 | |
380 | Any& swap(Any& rhs) |
381 | /// Swaps the content of the two Anys. |
382 | { |
383 | std::swap(_pHolder, rhs._pHolder); |
384 | return *this; |
385 | } |
386 | |
387 | template <typename ValueType> |
388 | Any& operator = (const ValueType& rhs) |
389 | /// Assignment operator for all types != Any. |
390 | /// |
391 | /// Example: |
392 | /// Any a = 13; |
393 | /// Any a = string("12345"); |
394 | { |
395 | Any(rhs).swap(*this); |
396 | return *this; |
397 | } |
398 | |
399 | Any& operator = (const Any& rhs) |
400 | /// Assignment operator for Any. |
401 | { |
402 | Any(rhs).swap(*this); |
403 | return *this; |
404 | } |
405 | |
406 | bool empty() const |
407 | /// Returns true if the Any is empty. |
408 | { |
409 | return !_pHolder; |
410 | } |
411 | |
412 | const std::type_info& type() const |
413 | /// Returns the type information of the stored content. |
414 | /// If the Any is empty typeid(void) is returned. |
415 | /// It is recommended to always query an Any for its type info before |
416 | /// trying to extract data via an AnyCast/RefAnyCast. |
417 | { |
418 | return _pHolder ? _pHolder->type() : typeid(void); |
419 | } |
420 | |
421 | private: |
422 | class ValueHolder |
423 | { |
424 | public: |
425 | virtual ~ValueHolder() |
426 | { |
427 | } |
428 | |
429 | virtual const std::type_info& type() const = 0; |
430 | virtual ValueHolder* clone() const = 0; |
431 | }; |
432 | |
433 | template <typename ValueType> |
434 | class Holder: public ValueHolder |
435 | { |
436 | public: |
437 | Holder(const ValueType& value): |
438 | _held(value) |
439 | { |
440 | } |
441 | |
442 | virtual const std::type_info& type() const |
443 | { |
444 | return typeid(ValueType); |
445 | } |
446 | |
447 | virtual ValueHolder* clone() const |
448 | { |
449 | return new Holder(_held); |
450 | } |
451 | |
452 | ValueType _held; |
453 | |
454 | private: |
455 | Holder & operator=(const Holder &); |
456 | }; |
457 | |
458 | ValueHolder* content() const |
459 | { |
460 | return _pHolder; |
461 | } |
462 | |
463 | private: |
464 | ValueHolder* _pHolder; |
465 | |
466 | #endif // POCO_NO_SOO |
467 | |
468 | template <typename ValueType> |
469 | friend ValueType* AnyCast(Any*); |
470 | |
471 | template <typename ValueType> |
472 | friend ValueType* UnsafeAnyCast(Any*); |
473 | |
474 | template <typename ValueType> |
475 | friend const ValueType& RefAnyCast(const Any&); |
476 | |
477 | template <typename ValueType> |
478 | friend ValueType& RefAnyCast(Any&); |
479 | |
480 | template <typename ValueType> |
481 | friend ValueType AnyCast(Any&); |
482 | }; |
483 | |
484 | |
485 | template <typename ValueType> |
486 | ValueType* AnyCast(Any* operand) |
487 | /// AnyCast operator used to extract the ValueType from an Any*. Will return a pointer |
488 | /// to the stored value. |
489 | /// |
490 | /// Example Usage: |
491 | /// MyType* pTmp = AnyCast<MyType*>(pAny). |
492 | /// Will return NULL if the cast fails, i.e. types don't match. |
493 | { |
494 | return operand && operand->type() == typeid(ValueType) |
495 | ? &static_cast<Any::Holder<ValueType>*>(operand->content())->_held |
496 | : 0; |
497 | } |
498 | |
499 | |
500 | template <typename ValueType> |
501 | const ValueType* AnyCast(const Any* operand) |
502 | /// AnyCast operator used to extract a const ValueType pointer from an const Any*. Will return a const pointer |
503 | /// to the stored value. |
504 | /// |
505 | /// Example Usage: |
506 | /// const MyType* pTmp = AnyCast<MyType*>(pAny). |
507 | /// Will return NULL if the cast fails, i.e. types don't match. |
508 | { |
509 | return AnyCast<ValueType>(const_cast<Any*>(operand)); |
510 | } |
511 | |
512 | |
513 | template <typename ValueType> |
514 | ValueType AnyCast(Any& operand) |
515 | /// AnyCast operator used to extract a copy of the ValueType from an Any&. |
516 | /// |
517 | /// Example Usage: |
518 | /// MyType tmp = AnyCast<MyType>(anAny). |
519 | /// Will throw a BadCastException if the cast fails. |
520 | /// Do not use an AnyCast in combination with references, i.e. MyType& tmp = ... or const MyType& tmp = ... |
521 | /// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in |
522 | /// these cases. |
523 | { |
524 | typedef typename TypeWrapper<ValueType>::TYPE NonRef; |
525 | |
526 | NonRef* result = AnyCast<NonRef>(&operand); |
527 | if (!result) |
528 | { |
529 | std::string s = "RefAnyCast: Failed to convert between Any types " ; |
530 | if (operand._pHolder) |
531 | { |
532 | s.append(1, '('); |
533 | s.append(operand._pHolder->type().name()); |
534 | s.append(" => " ); |
535 | s.append(typeid(ValueType).name()); |
536 | s.append(1, ')'); |
537 | } |
538 | throw BadCastException(s); |
539 | } |
540 | return *result; |
541 | } |
542 | |
543 | |
544 | template <typename ValueType> |
545 | ValueType AnyCast(const Any& operand) |
546 | /// AnyCast operator used to extract a copy of the ValueType from an const Any&. |
547 | /// |
548 | /// Example Usage: |
549 | /// MyType tmp = AnyCast<MyType>(anAny). |
550 | /// Will throw a BadCastException if the cast fails. |
551 | /// Do not use an AnyCast in combination with references, i.e. MyType& tmp = ... or const MyType& = ... |
552 | /// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in |
553 | /// these cases. |
554 | { |
555 | typedef typename TypeWrapper<ValueType>::TYPE NonRef; |
556 | |
557 | return AnyCast<NonRef&>(const_cast<Any&>(operand)); |
558 | } |
559 | |
560 | |
561 | template <typename ValueType> |
562 | const ValueType& RefAnyCast(const Any & operand) |
563 | /// AnyCast operator used to return a const reference to the internal data. |
564 | /// |
565 | /// Example Usage: |
566 | /// const MyType& tmp = RefAnyCast<MyType>(anAny); |
567 | { |
568 | ValueType* result = AnyCast<ValueType>(const_cast<Any*>(&operand)); |
569 | std::string s = "RefAnyCast: Failed to convert between Any types " ; |
570 | if (operand._pHolder) |
571 | { |
572 | s.append(1, '('); |
573 | s.append(operand._pHolder->type().name()); |
574 | s.append(" => " ); |
575 | s.append(typeid(ValueType).name()); |
576 | s.append(1, ')'); |
577 | } |
578 | return *result; |
579 | } |
580 | |
581 | |
582 | template <typename ValueType> |
583 | ValueType& RefAnyCast(Any& operand) |
584 | /// AnyCast operator used to return a reference to the internal data. |
585 | /// |
586 | /// Example Usage: |
587 | /// MyType& tmp = RefAnyCast<MyType>(anAny); |
588 | { |
589 | ValueType* result = AnyCast<ValueType>(&operand); |
590 | if (!result) |
591 | { |
592 | std::string s = "RefAnyCast: Failed to convert between Any types " ; |
593 | if (operand._pHolder) |
594 | { |
595 | s.append(1, '('); |
596 | s.append(operand._pHolder->type().name()); |
597 | s.append(" => " ); |
598 | s.append(typeid(ValueType).name()); |
599 | s.append(1, ')'); |
600 | } |
601 | throw BadCastException(s); |
602 | } |
603 | return *result; |
604 | } |
605 | |
606 | |
607 | template <typename ValueType> |
608 | ValueType* UnsafeAnyCast(Any* operand) |
609 | /// The "unsafe" versions of AnyCast are not part of the |
610 | /// public interface and may be removed at any time. They are |
611 | /// required where we know what type is stored in the any and can't |
612 | /// use typeid() comparison, e.g., when our types may travel across |
613 | /// different shared libraries. |
614 | { |
615 | return &static_cast<Any::Holder<ValueType>*>(operand->content())->_held; |
616 | } |
617 | |
618 | |
619 | template <typename ValueType> |
620 | const ValueType* UnsafeAnyCast(const Any* operand) |
621 | /// The "unsafe" versions of AnyCast are not part of the |
622 | /// public interface and may be removed at any time. They are |
623 | /// required where we know what type is stored in the any and can't |
624 | /// use typeid() comparison, e.g., when our types may travel across |
625 | /// different shared libraries. |
626 | { |
627 | return AnyCast<ValueType>(const_cast<Any*>(operand)); |
628 | } |
629 | |
630 | |
631 | } // namespace Poco |
632 | |
633 | |
634 | #endif |
635 | |