/** * @file lllinkedqueue.h * @brief Declaration of linked queue classes. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/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