/** * @file lllinkedqueue.h * @brief Declaration of linked queue classes. * * $LicenseInfo:firstyear=2003&license=viewergpl$ * * Copyright (c) 2003-2008, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #ifndef LL_LLLINKEDQUEUE_H #define LL_LLLINKEDQUEUE_H #include "llerror.h" // node that actually contains the data template class LLLinkedQueueNode { public: DATA_TYPE mData; LLLinkedQueueNode *mNextp; LLLinkedQueueNode *mPrevp; public: LLLinkedQueueNode(); LLLinkedQueueNode(const DATA_TYPE data); // destructor does not, by default, destroy associated data // however, the mDatap must be NULL to ensure that we aren't causing memory leaks ~LLLinkedQueueNode(); }; template class LLLinkedQueue { public: LLLinkedQueue(); // destructor destroys list and nodes, but not data in nodes ~LLLinkedQueue(); // Puts at end of FIFO void push(const DATA_TYPE data); // Takes off front of FIFO BOOL pop(DATA_TYPE &data); BOOL peek(DATA_TYPE &data); void reset(); S32 getLength() const; BOOL isEmpty() const; BOOL remove(const DATA_TYPE data); BOOL checkData(const DATA_TYPE data) const; private: // add node to end of list // set mCurrentp to mQueuep void addNodeAtEnd(LLLinkedQueueNode *nodep); private: LLLinkedQueueNode mHead; // head node LLLinkedQueueNode mTail; // tail node S32 mLength; }; // // Nodes // template LLLinkedQueueNode::LLLinkedQueueNode() : mData(), mNextp(NULL), mPrevp(NULL) { } template LLLinkedQueueNode::LLLinkedQueueNode(const DATA_TYPE data) : mData(data), mNextp(NULL), mPrevp(NULL) { } template LLLinkedQueueNode::~LLLinkedQueueNode() { } // // Queue itself // template LLLinkedQueue::LLLinkedQueue() : mHead(), mTail(), mLength(0) { } // destructor destroys list and nodes, but not data in nodes template LLLinkedQueue::~LLLinkedQueue() { reset(); } // put data into a node and stick it at the end of the list template void LLLinkedQueue::push(const DATA_TYPE data) { // make the new node LLLinkedQueueNode *nodep = new LLLinkedQueueNode(data); addNodeAtEnd(nodep); } // search the list starting at mHead.mNextp and remove the link with mDatap == data // set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data // return TRUE if found, FALSE if not found template BOOL LLLinkedQueue::remove(const DATA_TYPE data) { BOOL b_found = FALSE; LLLinkedQueueNode *currentp = mHead.mNextp; while (currentp) { if (currentp->mData == data) { b_found = TRUE; // if there is a next one, fix it if (currentp->mNextp) { currentp->mNextp->mPrevp = currentp->mPrevp; } else // we are at end of list { mTail.mPrevp = currentp->mPrevp; } // if there is a previous one, fix it if (currentp->mPrevp) { currentp->mPrevp->mNextp = currentp->mNextp; } else // we are at beginning of list { mHead.mNextp = currentp->mNextp; } // remove the node delete currentp; mLength--; break; } currentp = currentp->mNextp; } return b_found; } // remove all nodes from the list but do not delete associated data template void LLLinkedQueue::reset() { LLLinkedQueueNode *currentp; LLLinkedQueueNode *nextp; currentp = mHead.mNextp; while (currentp) { nextp = currentp->mNextp; delete currentp; currentp = nextp; } // reset mHead and mCurrentp mHead.mNextp = NULL; mTail.mPrevp = NULL; mLength = 0; } template S32 LLLinkedQueue::getLength() const { return mLength; } template BOOL LLLinkedQueue::isEmpty() const { return mLength <= 0; } // check to see if data is in list // set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep // return TRUE if found, FALSE if not found template BOOL LLLinkedQueue::checkData(const DATA_TYPE data) const { LLLinkedQueueNode *currentp = mHead.mNextp; while (currentp) { if (currentp->mData == data) { return TRUE; } currentp = currentp->mNextp; } return FALSE; } template BOOL LLLinkedQueue::pop(DATA_TYPE &data) { LLLinkedQueueNode *currentp; currentp = mHead.mNextp; if (!currentp) { return FALSE; } mHead.mNextp = currentp->mNextp; if (currentp->mNextp) { currentp->mNextp->mPrevp = currentp->mPrevp; } else { mTail.mPrevp = currentp->mPrevp; } data = currentp->mData; delete currentp; mLength--; return TRUE; } template BOOL LLLinkedQueue::peek(DATA_TYPE &data) { LLLinkedQueueNode *currentp; currentp = mHead.mNextp; if (!currentp) { return FALSE; } data = currentp->mData; return TRUE; } ////////////////////////////////////////////////////////////////////////////////////////// // private members ////////////////////////////////////////////////////////////////////////////////////////// // add node to end of list // set mCurrentp to mQueuep template void LLLinkedQueue::addNodeAtEnd(LLLinkedQueueNode *nodep) { // add the node to the end of the list nodep->mNextp = NULL; nodep->mPrevp = mTail.mPrevp; mTail.mPrevp = nodep; // if there's something in the list, fix its back pointer if (nodep->mPrevp) { nodep->mPrevp->mNextp = nodep; } else // otherwise fix the head node { mHead.mNextp = nodep; } mLength++; } #endif