#pragma once #include "BsPrerequisitesUtil.h" #include "BsDebug.h" #include #include namespace BansheeEngine { /** * @brief Class capable of storing any general type, and safely extracting * the proper type from the internal data. * * @note Requires C++ RTTI to be active in the compiler. If you don't want to * activate RTTI you may remove "typeid" type checks, in which case the * container functionality will remain but casting will no longer be type safe. */ class Any { private: class DataBase { public: virtual ~DataBase() { } virtual const std::type_info& type() const = 0; virtual DataBase* clone() const = 0; }; template class Data : public DataBase { public: Data(const ValueType& value) :value(value) { } virtual const std::type_info& type() const { return typeid(ValueType); } virtual DataBase* clone() const { return new Data(value); } ValueType value; }; public: Any() :mData(nullptr) { } template Any(const ValueType& value) :mData(bs_new>(value)) { } Any(const Any& other) :mData(other.mData != nullptr ? other.mData->clone() : nullptr) { } ~Any() { if (mData != nullptr) bs_delete(mData); } /** * @brief Swaps the contents of this object with another. */ Any& swap(Any& rhs) { std::swap(mData, rhs.mData); return *this; } template Any& operator= (const ValueType& rhs) { Any(rhs).swap(*this); return *this; } Any& operator= (const Any& rhs) { Any(rhs).swap(*this); return *this; } /** * @brief Returns true if no type is set. */ bool empty() const { return mData == nullptr; } /** * @brief Returns type of the internal data. If no internal * data is set returns void type. */ const std::type_info& type() const { return mData != nullptr ? mData->type() : typeid(void); } private: template friend ValueType* any_cast(Any*); template friend ValueType* any_cast_unsafe(Any*); DataBase* mData; }; /** * @brief Returns a pointer to the internal data of the specified type. * * @note Will return null if cast fails. */ template ValueType* any_cast(Any* operand) { if (operand != nullptr && operand->type() == typeid(ValueType)) return &static_cast*>(operand->mData)->value; else return nullptr; } /** * @brief Returns a const pointer to the internal data of the specified type. * * @note Will return null if cast fails. */ template const ValueType* any_cast(const Any* operand) { return any_cast(const_cast(operand)); } /** * @brief Returns a copy of the internal data of the specified type. * * @note Throws an exception if cast fails. */ template ValueType any_cast(const Any& operand) { ValueType* result = any_cast(const_cast(&operand)); if (result == nullptr) { String msg = String("Failed to cast between Any types: ") + String(operand.type().name()) + " != " + String(typeid(ValueType).name()); LOGERR(msg); } return *result; } /** * @brief Returns a copy of the internal data of the specified type. * * @note Throws an exception if cast fails. */ template ValueType any_cast(Any& operand) { ValueType* result = any_cast(&operand); if (result == nullptr) { String msg = String("Failed to cast between Any types: ") + String(operand.type().name()) + " != " + String(typeid(ValueType).name()); LOGERR(msg); } return *result; } /** * @brief Returns a reference to the internal data of the specified type. * * @note Throws an exception if cast fails. */ template const ValueType& any_cast_ref(const Any & operand) { ValueType* result = any_cast(const_cast(&operand)); if (result == nullptr) { String msg = String("Failed to cast between Any types: ") + String(operand.type().name()) + " != " + String(typeid(ValueType).name()); LOGERR(msg); } return *result; } /** * @brief Returns a reference to the internal data of the specified type. * * @note Throws an exception if cast fails. */ template ValueType& any_cast_ref(Any& operand) { ValueType* result = any_cast(&operand); if (result == nullptr) { String msg = String("Failed to cast between Any types: ") + String(operand.type().name()) + " != " + String(typeid(ValueType).name()); LOGERR(msg); } return *result; } /** * @brief Casts a type without performing any kind of checks. */ template ValueType* any_cast_unsafe(Any* operand) { return &static_cast*>(operand->mData)->value; } /** * @brief Casts a type without performing any kind of checks. */ template const ValueType* any_cast_unsafe(const Any* operand) { return any_cast_unsafe(const_cast(operand)); } }