reworked queue to use pointers instead of indexs
authorPatrik Gornicz <Gornicz.P@gmail.com>
Wed, 19 Aug 2009 03:48:37 +0000 (23:48 -0400)
committerPatrik Gornicz <Gornicz.P@gmail.com>
Wed, 19 Aug 2009 03:48:37 +0000 (23:48 -0400)
lib/include/bear/Queue.h

index cbfe641..ba0e5cb 100644 (file)
@@ -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<Item>::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<Item>::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<Item>::fini()
@@ -101,80 +116,64 @@ void bear::Queue<Item>::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<Item>::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<Item>::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<Item>::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<Item>::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<Item>::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<Item>::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<Item>::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<Item>::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<Item>::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<Item>::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<Item>::getSpaceNeeded(unsigned int uiSize) const
+void bear::Queue<Item>::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<Item>::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<Item>::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<Item>::getNextHead
+(
+  Item*           pHead,
+  unsigned int    uiAllocated,
+  Item*           pArrayItems
+)
+{
+  return withinBounds( pHead - 1, pArrayItems, pArrayItems + uiAllocated );
+}
+
+template < class Item >
+Item*    bear::Queue<Item>::getPrevHead
+(
+  Item*           pHead,
+  unsigned int    uiAllocated,
+  Item*           pArrayItems
+)
+{
+  return withinBounds( pHead + 1, pArrayItems, pArrayItems + uiAllocated );
+}
+
+template < class Item >
+Item*    bear::Queue<Item>::getNextTail
+(
+  Item*           pTail,
+  unsigned int    uiAllocated,
+  Item*           pArrayItems
+)
+{
+  return withinBounds( pTail + 1, pArrayItems, pArrayItems + uiAllocated );
+}
+
+template < class Item >
+Item*    bear::Queue<Item>::getPrevTail
+(
+  Item*           pTail,
+  unsigned int    uiAllocated,
+  Item*           pArrayItems
+)
+{
+  return withinBounds( pTail - 1, pArrayItems, pArrayItems + uiAllocated );
+}
+
+template < class Item >
+Item*    bear::Queue<Item>::withinBounds
+(
+  Item* pValue,
+  Item* pMinBound,
+  Item* pMaxBound
+)
+{
+  unsigned int  uiValue         = reinterpret_cast<unsigned int>(  pValue     );
+  unsigned int  uiMinBound      = reinterpret_cast<unsigned int>(  pMinBound  );
+  unsigned int  uiMaxBound      = reinterpret_cast<unsigned int>(  pMaxBound  );
+
+  unsigned int  uiBoundedValue  = uiMinBound + mod(uiValue - uiMinBound, uiMaxBound - uiMinBound);
+
+  Item*         pBoundedValue   = reinterpret_cast<Item*>(uiBoundedValue);
+
+  // sanity checks
+  bear::DASSERT(pMinBound <= pBoundedValue);
+  bear::DASSERT(pMaxBound >  pBoundedValue);
+
+  return pBoundedValue;
 }