BsAny.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #pragma once
  2. #include "BsPrerequisitesUtil.h"
  3. #include "BsException.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. BS_EXCEPT(InvalidStateException, "Failed to cast between Any types.");
  135. return *result;
  136. }
  137. /**
  138. * @brief Returns a copy of the internal data of the specified type.
  139. *
  140. * @note Throws an exception if cast fails.
  141. */
  142. template <typename ValueType>
  143. ValueType any_cast(Any& operand)
  144. {
  145. ValueType* result = any_cast<ValueType>(&operand);
  146. if (result == nullptr)
  147. BS_EXCEPT(InvalidStateException, "Failed to cast between Any types.");
  148. return *result;
  149. }
  150. /**
  151. * @brief Returns a reference to the internal data of the specified type.
  152. *
  153. * @note Throws an exception if cast fails.
  154. */
  155. template <typename ValueType>
  156. const ValueType& any_cast_ref(const Any & operand)
  157. {
  158. ValueType* result = any_cast<ValueType>(const_cast<Any*>(&operand));
  159. if (result == nullptr)
  160. BS_EXCEPT(InvalidStateException, "Failed to cast between Any types.");
  161. return *result;
  162. }
  163. /**
  164. * @brief Returns a reference to the internal data of the specified type.
  165. *
  166. * @note Throws an exception if cast fails.
  167. */
  168. template <typename ValueType>
  169. ValueType& any_cast_ref(Any& operand)
  170. {
  171. ValueType* result = any_cast<ValueType>(&operand);
  172. if (result == nullptr)
  173. BS_EXCEPT(InvalidStateException, "Failed to cast between Any types.");
  174. return *result;
  175. }
  176. /**
  177. * @brief Casts a type without performing any kind of checks.
  178. */
  179. template <typename ValueType>
  180. ValueType* any_cast_unsafe(Any* operand)
  181. {
  182. return &static_cast<Any::Data<ValueType>*>(operand->mData)->value;
  183. }
  184. /**
  185. * @brief Casts a type without performing any kind of checks.
  186. */
  187. template <typename ValueType>
  188. const ValueType* any_cast_unsafe(const Any* operand)
  189. {
  190. return any_cast_unsafe<ValueType>(const_cast<Any*>(operand));
  191. }
  192. }