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 
37 namespace Pt {
38 
63 class Any
64 {
65  template <typename T>
66  friend T any_cast(const Any&);
67 
68  template <typename T>
69  friend struct AnyCast;
70 
71  public:
73  class Value
74  {
75  public:
76  virtual ~Value() {}
77  virtual Value* clone(char*) const = 0;
78  virtual const std::type_info& type() const = 0;
79  virtual bool isRef() const = 0;
80  virtual void* get() = 0;
81  virtual const void* get() const = 0;
82  };
83 
85  template <typename T>
86  class BasicValue : public Value
87  {
88  public:
89  BasicValue(const T& value = T())
90  : _value(value)
91  { }
92 
93  const T& value() const
94  { return _value;}
95 
96  T& value()
97  { return _value;}
98 
99  virtual const std::type_info& type() const
100  { return typeid(T); }
101 
102  virtual Value* clone(char* data) const
103  {
104  return Any::cloneValue(_value, data);
105  }
106 
107  virtual bool isRef() const
108  { return false; }
109 
110  virtual void* get()
111  { return &_value; }
112 
113  virtual const void* get() const
114  { return &_value; }
115 
116  private:
117  T _value;
118  };
119 
121  template <typename T>
122  class BasicRefValue : public Value
123  {
124  public:
125  BasicRefValue(T* value)
126  : _value(value)
127  { }
128 
129  virtual const std::type_info& type() const
130  { return typeid(T); }
131 
132  virtual Value* clone(char* data) const
133  { return new(data) BasicRefValue(_value); }
134 
135  virtual bool isRef() const
136  { return true; }
137 
138  virtual void* get()
139  { return (void*) _value; }
140 
141  virtual const void* get() const
142  { return _value; }
143 
144  private:
145  T* _value;
146  };
147 
149  class RefValue : public Value
150  {
151  public:
152  RefValue(void* value, const std::type_info& ti)
153  : _value(value)
154  , _ti(&ti)
155  { }
156 
157  virtual bool isRef() const
158  { return true; }
159 
160  virtual const std::type_info& type() const
161  { return *_ti; }
162 
163  virtual Any::Value* clone(char* data) const
164  { return new(data) RefValue(_value, *_ti); }
165 
166  virtual void* get()
167  { return _value; }
168 
169  virtual const void* get() const
170  { return _value; }
171 
172  private:
173  void* _value;
174  const std::type_info* _ti;
175  };
176 
178  bool dataUsed() const
179  { return static_cast<const void*>(_value) == static_cast<const void*>(_data); }
180 
181  public:
192  template <typename T>
193  Any(const T& type)
194  : _value(0)
195  {
196  _value = this->createValue(type);
197  }
198 
208  template <typename T>
209  explicit Any(T* type)
210  : _value(0)
211  {
212  // storage is always large enough for BasicRefValue
213  _value = new(static_cast<void*>(_data)) BasicRefValue<T>(type);
214  }
215 
224  Any(void* type, const std::type_info& ti)
225  : _value(0)
226  {
227  // storage is always large enough for RefValue
228  _value = new(static_cast<void*>(_data)) RefValue(type, ti);
229  }
230 
236  Any()
237  : _value(0)
238  { }
239 
242  Any& assign(Value* value);
243 
253  Any(const Any& val);
254 
261  {
262  if (_value)
263  {
264  if (dataUsed())
265  _value->~Value();
266  else
267  delete _value;
268  }
269  }
270 
277  void clear()
278  {
279  if (_value)
280  {
281  if (dataUsed())
282  _value->~Value();
283  else
284  delete _value;
285  _value = 0;
286  }
287  }
288 
295  inline bool empty() const
296  { return !_value; }
297 
306  Any& swap(Any& other);
307 
309  inline bool isRef() const
310  { return _value && _value->isRef(); }
311 
319  const std::type_info& type() const
320  { return _value ? _value->type() : typeid(void); }
321 
331  template <typename T>
332  Any& operator=(const T& rhs)
333  {
334  clear();
335  _value = this->createValue(rhs);
336  return *this;
337  }
338 
348  template <typename T>
349  Any& operator=(T* rhs)
350  {
351  clear();
352  _value = new(static_cast<void*>(_data)) BasicRefValue<T>(rhs);
353  return *this;
354  }
355 
365  Any& operator=(const Any& rhs);
366 
369  const Any::Value* value() const
370  { return _value; }
371 
374  Any::Value* value()
375  { return _value; }
376 
385  void* get()
386  {
387  if(_value)
388  return _value->get();
389 
390  return 0;
391  }
392 
401  const void* get() const
402  {
403  if(_value)
404  return _value->get();
405 
406  return 0;
407  }
408 
409  private:
411  static const unsigned sizeofData = sizeof(RefValue);
412 
413  template <typename T>
414  struct IsSmallObject : BoolConstant< sizeof(BasicValue<T>) <= Any::sizeofData >
415  {
416  };
417 
418  template <typename T>
419  static Value* cloneValue(const T& value, char* data);
420 
421  template <typename T>
422  static Value* cloneValue(const T& value, char* data, TrueType);
423 
424  template <typename T>
425  static Value* cloneValue(const T& value, char* data, FalseType);
426 
427  template <typename T>
428  Value* createValue(const T& value);
429 
430  template <typename T>
431  Value* createValue(const T& value, TrueType);
432 
433  template <typename T>
434  Value* createValue(const T& value, FalseType);
435 
436  private:
438  Value* _value;
439 
441  alignas(Value) char _data[sizeofData];
442 };
443 
444 template <typename T>
445 inline Any::Value* Any::cloneValue(const T& value, char* data)
446 {
447  return Any::cloneValue(value, data, IsSmallObject<T>());
448 }
449 
450 template <typename T>
451 inline Any::Value* Any::cloneValue(const T& value, char* data, TrueType)
452 {
453  return new(data) BasicValue<T>(value);
454 }
455 
456 template <typename T>
457 inline Any::Value* Any::cloneValue(const T& value, char*, FalseType)
458 {
459  return new BasicValue<T>(value);
460 }
461 
462 template <typename T>
463 inline Any::Value* Any::createValue(const T& value)
464 {
465  return this->createValue(value, IsSmallObject<T>());
466 }
467 
468 template <typename T>
469 inline Any::Value* Any::createValue(const T& value, TrueType)
470 {
471  return new(static_cast<void*>(_data)) BasicValue<T>(value);
472 }
473 
474 template <typename T>
475 inline Any::Value* Any::createValue(const T& value, FalseType)
476 {
477  return new BasicValue<T>(value);
478 }
479 
482 template <typename T>
483 struct AnyCast
484 {
485  static T cast(const Any& any)
486  {
487  // NOTE:
488  // - the first if(...) may not work properly on Linux when loading libs,
489  // so there is also a comparison of string names (second if(...))
490  // - but: the name() method necessary for string comparison does not
491  // exist on WinCE, so the second if(...) is not compiled for WinCE
492  typedef typename TypeTraits<T>::Value ValueT;
493 
494  if( any.type() == typeid(ValueT) )
495  {
496  void* v = any._value->get();
497  ValueT* vtp = reinterpret_cast<ValueT*>(v);
498  return *vtp;
499  }
500 
501 #ifndef _WIN32_WCE
502  else if( 0 == std::strcmp(any.type().name(), typeid(ValueT).name() ) )
503  {
504  void* v = any._value->get();
505  ValueT* vtp = reinterpret_cast<ValueT*>(v);
506  return *vtp;
507  }
508 #endif
509 
510  throw std::bad_cast();
511  }
512 };
513 
516 template <typename T>
517 struct AnyCast<T*>
518 {
519  static T* cast(const Any& any)
520  {
521  // NOTE:
522  // - the first if(...) may not work properly on Linux when loading libs,
523  // so there is also a comparison of string names (second if(...))
524  // - but: the name() method necessary for string comparison does not
525  // exist on WinCE, so the second if(...) is not compiled for WinCE
526  typedef typename TypeTraits<T>::Value ValueT;
527 
528  if( any.type() == typeid(ValueT) )
529  {
530  void* v = any._value->get();
531  ValueT* vtp = reinterpret_cast<ValueT*>(v);
532  return vtp;
533  }
534 
535 #ifndef _WIN32_WCE
536  else if( 0 == std::strcmp(any.type().name(), typeid(ValueT).name() ) )
537  {
538  void* v = any._value->get();
539  ValueT* vtp = reinterpret_cast<ValueT*>(v);
540  return vtp;
541  }
542 #endif
543 
544  throw std::bad_cast();
545  }
546 };
547 
559 template <typename T>
560 inline T any_cast(const Any& any)
561 {
562  return AnyCast<T>::cast(any);
563 }
564 
565 
566 inline Any& Any::assign(Value* value)
567 {
568  clear();
569  _value = value->clone(_data);
570  return *this;
571 }
572 
573 
574 inline Any::Any(const Any& val)
575 : _value(0)
576 {
577  if (val._value)
578  _value = val._value->clone(_data);
579 }
580 
581 
582 inline Any& Any::swap(Any& rhs)
583 {
584  if (dataUsed())
585  {
586  if (rhs.dataUsed())
587  {
588  Any tmp(*this);
589  *this = rhs;
590  rhs = tmp;
591  }
592  else
593  {
594  Value* tmp = _value;
595  _value = rhs._value;
596  rhs._value = tmp->clone(rhs._data);
597  tmp->~Value();
598  }
599  }
600  else
601  {
602  if (rhs.dataUsed())
603  {
604  Value* tmp = rhs._value;
605  rhs._value = _value;
606  _value = tmp->clone(_data);
607  tmp->~Value();
608  }
609  else
610  {
611  Value* tmp = rhs._value;
612  rhs._value = _value;
613  _value = tmp;
614  }
615  }
616 
617  return *this;
618 }
619 
620 
621 inline Any& Any::operator=(const Any& rhs)
622 {
623  clear();
624 
625  if (rhs._value)
626  _value = rhs._value->clone(_data);
627 
628  return *this;
629 }
630 
631 } // namespace
632 
633 #endif
Core module.
Definition: Allocator.h:33
void * get()
Get pointer to stored value.
Definition: Any.h:385
const void * get() const
Get pointer to stored value.
Definition: Any.h:401
Any(const T &type)
Construct with value.
Definition: Any.h:193
void clear()
Clear content.
Definition: Any.h:277
Any & operator=(const T &rhs)
Assign value.
Definition: Any.h:332
bool empty() const
Check if empty.
Definition: Any.h:295
const std::type_info & type() const
Returns type info of assigned type.
Definition: Any.h:319
IMPLEMENTATION_DEFINED Value
The derived value type.
Definition: Api-TypeTraits.h:22
Any(void *type, const std::type_info &ti)
Construct with reference.
Definition: Any.h:224
~Any()
Destructor.
Definition: Any.h:260
bool isRef() const
Returns true if Any contains a weak reference.
Definition: Any.h:309
Any()
Default constructor.
Definition: Any.h:236
Any(T *type)
Construct with reference.
Definition: Any.h:209
T any_cast(const Any &any)
Get contained value.
Definition: Any.h:560
Contains an arbitrary type.
Definition: Any.h:64
Any & operator=(T *rhs)
Assign reference.
Definition: Any.h:349
Any & swap(Any &other)
Swap values.
Definition: Any.h:582