Any.h
1/*
2 * Copyright (C) 2004-2011 by Marc Boris Duerner
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * As a special exception, you may use this file as part of a free
10 * software library without restriction. Specifically, if other files
11 * instantiate templates or use macros or inline functions from this
12 * file, or you compile this file and link it with other files to
13 * produce an executable, this file does not by itself cause the
14 * resulting executable to be covered by the GNU General Public
15 * License. This exception does not however invalidate any other
16 * reasons why the executable file might be covered by the GNU Library
17 * General Public License.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 */
28
29#ifndef Pt_Any_h
30#define Pt_Any_h
31
32#include <Pt/TypeTraits.h>
33#include <typeinfo>
34#include <cstring>
35#include <new>
36
37namespace Pt {
38
78class Any
79{
80 template <typename T>
81 friend T any_cast(const Any&);
82
83 template <typename T>
84 friend struct AnyCast;
85
86 public:
88 class Value
89 {
90 public:
91 virtual ~Value() {}
92 virtual Value* clone(char*) const = 0;
93 virtual const std::type_info& type() const = 0;
94 virtual bool isRef() const = 0;
95 virtual void* get() = 0;
96 virtual const void* get() const = 0;
97 };
98
100 template <typename T>
101 class BasicValue : public Value
102 {
103 public:
104 BasicValue(const T& value = T())
105 : _value(value)
106 { }
107
108 const T& value() const
109 { return _value;}
110
111 T& value()
112 { return _value;}
113
114 virtual const std::type_info& type() const
115 { return typeid(T); }
116
117 virtual Value* clone(char* data) const
118 {
119 return Any::cloneValue(_value, data);
120 }
121
122 virtual bool isRef() const
123 { return false; }
124
125 virtual void* get()
126 { return &_value; }
127
128 virtual const void* get() const
129 { return &_value; }
130
131 private:
132 T _value;
133 };
134
136 template <typename T>
137 class BasicRefValue : public Value
138 {
139 public:
140 BasicRefValue(T* value)
141 : _value(value)
142 { }
143
144 virtual const std::type_info& type() const
145 { return typeid(T); }
146
147 virtual Value* clone(char* data) const
148 { return new(data) BasicRefValue(_value); }
149
150 virtual bool isRef() const
151 { return true; }
152
153 virtual void* get()
154 { return (void*) _value; }
155
156 virtual const void* get() const
157 { return _value; }
158
159 private:
160 T* _value;
161 };
162
164 class RefValue : public Value
165 {
166 public:
167 RefValue(void* value, const std::type_info& ti)
168 : _value(value)
169 , _ti(&ti)
170 { }
171
172 virtual bool isRef() const
173 { return true; }
174
175 virtual const std::type_info& type() const
176 { return *_ti; }
177
178 virtual Any::Value* clone(char* data) const
179 { return new(data) RefValue(_value, *_ti); }
180
181 virtual void* get()
182 { return _value; }
183
184 virtual const void* get() const
185 { return _value; }
186
187 private:
188 void* _value;
189 const std::type_info* _ti;
190 };
191
193 bool dataUsed() const
194 { return static_cast<const void*>(_value) == static_cast<const void*>(_data); }
195
196 public:
207 template <typename T>
208 Any(const T& type)
209 : _value(0)
210 {
211 _value = this->createValue(type);
212 }
213
223 template <typename T>
224 explicit Any(T* type)
225 : _value(0)
226 {
227 // storage is always large enough for BasicRefValue
228 _value = new(static_cast<void*>(_data)) BasicRefValue<T>(type);
229 }
230
239 Any(void* type, const std::type_info& ti)
240 : _value(0)
241 {
242 // storage is always large enough for RefValue
243 _value = new(static_cast<void*>(_data)) RefValue(type, ti);
244 }
245
252 : _value(0)
253 { }
254
257 Any& assign(Value* value);
258
268 Any(const Any& val);
269
276 {
277 if (_value)
278 {
279 if (dataUsed())
280 _value->~Value();
281 else
282 delete _value;
283 }
284 }
285
292 void clear()
293 {
294 if (_value)
295 {
296 if (dataUsed())
297 _value->~Value();
298 else
299 delete _value;
300 _value = 0;
301 }
302 }
303
310 inline bool empty() const
311 { return !_value; }
312
321 Any& swap(Any& other);
322
324 inline bool isRef() const
325 { return _value && _value->isRef(); }
326
334 const std::type_info& type() const
335 { return _value ? _value->type() : typeid(void); }
336
346 template <typename T>
347 Any& operator=(const T& rhs)
348 {
349 clear();
350 _value = this->createValue(rhs);
351 return *this;
352 }
353
363 template <typename T>
364 Any& operator=(T* rhs)
365 {
366 clear();
367 _value = new(static_cast<void*>(_data)) BasicRefValue<T>(rhs);
368 return *this;
369 }
370
380 Any& operator=(const Any& rhs);
381
384 const Any::Value* value() const
385 { return _value; }
386
389 Any::Value* value()
390 { return _value; }
391
400 void* get()
401 {
402 if(_value)
403 return _value->get();
404
405 return 0;
406 }
407
416 const void* get() const
417 {
418 if(_value)
419 return _value->get();
420
421 return 0;
422 }
423
424 private:
426 static const unsigned sizeofData = sizeof(RefValue);
427
428 template <typename T>
429 struct IsSmallObject : BoolConstant< sizeof(BasicValue<T>) <= Any::sizeofData >
430 {
431 };
432
433 template <typename T>
434 static Value* cloneValue(const T& value, char* data);
435
436 template <typename T>
437 static Value* cloneValue(const T& value, char* data, TrueType);
438
439 template <typename T>
440 static Value* cloneValue(const T& value, char* data, FalseType);
441
442 template <typename T>
443 Value* createValue(const T& value);
444
445 template <typename T>
446 Value* createValue(const T& value, TrueType);
447
448 template <typename T>
449 Value* createValue(const T& value, FalseType);
450
451 private:
453 Value* _value;
454
456 alignas(Value) char _data[sizeofData];
457};
458
459template <typename T>
460inline Any::Value* Any::cloneValue(const T& value, char* data)
461{
462 return Any::cloneValue(value, data, IsSmallObject<T>());
463}
464
465template <typename T>
466inline Any::Value* Any::cloneValue(const T& value, char* data, TrueType)
467{
468 return new(data) BasicValue<T>(value);
469}
470
471template <typename T>
472inline Any::Value* Any::cloneValue(const T& value, char*, FalseType)
473{
474 return new BasicValue<T>(value);
475}
476
477template <typename T>
478inline Any::Value* Any::createValue(const T& value)
479{
480 return this->createValue(value, IsSmallObject<T>());
481}
482
483template <typename T>
484inline Any::Value* Any::createValue(const T& value, TrueType)
485{
486 return new(static_cast<void*>(_data)) BasicValue<T>(value);
487}
488
489template <typename T>
490inline Any::Value* Any::createValue(const T& value, FalseType)
491{
492 return new BasicValue<T>(value);
493}
494
497template <typename T>
498struct AnyCast
499{
500 static T cast(const Any& any)
501 {
502 // NOTE:
503 // - the first if(...) may not work properly on Linux when loading libs,
504 // so there is also a comparison of string names (second if(...))
505 // - but: the name() method necessary for string comparison does not
506 // exist on WinCE, so the second if(...) is not compiled for WinCE
507 typedef typename TypeTraits<T>::Value ValueT;
508
509 if( any.type() == typeid(ValueT) )
510 {
511 void* v = any._value->get();
512 ValueT* vtp = reinterpret_cast<ValueT*>(v);
513 return *vtp;
514 }
515
516#ifndef _WIN32_WCE
517 else if( 0 == std::strcmp(any.type().name(), typeid(ValueT).name() ) )
518 {
519 void* v = any._value->get();
520 ValueT* vtp = reinterpret_cast<ValueT*>(v);
521 return *vtp;
522 }
523#endif
524
525 throw std::bad_cast();
526 }
527};
528
531template <typename T>
532struct AnyCast<T*>
533{
534 static T* cast(const Any& any)
535 {
536 // NOTE:
537 // - the first if(...) may not work properly on Linux when loading libs,
538 // so there is also a comparison of string names (second if(...))
539 // - but: the name() method necessary for string comparison does not
540 // exist on WinCE, so the second if(...) is not compiled for WinCE
541 typedef typename TypeTraits<T>::Value ValueT;
542
543 if( any.type() == typeid(ValueT) )
544 {
545 void* v = any._value->get();
546 ValueT* vtp = reinterpret_cast<ValueT*>(v);
547 return vtp;
548 }
549
550#ifndef _WIN32_WCE
551 else if( 0 == std::strcmp(any.type().name(), typeid(ValueT).name() ) )
552 {
553 void* v = any._value->get();
554 ValueT* vtp = reinterpret_cast<ValueT*>(v);
555 return vtp;
556 }
557#endif
558
559 throw std::bad_cast();
560 }
561};
562
570template <typename T>
571inline T any_cast(const Any& any)
572{
573 return AnyCast<T>::cast(any);
574}
575
576
577inline Any& Any::assign(Value* value)
578{
579 clear();
580 _value = value->clone(_data);
581 return *this;
582}
583
584
585inline Any::Any(const Any& val)
586: _value(0)
587{
588 if (val._value)
589 _value = val._value->clone(_data);
590}
591
592
593inline Any& Any::swap(Any& rhs)
594{
595 if (dataUsed())
596 {
597 if (rhs.dataUsed())
598 {
599 Any tmp(*this);
600 *this = rhs;
601 rhs = tmp;
602 }
603 else
604 {
605 Value* tmp = _value;
606 _value = rhs._value;
607 rhs._value = tmp->clone(rhs._data);
608 tmp->~Value();
609 }
610 }
611 else
612 {
613 if (rhs.dataUsed())
614 {
615 Value* tmp = rhs._value;
616 rhs._value = _value;
617 _value = tmp->clone(_data);
618 tmp->~Value();
619 }
620 else
621 {
622 Value* tmp = rhs._value;
623 rhs._value = _value;
624 _value = tmp;
625 }
626 }
627
628 return *this;
629}
630
631
632inline Any& Any::operator=(const Any& rhs)
633{
634 clear();
635
636 if (rhs._value)
637 _value = rhs._value->clone(_data);
638
639 return *this;
640}
641
642} // namespace
643
644#endif
Value of any copyable type.
Definition Any.h:79
Any()
Default constructor.
Definition Any.h:251
const void * get() const
Get pointer to stored value.
Definition Any.h:416
Any & operator=(T *rhs)
Assign reference.
Definition Any.h:364
Any(const T &type)
Construct with value.
Definition Any.h:208
bool empty() const
Check if empty.
Definition Any.h:310
~Any()
Destructor.
Definition Any.h:275
const std::type_info & type() const
Returns type info of assigned type.
Definition Any.h:334
bool isRef() const
Returns true if Any contains a weak reference.
Definition Any.h:324
void * get()
Get pointer to stored value.
Definition Any.h:400
Any & operator=(const T &rhs)
Assign value.
Definition Any.h:347
Any(T *type)
Construct with reference.
Definition Any.h:224
Any(void *type, const std::type_info &ti)
Construct with reference.
Definition Any.h:239
void clear()
Clear content.
Definition Any.h:292
T any_cast(const Any &any)
Returns the value stored in any as type T.
Definition Any.h:571
Any & swap(Any &other)
Swap values.
Definition Any.h:593
void swap(String &a, String &b)
Swaps two strings.
Definition Api-String.h:778
Core module.
Definition Allocator.h:33
IMPLEMENTATION_DEFINED Value
The derived value type.
Definition Api-TypeTraits.h:40