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;
|
|
}
|
|
|
|
|