| /*!**************************************************************************** | |
| @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) | |
| *****************************************************************************/ | |