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