Przeglądaj źródła

Added Any class

Marko Pintera 11 lat temu
rodzic
commit
adaa9b5cab

+ 1 - 0
CamelotUtility/CamelotUtility.vcxproj

@@ -265,6 +265,7 @@
     <ClCompile Include="Source\CmStringTable.cpp" />
     <ClCompile Include="Source\CmTexAtlasGenerator.cpp" />
     <ClCompile Include="Source\Win32\CmTimer.cpp" />
+    <ClInclude Include="Include\BsAny.h" />
     <ClInclude Include="Include\BsEvent.h" />
     <ClInclude Include="Include\BsSpinLock.h" />
     <ClInclude Include="Include\BsTaskScheduler.h" />

+ 3 - 0
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -237,6 +237,9 @@
     <ClInclude Include="Include\BsSpinLock.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsAny.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmMath.cpp">

+ 221 - 0
CamelotUtility/Include/BsAny.h

@@ -0,0 +1,221 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+#include <algorithm>
+#include <typeinfo>
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Class capable of storing any general type, and safely extracting 
+	 *			the proper type from the internal data.
+	 */
+	class Any
+	{
+	private:
+		class DataBase
+		{
+		public:
+			virtual ~DataBase()
+			{ }
+
+			virtual const std::type_info& type() const = 0;
+			virtual DataBase* clone() const = 0;
+		};
+
+		template <typename ValueType>
+		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(0)
+		{ }
+
+		template <typename ValueType>
+		Any(const ValueType& value) 
+			:mData(cm_new<Data<ValueType>>(value))
+		{ }
+
+		Any(const Any& other) 
+			:mData(other.mData != nullptr ? other.mData->clone() : nullptr)
+		{ }
+
+		~Any()
+		{
+			cm_delete(mData);
+		}
+
+		/**
+		 * @brief	Swaps the contents of this object with another.
+		 */
+		Any& swap(Any& rhs)
+		{
+			std::swap(mData, rhs.mData);
+			return *this;
+		}
+
+		template <typename ValueType>
+		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 <typename ValueType>
+		friend ValueType* any_cast(Any*);
+
+		template <typename ValueType>
+		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 <typename ValueType>
+	ValueType* any_cast(Any* operand)
+	{
+		if (operand != nullptr && operand->type() == typeid(ValueType))
+			return &static_cast<Any::Data<ValueType>*>(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 <typename ValueType>
+	const ValueType* any_cast(const Any* operand)
+	{
+		return any_cast<ValueType>(const_cast<Any*>(operand));
+	}
+
+	/**
+	* @brief	Returns a copy of the internal data of the specified type.
+	*
+	* @note		Throws an exception if cast fails.
+	*/
+	template <typename ValueType>
+	ValueType any_cast(const Any& operand)
+	{
+		ValueType* result = any_cast<ValueType>(const_cast<Any*>(&operand));
+
+		if (result == nullptr)
+			CM_EXCEPT(InvalidStateException, "Failed to cast between Any types.");
+
+		return *result;
+	}
+
+	/**
+	 * @brief	Returns a copy of the internal data of the specified type.
+	 *
+	 * @note	Throws an exception if cast fails.
+	 */
+	template <typename ValueType>
+	ValueType any_cast(Any& operand)
+	{
+		ValueType* result = any_cast<ValueType>(&operand);
+
+		if (result == nullptr)
+			CM_EXCEPT(InvalidStateException, "Failed to cast between Any types.");
+
+		return *result;
+	}
+
+	/**
+	* @brief	Returns a reference to the internal data of the specified type.
+	*
+	* @note		Throws an exception if cast fails.
+	*/
+	template <typename ValueType>
+	const ValueType& any_cast_ref(const Any & operand)
+	{
+		ValueType* result = any_cast<ValueType>(const_cast<Any*>(&operand));
+
+		if (result == nullptr)
+			CM_EXCEPT(InvalidStateException, "Failed to cast between Any types.");
+
+		return *result;
+	}
+
+	/**
+	 * @brief	Returns a reference to the internal data of the specified type.
+	 *
+	 * @note	Throws an exception if cast fails.
+	 */
+	template <typename ValueType>
+	ValueType& any_cast_ref(Any& operand)
+	{
+		ValueType* result = anyCast<ValueType>(&operand);
+
+		if (result == nullptr)
+			CM_EXCEPT(InvalidStateException, "Failed to cast between Any types.");
+
+		return *result;
+	}
+
+	/**
+	 * @brief	Casts a type without performing any kind of checks.
+	 */
+	template <typename ValueType>
+	ValueType* any_cast_unsafe(Any* operand)
+	{
+		return &static_cast<Any::Data<ValueType>*>(operand->mData)->value;
+	}
+
+	/**
+	* @brief	Casts a type without performing any kind of checks.
+	*/
+	template <typename ValueType>
+	const ValueType* any_cast_unsafe(const Any* operand)
+	{
+		return any_cast_unsafe<ValueType>(const_cast<Any*>(operand));
+	}
+}