// // Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved // #include CTreeElement :: CTreeElement(LPCWSTR lpszHashedName, CRefCountedObject *pObject) { m_lpszHashedName = new WCHAR[wcslen(lpszHashedName) + 1]; wcscpy(m_lpszHashedName, lpszHashedName); m_pObject = pObject; m_pObject->AddRef(); m_pLeft = NULL; m_pRight = NULL; } CTreeElement :: ~CTreeElement() { if (m_lpszHashedName) { delete [] m_lpszHashedName; } m_pObject->Release(); } LPCWSTR CTreeElement :: GetHashedName() const { return m_lpszHashedName; } CRefCountedObject *CTreeElement :: GetObject() const { m_pObject->AddRef(); return m_pObject; } CTreeElement *CTreeElement :: GetRight() const { return m_pRight; } CTreeElement *CTreeElement :: GetLeft() const { return m_pLeft; } void CTreeElement :: SetRight(CTreeElement *pNext) { m_pRight = pNext; } void CTreeElement :: SetLeft(CTreeElement *pNext) { m_pLeft = pNext; } CObjectTree :: CObjectTree() { // Initialize the critical section InitializeCriticalSection(&m_ModificationSection); m_dwNumElements = 0; m_pHead = NULL; } CObjectTree :: ~CObjectTree() { // Destroy the data DeleteTree(); // Destroy the critical section DeleteCriticalSection(&m_ModificationSection); } void CObjectTree :: DeleteTree() { EnterCriticalSection(&m_ModificationSection); if(m_pHead) DeleteSubTree(m_pHead); m_dwNumElements = 0; LeaveCriticalSection(&m_ModificationSection); } void CObjectTree :: DeleteSubTree(CTreeElement *pRoot) { if(pRoot->GetLeft()) DeleteSubTree(pRoot->GetLeft()); if(pRoot->GetRight()) DeleteSubTree(pRoot->GetRight()); delete pRoot; } BOOLEAN CObjectTree :: AddElement(LPCWSTR lpszHashedName, CRefCountedObject *pObject) { BOOLEAN retVal = TRUE; EnterCriticalSection(&m_ModificationSection); CTreeElement *pCurrent = m_pHead; CTreeElement *pParent = NULL; int iCompare; // Locate the position where the new element is to be inserted while(pCurrent) { iCompare = _wcsicmp(lpszHashedName, pCurrent->GetHashedName()); if(iCompare == 0) { retVal = FALSE; // The element already exists break; } else if(iCompare > 0) { pParent = pCurrent; pCurrent = pCurrent->GetRight(); } else { pParent = pCurrent; pCurrent = pCurrent->GetLeft(); } } // Create the new element at the appropriate position if(retVal == TRUE && pParent) { iCompare = _wcsicmp(lpszHashedName, pParent->GetHashedName()); if(iCompare == 0) retVal = FALSE; else if(iCompare > 0) { retVal = TRUE; pParent->SetRight(new CTreeElement(lpszHashedName, pObject)); } else { retVal = TRUE; pParent->SetLeft(new CTreeElement(lpszHashedName, pObject)); } } else if (retVal == TRUE) { m_pHead = new CTreeElement(lpszHashedName, pObject); retVal = TRUE; } // Increment the object count if the insertion was successful if(retVal) m_dwNumElements ++; LeaveCriticalSection(&m_ModificationSection); return retVal; } BOOLEAN CObjectTree :: DeleteElement(LPCWSTR lpszHashedName) { BOOLEAN retVal = FALSE; int iDirection = 0; // 0 indicates Unknown, 1 indicates LEFT and 2 indicates RIGHT EnterCriticalSection(&m_ModificationSection); if(m_pHead == NULL) retVal = FALSE; else { // Find the node to be deleted and its parent CTreeElement *pParent = NULL; CTreeElement *pCurrent = m_pHead; int iCompare; while(pCurrent) { iCompare = _wcsicmp(lpszHashedName, pCurrent->GetHashedName()); if(iCompare == 0) break; else if(iCompare < 0) { iDirection = 1; pParent = pCurrent; pCurrent = pCurrent->GetLeft(); } else { iDirection = 2; pParent = pCurrent; pCurrent = pCurrent->GetRight(); } } if(!pCurrent) // The element was not found retVal = FALSE; else { CTreeElement *pCutPart = NULL; // If its left child is null, attach the right subtree to parent if(pCurrent->GetLeft() == NULL) pCutPart = pCurrent->GetRight(); // If its right child is null, attach the left subtree to parent else if(pCurrent->GetRight() == NULL) pCutPart = pCurrent->GetLeft(); else // We need to find the inorder successor { CTreeElement *pInorderSuccessor = pCurrent->GetRight(); if(pInorderSuccessor->GetLeft() == NULL) { pInorderSuccessor->SetLeft(pCurrent->GetLeft()); pCutPart = pInorderSuccessor; } else { CTreeElement *pPredecessor = pCurrent->GetRight(); pInorderSuccessor = pPredecessor->GetLeft(); while(pInorderSuccessor->GetLeft()) { pPredecessor = pInorderSuccessor; pInorderSuccessor = pPredecessor->GetLeft(); } pPredecessor->SetLeft(pInorderSuccessor->GetRight()); pInorderSuccessor->SetLeft(pCurrent->GetLeft()); pInorderSuccessor->SetRight(pCurrent->GetRight()); pCutPart = pInorderSuccessor; } } if(iDirection == 0) m_pHead = pCutPart; else if (iDirection == 1) pParent->SetLeft(pCutPart); else pParent->SetRight(pCutPart); delete pCurrent; retVal = TRUE; } } // Decrement the count of items in the tree if(retVal) m_dwNumElements --; LeaveCriticalSection(&m_ModificationSection); return retVal; } CRefCountedObject * CObjectTree :: GetElement(LPCWSTR lpszHashedName) { EnterCriticalSection(&m_ModificationSection); CTreeElement *pCurrent = m_pHead; CRefCountedObject *pRetVal = NULL; int iCompare; while(pCurrent) { iCompare = _wcsicmp(lpszHashedName, pCurrent->GetHashedName()); if(iCompare == 0) { pRetVal = pCurrent->GetObject(); break; } else if (iCompare > 0) pCurrent = pCurrent->GetRight(); else pCurrent = pCurrent->GetLeft(); } LeaveCriticalSection(&m_ModificationSection); return pRetVal; } BOOLEAN CObjectTree :: DeleteLeastRecentlyAccessedElement() { BOOLEAN retVal = FALSE; EnterCriticalSection(&m_ModificationSection); if(m_pHead) { CRefCountedObject *pOldestElement = m_pHead->GetObject(); CRefCountedObject *pLeftOldestElement = GetLeastRecentlyAccessedElementRecursive(m_pHead->GetLeft()); CRefCountedObject *pRightOldestElement = GetLeastRecentlyAccessedElementRecursive(m_pHead->GetRight()); if (pLeftOldestElement) { if(pLeftOldestElement->GetLastAccessTime() < pOldestElement->GetLastAccessTime()) { pOldestElement->Release(); pOldestElement = pLeftOldestElement; } else pLeftOldestElement->Release(); } if (pRightOldestElement) { if(pRightOldestElement->GetLastAccessTime() < pOldestElement->GetLastAccessTime()) { pOldestElement->Release(); pOldestElement = pRightOldestElement; } else pRightOldestElement->Release(); } retVal = DeleteElement(pOldestElement->GetName()); pOldestElement->Release(); } LeaveCriticalSection(&m_ModificationSection); return retVal; } CRefCountedObject * CObjectTree :: GetLeastRecentlyAccessedElementRecursive(CTreeElement *pElement) { CRefCountedObject *pObject = NULL; if(pElement) { pObject = pElement->GetObject(); CRefCountedObject *pLeftObject = GetLeastRecentlyAccessedElementRecursive(pElement->GetLeft()); if(pLeftObject) { if(pLeftObject->GetCreationTime() < pObject->GetCreationTime()) { pObject->Release(); pObject = pLeftObject; } else pLeftObject->Release(); } CRefCountedObject *pRightObject = GetLeastRecentlyAccessedElementRecursive(pElement->GetRight()); if(pRightObject) { if (pRightObject->GetCreationTime() < pObject->GetCreationTime()) { pObject->Release(); pObject = pRightObject; } else pRightObject->Release(); } } return pObject; }