nameditemlist.cpp

#include "headers.h"

NamedItemList::NamedItemList()
{
this->m_cBuckets = 0;
this->m_Buckets = NULL;
this->m_pMutex = NULL;
}

NamedItemList::~NamedItemList()
{
this->Clear();
if (NULL != this->m_Buckets)
delete[] this->m_Buckets;
if (NULL != this->m_pMutex)
delete this->m_pMutex;
}

HRESULT NamedItemList::Create(int cBuckets, NamedItemList * * ppNamedItemList)
{
AssertOutPtr(ppNamedItemList);
Assert(cBuckets > 0);

    HRESULT hr;
int iBucket;
NamedItemList * pNamedItemList = NULL;

    *ppNamedItemList = NULL;

    pNamedItemList = new NamedItemList();
if (NULL == pNamedItemList)
{
hr = E_OUTOFMEMORY;
goto LError;
}

    hr = Mutex::Create(&pNamedItemList->m_pMutex);
if (FAILED(hr))
goto LError;

    pNamedItemList->m_Buckets = new NamedItem*[cBuckets];
if (NULL == pNamedItemList->m_Buckets)
{
hr = E_OUTOFMEMORY;
goto LError;
}

    pNamedItemList->m_cBuckets = cBuckets;

    for (iBucket = 0 ; iBucket < cBuckets ; ++iBucket)
pNamedItemList->m_Buckets[iBucket] = NULL;

    *ppNamedItemList = pNamedItemList;
pNamedItemList = NULL;

    hr = S_OK;

LError:

    if (NULL != pNamedItemList)
delete pNamedItemList;

    return hr;
}

void NamedItemList::Clear(void)
{
NamedItem * pNamedItem;
NamedItem * pNext;
int iBucket;

    // This could get called due to out-of-memory failure at creation of the mutex.
if (NULL != this->m_pMutex)
this->m_pMutex->Enter();

if (this->m_Buckets != NULL)
{
for (iBucket = 0 ; iBucket < this->m_cBuckets ; ++iBucket)
{
pNamedItem = m_Buckets[iBucket];
while (pNamedItem != NULL)
{
pNext = pNamedItem->m_pNext;
delete pNamedItem;
pNamedItem = pNext;
}
m_Buckets[iBucket] = NULL;
}
}

    if (NULL != this->m_pMutex)
this->m_pMutex->Leave();
}

HRESULT NamedItemList::Add(const WCHAR * pszName, DWORD flags)
{
HRESULT hr;

    int iBucket;
NamedItem * pNamedItemOld;
NamedItem * pNamedItem = NULL;

    this->m_pMutex->Enter();

    pNamedItemOld = this->Find(pszName);
if (NULL != pNamedItemOld)
{
if (pNamedItemOld->m_flags == flags)
{
Bug("You've added the same named item twice. That's legal, but weird. "
"You might have a bug.");
hr = S_OK;
}
else
{
Bug("It's a violation of the script engine contract to add the same "
"named item twice with different flags.");
hr = E_UNEXPECTED;
}
goto LError;
}

    hr = NamedItem::Create(pszName, &pNamedItem);
if (FAILED(hr))
goto LError;

    pNamedItem->m_flags = flags;
iBucket = ComputeHash(pNamedItem->m_bstrName) % this->m_cBuckets;
pNamedItem->m_pNext = this->m_Buckets[iBucket];
this->m_Buckets[iBucket] = pNamedItem;
pNamedItem = NULL;

hr = S_OK;

LError:

    if (NULL != pNamedItem)
delete pNamedItem;

    this->m_pMutex->Leave();

    return hr;
}

NamedItemList::NamedItem * NamedItemList::Find(const WCHAR * psz)
{
AssertReadString(psz);

int iBucket;
NamedItem * pNamedItem;

iBucket = ComputeHash(psz) % this->m_cBuckets;

    for(pNamedItem = this->m_Buckets[iBucket] ; NULL != pNamedItem; pNamedItem = pNamedItem->m_pNext)
{
if (0 == wcscmp(psz, pNamedItem->m_bstrName))
break;
}

    return pNamedItem;
}

void NamedItemList::Reset(void)
{
int iBucket;
NamedItem * pNamedItem;
NamedItem * pNext;
NamedItem * * ppPrevNext;

    this->m_pMutex->Enter();

    for (iBucket = 0 ; iBucket < this->m_cBuckets ; ++iBucket)
{
ppPrevNext = &this->m_Buckets[iBucket];
pNamedItem = this->m_Buckets[iBucket];
while (NULL != pNamedItem)
{
pNext = pNamedItem->m_pNext;
if (pNamedItem->IsPersistent())
{
pNamedItem->Reset();
ppPrevNext = &pNamedItem->m_pNext;
}
else
{
*ppPrevNext = pNext;
delete pNamedItem;
}
pNamedItem = pNext;
}
}

this->m_pMutex->Leave();
}

HRESULT NamedItemList::Clone(NamedItemList * * ppNamedItemList)
{
AssertOutPtr(ppNamedItemList);

HRESULT hr;
int iBucket;
NamedItemList * pNamedItemList = NULL;
NamedItem * pNamedItem;

    *ppNamedItemList = NULL;

    this->m_pMutex->Enter();

    hr = NamedItemList::Create(this->m_cBuckets, &pNamedItemList);
if (FAILED(hr))
goto LError;

    for (iBucket = 0 ; iBucket < this->m_cBuckets ; ++iBucket)
{
for (pNamedItem = this->m_Buckets[iBucket] ; NULL != pNamedItem ;
pNamedItem = pNamedItem->m_pNext)
{
if (!pNamedItem->IsPersistent())
continue;
hr = pNamedItemList->Add(pNamedItem->m_bstrName, pNamedItem->m_flags);
if (FAILED(hr))
goto LError;
}
}

    *ppNamedItemList = pNamedItemList;
pNamedItemList = NULL;

    hr = S_OK;

LError:

    if (NULL != pNamedItemList)
delete pNamedItemList;

    this->m_pMutex->Leave();

    return hr;
}

NamedItemList::NamedItem::NamedItem()
{
this->m_pNext = NULL;
this->m_bstrName = NULL;
this->m_flags = 0;
}

NamedItemList::NamedItem::~NamedItem()
{
SysFreeString(this->m_bstrName);
}

HRESULT NamedItemList::NamedItem::Create(const WCHAR * pszName, NamedItem * * ppNamedItem)
{
AssertReadString(pszName);
AssertOutPtr(ppNamedItem);

    HRESULT hr;

    NamedItem * pNamedItem = NULL;
*ppNamedItem = NULL;

    pNamedItem = new NamedItem();
if (NULL == pNamedItem)
{
hr = E_OUTOFMEMORY;
goto LError;
}

    pNamedItem->m_bstrName = SysAllocString(pszName);
if (NULL == pNamedItem->m_bstrName)
{
hr = E_OUTOFMEMORY;
goto LError;
}

    *ppNamedItem = pNamedItem;
pNamedItem = NULL;
hr = S_OK;

LError:

    if (NULL != pNamedItem)
delete pNamedItem;

    return hr;
}

BOOL NamedItemList::NamedItem::IsPersistent()
{
return (this->m_flags & SCRIPTITEM_ISPERSISTENT) == 0 ? FALSE : TRUE;
}

void NamedItemList::NamedItem::Reset(void)
{
}