Fabulous Adventures In Coding

Eric Lippert's Blog

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)
{
}

Published Monday, April 19, 2004 6:24 PM by Eric Lippert
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Fabulous Adventures In Coding said:

April 22, 2004 8:29 PM

Leave a Comment

(required) 
(optional)
(required) 
Submit

This Blog

Syndication


© 2008 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker