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 
389  _typeInfo{typeInfo}
390  {
391  _typeInfo.defaultConstruct(Storage::storage(_typeInfo));
392  }
393 
401  bool empty() const
402  {
403  return hasType<EmptyTag>();
404  }
405 
413  template<typename T, typename = std::enable_if_t<
414  !std::is_base_of<
415  SimpleAny,
416  std::decay_t<T>
417  >::value
418  >>
419  SimpleAny(const T& value) :
420  _typeInfo{cpp::typeerasure::TypeInfo::get<T>()}
421  {
422  SIPLASPLAS_ASSERT_TRUE(Storage::template objectFitsInStorage<T>());
423  _typeInfo.copyConstruct(Storage::storage(_typeInfo), &value);
424  }
425 
426  template<typename OtherStorage>
427  SimpleAny(const SimpleAny<OtherStorage>& other) :
428  _typeInfo{other.typeInfo()}
429  {
430  _typeInfo.copyConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
431  }
432 
433  template<typename OtherStorage>
435  _typeInfo{other.typeInfo()}
436  {
437  _typeInfo.moveConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
438  }
439 
440  SimpleAny(const SimpleAny& other) :
441  _typeInfo{other.typeInfo()}
442  {
443  _typeInfo.copyConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
444  }
445 
446  SimpleAny(SimpleAny&& other) :
447  _typeInfo{other.typeInfo()}
448  {
449  _typeInfo.moveConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
450  }
451 
457  template<typename T>
458  bool hasType() const
459  {
460  return cpp::typeerasure::TypeInfo::get<T>() == _typeInfo;
461  }
462 
471  template<typename T>
472  const std::decay_t<T>& get() const
473  {
475 #ifdef SIPLASPLAS_TYPEERASURE_SIMPLEANY_TYPECHECKS
476  SIPLASPLAS_ASSERT_TRUE(hasType<std::decay_t<T>>())("SimpleAny has type '{}', requested '{}' instead", typeInfo().typeName(), ctti::type_id<std::decay_t<T>>().name());
477 #endif
478  if(_typeInfo.isPointer())
479  {
480  return **reinterpret_cast<const std::decay_t<T>* const *>(Storage::storage(_typeInfo));
481  }
482  else
483  {
484  return *reinterpret_cast<const std::decay_t<T>*>(Storage::storage(_typeInfo));
485  }
486  }
487 
496  template<typename T>
497  std::decay_t<T>& get()
498  {
500 #ifdef SIPLASPLAS_TYPEERASURE_SIMPLEANY_TYPECHECKS
501  SIPLASPLAS_ASSERT_TRUE(hasType<std::decay_t<T>>())("SimpleAny has type '{}', requested '{}' instead", typeInfo().typeName(), ctti::type_id<std::decay_t<T>>().name());
502 #endif
503  if(_typeInfo.isPointer())
504  {
505  return **reinterpret_cast<std::decay_t<T>**>(Storage::storage(_typeInfo));
506  }
507  else
508  {
509  return *reinterpret_cast<std::decay_t<T>*>(Storage::storage(_typeInfo));
510  }
511  }
512 
517  {
518  return _typeInfo;
519  }
520 
525  {
526  return {Storage::storage(_typeInfo), _typeInfo};
527  }
528 
533  {
534  return {Storage::storage(_typeInfo), _typeInfo};
535  }
536 
547  template<typename T>
548  SimpleAny& operator=(const T& value)
549  {
550  if(!hasType<T>())
551  {
552  _typeInfo.destroy(Storage::storage(_typeInfo));
553  _typeInfo = cpp::typeerasure::TypeInfo::get<T>();
554  SIPLASPLAS_ASSERT_TRUE(Storage::template objectFitsInStorage<T>());
555  _typeInfo.copyConstruct(Storage::storage(_typeInfo), &value);
556  }
557  else
558  {
559  _typeInfo.copyAssign(Storage::storage(_typeInfo), &value);
560  }
561 
562  return *this;
563  }
564 
565  SimpleAny& operator=(const SimpleAny& other)
566  {
567  if(!sameType(*this, other))
568  {
569  _typeInfo.destroy(Storage::storage(_typeInfo));
570  _typeInfo = other._typeInfo;
571  _typeInfo.copyConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
572  }
573  else
574  {
575  _typeInfo.copyAssign(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
576  }
577 
578  return *this;
579  }
580 
581  SimpleAny& operator=(SimpleAny&& other)
582  {
583  if(!sameType(*this, other))
584  {
585  _typeInfo.destroy(Storage::storage(_typeInfo));
586  _typeInfo = other._typeInfo;
587  _typeInfo.moveConstruct(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
588  }
589  else
590  {
591  _typeInfo.moveAssign(Storage::storage(_typeInfo), other.storage(other.typeInfo()));
592  }
593 
594  return *this;
595  }
596 
597  ~SimpleAny()
598  {
599  _typeInfo.destroy(Storage::storage(_typeInfo));
600  }
601 
605  const Storage& getStorage() const
606  {
607  return *static_cast<const Storage*>(this);
608  }
609 
610 private:
611  cpp::typeerasure::TypeInfo _typeInfo;
612 
613  template<typename T, typename... Args>
614  SimpleAny(meta::identity<T>, Args&&... args) :
615  _typeInfo{cpp::typeerasure::TypeInfo::get<T>()}
616  {
617  SIPLASPLAS_ASSERT_TRUE(Storage::template objectFitsInStorage<T>());
618  features::Constructible::apply<T>(Storage::storage(_typeInfo), std::forward<Args>(args)...);
619  }
620 };
621 
622 
628 
634 
640 
646 
652 
658 
659 
660 }
661 
662 #endif // SIPLASPLAS_TYPEERASURE_SIPLEANY_HPP
SimpleAny(const T &value)
Constructs an any of type T from an lvalue of type T.
Definition: simpleany.hpp:419
SimpleAny(const cpp::typeerasure::TypeInfo &typeInfo)
Default constructs a value of the given type.
Definition: simpleany.hpp:388
SimpleAny & operator=(const T &value)
Assigns a value of type T.
Definition: simpleany.hpp:548
cpp::SimpleAny specialization for non-owning const references to existing objects. See cpp::ConstNonOwningStorage
Definition: simpleany.hpp:41
void defaultConstruct(void *where) const
Default constructs a value of the type If the passed argument is not of the represented type...
Definition: typeinfo.hpp:166
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:191
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:532
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:516
bool empty() const
Checks whether the any has an object hosted in or if is empty.
Definition: simpleany.hpp:401
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:178
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:605
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:524
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:458
const char * typeName() const
Returns the name of the type.
Definition: typeinfo.hpp:138
Implements a non owning storage.
Definition: nonowning.hpp:66
Contains minimal information to execute the value semantics operations of a type. ...
Definition: typeinfo.hpp:112
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