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