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
26namespace Poco {
27
28
29class Any;
30
31
32namespace Dynamic {
33
34class Var;
35class VarHolder;
36template <class, class Enable = void> class VarHolderImpl;
37
38}
39
40#ifndef POCO_NO_SOO
41
42template <typename PlaceholderT, unsigned int SizeV = POCO_SMALL_OBJECT_SIZE>
43union 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{
53public:
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))
89private:
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
107template <typename PlaceholderT>
108union 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{
118public:
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))
131private:
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
146class 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{
156public:
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
267private:
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
421private:
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
463private:
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
485template <typename ValueType>
486ValueType* 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
500template <typename ValueType>
501const 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
513template <typename ValueType>
514ValueType 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
544template <typename ValueType>
545ValueType 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
561template <typename ValueType>
562const 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
582template <typename ValueType>
583ValueType& 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
607template <typename ValueType>
608ValueType* 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
619template <typename ValueType>
620const 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