Selaa lähdekoodia

More work on improving the documentation

BearishSun 10 vuotta sitten
vanhempi
sitoutus
27da749c51

+ 114 - 117
BansheeUtility/Include/BsAsyncOp.h

@@ -1,118 +1,115 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsException.h"
-#include "BsAny.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Thread synchronization primitives used by AsyncOps and their
-	 *			callers.
-	 */
-	class BS_UTILITY_EXPORT AsyncOpSyncData
-	{
-	public:
-		BS_MUTEX(mMutex)
-		BS_THREAD_SYNCHRONISER(mCondition)
-	};
-
-	/**
-	 * @brief	Flag used for creating async operations signaling that we want to create an empty
-	 *			AsyncOp with no internal memory storage.
-	 */
-	struct BS_UTILITY_EXPORT AsyncOpEmpty {};
-
-	/**
-	 * @brief	Object you may use to check on the results of an asynchronous operation. 
-	 *			Contains uninitialized data until ::hasCompleted() returns true. 
-	 * 			
-	 * @note	You are allowed (and meant to) to copy this by value.
-	 * 			
-	 *			You'll notice mIsCompleted isn't synchronized. This is because we're okay if 
-	 *			mIsCompleted reports true a few cycles too late, which is not relevant for practical use.
-	 *			And in cases where you need to ensure operation has completed you will usually use some kind
-	 *			of synchronization primitive that includes a memory barrier anyway.
-	 */
-	class BS_UTILITY_EXPORT AsyncOp
-	{
-	private:
-		struct AsyncOpData
-		{
-			AsyncOpData()
-				:mIsCompleted(false)
-			{ }
-
-			Any mReturnValue;
-			volatile std::atomic<bool> mIsCompleted;
-		};
-
-	public:
-		AsyncOp()
-			:mData(bs_shared_ptr_new<AsyncOpData>())
-		{ }
-
-		AsyncOp(AsyncOpEmpty empty)
-		{ }
-
-		AsyncOp(const AsyncOpSyncDataPtr& syncData)
-			:mData(bs_shared_ptr_new<AsyncOpData>()), mSyncData(syncData)
-		{ }
-
-		AsyncOp(AsyncOpEmpty empty, const AsyncOpSyncDataPtr& syncData)
-			:mSyncData(syncData)
-		{ }
-
-		/**
-		 * @brief	True if the async operation has completed.
-		 * 
-		 * @note	Internal method.
-		 */
-		bool hasCompleted() const;
-
-		/**
-		 * @brief	Mark the async operation as completed.
-		 *
-		 * @note	Internal method.
-		 */
-		void _completeOperation(Any returnValue);
-
-		/**
-		 * @brief	Mark the async operation as completed, without setting a return value.
-		 *
-		 * @note	Internal method.
-		 */
-		void _completeOperation();
-
-		/**
-		 * @brief	Blocks the caller thread until the AsyncOp completes.
-		 *
-		 * @note	Internal method.
-		 *			Do not call this on the thread that is completing the async op, as it
-		 *			will cause a deadlock.
-		 *			Make sure the command you are waiting for is actually queued for execution
-		 *			because a deadlock will occurr otherwise.
-		 */
-		void _blockUntilComplete() const;
-
-		/**
-		 * @brief	Retrieves the value returned by the async operation. Only valid
-		 *			if "hasCompleted" returns true.
-		 */
-		template <typename T>
-		T getReturnValue() const 
-		{ 
-#if BS_DEBUG_MODE
-			if(!hasCompleted())
-				BS_EXCEPT(InternalErrorException, "Trying to get AsyncOp return value but the operation hasn't completed.");
-#endif
-			// Be careful if cast throws an exception. It doesn't support casting of polymorphic types. Provided and returned
-			// types must be EXACT. (You'll have to cast the data yourself when completing the operation)
-			return any_cast<T>(mData->mReturnValue);
-		}
-
-	private:
-		std::shared_ptr<AsyncOpData> mData;
-		AsyncOpSyncDataPtr mSyncData;
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsException.h"
+#include "BsAny.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Threading
+	 *  @{
+	 */
+
+	/** Thread synchronization primitives used by AsyncOps and their callers. */
+	class BS_UTILITY_EXPORT AsyncOpSyncData
+	{
+	public:
+		BS_MUTEX(mMutex)
+		BS_THREAD_SYNCHRONISER(mCondition)
+	};
+
+	/**
+	 * Flag used for creating async operations signaling that we want to create an empty AsyncOp with no internal 
+	 * memory storage.
+	 */
+	struct BS_UTILITY_EXPORT AsyncOpEmpty {};
+
+	/**
+	 * Object you may use to check on the results of an asynchronous operation. Contains uninitialized data until 
+	 * hasCompleted() returns true. 
+	 * 			
+	 * @note	
+	 * You are allowed (and meant to) to copy this by value.
+	 * @note
+	 * You'll notice mIsCompleted isn't synchronized. This is because we're okay if mIsCompleted reports true a few cycles 
+	 * too late, which is not relevant for practical use. And in cases where you need to ensure operation has completed 
+	 * you will usually use some kind of synchronization primitive that includes a memory barrier anyway.
+	 */
+	class BS_UTILITY_EXPORT AsyncOp
+	{
+	private:
+		struct AsyncOpData
+		{
+			AsyncOpData()
+				:mIsCompleted(false)
+			{ }
+
+			Any mReturnValue;
+			volatile std::atomic<bool> mIsCompleted;
+		};
+
+	public:
+		AsyncOp()
+			:mData(bs_shared_ptr_new<AsyncOpData>())
+		{ }
+
+		AsyncOp(AsyncOpEmpty empty)
+		{ }
+
+		AsyncOp(const AsyncOpSyncDataPtr& syncData)
+			:mData(bs_shared_ptr_new<AsyncOpData>()), mSyncData(syncData)
+		{ }
+
+		AsyncOp(AsyncOpEmpty empty, const AsyncOpSyncDataPtr& syncData)
+			:mSyncData(syncData)
+		{ }
+
+		/** True if the async operation has completed. */
+		bool hasCompleted() const;
+
+		/**
+		 * Blocks the caller thread until the AsyncOp completes.
+		 *
+		 * @note
+		 * Do not call this on the thread that is completing the async op, as it will cause a deadlock. Make sure the 
+		 * command you are waiting for is actually queued for execution because a deadlock will occurr otherwise.
+		 */
+		void blockUntilComplete() const;
+
+		/** Retrieves the value returned by the async operation. Only valid if hasCompleted() returns true. */
+		template <typename T>
+		T getReturnValue() const 
+		{ 
+#if BS_DEBUG_MODE
+			if(!hasCompleted())
+				BS_EXCEPT(InternalErrorException, "Trying to get AsyncOp return value but the operation hasn't completed.");
+#endif
+			// Be careful if cast throws an exception. It doesn't support casting of polymorphic types. Provided and returned
+			// types must be EXACT. (You'll have to cast the data yourself when completing the operation)
+			return any_cast<T>(mData->mReturnValue);
+		}
+
+		/** @cond INTERNAL */
+
+		/**
+		 * Mark the async operation as completed.
+		 *
+		 * @note	Internal method.
+		 */
+		void _completeOperation(Any returnValue);
+
+		/**
+		 * Mark the async operation as completed, without setting a return value.
+		 *
+		 * @note	Internal method.
+		 */
+		void _completeOperation();
+
+		/** @endcond */
+	private:
+		std::shared_ptr<AsyncOpData> mData;
+		AsyncOpSyncDataPtr mSyncData;
+	};
+
+	/** @} */
 }
 }

+ 15 - 3
BansheeUtility/Include/BsPrerequisitesUtil.h

@@ -29,15 +29,15 @@
  */
  */
 
 
 /** @defgroup Debug Debug
 /** @defgroup Debug Debug
- *  Contains various functionality used to help with debugging.
+ *  Contains functionality used to help with debugging.
  */
  */
 
 
 /** @defgroup Error Error handling
 /** @defgroup Error Error handling
- *  Contains various functionality used for handling and reporting errors.
+ *  Contains functionality used for handling and reporting errors.
  */
  */
 
 
 /** @defgroup Filesystem File system
 /** @defgroup Filesystem File system
- *  Contains various functionality used for manipulating, reading and writing files.
+ *  Contains functionality used for manipulating, reading and writing files.
  */
  */
 
 
 /** @defgroup General General
 /** @defgroup General General
@@ -48,6 +48,18 @@
  *  Contains various utility methods for manipulating images.
  *  Contains various utility methods for manipulating images.
  */
  */
 
 
+/** @defgroup String String
+ *  Contains functionality for manipulating strings.
+ */
+
+/** @defgroup Testing Testing
+ *  Contains functionality for running unit tests.
+ */
+
+ /** @defgroup Threading Threading
+ *  Contains functionality for manipulating threads and thread synchronization.
+ */
+
 /** @} */
 /** @} */
 
 
 // 0 - No thread support
 // 0 - No thread support

+ 65 - 65
BansheeUtility/Include/BsSpinLock.h

@@ -1,66 +1,66 @@
-#pragma once
-
-#include <atomic>
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Synchronization primitive with low overhead.
-	 *
-	 * @note	However it will actively block the thread waiting for the lock,
-	 *			not allowing any other work to be done, so it is best used for short
-	 *			locks.
-	 */
-	class SpinLock
-	{
-	public:
-		SpinLock()
-		{
-			mLock.clear(std::memory_order_relaxed);
-		}
-
-		/**
-		 * @brief	Lock any following operations with the spin lock, not allowing
-		 *			any other thread to access them.
-		 */
-		void lock()
-		{
-			while(mLock.test_and_set(std::memory_order_acquire))
-			{ }
-		}
-
-		/**
-		 * @brief	Release the lock and allow other threads to acquire the lock.
-		 */
-		void unlock()
-		{
-			mLock.clear(std::memory_order_release);
-		}
-
-	private:
-		std::atomic_flag mLock;
-	};
-
-	/**
-	 * @brief	Provides a safer method for locking a spin lock as the lock
-	 *			will get automatically locked when this objected is created and
-	 *			unlocked as soon as it goes out of scope.
-	 */
-	class ScopedSpinLock
-	{
-	public:
-		ScopedSpinLock(SpinLock& spinLock)
-			:mSpinLock(spinLock)
-		{
-			mSpinLock.lock();
-		}
-
-		~ScopedSpinLock()
-		{
-			mSpinLock.unlock();
-		}
-
-	private:
-		SpinLock& mSpinLock;
-	};
+#pragma once
+
+#include <atomic>
+
+namespace BansheeEngine
+{
+	/** @addtogroup Threading
+	 *  @{
+	 */
+
+	/**
+	 * Synchronization primitive with low overhead.
+	 *
+	 * @note	
+	 * However it will actively block the thread waiting for the lock, not allowing any other work to be done, so it is 
+	 * best used for short locks.
+	 */
+	class SpinLock
+	{
+	public:
+		SpinLock()
+		{
+			mLock.clear(std::memory_order_relaxed);
+		}
+
+		/** Lock any following operations with the spin lock, not allowing any other thread to access them. */
+		void lock()
+		{
+			while(mLock.test_and_set(std::memory_order_acquire))
+			{ }
+		}
+
+		/**	Release the lock and allow other threads to acquire the lock. */
+		void unlock()
+		{
+			mLock.clear(std::memory_order_release);
+		}
+
+	private:
+		std::atomic_flag mLock;
+	};
+
+	/**
+	 * Provides a safer method for locking a spin lock as the lock will get automatically locked when this objected is 
+	 * created and unlocked as soon as it goes out of scope.
+	 */
+	class ScopedSpinLock
+	{
+	public:
+		ScopedSpinLock(SpinLock& spinLock)
+			:mSpinLock(spinLock)
+		{
+			mSpinLock.lock();
+		}
+
+		~ScopedSpinLock()
+		{
+			mSpinLock.unlock();
+		}
+
+	private:
+		SpinLock& mSpinLock;
+	};
+
+	/** @} */
 }
 }

+ 149 - 246
BansheeUtility/Include/BsString.h

@@ -1,39 +1,29 @@
 #pragma once
 #pragma once
 
 
+/** @addtogroup String
+ *  @{
+ */
+
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	/**
-	 * @brief	Basic string that uses Banshee memory allocators.
-	 */
+	/** Basic string that uses Banshee memory allocators. */
 	template <typename T>
 	template <typename T>
 	using BasicString = std::basic_string < T, std::char_traits<T>, StdAlloc<T> > ;
 	using BasicString = std::basic_string < T, std::char_traits<T>, StdAlloc<T> > ;
 
 
-	/**
-	 * @brief	Basic string stream that uses Banshee memory allocators.
-	 */
+	/**	Basic string stream that uses Banshee memory allocators. */
 	template <typename T>
 	template <typename T>
 	using BasicStringStream = std::basic_stringstream < T, std::char_traits<T>, StdAlloc<T> > ;
 	using BasicStringStream = std::basic_stringstream < T, std::char_traits<T>, StdAlloc<T> > ;
 
 
-	/**
-	 * @brief	Wide string used primarily for handling Unicode text.
-	 */
+	/** Wide string used primarily for handling Unicode text. */
 	typedef BasicString<wchar_t> WString;
 	typedef BasicString<wchar_t> WString;
 
 
-	/**
-	 * @brief	Narrow string used primarily for handling ASCII text.
-	 */
+	/** Narrow string used primarily for handling ASCII text. */
 	typedef BasicString<char> String;
 	typedef BasicString<char> String;
 
 
-	/**
-	 * @brief	Wide string stream used for primarily for constructing
-	 * 			strings consisting of Unicode text.
-	 */
+	/** Wide string stream used for primarily for constructing strings consisting of Unicode text. */
 	typedef BasicStringStream<wchar_t> WStringStream;
 	typedef BasicStringStream<wchar_t> WStringStream;
 
 
-	/**
-	 * @brief	Wide string stream used for primarily for constructing
-	 * 			strings consisting of ASCII text.
-	 */
+	/** Wide string stream used for primarily for constructing strings consisting of ASCII text. */
 	typedef BasicStringStream<char> StringStream;
 	typedef BasicStringStream<char> StringStream;
 }
 }
 
 
@@ -41,159 +31,126 @@ namespace BansheeEngine
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-    /**
-     * @brief	Utility class for manipulating Strings.
-     */
+    /** Utility class for manipulating Strings. */
     class BS_UTILITY_EXPORT StringUtil
     class BS_UTILITY_EXPORT StringUtil
     {
     {
 	public:
 	public:
-        /**
-         * @brief	Removes any whitespace characters from beginning or end of the string.
-         */
+        /** Removes any whitespace characters from beginning or end of the string. */
         static void trim(String& str, bool left = true, bool right = true);
         static void trim(String& str, bool left = true, bool right = true);
 
 
-        /**
-         * @copydoc StringUtil::trim(String&, bool, bool)
-         */
+        /** @copydoc StringUtil::trim(String&, bool, bool) */
         static void trim(WString& str, bool left = true, bool right = true);
         static void trim(WString& str, bool left = true, bool right = true);
 
 
-        /**
-         * @brief	Removes specified characters from beginning or end of the string.
-         */
+        /**	Removes specified characters from beginning or end of the string. */
         static void trim(String& str, const String& delims, bool left = true, bool right = true);
         static void trim(String& str, const String& delims, bool left = true, bool right = true);
 
 
-		/**
-         * @copydoc StringUtil::trim(String&, const String&, bool, bool)
-         */
+		/** @copydoc StringUtil::trim(String&, const String&, bool, bool) */
         static void trim(WString& str, const WString& delims, bool left = true, bool right = true);
         static void trim(WString& str, const WString& delims, bool left = true, bool right = true);
 
 
 		/**
 		/**
-		 * @brief	Returns a vector of strings containing all the substrings delimited
-		 * 			by the provided delimiter characters.
+		 * Returns a vector of strings containing all the substrings delimited by the provided delimiter characters.
 		 *
 		 *
-		 * @param	str		 	The string to split.
-		 * @param	delims   	(optional) Delimiter characters to split the string by. They will not
-		 * 						be included in resulting substrings.
-		 * @param	maxSplits	(optional) The maximum number of splits to perform (0 for unlimited splits). If this
-		 *						parameters is > 0, the splitting process will stop after this many splits, left to right.
+		 * @param[in]	str		 	The string to split.
+		 * @param[in]	delims   	(optional) Delimiter characters to split the string by. They will not
+		 * 							be included in resulting substrings.
+		 * @param[in]	maxSplits	(optional) The maximum number of splits to perform (0 for unlimited splits). If this
+		 *							parameters is > 0, the splitting process will stop after this many splits, left to right.
 		 */
 		 */
 		static Vector<String> split(const String& str, const String& delims = "\t\n ", unsigned int maxSplits = 0);
 		static Vector<String> split(const String& str, const String& delims = "\t\n ", unsigned int maxSplits = 0);
 
 
-		/**
-		 * @copydoc	StringUtil::split(const String&, const String&, unsigned int)
-		 */
+		/** @copydoc StringUtil::split(const String&, const String&, unsigned int) */
 		static Vector<WString> split(const WString& str, const WString& delims = L"\t\n ", unsigned int maxSplits = 0);
 		static Vector<WString> split(const WString& str, const WString& delims = L"\t\n ", unsigned int maxSplits = 0);
 
 
 		/**
 		/**
-		 * @brief	Returns a vector of strings containing all the substrings delimited
-		 *			by the provided delimiter characters, or the double delimiters used for including
-		 *			normal delimiter characters in the tokenized string. 
+		 * Returns a vector of strings containing all the substrings delimited by the provided delimiter characters, or the 
+		 * double delimiters used for including normal delimiter characters in the tokenized string. 
 		 *
 		 *
-		 * @param	str		 	The string to split.
-		 * @param	delims   	(optional) Delimiter characters to split the string by. They will not
-		 * 						be included in resulting substrings.
-		 * @params	doubleDelims (optional) Delimiter character you may use to surround other normal delimiters, in order
-		 * 						to include them in the tokensized string.
-		 * @param	maxSplits	(optional) The maximum number of splits to perform (0 for unlimited splits). If this
-		 *						parameters is > 0, the splitting process will stop after this many splits, left to right.
+		 * @param[in]	str		 		The string to split.
+		 * @param[in]	delims   		(optional) Delimiter characters to split the string by. They will not
+		 * 								be included in resulting substrings.
+		 * @params[in]	doubleDelims	(optional) Delimiter character you may use to surround other normal delimiters, 
+		 *								in order to include them in the tokensized string.
+		 * @param[in]	maxSplits		(optional) The maximum number of splits to perform (0 for unlimited splits). 
+		 *								If this parameters is > 0, the splitting process will stop after this many splits, 
+		 *								left to right.
 		 */
 		 */
 		static Vector<String> tokenise(const String& str, const String& delims = "\t\n ", const String& doubleDelims = "\"", unsigned int maxSplits = 0);
 		static Vector<String> tokenise(const String& str, const String& delims = "\t\n ", const String& doubleDelims = "\"", unsigned int maxSplits = 0);
 
 
-		/**
-		 * @copydoc	StringUtil::tokenise(const String&, const String&, const String&, unsigned int)
-		 */
+		/** @copydoc StringUtil::tokenise(const String&, const String&, const String&, unsigned int) */
 		static Vector<WString> tokenise(const WString& str, const WString& delims = L"\t\n ", const WString& doubleDelims = L"\"", unsigned int maxSplits = 0);
 		static Vector<WString> tokenise(const WString& str, const WString& delims = L"\t\n ", const WString& doubleDelims = L"\"", unsigned int maxSplits = 0);
 
 
-        /**
-         * @brief	Converts all the characters in the string to lower case.
-         */
+        /** Converts all the characters in the string to lower case. */
         static void toLowerCase(String& str);
         static void toLowerCase(String& str);
 
 
-        /**
-         * @brief	Converts all the characters in the string to lower case.
-         */
+        /** Converts all the characters in the string to lower case. */
         static void toLowerCase(WString& str);
         static void toLowerCase(WString& str);
 
 
-        /**
-         * @brief	Converts all the characters in the string to upper case.
-         */
+        /** Converts all the characters in the string to upper case. */
         static void toUpperCase(String& str);
         static void toUpperCase(String& str);
 
 
-        /**
-         * @brief	Converts all the characters in the string to upper case.
-         */
+        /**	Converts all the characters in the string to upper case. */
         static void toUpperCase(WString& str);
         static void toUpperCase(WString& str);
 
 
         /**
         /**
-         * @brief	Returns whether the string begins with the pattern passed in.
+         * Returns whether the string begins with the pattern passed in.
          *
          *
-         * @param	str		 	String to compare.
-         * @param	pattern		Pattern to compare with.
-		 * @param	lowerCase	(optional) If true, the start of the string will be lower cased before
-		 *						comparison, and the pattern should also be in lower case.
+         * @param[in]	str		 	String to compare.
+         * @param[in]	pattern		Pattern to compare with.
+		 * @param[in]	lowerCase	(optional) If true, the start of the string will be lower cased before comparison, and 
+		 *							the pattern should also be in lower case.
          */
          */
         static bool startsWith(const String& str, const String& pattern, bool lowerCase = true);
         static bool startsWith(const String& str, const String& pattern, bool lowerCase = true);
 
 
-        /**
-         * @copydoc startsWidth(const String&, const String&, bool)
-         */
+        /** @copydoc startsWidth(const String&, const String&, bool) */
         static bool startsWith(const WString& str, const WString& pattern, bool lowerCase = true);
         static bool startsWith(const WString& str, const WString& pattern, bool lowerCase = true);
 
 
         /**
         /**
-         * @brief	Returns whether the string end with the pattern passed in.
+         * Returns whether the string end with the pattern passed in.
          *
          *
-         * @param	str		 	String to compare.
-         * @param	pattern		Pattern to compare with.
-		 * @param	lowerCase	(optional) If true, the start of the string will be lower cased before
-		 *						comparison, and the pattern should also be in lower case.
+         * @param[in]	str		 	String to compare.
+         * @param[in]	pattern		Pattern to compare with.
+		 * @param[in]	lowerCase	(optional) If true, the start of the string will be lower cased before comparison, and 
+		 *							the pattern should also be in lower case.
          */
          */
         static bool endsWith(const String& str, const String& pattern, bool lowerCase = true);
         static bool endsWith(const String& str, const String& pattern, bool lowerCase = true);
 
 
-        /**
-         * @copydoc endsWith(const String&, const String&, bool)
-         */
+        /** @copydoc endsWith(const String&, const String&, bool) */
         static bool endsWith(const WString& str, const WString& pattern, bool lowerCase = true);
         static bool endsWith(const WString& str, const WString& pattern, bool lowerCase = true);
 
 
         /**
         /**
-         * @brief	Returns true if the string matches the provided pattern. Pattern may use
-         * 			a "*" wildcard for matching any characters.
+         * Returns true if the string matches the provided pattern. Pattern may use a "*" wildcard for matching any 
+		 * characters.
          *
          *
-         * @param	str			 	The string to test.
-         * @param	pattern		 	Patterns to look for.
-         * @param	caseSensitive	(optional) Should the match be case sensitive or not.
+         * @param[in]	str			 	The string to test.
+         * @param[in]	pattern		 	Patterns to look for.
+         * @param[in]	caseSensitive	(optional) Should the match be case sensitive or not.
          */
          */
         static bool match(const String& str, const String& pattern, bool caseSensitive = true);
         static bool match(const String& str, const String& pattern, bool caseSensitive = true);
 
 
-		/**
-         * @copydoc match(const String&, const String&, bool)
-         */
+		/** @copydoc match(const String&, const String&, bool) */
         static bool match(const WString& str, const WString& pattern, bool caseSensitive = true);
         static bool match(const WString& str, const WString& pattern, bool caseSensitive = true);
 
 
 		/**
 		/**
-		 * @brief	 Replace all instances of a substring with a another substring.
+		 * Replace all instances of a substring with a another substring.
 		 *
 		 *
-		 * @param	source		   	String to search.
-		 * @param	replaceWhat	   	Substring to find and replace
-		 * @param	replaceWithWhat	Substring to replace with (the new sub-string)
+		 * @param[in]	source		   	String to search.
+		 * @param[in]	replaceWhat	   	Substring to find and replace
+		 * @param[in]	replaceWithWhat	Substring to replace with (the new sub-string)
 		 *
 		 *
 		 * @return	An updated string with the substrings replaced.
 		 * @return	An updated string with the substrings replaced.
 		 */
 		 */
 		static const String replaceAll(const String& source, const String& replaceWhat, const String& replaceWithWhat);
 		static const String replaceAll(const String& source, const String& replaceWhat, const String& replaceWithWhat);
 
 
-		/**
-         * @copydoc replaceAll(const String&, const String&, const String&)
-         */
+		/** @copydoc replaceAll(const String&, const String&, const String&) */
 		static const WString replaceAll(const WString& source, const WString& replaceWhat, const WString& replaceWithWhat);
 		static const WString replaceAll(const WString& source, const WString& replaceWhat, const WString& replaceWithWhat);
 
 
 		/**
 		/**
-		 * @brief	Compares two strings. Returns 0 if the two compare equal, <0 if the value of the left
-		 *			string is lower than of the right string, or >0 if the value of the left string is
-		 *			higher than the right string.
+		 * Compares two strings. Returns 0 if the two compare equal, <0 if the value of the left string is lower than of 
+		 * the right string, or >0 if the value of the left string is higher than the right string.
 		 *
 		 *
-		 * @param	lhs				Left string to compare.
-		 * @param	rhs				Right string to compare.
-		 * @param	caseSensitive	If true the comparison will consider uppercase and lowercase
-		 *							characters different.
+		 * @param[in]	lhs				Left string to compare.
+		 * @param[in]	rhs				Right string to compare.
+		 * @param[in]	caseSensitive	If true the comparison will consider uppercase and lowercase characters different.
 		 */
 		 */
 		template <class T>
 		template <class T>
 		static int compare(const BasicString<T>& lhs, const BasicString<T>& rhs, bool caseSensitive = true)
 		static int compare(const BasicString<T>& lhs, const BasicString<T>& rhs, bool caseSensitive = true)
@@ -211,32 +168,24 @@ namespace BansheeEngine
 			return (lhs.size() < rhs.size() ? -1 : (lhs.size() == rhs.size() ? 0 : 1));
 			return (lhs.size() < rhs.size() ? -1 : (lhs.size() == rhs.size() ? 0 : 1));
 		}
 		}
 
 
-		/**
-		 * @copydoc	StringFormat::format
-		 */
+		/** @copydoc StringFormat::format */
 		template<class T, class... Args>
 		template<class T, class... Args>
 		static BasicString<T> format(const BasicString<T>& source, Args&& ...args)
 		static BasicString<T> format(const BasicString<T>& source, Args&& ...args)
 		{
 		{
 			return StringFormat::format(source.c_str(), std::forward<Args>(args)...);
 			return StringFormat::format(source.c_str(), std::forward<Args>(args)...);
 		}
 		}
 
 
-		/**
-		 * @copydoc	StringFormat::format
-		 */
+		/** @copydoc StringFormat::format */
 		template<class T, class... Args>
 		template<class T, class... Args>
 		static BasicString<T> format(const T* source, Args&& ...args)
 		static BasicString<T> format(const T* source, Args&& ...args)
 		{
 		{
 			return StringFormat::format(source, std::forward<Args>(args)...);
 			return StringFormat::format(source, std::forward<Args>(args)...);
 		}
 		}
 
 
-		/**
-		 * @brief	Constant blank string, useful for returning by ref where local does not exist.
-		 */
+		/** Constant blank string, useful for returning by ref where local does not exist. */
         static const String BLANK;
         static const String BLANK;
 
 
-		/**
-		 * @brief	Constant blank wide string, useful for returning by ref where local does not exist.
-		 */
+		/**	Constant blank wide string, useful for returning by ref where local does not exist. */
 		static const WString WBLANK;
 		static const WString WBLANK;
 
 
 	private:
 	private:
@@ -464,377 +413,327 @@ namespace BansheeEngine
 		}
 		}
     };
     };
 
 
-	/**
-	 * @brief	Converts a narrow string to a wide string.
-	 */
+	/** Converts a narrow string to a wide string. */
 	BS_UTILITY_EXPORT WString toWString(const String& source);
 	BS_UTILITY_EXPORT WString toWString(const String& source);
 
 
-	/**
-	 * @brief	Converts a narrow string to a wide string.
-	 */
+	/**	Converts a narrow string to a wide string. */
 	BS_UTILITY_EXPORT WString toWString(const char* source);
 	BS_UTILITY_EXPORT WString toWString(const char* source);
 
 
-	/**
-	 * @brief	Converts a float to a string.
-	 */
+	/** Converts a float to a string. */
     BS_UTILITY_EXPORT WString toWString(float val, unsigned short precision = 6, 
     BS_UTILITY_EXPORT WString toWString(float val, unsigned short precision = 6, 
         unsigned short width = 0, char fill = ' ', 
         unsigned short width = 0, char fill = ' ', 
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts a double to a string.
-	 */
+	/** Converts a double to a string. */
 	BS_UTILITY_EXPORT WString toWString(double val, unsigned short precision = 6, 
 	BS_UTILITY_EXPORT WString toWString(double val, unsigned short precision = 6, 
 		unsigned short width = 0, char fill = ' ', 
 		unsigned short width = 0, char fill = ' ', 
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts a Radian to a string.
-	 */
+	/** Converts a Radian to a string. */
     BS_UTILITY_EXPORT WString toWString(Radian val, unsigned short precision = 6, 
     BS_UTILITY_EXPORT WString toWString(Radian val, unsigned short precision = 6, 
         unsigned short width = 0, char fill = ' ', 
         unsigned short width = 0, char fill = ' ', 
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts a Degree to a string.
-	 */
+	/** Converts a Degree to a string. */
     BS_UTILITY_EXPORT WString toWString(Degree val, unsigned short precision = 6, 
     BS_UTILITY_EXPORT WString toWString(Degree val, unsigned short precision = 6, 
         unsigned short width = 0, char fill = ' ', 
         unsigned short width = 0, char fill = ' ', 
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts an int to a string.
-	 */
+	/**	Converts an int to a string. */
     BS_UTILITY_EXPORT WString toWString(int val, unsigned short width = 0, 
     BS_UTILITY_EXPORT WString toWString(int val, unsigned short width = 0, 
         char fill = ' ', 
         char fill = ' ', 
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts an unsigned int to a string.
-	 */
+	/**	Converts an unsigned int to a string. */
     BS_UTILITY_EXPORT WString toWString(unsigned int val, 
     BS_UTILITY_EXPORT WString toWString(unsigned int val, 
         unsigned short width = 0, char fill = ' ', 
         unsigned short width = 0, char fill = ' ', 
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts an 64bit integer to a string.
-	 */
+	/**	Converts an 64bit integer to a string. */
 	BS_UTILITY_EXPORT WString toWString(INT64 val, 
 	BS_UTILITY_EXPORT WString toWString(INT64 val, 
 		unsigned short width = 0, char fill = ' ', 
 		unsigned short width = 0, char fill = ' ', 
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts an 64bit unsigned to a string.
-	 */
+	/**	Converts an 64bit unsigned to a string. */
 	BS_UTILITY_EXPORT WString toWString(UINT64 val, 
 	BS_UTILITY_EXPORT WString toWString(UINT64 val, 
 		unsigned short width = 0, char fill = ' ', 
 		unsigned short width = 0, char fill = ' ', 
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	* @brief	Converts an narrow char unsigned to a string.
-	*/
+	/**	Converts an narrow char unsigned to a string. */
 	BS_UTILITY_EXPORT WString toWString(char val,
 	BS_UTILITY_EXPORT WString toWString(char val,
 		unsigned short width = 0, char fill = ' ',
 		unsigned short width = 0, char fill = ' ',
 		std::ios::fmtflags flags = std::ios::fmtflags(0));
 		std::ios::fmtflags flags = std::ios::fmtflags(0));
 
 
-	/**
-	* @brief	Converts an wide bit char unsigned to a string.
-	*/
+	/**	Converts an wide bit char unsigned to a string. */
 	BS_UTILITY_EXPORT WString toWString(wchar_t val,
 	BS_UTILITY_EXPORT WString toWString(wchar_t val,
 		unsigned short width = 0, char fill = ' ',
 		unsigned short width = 0, char fill = ' ',
 		std::ios::fmtflags flags = std::ios::fmtflags(0));
 		std::ios::fmtflags flags = std::ios::fmtflags(0));
 
 
     /**
     /**
-     * @brief	Converts a boolean to a string.
+     * Converts a boolean to a string.
      *
      *
-     * @param	val  	Value to convert.
-     * @param	yesNo	(optional) If set to true, result is "yes" or "no" instead of "true" or "false".
+     * @param[in]	val  	Value to convert.
+     * @param[in]	yesNo	(optional) If set to true, result is "yes" or "no" instead of "true" or "false".
      */
      */
     BS_UTILITY_EXPORT WString toWString(bool val, bool yesNo = false);
     BS_UTILITY_EXPORT WString toWString(bool val, bool yesNo = false);
 
 
     /**
     /**
-     * @brief	Converts a 2 dimensional vector to a string.
+     * Converts a 2 dimensional vector to a string.
      * 			
      * 			
 	 * @note	Format is "x y".
 	 * @note	Format is "x y".
      */
      */
     BS_UTILITY_EXPORT WString toWString(const Vector2& val);
     BS_UTILITY_EXPORT WString toWString(const Vector2& val);
 
 
     /**
     /**
-     * @brief	Converts a 2 dimensional integer vector to a string.
+     * Converts a 2 dimensional integer vector to a string.
      * 			
      * 			
 	 * @note	Format is "x y".
 	 * @note	Format is "x y".
      */
      */
     BS_UTILITY_EXPORT WString toWString(const Vector2I& val);
     BS_UTILITY_EXPORT WString toWString(const Vector2I& val);
 
 
     /**
     /**
-     * @brief	Converts a 3 dimensional vector to a string.
+     * Converts a 3 dimensional vector to a string.
      * 			
      * 			
 	 * @note	Format is "x y z".
 	 * @note	Format is "x y z".
      */
      */
     BS_UTILITY_EXPORT WString toWString(const Vector3& val);
     BS_UTILITY_EXPORT WString toWString(const Vector3& val);
 
 
     /**
     /**
-     * @brief	Converts a 4 dimensional vector to a string.
+     * Converts a 4 dimensional vector to a string.
      * 			
      * 			
 	 * @note	Format is "x y z w".
 	 * @note	Format is "x y z w".
      */
      */
     BS_UTILITY_EXPORT WString toWString(const Vector4& val);
     BS_UTILITY_EXPORT WString toWString(const Vector4& val);
 
 
     /**
     /**
-     * @brief	Converts a 3x3 matrix to a string.
+     * Converts a 3x3 matrix to a string.
      * 			
      * 			
 	 * @note	Format is "00 01 02 10 11 12 20 21 22".
 	 * @note	Format is "00 01 02 10 11 12 20 21 22".
      */
      */
     BS_UTILITY_EXPORT WString toWString(const Matrix3& val);
     BS_UTILITY_EXPORT WString toWString(const Matrix3& val);
 
 
     /**
     /**
-     * @brief	Converts a 4x4 matrix to a string.
+     * Converts a 4x4 matrix to a string.
      * 			
      * 			
 	 * @note	Format is "00 01 02 03 10 11 12 13 20 21 22 23 30 31 32 33".
 	 * @note	Format is "00 01 02 03 10 11 12 13 20 21 22 23 30 31 32 33".
      */
      */
     BS_UTILITY_EXPORT WString toWString(const Matrix4& val);
     BS_UTILITY_EXPORT WString toWString(const Matrix4& val);
 
 
     /**
     /**
-     * @brief	Converts a Quaternion to a string.
+     * Converts a Quaternion to a string.
      * 			
      * 			
 	 * @note	Format is "w x y z".
 	 * @note	Format is "w x y z".
      */
      */
     BS_UTILITY_EXPORT WString toWString(const Quaternion& val);
     BS_UTILITY_EXPORT WString toWString(const Quaternion& val);
 
 
     /**
     /**
-     * @brief	Converts a color to a string.
+     * Converts a color to a string.
      * 			
      * 			
 	 * @note	Format is "r g b a".
 	 * @note	Format is "r g b a".
      */
      */
     BS_UTILITY_EXPORT WString toWString(const Color& val);
     BS_UTILITY_EXPORT WString toWString(const Color& val);
 
 
-    /**
-     * @brief	Converts a vector of strings into a single string where the substrings are
-	 *			delimited by spaces.
-     */
+    /** Converts a vector of strings into a single string where the substrings are delimited by spaces. */
     BS_UTILITY_EXPORT WString toWString(const Vector<BansheeEngine::WString>& val);
     BS_UTILITY_EXPORT WString toWString(const Vector<BansheeEngine::WString>& val);
 
 
-	/**
-	 * @brief	Converts a wide string to a narrow string.
-	 */
+	/** Converts a wide string to a narrow string. */
 	BS_UTILITY_EXPORT String toString(const WString& source);
 	BS_UTILITY_EXPORT String toString(const WString& source);
 
 
-	/**
-	 * @brief	Converts a wide string to a narrow string.
-	 */
+	/**	Converts a wide string to a narrow string. */
 	BS_UTILITY_EXPORT String toString(const wchar_t* source);
 	BS_UTILITY_EXPORT String toString(const wchar_t* source);
 
 
-	/**
-	 * @brief	Converts a float to a string.
-	 */
+	/**	Converts a float to a string. */
     BS_UTILITY_EXPORT String toString(float val, unsigned short precision = 6, 
     BS_UTILITY_EXPORT String toString(float val, unsigned short precision = 6, 
         unsigned short width = 0, char fill = ' ', 
         unsigned short width = 0, char fill = ' ', 
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts a double to a string.
-	 */
+	/**	Converts a double to a string. */
 	BS_UTILITY_EXPORT String toString(double val, unsigned short precision = 6, 
 	BS_UTILITY_EXPORT String toString(double val, unsigned short precision = 6, 
 		unsigned short width = 0, char fill = ' ', 
 		unsigned short width = 0, char fill = ' ', 
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts a Radian to a string.
-	 */
+	/**	Converts a Radian to a string. */
     BS_UTILITY_EXPORT String toString(Radian val, unsigned short precision = 6, 
     BS_UTILITY_EXPORT String toString(Radian val, unsigned short precision = 6, 
         unsigned short width = 0, char fill = ' ', 
         unsigned short width = 0, char fill = ' ', 
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts a Degree to a string.
-	 */
+	/**	Converts a Degree to a string. */
     BS_UTILITY_EXPORT String toString(Degree val, unsigned short precision = 6, 
     BS_UTILITY_EXPORT String toString(Degree val, unsigned short precision = 6, 
         unsigned short width = 0, char fill = ' ', 
         unsigned short width = 0, char fill = ' ', 
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts an int to a string.
-	 */
+	/**	Converts an int to a string. */
     BS_UTILITY_EXPORT String toString(int val, unsigned short width = 0, 
     BS_UTILITY_EXPORT String toString(int val, unsigned short width = 0, 
         char fill = ' ', 
         char fill = ' ', 
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts an unsigned int to a string.
-	 */
+	/**	Converts an unsigned int to a string. */
     BS_UTILITY_EXPORT String toString(unsigned int val, 
     BS_UTILITY_EXPORT String toString(unsigned int val, 
         unsigned short width = 0, char fill = ' ', 
         unsigned short width = 0, char fill = ' ', 
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
         std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts a 64bit int to a string.
-	 */
+	/**	Converts a 64bit int to a string. */
 	BS_UTILITY_EXPORT String toString(INT64 val, 
 	BS_UTILITY_EXPORT String toString(INT64 val, 
 		unsigned short width = 0, char fill = ' ', 
 		unsigned short width = 0, char fill = ' ', 
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
-	/**
-	 * @brief	Converts an 64bit unsigned int to a string.
-	 */
+	/**	Converts an 64bit unsigned int to a string. */
 	BS_UTILITY_EXPORT String toString(UINT64 val, 
 	BS_UTILITY_EXPORT String toString(UINT64 val, 
 		unsigned short width = 0, char fill = ' ', 
 		unsigned short width = 0, char fill = ' ', 
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 		std::ios::fmtflags flags = std::ios::fmtflags(0) );
 
 
     /**
     /**
-     * @brief	Converts a boolean to a string.
+     * Converts a boolean to a string.
      *
      *
-     * @param	val  	true to value.
-     * @param	yesNo	(optional) If set to true, result is "yes" or "no" instead of "true" or "false".
+     * @param[in]	val  	true to value.
+     * @param[in]	yesNo	(optional) If set to true, result is "yes" or "no" instead of "true" or "false".
      */
      */
     BS_UTILITY_EXPORT String toString(bool val, bool yesNo = false);
     BS_UTILITY_EXPORT String toString(bool val, bool yesNo = false);
 
 
     /**
     /**
-     * @brief	Converts a 2 dimensional vector to a string.
+     * Converts a 2 dimensional vector to a string.
      * 			
      * 			
 	 * @note	Format is "x y".
 	 * @note	Format is "x y".
      */
      */
     BS_UTILITY_EXPORT String toString(const Vector2& val);
     BS_UTILITY_EXPORT String toString(const Vector2& val);
 
 
     /**
     /**
-     * @brief	Converts a 2 dimensional integer vector to a string.
+     * Converts a 2 dimensional integer vector to a string.
      * 			
      * 			
 	 * @note	Format is "x y".
 	 * @note	Format is "x y".
      */
      */
     BS_UTILITY_EXPORT String toString(const Vector2I& val);
     BS_UTILITY_EXPORT String toString(const Vector2I& val);
 
 
     /**
     /**
-     * @brief	Converts a 3 dimensional vector to a string.
+     * Converts a 3 dimensional vector to a string.
      * 			
      * 			
 	 * @note	Format is "x y z".
 	 * @note	Format is "x y z".
      */
      */
     BS_UTILITY_EXPORT String toString(const Vector3& val);
     BS_UTILITY_EXPORT String toString(const Vector3& val);
 
 
     /**
     /**
-     * @brief	Converts a 4 dimensional vector to a string.
+     * Converts a 4 dimensional vector to a string.
      * 			
      * 			
 	 * @note	Format is "x y z w".
 	 * @note	Format is "x y z w".
      */
      */
     BS_UTILITY_EXPORT String toString(const Vector4& val);
     BS_UTILITY_EXPORT String toString(const Vector4& val);
 
 
     /**
     /**
-     * @brief	Converts a 3x3 matrix to a string.
+     * Converts a 3x3 matrix to a string.
      * 			
      * 			
 	 * @note	Format is "00 01 02 10 11 12 20 21 22".
 	 * @note	Format is "00 01 02 10 11 12 20 21 22".
      */
      */
     BS_UTILITY_EXPORT String toString(const Matrix3& val);
     BS_UTILITY_EXPORT String toString(const Matrix3& val);
 
 
     /**
     /**
-     * @brief	Converts a 4x4 matrix to a string.
+     * Converts a 4x4 matrix to a string.
      * 			
      * 			
 	 * @note	Format is "00 01 02 03 10 11 12 13 20 21 22 23 30 31 32 33".
 	 * @note	Format is "00 01 02 03 10 11 12 13 20 21 22 23 30 31 32 33".
      */
      */
     BS_UTILITY_EXPORT String toString(const Matrix4& val);
     BS_UTILITY_EXPORT String toString(const Matrix4& val);
 
 
     /**
     /**
-     * @brief	Converts a Quaternion to a string.
+     * Converts a Quaternion to a string.
      * 			
      * 			
 	 * @note	Format is "w x y z".
 	 * @note	Format is "w x y z".
      */
      */
     BS_UTILITY_EXPORT String toString(const Quaternion& val);
     BS_UTILITY_EXPORT String toString(const Quaternion& val);
 
 
     /**
     /**
-     * @brief	Converts a color to a string.
+     * Converts a color to a string.
      * 			
      * 			
 	 * @note	Format is "r g b a".
 	 * @note	Format is "r g b a".
      */
      */
     BS_UTILITY_EXPORT String toString(const Color& val);
     BS_UTILITY_EXPORT String toString(const Color& val);
 
 
     /**
     /**
-     * @brief	Converts a vector of strings into a single string where the substrings are
-	 *			delimited by spaces.
+     * Converts a vector of strings into a single string where the substrings are delimited by spaces.
      */
      */
     BS_UTILITY_EXPORT String toString(const Vector<BansheeEngine::String>& val);
     BS_UTILITY_EXPORT String toString(const Vector<BansheeEngine::String>& val);
 
 
     /**
     /**
-     * @brief	Converts a String to a float.
+     * Converts a String to a float.
      *
      *
      * @note	0.0f if the value could not be parsed, otherwise the numeric version of the string.
      * @note	0.0f if the value could not be parsed, otherwise the numeric version of the string.
      */
      */
     BS_UTILITY_EXPORT float parseFloat(const String& val, float defaultValue = 0);
     BS_UTILITY_EXPORT float parseFloat(const String& val, float defaultValue = 0);
 
 
     /**
     /**
-     * @brief	Converts a String to a whole number.
+     * Converts a String to a whole number.
      *
      *
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      */
      */
     BS_UTILITY_EXPORT INT32 parseINT32(const String& val, INT32 defaultValue = 0);
     BS_UTILITY_EXPORT INT32 parseINT32(const String& val, INT32 defaultValue = 0);
 
 
     /**
     /**
-     * @brief	Converts a String to a whole number.
+     * Converts a String to a whole number.
      *
      *
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      */
      */
     BS_UTILITY_EXPORT UINT32 parseUINT32(const String& val, UINT32 defaultValue = 0);
     BS_UTILITY_EXPORT UINT32 parseUINT32(const String& val, UINT32 defaultValue = 0);
 
 
     /**
     /**
-     * @brief	Converts a String to a whole number.
+     * Converts a String to a whole number.
      *
      *
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      */
      */
     BS_UTILITY_EXPORT INT64 parseINT64(const String& val, INT64 defaultValue = 0);
     BS_UTILITY_EXPORT INT64 parseINT64(const String& val, INT64 defaultValue = 0);
 
 
     /**
     /**
-     * @brief	Converts a String to a whole number.
+     * Converts a String to a whole number.
      *
      *
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      */
      */
     BS_UTILITY_EXPORT UINT64 parseUINT64(const String& val, UINT64 defaultValue = 0);
     BS_UTILITY_EXPORT UINT64 parseUINT64(const String& val, UINT64 defaultValue = 0);
 
 
     /**
     /**
-     * @brief	Converts a String to a boolean.
+     * Converts a String to a boolean.
      *
      *
-	 * @note	Returns true if case-insensitive match of the start of the string
-	 *			matches "true", "yes" or "1", false otherwise.
+	 * @note	Returns true if case-insensitive match of the start of the string matches "true", "yes" or "1", 
+	 *			false otherwise.
      */
      */
     BS_UTILITY_EXPORT bool parseBool(const String& val, bool defaultValue = 0);
     BS_UTILITY_EXPORT bool parseBool(const String& val, bool defaultValue = 0);
 
 
-    /**
-     * @brief	Checks the String is a valid number value.
-     */
+    /** Checks the String is a valid number value. */
     BS_UTILITY_EXPORT bool isNumber(const String& val);
     BS_UTILITY_EXPORT bool isNumber(const String& val);
 
 
     /**
     /**
-     * @brief	Converts a WString to a float.
+     * Converts a WString to a float.
      *
      *
      * @note	0.0f if the value could not be parsed, otherwise the numeric version of the string.
      * @note	0.0f if the value could not be parsed, otherwise the numeric version of the string.
      */
      */
     BS_UTILITY_EXPORT float parseFloat(const WString& val, float defaultValue = 0);
     BS_UTILITY_EXPORT float parseFloat(const WString& val, float defaultValue = 0);
 
 
     /**
     /**
-     * @brief	Converts a WString to a whole number.
+     * Converts a WString to a whole number.
      *
      *
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      */
      */
     BS_UTILITY_EXPORT INT32 parseINT32(const WString& val, INT32 defaultValue = 0);
     BS_UTILITY_EXPORT INT32 parseINT32(const WString& val, INT32 defaultValue = 0);
 
 
     /**
     /**
-     * @brief	Converts a WString to a whole number.
+     * Converts a WString to a whole number.
      *
      *
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      */
      */
     BS_UTILITY_EXPORT UINT32 parseUINT32(const WString& val, UINT32 defaultValue = 0);
     BS_UTILITY_EXPORT UINT32 parseUINT32(const WString& val, UINT32 defaultValue = 0);
 
 
     /**
     /**
-     * @brief	Converts a WString to a whole number.
+     * Converts a WString to a whole number.
      *
      *
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      */
      */
     BS_UTILITY_EXPORT INT64 parseINT64(const WString& val, INT64 defaultValue = 0);
     BS_UTILITY_EXPORT INT64 parseINT64(const WString& val, INT64 defaultValue = 0);
 
 
     /**
     /**
-     * @brief	Converts a WString to a whole number.
+     * Converts a WString to a whole number.
      *
      *
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      * @note	0 if the value could not be parsed, otherwise the numeric version of the string.
      */
      */
     BS_UTILITY_EXPORT UINT64 parseUINT64(const WString& val, UINT64 defaultValue = 0);
     BS_UTILITY_EXPORT UINT64 parseUINT64(const WString& val, UINT64 defaultValue = 0);
 
 
     /**
     /**
-     * @brief	Converts a WString to a boolean.
+     * Converts a WString to a boolean.
      *
      *
 	 * @note	Returns true if case-insensitive match of the start of the string
 	 * @note	Returns true if case-insensitive match of the start of the string
 	 *			matches "true", "yes" or "1", false otherwise.
 	 *			matches "true", "yes" or "1", false otherwise.
@@ -842,18 +741,20 @@ namespace BansheeEngine
     BS_UTILITY_EXPORT bool parseBool(const WString& val, bool defaultValue = 0);
     BS_UTILITY_EXPORT bool parseBool(const WString& val, bool defaultValue = 0);
 
 
     /**
     /**
-     * @brief	Checks the WString is a valid number value.
+     * Checks the WString is a valid number value.
      */
      */
     BS_UTILITY_EXPORT bool isNumber(const WString& val);
     BS_UTILITY_EXPORT bool isNumber(const WString& val);
 
 
-	/**
-	 * @brief	Helper method that throws an exception regarding a data overflow.
-	 */
+	/** @cond INTERNAL */
+
+	/** Helper method that throws an exception regarding a data overflow. */
 	void BS_UTILITY_EXPORT __string_throwDataOverflowException();
 	void BS_UTILITY_EXPORT __string_throwDataOverflowException();
 
 
+	/** @endcond */
+	/** @cond SPECIALIZATIONS */
+
 	/**
 	/**
-	 * @brief	RTTIPlainType specialization for String that allows strings be serialized as
-	 * 			value types.
+	 * RTTIPlainType specialization for String that allows strings be serialized as value types.
 	 * 			
 	 * 			
 	 * @see		RTTIPlainType
 	 * @see		RTTIPlainType
 	 */
 	 */
@@ -904,8 +805,7 @@ namespace BansheeEngine
 	}; 
 	}; 
 
 
 	/**
 	/**
-	 * @brief	RTTIPlainType specialization for WString that allows strings be serialized as
-	 * 			value types.
+	 * RTTIPlainType specialization for WString that allows strings be serialized as value types.
 	 * 			
 	 * 			
 	 * @see		RTTIPlainType
 	 * @see		RTTIPlainType
 	 */
 	 */
@@ -957,11 +857,13 @@ namespace BansheeEngine
 			return (UINT32)dataSize;
 			return (UINT32)dataSize;
 		}	
 		}	
 	}; 
 	}; 
+
+	/** @endcond */
 }
 }
 
 
-/**
- * @brief	Hash value generator for String.
- */
+/** @cond STDLIB */
+
+/** Hash value generator for String. */
 template<> 
 template<> 
 struct std::hash<BansheeEngine::String>
 struct std::hash<BansheeEngine::String>
 {
 {
@@ -974,9 +876,7 @@ struct std::hash<BansheeEngine::String>
 	}
 	}
 };
 };
 
 
-/**
- * @brief	Hash value generator for WString.
- */
+/**	Hash value generator for WString. */
 template<> 
 template<> 
 struct std::hash<BansheeEngine::WString>
 struct std::hash<BansheeEngine::WString>
 {
 {
@@ -987,4 +887,7 @@ struct std::hash<BansheeEngine::WString>
 			hash = 65599 * hash + string[i];
 			hash = 65599 * hash + string[i];
 		return hash ^ (hash >> 16);
 		return hash ^ (hash >> 16);
 	}
 	}
-};
+};
+
+/** @endcond */
+/** @} */

+ 281 - 310
BansheeUtility/Include/BsStringFormat.h

@@ -1,311 +1,282 @@
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Helper class used for string formatting operations.
-	 */
-	class StringFormat
-	{
-	private:
-		/**
-		 * @brief	Data structure used during string formatting. It holds
-		 *			information about parameter identifiers to replace with
-		 *			actual parameters.
-		 */
-		struct FormatParamRange
-		{
-			FormatParamRange() { }
-			FormatParamRange(UINT32 start, UINT32 identifierSize, UINT32 paramIdx)
-				:start(start), identifierSize(identifierSize), paramIdx(paramIdx)
-			{ }
-
-			UINT32 start;
-			UINT32 identifierSize;
-			UINT32 paramIdx;
-		};
-
-		/**
-		 * @brief	Structure that holds value of a parameter during string
-		 *			formatting.
-		 */
-		template<class T>
-		struct ParamData
-		{
-			T* buffer;
-			UINT32 size;
-		};
-
-	public:
-		/**
-		 * @brief	Formats the provided string by replacing the identifiers with the provided parameters.
-		 *			The identifiers are represented like "{0}, {1}" in the source string, where the number
-		 *			represents the position of the parameter that will be used for replacing the identifier.
-		 *			
-		 * @note	You may use "\" to escape identifier brackets.
-		 *			Maximum identifier number is 19 (for a total of 20 unique identifiers. e.g. {20} won't be recognized as an identifier).
-		 *			Total number of parameters that can be referenced is 200.
-		 */
-		template<class T, class... Args>
-		static BasicString<T> format(const T* source, Args&& ...args)
-		{
-			UINT32 strLength = getLength(source);
-
-			ParamData<T> parameters[MAX_PARAMS];
-			memset(parameters, 0, sizeof(parameters));
-			getParams(parameters, 0U, std::forward<Args>(args)...);
-
-			T bracketChars[MAX_IDENTIFIER_SIZE + 1];
-			UINT32 bracketWriteIdx = 0;
-
-			FormatParamRange paramRanges[MAX_PARAM_REFERENCES];
-			memset(paramRanges, 0, sizeof(paramRanges));
-			UINT32 paramRangeWriteIdx = 0;
-
-			// Determine parameter positions
-			INT32 lastBracket = -1;
-			bool escaped = false;
-			UINT32 charWriteIdx = 0;
-			for (UINT32 i = 0; i < strLength; i++)
-			{
-				if (source[i] == '\\' && !escaped && paramRangeWriteIdx < MAX_PARAM_REFERENCES)
-				{
-					escaped = true;
-					paramRanges[paramRangeWriteIdx++] = FormatParamRange(charWriteIdx, 1, (UINT32)-1);
-					continue;
-				}
-
-				if (lastBracket == -1)
-				{
-					// If current char is non-escaped opening bracket start parameter definition
-					if (source[i] == '{' && !escaped)
-						lastBracket = i;
-					else
-						charWriteIdx++;
-				}
-				else
-				{
-					if (isdigit(source[i]) && bracketWriteIdx < MAX_IDENTIFIER_SIZE)
-						bracketChars[bracketWriteIdx++] = source[i];
-					else
-					{
-						// If current char is non-escaped closing bracket end parameter definition
-						UINT32 numParamChars = bracketWriteIdx;
-						bool processedBracket = false;
-						if (source[i] == '}' && numParamChars > 0 && !escaped)
-						{
-							bracketChars[bracketWriteIdx] = '\0';
-							UINT32 paramIdx = strToInt(bracketChars);
-							if (paramIdx < MAX_PARAMS && paramRangeWriteIdx < MAX_PARAM_REFERENCES) // Check if exceeded maximum parameter limit
-							{
-								paramRanges[paramRangeWriteIdx++] = FormatParamRange(charWriteIdx, numParamChars + 2, paramIdx);
-								charWriteIdx += parameters[paramIdx].size;
-
-								processedBracket = true;
-							}
-						}
-
-						if (!processedBracket)
-						{
-							// Last bracket wasn't really a parameter
-							for (UINT32 j = lastBracket; j <= i; j++)
-								charWriteIdx++;
-						}
-
-						lastBracket = -1;
-						bracketWriteIdx = 0;
-					}
-				}
-
-				escaped = false;
-			}
-
-			// Copy the clean string into output buffer
-			UINT32 finalStringSize = charWriteIdx;
-
-			T* outputBuffer = (T*)bs_alloc(finalStringSize * sizeof(T));
-			UINT32 copySourceIdx = 0;
-			UINT32 copyDestIdx = 0;
-			for (UINT32 i = 0; i < paramRangeWriteIdx; i++)
-			{
-				const FormatParamRange& rangeInfo = paramRanges[i];
-				UINT32 copySize = rangeInfo.start - copyDestIdx;
-				
-				memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, copySize * sizeof(T));
-				copySourceIdx += copySize + rangeInfo.identifierSize;
-				copyDestIdx += copySize;
-
-				if (rangeInfo.paramIdx == (UINT32)-1)
-					continue;
-
-				UINT32 paramSize = parameters[rangeInfo.paramIdx].size;
-				memcpy(outputBuffer + copyDestIdx, parameters[rangeInfo.paramIdx].buffer, paramSize * sizeof(T));
-				copyDestIdx += paramSize;
-			}
-
-			memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, (finalStringSize - copyDestIdx) * sizeof(T));
-
-			BasicString<T> outputStr(outputBuffer, finalStringSize);
-			bs_free(outputBuffer);
-
-			for (UINT32 i = 0; i < MAX_PARAMS; i++)
-			{
-				if (parameters[i].buffer != nullptr)
-					bs_free(parameters[i].buffer);
-			}
-
-			return outputStr;
-		}
-
-	private:
-		/**
-		 * @brief	Set of methods that can be specialized so we have a generalized way for retrieving length
-		 *			of strings of different types.
-		 */
-		static UINT32 getLength(const char* source) { return (UINT32)strlen(source); }
-
-		/**
-		 * @brief	Set of methods that can be specialized so we have a generalized way for retrieving length
-		 *			of strings of different types.
-		 */
-		static UINT32 getLength(const wchar_t* source) { return (UINT32)wcslen(source); }
-
-		/**
-		 * @brief	Parses the string and returns an integer value extracted from string characters.
-		 */
-		static UINT32 strToInt(const char* buffer)
-		{
-			return (UINT32)strtoul(buffer, nullptr, 10);
-		}
-
-		/**
-		 * @brief	Parses the string and returns an integer value extracted from string characters.
-		 */
-		static UINT32 strToInt(const wchar_t* buffer)
-		{
-			return (UINT32)wcstoul(buffer, nullptr, 10);
-		}
-
-		/**
-		 * @brief	Helper method for converting any data type to a narrow string.
-		 */
-		template<class T> static std::string toString(const T& param) { return std::to_string(param); }
-
-		/**
-		 * @brief	Helper method that "converts" a narrow string to a narrow string (simply a pass through).
-		 */
-		template<> static std::string toString<std::string>(const std::string& param) { return param; }
-
-		/**
-		 * @brief	Helper method that converts a Banshee narrow string to a standard narrow string.
-		 */
-		template<> static std::string toString<String>(const String& param)
-		{
-			return std::string(param.c_str());
-		}
-
-		/**
-		 * @brief	Helper method that converts a narrow character array to a narrow string.
-		 */
-		template<class T> static std::string toString(T* param) { static_assert("Invalid pointer type."); }
-
-		/**
-		 * @brief	Helper method that converts a narrow character array to a narrow string.
-		 */
-		template<> static std::string toString<const char>(const char* param) { return std::string(param); }
-
-		/**
-		 * @brief	Helper method that converts a narrow character array to a narrow string.
-		 */
-		template<> static std::string toString<char>(char* param) { return std::string(param); }
-
-		/**
-		 * @brief	Helper method for converting any data type to a wide string.
-		 */
-		template<class T> static std::wstring toWString(const T& param) { return std::to_wstring(param); }
-
-		/**
-		 * @brief	Helper method that "converts" a wide string to a wide string (simply a pass through).
-		 */
-		template<> static std::wstring toWString<std::wstring>(const std::wstring& param) { return param; }
-
-		/**
-		 * @brief	Helper method that converts a Banshee wide string to a standard wide string.
-		 */
-		template<> static std::wstring toWString<WString>(const WString& param)
-		{
-			return std::wstring(param.c_str());
-		}
-
-		/**
-		 * @brief	Helper method that converts a wide character array to a wide string.
-		 */
-		template<class T> static std::wstring toWString(T* param) { static_assert("Invalid pointer type."); }
-
-		/**
-		 * @brief	Helper method that converts a wide character array to a wide string.
-		 */
-		template<> static std::wstring toWString<const wchar_t>(const wchar_t* param) { return std::wstring(param); }
-
-		/**
-		* @brief	Helper method that converts a wide character array to a wide string.
-		*/
-		template<> static std::wstring toWString<wchar_t>(wchar_t* param) { return std::wstring(param); }
-
-		/**
-		 * @brief	Converts all the provided parameters into string representations and populates the provided
-		 *			"parameter" array.
-		 */
-		template<class P, class... Args>
-		static void getParams(ParamData<char>* parameters, UINT32 idx, P&& param, Args&& ...args)
-		{
-			if (idx >= MAX_PARAMS)
-				return;
-
-			std::basic_string<char> sourceParam = toString(param);
-			parameters[idx].buffer = (char*)bs_alloc((UINT32)sourceParam.size() * sizeof(char));
-			parameters[idx].size = (UINT32)sourceParam.size();
-
-			sourceParam.copy(parameters[idx].buffer, parameters[idx].size, 0);
-			
-			getParams(parameters, idx + 1, std::forward<Args>(args)...);
-		}
-
-		/**
-		 * @brief	Converts all the provided parameters into string representations and populates the provided
-		 *			"parameter" array.
-		 */
-		template<class P, class... Args>
-		static void getParams(ParamData<wchar_t>* parameters, UINT32 idx, P&& param, Args&& ...args)
-		{
-			if (idx >= MAX_PARAMS)
-				return;
-
-			std::basic_string<wchar_t> sourceParam = toWString(param);
-			parameters[idx].buffer = (wchar_t*)bs_alloc((UINT32)sourceParam.size() * sizeof(wchar_t));
-			parameters[idx].size = (UINT32)sourceParam.size();
-			
-			sourceParam.copy(parameters[idx].buffer, parameters[idx].size, 0);
-
-			getParams(parameters, idx + 1, std::forward<Args>(args)...);
-		}
-
-		/**
-		 * @brief	Helper method for parameter size calculation. Used as a stopping point in template recursion.
-		 */
-		static void getParams(ParamData<char>* parameters, UINT32 idx)
-		{
-			// Do nothing
-		}
-
-		/**
-		 * @brief	Helper method for parameter size calculation. Used as a stopping point in template recursion.
-		 */
-		static void getParams(ParamData<wchar_t>* parameters, UINT32 idx)
-		{
-			// Do nothing
-		}
-
-		static const UINT32 MAX_PARAMS = 20;
-		static const UINT32 MAX_IDENTIFIER_SIZE = 2;
-		static const UINT32 MAX_PARAM_REFERENCES = 200;
-	};
+namespace BansheeEngine
+{
+	/** @cond INTERNAL */
+	/** @addtogroup String
+	 *  @{
+	 */
+
+	/** Helper class used for string formatting operations. */
+	class StringFormat
+	{
+	private:
+		/**
+		 * Data structure used during string formatting. It holds information about parameter identifiers to replace with
+		 * actual parameters.
+		 */
+		struct FormatParamRange
+		{
+			FormatParamRange() { }
+			FormatParamRange(UINT32 start, UINT32 identifierSize, UINT32 paramIdx)
+				:start(start), identifierSize(identifierSize), paramIdx(paramIdx)
+			{ }
+
+			UINT32 start;
+			UINT32 identifierSize;
+			UINT32 paramIdx;
+		};
+
+		/**
+		 * @brief	Structure that holds value of a parameter during string
+		 *			formatting.
+		 */
+		template<class T>
+		struct ParamData
+		{
+			T* buffer;
+			UINT32 size;
+		};
+
+	public:
+		/**
+		 * Formats the provided string by replacing the identifiers with the provided parameters. The identifiers are 
+		 * represented like "{0}, {1}" in the source string, where the number represents the position of the parameter 
+		 * that will be used for replacing the identifier.
+		 *			
+		 * @note	You may use "\" to escape identifier brackets.
+		 * @note	Maximum identifier number is 19 (for a total of 20 unique identifiers. e.g. {20} won't be recognized as an identifier).
+		 * @note	Total number of parameters that can be referenced is 200.
+		 */
+		template<class T, class... Args>
+		static BasicString<T> format(const T* source, Args&& ...args)
+		{
+			UINT32 strLength = getLength(source);
+
+			ParamData<T> parameters[MAX_PARAMS];
+			memset(parameters, 0, sizeof(parameters));
+			getParams(parameters, 0U, std::forward<Args>(args)...);
+
+			T bracketChars[MAX_IDENTIFIER_SIZE + 1];
+			UINT32 bracketWriteIdx = 0;
+
+			FormatParamRange paramRanges[MAX_PARAM_REFERENCES];
+			memset(paramRanges, 0, sizeof(paramRanges));
+			UINT32 paramRangeWriteIdx = 0;
+
+			// Determine parameter positions
+			INT32 lastBracket = -1;
+			bool escaped = false;
+			UINT32 charWriteIdx = 0;
+			for (UINT32 i = 0; i < strLength; i++)
+			{
+				if (source[i] == '\\' && !escaped && paramRangeWriteIdx < MAX_PARAM_REFERENCES)
+				{
+					escaped = true;
+					paramRanges[paramRangeWriteIdx++] = FormatParamRange(charWriteIdx, 1, (UINT32)-1);
+					continue;
+				}
+
+				if (lastBracket == -1)
+				{
+					// If current char is non-escaped opening bracket start parameter definition
+					if (source[i] == '{' && !escaped)
+						lastBracket = i;
+					else
+						charWriteIdx++;
+				}
+				else
+				{
+					if (isdigit(source[i]) && bracketWriteIdx < MAX_IDENTIFIER_SIZE)
+						bracketChars[bracketWriteIdx++] = source[i];
+					else
+					{
+						// If current char is non-escaped closing bracket end parameter definition
+						UINT32 numParamChars = bracketWriteIdx;
+						bool processedBracket = false;
+						if (source[i] == '}' && numParamChars > 0 && !escaped)
+						{
+							bracketChars[bracketWriteIdx] = '\0';
+							UINT32 paramIdx = strToInt(bracketChars);
+							if (paramIdx < MAX_PARAMS && paramRangeWriteIdx < MAX_PARAM_REFERENCES) // Check if exceeded maximum parameter limit
+							{
+								paramRanges[paramRangeWriteIdx++] = FormatParamRange(charWriteIdx, numParamChars + 2, paramIdx);
+								charWriteIdx += parameters[paramIdx].size;
+
+								processedBracket = true;
+							}
+						}
+
+						if (!processedBracket)
+						{
+							// Last bracket wasn't really a parameter
+							for (UINT32 j = lastBracket; j <= i; j++)
+								charWriteIdx++;
+						}
+
+						lastBracket = -1;
+						bracketWriteIdx = 0;
+					}
+				}
+
+				escaped = false;
+			}
+
+			// Copy the clean string into output buffer
+			UINT32 finalStringSize = charWriteIdx;
+
+			T* outputBuffer = (T*)bs_alloc(finalStringSize * sizeof(T));
+			UINT32 copySourceIdx = 0;
+			UINT32 copyDestIdx = 0;
+			for (UINT32 i = 0; i < paramRangeWriteIdx; i++)
+			{
+				const FormatParamRange& rangeInfo = paramRanges[i];
+				UINT32 copySize = rangeInfo.start - copyDestIdx;
+				
+				memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, copySize * sizeof(T));
+				copySourceIdx += copySize + rangeInfo.identifierSize;
+				copyDestIdx += copySize;
+
+				if (rangeInfo.paramIdx == (UINT32)-1)
+					continue;
+
+				UINT32 paramSize = parameters[rangeInfo.paramIdx].size;
+				memcpy(outputBuffer + copyDestIdx, parameters[rangeInfo.paramIdx].buffer, paramSize * sizeof(T));
+				copyDestIdx += paramSize;
+			}
+
+			memcpy(outputBuffer + copyDestIdx, source + copySourceIdx, (finalStringSize - copyDestIdx) * sizeof(T));
+
+			BasicString<T> outputStr(outputBuffer, finalStringSize);
+			bs_free(outputBuffer);
+
+			for (UINT32 i = 0; i < MAX_PARAMS; i++)
+			{
+				if (parameters[i].buffer != nullptr)
+					bs_free(parameters[i].buffer);
+			}
+
+			return outputStr;
+		}
+
+	private:
+		/**
+		 * Set of methods that can be specialized so we have a generalized way for retrieving length of strings of 
+		 * different types.
+		 */
+		static UINT32 getLength(const char* source) { return (UINT32)strlen(source); }
+
+		/**
+		 * Set of methods that can be specialized so we have a generalized way for retrieving length of strings of 
+		 * different types.
+		 */
+		static UINT32 getLength(const wchar_t* source) { return (UINT32)wcslen(source); }
+
+		/** Parses the string and returns an integer value extracted from string characters. */
+		static UINT32 strToInt(const char* buffer)
+		{
+			return (UINT32)strtoul(buffer, nullptr, 10);
+		}
+
+		/** Parses the string and returns an integer value extracted from string characters. */
+		static UINT32 strToInt(const wchar_t* buffer)
+		{
+			return (UINT32)wcstoul(buffer, nullptr, 10);
+		}
+
+		/**	Helper method for converting any data type to a narrow string. */
+		template<class T> static std::string toString(const T& param) { return std::to_string(param); }
+
+		/**	Helper method that "converts" a narrow string to a narrow string (simply a pass through). */
+		template<> static std::string toString<std::string>(const std::string& param) { return param; }
+
+		/**	Helper method that converts a Banshee narrow string to a standard narrow string. */
+		template<> static std::string toString<String>(const String& param)
+		{
+			return std::string(param.c_str());
+		}
+
+		/**	Helper method that converts a narrow character array to a narrow string. */
+		template<class T> static std::string toString(T* param) { static_assert("Invalid pointer type."); }
+
+		/**	Helper method that converts a narrow character array to a narrow string. */
+		template<> static std::string toString<const char>(const char* param) { return std::string(param); }
+
+		/**	Helper method that converts a narrow character array to a narrow string. */
+		template<> static std::string toString<char>(char* param) { return std::string(param); }
+
+		/**	Helper method for converting any data type to a wide string. */
+		template<class T> static std::wstring toWString(const T& param) { return std::to_wstring(param); }
+
+		/**	Helper method that "converts" a wide string to a wide string (simply a pass through). */
+		template<> static std::wstring toWString<std::wstring>(const std::wstring& param) { return param; }
+
+		/**	Helper method that converts a Banshee wide string to a standard wide string. */
+		template<> static std::wstring toWString<WString>(const WString& param)
+		{
+			return std::wstring(param.c_str());
+		}
+
+		/**	Helper method that converts a wide character array to a wide string. */
+		template<class T> static std::wstring toWString(T* param) { static_assert("Invalid pointer type."); }
+
+		/**	Helper method that converts a wide character array to a wide string. */
+		template<> static std::wstring toWString<const wchar_t>(const wchar_t* param) { return std::wstring(param); }
+
+		/**	Helper method that converts a wide character array to a wide string. */
+		template<> static std::wstring toWString<wchar_t>(wchar_t* param) { return std::wstring(param); }
+
+		/**
+		 * Converts all the provided parameters into string representations and populates the provided @p parameters array.
+		 */
+		template<class P, class... Args>
+		static void getParams(ParamData<char>* parameters, UINT32 idx, P&& param, Args&& ...args)
+		{
+			if (idx >= MAX_PARAMS)
+				return;
+
+			std::basic_string<char> sourceParam = toString(param);
+			parameters[idx].buffer = (char*)bs_alloc((UINT32)sourceParam.size() * sizeof(char));
+			parameters[idx].size = (UINT32)sourceParam.size();
+
+			sourceParam.copy(parameters[idx].buffer, parameters[idx].size, 0);
+			
+			getParams(parameters, idx + 1, std::forward<Args>(args)...);
+		}
+
+		/**
+		 * Converts all the provided parameters into string representations and populates the provided @p parameters array.
+		 */
+		template<class P, class... Args>
+		static void getParams(ParamData<wchar_t>* parameters, UINT32 idx, P&& param, Args&& ...args)
+		{
+			if (idx >= MAX_PARAMS)
+				return;
+
+			std::basic_string<wchar_t> sourceParam = toWString(param);
+			parameters[idx].buffer = (wchar_t*)bs_alloc((UINT32)sourceParam.size() * sizeof(wchar_t));
+			parameters[idx].size = (UINT32)sourceParam.size();
+			
+			sourceParam.copy(parameters[idx].buffer, parameters[idx].size, 0);
+
+			getParams(parameters, idx + 1, std::forward<Args>(args)...);
+		}
+
+		/** Helper method for parameter size calculation. Used as a stopping point in template recursion. */
+		static void getParams(ParamData<char>* parameters, UINT32 idx)
+		{
+			// Do nothing
+		}
+
+		/**	Helper method for parameter size calculation. Used as a stopping point in template recursion. */
+		static void getParams(ParamData<wchar_t>* parameters, UINT32 idx)
+		{
+			// Do nothing
+		}
+
+		static const UINT32 MAX_PARAMS = 20;
+		static const UINT32 MAX_IDENTIFIER_SIZE = 2;
+		static const UINT32 MAX_PARAM_REFERENCES = 200;
+	};
+
+	/** @} */
+	/** @endcond */
 }
 }

+ 192 - 204
BansheeUtility/Include/BsStringID.h

@@ -1,205 +1,193 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsSpinLock.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	A string identifier that provides very fast comparisons
-	 *			to other string ids.
-	 *
-	 * @note	Essentially a unique ID is generated for each string and then
-	 *			the ID is used for comparisons as if you were using an integer
-	 *			or an enum.
-	 *
-	 *			Thread safe.
-	 */
-	class BS_UTILITY_EXPORT StringID
-	{
-		static const int HASH_TABLE_SIZE = 4096;
-		static const int MAX_CHUNK_COUNT = 50;
-		static const int ELEMENTS_PER_CHUNK = 256;
-		static const int STRING_SIZE = 256;
-
-		/**
-		 * @brief	Helper class that performs string actions on both null terminated character
-		 *			arrays and standard strings.
-		 */
-		template<class T>
-		class StringIDUtil
-		{
-		public:
-			static UINT32 size(T const& input) { return 0; }
-			static void copy(T const& input, char* dest) { }
-			static bool compare(T const& a, char* b) { return 0; }
-		};
-
-		/**
-		 * @brief	Internal data that is shared by all instances for a specific string.
-		 */
-		struct InternalData
-		{
-			UINT32 id;
-			InternalData* next;
-			char chars[STRING_SIZE];
-		};
-
-		/**
-		 * @brief	Performs initialization of static members as soon as the library is loaded.
-		 */
-		struct InitStatics
-		{
-			InitStatics();
-		};
-
-	public:
-		StringID();
-
-		StringID(const char* name)
-			:mData(nullptr)
-		{
-			construct(name);
-		}
-
-		StringID(const String& name)
-			:mData(nullptr)
-		{
-			construct(name);
-		}
-
-		template<int N>
-		StringID(const char name[N])
-			:mData(nullptr)
-		{
-			construct((const char*)name);
-		}
-
-		/**
-		 * @brief	Compare to string ids for equality. Uses fast integer comparison.
-		 */
-		bool operator== (const StringID& rhs) const
-		{
-			return mData == rhs.mData;
-		}
-
-		/**
-		 * @brief	Compare to string ids for inequality. Uses fast integer comparison.
-		 */
-		bool operator!= (const StringID& rhs) const
-		{
-			return mData != rhs.mData;
-		}
-
-		/**
-		 * @brief	Returns true if the string id has no value assigned.
-		 */
-		bool empty() const
-		{
-			return mData == nullptr;
-		}
-
-		/**
-		 * @brief	Returns the null-terminated name of the string id.
-		 */
-		const char* cstr() const
-		{
-			if (mData == nullptr)
-				return nullptr;
-
-			return mData->chars;
-		}
-
-		static const StringID NONE;
-
-	private:
-		/**
-		 * @brief	Constructs a StringID object in a way that works for pointers to character arrays
-		 *			and standard strings.
-		 */
-		template<class T>
-		void construct(T const& name);
-
-		/**
-		 * @brief	Calculates a hash value for the provided null-terminated string. 
-		 */
-		template<class T>
-		UINT32 calcHash(T const& input);
-
-		/**
-		 * @brief	Allocates a new string entry and assigns it a unique ID. 
-		 *			Optionally expands the chunks buffer if the new entry doesn't fit.
-		 */
-		InternalData* allocEntry();
-
-		InternalData* mData;
-
-		static volatile InitStatics mInitStatics;
-		static InternalData* mStringHashTable[HASH_TABLE_SIZE];
-		static InternalData* mChunks[MAX_CHUNK_COUNT];
-
-		static UINT32 mNextId;
-		static UINT32 mNumChunks;
-		static SpinLock mSync;
-	};
-
-	template<> struct RTTIPlainType <StringID>
-	{
-		enum { id = TID_StringID }; enum { hasDynamicSize = 1 };
-
-		static void toMemory(const StringID& data, char* memory)
-		{
-			UINT32 size = getDynamicSize(data);
-
-			UINT32 curSize = sizeof(UINT32);
-			memcpy(memory, &size, curSize);
-			memory += curSize;
-
-			bool isEmpty = data.empty();
-			memory = rttiWriteElem(isEmpty, memory);
-
-			if (!isEmpty)
-			{
-				UINT32 length = (UINT32)strlen(data.cstr());
-				memcpy(memory, data.cstr(), length * sizeof(char));
-			}
-		}
-
-		static UINT32 fromMemory(StringID& data, char* memory)
-		{
-			UINT32 size;
-			memcpy(&size, memory, sizeof(UINT32));
-			memory += sizeof(UINT32);
-
-			bool empty = false;
-			memory = rttiReadElem(empty, memory);
-
-			if (!empty)
-			{
-				UINT32 length = (size - sizeof(UINT32) - sizeof(bool)) / sizeof(char);
-
-				char* name = (char*)bs_alloc(length + 1);
-				memcpy(name, memory, length);
-				name[length] = '\0';
-
-				data = StringID(name);
-			}
-
-			return size;
-		}
-
-		static UINT32 getDynamicSize(const StringID& data)
-		{
-			UINT32 dataSize = sizeof(bool) + sizeof(UINT32);
-
-			bool isEmpty = data.empty();
-			if (!isEmpty)
-			{
-				UINT32 length = (UINT32)strlen(data.cstr());
-				dataSize += length * sizeof(char);
-			}
-
-			return (UINT32)dataSize;
-		}
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsSpinLock.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup String
+	 *  @{
+	 */
+
+	/**
+	 * A string identifier that provides very fast comparisons to other string ids.
+	 *
+	 * @note	
+	 * Essentially a unique ID is generated for each string and then the ID is used for comparisons as if you were using 
+	 * an integer or an enum.
+	 * @note
+	 * Thread safe.
+	 */
+	class BS_UTILITY_EXPORT StringID
+	{
+		static const int HASH_TABLE_SIZE = 4096;
+		static const int MAX_CHUNK_COUNT = 50;
+		static const int ELEMENTS_PER_CHUNK = 256;
+		static const int STRING_SIZE = 256;
+
+		/** Helper class that performs string actions on both null terminated character arrays and standard strings. */
+		template<class T>
+		class StringIDUtil
+		{
+		public:
+			static UINT32 size(T const& input) { return 0; }
+			static void copy(T const& input, char* dest) { }
+			static bool compare(T const& a, char* b) { return 0; }
+		};
+
+		/**	Internal data that is shared by all instances for a specific string. */
+		struct InternalData
+		{
+			UINT32 id;
+			InternalData* next;
+			char chars[STRING_SIZE];
+		};
+
+		/**	Performs initialization of static members as soon as the library is loaded. */
+		struct InitStatics
+		{
+			InitStatics();
+		};
+
+	public:
+		StringID();
+
+		StringID(const char* name)
+			:mData(nullptr)
+		{
+			construct(name);
+		}
+
+		StringID(const String& name)
+			:mData(nullptr)
+		{
+			construct(name);
+		}
+
+		template<int N>
+		StringID(const char name[N])
+			:mData(nullptr)
+		{
+			construct((const char*)name);
+		}
+
+		/**	Compare to string ids for equality. Uses fast integer comparison. */
+		bool operator== (const StringID& rhs) const
+		{
+			return mData == rhs.mData;
+		}
+
+		/**	Compare to string ids for inequality. Uses fast integer comparison. */
+		bool operator!= (const StringID& rhs) const
+		{
+			return mData != rhs.mData;
+		}
+
+		/**	Returns true if the string id has no value assigned. */
+		bool empty() const
+		{
+			return mData == nullptr;
+		}
+
+		/**	Returns the null-terminated name of the string id. */
+		const char* cstr() const
+		{
+			if (mData == nullptr)
+				return nullptr;
+
+			return mData->chars;
+		}
+
+		static const StringID NONE;
+
+	private:
+		/**Constructs a StringID object in a way that works for pointers to character arrays and standard strings. */
+		template<class T>
+		void construct(T const& name);
+
+		/**	Calculates a hash value for the provided null-terminated string. */
+		template<class T>
+		UINT32 calcHash(T const& input);
+
+		/**
+		 * Allocates a new string entry and assigns it a unique ID. Optionally expands the chunks buffer if the new entry 
+		 * doesn't fit.
+		 */
+		InternalData* allocEntry();
+
+		InternalData* mData;
+
+		static volatile InitStatics mInitStatics;
+		static InternalData* mStringHashTable[HASH_TABLE_SIZE];
+		static InternalData* mChunks[MAX_CHUNK_COUNT];
+
+		static UINT32 mNextId;
+		static UINT32 mNumChunks;
+		static SpinLock mSync;
+	};
+
+	/** @cond SPECIALIZATIONS */
+
+	template<> struct RTTIPlainType <StringID>
+	{
+		enum { id = TID_StringID }; enum { hasDynamicSize = 1 };
+
+		static void toMemory(const StringID& data, char* memory)
+		{
+			UINT32 size = getDynamicSize(data);
+
+			UINT32 curSize = sizeof(UINT32);
+			memcpy(memory, &size, curSize);
+			memory += curSize;
+
+			bool isEmpty = data.empty();
+			memory = rttiWriteElem(isEmpty, memory);
+
+			if (!isEmpty)
+			{
+				UINT32 length = (UINT32)strlen(data.cstr());
+				memcpy(memory, data.cstr(), length * sizeof(char));
+			}
+		}
+
+		static UINT32 fromMemory(StringID& data, char* memory)
+		{
+			UINT32 size;
+			memcpy(&size, memory, sizeof(UINT32));
+			memory += sizeof(UINT32);
+
+			bool empty = false;
+			memory = rttiReadElem(empty, memory);
+
+			if (!empty)
+			{
+				UINT32 length = (size - sizeof(UINT32) - sizeof(bool)) / sizeof(char);
+
+				char* name = (char*)bs_alloc(length + 1);
+				memcpy(name, memory, length);
+				name[length] = '\0';
+
+				data = StringID(name);
+			}
+
+			return size;
+		}
+
+		static UINT32 getDynamicSize(const StringID& data)
+		{
+			UINT32 dataSize = sizeof(bool) + sizeof(UINT32);
+
+			bool isEmpty = data.empty();
+			if (!isEmpty)
+			{
+				UINT32 length = (UINT32)strlen(data.cstr());
+				dataSize += length * sizeof(char);
+			}
+
+			return (UINT32)dataSize;
+		}
+	};
+
+	/** @endcond */
+	/** @} */
 }
 }

+ 136 - 153
BansheeUtility/Include/BsTaskScheduler.h

@@ -1,154 +1,137 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsModule.h"
-#include "BsThreadPool.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Task priority. Tasks with higher priority will get executed sooner.
-	 */
-	enum class TaskPriority
-	{
-		VeryLow = 98,
-		Low = 99,
-		Normal = 100,
-		High = 101,
-		VeryHigh = 102
-	};
-
-	/**
-	 * @brief	Represents a single task that may be queued in the TaskScheduler.
-	 * 			
-	 * @note	Thread safe.
-	 */
-	class BS_UTILITY_EXPORT Task
-	{
-		struct PrivatelyConstruct {};
-
-	public:
-		Task(const PrivatelyConstruct& dummy, const String& name, std::function<void()> taskWorker, 
-			TaskPriority priority, TaskPtr dependency);
-
-		/**
-		 * @brief	Creates a new task. Task should be provided to TaskScheduler in order for it
-		 * 			to start.
-		 *
-		 * @param	name		Name you can use to more easily identify the task.
-		 * @param	taskWorker	Worker method that does all of the work in the task.
-		 * @param	priority  	(optional) Higher priority means the tasks will be executed sooner.
-		 * @param	dependency	(optional) Task dependency if one exists. If provided the task will
-		 * 						not be executed until its dependency is complete.
-		 */
-		static TaskPtr create(const String& name, std::function<void()> taskWorker, TaskPriority priority = TaskPriority::Normal, 
-			TaskPtr dependency = nullptr);
-
-		/**
-		 * @brief	Returns true if the task has completed.
-		 */
-		bool isComplete() const;
-
-		/**
-		 * @brief	Returns true if the task has been canceled.
-		 */
-		bool isCanceled() const;
-
-		/**
-		 * @brief	Blocks the current thread until the task has completed. 
-		 * 			
-		 * @note	While waiting adds a new worker thread, so that the blocking threads core can be utilized.
-		 */
-		void wait();
-
-		/**
-		 * @brief	Cancels the task and removes it from the TaskSchedulers queue.
-		 */
-		void cancel();
-
-	private:
-		friend class TaskScheduler;
-
-		String mName;
-		TaskPriority mPriority;
-		UINT32 mTaskId;
-		std::function<void()> mTaskWorker;
-		TaskPtr mTaskDependency;
-		std::atomic<UINT32> mState; /**< 0 - Inactive, 1 - In progress, 2 - Completed, 3 - Canceled */
-
-		TaskScheduler* mParent;
-	};
-
-	/**
-	 * @brief	Represents a task scheduler running on multiple threads. You may queue
-	 * 			tasks on it from any thread and they will be executed in user specified order
-	 * 			on any available thread.
-	 * 			
-	 * @note	Thread safe.
-	 * 			
-	 *			This type of task scheduler uses a global queue and is best used for coarse granularity of tasks.
-	 *			(Number of tasks in the order of hundreds. Higher number of tasks might require different queuing and
-	 *			locking mechanism, potentially at the cost of flexibility.)
-	 *			
-	 *			By default the task scheduler will create as many threads as there are physical CPU cores. You may add or remove
-	 *			threads using addWorker/removeWorker methods.
-	 */
-	class BS_UTILITY_EXPORT TaskScheduler : public Module<TaskScheduler>
-	{
-	public:
-		TaskScheduler();
-		~TaskScheduler();
-
-		/**
-		 * @brief	Queues a new task.
-		 */
-		void addTask(const TaskPtr& task);
-
-		/**
-		 * @brief	Adds a new worker thread which will be used for executing queued tasks.
-		 */
-		void addWorker();
-
-		/**
-		 * @brief	Removes a worker thread (as soon as its current task is finished).
-		 */
-		void removeWorker();
-
-	protected:
-		friend class Task;
-
-		/**
-		 * @brief	Main task scheduler method that dispatches tasks to other threads.
-		 */
-		void runMain();
-
-		/**
-		 * @brief	Worker method that runs a single task.
-		 */
-		void runTask(TaskPtr task);
-
-		/**
-		 * @brief	Blocks the calling thread until the specified task has completed.
-		 */
-		void waitUntilComplete(const Task* task);
-
-		/**
-		 * @brief	Method used for sorting tasks.
-		 */
-		static bool taskCompare(const TaskPtr& lhs, const TaskPtr& rhs);
-
-		HThread mTaskSchedulerThread;
-		Set<TaskPtr, std::function<bool(const TaskPtr&, const TaskPtr&)>> mTaskQueue;
-		Vector<TaskPtr> mActiveTasks;
-		UINT32 mNumActiveTasks;
-		UINT32 mMaxActiveTasks;
-		UINT32 mNextTaskId;
-		bool mShutdown;
-
-		BS_MUTEX(mReadyMutex);
-		BS_MUTEX(mCompleteMutex);
-		BS_MUTEX(mActiveTaskMutex);
-		BS_THREAD_SYNCHRONISER(mTaskReadyCond);
-		BS_THREAD_SYNCHRONISER(mTaskCompleteCond);
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsModule.h"
+#include "BsThreadPool.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Threading
+	 *  @{
+	 */
+
+	/** Task priority. Tasks with higher priority will get executed sooner. */
+	enum class TaskPriority
+	{
+		VeryLow = 98,
+		Low = 99,
+		Normal = 100,
+		High = 101,
+		VeryHigh = 102
+	};
+
+	/**
+	 * Represents a single task that may be queued in the TaskScheduler.
+	 * 			
+	 * @note	Thread safe.
+	 */
+	class BS_UTILITY_EXPORT Task
+	{
+		struct PrivatelyConstruct {};
+
+	public:
+		Task(const PrivatelyConstruct& dummy, const String& name, std::function<void()> taskWorker, 
+			TaskPriority priority, TaskPtr dependency);
+
+		/**
+		 * Creates a new task. Task should be provided to TaskScheduler in order for it to start.
+		 *
+		 * @param[in]	name		Name you can use to more easily identify the task.
+		 * @param[in]	taskWorker	Worker method that does all of the work in the task.
+		 * @param[in]	priority  	(optional) Higher priority means the tasks will be executed sooner.
+		 * @param[in]	dependency	(optional) Task dependency if one exists. If provided the task will
+		 * 							not be executed until its dependency is complete.
+		 */
+		static TaskPtr create(const String& name, std::function<void()> taskWorker, TaskPriority priority = TaskPriority::Normal, 
+			TaskPtr dependency = nullptr);
+
+		/** Returns true if the task has completed. */
+		bool isComplete() const;
+
+		/**	Returns true if the task has been canceled. */
+		bool isCanceled() const;
+
+		/**
+		 * Blocks the current thread until the task has completed. 
+		 * 
+		 * @note	While waiting adds a new worker thread, so that the blocking threads core can be utilized.
+		 */
+		void wait();
+
+		/** Cancels the task and removes it from the TaskSchedulers queue. */
+		void cancel();
+
+	private:
+		friend class TaskScheduler;
+
+		String mName;
+		TaskPriority mPriority;
+		UINT32 mTaskId;
+		std::function<void()> mTaskWorker;
+		TaskPtr mTaskDependency;
+		std::atomic<UINT32> mState; /**< 0 - Inactive, 1 - In progress, 2 - Completed, 3 - Canceled */
+
+		TaskScheduler* mParent;
+	};
+
+	/**
+	 * Represents a task scheduler running on multiple threads. You may queue tasks on it from any thread and they will be
+	 * executed in user specified order on any available thread.
+	 * 			
+	 * @note	
+	 * Thread safe.
+	 * @note
+	 * This type of task scheduler uses a global queue and is best used for coarse granularity of tasks. (Number of tasks 
+	 * in the order of hundreds. Higher number of tasks might require different queuing and locking mechanism, potentially 
+	 * at the cost of flexibility.)
+	 * @note
+	 * By default the task scheduler will create as many threads as there are physical CPU cores. You may add or remove
+	 * threads using addWorker()/removeWorker() methods.
+	 */
+	class BS_UTILITY_EXPORT TaskScheduler : public Module<TaskScheduler>
+	{
+	public:
+		TaskScheduler();
+		~TaskScheduler();
+
+		/** Queues a new task. */
+		void addTask(const TaskPtr& task);
+
+		/**	Adds a new worker thread which will be used for executing queued tasks. */
+		void addWorker();
+
+		/**	Removes a worker thread (as soon as its current task is finished). */
+		void removeWorker();
+
+	protected:
+		friend class Task;
+
+		/**	Main task scheduler method that dispatches tasks to other threads. */
+		void runMain();
+
+		/**	Worker method that runs a single task. */
+		void runTask(TaskPtr task);
+
+		/**	Blocks the calling thread until the specified task has completed. */
+		void waitUntilComplete(const Task* task);
+
+		/**	Method used for sorting tasks. */
+		static bool taskCompare(const TaskPtr& lhs, const TaskPtr& rhs);
+
+		HThread mTaskSchedulerThread;
+		Set<TaskPtr, std::function<bool(const TaskPtr&, const TaskPtr&)>> mTaskQueue;
+		Vector<TaskPtr> mActiveTasks;
+		UINT32 mNumActiveTasks;
+		UINT32 mMaxActiveTasks;
+		UINT32 mNextTaskId;
+		bool mShutdown;
+
+		BS_MUTEX(mReadyMutex);
+		BS_MUTEX(mCompleteMutex);
+		BS_MUTEX(mActiveTaskMutex);
+		BS_THREAD_SYNCHRONISER(mTaskReadyCond);
+		BS_THREAD_SYNCHRONISER(mTaskCompleteCond);
+	};
+
+	/** @} */
 }
 }

+ 36 - 36
BansheeUtility/Include/BsTestOutput.h

@@ -1,37 +1,37 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Abstract interface used for outputting unit test results.
-	 */
-	class BS_UTILITY_EXPORT TestOutput
-	{
-	public:
-		virtual ~TestOutput() {}
-
-		/**
-		 * @brief	Triggered when a unit test fails.
-		 *
-		 * @param	desc		Reason why the unit test failed.
-		 * @param	function	Name of the function the test failed in.
-		 * @param	file		File the unit test failed in.
-		 * @param	line		Line of code the unit test failed on.
-		 */
-		virtual void outputFail(const String& desc, const String& function, const String& file, long line) = 0;
-	};
-
-	/**
-	 * @brief	Outputs unit test results so that failures are reported as exceptions. Success is not reported.
-	 */
-	class BS_UTILITY_EXPORT ExceptionTestOutput : public TestOutput
-	{
-	public:
-		/**
-		 * @copydoc	TestOutput::outputFail
-		 */
-		void outputFail(const String& desc, const String& function, const String& file, long line) final;
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Testing
+	 *  @{
+	 */
+
+	/** Abstract interface used for outputting unit test results. */
+	class BS_UTILITY_EXPORT TestOutput
+	{
+	public:
+		virtual ~TestOutput() {}
+
+		/**
+		 * Triggered when a unit test fails.
+		 *
+		 * @param[in]	desc		Reason why the unit test failed.
+		 * @param[in]	function	Name of the function the test failed in.
+		 * @param[in]	file		File the unit test failed in.
+		 * @param[in]	line		Line of code the unit test failed on.
+		 */
+		virtual void outputFail(const String& desc, const String& function, const String& file, long line) = 0;
+	};
+
+	/** Outputs unit test results so that failures are reported as exceptions. Success is not reported. */
+	class BS_UTILITY_EXPORT ExceptionTestOutput : public TestOutput
+	{
+	public:
+		/** @copydoc TestOutput::outputFail */
+		void outputFail(const String& desc, const String& function, const String& file, long line) final override;
+	};
+
+	/** @} */
 }
 }

+ 94 - 97
BansheeUtility/Include/BsTestSuite.h

@@ -1,97 +1,94 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-
-#define BS_TEST_ASSERT(expr) assertment((expr), "", __FILE__, __LINE__); 
-#define BS_TEST_ASSERT_MSG(expr, msg) assertment((expr), msg, __FILE__, __LINE__); 
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Primary class for unit testing. Override and register unit tests
-	 *			in constructor then run the tests using the desired method of output.
-	 */
-	class BS_UTILITY_EXPORT TestSuite
-	{
-	public:
-		typedef void(TestSuite::*Func)();
-
-	private:
-
-		/**
-		 * @brief	Contains data about a single unit test.
-		 */
-		struct TestEntry
-		{
-			TestEntry(Func test, const String& name);
-
-			Func test;
-			String name;
-		};
-
-	public:
-		virtual ~TestSuite() {}
-
-		/**
-		 * @brief	Runs all the tests in the suite (and sub-suites). Tests results
-		 *			are reported to the provided output class.
-		 */
-		void run(TestOutput& output);
-
-		/**
-		 * @brief	Adds a new child suite to this suite. This method allows
-		 *			you to group suites and execute them all at once.
-		 */
-		void add(const TestSuitePtr& suite);
-
-		/**
-		 * @brief	Creates a new suite of a particular type.
-		 */
-		template <class T>
-		static TestSuitePtr create()
-		{
-			static_assert((std::is_base_of<TestSuite, T>::value), "Invalid test suite type. It needs to derive from BansheeEngine::TestSuite.");
-
-			return std::static_pointer_cast<TestSuite>(bs_shared_ptr_new<T>());
-		}
-
-	protected:
-		TestSuite();
-
-		/**
-		 * @brief	Called right before any tests are ran.
-		 */
-		virtual void startUp() {}
-
-		/**
-		 * @brief	Called after all tests and child suite's tests are ran.
-		 */
-		virtual void shutDown() {}
-
-		/**
-		 * @brief	Register a new unit test.
-		 *
-		 * @param	test	Function to call in order to execute the test.
-		 * @param	name	Name of the test we can use for referencing it later.
-		 */
-		void addTest(Func test, const String& name);
-
-		/**
-		 * @brief	Reports success or failure depending on the result of an expression.
-		 *
-		 * @param	success		If true success is reported, otherwise failure.
-		 * @param	file		Name of the source code file the assertment originates from.
-		 * @param	line		Line number at which the assertment was triggered at.
-		 */
-		void assertment(bool success, const String& desc, const String& file, long line);
-
-		Vector<TestEntry> mTests;
-		Vector<TestSuitePtr> mSuites;
-
-		// Transient
-		TestOutput* mOutput;
-		String mActiveTestName;
-	};
-}
-
-#define BS_ADD_TEST(func) addTest(static_cast<Func>(&func), #func);
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+
+/** @addtogroup Testing
+ *  @{
+ */
+
+/** Tests if condition is true, and reports unit test failure if it fails. */
+#define BS_TEST_ASSERT(expr) assertment((expr), "", __FILE__, __LINE__); 
+
+/** Tests if condition is true, and reports unit test failure with a message if it fails. */
+#define BS_TEST_ASSERT_MSG(expr, msg) assertment((expr), msg, __FILE__, __LINE__); 
+
+namespace BansheeEngine
+{
+	/**
+	 * Primary class for unit testing. Override and register unit tests in constructor then run the tests using the 
+	 * desired method of output.
+	 */
+	class BS_UTILITY_EXPORT TestSuite
+	{
+	public:
+		typedef void(TestSuite::*Func)();
+
+	private:
+		/** Contains data about a single unit test. */
+		struct TestEntry
+		{
+			TestEntry(Func test, const String& name);
+
+			Func test;
+			String name;
+		};
+
+	public:
+		virtual ~TestSuite() {}
+
+		/** Runs all the tests in the suite (and sub-suites). Tests results are reported to the provided output class. */
+		void run(TestOutput& output);
+
+		/** Adds a new child suite to this suite. This method allows you to group suites and execute them all at once. */
+		void add(const TestSuitePtr& suite);
+
+		/**	Creates a new suite of a particular type. */
+		template <class T>
+		static TestSuitePtr create()
+		{
+			static_assert((std::is_base_of<TestSuite, T>::value), "Invalid test suite type. It needs to derive from BansheeEngine::TestSuite.");
+
+			return std::static_pointer_cast<TestSuite>(bs_shared_ptr_new<T>());
+		}
+
+	protected:
+		TestSuite();
+
+		/** Called right before any tests are ran. */
+		virtual void startUp() {}
+
+		/**
+		 * @brief	Called after all tests and child suite's tests are ran.
+		 */
+		virtual void shutDown() {}
+
+		/**
+		 * Register a new unit test.
+		 *
+		 * @param[in]	test	Function to call in order to execute the test.
+		 * @param[in]	name	Name of the test we can use for referencing it later.
+		 */
+		void addTest(Func test, const String& name);
+
+		/**
+		 * Reports success or failure depending on the result of an expression.
+		 *
+		 * @param[in]	success		If true success is reported, otherwise failure.
+		 * @param[in]	file		Name of the source code file the assertment originates from.
+		 * @param[in]	line		Line number at which the assertment was triggered at.
+		 */
+		void assertment(bool success, const String& desc, const String& file, long line);
+
+		Vector<TestEntry> mTests;
+		Vector<TestSuitePtr> mSuites;
+
+		// Transient
+		TestOutput* mOutput;
+		String mActiveTestName;
+	};
+}
+
+/** Registers a new unit test within an implementation of TestSuite. */
+#define BS_ADD_TEST(func) addTest(static_cast<Func>(&func), #func);
+
+/** @} */

+ 67 - 61
BansheeUtility/Include/BsThreadDefines.h

@@ -1,61 +1,67 @@
-#pragma once
-
-#define BS_AUTO_MUTEX_NAME mutex
-
-#include <thread>
-#include <chrono>
-#include <mutex>
-#include <condition_variable>
-#include "BsSpinLock.h"
-
-#define BS_AUTO_MUTEX mutable std::mutex BS_AUTO_MUTEX_NAME;
-#define BS_LOCK_AUTO_MUTEX std::unique_lock<std::mutex> bsAutoMutexLock(BS_AUTO_MUTEX_NAME);
-#define BS_MUTEX(name) mutable std::mutex name;
-#define BS_STATIC_MUTEX(name) static std::mutex name;
-#define BS_STATIC_MUTEX_INSTANCE(name) std::mutex name;
-#define BS_STATIC_MUTEX_CLASS_INSTANCE(name, classTypeName) std::mutex classTypeName##::name;
-#define BS_LOCK_MUTEX(name) std::unique_lock<std::mutex> bsnameLock(name);
-#define BS_LOCK_MUTEX_NAMED(mutexName, lockName) std::unique_lock<std::mutex> lockName(mutexName);
-#define BS_LOCK_TYPE std::unique_lock<std::mutex>
-// like BS_AUTO_MUTEX but mutex held by pointer
-#define BS_AUTO_SHARED_MUTEX mutable std::mutex *BS_AUTO_MUTEX_NAME;
-#define BS_LOCK_AUTO_SHARED_MUTEX assert(BS_AUTO_MUTEX_NAME); std::lock_guard<std::mutex> bsAutoMutexLock(*BS_AUTO_MUTEX_NAME);
-#define BS_COPY_AUTO_SHARED_MUTEX(from) assert(!BS_AUTO_MUTEX_NAME); BS_AUTO_MUTEX_NAME = from;
-#define BS_SET_AUTO_SHARED_MUTEX_NULL BS_AUTO_MUTEX_NAME = 0;
-#define BS_MUTEX_CONDITIONAL(mutex) if (mutex)
-#define BS_THREAD_SYNCHRONISER(sync) std::condition_variable sync;
-#define BS_STATIC_THREAD_SYNCHRONISER(sync) static std::condition_variable sync;
-#define BS_STATIC_THREAD_SYNCHRONISER_CLASS_INSTANCE(sync, classTypeName) std::condition_variable classTypeName##::sync;
-#define BS_THREAD_WAIT(sync, mutex, lock) sync.wait(lock);
-#define BS_THREAD_NOTIFY_ONE(sync) sync.notify_one(); 
-#define BS_THREAD_NOTIFY_ALL(sync) sync.notify_all(); 
-#define BS_THREAD_JOIN(thread) thread.join();
-// Recursive mutex
-#define BS_RECURSIVE_MUTEX(name) mutable std::recursive_mutex name
-#define BS_LOCK_RECURSIVE_MUTEX(name) std::unique_lock<std::recursive_mutex> cmnameLock(name);
-// Read-write mutex
-#define BS_RW_MUTEX(name) mutable std::mutex name
-#define BS_LOCK_RW_MUTEX_READ(name) std::unique_lock<std::mutex> cmnameLock(name)
-#define BS_LOCK_RW_MUTEX_WRITE(name) std::unique_lock<std::mutex> cmnameLock(name)
-// Thread objects and related functions
-#define BS_THREAD_TYPE std::thread
-#define BS_THREAD_CREATE(name, worker) std::thread* name = new (BansheeEngine::MemoryAllocator<BansheeEngine::GenAlloc>::allocate(sizeof(std::thread))) std::thread(worker);
-#define BS_THREAD_DESTROY(name) BansheeEngine::bs_delete<std::thread, BansheeEngine::GenAlloc>(name);
-#define BS_THREAD_HARDWARE_CONCURRENCY std::thread::hardware_concurrency()
-#define BS_THREAD_CURRENT_ID std::this_thread::get_id()
-#define BS_THREAD_ID_TYPE std::thread::id
-#define BS_DEFER_LOCK std::defer_lock
-#define BS_THREAD_WORKER_INHERIT
-// Utility
-#define BS_THREAD_SLEEP(ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms));
-
-using Mutex = std::mutex;
-using RecursiveMutex = std::recursive_mutex;
-using Signal = std::condition_variable;
-using Thread = std::thread;
-
-template <typename T = Mutex>
-using Lock = std::unique_lock<T>;
-
-template <typename T = RecursiveMutex>
-using RecursiveLock = std::unique_lock<T>;
+#pragma once
+
+#define BS_AUTO_MUTEX_NAME mutex
+
+#include <thread>
+#include <chrono>
+#include <mutex>
+#include <condition_variable>
+#include "BsSpinLock.h"
+
+/** @addtogroup Threading
+ *  @{
+ */
+
+#define BS_AUTO_MUTEX mutable std::mutex BS_AUTO_MUTEX_NAME;
+#define BS_LOCK_AUTO_MUTEX std::unique_lock<std::mutex> bsAutoMutexLock(BS_AUTO_MUTEX_NAME);
+#define BS_MUTEX(name) mutable std::mutex name;
+#define BS_STATIC_MUTEX(name) static std::mutex name;
+#define BS_STATIC_MUTEX_INSTANCE(name) std::mutex name;
+#define BS_STATIC_MUTEX_CLASS_INSTANCE(name, classTypeName) std::mutex classTypeName##::name;
+#define BS_LOCK_MUTEX(name) std::unique_lock<std::mutex> bsnameLock(name);
+#define BS_LOCK_MUTEX_NAMED(mutexName, lockName) std::unique_lock<std::mutex> lockName(mutexName);
+#define BS_LOCK_TYPE std::unique_lock<std::mutex>
+// like BS_AUTO_MUTEX but mutex held by pointer
+#define BS_AUTO_SHARED_MUTEX mutable std::mutex *BS_AUTO_MUTEX_NAME;
+#define BS_LOCK_AUTO_SHARED_MUTEX assert(BS_AUTO_MUTEX_NAME); std::lock_guard<std::mutex> bsAutoMutexLock(*BS_AUTO_MUTEX_NAME);
+#define BS_COPY_AUTO_SHARED_MUTEX(from) assert(!BS_AUTO_MUTEX_NAME); BS_AUTO_MUTEX_NAME = from;
+#define BS_SET_AUTO_SHARED_MUTEX_NULL BS_AUTO_MUTEX_NAME = 0;
+#define BS_MUTEX_CONDITIONAL(mutex) if (mutex)
+#define BS_THREAD_SYNCHRONISER(sync) std::condition_variable sync;
+#define BS_STATIC_THREAD_SYNCHRONISER(sync) static std::condition_variable sync;
+#define BS_STATIC_THREAD_SYNCHRONISER_CLASS_INSTANCE(sync, classTypeName) std::condition_variable classTypeName##::sync;
+#define BS_THREAD_WAIT(sync, mutex, lock) sync.wait(lock);
+#define BS_THREAD_NOTIFY_ONE(sync) sync.notify_one(); 
+#define BS_THREAD_NOTIFY_ALL(sync) sync.notify_all(); 
+#define BS_THREAD_JOIN(thread) thread.join();
+// Recursive mutex
+#define BS_RECURSIVE_MUTEX(name) mutable std::recursive_mutex name
+#define BS_LOCK_RECURSIVE_MUTEX(name) std::unique_lock<std::recursive_mutex> cmnameLock(name);
+// Read-write mutex
+#define BS_RW_MUTEX(name) mutable std::mutex name
+#define BS_LOCK_RW_MUTEX_READ(name) std::unique_lock<std::mutex> cmnameLock(name)
+#define BS_LOCK_RW_MUTEX_WRITE(name) std::unique_lock<std::mutex> cmnameLock(name)
+// Thread objects and related functions
+#define BS_THREAD_TYPE std::thread
+#define BS_THREAD_CREATE(name, worker) std::thread* name = new (BansheeEngine::MemoryAllocator<BansheeEngine::GenAlloc>::allocate(sizeof(std::thread))) std::thread(worker);
+#define BS_THREAD_DESTROY(name) BansheeEngine::bs_delete<std::thread, BansheeEngine::GenAlloc>(name);
+#define BS_THREAD_HARDWARE_CONCURRENCY std::thread::hardware_concurrency()
+#define BS_THREAD_CURRENT_ID std::this_thread::get_id()
+#define BS_THREAD_ID_TYPE std::thread::id
+#define BS_DEFER_LOCK std::defer_lock
+#define BS_THREAD_WORKER_INHERIT
+// Utility
+#define BS_THREAD_SLEEP(ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms));
+
+using Mutex = std::mutex;
+using RecursiveMutex = std::recursive_mutex;
+using Signal = std::condition_variable;
+using Thread = std::thread;
+
+template <typename T = Mutex>
+using Lock = std::unique_lock<T>;
+
+template <typename T = RecursiveMutex>
+using RecursiveLock = std::unique_lock<T>;
+
+/** @} */

+ 243 - 283
BansheeUtility/Include/BsThreadPool.h

@@ -1,284 +1,244 @@
-#pragma once
-
-#include "BsPrerequisitesUtil.h"
-#include "BsModule.h"
-
-namespace BansheeEngine
-{
-	class ThreadPool;
-
-	/**
-	 * @brief	Handle to a thread managed by ThreadPool.
-	 */
-	class BS_UTILITY_EXPORT HThread
-	{
-	public:
-		HThread();
-		HThread(ThreadPool* pool, UINT32 threadId);
-
-		/**
-		 * @brief	Block the calling thread until the thread this handle points to completes.
-		 */
-		void blockUntilComplete();
-
-	private:
-		UINT32 mThreadId;
-		ThreadPool* mPool;
-	};
-
-	/**
-	 * @brief	Wrapper around a thread that is used within ThreadPool.
-	 */
-	class BS_UTILITY_EXPORT PooledThread
-	{
-	public:
-		PooledThread(const String& name);
-		virtual ~PooledThread();
-
-		/**
-		 * @brief	Initializes the pooled thread. Must be called
-		 * 			right after the object is constructed.
-		 */
-		void initialize();
-
-		/**
-		 * @brief	Starts executing the given worker method.
-		 *
-		 * @note	Caller must ensure worker method is not null and that the thread
-		 * 			is currently idle, otherwise undefined behavior will occur.
-		 */
-		void start(std::function<void()> workerMethod, UINT32 id);
-
-		/**
-		 * @brief	Attempts to join the currently running thread and destroys it. Caller must ensure
-		 * 			that any worker method currently running properly returns, otherwise this
-		 * 			will block indefinitely.
-		 */
-		void destroy();
-
-		/**
-		 * @brief	Returns true if the thread is idle and new worker method can be scheduled on it.
-		 */
-		bool isIdle();
-
-		/**
-		 * @brief	Returns how long has the thread been idle. Value is undefined if thread is not idle.
-		 */
-		time_t idleTime();
-
-		/**
-		 * @brief	Sets a name of the thread.
-		 */
-		void setName(const String& name);
-
-		/**
-		 * @brief	Gets unique ID of the currently executing thread.
-		 */
-		UINT32 getId() const;
-
-		/**
-		 * @brief	Blocks the current thread until this thread completes.
-		 *			Returns immediately if the thread is idle.
-		 */
-		void blockUntilComplete();
-
-		/**
-		 * @brief	Called when the thread is first created.
-		 */
-		virtual void onThreadStarted(const String& name) = 0;
-
-		/**
-		 * @brief	Called when the thread is being shut down.
-		 */
-		virtual void onThreadEnded(const String& name) = 0;
-
-	protected:
-		friend class HThread;
-
-		/**
-		 * @brief	Primary worker method that is ran when the thread is first
-		 * 			initialized.
-		 */
-		void run();
-
-	protected:
-		std::function<void()> mWorkerMethod;
-
-		String mName;
-		UINT32 mId;
-		bool mIdle;
-		bool mThreadStarted;
-		bool mThreadReady;
-
-		time_t mIdleTime;
-
-		BS_THREAD_TYPE* mThread;
-		BS_MUTEX(mMutex);
-		BS_THREAD_SYNCHRONISER(mStartedCond);
-		BS_THREAD_SYNCHRONISER(mReadyCond);
-		BS_THREAD_SYNCHRONISER(mWorkerEndedCond);
-	};
-
-	/**
-	 * @copydoc	PooledThread
-	 * 			
-	 * @tparam	ThreadPolicy Allows you specify a policy with methods that will get called
-	 * 						 whenever a new thread is created or when a thread is destroyed.
-	 */
-	template<class ThreadPolicy>
-	class TPooledThread : public PooledThread
-	{
-	public:
-		TPooledThread(const String& name)
-			:PooledThread(name)
-		{ }
-
-		/**
-		 * @copydoc	PooledThread::onThreadStarted
-		 */
-		void onThreadStarted(const String& name)
-		{
-			ThreadPolicy::onThreadStarted(name);
-		}
-
-		/**
-		 * @copydoc	PooledThread::onThreadEnded
-		 */
-		void onThreadEnded(const String& name)
-		{
-			ThreadPolicy::onThreadEnded(name);
-		}
-	};
-
-	/**
-	 * @brief	Class that maintains a pool of threads we can easily retrieve and use
-	 * 			for any task. This saves on the cost of creating and destroying threads.
-	 */
-	class BS_UTILITY_EXPORT ThreadPool : public Module<ThreadPool>
-	{
-	public:
-		/**
-		 * @brief	Constructs a new thread pool
-		 *
-		 * @param	threadCapacity	Default thread capacity, the pool will always
-		 * 							try to keep this many threads available.
-		 * @param	maxCapacity   	(optional) Maximum number of threads the pool can create.
-		 * 							If we go over this limit an exception will be thrown.
-		 * @param	idleTimeout   	(optional) How many seconds do threads need to be idle before
-		 * 							we remove them from the pool
-		 */
-		ThreadPool(UINT32 threadCapacity, UINT32 maxCapacity = 16, UINT32 idleTimeout = 60);
-		virtual ~ThreadPool();
-
-		/**
-		 * @brief	Find an unused thread (or creates a new one) and runs the specified worker
-		 * 			method on it.
-		 *
-		 * @param	name			A name you may use for more easily identifying the thread.
-		 * @param	workerMethod	The worker method to be called by the thread.
-		 *
-		 * @returns	A thread handle you may use for monitoring the thread execution.
-		 */
-		HThread run(const String& name, std::function<void()> workerMethod);
-
-		/**
-		 * @brief	Stops all threads and destroys them. Caller must ensure each threads workerMethod
-		 * 			returns otherwise this will never return.
-		 */
-		void stopAll();
-
-		/**
-		 * @brief	Clear any unused threads that are over the capacity.
-		 */
-		void clearUnused();
-
-		/**
-		 * @brief	Returns the number of unused threads in the pool.
-		 */
-		UINT32 getNumAvailable() const;
-
-		/**
-		 * @brief	Returns the number of running threads in the pool.
-		 */
-		UINT32 getNumActive() const;
-
-		/**
-		 * @brief	Returns the total number of created threads in the pool
-		 * 			(both running and unused).
-		 */
-		UINT32 getNumAllocated() const;
-
-	protected:
-		friend class HThread;
-
-		Vector<PooledThread*> mThreads;
-		
-		/**
-		 * @brief	Creates a new thread to be used by the pool.
-		 */
-		virtual PooledThread* createThread(const String& name) = 0;
-
-		/**
-		 * @brief	Destroys the specified thread. Caller needs to make sure
-		 * 			the thread is actually shut down beforehand.
-		 */
-		void destroyThread(PooledThread* thread);
-
-		/**
-		 * @brief	Returns the first unused thread if one exists, otherwise
-		 * 			creates a new one.
-		 *
-		 * @param	name	Name to assign the thread.
-		 *
-		 * @note	Throws an exception if we have reached our maximum thread capacity.
-		 */
-		PooledThread* getThread(const String& name);
-
-		UINT32 mDefaultCapacity;
-		UINT32 mMaxCapacity;
-		UINT32 mIdleTimeout;
-		UINT32 mAge;
-		
-		std::atomic_uint mUniqueId;
-		BS_MUTEX(mMutex);
-	};
-
-	/**
-	 * @brief	Policy used for thread start & end used by the ThreadPool.
-	 */
-	class ThreadNoPolicy
-	{
-	public:
-		static void onThreadStarted(const String& name) { }
-		static void onThreadEnded(const String& name) { }
-	};
-
-	/**
-	 * @copydoc ThreadPool
-	 * 			
-	 * @tparam	ThreadPolicy Allows you specify a policy with methods that will get called
-	 * 						 whenever a new thread is created or when a thread is destroyed.
-	 */
-	template<class ThreadPolicy = ThreadNoPolicy>
-	class TThreadPool : public ThreadPool
-	{
-	public:
-		TThreadPool(UINT32 threadCapacity, UINT32 maxCapacity = 16, UINT32 idleTimeout = 60)
-			:ThreadPool(threadCapacity, maxCapacity, idleTimeout)
-		{
-
-		}
-
-	protected:
-		/**
-		 * @copydoc ThreadPool::createThread
-		 */
-		PooledThread* createThread(const String& name)
-		{
-			PooledThread* newThread = bs_new<TPooledThread<ThreadPolicy>>(name);
-			newThread->initialize();
-
-			return newThread;
-		}
-	};
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsModule.h"
+
+namespace BansheeEngine
+{
+	/** @addtogroup Threading
+	 *  @{
+	 */
+
+	class ThreadPool;
+
+	/** Handle to a thread managed by ThreadPool. */
+	class BS_UTILITY_EXPORT HThread
+	{
+	public:
+		HThread();
+		HThread(ThreadPool* pool, UINT32 threadId);
+
+		/**	Block the calling thread until the thread this handle points to completes. */
+		void blockUntilComplete();
+
+	private:
+		UINT32 mThreadId;
+		ThreadPool* mPool;
+	};
+
+	/** @cond INTERNAL */
+
+	/**	Wrapper around a thread that is used within ThreadPool. */
+	class BS_UTILITY_EXPORT PooledThread
+	{
+	public:
+		PooledThread(const String& name);
+		virtual ~PooledThread();
+
+		/**	Initializes the pooled thread. Must be called right after the object is constructed. */
+		void initialize();
+
+		/**
+		 * Starts executing the given worker method.
+		 *
+		 * @note	
+		 * Caller must ensure worker method is not null and that the thread is currently idle, otherwise undefined behavior
+		 * will occur.
+		 */
+		void start(std::function<void()> workerMethod, UINT32 id);
+
+		/**
+		 * Attempts to join the currently running thread and destroys it. Caller must ensure that any worker method 
+		 * currently running properly returns, otherwise this will block indefinitely.
+		 */
+		void destroy();
+
+		/**	Returns true if the thread is idle and new worker method can be scheduled on it. */
+		bool isIdle();
+
+		/** Returns how long has the thread been idle. Value is undefined if thread is not idle. */
+		time_t idleTime();
+
+		/**	Sets a name of the thread. */
+		void setName(const String& name);
+
+		/**	Gets unique ID of the currently executing thread. */
+		UINT32 getId() const;
+
+		/**	Blocks the current thread until this thread completes. Returns immediately if the thread is idle. */
+		void blockUntilComplete();
+
+		/**	Called when the thread is first created. */
+		virtual void onThreadStarted(const String& name) = 0;
+
+		/**	Called when the thread is being shut down. */
+		virtual void onThreadEnded(const String& name) = 0;
+
+	protected:
+		friend class HThread;
+
+		/** Primary worker method that is ran when the thread is first initialized. */
+		void run();
+
+	protected:
+		std::function<void()> mWorkerMethod;
+
+		String mName;
+		UINT32 mId;
+		bool mIdle;
+		bool mThreadStarted;
+		bool mThreadReady;
+
+		time_t mIdleTime;
+
+		BS_THREAD_TYPE* mThread;
+		BS_MUTEX(mMutex);
+		BS_THREAD_SYNCHRONISER(mStartedCond);
+		BS_THREAD_SYNCHRONISER(mReadyCond);
+		BS_THREAD_SYNCHRONISER(mWorkerEndedCond);
+	};
+
+	/**
+	 * @copydoc	PooledThread
+	 * 			
+	 * @tparam	ThreadPolicy Allows you specify a policy with methods that will get called whenever a new thread is created 
+	 *						 or when a thread is destroyed.
+	 */
+	template<class ThreadPolicy>
+	class TPooledThread : public PooledThread
+	{
+	public:
+		TPooledThread(const String& name)
+			:PooledThread(name)
+		{ }
+
+		/** @copydoc PooledThread::onThreadStarted */
+		void onThreadStarted(const String& name) override
+		{
+			ThreadPolicy::onThreadStarted(name);
+		}
+
+		/** @copydoc PooledThread::onThreadEnded */
+		void onThreadEnded(const String& name) override
+		{
+			ThreadPolicy::onThreadEnded(name);
+		}
+	};
+
+	/** @endcond */
+
+	/**
+	 * Class that maintains a pool of threads we can easily retrieve and use for any task. This saves on the cost of 
+	 * creating and destroying threads.
+	 */
+	class BS_UTILITY_EXPORT ThreadPool : public Module<ThreadPool>
+	{
+	public:
+		/**
+		 * @brief	Constructs a new thread pool
+		 *
+		 * @param[in]	threadCapacity	Default thread capacity, the pool will always try to keep this many threads available.
+		 * @param[in]	maxCapacity   	(optional) Maximum number of threads the pool can create. If we go over this limit an 
+		 *								exception will be thrown.
+		 * @param[in]	idleTimeout   	(optional) How many seconds do threads need to be idle before we remove them from the pool.
+		 */
+		ThreadPool(UINT32 threadCapacity, UINT32 maxCapacity = 16, UINT32 idleTimeout = 60);
+		virtual ~ThreadPool();
+
+		/**
+		 * Find an unused thread (or creates a new one) and runs the specified worker method on it.
+		 *
+		 * @param[in]	name			A name you may use for more easily identifying the thread.
+		 * @param[in]	workerMethod	The worker method to be called by the thread.
+		 *
+		 * @return	A thread handle you may use for monitoring the thread execution.
+		 */
+		HThread run(const String& name, std::function<void()> workerMethod);
+
+		/**
+		 * Stops all threads and destroys them. Caller must ensure each threads worker method returns otherwise this will 
+		 * never return.
+		 */
+		void stopAll();
+
+		/** Clear any unused threads that are over the capacity. */
+		void clearUnused();
+
+		/**	Returns the number of unused threads in the pool. */
+		UINT32 getNumAvailable() const;
+
+		/**	Returns the number of running threads in the pool. */
+		UINT32 getNumActive() const;
+
+		/**	Returns the total number of created threads in the pool	(both running and unused). */
+		UINT32 getNumAllocated() const;
+
+	protected:
+		friend class HThread;
+
+		Vector<PooledThread*> mThreads;
+		
+		/**	Creates a new thread to be used by the pool. */
+		virtual PooledThread* createThread(const String& name) = 0;
+
+		/**	Destroys the specified thread. Caller needs to make sure the thread is actually shut down beforehand. */
+		void destroyThread(PooledThread* thread);
+
+		/**
+		 * Returns the first unused thread if one exists, otherwise creates a new one.
+		 *
+		 * @param[in]	name	Name to assign the thread.
+		 *
+		 * @note	Throws an exception if we have reached our maximum thread capacity.
+		 */
+		PooledThread* getThread(const String& name);
+
+		UINT32 mDefaultCapacity;
+		UINT32 mMaxCapacity;
+		UINT32 mIdleTimeout;
+		UINT32 mAge;
+		
+		std::atomic_uint mUniqueId;
+		BS_MUTEX(mMutex);
+	};
+
+	/** @cond INTERNAL */
+
+	/** Policy used for thread start & end used by the ThreadPool. */
+	class ThreadNoPolicy
+	{
+	public:
+		static void onThreadStarted(const String& name) { }
+		static void onThreadEnded(const String& name) { }
+	};
+
+	/**
+	 * @copydoc ThreadPool
+	 * 			
+	 * @tparam	ThreadPolicy Allows you specify a policy with methods that will get called whenever a new thread is created 
+	 *			or when a thread is destroyed.
+	 */
+	template<class ThreadPolicy = ThreadNoPolicy>
+	class TThreadPool : public ThreadPool
+	{
+	public:
+		TThreadPool(UINT32 threadCapacity, UINT32 maxCapacity = 16, UINT32 idleTimeout = 60)
+			:ThreadPool(threadCapacity, maxCapacity, idleTimeout)
+		{
+
+		}
+
+	protected:
+		/** @copydoc ThreadPool::createThread */
+		PooledThread* createThread(const String& name) override
+		{
+			PooledThread* newThread = bs_new<TPooledThread<ThreadPolicy>>(name);
+			newThread->initialize();
+
+			return newThread;
+		}
+	};
+
+	/** @endcond */
+	/** @} */
 }
 }

+ 39 - 39
BansheeUtility/Source/BsAsyncOp.cpp

@@ -1,40 +1,40 @@
-#include "BsAsyncOp.h"
-#include "BsDebug.h"
-
-namespace BansheeEngine
-{
-	bool AsyncOp::hasCompleted() const 
-	{ 
-		return mData->mIsCompleted.load(std::memory_order_acquire);
-	}
-
-	void AsyncOp::_completeOperation(Any returnValue) 
-	{ 
-		mData->mReturnValue = returnValue; 
-		mData->mIsCompleted.store(true, std::memory_order_release);
-
-		if (mSyncData != nullptr)
-			BS_THREAD_NOTIFY_ALL(mSyncData->mCondition);
-	}
-
-	void AsyncOp::_completeOperation() 
-	{ 
-		mData->mIsCompleted.store(true, std::memory_order_release);
-
-		if (mSyncData != nullptr)
-			BS_THREAD_NOTIFY_ALL(mSyncData->mCondition);
-	}
-
-	void AsyncOp::_blockUntilComplete() const
-	{
-		if (mSyncData == nullptr)
-		{
-			LOGERR("No sync data is available. Cannot block until AsyncOp is complete.");
-			return;
-		}
-
-		BS_LOCK_MUTEX_NAMED(mSyncData->mMutex, lock);
-		while (!hasCompleted())
-			BS_THREAD_WAIT(mSyncData->mCondition, mSyncData->mMutex, lock);
-	}
+#include "BsAsyncOp.h"
+#include "BsDebug.h"
+
+namespace BansheeEngine
+{
+	bool AsyncOp::hasCompleted() const 
+	{ 
+		return mData->mIsCompleted.load(std::memory_order_acquire);
+	}
+
+	void AsyncOp::_completeOperation(Any returnValue) 
+	{ 
+		mData->mReturnValue = returnValue; 
+		mData->mIsCompleted.store(true, std::memory_order_release);
+
+		if (mSyncData != nullptr)
+			BS_THREAD_NOTIFY_ALL(mSyncData->mCondition);
+	}
+
+	void AsyncOp::_completeOperation() 
+	{ 
+		mData->mIsCompleted.store(true, std::memory_order_release);
+
+		if (mSyncData != nullptr)
+			BS_THREAD_NOTIFY_ALL(mSyncData->mCondition);
+	}
+
+	void AsyncOp::blockUntilComplete() const
+	{
+		if (mSyncData == nullptr)
+		{
+			LOGERR("No sync data is available. Cannot block until AsyncOp is complete.");
+			return;
+		}
+
+		BS_LOCK_MUTEX_NAMED(mSyncData->mMutex, lock);
+		while (!hasCompleted())
+			BS_THREAD_WAIT(mSyncData->mCondition, mSyncData->mMutex, lock);
+	}
 }
 }

+ 2 - 2
RenderBeast/Source/BsLightRendering.cpp

@@ -47,8 +47,8 @@ namespace BansheeEngine
 		mBuffer.gLightDirection.set(light->getRotation().zAxis());
 		mBuffer.gLightDirection.set(light->getRotation().zAxis());
 
 
 		Vector4 lightGeometry;
 		Vector4 lightGeometry;
-		lightGeometry.x = light->getType() == LightType::Spot ? LightCore::LIGHT_CONE_NUM_SIDES : 0;
-		lightGeometry.y = LightCore::LIGHT_CONE_NUM_SLICES;
+		lightGeometry.x = light->getType() == LightType::Spot ? (float)LightCore::LIGHT_CONE_NUM_SIDES : 0;
+		lightGeometry.y = (float)LightCore::LIGHT_CONE_NUM_SLICES;
 		lightGeometry.z = light->getBounds().getRadius();
 		lightGeometry.z = light->getBounds().getRadius();
 
 
 		float coneRadius = Math::sin(light->getSpotFalloffAngle()) * light->getRange();
 		float coneRadius = Math::sin(light->getSpotFalloffAngle()) * light->getRange();

+ 68 - 68
SBansheeEngine/Source/BsScriptAsyncOp.cpp

@@ -1,69 +1,69 @@
-#include "BsScriptAsyncOp.h"
-#include "BsMonoManager.h"
-#include "BsMonoClass.h"
-#include "BsMonoUtil.h"
-#include "BsCoreThread.h"
-
-namespace BansheeEngine
-{
-	ScriptAsyncOp::ScriptAsyncOp(MonoObject* instance)
-		:ScriptObject(instance)
-	{ }
-
-	void ScriptAsyncOp::initRuntimeData()
-	{
-		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptAsyncOp::internal_createInstance);
-		metaData.scriptClass->addInternalCall("Internal_IsComplete", &ScriptAsyncOp::internal_isComplete);
-		metaData.scriptClass->addInternalCall("Internal_GetReturnValue", &ScriptAsyncOp::internal_getReturnValue);
-		metaData.scriptClass->addInternalCall("Internal_BlockUntilComplete", &ScriptAsyncOp::internal_blockUntilComplete);
-	}
-
-	MonoObject* ScriptAsyncOp::create(const AsyncOp& op, 
-		std::function<MonoObject*(const AsyncOp&)> asyncOpToReturnValue)
-	{
-		MonoObject* managedInstance = metaData.scriptClass->createInstance();
-
-		ScriptAsyncOp* scriptAsyncOp = toNative(managedInstance);
-		scriptAsyncOp->initialize(op, asyncOpToReturnValue);
-
-		return managedInstance;
-	}
-
-	void ScriptAsyncOp::initialize(const AsyncOp& op, std::function<MonoObject*(const AsyncOp&)> asyncOpToReturnValue)
-	{
-		mAsyncOp = op;
-		mConvertCallback = asyncOpToReturnValue;
-	}
-
-	void ScriptAsyncOp::internal_createInstance(MonoObject* managedInstance)
-	{
-		ScriptAsyncOp* scriptAsyncOp = new (bs_alloc<ScriptAsyncOp>()) ScriptAsyncOp(managedInstance);
-	}
-
-	void ScriptAsyncOp::internal_isComplete(ScriptAsyncOp* thisPtr, bool* value)
-	{
-		*value = thisPtr->mAsyncOp.hasCompleted();
-	}
-
-	MonoObject* ScriptAsyncOp::internal_getReturnValue(ScriptAsyncOp* thisPtr)
-	{
-		if (!thisPtr->mAsyncOp.hasCompleted())
-			return nullptr;
-
-		if (thisPtr->mConvertCallback == nullptr)
-			return nullptr;
-
-		return thisPtr->mConvertCallback(thisPtr->mAsyncOp);
-	}
-
-	void ScriptAsyncOp::internal_blockUntilComplete(ScriptAsyncOp* thisPtr)
-	{
-		if (!thisPtr->mAsyncOp.hasCompleted())
-		{
-			// Note: Assuming the AsyncOp was queued via accessor. This will deadlock
-			// if it wasn't.
-			gCoreThread().getAccessor()->submitToCoreThread();
-			thisPtr->mAsyncOp._blockUntilComplete();
-		}
-	}
+#include "BsScriptAsyncOp.h"
+#include "BsMonoManager.h"
+#include "BsMonoClass.h"
+#include "BsMonoUtil.h"
+#include "BsCoreThread.h"
+
+namespace BansheeEngine
+{
+	ScriptAsyncOp::ScriptAsyncOp(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptAsyncOp::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptAsyncOp::internal_createInstance);
+		metaData.scriptClass->addInternalCall("Internal_IsComplete", &ScriptAsyncOp::internal_isComplete);
+		metaData.scriptClass->addInternalCall("Internal_GetReturnValue", &ScriptAsyncOp::internal_getReturnValue);
+		metaData.scriptClass->addInternalCall("Internal_BlockUntilComplete", &ScriptAsyncOp::internal_blockUntilComplete);
+	}
+
+	MonoObject* ScriptAsyncOp::create(const AsyncOp& op, 
+		std::function<MonoObject*(const AsyncOp&)> asyncOpToReturnValue)
+	{
+		MonoObject* managedInstance = metaData.scriptClass->createInstance();
+
+		ScriptAsyncOp* scriptAsyncOp = toNative(managedInstance);
+		scriptAsyncOp->initialize(op, asyncOpToReturnValue);
+
+		return managedInstance;
+	}
+
+	void ScriptAsyncOp::initialize(const AsyncOp& op, std::function<MonoObject*(const AsyncOp&)> asyncOpToReturnValue)
+	{
+		mAsyncOp = op;
+		mConvertCallback = asyncOpToReturnValue;
+	}
+
+	void ScriptAsyncOp::internal_createInstance(MonoObject* managedInstance)
+	{
+		ScriptAsyncOp* scriptAsyncOp = new (bs_alloc<ScriptAsyncOp>()) ScriptAsyncOp(managedInstance);
+	}
+
+	void ScriptAsyncOp::internal_isComplete(ScriptAsyncOp* thisPtr, bool* value)
+	{
+		*value = thisPtr->mAsyncOp.hasCompleted();
+	}
+
+	MonoObject* ScriptAsyncOp::internal_getReturnValue(ScriptAsyncOp* thisPtr)
+	{
+		if (!thisPtr->mAsyncOp.hasCompleted())
+			return nullptr;
+
+		if (thisPtr->mConvertCallback == nullptr)
+			return nullptr;
+
+		return thisPtr->mConvertCallback(thisPtr->mAsyncOp);
+	}
+
+	void ScriptAsyncOp::internal_blockUntilComplete(ScriptAsyncOp* thisPtr)
+	{
+		if (!thisPtr->mAsyncOp.hasCompleted())
+		{
+			// Note: Assuming the AsyncOp was queued via accessor. This will deadlock
+			// if it wasn't.
+			gCoreThread().getAccessor()->submitToCoreThread();
+			thisPtr->mAsyncOp.blockUntilComplete();
+		}
+	}
 }
 }