180 lines
4.2 KiB
C++
180 lines
4.2 KiB
C++
|
/*===================================================================
|
||
|
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<CLruLinkElem *>(m_rgpBuckets[iBucket]);
|
||
|
|
||
|
while (pT)
|
||
|
{
|
||
|
if (pT->m_Info > 0)
|
||
|
pT = static_cast<CLruLinkElem *>(pT->m_pNext);
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pT)
|
||
|
{
|
||
|
// There are other elements in bucket
|
||
|
pT = static_cast<CLruLinkElem *>(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<const BYTE *>(pKey), cbKey) % m_cBuckets;
|
||
|
CLruLinkElem * pT = static_cast<CLruLinkElem *>(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<CASEElem *>(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<CLruLinkElem *>(pT->m_pNext);
|
||
|
else
|
||
|
{
|
||
|
// got to the last element in this bucket chain
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pRet)
|
||
|
pRet->PrependTo(m_lruHead);
|
||
|
|
||
|
AssertValid();
|
||
|
return pRet;
|
||
|
}
|
||
|
|
||
|
|