llptrskiplist.h
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:17k
- /**
- * @file llptrskiplist.h
- * @brief Skip list implementation.
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2010, 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_LLPTRSKIPLIST_H
- #define LL_LLPTRSKIPLIST_H
- #include "llerror.h"
- #include "llrand.h"
- //#include "vmath.h"
- #include "llrand.h"
- /////////////////////////////////////////////
- //
- // LLPtrSkipList implementation - skip list for pointers to objects
- //
- template <class DATA_TYPE, S32 BINARY_DEPTH = 8>
- class LLPtrSkipList
- {
- public:
- friend class LLPtrSkipNode;
- // basic constructor
- LLPtrSkipList();
- // basic constructor including sorter
- LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second),
- BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second));
- ~LLPtrSkipList();
- inline void setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second));
- inline void setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second));
- inline BOOL addData(DATA_TYPE *data);
- inline BOOL checkData(const DATA_TYPE *data);
- inline S32 getLength(); // returns number of items in the list - NOT constant time!
- inline BOOL removeData(const DATA_TYPE *data);
- // note that b_sort is ignored
- inline BOOL moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort);
- inline BOOL moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort);
- // resort -- use when the value we're sorting by changes
- /* IW 12/6/02 - This doesn't work!
- Instead, remove the data BEFORE you change it
- Then re-insert it after you change it
- BOOL resortData(DATA_TYPE *data)
- */
- // remove all nodes from the list but do not delete data
- inline void removeAllNodes();
- inline BOOL deleteData(const DATA_TYPE *data);
- // remove all nodes from the list and delete data
- inline void deleteAllData();
- // 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();
- // remove the Node at mCurentOperatingp
- // leave mCurrentp and mCurentOperatingp on the next entry
- inline void removeCurrentData();
- // delete the Node at mCurentOperatingp
- // leave mCurrentp and mCurentOperatingp on the next entry
- inline void deleteCurrentData();
- // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
- inline DATA_TYPE *getFirstData();
- // TRUE if nodes are not in sorted order
- inline BOOL corrupt();
- protected:
- class LLPtrSkipNode
- {
- public:
- LLPtrSkipNode()
- : mData(NULL)
- {
- S32 i;
- for (i = 0; i < BINARY_DEPTH; i++)
- {
- mForward[i] = NULL;
- }
- }
- LLPtrSkipNode(DATA_TYPE *data)
- : mData(data)
- {
- S32 i;
- for (i = 0; i < BINARY_DEPTH; i++)
- {
- mForward[i] = NULL;
- }
- }
- ~LLPtrSkipNode()
- {
- if (mData)
- {
- llerror("Attempting to call LLPtrSkipNode destructor with a non-null mDatap!", 1);
- }
- }
- // delete associated data and NULLs out pointer
- void deleteData()
- {
- delete mData;
- mData = NULL;
- }
- // NULLs out pointer
- void removeData()
- {
- mData = NULL;
- }
- DATA_TYPE *mData;
- LLPtrSkipNode *mForward[BINARY_DEPTH];
- };
- static BOOL defaultEquals(const DATA_TYPE *first, const DATA_TYPE *second)
- {
- return first == second;
- }
- LLPtrSkipNode mHead;
- LLPtrSkipNode *mUpdate[BINARY_DEPTH];
- LLPtrSkipNode *mCurrentp;
- LLPtrSkipNode *mCurrentOperatingp;
- S32 mLevel;
- BOOL (*mInsertFirst)(const DATA_TYPE *first, const DATA_TYPE *second);
- BOOL (*mEquals)(const DATA_TYPE *first, const DATA_TYPE *second);
- };
- // basic constructor
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList()
- : mInsertFirst(NULL), mEquals(defaultEquals)
- {
- if (BINARY_DEPTH < 2)
- {
- llerrs << "Trying to create skip list with too little depth, "
- "must be 2 or greater" << llendl;
- }
- S32 i;
- for (i = 0; i < BINARY_DEPTH; i++)
- {
- mUpdate[i] = NULL;
- }
- mLevel = 1;
- mCurrentp = *(mHead.mForward);
- mCurrentOperatingp = *(mHead.mForward);
- }
- // basic constructor including sorter
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second),
- BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second))
- :mInsertFirst(insert_first), mEquals(equals)
- {
- if (BINARY_DEPTH < 2)
- {
- llerrs << "Trying to create skip list with too little depth, "
- "must be 2 or greater" << llendl;
- }
- mLevel = 1;
- S32 i;
- for (i = 0; i < BINARY_DEPTH; i++)
- {
- mHead.mForward[i] = NULL;
- mUpdate[i] = NULL;
- }
- mCurrentp = *(mHead.mForward);
- mCurrentOperatingp = *(mHead.mForward);
- }
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::~LLPtrSkipList()
- {
- removeAllNodes();
- }
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second))
- {
- mInsertFirst = insert_first;
- }
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second))
- {
- mEquals = equals;
- }
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::addData(DATA_TYPE *data)
- {
- S32 level;
- LLPtrSkipNode *current = &mHead;
- LLPtrSkipNode *temp;
- // find the pointer one in front of the one we want
- if (mInsertFirst)
- {
- for (level = mLevel - 1; level >= 0; level--)
- {
- temp = *(current->mForward + level);
- while ( (temp)
- &&(mInsertFirst(temp->mData, data)))
- {
- current = temp;
- temp = *(current->mForward + level);
- }
- *(mUpdate + level) = current;
- }
- }
- else
- {
- for (level = mLevel - 1; level >= 0; level--)
- {
- temp = *(current->mForward + level);
- while ( (temp)
- &&(temp->mData < data))
- {
- current = temp;
- temp = *(current->mForward + level);
- }
- *(mUpdate + level) = current;
- }
- }
-
- // we're now just in front of where we want to be . . . take one step forward
- current = *current->mForward;
- // now add the new node
- S32 newlevel;
- for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
- {
- if (ll_frand() < 0.5f)
- break;
- }
- LLPtrSkipNode *snode = new LLPtrSkipNode(data);
- if (newlevel > mLevel)
- {
- mHead.mForward[mLevel] = NULL;
- mUpdate[mLevel] = &mHead;
- mLevel = newlevel;
- }
- for (level = 0; level < newlevel; level++)
- {
- snode->mForward[level] = mUpdate[level]->mForward[level];
- mUpdate[level]->mForward[level] = snode;
- }
- return TRUE;
- }
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE *data)
- {
- S32 level;
- LLPtrSkipNode *current = &mHead;
- LLPtrSkipNode *temp;
- // find the pointer one in front of the one we want
- if (mInsertFirst)
- {
- for (level = mLevel - 1; level >= 0; level--)
- {
- temp = *(current->mForward + level);
- while ( (temp)
- &&(mInsertFirst(temp->mData, data)))
- {
- current = temp;
- temp = *(current->mForward + level);
- }
- *(mUpdate + level) = current;
- }
- }
- else
- {
- for (level = mLevel - 1; level >= 0; level--)
- {
- temp = *(current->mForward + level);
- while ( (temp)
- &&(temp->mData < data))
- {
- current = temp;
- temp = *(current->mForward + level);
- }
- *(mUpdate + level) = current;
- }
- }
-
- // we're now just in front of where we want to be . . . take one step forward
- current = *current->mForward;
-
- if (current)
- {
- return mEquals(current->mData, data);
- }
- else
- {
- return FALSE;
- }
- }
- // returns number of items in the list
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline S32 LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getLength()
- {
- U32 length = 0;
- for (LLPtrSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0])
- {
- length++;
- }
- return length;
- }
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE *data)
- {
- S32 level;
- LLPtrSkipNode *current = &mHead;
- LLPtrSkipNode *temp;
- // find the pointer one in front of the one we want
- if (mInsertFirst)
- {
- for (level = mLevel - 1; level >= 0; level--)
- {
- temp = *(current->mForward + level);
- while ( (temp)
- &&(mInsertFirst(temp->mData, data)))
- {
- current = temp;
- temp = *(current->mForward + level);
- }
- *(mUpdate + level) = current;
- }
- }
- else
- {
- for (level = mLevel - 1; level >= 0; level--)
- {
- temp = *(current->mForward + level);
- while ( (temp)
- &&(temp->mData < data))
- {
- current = temp;
- temp = *(current->mForward + level);
- }
- *(mUpdate + level) = current;
- }
- }
-
- // we're now just in front of where we want to be . . . take one step forward
- current = *current->mForward;
- if (!current)
- {
- // empty list or beyond the end!
- return FALSE;
- }
- // is this the one we want?
- if (!mEquals(current->mData, data))
- {
- // nope!
- return FALSE;
- }
- else
- {
- // yes it is! change pointers as required
- for (level = 0; level < mLevel; level++)
- {
- if (mUpdate[level]->mForward[level] != current)
- {
- // cool, we've fixed all the pointers!
- break;
- }
- mUpdate[level]->mForward[level] = current->mForward[level];
- }
- // clean up cuurent
- current->removeData();
- delete current;
- // clean up mHead
- while ( (mLevel > 1)
- &&(!mHead.mForward[mLevel - 1]))
- {
- mLevel--;
- }
- }
- return TRUE;
- }
- // note that b_sort is ignored
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort)
- {
- BOOL removed = removeData(data);
- BOOL added = newlist->addData(data);
- return removed && added;
- }
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort)
- {
- if (mCurrentOperatingp)
- {
- mCurrentp = mCurrentOperatingp->mForward[0];
- BOOL removed = removeData(mCurrentOperatingp);
- BOOL added = newlist->addData(mCurrentOperatingp);
- mCurrentOperatingp = mCurrentp;
- return removed && added;
- }
- return FALSE;
- }
- // resort -- use when the value we're sorting by changes
- /* IW 12/6/02 - This doesn't work!
- Instead, remove the data BEFORE you change it
- Then re-insert it after you change it
- BOOL resortData(DATA_TYPE *data)
- {
- removeData(data);
- addData(data);
- }
- */
- // remove all nodes from the list but do not delete data
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes()
- {
- LLPtrSkipNode *temp;
- // reset mCurrentp
- mCurrentp = *(mHead.mForward);
- while (mCurrentp)
- {
- temp = mCurrentp->mForward[0];
- mCurrentp->removeData();
- delete mCurrentp;
- mCurrentp = temp;
- }
- S32 i;
- for (i = 0; i < BINARY_DEPTH; i++)
- {
- mHead.mForward[i] = NULL;
- mUpdate[i] = NULL;
- }
- mCurrentp = *(mHead.mForward);
- mCurrentOperatingp = *(mHead.mForward);
- }
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteData(const DATA_TYPE *data)
- {
- S32 level;
- LLPtrSkipNode *current = &mHead;
- LLPtrSkipNode *temp;
- // find the pointer one in front of the one we want
- if (mInsertFirst)
- {
- for (level = mLevel - 1; level >= 0; level--)
- {
- temp = *(current->mForward + level);
- while ( (temp)
- &&(mInsertFirst(temp->mData, data)))
- {
- current = temp;
- temp = *(current->mForward + level);
- }
- *(mUpdate + level) = current;
- }
- }
- else
- {
- for (level = mLevel - 1; level >= 0; level--)
- {
- temp = *(current->mForward + level);
- while ( (temp)
- &&(temp->mData < data))
- {
- current = temp;
- temp = *(current->mForward + level);
- }
- *(mUpdate + level) = current;
- }
- }
-
- // we're now just in front of where we want to be . . . take one step forward
- current = *current->mForward;
- if (!current)
- {
- // empty list or beyond the end!
- return FALSE;
- }
- // is this the one we want?
- if (!mEquals(current->mData, data))
- {
- // nope!
- return FALSE;
- }
- else
- {
- // do we need to fix current or currentop?
- if (current == mCurrentp)
- {
- mCurrentp = current->mForward[0];
- }
- if (current == mCurrentOperatingp)
- {
- mCurrentOperatingp = current->mForward[0];
- }
- // yes it is! change pointers as required
- for (level = 0; level < mLevel; level++)
- {
- if (mUpdate[level]->mForward[level] != current)
- {
- // cool, we've fixed all the pointers!
- break;
- }
- mUpdate[level]->mForward[level] = current->mForward[level];
- }
- // clean up cuurent
- current->deleteData();
- delete current;
- // clean up mHead
- while ( (mLevel > 1)
- &&(!mHead.mForward[mLevel - 1]))
- {
- mLevel--;
- }
- }
- return TRUE;
- }
- // remove all nodes from the list and delete data
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteAllData()
- {
- LLPtrSkipNode *temp;
- // reset mCurrentp
- mCurrentp = *(mHead.mForward);
- while (mCurrentp)
- {
- temp = mCurrentp->mForward[0];
- mCurrentp->deleteData();
- delete mCurrentp;
- mCurrentp = temp;
- }
- S32 i;
- for (i = 0; i < BINARY_DEPTH; i++)
- {
- mHead.mForward[i] = NULL;
- mUpdate[i] = NULL;
- }
- mCurrentp = *(mHead.mForward);
- mCurrentOperatingp = *(mHead.mForward);
- }
- // place mCurrentp on first node
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::resetList()
- {
- mCurrentp = *(mHead.mForward);
- mCurrentOperatingp = *(mHead.mForward);
- }
- // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData()
- {
- if (mCurrentp)
- {
- mCurrentOperatingp = mCurrentp;
- mCurrentp = *mCurrentp->mForward;
- return mCurrentOperatingp->mData;
- }
- else
- {
- //return NULL; // causes compile warning
- return 0; // equivalent, but no warning
- }
- }
- // same as getCurrentData() but a more intuitive name for the operation
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData()
- {
- if (mCurrentp)
- {
- mCurrentOperatingp = mCurrentp;
- mCurrentp = *mCurrentp->mForward;
- return mCurrentOperatingp->mData;
- }
- else
- {
- //return NULL; // causes compile warning
- return 0; // equivalent, but no warning
- }
- }
- // remove the Node at mCurentOperatingp
- // leave mCurrentp and mCurentOperatingp on the next entry
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData()
- {
- if (mCurrentOperatingp)
- {
- removeData(mCurrentOperatingp->mData);
- }
- }
- // delete the Node at mCurentOperatingp
- // leave mCurrentp and mCurentOperatingp on the next entry
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteCurrentData()
- {
- if (mCurrentOperatingp)
- {
- deleteData(mCurrentOperatingp->mData);
- }
- }
- // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getFirstData()
- {
- mCurrentp = *(mHead.mForward);
- mCurrentOperatingp = *(mHead.mForward);
- if (mCurrentp)
- {
- mCurrentOperatingp = mCurrentp;
- mCurrentp = mCurrentp->mForward[0];
- return mCurrentOperatingp->mData;
- }
- else
- {
- //return NULL; // causes compile warning
- return 0; // equivalent, but no warning
- }
- }
- template <class DATA_TYPE, S32 BINARY_DEPTH>
- inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::corrupt()
- {
- LLPtrSkipNode *previous = mHead.mForward[0];
- // Empty lists are not corrupt.
- if (!previous) return FALSE;
- LLPtrSkipNode *current = previous->mForward[0];
- while(current)
- {
- if (!mInsertFirst(previous->mData, current->mData))
- {
- // prev shouldn't be in front of cur!
- return TRUE;
- }
- current = current->mForward[0];
- }
- return FALSE;
- }
- #endif