/*=================================================================== Microsoft Denali Microsoft Confidential. Copyright 1996 Microsoft Corporation. All Rights Reserved. Component: Hash table for Script Manager File: SMHash.cpp Owner: AndrewS This is the Link list and Hash table for use by the Script Manager only ===================================================================*/ #include "denpre.h" #pragma hdrstop #include "memchk.h" /*=================================================================== CSMHash::AddElem Adds a CLruLinkElem to the SM Hash table. User is responsible for allocating the Element to be added. Note: This is identical to the standard CHashTable::AddElem, except that it allows for elements with duplicate names Parameters: CLruLinkElem *pElem Object to be added Returns: Pointer to element added/found. ===================================================================*/ CLruLinkElem *CSMHash::AddElem ( CLruLinkElem *pElem ) { AssertValid(); if (m_rgpBuckets == NULL) { if (FAILED(AllocateBuckets())) return NULL; } if (pElem == NULL) return NULL; UINT iBucket = m_pfnHash(pElem->m_pKey, pElem->m_cbKey) % m_cBuckets; CLruLinkElem * pT = static_cast(m_rgpBuckets[iBucket]); while (pT) { if (pT->m_Info > 0) pT = static_cast(pT->m_pNext); else break; } if (pT) { // There are other elements in bucket pT = static_cast(m_rgpBuckets[iBucket]); m_rgpBuckets[iBucket] = pElem; pElem->m_Info = pT->m_Info + 1; pElem->m_pNext = pT; pElem->m_pPrev = pT->m_pPrev; pT->m_pPrev = pElem; if (pElem->m_pPrev == NULL) m_pHead = pElem; else pElem->m_pPrev->m_pNext = pElem; } else { // This is the first element in the bucket m_rgpBuckets[iBucket] = pElem; pElem->m_pPrev = NULL; pElem->m_pNext = m_pHead; pElem->m_Info = 0; if (m_pHead) m_pHead->m_pPrev = pElem; else m_pTail = pElem; m_pHead = pElem; } m_Count++; pElem->PrependTo(m_lruHead); AssertValid(); return pElem; } /*=================================================================== CSMHash::FindElem Finds a script engine element in the hash table based on the name and language type. Parameters: void * pKey - the key to look for int cbKey - length of the key to look for PROGLANG_ID proglang_id - program language name DWORD dwInstanceID - instance ID to find BOOL fCheckLoaded - if true, only return engines flagged as "loaded" Returns: Pointer to CLruLinkElem if found, otherwise NULL. ===================================================================*/ CLruLinkElem * CSMHash::FindElem ( const void *pKey, int cbKey, PROGLANG_ID proglang_id, DWORD dwInstanceID, BOOL fCheckLoaded ) { AssertValid(); if (m_rgpBuckets == NULL || pKey == NULL) return NULL; UINT iBucket = m_pfnHash(static_cast(pKey), cbKey) % m_cBuckets; CLruLinkElem * pT = static_cast(m_rgpBuckets[iBucket]); CLruLinkElem * pRet = NULL; /* * We have the right bucket based on the hashed name. * Search through the bucket chain looking for elements whose name * is correct (multiple names can hash to the same bucket), and * whose language is the one we want, and (optionally) skip * elements that are not fully "loaded" * * Note: This all relys on intimate knowlege of the format of an ActiveScriptEngine. * these elements better be ASE's. */ while (pT && pRet == NULL) { if (FIsEqual(pT->m_pKey, pT->m_cbKey, pKey, cbKey)) { CASEElem *pASEElem = static_cast(pT); Assert(pASEElem != NULL); CActiveScriptEngine *pASE = pASEElem->PASE(); Assert(pASE != NULL); // Element has the right name. Is it really the one we want? if (proglang_id != pASE->ProgLang_Id()) goto LNext; if (dwInstanceID != pASE->DWInstanceID()) goto LNext; if (fCheckLoaded && !pASE->FFullyLoaded()) goto LNext; // Yup, its the right one! pRet = pT; break; } LNext: if (pT->m_Info > 0) pT = static_cast(pT->m_pNext); else { // got to the last element in this bucket chain break; } } if (pRet) pRet->PrependTo(m_lruHead); AssertValid(); return pRet; }