/*
* CircularQueue.h
* created for Marathon: Aleph One
Copyright (C) 2002 and beyond by Woody Zenfell, III
and the "Aleph One" developers.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This license is contained in the file "COPYING",
which is included with this source code; it is available online at
http://www.gnu.org/licenses/gpl.html
* The code in this file is licensed to you under the GNU GPL. As the copyright holder,
* however, I reserve the right to use this code as I see fit, without being bound by the
* GPL's terms. This exemption is not intended to apply to modified versions of this file -
* if I were to use a modified version, I would be a licensee of whomever modified it, and
* thus must observe the GPL terms.
*
* Done a thousand times a thousand ways, this is another circular queue.
* Hope it's useful. (And correct.)
*
* Created by woody in February 2002.
*
* May 8, 2003 (Woody Zenfell): minor modifications; can now copy/assign queues.
*/
#ifndef CIRCULAR_QUEUE_H
#define CIRCULAR_QUEUE_H
template
class CircularQueue {
public:
CircularQueue() : mData(NULL) { reset(0); }
explicit CircularQueue(unsigned int inSize) : mData(NULL) { reset(inSize); }
// The queue being copied had best not change while we're copying...
CircularQueue(const CircularQueue& o) : mData(NULL) {
*this = o;
}
CircularQueue& operator =(const CircularQueue& o) {
if(&o != this)
{
reset(o.getTotalSpace());
for(unsigned int i = 0; i < o.getCountOfElements(); i++)
enqueue(o.mData[o.getReadIndex(i)]);
}
return *this;
}
void reset() { reset(getTotalSpace()); }
void reset(unsigned int inSize) {
// We need size+1 elements of storage to allow size elements in queue
unsigned int theStorageCount = inSize + 1;
// Guard against wrap-around
assert(theStorageCount > inSize);
mReadIndex = mWriteIndex = 0;
if(theStorageCount != mQueueSize || mData == NULL) {
mQueueSize = theStorageCount;
if(mData != NULL)
delete [] mData;
mData = new T[mQueueSize];
}
}
unsigned int getCountOfElements() const
{ return (mQueueSize > 0) ? (mQueueSize + mWriteIndex - mReadIndex) % mQueueSize : 0; }
unsigned int getRemainingSpace() const
{ return getTotalSpace() - getCountOfElements(); }
unsigned int getTotalSpace() const { return (mQueueSize > 0) ? mQueueSize - 1 : 0; }
const T& peek() const { return mData[getReadIndex()]; }
void dequeue(unsigned int inAmount = 1) { advanceReadIndex(inAmount); }
void enqueue(const T& inData) { mData[getWriteIndex()] = inData; advanceWriteIndex(); }
virtual ~CircularQueue() { if(mData != NULL) delete [] mData; }
protected:
unsigned int getReadIndex(unsigned int inOffset = 0) const
{ assert(getCountOfElements() > inOffset); return (mReadIndex + inOffset) % mQueueSize; }
unsigned int getWriteIndex(unsigned int inOffset = 0) const
{ assert(getRemainingSpace() > inOffset); return (mWriteIndex + inOffset) % mQueueSize; }
unsigned int advanceReadIndex(unsigned int inAmount = 1) {
if(inAmount > 0) {
assert(inAmount <= getCountOfElements());
mReadIndex = (mReadIndex + inAmount) % mQueueSize;
}
return mReadIndex;
}
unsigned int advanceWriteIndex(unsigned int inAmount = 1) {
if(inAmount > 0) {
assert(inAmount <= getRemainingSpace());
mWriteIndex = (mWriteIndex + inAmount) % mQueueSize;
}
return mWriteIndex;
}
unsigned int mReadIndex;
unsigned int mWriteIndex;
unsigned int mQueueSize;
T* mData;
};
#endif // CIRCULAR_QUEUE_H