302 lines
6.6 KiB
C
302 lines
6.6 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
hashtable.h
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Definition of:
|
||
|
CPool<T>, CStringPool, CHashTableElement<T>
|
||
|
|
||
|
Implementation of:
|
||
|
CHashTable<T>
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Mohit Srivastava 10-Nov-2000
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#ifndef _hashtable_h_
|
||
|
#define _hashtable_h_
|
||
|
|
||
|
#include <lkrhash.h>
|
||
|
|
||
|
const ULONG POOL_ARRAY_SIZE = 10;
|
||
|
const ULONG HASH_TABLE_POOL_SIZE = 10;
|
||
|
const ULONG STRING_POOL_STRING_SIZE = 64;
|
||
|
|
||
|
//
|
||
|
// This is an array of pointers to arrays (aka buckets).
|
||
|
// -You pass the size of the first bucket to Initialize.
|
||
|
// -When first bucket is full, a new bucket is created
|
||
|
// that is twice as big as the last one.
|
||
|
// -When the array itself is full, it is doubled and the
|
||
|
// bucket pointers from the old array are copied. Then
|
||
|
// the old array is cleaned up.
|
||
|
//
|
||
|
|
||
|
template <class T> class CPool
|
||
|
{
|
||
|
public:
|
||
|
CPool() :
|
||
|
m_bInitCalled(false),
|
||
|
m_bInitSuccessful(false),
|
||
|
m_apBuckets(NULL),
|
||
|
m_iArrayPosition(0),
|
||
|
m_iArraySize(0),
|
||
|
m_iCurrentBucketPosition(0),
|
||
|
m_iCurrentBucketSize(0),
|
||
|
m_iFirstBucketSize(0) {}
|
||
|
~CPool()
|
||
|
{
|
||
|
for(ULONG i = 0; i < m_iArrayPosition; i++)
|
||
|
{
|
||
|
delete [] m_apBuckets[i];
|
||
|
}
|
||
|
delete [] m_apBuckets;
|
||
|
}
|
||
|
HRESULT Initialize(ULONG i_iFirstBucketSize);
|
||
|
HRESULT GetNewElement(T** o_ppElement);
|
||
|
T* Lookup(ULONG i_idx) const;
|
||
|
ULONG GetUsed() const
|
||
|
{
|
||
|
return (GetSize() - m_iCurrentBucketSize) + m_iCurrentBucketPosition;
|
||
|
}
|
||
|
ULONG GetSize() const
|
||
|
{
|
||
|
return (2 * m_iCurrentBucketSize - m_iFirstBucketSize);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
//
|
||
|
// Change this as necessary for best performance.
|
||
|
//
|
||
|
static const ULONG ARRAY_SIZE = ::POOL_ARRAY_SIZE;
|
||
|
|
||
|
bool m_bInitCalled;
|
||
|
bool m_bInitSuccessful;
|
||
|
|
||
|
ULONG m_iCurrentBucketPosition;
|
||
|
ULONG m_iCurrentBucketSize;
|
||
|
ULONG m_iFirstBucketSize;
|
||
|
|
||
|
ULONG m_iArraySize;
|
||
|
ULONG m_iArrayPosition;
|
||
|
T** m_apBuckets;
|
||
|
};
|
||
|
|
||
|
|
||
|
//
|
||
|
// CArrayPool contains two pools.
|
||
|
// If a user calls GetNewArray with i <= size, then we serve request from fixedsize pool.
|
||
|
// If i > size, then we serve request from dynamic pool. In this case, we need to perform
|
||
|
// a new since the dynamic pool is a pool of ptrs to T.
|
||
|
//
|
||
|
|
||
|
template <class T, ULONG size>
|
||
|
struct CArrayPoolEntry
|
||
|
{
|
||
|
T m_data[size];
|
||
|
};
|
||
|
|
||
|
template <class T, ULONG size> class CArrayPool
|
||
|
{
|
||
|
public:
|
||
|
CArrayPool() {}
|
||
|
virtual ~CArrayPool()
|
||
|
{
|
||
|
T* pElem;
|
||
|
for(ULONG i = 0; i < m_PoolDynamic.GetUsed(); i++)
|
||
|
{
|
||
|
pElem = *m_PoolDynamic.Lookup(i);
|
||
|
delete [] pElem;
|
||
|
}
|
||
|
}
|
||
|
HRESULT Initialize();
|
||
|
HRESULT GetNewArray(ULONG i_cElem, T** o_ppElem);
|
||
|
T* Lookup(ULONG i_idx) const;
|
||
|
|
||
|
protected:
|
||
|
CPool< CArrayPoolEntry<T, size> > m_PoolFixedSize;
|
||
|
CPool< T * > m_PoolDynamic;
|
||
|
|
||
|
private:
|
||
|
//
|
||
|
// This is passed to constructor of the embedded CPools.
|
||
|
//
|
||
|
static const FIRST_BUCKET_SIZE = 10;
|
||
|
};
|
||
|
|
||
|
|
||
|
class CStringPool: public CArrayPool<wchar_t, ::STRING_POOL_STRING_SIZE>
|
||
|
{
|
||
|
public:
|
||
|
void ToConsole() const;
|
||
|
HRESULT GetNewString(LPCWSTR i_wsz, LPWSTR* o_pwsz);
|
||
|
HRESULT GetNewString(LPCWSTR i_wsz, ULONG i_cch, LPWSTR* o_pwsz);
|
||
|
};
|
||
|
|
||
|
|
||
|
template <class T> class CHashTableElement
|
||
|
{
|
||
|
public:
|
||
|
LPWSTR m_wszKey;
|
||
|
T m_data;
|
||
|
ULONG m_idx;
|
||
|
};
|
||
|
|
||
|
template <class T>
|
||
|
class CHashTable : public CTypedHashTable<CHashTable, const CHashTableElement<T>, const WCHAR*>
|
||
|
{
|
||
|
public:
|
||
|
CHashTable() : CTypedHashTable<CHashTable, const CHashTableElement<T>, const WCHAR*>("n")
|
||
|
{
|
||
|
m_idxCur = 0;
|
||
|
}
|
||
|
|
||
|
~CHashTable()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
//
|
||
|
// These 4 functions are callbacks and must be implemented.
|
||
|
// The user of CHashTable should NOT call these explicitly.
|
||
|
//
|
||
|
static const WCHAR* ExtractKey(
|
||
|
const CHashTableElement<T>* i_pElem)
|
||
|
{
|
||
|
return i_pElem->m_wszKey;
|
||
|
}
|
||
|
static DWORD CalcKeyHash(
|
||
|
const WCHAR* i_wszKey)
|
||
|
{
|
||
|
return HashStringNoCase(i_wszKey);
|
||
|
}
|
||
|
static bool EqualKeys(
|
||
|
const WCHAR* i_wszKey1,
|
||
|
const WCHAR* i_wszKey2)
|
||
|
{
|
||
|
return ( _wcsicmp( i_wszKey1, i_wszKey2 ) == 0 );
|
||
|
}
|
||
|
static void AddRefRecord(
|
||
|
const CHashTableElement<T>* i_pElem,
|
||
|
int i_iIncrementAmount)
|
||
|
{
|
||
|
//
|
||
|
// do nothing
|
||
|
//
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The following functions are the functions that the user should
|
||
|
// actually call.
|
||
|
//
|
||
|
HRESULT Wmi_Initialize()
|
||
|
{
|
||
|
return m_pool.Initialize(HASH_TABLE_POOL_SIZE);
|
||
|
}
|
||
|
|
||
|
HRESULT Wmi_Insert(LPWSTR i_wszKey, T i_DataNew)
|
||
|
{
|
||
|
DBG_ASSERT(i_wszKey != NULL);
|
||
|
|
||
|
HRESULT hr = WBEM_S_NO_ERROR;
|
||
|
LK_RETCODE lkrc;
|
||
|
|
||
|
CHashTableElement<T>* pElementNew;
|
||
|
|
||
|
hr = m_pool.GetNewElement(&pElementNew);
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
pElementNew->m_data = i_DataNew;
|
||
|
pElementNew->m_wszKey = i_wszKey;
|
||
|
pElementNew->m_idx = m_idxCur;
|
||
|
|
||
|
lkrc = InsertRecord(pElementNew);
|
||
|
if(lkrc != LK_SUCCESS)
|
||
|
{
|
||
|
hr = Wmi_LKRToHR(lkrc);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
exit:
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
m_idxCur++;
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT Wmi_GetByKey(LPCWSTR i_wszKey, T* o_pData, ULONG *o_idx)
|
||
|
{
|
||
|
DBG_ASSERT(i_wszKey != NULL);
|
||
|
DBG_ASSERT(o_pData != NULL);
|
||
|
|
||
|
*o_pData = NULL;
|
||
|
|
||
|
HRESULT hr = WBEM_S_NO_ERROR;
|
||
|
LK_RETCODE lkrc;
|
||
|
const CHashTableElement<T>* pElem = NULL;
|
||
|
|
||
|
lkrc = FindKey(i_wszKey, &pElem);
|
||
|
if(lkrc != LK_SUCCESS)
|
||
|
{
|
||
|
hr = Wmi_LKRToHR(lkrc);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
*o_pData = pElem->m_data;
|
||
|
if(o_idx != NULL)
|
||
|
{
|
||
|
*o_idx = pElem->m_idx;
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT Wmi_GetByKey(LPCWSTR i_wszKey, T* o_pData)
|
||
|
{
|
||
|
return Wmi_GetByKey(i_wszKey, o_pData, NULL);
|
||
|
}
|
||
|
|
||
|
HRESULT Wmi_LKRToHR(LK_RETCODE i_lkrc)
|
||
|
{
|
||
|
if(i_lkrc == LK_SUCCESS)
|
||
|
{
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
switch(i_lkrc)
|
||
|
{
|
||
|
case LK_ALLOC_FAIL:
|
||
|
return WBEM_E_OUT_OF_MEMORY;
|
||
|
default:
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ULONG Wmi_GetNumElements()
|
||
|
{
|
||
|
CLKRHashTableStats stats;
|
||
|
stats = GetStatistics();
|
||
|
DBG_ASSERT(stats.RecordCount == m_idxCur);
|
||
|
return m_idxCur;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
CPool< CHashTableElement<T> > m_pool;
|
||
|
ULONG m_idxCur;
|
||
|
};
|
||
|
|
||
|
//
|
||
|
|
||
|
#endif // _hashtable_h_
|