siplasplas
A library for C++ reflection and introspection
simpleany.hpp
1 #ifndef SIPLASPLAS_TYPEERASURE_SIPLEANY_HPP
2 #define SIPLASPLAS_TYPEERASURE_SIPLEANY_HPP
3 
4 #include "typeinfo.hpp"
5 #include "anystorage/deadpool.hpp"
6 #include "anystorage/nonowning.hpp"
7 #include "logger.hpp"
8 #include <siplasplas/utility/assert.hpp>
9 #include <cstdint>
10 
11 namespace cpp
12 {
13 
14 template<typename Storage>
15 class SimpleAny;
16 
17 template<>
19 
20 template<>
21 class SimpleAny<cpp::ConstNonOwningStorage>;
22 
23 
30 template<typename LhsStorage, typename RhsStorage>
31 bool sameType(const SimpleAny<LhsStorage>& lhs, const SimpleAny<RhsStorage>& rhs)
32 {
33  return lhs.typeInfo() == rhs.typeInfo();
34 }
35 
40 template<>
42 {
43 public:
44  struct EmptyTag {};
45 
46  SimpleAny() :
47  ConstNonOwningStorage{nullptr},
48  _typeInfo{cpp::typeerasure::TypeInfo::get<EmptyTag>()}
49  {}
50 
58  bool empty() const
59  {
60  return hasType<EmptyTag>();
61  }
62 
63  template<typename T>
64  SimpleAny(const T& value) :
65  ConstNonOwningStorage(&value),
66  _typeInfo{cpp::typeerasure::TypeInfo::get<T>()}
67  {}
68 
69  SimpleAny(const void* object, const cpp::typeerasure::TypeInfo& typeInfo) :
70  ConstNonOwningStorage{object},
71  _typeInfo{typeInfo}
72  {}
73 
78  template<typename T>
79  static SimpleAny create(const T& value)
80  {
81  return SimpleAny(value);
82  }
83 
89  template<typename T>
90  bool hasType() const
91  {
92  return cpp::typeerasure::TypeInfo::get<T>() == _typeInfo;
93  }
94 
101  template<typename T>
102  const std::decay_t<T>& get() const
103  {
105 #ifdef SIPLASPLAS_TYPEERASURE_SIMPLEANY_TYPECHECKS
106  SIPLASPLAS_ASSERT_TRUE(hasType<std::decay_t<T>>())("SimpleAny has type '{}', requested '{}' instead", typeInfo().typeName(), ctti::type_id<std::decay_t<T>>().name());
107 #endif
108  return *reinterpret_cast<const std::decay_t<T>*>(ConstNonOwningStorage::storage(_typeInfo));
109  }
110 
115  {
116  return _typeInfo;
117  }
118 
129  template<typename T>
130  SimpleAny& operator=(const T& value)
131  {
132  if(!hasType<T>())
133  {
134  _typeInfo = cpp::typeerasure::TypeInfo::get<T>();
136  }
137  else
138  {
139  _typeInfo.copyAssign(ConstNonOwningStorage::storage(_typeInfo), &value);
140  }
141 
142  return *this;
143  }
144 
149  {
150  return *static_cast<const ConstNonOwningStorage*>(this);
151  }
152 
153 private:
154  cpp::typeerasure::TypeInfo _typeInfo;
155 };
156 
161 template<>
163 {
164 public:
165  struct EmptyTag {};
166 
167  SimpleAny() :
168  NonOwningStorage{nullptr},
169  _typeInfo{cpp::typeerasure::TypeInfo::get<EmptyTag>()}
170  {}
171 
179  bool empty() const
180  {
181  return hasType<EmptyTag>();
182  }
183 
184  template<typename T>
185  SimpleAny(T& value) :
186  NonOwningStorage(const_cast<std::decay_t<T>*>(&value)),
187  _typeInfo{cpp::typeerasure::TypeInfo::get<std::decay_t<T>>()}
188  {}
189 
190  SimpleAny(void* object, const cpp::typeerasure::TypeInfo& typeInfo) :
191  NonOwningStorage{object},
192  _typeInfo{typeInfo}
193  {}
194 
199  template<typename T>
200  static SimpleAny create(const T& value)
201  {
202  return SimpleAny(value);
203  }
204 
210  template<typename T>
211  bool hasType() const
212  {
213  return cpp::typeerasure::TypeInfo::get<T>() == _typeInfo;
214  }
215 
222  template<typename T>
223  const std::decay_t<T>& get() const
224  {
226 #ifdef SIPLASPLAS_TYPEERASURE_SIMPLEANY_TYPECHECKS
227  SIPLASPLAS_ASSERT_TRUE(hasType<std::decay_t<T>>())("SimpleAny has type '{}', requested '{}' instead", typeInfo().typeName(), ctti::type_id<std::decay_t<T>>().name());
228 #endif
229  return *reinterpret_cast<const std::decay_t<T>*>(NonOwningStorage::storage(_typeInfo));
230  }
231 
238  template<typename T>
239  std::decay_t<T>& get()
240  {
242 #ifdef SIPLASPLAS_TYPEERASURE_SIMPLEANY_TYPECHECKS
243  SIPLASPLAS_ASSERT_TRUE(hasType<std::decay_t<T>>())("SimpleAny has type '{}', requested '{}' instead", typeInfo().typeName(), ctti::type_id<std::decay_t<T>>().name());
244 #endif
245  return *reinterpret_cast<std::decay_t<T>*>(NonOwningStorage::storage(_typeInfo));
246  }
247 
252  {
253  return _typeInfo;
254  }
255 
266  template<typename T>
267  SimpleAny& operator=(T& value)
268  {
269  if(!hasType<T>())
270  {
271  _typeInfo = cpp::typeerasure::TypeInfo::get<T>();
272  NonOwningStorage::rebind(&value);
273  }
274  else
275  {
276  _typeInfo.copyAssign(NonOwningStorage::storage(_typeInfo), &value);
277  }
278 
279  return *this;
280  }
281 
292  template<typename T>
293  SimpleAny& operator=(T&& value)
294  {
295  if(!hasType<std::decay_t<T>>())
296  {
297  throw cpp::exception<std::runtime_error>(
298  "Cannot assign an rvalue of type {} to an lvalue reference of type {}",
299  ctti::type_id(value).name(),
300  _typeInfo.typeName()
301  );
302  }
303  else
304  {
305  get<std::decay_t<T>>() = std::move(value);
306  return *this;
307  }
308  }
309 
314  {
315  return *static_cast<const NonOwningStorage*>(this);
316  }
317 
318 private:
319  cpp::typeerasure::TypeInfo _typeInfo;
320 };
321 
347 template<typename Storage>
348 class SimpleAny : protected Storage
349 {
350 public:
354  struct EmptyTag {};
355 
368  template<typename T, typename... Args>
369  static SimpleAny create(Args&&... args)
370  {
371  return SimpleAny{meta::identity<T>(), std::forward<Args>(args)...};
372  }
373 
378  _typeInfo{cpp::typeerasure::TypeInfo::get<EmptyTag>()}
379  {}
380 
388  bool empty() const
389  {
390  return hasType<EmptyTag>();
391  }
392 
400  template<typename T, typename = std::enable_if_t<
401  !std::is_base_of<
402  SimpleAny,
403  std::decay_t<T>
404  >::value
405  >>
406  SimpleAny(const T& value) :
407  _typeInfo{cpp::typeerasure::TypeInfo::get<T>()}
408  {
409  SIPLASPLAS_ASSERT_TRUE(Storage::template objectFitsInStorage<T>());
410  _typeInfo.copyConstruct(Storage::storage(_typeInfo), &value);
411  }
412 
413  template<typename OtherStorage>
414  SimpleAny(const SimpleAny<OtherStorage>& other) :
415  _typeInfo{other.typeInfo()}
416  {
417  _typeInfo.copyConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
418  }
419 
420  template<typename OtherStorage>
422  _typeInfo{other.typeInfo()}
423  {
424  _typeInfo.moveConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
425  }
426 
427  SimpleAny(const SimpleAny& other) :
428  _typeInfo{other.typeInfo()}
429  {
430  _typeInfo.copyConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
431  }
432 
433  SimpleAny(SimpleAny&& other) :
434  _typeInfo{other.typeInfo()}
435  {
436  _typeInfo.moveConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
437  }
438 
444  template<typename T>
445  bool hasType() const
446  {
447  return cpp::typeerasure::TypeInfo::get<T>() == _typeInfo;
448  }
449 
458  template<typename T>
459  const std::decay_t<T>& get() const
460  {
462 #ifdef SIPLASPLAS_TYPEERASURE_SIMPLEANY_TYPECHECKS
463  SIPLASPLAS_ASSERT_TRUE(hasType<std::decay_t<T>>())("SimpleAny has type '{}', requested '{}' instead", typeInfo().typeName(), ctti::type_id<std::decay_t<T>>().name());
464 #endif
465  if(_typeInfo.isPointer())
466  {
467  return **reinterpret_cast<const std::decay_t<T>* const *>(Storage::storage(_typeInfo));
468  }
469  else
470  {
471  return *reinterpret_cast<const std::decay_t<T>*>(Storage::storage(_typeInfo));
472  }
473  }
474 
483  template<typename T>
484  std::decay_t<T>& get()
485  {
487 #ifdef SIPLASPLAS_TYPEERASURE_SIMPLEANY_TYPECHECKS
488  SIPLASPLAS_ASSERT_TRUE(hasType<std::decay_t<T>>())("SimpleAny has type '{}', requested '{}' instead", typeInfo().typeName(), ctti::type_id<std::decay_t<T>>().name());
489 #endif
490  if(_typeInfo.isPointer())
491  {
492  return **reinterpret_cast<std::decay_t<T>**>(Storage::storage(_typeInfo));
493  }
494  else
495  {
496  return *reinterpret_cast<std::decay_t<T>*>(Storage::storage(_typeInfo));
497  }
498  }
499 
504  {
505  return _typeInfo;
506  }
507 
512  {
513  return {Storage::storage(_typeInfo), _typeInfo};
514  }
515 
520  {
521  return {Storage::storage(_typeInfo), _typeInfo};
522  }
523 
534  template<typename T>
535  SimpleAny& operator=(const T& value)
536  {
537  if(!hasType<T>())
538  {
539  _typeInfo.destroy(Storage::storage(_typeInfo));
540  _typeInfo = cpp::typeerasure::TypeInfo::get<T>();
541  SIPLASPLAS_ASSERT_TRUE(Storage::template objectFitsInStorage<T>());
542  _typeInfo.copyConstruct(Storage::storage(_typeInfo), &value);
543  }
544  else
545  {
546  _typeInfo.copyAssign(Storage::storage(_typeInfo), &value);
547  }
548 
549  return *this;
550  }
551 
552  SimpleAny& operator=(const SimpleAny& other)
553  {
554  if(!sameType(*this, other))
555  {
556  _typeInfo.destroy(Storage::storage(_typeInfo));
557  _typeInfo = other._typeInfo;
558  _typeInfo.copyConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
559  }
560  else
561  {
562  _typeInfo.copyAssign(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
563  }
564 
565  return *this;
566  }
567 
568  SimpleAny& operator=(SimpleAny&& other)
569  {
570  if(!sameType(*this, other))
571  {
572  _typeInfo.destroy(Storage::storage(_typeInfo));
573  _typeInfo = other._typeInfo;
574  _typeInfo.moveConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
575  }
576  else
577  {
578  _typeInfo.moveAssign(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
579  }
580 
581  return *this;
582  }
583 
584  ~SimpleAny()
585  {
586  _typeInfo.destroy(Storage::storage(_typeInfo));
587  }
588 
592  const Storage& getStorage() const
593  {
594  return *static_cast<const Storage*>(this);
595  }
596 
597 private:
598  cpp::typeerasure::TypeInfo _typeInfo;
599 
600  template<typename T, typename... Args>
601  SimpleAny(meta::identity<T>, Args&&... args) :
602  _typeInfo{cpp::typeerasure::TypeInfo::get<T>()}
603  {
604  SIPLASPLAS_ASSERT_TRUE(Storage::template objectFitsInStorage<T>());
605  features::Constructible::apply<T>(Storage::storage(_typeInfo), std::forward<Args>(args)...);
606  }
607 };
608 
609 
615 
621 
627 
633 
639 
645 
646 
647 }
648 
649 #endif // SIPLASPLAS_TYPEERASURE_SIPLEANY_HPP
SimpleAny(const T &value)
Constructs an any of type T from an lvalue of type T.
Definition: simpleany.hpp:406
SimpleAny & operator=(const T &value)
Assigns a value of type T.
Definition: simpleany.hpp:535
cpp::SimpleAny specialization for non-owning const references to existing objects. See cpp::ConstNonOwningStorage
Definition: simpleany.hpp:41
void * storage(cpp::typeerasure::TypeInfo typeInfo) const
Returns a pointer to the storage memory space.
Definition: nonowning.hpp:99
void moveConstruct(void *where, void *other) const
Move constructs values of the type If the passed arguments are not of the represented type...
Definition: typeinfo.hpp:176
Definition: canary_allocator.hpp:7
#define SIPLASPLAS_ASSERT_FALSE(...)
Defines a false assertion.
Definition: assert.hpp:415
cpp::SimpleAny< cpp::ConstNonOwningStorage > getReference() const
Returns a const reference any to the hosted object.
Definition: simpleany.hpp:519
void rebind(const void *object)
Reassigns the storage to reference another object.
Definition: nonowning.hpp:36
Implements a read-only non owning storage.
Definition: nonowning.hpp:17
static SimpleAny create(const T &value)
Creates a const reference SimpleAny referencing the given object of type T.
Definition: simpleany.hpp:200
cpp::typeerasure::TypeInfo typeInfo() const
Returns the type information of the hosted type.
Definition: simpleany.hpp:251
SimpleAny & operator=(const T &value)
Assigns a value of type T.
Definition: simpleany.hpp:130
cpp::typeerasure::TypeInfo typeInfo() const
Returns the type information of the hosted type.
Definition: simpleany.hpp:503
bool empty() const
Checks whether the any has an object hosted in or if is empty.
Definition: simpleany.hpp:388
SimpleAny()
Constructs an empty SimpleAny.
Definition: simpleany.hpp:377
const void * storage(cpp::typeerasure::TypeInfo typeInfo) const
Returns a pointer to the storage memory space.
Definition: nonowning.hpp:49
void copyConstruct(void *where, const void *other) const
Copy constructs values of the type If the passed arguments are not of the represented type...
Definition: typeinfo.hpp:163
const ConstNonOwningStorage & getStorage() const
Returns the storage backend of the SimpleAny object.
Definition: simpleany.hpp:148
const Storage & getStorage() const
Returns the storage backend of the SimpleAny object.
Definition: simpleany.hpp:592
bool empty() const
Checks whether the any has an object hosted in or if is empty.
Definition: simpleany.hpp:58
void rebind(void *object)
Reassigns the storage to reference another object.
Definition: nonowning.hpp:86
cpp::SimpleAny specialization for non-owning references to existing objects. See cpp::NonOwningStorag...
Definition: simpleany.hpp:162
bool hasType() const
Checks if the any has a value of type T.
Definition: simpleany.hpp:211
static SimpleAny create(const T &value)
Creates a const reference SimpleAny referencing the given object of type T.
Definition: simpleany.hpp:79
Implements a type-erased value container with minimal value semantics requirements.
Definition: simpleany.hpp:15
cpp::SimpleAny< cpp::NonOwningStorage > getReference()
Returns a reference any to the hosted object.
Definition: simpleany.hpp:511
bool hasType() const
Checks if the any has a value of type T.
Definition: simpleany.hpp:90
bool empty() const
Checks whether the any has an object hosted in or if is empty.
Definition: simpleany.hpp:179
bool hasType() const
Checks if the any has a value of type T.
Definition: simpleany.hpp:445
const char * typeName() const
Returns the name of the type.
Definition: typeinfo.hpp:134
Implements a non owning storage.
Definition: nonowning.hpp:66
Contains minimal information to execute the value semantics operations of a type. ...
Definition: typeinfo.hpp:108
SimpleAny & operator=(T &&value)
Assigns an rvalue of type T.
Definition: simpleany.hpp:293
Type used to represent empty state.
Definition: simpleany.hpp:354
const NonOwningStorage & getStorage() const
Returns the storage backend of the SimpleAny object.
Definition: simpleany.hpp:313
SimpleAny & operator=(T &value)
Assigns a value of type T.
Definition: simpleany.hpp:267
static SimpleAny create(Args &&...args)
Constructs a SimpleAny with an in-place constructed value of type T.
Definition: simpleany.hpp:369
#define SIPLASPLAS_ASSERT_TRUE(...)
Defines a true assertion.
Definition: assert.hpp:398
cpp::typeerasure::TypeInfo typeInfo() const
Returns the type information of the hosted type.
Definition: simpleany.hpp:114