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 sizeof(BasicValue<T>) > Any::sizeofData ? new BasicValue(_value)
105  : new(data) BasicValue(_value);
106  }
107 
108  virtual bool isRef() const
109  { return false; }
110 
111  virtual void* get()
112  { return &_value; }
113 
114  virtual const void* get() const
115  { return &_value; }
116 
117  private:
118  T _value;
119  };
120 
122  template <typename T>
123  class BasicRefValue : public Value
124  {
125  public:
126  BasicRefValue(T* value)
127  : _value(value)
128  { }
129 
130  virtual const std::type_info& type() const
131  { return typeid(T); }
132 
133  virtual Value* clone(char* data) const
134  { return new(data) BasicRefValue(_value); }
135 
136  virtual bool isRef() const
137  { return true; }
138 
139  virtual void* get()
140  { return (void*) _value; }
141 
142  virtual const void* get() const
143  { return _value; }
144 
145  private:
146  T* _value;
147  };
148 
150  class RefValue : public Value
151  {
152  public:
153  RefValue(void* value, const std::type_info& ti)
154  : _value(value)
155  , _ti(&ti)
156  { }
157 
158  virtual bool isRef() const
159  { return true; }
160 
161  virtual const std::type_info& type() const
162  { return *_ti; }
163 
164  virtual Any::Value* clone(char* data) const
165  { return new(data) RefValue(_value, *_ti); }
166 
167  virtual void* get()
168  { return _value; }
169 
170  virtual const void* get() const
171  { return _value; }
172 
173  private:
174  void* _value;
175  const std::type_info* _ti;
176  };
177 
179  bool dataUsed() const
180  { return static_cast<const void*>(_value) == static_cast<const void*>(_data); }
181 
182  public:
193  template <typename T>
194  Any(const T& type)
195  : _value(0)
196  {
197  _value = sizeof(BasicValue<T>) > Any::sizeofData ? new BasicValue<T>(type)
198  : new(static_cast<void*>(_data)) BasicValue<T>(type);
199  }
200 
210  template <typename T>
211  explicit Any(T* type)
212  : _value(0)
213  {
214  // storage is always large enough for BasicRefValue
215  _value = new(static_cast<void*>(_data)) BasicRefValue<T>(type);
216  }
217 
226  Any(void* type, const std::type_info& ti)
227  : _value(0)
228  {
229  // storage is always large enough for RefValue
230  _value = new(static_cast<void*>(_data)) RefValue(type, ti);
231  }
232 
238  Any()
239  : _value(0)
240  { }
241 
244  Any& assign(Value* value);
245 
255  Any(const Any& val);
256 
263  {
264  if (_value)
265  {
266  if (dataUsed())
267  _value->~Value();
268  else
269  delete _value;
270  }
271  }
272 
279  void clear()
280  {
281  if (_value)
282  {
283  if (dataUsed())
284  _value->~Value();
285  else
286  delete _value;
287  _value = 0;
288  }
289  }
290 
297  inline bool empty() const
298  { return !_value; }
299 
308  Any& swap(Any& other);
309 
311  inline bool isRef() const
312  { return _value && _value->isRef(); }
313 
321  const std::type_info& type() const
322  { return _value ? _value->type() : typeid(void); }
323 
333  template <typename T>
334  Any& operator=(const T& rhs)
335  {
336  clear();
337  _value = sizeof(BasicValue<T>) > Any::sizeofData ? new BasicValue<T>(rhs)
338  : new(static_cast<void*>(_data)) BasicValue<T>(rhs);
339  return *this;
340  }
341 
351  template <typename T>
352  Any& operator=(T* rhs)
353  {
354  clear();
355  _value = new(static_cast<void*>(_data)) BasicRefValue<T>(rhs);
356  return *this;
357  }
358 
368  Any& operator=(const Any& rhs);
369 
372  const Any::Value* value() const
373  { return _value; }
374 
377  Any::Value* value()
378  { return _value; }
379 
388  void* get()
389  {
390  if(_value)
391  return _value->get();
392 
393  return 0;
394  }
395 
404  const void* get() const
405  {
406  if(_value)
407  return _value->get();
408 
409  return 0;
410  }
411 
412  private:
414  static const unsigned sizeofData = sizeof(RefValue);
415 
417  Value* _value;
418 
420  char _data[sizeofData];
421 };
422 
425 template <typename T>
426 struct AnyCast
427 {
428  static T cast(const Any& any)
429  {
430  // NOTE:
431  // - the first if(...) may not work properly on Linux when loading libs,
432  // so there is also a comparison of string names (second if(...))
433  // - but: the name() method necessary for string comparison does not
434  // exist on WinCE, so the second if(...) is not compiled for WinCE
435  typedef typename TypeTraits<T>::Value ValueT;
436 
437  if( any.type() == typeid(ValueT) )
438  {
439  void* v = any._value->get();
440  ValueT* vtp = reinterpret_cast<ValueT*>(v);
441  return *vtp;
442  }
443 
444 #ifndef _WIN32_WCE
445  else if( 0 == std::strcmp(any.type().name(), typeid(ValueT).name() ) )
446  {
447  void* v = any._value->get();
448  ValueT* vtp = reinterpret_cast<ValueT*>(v);
449  return *vtp;
450  }
451 #endif
452 
453  throw std::bad_cast();
454  }
455 };
456 
459 template <typename T>
460 struct AnyCast<T*>
461 {
462  static T* cast(const Any& any)
463  {
464  // NOTE:
465  // - the first if(...) may not work properly on Linux when loading libs,
466  // so there is also a comparison of string names (second if(...))
467  // - but: the name() method necessary for string comparison does not
468  // exist on WinCE, so the second if(...) is not compiled for WinCE
469  typedef typename TypeTraits<T>::Value ValueT;
470 
471  if( any.type() == typeid(ValueT) )
472  {
473  void* v = any._value->get();
474  ValueT* vtp = reinterpret_cast<ValueT*>(v);
475  return vtp;
476  }
477 
478 #ifndef _WIN32_WCE
479  else if( 0 == std::strcmp(any.type().name(), typeid(ValueT).name() ) )
480  {
481  void* v = any._value->get();
482  ValueT* vtp = reinterpret_cast<ValueT*>(v);
483  return vtp;
484  }
485 #endif
486 
487  throw std::bad_cast();
488  }
489 };
490 
502 template <typename T>
503 inline T any_cast(const Any& any)
504 {
505  return AnyCast<T>::cast(any);
506 }
507 
508 
509 inline Any& Any::assign(Value* value)
510 {
511  clear();
512  _value = value->clone(_data);
513  return *this;
514 }
515 
516 
517 inline Any::Any(const Any& val)
518 : _value(0)
519 {
520  if (val._value)
521  _value = val._value->clone(_data);
522 }
523 
524 
525 inline Any& Any::swap(Any& rhs)
526 {
527  if (dataUsed())
528  {
529  if (rhs.dataUsed())
530  {
531  Any tmp(*this);
532  *this = rhs;
533  rhs = tmp;
534  }
535  else
536  {
537  Value* tmp = _value;
538  _value = rhs._value;
539  rhs._value = tmp->clone(rhs._data);
540  tmp->~Value();
541  }
542  }
543  else
544  {
545  if (rhs.dataUsed())
546  {
547  Value* tmp = rhs._value;
548  rhs._value = _value;
549  _value = tmp->clone(_data);
550  tmp->~Value();
551  }
552  else
553  {
554  Value* tmp = rhs._value;
555  rhs._value = _value;
556  _value = tmp;
557  }
558  }
559 
560  return *this;
561 }
562 
563 
564 inline Any& Any::operator=(const Any& rhs)
565 {
566  clear();
567 
568  if (rhs._value)
569  _value = rhs._value->clone(_data);
570 
571  return *this;
572 }
573 
574 } // namespace xxx
575 
576 #endif
Any & swap(Any &other)
Swap values.
Definition: Any.h:525
Any(T *type)
Construct with reference.
Definition: Any.h:211
void clear()
Clear content.
Definition: Any.h:279
Any(void *type, const std::type_info &ti)
Construct with reference.
Definition: Any.h:226
const std::type_info & type() const
Returns type info of assigned type.
Definition: Any.h:321
Any()
Default constructor.
Definition: Any.h:238
bool empty() const
Check if empty.
Definition: Any.h:297
bool isRef() const
Returns true if Any contains a weak reference.
Definition: Any.h:311
T any_cast(const Any &any)
Get contained value.
Definition: Any.h:503
Any & operator=(const T &rhs)
Assign value.
Definition: Any.h:334
Any(const T &type)
Construct with value.
Definition: Any.h:194
Contains an arbitrary type.
Definition: Any.h:63
~Any()
Destructor.
Definition: Any.h:262
Any & operator=(T *rhs)
Assign reference.
Definition: Any.h:352