From: Patrik Gornicz Date: Wed, 19 Aug 2009 03:48:37 +0000 (-0400) Subject: reworked queue to use pointers instead of indexs X-Git-Tag: libbear-premerge~19 X-Git-Url: http://gitweb.pgornicz.com/?a=commitdiff_plain;h=08518243c5b4180856e90ee8430ef0d70270720f;p=libbear.git reworked queue to use pointers instead of indexs --- diff --git a/lib/include/bear/Queue.h b/lib/include/bear/Queue.h index cbfe641..ba0e5cb 100644 --- a/lib/include/bear/Queue.h +++ b/lib/include/bear/Queue.h @@ -26,7 +26,7 @@ namespace bear Queue(); ~Queue() {} - void init(unsigned int uiStartSize = 2, unsigned int uiSizeMultiplier = 2); + void init(unsigned int uiStartSize = 8, unsigned int uiSizeMultiplier = 2); void fini(); void alloc(unsigned int uiSize); @@ -47,15 +47,28 @@ namespace bear unsigned int getLength() const; unsigned int getSpaceNeeded(unsigned int uiSize) const; + // alloc helpers + void allocFirstTime(unsigned int uiSize); + void allocWhenNeeded(unsigned int uiSize); + void allocForce(unsigned int uiSize); + + static Item* getNextHead(Item* pHead, unsigned int uiAllocated, Item* pArrayItems); + static Item* getPrevHead(Item* pHead, unsigned int uiAllocated, Item* pArrayItems); + static Item* getNextTail(Item* pTail, unsigned int uiAllocated, Item* pArrayItems); + static Item* getPrevTail(Item* pTail, unsigned int uiAllocated, Item* pArrayItems); + + static Item* withinBounds(Item* pValue, Item* pMinBound, Item* pMaxBound); + + private: unsigned int m_uiStartSize; unsigned int m_uiSizeMultiplier; unsigned int m_uiAllocated; Item* m_pArrayItems; - bool m_fIsEmpty; - unsigned int m_uiHead; - unsigned int m_uiTail; + // NULL Head _and_ NULL Tail means empty + Item* m_pHead; + Item* m_pTail; }; } // namespace bear @@ -66,9 +79,8 @@ bear::Queue::Queue() m_uiSizeMultiplier(0), m_uiAllocated(0), m_pArrayItems(NULL), - m_fIsEmpty(0), - m_uiHead(0), - m_uiTail(0) + m_pHead(NULL), + m_pTail(NULL) { } @@ -80,18 +92,21 @@ void bear::Queue::init unsigned int uiSizeMultiplier ) { + // Sanity checks + bear::DASSERT(0 < uiStartSize); + bear::DASSERT(1 < uiSizeMultiplier); + m_uiStartSize = uiStartSize; m_uiSizeMultiplier = uiSizeMultiplier; m_uiAllocated = 0; - bear::DASSERT(NULL == m_pArrayItems); // this better be the case + // If this fires you have memory leaks + bear::DASSERT(NULL == m_pArrayItems); m_pArrayItems = NULL; - m_fIsEmpty = true; - - m_uiHead = 0; - m_uiTail = 0; + m_pHead = NULL; + m_pTail = NULL; } template < class Item > void bear::Queue::fini() @@ -101,80 +116,64 @@ void bear::Queue::fini() m_uiAllocated = 0; - if(NULL != m_pArrayItems) delete m_pArrayItems; - m_pArrayItems = NULL; - - m_fIsEmpty = true; + if(NULL != m_pArrayItems) + { + delete m_pArrayItems; + m_pArrayItems = NULL; + } - m_uiHead = 0; - m_uiTail = 0; + m_pHead = NULL; + m_pTail = NULL; } template < class Item > void bear::Queue::alloc(unsigned int uiSize) { - if(m_uiAllocated < uiSize) + if(NULL == m_pArrayItems) { - unsigned int uiOldLength = getLength(); - - unsigned int uiOldAllocated = m_uiAllocated; - Item * pOldArrayItems = m_pArrayItems; - unsigned int uiOldHead = m_uiHead; - //unsigned int uiOldTail = m_uiTail; - - m_uiAllocated = 0; - m_pArrayItems = NULL; - m_uiHead = 0; - m_uiTail = 0; - - unsigned int uiNewAllocated = uiSize; - Item * pNewArrayItems = new Item[uiNewAllocated]; - unsigned int uiNewHead = 0; - unsigned int uiNewTail = uiOldLength - 1; - - if(NULL == pOldArrayItems) - { - // santiy check - bear::DASSERT(0 == uiOldLength); - bear::DASSERT(true == m_fIsEmpty); - - uiNewTail = 0; - - // Nothing to copy over - } - else - { - // Copy old items into new array - for(unsigned int uiNewIndex = uiNewHead; uiNewIndex <= uiNewTail; uiNewIndex++) - { - unsigned int uiOldIndex = mod(uiNewIndex + uiOldHead, uiOldAllocated); - bear::DASSERT(uiOldIndex <= uiOldAllocated); - - bear::DASSERT(NULL != pOldArrayItems); - pNewArrayItems[uiNewIndex] = pOldArrayItems[uiOldIndex]; - } - - delete pOldArrayItems; - } - - m_uiAllocated = uiNewAllocated; - m_pArrayItems = pNewArrayItems; - m_uiHead = uiNewHead; - m_uiTail = uiNewTail; + allocFirstTime(uiSize); + } + else if(m_uiAllocated < uiSize) + { + allocForce(uiSize); } - // TODO: return error code + bear::DASSERT(m_uiAllocated >= uiSize); + + // TODO: return error when new fails } + template < class Item > void bear::Queue::trim() { - bear::DASSERT(false); // Not Implemented + unsigned int uiSize = getLength(); + if(NULL == m_pArrayItems) + { + allocFirstTime(uiSize); + } + else + { + allocForce(uiSize); + } + + // Sanity checks + bear::DASSERT(uiSize == getLength()); + bear::DASSERT(uiSize == m_uiAllocated); } template < class Item > bool bear::Queue::isEmpty() const { - return m_fIsEmpty; + if ( NULL == m_pHead ) + { + bear::DASSERT(NULL == m_pTail); + return true; + } + else + { + bear::DASSERT(NULL != m_pTail); + return false; + } } template < class Item > @@ -184,9 +183,9 @@ const Item& bear::Queue::getFront() const bear::DASSERT(!isEmpty()); // sanity check - bear::DASSERT(m_uiHead <= m_uiAllocated); + //bear::DASSERT(m_pHead <= m_uiAllocated); - return m_pArrayItems[m_uiHead]; + return *m_pHead; } template < class Item > @@ -196,51 +195,47 @@ const Item& bear::Queue::getBack() const bear::DASSERT(!isEmpty()); // sanity check - bear::DASSERT(m_uiTail <= m_uiAllocated); + //bear::DASSERT(m_pTail <= m_uiAllocated); - return m_pArrayItems[m_uiTail]; + return *m_pTail; } template < class Item > void bear::Queue::pushFront(const Item& i) { // Make sure we have the space to add an item - alloc( getSpaceNeeded( getLength() + 1 ) ); + allocWhenNeeded( getLength() + 1 ); if(isEmpty()) { - m_fIsEmpty = false; - - m_uiHead = 0; - m_uiTail = 0; + m_pHead = m_pArrayItems; + m_pTail = m_pArrayItems; } else { - m_uiHead = mod( m_uiHead - 1, m_uiAllocated ); + m_pHead = getNextHead(m_pHead, m_uiAllocated, m_pArrayItems); } - m_pArrayItems[m_uiHead] = i; + *m_pHead = i; } template < class Item > void bear::Queue::pushBack(const Item& i) { // Make sure we have the space to add an item - alloc( getSpaceNeeded( getLength() + 1 ) ); + allocWhenNeeded( getLength() + 1 ); if(isEmpty()) { - m_fIsEmpty = false; - - m_uiHead = 0; - m_uiTail = 0; + m_pHead = m_pArrayItems; + m_pTail = m_pArrayItems; } else { - m_uiTail = mod( m_uiTail + 1, m_uiAllocated ); + m_pTail = getNextTail(m_pTail, m_uiAllocated, m_pArrayItems); } - m_pArrayItems[m_uiTail] = i; + *m_pTail = i; } template < class Item > @@ -248,16 +243,14 @@ void bear::Queue::popFront() { bear::DASSERT(!isEmpty()); - if( m_uiHead == m_uiTail ) + if( m_pHead == m_pTail ) { - m_fIsEmpty = true; - - m_uiHead = 0; - m_uiTail = 0; + m_pHead = NULL; + m_pTail = NULL; } else { - m_uiHead = mod( m_uiHead + 1, m_uiAllocated ); + m_pHead = getPrevHead(m_pHead, m_uiAllocated, m_pArrayItems); } } @@ -266,16 +259,14 @@ void bear::Queue::popBack() { bear::DASSERT(!isEmpty()); - if( m_uiHead == m_uiTail ) + if( m_pHead == m_pTail ) { - m_fIsEmpty = true; - - m_uiHead = 0; - m_uiTail = 0; + m_pHead = NULL; + m_pTail = NULL; } else { - m_uiTail = mod( m_uiTail - 1, m_uiAllocated ); + m_pTail = getPrevTail(m_pTail, m_uiAllocated, m_pArrayItems); } } @@ -289,24 +280,159 @@ unsigned int bear::Queue::getLength() const } else { - return mod( m_uiTail - m_uiHead, m_uiAllocated ) + 1; + return mod( m_pTail - m_pHead, m_uiAllocated ) + 1; } } template < class Item > -unsigned int bear::Queue::getSpaceNeeded(unsigned int uiSize) const +void bear::Queue::allocFirstTime(unsigned int uiSize) { - unsigned int uiNewSize = m_uiAllocated; + // santiy checks + bear::DASSERT(0 == m_uiAllocated); + bear::DASSERT(NULL == m_pArrayItems); + bear::DASSERT(isEmpty()); - if(0 == uiNewSize) + if(0 < uiSize) { - uiNewSize = m_uiStartSize; + unsigned int uiNewAllocated = uiSize; + Item * pNewArrayItems = new Item[uiNewAllocated]; + + m_uiAllocated = uiNewAllocated; + m_pArrayItems = pNewArrayItems; } +} + +template < class Item > +void bear::Queue::allocWhenNeeded(unsigned int uiSize) +{ + unsigned int uiSizeNeeded = (0 == m_uiAllocated) ? m_uiStartSize : m_uiAllocated; + + bear::DASSERT(0 < m_uiStartSize); + bear::DASSERT(1 < m_uiSizeMultiplier); - while ( uiNewSize < uiSize ) + while ( uiSizeNeeded < uiSize ) { - uiNewSize *= m_uiSizeMultiplier; + uiSizeNeeded *= m_uiSizeMultiplier; } - return uiNewSize; + if(uiSizeNeeded > m_uiAllocated) + { + alloc(uiSizeNeeded); + } +} + +template < class Item > +void bear::Queue::allocForce(unsigned int uiSize) +{ + unsigned int uiOldLength = getLength(); + + unsigned int uiOldAllocated = m_uiAllocated; + Item * pOldArrayItems = m_pArrayItems; + Item * pOldHead = m_pHead; + Item * pOldTail = m_pTail; + + m_uiAllocated = 0; + m_pArrayItems = NULL; + m_pHead = 0; + m_pTail = 0; + + unsigned int uiNewAllocated = uiSize; + Item * pNewArrayItems = new Item[uiNewAllocated]; + Item * pNewHead = pNewArrayItems; + Item * pNewTail = pNewHead + uiOldLength - 1; + + { + // Copy old items into new array + Item * pNewItem = pNewHead; + Item * pOldItem = pOldHead; + + for( unsigned int ii = 0; ii < uiOldLength; ii++ ) + { + *pNewItem = *pOldItem; + + // Pick next item + pNewItem = getNextTail(pNewItem, uiNewAllocated, pNewArrayItems); + pOldItem = getNextTail(pOldItem, uiOldAllocated, pOldArrayItems); + } + + // santiy checks + bear::DASSERT(pNewTail == getPrevTail(pNewItem, uiNewAllocated, pNewArrayItems)); + bear::DASSERT(pOldTail == getPrevTail(pOldItem, uiOldAllocated, pOldArrayItems)); + + delete pOldArrayItems; + pOldArrayItems = NULL; + } + + m_uiAllocated = uiNewAllocated; + m_pArrayItems = pNewArrayItems; + m_pHead = pNewHead; + m_pTail = pNewTail; +} + + +template < class Item > +Item* bear::Queue::getNextHead +( + Item* pHead, + unsigned int uiAllocated, + Item* pArrayItems +) +{ + return withinBounds( pHead - 1, pArrayItems, pArrayItems + uiAllocated ); +} + +template < class Item > +Item* bear::Queue::getPrevHead +( + Item* pHead, + unsigned int uiAllocated, + Item* pArrayItems +) +{ + return withinBounds( pHead + 1, pArrayItems, pArrayItems + uiAllocated ); +} + +template < class Item > +Item* bear::Queue::getNextTail +( + Item* pTail, + unsigned int uiAllocated, + Item* pArrayItems +) +{ + return withinBounds( pTail + 1, pArrayItems, pArrayItems + uiAllocated ); +} + +template < class Item > +Item* bear::Queue::getPrevTail +( + Item* pTail, + unsigned int uiAllocated, + Item* pArrayItems +) +{ + return withinBounds( pTail - 1, pArrayItems, pArrayItems + uiAllocated ); +} + +template < class Item > +Item* bear::Queue::withinBounds +( + Item* pValue, + Item* pMinBound, + Item* pMaxBound +) +{ + unsigned int uiValue = reinterpret_cast( pValue ); + unsigned int uiMinBound = reinterpret_cast( pMinBound ); + unsigned int uiMaxBound = reinterpret_cast( pMaxBound ); + + unsigned int uiBoundedValue = uiMinBound + mod(uiValue - uiMinBound, uiMaxBound - uiMinBound); + + Item* pBoundedValue = reinterpret_cast(uiBoundedValue); + + // sanity checks + bear::DASSERT(pMinBound <= pBoundedValue); + bear::DASSERT(pMaxBound > pBoundedValue); + + return pBoundedValue; }