/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. 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 3 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. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #ifndef hsQueue_Defined #define hsQueue_Defined #include "hsTypes.h" template class hsQueue { private: int fArraySize; T *fArray; int fHead; // Index of first element in the queue int fTail; // Index of next free spot in the queue int fLook; // Index of look pointer hsBool fFull; // Is queue full? hsBool fEmpty; // Is queue empty? void Inc(int *index); int Inc(int index); void Dec(int *index); int Dec(int index); public: hsQueue( int size ); ~hsQueue(); hsBool Append(const T &newTail); // Add to end of line hsBool Remove(const T &someElement); // Find and remove element in the line hsBool Pop(T *headElement); // Remove and return the head of the line hsBool StartLook(T *headElement); // Return the head of the line w/out removing it hsBool NextLook(T *nextElement); // Return the head of the line w/out removing it hsBool IsEmpty(void) { return fEmpty; } hsBool IsFull(void) { return fFull; } }; // // Constructor // Allocate array, init head/tail indices // template hsQueue::hsQueue( int size ) { fArraySize = size; fArray = TRACKED_NEW T[ size ]; fHead = -1; fTail = -1; fLook = -1; fEmpty = true; fFull = false; } // // Destructor. free array // template hsQueue::~hsQueue() { delete [] fArray; } // // Wrap index on increment // template void hsQueue::Inc( int *index ) { (*index) ++; if ((*index) == fArraySize) { *index = 0; } } // // Wrap index on increment // template int hsQueue::Inc( int index ) { (index) ++; if ((index) == fArraySize) { index = 0; } return index; } // // Wrap index on decrement // template void hsQueue::Dec( int *index ) { (*index) --; if ((*index) < 0) { *index = fArraySize-1; } } // // Wrap index on decrement // template int hsQueue::Dec( int index ) { (index) --; if ((index) < 0) { index = fArraySize-1; } return index; } // // Add copy of item to the array. // template hsBool hsQueue::Append(const T &thing) { if (fHead == -1 && fTail == -1) { // init case fHead = 0; fTail = 0; } if (fFull) { // Queue is full return false; } if ( (fHead<0 || fHead>=fArraySize) ) { hsIfDebugMessage( (fHead<0 || fHead>=fArraySize), "Append: Illegal head pointer", fHead); } hsIfDebugMessage( (fTail<0 || fTail>=fArraySize), "Append: Illegal tail pointer", fTail); // Copy fArray[fTail] = thing; fEmpty = false; // increment tail pointer Inc(&fTail); if (fTail == fHead) { fFull = true; } return true; } // // Get a copy of the head of the array // template hsBool hsQueue::Pop(T *thing) { if (fEmpty) { return false; } hsIfDebugMessage( (fHead<0 || fHead>=fArraySize), "Pop: Illegal head pointer", fHead); hsIfDebugMessage( (fTail<0 || fTail>=fArraySize), "Pop: Illegal tail pointer", fTail); // Copy *thing = fArray[fHead]; fFull = false; // Increment head pointer Inc(&fHead); if (fHead == fTail) { fEmpty = true; } return true; } // // Remove item from list // template hsBool hsQueue::Remove(const T &thing) { if (fEmpty) { return false; } hsIfDebugMessage( (fHead<0 || fHead>=fArraySize), "Remove: Illegal head pointer", fHead); hsIfDebugMessage( (fTail<0 || fTail>=fArraySize), "Remove: Illegal tail pointer", fTail); // loop through list, find item int i = fHead; do { if (fArray[i] == thing) { // Found it - now remove it by sliding everything down 1 int j=Inc(i); while(j!= fTail) { if (fLook==j) Dec(&fLook); fArray[Dec(j)] = fArray[j]; Inc(&j); } if (fLook==fTail) Dec(&fLook); Dec(&fTail); if (fTail == fHead) { fEmpty = true; } return true; } Inc(&i); if (i==fTail) { return false; } } while(true); } // // Return pointer to first item in list, without popping it. // Return false if nothing there. // template hsBool hsQueue::StartLook(T *thing) { if (fEmpty) { return false; } hsIfDebugMessage( (fHead<0 || fHead>=fArraySize), "StartLook: Illegal head pointer", fHead); hsIfDebugMessage( (fTail<0 || fTail>=fArraySize), "StartLook: Illegal tail pointer", fTail); fLook = fHead; *thing = fArray[fLook]; // inc look pointer Inc(&fLook); // success return true; } // // Return pointer to next item in list, without popping it. Doesn't change head or tail. // Should be called immediately after StartLook. // Return false when at end of list. // template hsBool hsQueue::NextLook(T *thing) { if (fEmpty || fLook == fTail) { return false; } hsAssert(fLook != -1, "Must call StartLook first\n"); hsIfDebugMessage( (fHead<0 || fHead>=fArraySize), "NextLook: Illegal head pointer", fHead); hsIfDebugMessage( (fTail<0 || fTail>=fArraySize), "NextLook: Illegal tail pointer", fTail); // Return copy of item without removing it *thing = fArray[fLook]; Inc(&fLook); return true; } ///////////////////////////////////////////////////////////////////////////////////////// // // Code for threaded message queues - move to another file // #ifdef MQUEUE #include "hsThread.h" #if HS_BUILD_FOR_UNIX #include #endif class hsListQue { public: struct Elem { Elem* fNext; }; private: Elem* fHead; Elem* fTail; int fCount; public: hsListQue(); virtual ~hsListQue(); virtual int Count(); virtual void Enqueue(Elem* newItem); virtual Elem* Dequeue(); }; class hsMutexQueue : public hsListQue { hsMutex fMutex; public: hsMutexQueue() {} virtual int Count(); virtual void Enqueue(Elem* newItem); virtual Elem* Dequeue(); // will return nil if the queue is empty }; class hsSemaphoreQueue : public hsMutexQueue { hsSemaphore fSema; public: hsSemaphoreQueue() {} virtual void Enqueue(Elem* newItem); virtual Elem* Dequeue(); // never returns nil, it just waits }; class hsMsgQueue { int fMaxSize; #if HS_BUILD_FOR_UNIX mqd_t fMQ; #else class hsPrivateMQ* fMQ; UInt32 fAccess; #endif public: enum { kRead = 0x0001, kWrite = 0x0002, kBlock = 0x0004 }; hsMsgQueue(); virtual ~hsMsgQueue(); hsBool Create(const char name[], int maxSize, UInt32 access); hsBool Open(const char name[], UInt32 access); void Close(); int GetMaxSize() const { return fMaxSize; } hsBool Send(const void* data, int size = 0); int Receive(void* data); // returns actual size or 0 static void Delete(const char name[]); }; #endif // MQUEUE #endif