/*++ Copyright (c) 2000 Microsoft Corporation Module Name: hashtable.h Abstract: Implementation of: CPool, CStringPool, CHashTableElement Author: Mohit Srivastava 10-Nov-2000 Revision History: --*/ #include "iisprov.h" template CPool; template CHashTable; template CPool; template CHashTable; template CPool; template CHashTable; template CPool; template CHashTable; template CArrayPool; template CArrayPool; template CArrayPool; template CPool; // // CPool // template HRESULT CPool::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 HRESULT CPool::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(apBucketsNew == 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 T* CPool::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 HRESULT CArrayPool::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 HRESULT CArrayPool::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**)&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 T* CArrayPool::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) ) ); } }