944 lines
22 KiB
C++
944 lines
22 KiB
C++
/**
|
|
* @file linked_lists.h
|
|
* @brief LLLinkedList class header amd implementation file.
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
|
*
|
|
* Copyright (c) 2001-2009, 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_LINKED_LISTS_H
|
|
#define LL_LINKED_LISTS_H
|
|
|
|
/**
|
|
* Provides a standard doubly linked list for fun and profit
|
|
* Utilizes a neat trick off of Flipcode where the back pointer is a
|
|
* pointer to a pointer, allowing easier transfer of nodes between lists, &c
|
|
* And a template class, of course
|
|
*/
|
|
|
|
#include "llerror.h"
|
|
|
|
|
|
template <class DATA_TYPE> class LLLinkedList
|
|
{
|
|
public:
|
|
friend class LLLinkNode;
|
|
// External interface
|
|
|
|
// basic constructor
|
|
LLLinkedList() : mHead(NULL), mCurrentp(NULL), mInsertBefore(NULL)
|
|
{
|
|
mCurrentp = mHead.mNextp;
|
|
mCurrentOperatingp = mHead.mNextp;
|
|
mCount = 0;
|
|
}
|
|
|
|
// basic constructor
|
|
LLLinkedList(BOOL (*insert_before)(DATA_TYPE *data_new, DATA_TYPE *data_tested)) : mHead(NULL), mCurrentp(NULL), mInsertBefore(insert_before)
|
|
{
|
|
mCurrentp = mHead.mNextp;
|
|
mCurrentOperatingp = mHead.mNextp;
|
|
mCount = 0;
|
|
}
|
|
|
|
// destructor destroys list and nodes, but not data in nodes
|
|
~LLLinkedList()
|
|
{
|
|
removeAllNodes();
|
|
}
|
|
|
|
// set mInsertBefore
|
|
void setInsertBefore(BOOL (*insert_before)(DATA_TYPE *data_new, DATA_TYPE *data_tested))
|
|
{
|
|
mInsertBefore = insert_before;
|
|
}
|
|
|
|
//
|
|
// WARNING!!!!!!!
|
|
// addData and addDataSorted are NOT O(1) operations, but O(n) because they check
|
|
// for existence of the data in the linked list first. Why, I don't know - djs
|
|
// If you don't care about dupes, use addDataNoCheck
|
|
//
|
|
|
|
// put data into a node and stick it at the front of the list
|
|
inline BOOL addData(DATA_TYPE *data);
|
|
|
|
// put data into a node and sort into list by mInsertBefore()
|
|
// calls normal add if mInsertBefore isn't set
|
|
inline BOOL addDataSorted(DATA_TYPE *data);
|
|
|
|
inline BOOL addDataNoCheck(DATA_TYPE *data);
|
|
|
|
// bubbleSortList
|
|
// does an improved bubble sort of the list . . . works best with almost sorted data
|
|
// does nothing if mInsertBefore isn't set
|
|
// Nota Bene: Swaps are accomplished by swapping data pointers
|
|
inline void bubbleSortList();
|
|
|
|
// put data into a node and stick it at the end of the list
|
|
inline BOOL addDataAtEnd(DATA_TYPE *data);
|
|
|
|
// returns number of items in the list
|
|
inline S32 getLength() const;
|
|
|
|
inline BOOL isEmpty();
|
|
|
|
// search the list starting at mHead.mNextp and remove the link with mDatap == data
|
|
// leave mCurrentp and mCurrentOperatingp on the next entry
|
|
// return TRUE if found, FALSE if not found
|
|
inline BOOL removeData(DATA_TYPE *data);
|
|
|
|
// search the list starting at mHead.mNextp and delete the link with mDatap == data
|
|
// leave mCurrentp and mCurrentOperatingp on the next entry
|
|
// return TRUE if found, FALSE if not found
|
|
inline BOOL deleteData(DATA_TYPE *data);
|
|
|
|
// remove all nodes from the list and delete the associated data
|
|
inline void deleteAllData();
|
|
|
|
// remove all nodes from the list but do not delete data
|
|
inline void removeAllNodes();
|
|
|
|
// check to see if data is in list
|
|
// if TRUE then mCurrentp and mCurrentOperatingp point to data
|
|
inline BOOL checkData(DATA_TYPE *data);
|
|
|
|
// place mCurrentp on first node
|
|
inline void resetList();
|
|
|
|
// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
|
|
inline DATA_TYPE *getCurrentData();
|
|
|
|
// same as getCurrentData() but a more intuitive name for the operation
|
|
inline DATA_TYPE *getNextData();
|
|
|
|
// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
|
|
inline DATA_TYPE *getFirstData();
|
|
|
|
// reset the list and return the data at position n, set mCurentOperatingp to that node and bump mCurrentp
|
|
// Note: n is zero-based
|
|
inline DATA_TYPE *getNthData( U32 n);
|
|
|
|
// reset the list and return the last data in it, set mCurentOperatingp to that node and bump mCurrentp
|
|
inline DATA_TYPE *getLastData();
|
|
|
|
// remove the Node at mCurentOperatingp
|
|
// leave mCurrentp and mCurentOperatingp on the next entry
|
|
inline void removeCurrentData();
|
|
|
|
// remove the Node at mCurentOperatingp and add it to newlist
|
|
// leave mCurrentp and mCurentOperatingp on the next entry
|
|
void moveCurrentData(LLLinkedList *newlist, BOOL b_sort);
|
|
|
|
BOOL moveData(DATA_TYPE *data, LLLinkedList *newlist, BOOL b_sort);
|
|
|
|
// delete the Node at mCurentOperatingp
|
|
// leave mCurrentp anf mCurentOperatingp on the next entry
|
|
void deleteCurrentData();
|
|
|
|
private:
|
|
// node that actually contains the data
|
|
class LLLinkNode
|
|
{
|
|
public:
|
|
// assign the mDatap pointer
|
|
LLLinkNode(DATA_TYPE *data) : mDatap(data), mNextp(NULL), mPrevpp(NULL)
|
|
{
|
|
}
|
|
|
|
// destructor does not, by default, destroy associated data
|
|
// however, the mDatap must be NULL to ensure that we aren't causing memory leaks
|
|
~LLLinkNode()
|
|
{
|
|
if (mDatap)
|
|
{
|
|
llerror("Attempting to call LLLinkNode destructor with a non-null mDatap!", 1);
|
|
}
|
|
}
|
|
|
|
// delete associated data and NULL out pointer
|
|
void deleteData()
|
|
{
|
|
delete mDatap;
|
|
mDatap = NULL;
|
|
}
|
|
|
|
// NULL out pointer
|
|
void removeData()
|
|
{
|
|
mDatap = NULL;
|
|
}
|
|
|
|
DATA_TYPE *mDatap;
|
|
LLLinkNode *mNextp;
|
|
LLLinkNode **mPrevpp;
|
|
};
|
|
|
|
// add a node at the front of the list
|
|
void addData(LLLinkNode *node)
|
|
{
|
|
// don't allow NULL to be passed to addData
|
|
if (!node)
|
|
{
|
|
llerror("NULL pointer passed to LLLinkedList::addData", 0);
|
|
}
|
|
|
|
// add the node to the front of the list
|
|
node->mPrevpp = &mHead.mNextp;
|
|
node->mNextp = mHead.mNextp;
|
|
|
|
// if there's something in the list, fix its back pointer
|
|
if (node->mNextp)
|
|
{
|
|
node->mNextp->mPrevpp = &node->mNextp;
|
|
}
|
|
|
|
mHead.mNextp = node;
|
|
}
|
|
|
|
LLLinkNode mHead; // fake head node. . . makes pointer operations faster and easier
|
|
LLLinkNode *mCurrentp; // mCurrentp is the Node that getCurrentData returns
|
|
LLLinkNode *mCurrentOperatingp; // this is the node that the various mumbleCurrentData functions act on
|
|
BOOL (*mInsertBefore)(DATA_TYPE *data_new, DATA_TYPE *data_tested); // user function set to allow sorted lists
|
|
U32 mCount;
|
|
};
|
|
|
|
template <class DATA_TYPE>
|
|
BOOL LLLinkedList<DATA_TYPE>::addData(DATA_TYPE *data)
|
|
{
|
|
// don't allow NULL to be passed to addData
|
|
if (!data)
|
|
{
|
|
llerror("NULL pointer passed to LLLinkedList::addData", 0);
|
|
}
|
|
|
|
LLLinkNode *tcurr = mCurrentp;
|
|
LLLinkNode *tcurrop = mCurrentOperatingp;
|
|
|
|
if ( checkData(data))
|
|
{
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
return FALSE;
|
|
}
|
|
|
|
// make the new node
|
|
LLLinkNode *temp = new LLLinkNode(data);
|
|
|
|
// add the node to the front of the list
|
|
temp->mPrevpp = &mHead.mNextp;
|
|
temp->mNextp = mHead.mNextp;
|
|
|
|
// if there's something in the list, fix its back pointer
|
|
if (temp->mNextp)
|
|
{
|
|
temp->mNextp->mPrevpp = &temp->mNextp;
|
|
}
|
|
|
|
mHead.mNextp = temp;
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
mCount++;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
template <class DATA_TYPE>
|
|
BOOL LLLinkedList<DATA_TYPE>::addDataNoCheck(DATA_TYPE *data)
|
|
{
|
|
// don't allow NULL to be passed to addData
|
|
if (!data)
|
|
{
|
|
llerror("NULL pointer passed to LLLinkedList::addData", 0);
|
|
}
|
|
|
|
LLLinkNode *tcurr = mCurrentp;
|
|
LLLinkNode *tcurrop = mCurrentOperatingp;
|
|
|
|
// make the new node
|
|
LLLinkNode *temp = new LLLinkNode(data);
|
|
|
|
// add the node to the front of the list
|
|
temp->mPrevpp = &mHead.mNextp;
|
|
temp->mNextp = mHead.mNextp;
|
|
|
|
// if there's something in the list, fix its back pointer
|
|
if (temp->mNextp)
|
|
{
|
|
temp->mNextp->mPrevpp = &temp->mNextp;
|
|
}
|
|
|
|
mHead.mNextp = temp;
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
mCount++;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
template <class DATA_TYPE>
|
|
BOOL LLLinkedList<DATA_TYPE>::addDataSorted(DATA_TYPE *data)
|
|
{
|
|
LLLinkNode *tcurr = mCurrentp;
|
|
LLLinkNode *tcurrop = mCurrentOperatingp;
|
|
// don't allow NULL to be passed to addData
|
|
if (!data)
|
|
{
|
|
llerror("NULL pointer passed to LLLinkedList::addDataSorted", 0);
|
|
}
|
|
|
|
if (checkData(data))
|
|
{
|
|
// restore
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
return FALSE;
|
|
}
|
|
|
|
// mInsertBefore not set?
|
|
if (!mInsertBefore)
|
|
{
|
|
addData(data);
|
|
// restore
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
return FALSE;
|
|
}
|
|
|
|
// empty list?
|
|
if (!mHead.mNextp)
|
|
{
|
|
addData(data);
|
|
// restore
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
return TRUE;
|
|
}
|
|
|
|
// make the new node
|
|
LLLinkNode *temp = new LLLinkNode(data);
|
|
|
|
// walk the list until mInsertBefore returns true
|
|
mCurrentp = mHead.mNextp;
|
|
while (mCurrentp->mNextp)
|
|
{
|
|
if (mInsertBefore(data, mCurrentp->mDatap))
|
|
{
|
|
// insert before the current one
|
|
temp->mPrevpp = mCurrentp->mPrevpp;
|
|
temp->mNextp = mCurrentp;
|
|
*(temp->mPrevpp) = temp;
|
|
mCurrentp->mPrevpp = &temp->mNextp;
|
|
// restore
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
mCount++;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
mCurrentp = mCurrentp->mNextp;
|
|
}
|
|
}
|
|
|
|
// on the last element, add before?
|
|
if (mInsertBefore(data, mCurrentp->mDatap))
|
|
{
|
|
// insert before the current one
|
|
temp->mPrevpp = mCurrentp->mPrevpp;
|
|
temp->mNextp = mCurrentp;
|
|
*(temp->mPrevpp) = temp;
|
|
mCurrentp->mPrevpp = &temp->mNextp;
|
|
// restore
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
}
|
|
else // insert after
|
|
{
|
|
temp->mPrevpp = &mCurrentp->mNextp;
|
|
temp->mNextp = NULL;
|
|
mCurrentp->mNextp = temp;
|
|
|
|
// restore
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
}
|
|
mCount++;
|
|
return TRUE;
|
|
}
|
|
|
|
template <class DATA_TYPE>
|
|
void LLLinkedList<DATA_TYPE>::bubbleSortList()
|
|
{
|
|
// mInsertBefore not set
|
|
if (!mInsertBefore)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLLinkNode *tcurr = mCurrentp;
|
|
LLLinkNode *tcurrop = mCurrentOperatingp;
|
|
|
|
BOOL b_swapped = FALSE;
|
|
DATA_TYPE *temp;
|
|
|
|
// Nota Bene: This will break if more than 0x7FFFFFFF members in list!
|
|
S32 length = 0x7FFFFFFF;
|
|
S32 count = 0;
|
|
do
|
|
{
|
|
b_swapped = FALSE;
|
|
mCurrentp = mHead.mNextp;
|
|
count = 0;
|
|
while ( (count + 1 < length)
|
|
&&(mCurrentp))
|
|
{
|
|
if (mCurrentp->mNextp)
|
|
{
|
|
if (!mInsertBefore(mCurrentp->mDatap, mCurrentp->mNextp->mDatap))
|
|
{
|
|
// swap data pointers!
|
|
temp = mCurrentp->mDatap;
|
|
mCurrentp->mDatap = mCurrentp->mNextp->mDatap;
|
|
mCurrentp->mNextp->mDatap = temp;
|
|
b_swapped = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
count++;
|
|
mCurrentp = mCurrentp->mNextp;
|
|
}
|
|
length = count;
|
|
} while (b_swapped);
|
|
|
|
// restore
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
}
|
|
|
|
|
|
template <class DATA_TYPE>
|
|
BOOL LLLinkedList<DATA_TYPE>::addDataAtEnd(DATA_TYPE *data)
|
|
{
|
|
LLLinkNode *tcurr = mCurrentp;
|
|
LLLinkNode *tcurrop = mCurrentOperatingp;
|
|
|
|
// don't allow NULL to be passed to addData
|
|
if (!data)
|
|
{
|
|
llerror("NULL pointer passed to LLLinkedList::addData", 0);
|
|
}
|
|
|
|
if (checkData(data))
|
|
{
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
return FALSE;
|
|
}
|
|
|
|
// make the new node
|
|
LLLinkNode *temp = new LLLinkNode(data);
|
|
|
|
// add the node to the end of the list
|
|
|
|
// if empty, add to the front and be done with it
|
|
if (!mHead.mNextp)
|
|
{
|
|
temp->mPrevpp = &mHead.mNextp;
|
|
temp->mNextp = NULL;
|
|
mHead.mNextp = temp;
|
|
}
|
|
else
|
|
{
|
|
// otherwise, walk to the end of the list
|
|
mCurrentp = mHead.mNextp;
|
|
while (mCurrentp->mNextp)
|
|
{
|
|
mCurrentp = mCurrentp->mNextp;
|
|
}
|
|
temp->mPrevpp = &mCurrentp->mNextp;
|
|
temp->mNextp = NULL;
|
|
mCurrentp->mNextp = temp;
|
|
}
|
|
|
|
// restore
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
mCount++;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// returns number of items in the list
|
|
template <class DATA_TYPE>
|
|
S32 LLLinkedList<DATA_TYPE>::getLength() const
|
|
{
|
|
// S32 length = 0;
|
|
// for (LLLinkNode* temp = mHead.mNextp; temp != NULL; temp = temp->mNextp)
|
|
// {
|
|
// length++;
|
|
// }
|
|
return mCount;
|
|
}
|
|
|
|
|
|
template <class DATA_TYPE>
|
|
BOOL LLLinkedList<DATA_TYPE>::isEmpty()
|
|
{
|
|
return (mCount == 0);
|
|
}
|
|
|
|
|
|
// search the list starting at mHead.mNextp and remove the link with mDatap == data
|
|
// leave mCurrentp and mCurrentOperatingp on the next entry
|
|
// return TRUE if found, FALSE if not found
|
|
template <class DATA_TYPE>
|
|
BOOL LLLinkedList<DATA_TYPE>::removeData(DATA_TYPE *data)
|
|
{
|
|
BOOL b_found = FALSE;
|
|
// don't allow NULL to be passed to addData
|
|
if (!data)
|
|
{
|
|
llerror("NULL pointer passed to LLLinkedList::removeData", 0);
|
|
}
|
|
|
|
LLLinkNode *tcurr = mCurrentp;
|
|
LLLinkNode *tcurrop = mCurrentOperatingp;
|
|
|
|
mCurrentp = mHead.mNextp;
|
|
mCurrentOperatingp = mHead.mNextp;
|
|
|
|
while (mCurrentOperatingp)
|
|
{
|
|
if (mCurrentOperatingp->mDatap == data)
|
|
{
|
|
b_found = TRUE;
|
|
|
|
// remove the node
|
|
|
|
// if there is a next one, fix it
|
|
if (mCurrentOperatingp->mNextp)
|
|
{
|
|
mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
|
|
}
|
|
*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
|
|
|
|
// remove the LLLinkNode
|
|
|
|
// if we were on the one we want to delete, bump the cached copies
|
|
if (mCurrentOperatingp == tcurrop)
|
|
{
|
|
tcurrop = tcurr = mCurrentOperatingp->mNextp;
|
|
}
|
|
else if (mCurrentOperatingp == tcurr)
|
|
{
|
|
tcurrop = tcurr = mCurrentOperatingp->mNextp;
|
|
}
|
|
|
|
mCurrentp = mCurrentOperatingp->mNextp;
|
|
|
|
mCurrentOperatingp->removeData();
|
|
delete mCurrentOperatingp;
|
|
mCurrentOperatingp = mCurrentp;
|
|
mCount--;
|
|
break;
|
|
}
|
|
mCurrentOperatingp = mCurrentOperatingp->mNextp;
|
|
}
|
|
// restore
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
return b_found;
|
|
}
|
|
|
|
// search the list starting at mHead.mNextp and delete the link with mDatap == data
|
|
// leave mCurrentp and mCurrentOperatingp on the next entry
|
|
// return TRUE if found, FALSE if not found
|
|
template <class DATA_TYPE>
|
|
BOOL LLLinkedList<DATA_TYPE>::deleteData(DATA_TYPE *data)
|
|
{
|
|
BOOL b_found = FALSE;
|
|
// don't allow NULL to be passed to addData
|
|
if (!data)
|
|
{
|
|
llerror("NULL pointer passed to LLLinkedList::removeData", 0);
|
|
}
|
|
|
|
LLLinkNode *tcurr = mCurrentp;
|
|
LLLinkNode *tcurrop = mCurrentOperatingp;
|
|
|
|
mCurrentp = mHead.mNextp;
|
|
mCurrentOperatingp = mHead.mNextp;
|
|
|
|
while (mCurrentOperatingp)
|
|
{
|
|
if (mCurrentOperatingp->mDatap == data)
|
|
{
|
|
b_found = TRUE;
|
|
|
|
// remove the node
|
|
// if there is a next one, fix it
|
|
if (mCurrentOperatingp->mNextp)
|
|
{
|
|
mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
|
|
}
|
|
*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
|
|
|
|
// delete the LLLinkNode
|
|
// if we were on the one we want to delete, bump the cached copies
|
|
if (mCurrentOperatingp == tcurrop)
|
|
{
|
|
tcurrop = tcurr = mCurrentOperatingp->mNextp;
|
|
}
|
|
|
|
// and delete the associated data
|
|
llassert(mCurrentOperatingp);
|
|
mCurrentp = mCurrentOperatingp->mNextp;
|
|
mCurrentOperatingp->deleteData();
|
|
delete mCurrentOperatingp;
|
|
mCurrentOperatingp = mCurrentp;
|
|
mCount--;
|
|
break;
|
|
}
|
|
mCurrentOperatingp = mCurrentOperatingp->mNextp;
|
|
}
|
|
// restore
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
return b_found;
|
|
}
|
|
|
|
// remove all nodes from the list and delete the associated data
|
|
template <class DATA_TYPE>
|
|
void LLLinkedList<DATA_TYPE>::deleteAllData()
|
|
{
|
|
LLLinkNode *temp;
|
|
// reset mCurrentp
|
|
mCurrentp = mHead.mNextp;
|
|
|
|
while (mCurrentp)
|
|
{
|
|
temp = mCurrentp->mNextp;
|
|
mCurrentp->deleteData();
|
|
delete mCurrentp;
|
|
mCurrentp = temp;
|
|
}
|
|
|
|
// reset mHead and mCurrentp
|
|
mHead.mNextp = NULL;
|
|
mCurrentp = mHead.mNextp;
|
|
mCurrentOperatingp = mHead.mNextp;
|
|
mCount = 0;
|
|
}
|
|
|
|
// remove all nodes from the list but do not delete data
|
|
template <class DATA_TYPE>
|
|
void LLLinkedList<DATA_TYPE>::removeAllNodes()
|
|
{
|
|
LLLinkNode *temp;
|
|
// reset mCurrentp
|
|
mCurrentp = mHead.mNextp;
|
|
|
|
while (mCurrentp)
|
|
{
|
|
temp = mCurrentp->mNextp;
|
|
mCurrentp->removeData();
|
|
delete mCurrentp;
|
|
mCurrentp = temp;
|
|
}
|
|
|
|
// reset mHead and mCurrentp
|
|
mHead.mNextp = NULL;
|
|
mCurrentp = mHead.mNextp;
|
|
mCurrentOperatingp = mHead.mNextp;
|
|
mCount = 0;
|
|
}
|
|
|
|
// check to see if data is in list
|
|
// if TRUE then mCurrentp and mCurrentOperatingp point to data
|
|
template <class DATA_TYPE>
|
|
BOOL LLLinkedList<DATA_TYPE>::checkData(DATA_TYPE *data)
|
|
{
|
|
// reset mCurrentp
|
|
mCurrentp = mHead.mNextp;
|
|
|
|
while (mCurrentp)
|
|
{
|
|
if (mCurrentp->mDatap == data)
|
|
{
|
|
mCurrentOperatingp = mCurrentp;
|
|
return TRUE;
|
|
}
|
|
mCurrentp = mCurrentp->mNextp;
|
|
}
|
|
mCurrentOperatingp = mCurrentp;
|
|
return FALSE;
|
|
}
|
|
|
|
// place mCurrentp on first node
|
|
template <class DATA_TYPE>
|
|
void LLLinkedList<DATA_TYPE>::resetList()
|
|
{
|
|
mCurrentp = mHead.mNextp;
|
|
mCurrentOperatingp = mHead.mNextp;
|
|
}
|
|
|
|
// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
|
|
template <class DATA_TYPE>
|
|
DATA_TYPE *LLLinkedList<DATA_TYPE>::getCurrentData()
|
|
{
|
|
if (mCurrentp)
|
|
{
|
|
mCurrentOperatingp = mCurrentp;
|
|
mCurrentp = mCurrentp->mNextp;
|
|
return mCurrentOperatingp->mDatap;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// same as getCurrentData() but a more intuitive name for the operation
|
|
template <class DATA_TYPE>
|
|
DATA_TYPE *LLLinkedList<DATA_TYPE>::getNextData()
|
|
{
|
|
if (mCurrentp)
|
|
{
|
|
mCurrentOperatingp = mCurrentp;
|
|
mCurrentp = mCurrentp->mNextp;
|
|
return mCurrentOperatingp->mDatap;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
|
|
template <class DATA_TYPE>
|
|
DATA_TYPE *LLLinkedList<DATA_TYPE>::getFirstData()
|
|
{
|
|
mCurrentp = mHead.mNextp;
|
|
mCurrentOperatingp = mHead.mNextp;
|
|
if (mCurrentp)
|
|
{
|
|
mCurrentOperatingp = mCurrentp;
|
|
mCurrentp = mCurrentp->mNextp;
|
|
return mCurrentOperatingp->mDatap;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Note: n is zero-based
|
|
template <class DATA_TYPE>
|
|
DATA_TYPE *LLLinkedList<DATA_TYPE>::getNthData( U32 n )
|
|
{
|
|
mCurrentOperatingp = mHead.mNextp;
|
|
|
|
// if empty, return NULL
|
|
if (!mCurrentOperatingp)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for( U32 i = 0; i < n; i++ )
|
|
{
|
|
mCurrentOperatingp = mCurrentOperatingp->mNextp;
|
|
if( !mCurrentOperatingp )
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
mCurrentp = mCurrentOperatingp->mNextp;
|
|
return mCurrentOperatingp->mDatap;
|
|
}
|
|
|
|
|
|
// reset the list and return the last data in it, set mCurentOperatingp to that node and bump mCurrentp
|
|
template <class DATA_TYPE>
|
|
DATA_TYPE *LLLinkedList<DATA_TYPE>::getLastData()
|
|
{
|
|
mCurrentOperatingp = mHead.mNextp;
|
|
|
|
// if empty, return NULL
|
|
if (!mCurrentOperatingp)
|
|
return NULL;
|
|
|
|
// walk until we're pointing at the last entry
|
|
while (mCurrentOperatingp->mNextp)
|
|
{
|
|
mCurrentOperatingp = mCurrentOperatingp->mNextp;
|
|
}
|
|
mCurrentp = mCurrentOperatingp->mNextp;
|
|
return mCurrentOperatingp->mDatap;
|
|
}
|
|
|
|
// remove the Node at mCurentOperatingp
|
|
// leave mCurrentp and mCurentOperatingp on the next entry
|
|
// return TRUE if found, FALSE if not found
|
|
template <class DATA_TYPE>
|
|
void LLLinkedList<DATA_TYPE>::removeCurrentData()
|
|
{
|
|
if (mCurrentOperatingp)
|
|
{
|
|
// remove the node
|
|
// if there is a next one, fix it
|
|
if (mCurrentOperatingp->mNextp)
|
|
{
|
|
mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
|
|
}
|
|
*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
|
|
|
|
// remove the LLLinkNode
|
|
mCurrentp = mCurrentOperatingp->mNextp;
|
|
|
|
mCurrentOperatingp->removeData();
|
|
delete mCurrentOperatingp;
|
|
mCount--;
|
|
mCurrentOperatingp = mCurrentp;
|
|
}
|
|
}
|
|
|
|
// remove the Node at mCurentOperatingp and add it to newlist
|
|
// leave mCurrentp and mCurentOperatingp on the next entry
|
|
// return TRUE if found, FALSE if not found
|
|
template <class DATA_TYPE>
|
|
void LLLinkedList<DATA_TYPE>::moveCurrentData(LLLinkedList *newlist, BOOL b_sort)
|
|
{
|
|
if (mCurrentOperatingp)
|
|
{
|
|
// remove the node
|
|
// if there is a next one, fix it
|
|
if (mCurrentOperatingp->mNextp)
|
|
{
|
|
mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
|
|
}
|
|
*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
|
|
|
|
// remove the LLLinkNode
|
|
mCurrentp = mCurrentOperatingp->mNextp;
|
|
// move the node to the new list
|
|
newlist->addData(mCurrentOperatingp);
|
|
if (b_sort)
|
|
bubbleSortList();
|
|
mCurrentOperatingp = mCurrentp;
|
|
}
|
|
}
|
|
|
|
template <class DATA_TYPE>
|
|
BOOL LLLinkedList<DATA_TYPE>::moveData(DATA_TYPE *data, LLLinkedList *newlist, BOOL b_sort)
|
|
{
|
|
BOOL b_found = FALSE;
|
|
// don't allow NULL to be passed to addData
|
|
if (!data)
|
|
{
|
|
llerror("NULL pointer passed to LLLinkedList::removeData", 0);
|
|
}
|
|
|
|
LLLinkNode *tcurr = mCurrentp;
|
|
LLLinkNode *tcurrop = mCurrentOperatingp;
|
|
|
|
mCurrentp = mHead.mNextp;
|
|
mCurrentOperatingp = mHead.mNextp;
|
|
|
|
while (mCurrentOperatingp)
|
|
{
|
|
if (mCurrentOperatingp->mDatap == data)
|
|
{
|
|
b_found = TRUE;
|
|
|
|
// remove the node
|
|
|
|
// if there is a next one, fix it
|
|
if (mCurrentOperatingp->mNextp)
|
|
{
|
|
mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
|
|
}
|
|
*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
|
|
|
|
// if we were on the one we want to delete, bump the cached copies
|
|
if ( (mCurrentOperatingp == tcurrop)
|
|
||(mCurrentOperatingp == tcurr))
|
|
{
|
|
tcurrop = tcurr = mCurrentOperatingp->mNextp;
|
|
}
|
|
|
|
// remove the LLLinkNode
|
|
mCurrentp = mCurrentOperatingp->mNextp;
|
|
// move the node to the new list
|
|
newlist->addData(mCurrentOperatingp);
|
|
if (b_sort)
|
|
newlist->bubbleSortList();
|
|
mCurrentOperatingp = mCurrentp;
|
|
break;
|
|
}
|
|
mCurrentOperatingp = mCurrentOperatingp->mNextp;
|
|
}
|
|
// restore
|
|
mCurrentp = tcurr;
|
|
mCurrentOperatingp = tcurrop;
|
|
return b_found;
|
|
}
|
|
|
|
// delete the Node at mCurentOperatingp
|
|
// leave mCurrentp anf mCurentOperatingp on the next entry
|
|
// return TRUE if found, FALSE if not found
|
|
template <class DATA_TYPE>
|
|
void LLLinkedList<DATA_TYPE>::deleteCurrentData()
|
|
{
|
|
if (mCurrentOperatingp)
|
|
{
|
|
// remove the node
|
|
// if there is a next one, fix it
|
|
if (mCurrentOperatingp->mNextp)
|
|
{
|
|
mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
|
|
}
|
|
*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
|
|
|
|
// remove the LLLinkNode
|
|
mCurrentp = mCurrentOperatingp->mNextp;
|
|
|
|
mCurrentOperatingp->deleteData();
|
|
if (mCurrentOperatingp->mDatap)
|
|
llerror("This is impossible!", 0);
|
|
delete mCurrentOperatingp;
|
|
mCurrentOperatingp = mCurrentp;
|
|
mCount--;
|
|
}
|
|
}
|
|
|
|
#endif
|