Queue.h

00001 /* This file is Copyright 2000-2008 Meyer Sound Laboratories Inc.  See the included LICENSE.txt file for details. */
00002 
00003 #ifndef MuscleQueue_h
00004 #define MuscleQueue_h
00005 
00006 #include "support/MuscleSupport.h"
00007 
00008 BEGIN_NAMESPACE(muscle);
00009 
00010 #ifndef SMALL_QUEUE_SIZE
00011 # define SMALL_QUEUE_SIZE 3
00012 #endif
00013 
00018 template <class ItemType> class Queue
00019 {
00020 public:
00022    Queue();
00023 
00027    explicit Queue(uint32 initialSlots);
00028 
00030    Queue(const Queue& copyMe);
00031 
00033    virtual ~Queue();
00034 
00036    Queue &operator=(const Queue &from);
00037 
00040    bool operator==(const Queue &rhs) const;
00041 
00043    bool operator!=(const Queue &rhs) const {return !(*this == rhs);}
00044 
00049    status_t CopyFrom(const Queue<ItemType> & rhs);
00050 
00055    status_t AddTail(const ItemType & item = ItemType());
00056 
00068    status_t AddTail(const Queue<ItemType> & queue, uint32 startIndex = 0, uint32 numItems = MUSCLE_NO_LIMIT);
00069 
00077    status_t AddTail(const ItemType * items, uint32 numItems);
00078 
00083    status_t AddHead(const ItemType &item = ItemType());
00084 
00096    status_t AddHead(const Queue<ItemType> & queue, uint32 startIndex = 0, uint32 numItems = MUSCLE_NO_LIMIT);
00097 
00104    status_t AddHead(const ItemType * items, uint32 numItems);
00105 
00109    status_t RemoveHead();
00110 
00115    status_t RemoveHead(ItemType & returnItem);
00116 
00120    status_t RemoveTail();
00121 
00126    status_t RemoveTail(ItemType & returnItem);
00127 
00135    status_t RemoveItemAt(uint32 index);
00136 
00143    status_t RemoveItemAt(uint32 index, ItemType & returnItem);
00144 
00151    status_t GetItemAt(uint32 index, ItemType & returnItem) const;
00152 
00159    ItemType * GetItemAt(uint32 index) const;
00160 
00167    status_t ReplaceItemAt(uint32 index, const ItemType & newItem = ItemType());
00168  
00176    status_t InsertItemAt(uint32 index, const ItemType & newItem = ItemType());
00177    
00189    status_t InsertItemsAt(uint32 index, const Queue<ItemType> & queue, uint32 startIndex = 0, uint32 numNewItems = MUSCLE_NO_LIMIT);
00190 
00201    status_t InsertItemsAt(uint32 index, const ItemType * items, uint32 numNewItems);
00202 
00207    void Clear(bool releaseCachedBuffers = false);
00208 
00210    uint32 GetNumItems() const {return _itemCount;}
00211 
00216    uint32 GetNumAllocatedItemSlots() const {return _queueSize;}
00217 
00219    bool IsEmpty() const {return (_itemCount == 0);}
00220 
00222    bool HasItems() const {return (_itemCount > 0);}
00223 
00225    const ItemType & Head() const {return *GetItemAt(0);}
00226 
00228    const ItemType & Tail() const {return *GetItemAt(_itemCount-1);}
00229 
00231    ItemType & Head() {return *GetItemAt(0);}
00232 
00234    ItemType & Tail() {return *GetItemAt(_itemCount-1);}
00235 
00237    ItemType * HeadPointer() const {return (_itemCount > 0) ? GetItemAt(0) : NULL;}
00238 
00240    ItemType * TailPointer() const {return (_itemCount > 0) ? GetItemAt(_itemCount-1) : NULL;}
00241 
00243    const ItemType & operator [](uint32 Index) const; 
00244 
00246    ItemType & operator [](uint32 Index);
00247 
00251    ItemType * GetItemPointer(uint32 index) const {return GetItemAt(index);}
00252 
00268    status_t EnsureSize(uint32 numSlots, bool setNumItems = false, uint32 extraReallocItems = 0);
00269 
00275    int32 IndexOf(const ItemType & item) const;
00276 
00283    void Swap(uint32 fromIndex, uint32 toIndex);
00284 
00293    void ReverseItemOrdering(uint32 from=0, uint32 to = MUSCLE_NO_LIMIT); 
00294 
00305    typedef int (*ItemCompareFunc)(const ItemType & item1, const ItemType & item2, void * cookie);
00306 
00320    void Sort(ItemCompareFunc compareFunc, uint32 from=0, uint32 to = MUSCLE_NO_LIMIT, void * optCookie = NULL);
00321 
00326    void SwapContents(Queue<ItemType> & that);
00327 
00333    uint32 RemoveAllInstancesOf(const ItemType & val);
00334 
00340    status_t RemoveFirstInstanceOf(const ItemType & val);
00341 
00347    status_t RemoveLastInstanceOf(const ItemType & val);
00348 
00350    bool StartsWith(const ItemType & prefix) const {return ((HasItems())&&(Head() == prefix));}
00351 
00353    bool StartsWith(const Queue<ItemType> & prefixQueue) const;
00354 
00356    bool EndsWith(const ItemType & suffix) const {return ((HasItems())&&(Tail() == suffix));}
00357 
00359    bool EndsWith(const Queue<ItemType> & suffixQueue) const;
00360 
00371    ItemType * GetArrayPointer(uint32 whichArray, uint32 & retLength) {return const_cast<ItemType *>(GetArrayPointerAux(whichArray, retLength));} 
00372 
00374    const ItemType * GetArrayPointer(uint32 whichArray, uint32 & retLength) const {return GetArrayPointerAux(whichArray, retLength);}
00375 
00382    void Normalize();
00383 
00384 private:
00385    const ItemType * GetArrayPointerAux(uint32 whichArray, uint32 & retLength) const;
00386    void SwapContentsAux(Queue<ItemType> & that);
00387 
00388    inline uint32 NextIndex(uint32 idx) const {return (idx >= _queueSize-1) ? 0 : idx+1;}
00389    inline uint32 PrevIndex(uint32 idx) const {return (idx == 0) ? _queueSize-1 : idx-1;}
00390 
00391    // Translates a user-index into an index into the _queue array.
00392    inline uint32 InternalizeIndex(uint32 idx) const {return (_headIndex + idx) % _queueSize;}
00393 
00394    // Helper methods, used for sorting (stolen from http://www-ihm.lri.fr/~thomas/VisuTri/inplacestablesort.html)
00395    void Merge(ItemCompareFunc compareFunc, uint32 from, uint32 pivot, uint32 to, uint32 len1, uint32 len2, void * cookie);
00396    uint32 Lower(ItemCompareFunc compareFunc, uint32 from, uint32 to, const ItemType & val, void * cookie) const;
00397    uint32 Upper(ItemCompareFunc compareFunc, uint32 from, uint32 to, const ItemType & val, void * cookie) const;
00398 
00399    ItemType _smallQueue[SMALL_QUEUE_SIZE];  // small queues can be stored inline in this array
00400    ItemType * _queue;                       // points to _smallQueue, or to a dynamically alloc'd array
00401    uint32 _queueSize;  // number of slots in the _queue array
00402    uint32 _itemCount;  // number of valid items in the array
00403    uint32 _headIndex;  // index of the first filled slot (meaningless if _itemCount is zero)
00404    uint32 _tailIndex;  // index of the last filled slot (meaningless if _itemCount is zero)
00405    const uint32 _initialSize;  // as specified in ctor
00406 };
00407 
00408 template <class ItemType>
00409 Queue<ItemType>::Queue()
00410    : _queue(NULL), _queueSize(0), _itemCount(0), _initialSize(SMALL_QUEUE_SIZE)
00411 {
00412    // empty
00413 }
00414 
00415 template <class ItemType>
00416 Queue<ItemType>::Queue(uint32 initialSize)
00417    : _queue(NULL), _queueSize(0), _itemCount(0), _initialSize(initialSize)
00418 {
00419    // empty
00420 }
00421 
00422 template <class ItemType>
00423 Queue<ItemType>::Queue(const Queue& rhs)
00424    : _queue(NULL), _queueSize(0), _itemCount(0), _initialSize(rhs._initialSize)
00425 {
00426    *this = rhs;
00427 }
00428 
00429 template <class ItemType>
00430 bool
00431 Queue<ItemType>::operator ==(const Queue& rhs) const
00432 {
00433    if (this == &rhs) return true;
00434    if (GetNumItems() != rhs.GetNumItems()) return false;
00435 
00436    for (int i = GetNumItems()-1; i>=0; i--) if (((*this)[i] == rhs[i]) == false) return false;
00437 
00438    return true;
00439 }
00440 
00441 template <class ItemType>
00442 Queue<ItemType> &
00443 Queue<ItemType>::operator =(const Queue& rhs)
00444 {
00445    if (this != &rhs)
00446    {
00447       uint32 numItems = rhs.GetNumItems();
00448       if (EnsureSize(numItems, true) == B_NO_ERROR) for (uint32 i=0; i<numItems; i++) (*this)[i] = rhs[i];
00449    }
00450    return *this;
00451 }
00452 
00453 template <class ItemType>
00454 status_t 
00455 Queue<ItemType>::CopyFrom(const Queue & rhs)
00456 {
00457    if (this == &rhs) return B_NO_ERROR;
00458 
00459    uint32 numItems = rhs.GetNumItems();
00460    if (EnsureSize(numItems, true) == B_NO_ERROR)
00461    {
00462       for (uint32 i=0; i<numItems; i++) (*this)[i] = rhs[i];
00463       return B_NO_ERROR;
00464    }
00465    return B_ERROR;
00466 }
00467 
00468 template <class ItemType>
00469 ItemType &
00470 Queue<ItemType>::operator[](uint32 i)
00471 {
00472    MASSERT(i<_itemCount, "Invalid index to Queue::[]");
00473    return _queue[InternalizeIndex(i)];
00474 }
00475 
00476 template <class ItemType>
00477 const ItemType &
00478 Queue<ItemType>::operator[](uint32 i) const
00479 {
00480    MASSERT(i<_itemCount, "Invalid index to Queue::[]");
00481    return _queue[InternalizeIndex(i)];
00482 }             
00483 
00484 template <class ItemType>
00485 ItemType * 
00486 Queue<ItemType>::GetItemAt(uint32 i) const
00487 {
00488    return &_queue[InternalizeIndex(i)];
00489 }
00490 
00491 template <class ItemType>
00492 Queue<ItemType>::~Queue()
00493 {
00494    if (_queue != _smallQueue) delete [] _queue;
00495 }
00496 
00497 template <class ItemType>
00498 status_t 
00499 Queue<ItemType>::
00500 AddTail(const ItemType &item)
00501 {
00502    if (EnsureSize(_itemCount+1, false, _itemCount+1) == B_ERROR) return B_ERROR;
00503    if (_itemCount == 0) _headIndex = _tailIndex = 0;
00504                    else _tailIndex = NextIndex(_tailIndex);
00505    _queue[_tailIndex] = item;
00506    _itemCount++;
00507    return B_NO_ERROR;
00508 }
00509 
00510 template <class ItemType>
00511 status_t 
00512 Queue<ItemType>::
00513 AddTail(const Queue<ItemType> &queue, uint32 startIndex, uint32 numNewItems)
00514 {
00515    uint32 hisSize = queue.GetNumItems();
00516    numNewItems = muscleMin(numNewItems, (startIndex < hisSize) ? (hisSize-startIndex) : 0);
00517    
00518    uint32 mySize = GetNumItems();
00519    uint32 newSize = mySize+numNewItems;
00520 
00521    if (EnsureSize(newSize, true) != B_NO_ERROR) return B_ERROR;
00522    for (uint32 i=mySize; i<newSize; i++) (*this)[i] = queue[startIndex++];
00523    return B_NO_ERROR;
00524 }
00525 
00526 template <class ItemType>
00527 status_t 
00528 Queue<ItemType>::
00529 AddTail(const ItemType * items, uint32 numItems)
00530 {
00531    uint32 mySize = GetNumItems();
00532    uint32 newSize = mySize+numItems;
00533    uint32 rhs = 0;
00534 
00535    if (EnsureSize(newSize, true) != B_NO_ERROR) return B_ERROR;
00536    for (uint32 i=mySize; i<newSize; i++) (*this)[i] = items[rhs++];
00537    return B_NO_ERROR;
00538 }
00539 
00540 template <class ItemType>
00541 status_t 
00542 Queue<ItemType>::
00543 AddHead(const ItemType &item)
00544 {
00545    if (EnsureSize(_itemCount+1, false, _itemCount+1) == B_ERROR) return B_ERROR;
00546    if (_itemCount == 0) _headIndex = _tailIndex = 0;
00547                    else _headIndex = PrevIndex(_headIndex);
00548    _queue[_headIndex] = item;
00549    _itemCount++;
00550    return B_NO_ERROR;
00551 }
00552 
00553 template <class ItemType>
00554 status_t 
00555 Queue<ItemType>::
00556 AddHead(const Queue<ItemType> &queue, uint32 startIndex, uint32 numNewItems)
00557 {
00558    uint32 hisSize = queue.GetNumItems();
00559    numNewItems = muscleMin(numNewItems, (startIndex < hisSize) ? (hisSize-startIndex) : 0);
00560 
00561    if (EnsureSize(numNewItems+GetNumItems()) != B_NO_ERROR) return B_ERROR;
00562    for (int i=((int)startIndex+numNewItems)-1; i>=(int32)startIndex; i--) if (AddHead(queue[i]) == B_ERROR) return B_ERROR;
00563    return B_NO_ERROR;
00564 }
00565 
00566 template <class ItemType>
00567 status_t 
00568 Queue<ItemType>::
00569 AddHead(const ItemType * items, uint32 numItems)
00570 {
00571    if (EnsureSize(_itemCount+numItems) != B_NO_ERROR) return B_ERROR;
00572    for (int i=((int)numItems)-1; i>=0; i--) if (AddHead(items[i]) == B_ERROR) return B_ERROR;
00573    return B_NO_ERROR;
00574 }
00575 
00576 template <class ItemType>
00577 status_t 
00578 Queue<ItemType>::
00579 RemoveHead(ItemType & returnItem)
00580 {
00581    if (_itemCount == 0) return B_ERROR;
00582    returnItem = _queue[_headIndex];
00583    return RemoveHead();
00584 }
00585 
00586 template <class ItemType>
00587 status_t
00588 Queue<ItemType>::
00589 RemoveHead()
00590 {
00591    if (_itemCount == 0) return B_ERROR;
00592    int oldHeadIndex = _headIndex;
00593    _headIndex = NextIndex(_headIndex);
00594    _itemCount--;
00595    _queue[oldHeadIndex] = ItemType();  // this must be done last, as queue state must be coherent when we do this
00596    return B_NO_ERROR;
00597 }
00598 
00599 template <class ItemType>
00600 status_t 
00601 Queue<ItemType>::
00602 RemoveTail(ItemType & returnItem)
00603 {
00604    if (_itemCount == 0) return B_ERROR;
00605    returnItem = _queue[_tailIndex];
00606    return RemoveTail();
00607 }
00608 
00609 template <class ItemType>
00610 status_t 
00611 Queue<ItemType>::
00612 RemoveTail()
00613 {
00614    if (_itemCount == 0) return B_ERROR;
00615    int removedItemIndex = _tailIndex;
00616    _tailIndex = PrevIndex(_tailIndex);
00617    _itemCount--;
00618    _queue[removedItemIndex] = ItemType();  // this must be done last, as queue state must be coherent when we do this
00619    return B_NO_ERROR;
00620 }
00621 
00622 template <class ItemType>
00623 status_t
00624 Queue<ItemType>::
00625 GetItemAt(uint32 index, ItemType & returnItem) const
00626 {
00627    if (index >= _itemCount) return B_ERROR;
00628    returnItem = _queue[InternalizeIndex(index)];
00629    return B_NO_ERROR;
00630 }
00631 
00632 template <class ItemType>
00633 status_t 
00634 Queue<ItemType>::
00635 RemoveItemAt(uint32 index, ItemType & returnItem)
00636 {
00637    if (index >= _itemCount) return B_ERROR;
00638    returnItem = _queue[InternalizeIndex(index)];
00639    return RemoveItemAt(index);
00640 }
00641 
00642 template <class ItemType>
00643 status_t 
00644 Queue<ItemType>::
00645 RemoveItemAt(uint32 index)
00646 {
00647    if (index >= _itemCount) return B_ERROR;
00648 
00649    uint32 internalizedIndex = InternalizeIndex(index);
00650    uint32 indexToClear;
00651 
00652    if (index < _itemCount/2)
00653    {
00654       // item is closer to the head:  shift everything forward one, ending at the head
00655       while(internalizedIndex != _headIndex)
00656       {
00657          uint32 prev = PrevIndex(internalizedIndex);
00658          _queue[internalizedIndex] = _queue[prev];
00659          internalizedIndex = prev;
00660       }
00661       indexToClear = _headIndex;
00662       _headIndex = NextIndex(_headIndex); 
00663    }
00664    else
00665    {
00666       // item is closer to the tail:  shift everything back one, ending at the tail
00667       while(internalizedIndex != _tailIndex)
00668       {
00669          uint32 next = NextIndex(internalizedIndex);
00670          _queue[internalizedIndex] = _queue[next];
00671          internalizedIndex = next;
00672       }
00673       indexToClear = _tailIndex;
00674       _tailIndex = PrevIndex(_tailIndex); 
00675    }
00676 
00677    _itemCount--;
00678    _queue[indexToClear] = ItemType();  // this must be done last, as queue state must be coherent when we do this
00679    return B_NO_ERROR; 
00680 }
00681 
00682 template <class ItemType>
00683 status_t 
00684 Queue<ItemType>::
00685 ReplaceItemAt(uint32 index, const ItemType & newItem)
00686 {
00687    if (index >= _itemCount) return B_ERROR;
00688    _queue[InternalizeIndex(index)] = newItem;
00689    return B_NO_ERROR;
00690 }
00691 
00692 template <class ItemType>
00693 status_t 
00694 Queue<ItemType>::
00695 InsertItemAt(uint32 index, const ItemType & newItem)
00696 {
00697    // Simple cases
00698    if (index >  _itemCount) return B_ERROR;
00699    if (index == _itemCount) return AddTail(newItem);
00700    if (index == 0)          return AddHead(newItem);
00701 
00702    // Harder case:  inserting into the middle of the array
00703    if (index < _itemCount/2)
00704    {
00705       // Add a space at the front, and shift things back
00706       if (AddHead() != B_NO_ERROR) return B_ERROR;  // allocate an extra slot
00707       for (uint32 i=0; i<index; i++) ReplaceItemAt(i, *GetItemAt(i+1));
00708    }
00709    else
00710    {
00711       // Add a space at the rear, and shift things forward
00712       if (AddTail() != B_NO_ERROR) return B_ERROR;  // allocate an extra slot
00713       for (int32 i=((int32)_itemCount)-1; i>((int32)index); i--) ReplaceItemAt(i, *GetItemAt(i-1));
00714    }
00715    return ReplaceItemAt(index, newItem);
00716 }
00717 
00718 template <class ItemType>
00719 status_t 
00720 Queue<ItemType>::
00721 InsertItemsAt(uint32 index, const Queue<ItemType> & queue, uint32 startIndex, uint32 numNewItems)
00722 {
00723    uint32 hisSize = queue.GetNumItems();
00724    numNewItems = muscleMin(numNewItems, (startIndex < hisSize) ? (hisSize-startIndex) : 0);
00725    if (numNewItems == 0) return B_NO_ERROR;
00726    if (index > _itemCount) return B_ERROR;
00727    if (numNewItems == 1)
00728    {
00729       if (index == 0)          return AddHead(queue.Head());
00730       if (index == _itemCount) return AddTail(queue.Head());
00731    }
00732 
00733    uint32 oldSize = GetNumItems();
00734    uint32 newSize = oldSize+numNewItems;
00735 
00736    if (EnsureSize(newSize, true) != B_NO_ERROR) return B_ERROR;
00737    for (uint32 i=index; i<oldSize; i++)           (*this)[i+numNewItems] = (*this)[i];
00738    for (uint32 i=index; i<index+numNewItems; i++) (*this)[i]             = queue[startIndex++];
00739    return B_NO_ERROR;
00740 }
00741 
00742 template <class ItemType>
00743 status_t 
00744 Queue<ItemType>::
00745 InsertItemsAt(uint32 index, const ItemType * items, uint32 numNewItems)
00746 {
00747    if (numNewItems == 0) return B_NO_ERROR;
00748    if (index > _itemCount) return B_ERROR;
00749    if (numNewItems == 1)
00750    {
00751       if (index == 0)          return AddHead(*items);
00752       if (index == _itemCount) return AddTail(*items);
00753    }
00754 
00755    uint32 oldSize = GetNumItems();
00756    uint32 newSize = oldSize+numNewItems;
00757 
00758    if (EnsureSize(newSize, true) != B_NO_ERROR) return B_ERROR;
00759    int32 si = 0;
00760    for (uint32 i=index; i<oldSize; i++)           (*this)[i+numNewItems] = (*this)[i];
00761    for (uint32 i=index; i<index+numNewItems; i++) (*this)[i]             = items[si++];
00762    return B_NO_ERROR;
00763 }
00764 
00765 template <class ItemType>
00766 void 
00767 Queue<ItemType>::
00768 Clear(bool releaseCachedBuffers)
00769 {
00770    if ((releaseCachedBuffers)&&(_queue != _smallQueue))
00771    {
00772       delete [] _queue;
00773       _queue = NULL;
00774       _queueSize = 0;
00775       _itemCount = 0;
00776    }
00777    else while(RemoveTail() == B_NO_ERROR) {/* empty */}
00778 }
00779 
00780 template <class ItemType>
00781 status_t 
00782 Queue<ItemType>::
00783 EnsureSize(uint32 size, bool setNumItems, uint32 extraPreallocs)
00784 {
00785    if ((_queue == NULL)||(_queueSize < size))
00786    {
00787       const uint32 sqLen = ARRAYITEMS(_smallQueue);
00788       uint32 temp    = size + extraPreallocs;
00789       uint32 newQLen = muscleMax(_initialSize, ((setNumItems)||(temp <= sqLen)) ? muscleMax(sqLen,temp) : temp);
00790 
00791       ItemType * newQueue = ((_queue == _smallQueue)||(newQLen > sqLen)) ? newnothrow_array(ItemType,newQLen) : _smallQueue;
00792       if (newQueue == NULL) {WARN_OUT_OF_MEMORY; return B_ERROR;}
00793       if (newQueue == _smallQueue) newQLen = sqLen;
00794       
00795       for (uint32 i=0; i<_itemCount; i++) (void) GetItemAt(i, newQueue[i]);  // we know that (_itemCount < size)
00796       if (setNumItems) _itemCount = size;
00797       _headIndex = 0;
00798       _tailIndex = _itemCount-1;
00799 
00800       if (_queue == _smallQueue) 
00801       {
00802          ItemType blank = ItemType();
00803          for (uint32 i=0; i<sqLen; i++) _smallQueue[i] = blank;
00804       }
00805       else delete [] _queue;
00806 
00807       _queue = newQueue;
00808       _queueSize = newQLen;
00809    }
00810 
00811    if (setNumItems) 
00812    {
00813       // Force ourselves to contain exactly the required number of items
00814       if (_itemCount < size)
00815       {
00816          // We can do this quickly because the "new" items are already initialized properly
00817          _tailIndex = (_tailIndex + (size-_itemCount)) % _queueSize;
00818          _itemCount = size;
00819       }
00820       else while(_itemCount > size) (void) RemoveTail();  // Gotta overwrite the "removed" items, so this is a bit slower
00821    }
00822 
00823    return B_NO_ERROR;
00824 }
00825 
00826 template <class ItemType>
00827 int32 
00828 Queue<ItemType>::
00829 IndexOf(const ItemType & item) const
00830 {
00831    if (_queue) for (int i=((int)GetNumItems())-1; i>=0; i--) if (*GetItemAt(i) == item) return i;
00832    return -1;
00833 }
00834 
00835 
00836 template <class ItemType>
00837 void 
00838 Queue<ItemType>::
00839 Swap(uint32 fromIndex, uint32 toIndex) 
00840 {
00841    ItemType temp = *(GetItemAt(fromIndex));
00842    ReplaceItemAt(fromIndex, *(GetItemAt(toIndex)));
00843    ReplaceItemAt(toIndex,   temp);
00844 }
00845 
00846 template <class ItemType>
00847 void 
00848 Queue<ItemType>::
00849 Sort(ItemCompareFunc compareFunc, uint32 from, uint32 to, void * cookie) 
00850 { 
00851    uint32 size = GetNumItems();
00852    if (to > size) to = size;
00853    if (to > from)
00854    {
00855       if (to < from+12) 
00856       {
00857          // too easy, just do a bubble sort (base case)
00858          if (to > from+1) 
00859          {
00860             for (uint32 i=from+1; i<to; i++) 
00861             {
00862                for (uint32 j=i; j>from; j--) 
00863                {
00864                   int ret = compareFunc(*(GetItemAt(j)), *(GetItemAt(j-1)), cookie);
00865                   if (ret < 0) Swap(j, j-1); 
00866                           else break; 
00867                }
00868             } 
00869          } 
00870       }
00871       else
00872       {
00873          // Okay, do the real thing
00874          uint32 middle = (from + to)/2; 
00875          Sort(compareFunc, from, middle, cookie); 
00876          Sort(compareFunc, middle, to, cookie); 
00877          Merge(compareFunc, from, middle, to, middle-from, to-middle, cookie); 
00878       }
00879    }
00880 }
00881 
00882 template <class ItemType>
00883 void 
00884 Queue<ItemType>::
00885 ReverseItemOrdering(uint32 from, uint32 to) 
00886 {
00887    uint32 size = GetNumItems();
00888    if (size > 0)
00889    {
00890       to--;  // make it inclusive
00891       if (to >= size) to = size-1;
00892       while (from < to) Swap(from++, to--); 
00893    }
00894 } 
00895 
00896 template <class ItemType>
00897 status_t 
00898 Queue<ItemType>::
00899 RemoveFirstInstanceOf(const ItemType & val) 
00900 {
00901    uint32 ni = GetNumItems();
00902    for (uint32 i=0; i<ni; i++) if ((*this)[i] == val) return RemoveItemAt(i);
00903    return B_ERROR;
00904 }
00905 
00906 template <class ItemType>
00907 status_t 
00908 Queue<ItemType>::
00909 RemoveLastInstanceOf(const ItemType & val) 
00910 {
00911    for (int32 i=((int32)GetNumItems())-1; i>=0; i--) if ((*this)[i] == val) return RemoveItemAt(i);
00912    return B_ERROR;
00913 }
00914 
00915 template <class ItemType>
00916 uint32 
00917 Queue<ItemType>::
00918 RemoveAllInstancesOf(const ItemType & val) 
00919 {
00920    // Efficiently collapse all non-matching slots up to the top of the list
00921    uint32 ret      = 0;
00922    uint32 writeTo  = 0;
00923    uint32 origSize = GetNumItems();
00924    for(uint32 readFrom=0; readFrom<origSize; readFrom++)
00925    {
00926       const ItemType & nextRead = (*this)[readFrom];
00927       if (nextRead == val) ret++;
00928       else 
00929       {
00930          if (readFrom > writeTo) (*this)[writeTo] = nextRead;
00931          writeTo++;
00932       }
00933    }
00934 
00935    // Now get rid of any now-surplus slots
00936    for (; writeTo<origSize; writeTo++) RemoveTail();
00937 
00938    return ret;
00939 }
00940 
00941 template <class ItemType>
00942 void 
00943 Queue<ItemType>::
00944 Merge(ItemCompareFunc compareFunc, uint32 from, uint32 pivot, uint32 to, uint32 len1, uint32 len2, void * cookie) 
00945 {
00946    if ((len1)&&(len2))
00947    {
00948       if (len1+len2 == 2) 
00949       { 
00950          if (compareFunc(*(GetItemAt(pivot)), *(GetItemAt(from)), cookie) < 0) Swap(pivot, from); 
00951       } 
00952       else
00953       {
00954          uint32 first_cut, second_cut; 
00955          uint32 len11, len22; 
00956          if (len1 > len2) 
00957          { 
00958             len11      = len1/2; 
00959             first_cut  = from + len11; 
00960             second_cut = Lower(compareFunc, pivot, to, *GetItemAt(first_cut), cookie); 
00961             len22      = second_cut - pivot; 
00962          } 
00963          else 
00964          { 
00965             len22      = len2/2; 
00966             second_cut = pivot + len22; 
00967             first_cut  = Upper(compareFunc, from, pivot, *GetItemAt(second_cut), cookie); 
00968             len11      = first_cut - from; 
00969          } 
00970 
00971          // do a rotation
00972          if ((pivot!=first_cut)&&(pivot!=second_cut)) 
00973          {
00974             // find the greatest common denominator of (pivot-first_cut) and (second_cut-first_cut)
00975             uint32 n = pivot-first_cut;
00976             {
00977                uint32 m = second_cut-first_cut;
00978                while(n!=0) 
00979                {
00980                   uint32 t = m % n; 
00981                   m=n; 
00982                   n=t;
00983                } 
00984                n = m;
00985             }
00986 
00987             while(n--) 
00988             {
00989                const ItemType val = *GetItemAt(first_cut+n); 
00990                uint32 shift = pivot - first_cut; 
00991                uint32 p1 = first_cut+n;
00992                uint32 p2 = p1+shift; 
00993                while (p2 != first_cut + n) 
00994                { 
00995                   ReplaceItemAt(p1, *GetItemAt(p2));
00996                   p1 = p2; 
00997                   if (second_cut - p2 > shift) p2 += shift; 
00998                                           else p2  = first_cut + (shift - (second_cut - p2)); 
00999                } 
01000                ReplaceItemAt(p1, val);
01001             }
01002          }
01003 
01004          uint32 new_mid = first_cut+len22; 
01005          Merge(compareFunc, from,    first_cut,  new_mid, len11,        len22,        cookie); 
01006          Merge(compareFunc, new_mid, second_cut, to,      len1 - len11, len2 - len22, cookie); 
01007       }
01008    }
01009 }
01010 
01011 
01012 template <class ItemType>
01013 uint32 
01014 Queue<ItemType>::
01015 Lower(ItemCompareFunc compareFunc, uint32 from, uint32 to, const ItemType & val, void * cookie) const
01016 {
01017    if (to > from)
01018    {
01019       uint32 len = to - from;
01020       while (len > 0) 
01021       {
01022          uint32 half = len/2; 
01023          uint32 mid  = from + half; 
01024          if (compareFunc(*(GetItemAt(mid)), val, cookie) < 0) 
01025          {
01026             from = mid+1; 
01027             len  = len - half - 1; 
01028          } 
01029          else len = half; 
01030       }
01031    }
01032    return from; 
01033 } 
01034 
01035 template <class ItemType>
01036 uint32 
01037 Queue<ItemType>::
01038 Upper(ItemCompareFunc compareFunc, uint32 from, uint32 to, const ItemType & val, void * cookie) const 
01039 {
01040    if (to > from)
01041    {
01042       uint32 len = to - from;
01043       while (len > 0) 
01044       { 
01045          uint32 half = len/2; 
01046          uint32 mid  = from + half; 
01047          if (compareFunc(val, *(GetItemAt(mid)), cookie) < 0) len = half; 
01048          else 
01049          {
01050             from = mid+1; 
01051             len  = len - half -1; 
01052          } 
01053       } 
01054    }
01055    return from; 
01056 }
01057 
01058 template <class ItemType>
01059 const ItemType * 
01060 Queue<ItemType> :: GetArrayPointerAux(uint32 whichArray, uint32 & retLength) const
01061 {
01062    if (_itemCount > 0)
01063    {
01064       switch(whichArray)
01065       {
01066          case 0:  
01067             retLength = (_headIndex <= _tailIndex) ? (_tailIndex-_headIndex)+1 : (_queueSize-_headIndex);
01068             return &_queue[_headIndex];
01069          break;
01070 
01071          case 1:
01072             if (_headIndex > _tailIndex)
01073             {
01074                retLength = _tailIndex+1;
01075                return &_queue[0];
01076             }
01077          break;
01078       }
01079    }
01080    return NULL;
01081 }
01082 
01083 template <class ItemType>
01084 void
01085 Queue<ItemType>::SwapContents(Queue<ItemType> & that)
01086 {
01087    bool thisSmall = (_queue == _smallQueue);
01088    bool thatSmall = (that._queue == that._smallQueue);
01089 
01090    if ((thisSmall)&&(thatSmall))
01091    {
01092       // First, move any extra items from the longer queue to the shorter one...
01093       uint32 commonSize = muscleMin(GetNumItems(), that.GetNumItems());
01094       int32 sizeDiff    = ((int32)GetNumItems())-((int32)that.GetNumItems());
01095       Queue<ItemType> & copyTo   = (sizeDiff > 0) ? that : *this;
01096       Queue<ItemType> & copyFrom = (sizeDiff > 0) ? *this : that;
01097       (void) copyTo.AddTail(copyFrom, commonSize);   // guaranteed not to fail
01098       (void) copyFrom.EnsureSize(commonSize, true);  // remove the copied items from (copyFrom)
01099 
01100       // Then just swap the elements that are present in both arrays
01101       for (uint32 i=0; i<commonSize; i++) muscleSwap((*this)[i], that[i]);
01102    }
01103    else if (thisSmall) SwapContentsAux(that);
01104    else if (thatSmall) that.SwapContentsAux(*this);
01105    else
01106    {
01107       // this case is easy, we can just swizzle the pointers around
01108       muscleSwap(_queue,     that._queue);
01109       muscleSwap(_queueSize, that._queueSize);
01110       muscleSwap(_headIndex, that._headIndex);
01111       muscleSwap(_tailIndex, that._tailIndex);
01112       muscleSwap(_itemCount, that._itemCount);
01113    }
01114 }
01115 
01116 template <class ItemType>
01117 void
01118 Queue<ItemType>::SwapContentsAux(Queue<ItemType> & largeThat)
01119 {
01120    // First, copy over our (small) contents to his static buffer
01121    uint32 ni = GetNumItems();
01122    for (uint32 i=0; i<ni; i++) largeThat._smallQueue[i] = (*this)[i];
01123 
01124    // Now adopt his dynamic buffer
01125    _queue     = largeThat._queue;
01126    _queueSize = largeThat._queueSize;
01127    _headIndex = largeThat._headIndex;
01128    _tailIndex = largeThat._tailIndex;
01129    
01130    // And point him back at his static buffer
01131    if (ni > 0)
01132    {
01133       largeThat._queue     = largeThat._smallQueue;
01134       largeThat._queueSize = ARRAYITEMS(largeThat._smallQueue);
01135       largeThat._headIndex = 0;
01136       largeThat._tailIndex = ni-1;
01137    }
01138    else
01139    {
01140       largeThat._queue     = NULL;
01141       largeThat._queueSize = 0;
01142       // headIndex and tailIndex are undefined in this case anyway
01143    }
01144    
01145    muscleSwap(_itemCount, largeThat._itemCount);
01146 }
01147 
01148 template <class ItemType>
01149 bool
01150 Queue<ItemType>::StartsWith(const Queue<ItemType> & prefixQueue) const
01151 {
01152    if (prefixQueue.GetNumItems() > GetNumItems()) return false;
01153    uint32 prefixQueueLen = prefixQueue.GetNumItems();
01154    for (uint32 i=0; i<prefixQueueLen; i++) if (!(prefixQueue[i] == (*this)[i])) return false;
01155    return true;
01156 }
01157 
01158 template <class ItemType>
01159 bool
01160 Queue<ItemType>::EndsWith(const Queue<ItemType> & suffixQueue) const
01161 {
01162    if (suffixQueue.GetNumItems() > GetNumItems()) return false;
01163    int32 lastToCheck = GetNumItems()-suffixQueue.GetNumItems();
01164    for (int32 i=GetNumItems()-1; i>=lastToCheck; i--) if (!(suffixQueue[i] == (*this)[i])) return false;
01165    return true;
01166 }
01167 
01168 template <class ItemType>
01169 void
01170 Queue<ItemType>::Normalize()
01171 {
01172    if ((_itemCount > 0)&&(_headIndex > _tailIndex))
01173    {
01174       if (_itemCount*2 <= _queueSize)
01175       {
01176          // There's enough space in the middle of the
01177          // array to just copy the items over, yay!  This
01178          // is more efficient when there are just a few
01179          // valid items in a large array.
01180          uint32 startAt = _tailIndex+1;
01181          for (uint32 i=0; i<_itemCount; i++) 
01182          {
01183             ItemType & from = (*this)[i];
01184             _queue[startAt+i] = from;
01185             from = ItemType();  // clear the old slot to avoid leaving extra Refs, etc
01186          }
01187          _headIndex = startAt;
01188          _tailIndex = startAt+_itemCount-1; 
01189       }
01190       else
01191       {
01192          // There's not enough room to do a simple copy,
01193          // so we'll rotate the entire array using this
01194          // algorithm that was written by Paul Hsieh, taken
01195          // from http://www.azillionmonkeys.com/qed/case8.html
01196          uint32 c = 0;
01197          for (uint32 v = 0; c<_queueSize; v++)
01198          {
01199              uint32 t  = v;
01200              uint32 tp = v + _headIndex;
01201              ItemType tmp = _queue[v];
01202              c++;
01203              while(tp != v) 
01204              {
01205                  _queue[t] = _queue[tp];
01206                  t = tp;
01207                  tp += _headIndex;
01208                  if (tp >= _queueSize) tp -= _queueSize;
01209                  c++;
01210              }
01211              _queue[t] = tmp;
01212          }
01213          _headIndex = 0;
01214          _tailIndex = _itemCount-1;
01215       }
01216    }
01217 }
01218 
01219 END_NAMESPACE(muscle);
01220 
01221 #endif

Generated on Thu Jun 5 17:47:54 2008 for MUSCLE by  doxygen 1.5.1