Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

343 lines
6.8 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
hashtable.h
Abstract:
Implementation of:
CPool<T>, CStringPool, CHashTableElement<T>
Author:
Mohit Srivastava 10-Nov-2000
Revision History:
--*/
#include "iisprov.h"
template CPool<METABASE_PROPERTY>;
template CHashTable<METABASE_PROPERTY*>;
template CPool<WMI_CLASS>;
template CHashTable<WMI_CLASS*>;
template CPool<WMI_ASSOCIATION>;
template CHashTable<WMI_ASSOCIATION*>;
template CPool<METABASE_KEYTYPE>;
template CHashTable<METABASE_KEYTYPE*>;
template CArrayPool<wchar_t, ::STRING_POOL_STRING_SIZE>;
template CArrayPool<METABASE_PROPERTY*, 10>;
template CArrayPool<BYTE, 10>;
template CPool<METABASE_KEYTYPE_NODE>;
//
// CPool<T>
//
template <class T>
HRESULT CPool<T>::Initialize(ULONG i_iFirstBucketSize)
/*++
Synopsis:
Set up data structures:
Initialize array to size CPool::ARRAY_SIZE
Create first bucket of size i_iFirstBucketSize
Arguments: [i_iFirstBucketSize] -
Return Value:
S_OK, E_OUTOFMEMORY
--*/
{
DBG_ASSERT(m_bInitCalled == false);
DBG_ASSERT(m_bInitSuccessful == false);
m_bInitCalled = true;
HRESULT hr = S_OK;
m_apBuckets = new T*[ARRAY_SIZE];
if(m_apBuckets == NULL)
{
hr = E_OUTOFMEMORY;
goto exit;
}
m_iArraySize = ARRAY_SIZE;
m_iArrayPosition = 1;
m_apBuckets[0] = new T[i_iFirstBucketSize];
if(m_apBuckets[0] == NULL)
{
hr = E_OUTOFMEMORY;
goto exit;
}
m_iCurrentBucketSize = i_iFirstBucketSize;
m_iFirstBucketSize = i_iFirstBucketSize;
m_iCurrentBucketPosition = 0;
exit:
if(SUCCEEDED(hr))
{
m_bInitSuccessful = true;
}
return hr;
}
template <class T>
HRESULT CPool<T>::GetNewElement(T** o_ppElement)
/*++
Synopsis:
Normally, just a matter of returning pointer to next spot in bucket.
May have to create a new bucket and/or grow the array, however.
Arguments: [o_ppElement] -
Return Value:
S_OK, E_OUTOFMEMORY
--*/{
DBG_ASSERT(m_bInitCalled == true);
DBG_ASSERT(m_bInitSuccessful == true);
DBG_ASSERT(o_ppElement != NULL);
HRESULT hr = S_OK;
//
// Check to see if we need to move on to the next bucket
//
if(m_iCurrentBucketPosition == m_iCurrentBucketSize)
{
//
// Check to see if we need to grow the array
//
if(m_iArrayPosition == m_iArraySize)
{
T** apBucketsNew;
apBucketsNew = new T*[m_iArraySize*2];
if(m_apBuckets == NULL)
{
return E_OUTOFMEMORY;
}
memcpy(apBucketsNew, m_apBuckets, m_iArraySize * sizeof(T*));
delete [] m_apBuckets;
m_apBuckets = apBucketsNew;
m_iArraySize *= 2;
}
T* pBucketNew;
pBucketNew = new T[m_iCurrentBucketSize*2];
if(pBucketNew == NULL)
{
return E_OUTOFMEMORY;
}
m_apBuckets[m_iArrayPosition] = pBucketNew;
m_iCurrentBucketSize *= 2;
m_iCurrentBucketPosition = 0;
m_iArrayPosition++;
}
*o_ppElement = &m_apBuckets[m_iArrayPosition-1][m_iCurrentBucketPosition];
m_iCurrentBucketPosition++;
return hr;
}
template <class T>
T* CPool<T>::Lookup(ULONG i_idx) const
/*++
Synopsis:
Looks up data in pool by index
Arguments: [i_idx] - Valid Range is 0 to GetUsed()-1
Return Value:
A pointer to the data unless i_idx is out of range.
--*/
{
DBG_ASSERT(m_bInitCalled == true);
DBG_ASSERT(m_bInitSuccessful == true);
//
// Total element capacity of all buckets up to and including the current one
// in the for loop below
//
ULONG iElementsCovered = 0;
ULONG iBucketPos = 0;
if (i_idx >= GetUsed())
{
return NULL;
}
for(ULONG i = 0; i < m_iArrayPosition; i++)
{
iElementsCovered = iElementsCovered + (1 << i)*(m_iFirstBucketSize);
if(i_idx < iElementsCovered)
{
iBucketPos =
i_idx - ( iElementsCovered - (1 << i)*(m_iFirstBucketSize) );
return &m_apBuckets[i][iBucketPos];
}
}
return NULL;
}
//
// CArrayPool
//
template <class T, ULONG size>
HRESULT CArrayPool<T, size>::Initialize()
/*++
Synopsis:
should only be called once
Return Value:
--*/
{
HRESULT hr = S_OK;
hr = m_PoolFixedSize.Initialize(FIRST_BUCKET_SIZE);
if(FAILED(hr))
{
return hr;
}
hr = m_PoolDynamic.Initialize(FIRST_BUCKET_SIZE);
if(FAILED(hr))
{
return hr;
}
return hr;
}
template <class T, ULONG size>
HRESULT CArrayPool<T, size>::GetNewArray(ULONG i_cElem, T** o_ppElem)
/*++
Synopsis:
Fills o_ppElem from either the fixedsize or dynamic pool based on the
requested size.
Arguments: [i_cElem] - number of elements caller wants in new array
[o_ppElem] - receives the new array
Return Value:
--*/
{
DBG_ASSERT(o_ppElem != NULL);
HRESULT hr = S_OK;
T** ppNew = NULL;
T* pNew = NULL;
if(i_cElem <= size)
{
hr = m_PoolFixedSize.GetNewElement((CArrayPoolEntry<T,size>**)&pNew);
if(FAILED(hr))
{
return hr;
}
ppNew = &pNew;
}
else
{
hr = m_PoolDynamic.GetNewElement(&ppNew);
if(FAILED(hr))
{
return hr;
}
*ppNew = NULL;
*ppNew = new T[i_cElem+1];
if(*ppNew == NULL)
{
return E_OUTOFMEMORY;
}
}
*o_ppElem = *ppNew;
return hr;
}
//
// for debugging only
// if msb set, goto dynamic pool
// else use fixedsize pool
//
template <class T, ULONG size>
T* CArrayPool<T, size>::Lookup(ULONG i_idx) const
{
ULONG i_msb;
i_msb = i_idx >> 31;
if(i_msb == 0)
{
return (T *)(m_PoolFixedSize.Lookup(i_idx));
}
else {
T** pElem = m_PoolDynamic.Lookup( i_idx - (ULONG)(1 << 31) );
if(pElem == NULL)
{
return NULL;
}
else
{
return *pElem;
}
}
}
//
// CStringPool
//
HRESULT CStringPool::GetNewString(LPCWSTR i_wsz, ULONG i_cch, LPWSTR* o_pwsz)
{
DBG_ASSERT(o_pwsz != NULL);
HRESULT hr;
hr = GetNewArray(i_cch+1, o_pwsz);
if(FAILED(hr))
{
return hr;
}
memcpy(*o_pwsz, i_wsz, (i_cch+1)*sizeof(wchar_t));
return hr;
}
HRESULT CStringPool::GetNewString(LPCWSTR i_wsz, LPWSTR* o_pwsz)
{
return GetNewString(i_wsz, wcslen(i_wsz), o_pwsz);
}
//
// for debugging only
//
void CStringPool::ToConsole() const
{
ULONG i;
for(i = 0; i < m_PoolFixedSize.GetUsed(); i++)
{
wprintf(L"%s\n", Lookup(i));
}
for(i = 0; i < m_PoolDynamic.GetUsed(); i++)
{
wprintf( L"%s\n", Lookup( i | (1 << 31) ) );
}
}