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 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> 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};
475
476
477template <typename ValueType>
478ValueType* AnyCast(Any* operand)
479 /// AnyCast operator used to extract the ValueType from an Any*. Will return a pointer
480 /// to the stored value.
481 ///
482 /// Example Usage:
483 /// MyType* pTmp = AnyCast<MyType*>(pAny).
484 /// Will return NULL if the cast fails, i.e. types don't match.
485{
486 return operand && operand->type() == typeid(ValueType)
487 ? &static_cast<Any::Holder<ValueType>*>(operand->content())->_held
488 : 0;
489}
490
491
492template <typename ValueType>
493const ValueType* AnyCast(const Any* operand)
494 /// AnyCast operator used to extract a const ValueType pointer from an const Any*. Will return a const pointer
495 /// to the stored value.
496 ///
497 /// Example Usage:
498 /// const MyType* pTmp = AnyCast<MyType*>(pAny).
499 /// Will return NULL if the cast fails, i.e. types don't match.
500{
501 return AnyCast<ValueType>(const_cast<Any*>(operand));
502}
503
504
505template <typename ValueType>
506ValueType AnyCast(Any& operand)
507 /// AnyCast operator used to extract a copy of the ValueType from an Any&.
508 ///
509 /// Example Usage:
510 /// MyType tmp = AnyCast<MyType>(anAny).
511 /// Will throw a BadCastException if the cast fails.
512 /// Do not use an AnyCast in combination with references, i.e. MyType& tmp = ... or const MyType& tmp = ...
513 /// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in
514 /// these cases.
515{
516 typedef typename TypeWrapper<ValueType>::TYPE NonRef;
517
518 NonRef* result = AnyCast<NonRef>(&operand);
519 if (!result) throw BadCastException("Failed to convert between Any types");
520 return *result;
521}
522
523
524template <typename ValueType>
525ValueType AnyCast(const Any& operand)
526 /// AnyCast operator used to extract a copy of the ValueType from an const Any&.
527 ///
528 /// Example Usage:
529 /// MyType tmp = AnyCast<MyType>(anAny).
530 /// Will throw a BadCastException if the cast fails.
531 /// Do not use an AnyCast in combination with references, i.e. MyType& tmp = ... or const MyType& = ...
532 /// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in
533 /// these cases.
534{
535 typedef typename TypeWrapper<ValueType>::TYPE NonRef;
536
537 return AnyCast<NonRef&>(const_cast<Any&>(operand));
538}
539
540
541template <typename ValueType>
542const ValueType& RefAnyCast(const Any & operand)
543 /// AnyCast operator used to return a const reference to the internal data.
544 ///
545 /// Example Usage:
546 /// const MyType& tmp = RefAnyCast<MyType>(anAny);
547{
548 ValueType* result = AnyCast<ValueType>(const_cast<Any*>(&operand));
549 if (!result) throw BadCastException("RefAnyCast: Failed to convert between const Any types");
550 return *result;
551}
552
553
554template <typename ValueType>
555ValueType& RefAnyCast(Any& operand)
556 /// AnyCast operator used to return a reference to the internal data.
557 ///
558 /// Example Usage:
559 /// MyType& tmp = RefAnyCast<MyType>(anAny);
560{
561 ValueType* result = AnyCast<ValueType>(&operand);
562 if (!result) throw BadCastException("RefAnyCast: Failed to convert between Any types");
563 return *result;
564}
565
566
567template <typename ValueType>
568ValueType* UnsafeAnyCast(Any* operand)
569 /// The "unsafe" versions of AnyCast are not part of the
570 /// public interface and may be removed at any time. They are
571 /// required where we know what type is stored in the any and can't
572 /// use typeid() comparison, e.g., when our types may travel across
573 /// different shared libraries.
574{
575 return &static_cast<Any::Holder<ValueType>*>(operand->content())->_held;
576}
577
578
579template <typename ValueType>
580const ValueType* UnsafeAnyCast(const Any* operand)
581 /// The "unsafe" versions of AnyCast are not part of the
582 /// public interface and may be removed at any time. They are
583 /// required where we know what type is stored in the any and can't
584 /// use typeid() comparison, e.g., when our types may travel across
585 /// different shared libraries.
586{
587 return AnyCast<ValueType>(const_cast<Any*>(operand));
588}
589
590
591} // namespace Poco
592
593
594#endif
595