BsAny.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #pragma once
  2. #include "BsPrerequisitesUtil.h"
  3. #include "BsDebug.h"
  4. #include <algorithm>
  5. #include <typeinfo>
  6. namespace BansheeEngine
  7. {
  8. /**
  9. * @brief Class capable of storing any general type, and safely extracting
  10. * the proper type from the internal data.
  11. *
  12. * @note Requires C++ RTTI to be active in the compiler. If you don't want to
  13. * activate RTTI you may remove "typeid" type checks, in which case the
  14. * container functionality will remain but casting will no longer be type safe.
  15. */
  16. class Any
  17. {
  18. private:
  19. class DataBase
  20. {
  21. public:
  22. virtual ~DataBase()
  23. { }
  24. virtual const std::type_info& type() const = 0;
  25. virtual DataBase* clone() const = 0;
  26. };
  27. template <typename ValueType>
  28. class Data : public DataBase
  29. {
  30. public:
  31. Data(const ValueType& value)
  32. :value(value)
  33. { }
  34. virtual const std::type_info& type() const
  35. {
  36. return typeid(ValueType);
  37. }
  38. virtual DataBase* clone() const
  39. {
  40. return new Data(value);
  41. }
  42. ValueType value;
  43. };
  44. public:
  45. Any()
  46. :mData(nullptr)
  47. { }
  48. template <typename ValueType>
  49. Any(const ValueType& value)
  50. :mData(bs_new<Data<ValueType>>(value))
  51. { }
  52. Any(const Any& other)
  53. :mData(other.mData != nullptr ? other.mData->clone() : nullptr)
  54. { }
  55. ~Any()
  56. {
  57. if (mData != nullptr)
  58. bs_delete(mData);
  59. }
  60. /**
  61. * @brief Swaps the contents of this object with another.
  62. */
  63. Any& swap(Any& rhs)
  64. {
  65. std::swap(mData, rhs.mData);
  66. return *this;
  67. }
  68. template <typename ValueType>
  69. Any& operator= (const ValueType& rhs)
  70. {
  71. Any(rhs).swap(*this);
  72. return *this;
  73. }
  74. Any& operator= (const Any& rhs)
  75. {
  76. Any(rhs).swap(*this);
  77. return *this;
  78. }
  79. /**
  80. * @brief Returns true if no type is set.
  81. */
  82. bool empty() const
  83. {
  84. return mData == nullptr;
  85. }
  86. /**
  87. * @brief Returns type of the internal data. If no internal
  88. * data is set returns void type.
  89. */
  90. const std::type_info& type() const
  91. {
  92. return mData != nullptr ? mData->type() : typeid(void);
  93. }
  94. private:
  95. template <typename ValueType>
  96. friend ValueType* any_cast(Any*);
  97. template <typename ValueType>
  98. friend ValueType* any_cast_unsafe(Any*);
  99. DataBase* mData;
  100. };
  101. /**
  102. * @brief Returns a pointer to the internal data of the specified type.
  103. *
  104. * @note Will return null if cast fails.
  105. */
  106. template <typename ValueType>
  107. ValueType* any_cast(Any* operand)
  108. {
  109. if (operand != nullptr && operand->type() == typeid(ValueType))
  110. return &static_cast<Any::Data<ValueType>*>(operand->mData)->value;
  111. else
  112. return nullptr;
  113. }
  114. /**
  115. * @brief Returns a const pointer to the internal data of the specified type.
  116. *
  117. * @note Will return null if cast fails.
  118. */
  119. template <typename ValueType>
  120. const ValueType* any_cast(const Any* operand)
  121. {
  122. return any_cast<ValueType>(const_cast<Any*>(operand));
  123. }
  124. /**
  125. * @brief Returns a copy of the internal data of the specified type.
  126. *
  127. * @note Throws an exception if cast fails.
  128. */
  129. template <typename ValueType>
  130. ValueType any_cast(const Any& operand)
  131. {
  132. ValueType* result = any_cast<ValueType>(const_cast<Any*>(&operand));
  133. if (result == nullptr)
  134. {
  135. String msg = String("Failed to cast between Any types: ") + String(operand.type().name()) + " != " + String(typeid(ValueType).name());
  136. LOGERR(msg);
  137. }
  138. return *result;
  139. }
  140. /**
  141. * @brief Returns a copy of the internal data of the specified type.
  142. *
  143. * @note Throws an exception if cast fails.
  144. */
  145. template <typename ValueType>
  146. ValueType any_cast(Any& operand)
  147. {
  148. ValueType* result = any_cast<ValueType>(&operand);
  149. if (result == nullptr)
  150. {
  151. String msg = String("Failed to cast between Any types: ") + String(operand.type().name()) + " != " + String(typeid(ValueType).name());
  152. LOGERR(msg);
  153. }
  154. return *result;
  155. }
  156. /**
  157. * @brief Returns a reference to the internal data of the specified type.
  158. *
  159. * @note Throws an exception if cast fails.
  160. */
  161. template <typename ValueType>
  162. const ValueType& any_cast_ref(const Any & operand)
  163. {
  164. ValueType* result = any_cast<ValueType>(const_cast<Any*>(&operand));
  165. if (result == nullptr)
  166. {
  167. String msg = String("Failed to cast between Any types: ") + String(operand.type().name()) + " != " + String(typeid(ValueType).name());
  168. LOGERR(msg);
  169. }
  170. return *result;
  171. }
  172. /**
  173. * @brief Returns a reference to the internal data of the specified type.
  174. *
  175. * @note Throws an exception if cast fails.
  176. */
  177. template <typename ValueType>
  178. ValueType& any_cast_ref(Any& operand)
  179. {
  180. ValueType* result = any_cast<ValueType>(&operand);
  181. if (result == nullptr)
  182. {
  183. String msg = String("Failed to cast between Any types: ") + String(operand.type().name()) + " != " + String(typeid(ValueType).name());
  184. LOGERR(msg);
  185. }
  186. return *result;
  187. }
  188. /**
  189. * @brief Casts a type without performing any kind of checks.
  190. */
  191. template <typename ValueType>
  192. ValueType* any_cast_unsafe(Any* operand)
  193. {
  194. return &static_cast<Any::Data<ValueType>*>(operand->mData)->value;
  195. }
  196. /**
  197. * @brief Casts a type without performing any kind of checks.
  198. */
  199. template <typename ValueType>
  200. const ValueType* any_cast_unsafe(const Any* operand)
  201. {
  202. return any_cast_unsafe<ValueType>(const_cast<Any*>(operand));
  203. }
  204. }