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