| /*!**************************************************************************** | 
 |  | 
 |  @file         PVRTSkipGraph.h | 
 |  @copyright    Copyright (c) Imagination Technologies Limited. | 
 |  @brief        A "tree-like" structure for storing data which, unlike a tree, can | 
 |                reference any other node. | 
 |  | 
 | ******************************************************************************/ | 
 | #ifndef __PVRTSKIPGRAPH_H__ | 
 | #define __PVRTSKIPGRAPH_H__ | 
 |  | 
 |  | 
 | #include "PVRTArray.h" | 
 | #include "PVRTHash.h" | 
 |  | 
 | /*!*************************************************************************** | 
 |  @class				CPVRTSkipGraphNode | 
 |  @brief      		Stores a pointer to the node's data and also uses a dynamic | 
 | 					array to store pointer to nodes this node depends on and | 
 | 					another to store pointers to nodes that are dependant on this node | 
 | *****************************************************************************/ | 
 | template<class T> | 
 | class CPVRTSkipGraphNode | 
 | { | 
 | private: | 
 | 	T								m_pData; | 
 | 	CPVRTArray<CPVRTSkipGraphNode*> m_apDependencies;	// What I depend on | 
 | 	CPVRTArray<CPVRTSkipGraphNode*> m_apDependents;		// What depends on me | 
 | 	 | 
 | public: | 
 | 	/*!*************************************************************************** | 
 | 	@brief      	Constructor | 
 | 	*****************************************************************************/ | 
 | 	CPVRTSkipGraphNode() | 
 | 	{} | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	@brief      	Overloaded constructor | 
 | 	@param[in]		data    Pointer to a node | 
 | 	*****************************************************************************/ | 
 | 	CPVRTSkipGraphNode(const T& data) : m_pData(data) | 
 | 	{} | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	@brief      	Destructor | 
 | 	*****************************************************************************/ | 
 | 	~CPVRTSkipGraphNode() | 
 | 	{}  | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	@fn       		GetNumDependencies | 
 | 	@return			unsigned int	 | 
 | 	@brief      	Returns the number of dependencies referenced by this node. | 
 | 	*****************************************************************************/ | 
 | 	unsigned int GetNumDependencies() const					 | 
 | 	{  | 
 | 		return (unsigned int)m_apDependencies.GetSize();  | 
 | 	} | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	@fn       		GetDependency | 
 | 	@param[in]			ui32Id | 
 | 	@return			CPVRTSkipGraphNode &	 | 
 | 	@brief      	Returns given dependency. | 
 | 	*****************************************************************************/ | 
 | 	CPVRTSkipGraphNode& GetDependency(const unsigned int ui32Id) const | 
 | 	{  | 
 | 		_ASSERT(ui32Id >= 0 && ui32Id < (unsigned int)m_apDependencies.GetSize()); | 
 | 		return *m_apDependencies[ui32Id]; | 
 | 	} | 
 |  | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	@fn       		AddDependency | 
 | 	@param[out]			pDependentNode | 
 | 	@return			bool	 | 
 | 	@brief      	Adds a dependency to this node. | 
 | 	*****************************************************************************/ | 
 | 	bool AddDependency(CPVRTSkipGraphNode* pDependentNode) | 
 | 	{ | 
 | 		unsigned int ui(0); | 
 |  | 
 | 		if(pDependentNode == this) | 
 | 			return false; | 
 |  | 
 | 		if(!pDependentNode) | 
 | 			return false; | 
 |  | 
 | 		/* | 
 | 			Check the dependency doesn't already exist | 
 | 		*/ | 
 | 		for(ui = 0; ui < (unsigned int)m_apDependencies.GetSize(); ++ui) | 
 | 		{ | 
 | 			if(m_apDependencies[ui] == pDependentNode) | 
 | 			{ | 
 | 				return true; | 
 | 			} | 
 | 		} | 
 |  | 
 | 		/* | 
 | 			Add the dependency and also set this node as a dependent of | 
 | 			the referenced node | 
 | 		*/ | 
 | 		m_apDependencies.Append(pDependentNode); | 
 | 		pDependentNode->AddDependent(this); | 
 | 		 | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	@fn       		GetData | 
 | 	@return			T &	 | 
 | 	@brief      	Returns the data associated with this node. | 
 | 	*****************************************************************************/ | 
 | 	T& GetData()				 | 
 | 	{ | 
 | 		return m_pData; | 
 | 	} | 
 |  | 
 | private: | 
 | 	/*!*************************************************************************** | 
 | 	@fn       		AddDependent | 
 | 	@param[out]			pDependancyNode | 
 | 	@return			bool	 | 
 | 	@brief      	Adds a dependent to this node. | 
 | 	*****************************************************************************/ | 
 | 	bool AddDependent(CPVRTSkipGraphNode* pDependencyNode) | 
 | 	{ | 
 | 		unsigned int ui(0); | 
 |  | 
 | 		if(!pDependencyNode) | 
 | 			return false; | 
 |  | 
 | 		/* | 
 | 			Check the dependency doesn't already exist | 
 | 		*/ | 
 | 		for(ui = 0; ui < (unsigned int)m_apDependents.GetSize(); ++ui) | 
 | 		{ | 
 | 			if(m_apDependencies[ui] == pDependencyNode) | 
 | 			{ | 
 | 				return true; | 
 | 			} | 
 | 		} | 
 |  | 
 | 		/* | 
 | 			Add the dependancy | 
 | 		*/ | 
 | 		m_apDependents.Append(pDependencyNode); | 
 | 		return true; | 
 | 	} | 
 | }; | 
 |  | 
 | /*!*************************************************************************** | 
 |  @class				CPVRTSkipGraphRoot | 
 |  @brief      		This class is the entry point for creating and accessing | 
 | 					the elements of a skip graph. It uses a hash table to store | 
 | 					the nodes of the structure and a hash value that allows | 
 | 					fast searching of the skip graph | 
 | *****************************************************************************/ | 
 | template<class T> | 
 | class CPVRTSkipGraphRoot | 
 | { | 
 | //-------------------------------------------------------------------------// | 
 | private: | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	 @struct		SPVRTHashElement | 
 | 	 @brief      	A struct to store data and a hash value generated from the | 
 | 					data. The hash value allows faster searching of the skip graph. | 
 | 	*****************************************************************************/ | 
 | 	struct SPVRTHashElement | 
 | 	{		 | 
 | 	public: | 
 | 		/*!*************************************************************************** | 
 | 		@fn       		SPVRTHashElement | 
 | 		@param[in]			hash | 
 | 		@param[in]			data | 
 | 		@brief      	Overloaded constructor. | 
 | 		*****************************************************************************/ | 
 | 		SPVRTHashElement(const CPVRTHash& hash, const T& data) | 
 | 		: | 
 | 		m_hash(hash), | 
 | 		m_skipGraphNode(data) | 
 | 		{} | 
 |  | 
 | 		/*!*************************************************************************** | 
 | 		@fn       		SPVRTHashElement | 
 | 		@brief      	Constructor | 
 | 		*****************************************************************************/ | 
 | 		SPVRTHashElement() | 
 | 		{} | 
 |  | 
 | 		/*!*************************************************************************** | 
 | 		@fn       		~SPVRTHashElement | 
 | 		@brief      	Destructor | 
 | 		*****************************************************************************/ | 
 | 		~SPVRTHashElement() | 
 | 		{} | 
 | 		 | 
 | 		/*!*************************************************************************** | 
 | 		@fn       		GetHash | 
 | 		@return			unsigned int	 | 
 | 		@brief      	Returns the element's hash value. | 
 | 		*****************************************************************************/ | 
 | 		const CPVRTHash& GetHash() const				 | 
 | 		{  | 
 | 			return m_hash; | 
 | 		} | 
 |  | 
 | 		/*!*************************************************************************** | 
 | 		@fn       		GetNode | 
 | 		@return			CPVRTSkipGraphNode<T>&	 | 
 | 		@brief      	Return the node associated with this element. | 
 | 		*****************************************************************************/ | 
 | 		CPVRTSkipGraphNode<T>& GetNode()			 | 
 | 		{ | 
 | 			return m_skipGraphNode;  | 
 | 		} | 
 |  | 
 | 		/*!*************************************************************************** | 
 | 		@fn       		GetNode | 
 | 		@return			CPVRTSkipGraphNode<T>&	 | 
 | 		@brief      	Return the node associated with this element. | 
 | 		*****************************************************************************/ | 
 | 		const CPVRTSkipGraphNode<T>& GetNode() const			 | 
 | 		{ | 
 | 			return m_skipGraphNode;  | 
 | 		} | 
 |  | 
 | 	private: | 
 | 		CPVRTHash				m_hash; | 
 | 		CPVRTSkipGraphNode<T>	m_skipGraphNode; | 
 | 	}; | 
 |  | 
 | 	 | 
 | 	CPVRTArray<SPVRTHashElement>		m_aHashTable; | 
 |  | 
 | //-------------------------------------------------------------------------// | 
 | public: | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	 @fn       			AddNode | 
 | 	 @param[in]			data							The data of the node to be added | 
 | 	 @return			CPVRTSkipGraphNode<T>* const	A handle to the added node | 
 | 	 @brief      		Searches through the hash table to see if the added node already | 
 | 						exists. If it doesn't, it creates a node. | 
 | 						The function returns true if the node was found or was created | 
 | 						successfully. | 
 | 	*****************************************************************************/ | 
 | 	bool AddNode(const T& data) | 
 | 	{ | 
 | 		CPVRTHash NewNodeHash((void*)&data, sizeof(T), 1); | 
 | 		int iArrayElement(-1); | 
 | 		/* | 
 | 			First, search the hash table to see | 
 | 			if the node already exists | 
 | 		*/ | 
 | 		CPVRTSkipGraphNode<T>* skipGraphNode(FindNode(NewNodeHash)); | 
 |  | 
 | 		if(skipGraphNode == NULL) | 
 | 		{ | 
 | 			/* | 
 | 				The node wasn't found, so a new node needs to be | 
 | 				created | 
 | 			*/ | 
 | 			iArrayElement = m_aHashTable.Append(SPVRTHashElement(NewNodeHash, data)); | 
 |  | 
 | 			/* | 
 | 				Now point to the new instance | 
 | 			*/ | 
 | 			skipGraphNode = &m_aHashTable[iArrayElement].GetNode(); | 
 | 		} | 
 |  | 
 | 		return skipGraphNode ? true : false; | 
 | 	} | 
 |  | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	@brief      	Adds a node dependency. | 
 | 	@param[in]		nodeData | 
 | 	@param[in]		dependantData | 
 | 	@return			bool	 | 
 | 	*****************************************************************************/ | 
 | 	bool AddNodeDependency(const T& nodeData, const T& dependantData) | 
 | 	{ | 
 | 		CPVRTSkipGraphNode<T>* pNode(NULL); | 
 | 		CPVRTSkipGraphNode<T>* pDependantNode(NULL); | 
 |  | 
 | 		pNode = FindNode(nodeData); | 
 | 		if(!pNode) | 
 | 		{ | 
 | 			return false; | 
 | 		} | 
 |  | 
 | 		pDependantNode = FindNode(dependantData); | 
 | 		if(!pDependantNode) | 
 | 		{ | 
 | 			return false; | 
 | 		} | 
 |  | 
 | 		/* | 
 | 			Nodes are not allowed to self reference | 
 | 		*/ | 
 | 		if(pNode == pDependantNode) | 
 | 		{ | 
 | 			return false; | 
 | 		} | 
 | 		pNode->AddDependency(pDependantNode); | 
 |  | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	 @fn       			GetNumNodes | 
 | 	 @return			unsigned int	The total number of nodes | 
 | 	 @brief      		Returns the total number of nodes in the skip graph. | 
 | 	*****************************************************************************/ | 
 | 	unsigned int GetNumNodes() const | 
 | 	{ | 
 | 		return (unsigned int)m_aHashTable.GetSize(); | 
 | 	} | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	 @brief      		Returns a sorted list of dependencies for the specified | 
 | 						node. The list is ordered with the leaf nodes at the front, | 
 | 						followed by nodes that depend on them and so forth until | 
 | 						the root node is reached and added at the end of the list | 
 | 	 @param[in]			aOutputArray	The dynamic array to store | 
 | 										the sorted results in | 
 | 	 @param[in]			ui32NodeID		The ID of the root node for | 
 | 										the dependency search | 
 | 	*****************************************************************************/ | 
 | 	void RetreiveSortedDependencyList(CPVRTArray<T> &aOutputArray,  | 
 | 										const unsigned int ui32NodeID) | 
 | 	{ | 
 | 		_ASSERT(ui32NodeID >= 0 && ui32NodeID < (unsigned int)m_aHashTable.GetSize()); | 
 | 		RecursiveSortedListAdd(aOutputArray, m_aHashTable[ui32NodeID].GetNode()); | 
 | 	} | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	 @brief      		Overloads operator[] to returns a handle to the node data | 
 | 						for the specified ID | 
 | 	 @return			T&		Handle to the node data | 
 | 	*****************************************************************************/ | 
 | 	T& operator[](const unsigned int ui32NodeID) | 
 | 	{ | 
 | 		return *(GetNodeData(ui32NodeID)); | 
 | 	} | 
 | 	 | 
 | 	/*!*************************************************************************** | 
 | 	 @brief      		Overloads operator[] to returns a const handle to the node  | 
 | 						data for the specified ID | 
 | 	 @return			T&		Handle to the node data | 
 | 	*****************************************************************************/ | 
 | 	const T& operator[](const unsigned int ui32NodeID) const | 
 | 	{ | 
 | 		return *(GetNodeData(ui32NodeID)); | 
 | 	} | 
 |  | 
 | //-------------------------------------------------------------------------// | 
 | private: | 
 | 	/*!*************************************************************************** | 
 | 	 @brief      		Recursively adds node dependancies to aOutputArray. | 
 | 						By doing so, aOutputArray will be ordered from leaf nodes to | 
 | 						the root node that started the recursive chain | 
 | 	 @param[in]			aOutputArray	The dynamic array to store | 
 | 										the sorted results in | 
 | 	 @param[in]			currentNode		The current node to process | 
 | 	*****************************************************************************/ | 
 | 	void RecursiveSortedListAdd(CPVRTArray<T> &aOutputArray, | 
 | 								CPVRTSkipGraphNode<T> ¤tNode) | 
 | 	{ | 
 | 		unsigned int ui(0); | 
 |  | 
 | 		/* | 
 | 			Recursively add dependancies first | 
 | 		*/ | 
 | 		for(ui = 0; ui < currentNode.GetNumDependencies(); ++ui) | 
 | 		{ | 
 | 			RecursiveSortedListAdd(aOutputArray, currentNode.GetDependency(ui)); | 
 | 		} | 
 |  | 
 | 		/* | 
 | 			Then add this node to the array | 
 | 		*/ | 
 | 		aOutputArray.Append(currentNode.GetData()); | 
 | 	} | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	 @fn       			GetNodeData | 
 | 	 @param[in,out] 	ui32NodeID		The node's ID | 
 | 	 @return			T*				A handle to node's data | 
 | 	 @brief      		Retrieve a handle to the specified node's data | 
 | 	*****************************************************************************/ | 
 | 	T* GetNodeData(unsigned int ui32NodeID) | 
 | 	{ | 
 | 		_ASSERT(ui32NodeID >= 0 && ui32NodeID < (unsigned int)m_aHashTable.GetSize()); | 
 | 		return &m_aHashTable[ui32NodeID].GetNode().GetData(); | 
 | 	} | 
 | 	 | 
 | 	/*!*************************************************************************** | 
 | 	 @brief      		Use the input hash to search the hash table and see if the | 
 | 						node already exists. If it does, the function returns a pointer | 
 | 						to the node. If it doesn't, it returns NULL | 
 | 	 @param[in,out] 	ui32Hash						The hash value to search with | 
 | 	 @return			CPVRTSkipGraphNode<T>* const	A handle to the found node | 
 | 	*****************************************************************************/ | 
 | 	CPVRTSkipGraphNode<T>* FindNode(const CPVRTHash& Hash) | 
 | 	{ | 
 | 		int i(0); | 
 | 		int i32HashTableSize(m_aHashTable.GetSize()); | 
 |  | 
 | 		/* | 
 | 			A NULL hash means the node has not initialised | 
 | 			correctly | 
 | 		*/ | 
 | 		if(Hash == 0) | 
 | 			return NULL; | 
 |  | 
 | 		/* | 
 | 			NOTE: | 
 | 			In the future, the hash table could be sorted from | 
 | 			lowest hash value to highest so that binary search could | 
 | 			be used to find a given node. It should be possible to | 
 | 			use a bool (or some other mechanism) to toggle this form of search | 
 | 			(if the skip graph is small, it might be faster to just use a brute | 
 | 			force for loop to search through) | 
 | 		*/ | 
 | 		for(i = 0; i < i32HashTableSize; i++) | 
 | 		{ | 
 | 			if(m_aHashTable[i].GetHash() == Hash) | 
 | 			{ | 
 | 				return &m_aHashTable[i].GetNode(); | 
 | 			} | 
 | 		} | 
 |  | 
 | 		/* | 
 | 			The element wasn't found, so return null | 
 | 		*/ | 
 | 		return NULL; | 
 | 	} | 
 |  | 
 | 	/*!*************************************************************************** | 
 | 	 @brief      		Use the input data to generate a hash and then | 
 | 						search the hash table and see if the node already exists. | 
 | 						If it does, the function returns a pointer | 
 | 						to the node. If it doesn't, it returns NULL | 
 | 	 @param[in,out] 	data							Data to use as a source for the hash | 
 | 	 @return			CPVRTSkipGraphNode<T>* const	A handle to the found node | 
 | 	*****************************************************************************/ | 
 | 	CPVRTSkipGraphNode<T>* FindNode(const T& data) | 
 | 	{ | 
 | 		CPVRTHash inputHash((void*)&data, sizeof(T), 1);	// Generate hash for searching | 
 | 		return FindNode(inputHash); | 
 | 	} | 
 | }; | 
 |  | 
 | #endif //__PVRTSKIPGRAPH_H__ | 
 |  | 
 | /***************************************************************************** | 
 |  End of file (PVRTSkipGraph.h) | 
 | *****************************************************************************/ | 
 |  |