removed unused data structures

master
Richard Linden 2013-04-11 19:08:57 -07:00
parent 49933aadb1
commit ae028e7987
10 changed files with 0 additions and 4546 deletions

View File

@ -34,7 +34,6 @@
#include <map>
#include <deque>
#include "lluuidhashmap.h"
#include "llmotion.h"
#include "llpose.h"
#include "llframetimer.h"

View File

@ -212,8 +212,6 @@ set(llcommon_HEADER_FILES
llpriqueuemap.h
llprocess.h
llprocessor.h
llptrskiplist.h
llptrskipmap.h
llptrto.h
llqueuedthread.h
llrand.h
@ -230,8 +228,6 @@ set(llcommon_HEADER_FILES
llsecondlifeurls.h
llsimplehash.h
llsingleton.h
llskiplist.h
llskipmap.h
llsortedvector.h
llstack.h
llstacktrace.h
@ -255,7 +251,6 @@ set(llcommon_HEADER_FILES
llunit.h
lluri.h
lluuid.h
lluuidhashmap.h
llversionserver.h
llversionviewer.h
llwin32headers.h

View File

@ -1,724 +0,0 @@
/**
* @file llptrskiplist.h
* @brief Skip list implementation.
*
* $LicenseInfo:firstyear=2001&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_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

File diff suppressed because it is too large Load Diff

View File

@ -1,517 +0,0 @@
/**
* @file llskiplist.h
* @brief skip list implementation
*
* $LicenseInfo:firstyear=2001&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_LLSKIPLIST_H
#define LL_LLSKIPLIST_H
#include "llrand.h"
#include "llrand.h"
// NOTA BENE: Insert first needs to be < NOT <=
// Binary depth must be >= 2
template <class DATA_TYPE, S32 BINARY_DEPTH = 10>
class LLSkipList
{
public:
typedef BOOL (*compare)(const DATA_TYPE& first, const DATA_TYPE& second);
typedef compare insert_func;
typedef compare equals_func;
void init();
// basic constructor
LLSkipList();
// basic constructor including sorter
LLSkipList(insert_func insert_first, equals_func equals);
~LLSkipList();
inline void setInsertFirst(insert_func insert_first);
inline void setEquals(equals_func equals);
inline BOOL addData(const DATA_TYPE& data);
inline BOOL checkData(const DATA_TYPE& data);
// returns number of items in the list
inline S32 getLength() const; // NOT a constant time operation, traverses entire list!
inline BOOL moveData(const DATA_TYPE& data, LLSkipList *newlist);
inline BOOL removeData(const DATA_TYPE& data);
// remove all nodes from the list but do not delete data
inline void removeAllNodes();
// 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();
// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
inline DATA_TYPE getFirstData();
class LLSkipNode
{
public:
LLSkipNode()
: mData(0)
{
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mForward[i] = NULL;
}
}
LLSkipNode(DATA_TYPE data)
: mData(data)
{
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mForward[i] = NULL;
}
}
~LLSkipNode()
{
}
DATA_TYPE mData;
LLSkipNode *mForward[BINARY_DEPTH];
private:
// Disallow copying of LLSkipNodes by not implementing these methods.
LLSkipNode(const LLSkipNode &);
LLSkipNode &operator=(const LLSkipNode &);
};
static BOOL defaultEquals(const DATA_TYPE& first, const DATA_TYPE& second)
{
return first == second;
}
private:
LLSkipNode mHead;
LLSkipNode *mUpdate[BINARY_DEPTH];
LLSkipNode *mCurrentp;
LLSkipNode *mCurrentOperatingp;
S32 mLevel;
insert_func mInsertFirst;
equals_func mEquals;
private:
// Disallow copying of LLSkipNodes by not implementing these methods.
LLSkipList(const LLSkipList &);
LLSkipList &operator=(const LLSkipList &);
};
///////////////////////
//
// Implementation
//
// Binary depth must be >= 2
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::init()
{
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mHead.mForward[i] = NULL;
mUpdate[i] = NULL;
}
mLevel = 1;
mCurrentp = *(mHead.mForward);
mCurrentOperatingp = *(mHead.mForward);
}
// basic constructor
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList()
: mInsertFirst(NULL),
mEquals(defaultEquals)
{
init();
}
// basic constructor including sorter
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList(insert_func insert,
equals_func equals)
: mInsertFirst(insert),
mEquals(equals)
{
init();
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::~LLSkipList()
{
removeAllNodes();
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(insert_func insert_first)
{
mInsertFirst = insert_first;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(equals_func equals)
{
mEquals = equals;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::addData(const DATA_TYPE& data)
{
S32 level;
LLSkipNode *current = &mHead;
LLSkipNode *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;
}
LLSkipNode *snode = new LLSkipNode(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 LLSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE& data)
{
S32 level;
LLSkipNode *current = &mHead;
LLSkipNode *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);
}
return FALSE;
}
// returns number of items in the list
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline S32 LLSkipList<DATA_TYPE, BINARY_DEPTH>::getLength() const
{
U32 length = 0;
for (LLSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0])
{
length++;
}
return length;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE& data, LLSkipList *newlist)
{
BOOL removed = removeData(data);
BOOL added = newlist->addData(data);
return removed && added;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE& data)
{
S32 level;
LLSkipNode *current = &mHead;
LLSkipNode *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
delete current;
// clean up mHead
while ( (mLevel > 1)
&&(!mHead.mForward[mLevel - 1]))
{
mLevel--;
}
}
return TRUE;
}
// remove all nodes from the list but do not delete data
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes()
{
LLSkipNode *temp;
// reset mCurrentp
mCurrentp = *(mHead.mForward);
while (mCurrentp)
{
temp = mCurrentp->mForward[0];
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 LLSkipList<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 LLSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData()
{
if (mCurrentp)
{
mCurrentOperatingp = mCurrentp;
mCurrentp = mCurrentp->mForward[0];
return mCurrentOperatingp->mData;
}
else
{
//return NULL; // causes compile warning
return (DATA_TYPE)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 LLSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData()
{
if (mCurrentp)
{
mCurrentOperatingp = mCurrentp;
mCurrentp = mCurrentp->mForward[0];
return mCurrentOperatingp->mData;
}
else
{
//return NULL; // causes compile warning
return (DATA_TYPE)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 LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData()
{
if (mCurrentOperatingp)
{
removeData(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 LLSkipList<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 (DATA_TYPE)0; // equivalent, but no warning
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,583 +0,0 @@
/**
* @file lluuidhashmap.h
* @brief A uuid based hash map.
*
* $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_LLUUIDHASHMAP_H
#define LL_LLUUIDHASHMAP_H
#include "stdtypes.h"
#include "llerror.h"
#include "lluuid.h"
// UUID hash map
/*
LLUUIDHashMap<uuid_pair, 32> foo(test_equals);
LLUUIDHashMapIter<uuid_pair, 32> bar(&foo);
LLDynamicArray<LLUUID> source_ids;
const S32 COUNT = 100000;
S32 q;
for (q = 0; q < COUNT; q++)
{
llinfos << "Creating" << llendl;
LLUUID id;
id.generate();
//llinfos << q << ":" << id << llendl;
uuid_pair pair;
pair.mUUID = id;
pair.mValue = q;
foo.set(id, pair);
source_ids.put(id);
//ms_sleep(1);
}
uuid_pair cur;
llinfos << "Iterating" << llendl;
for (cur = bar.first(); !bar.done(); cur = bar.next())
{
if (source_ids[cur.mValue] != cur.mUUID)
{
llerrs << "Incorrect value iterated!" << llendl;
}
//llinfos << cur.mValue << ":" << cur.mUUID << llendl;
//ms_sleep(1);
}
llinfos << "Finding" << llendl;
for (q = 0; q < COUNT; q++)
{
cur = foo.get(source_ids[q]);
if (source_ids[cur.mValue] != cur.mUUID)
{
llerrs << "Incorrect value found!" << llendl;
}
//llinfos << res.mValue << ":" << res.mUUID << llendl;
//ms_sleep(1);
}
llinfos << "Removing" << llendl;
for (q = 0; q < COUNT/2; q++)
{
if (!foo.remove(source_ids[q]))
{
llerrs << "Remove failed!" << llendl;
}
//ms_sleep(1);
}
llinfos << "Iterating" << llendl;
for (cur = bar.first(); !bar.done(); cur = bar.next())
{
if (source_ids[cur.mValue] != cur.mUUID)
{
llerrs << "Incorrect value found!" << llendl;
}
//llinfos << cur.mValue << ":" << cur.mUUID << llendl;
//ms_sleep(1);
}
llinfos << "Done with UUID map test" << llendl;
return 0;
*/
//
// LLUUIDHashNode
//
template <class DATA, int SIZE>
class LLUUIDHashNode
{
public:
LLUUIDHashNode();
public:
S32 mCount;
U8 mKey[SIZE];
DATA mData[SIZE];
LLUUIDHashNode<DATA, SIZE> *mNextNodep;
};
//
// LLUUIDHashNode implementation
//
template <class DATA, int SIZE>
LLUUIDHashNode<DATA, SIZE>::LLUUIDHashNode()
{
mCount = 0;
mNextNodep = NULL;
}
template <class DATA_TYPE, int SIZE>
class LLUUIDHashMap
{
public:
// basic constructor including sorter
LLUUIDHashMap(BOOL (*equals)(const LLUUID &uuid, const DATA_TYPE &data),
const DATA_TYPE &null_data);
~LLUUIDHashMap();
inline DATA_TYPE &get(const LLUUID &uuid);
inline BOOL check(const LLUUID &uuid) const;
inline DATA_TYPE &set(const LLUUID &uuid, const DATA_TYPE &type);
inline BOOL remove(const LLUUID &uuid);
void removeAll();
inline S32 getLength() const; // Warning, NOT O(1!)
public:
BOOL (*mEquals)(const LLUUID &uuid, const DATA_TYPE &data);
LLUUIDHashNode<DATA_TYPE, SIZE> mNodes[256];
S32 mIterCount;
protected:
DATA_TYPE mNull;
};
//
// LLUUIDHashMap implementation
//
template <class DATA_TYPE, int SIZE>
LLUUIDHashMap<DATA_TYPE, SIZE>::LLUUIDHashMap(BOOL (*equals)(const LLUUID &uuid, const DATA_TYPE &data),
const DATA_TYPE &null_data)
: mEquals(equals),
mIterCount(0),
mNull(null_data)
{ }
template <class DATA_TYPE, int SIZE>
LLUUIDHashMap<DATA_TYPE, SIZE>::~LLUUIDHashMap()
{
removeAll();
}
template <class DATA_TYPE, int SIZE>
void LLUUIDHashMap<DATA_TYPE, SIZE>::removeAll()
{
S32 bin;
for (bin = 0; bin < 256; bin++)
{
LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
BOOL first = TRUE;
while (nodep)
{
S32 i;
const S32 count = nodep->mCount;
// Iterate through all members of this node
for (i = 0; i < count; i++)
{
nodep->mData[i] = mNull;
}
nodep->mCount = 0;
// Done with all objects in this node, go to the next.
LLUUIDHashNode<DATA_TYPE, SIZE>* curp = nodep;
nodep = nodep->mNextNodep;
// Delete the node if it's not the first node
if (first)
{
first = FALSE;
curp->mNextNodep = NULL;
}
else
{
delete curp;
}
}
}
}
template <class DATA_TYPE, int SIZE>
inline S32 LLUUIDHashMap<DATA_TYPE, SIZE>::getLength() const
{
S32 count = 0;
S32 bin;
for (bin = 0; bin < 256; bin++)
{
LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = (LLUUIDHashNode<DATA_TYPE, SIZE>*) &mNodes[bin];
while (nodep)
{
count += nodep->mCount;
nodep = nodep->mNextNodep;
}
}
return count;
}
template <class DATA_TYPE, int SIZE>
inline DATA_TYPE &LLUUIDHashMap<DATA_TYPE, SIZE>::get(const LLUUID &uuid)
{
LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]];
// Grab the second byte of the UUID, which is the key for the node data
const S32 second_byte = uuid.mData[1];
while (nodep)
{
S32 i;
const S32 count = nodep->mCount;
// Iterate through all members of this node
for (i = 0; i < count; i++)
{
if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
{
// The second byte matched, and our equality test passed.
// We found it.
return nodep->mData[i];
}
}
// Done with all objects in this node, go to the next.
nodep = nodep->mNextNodep;
}
return mNull;
}
template <class DATA_TYPE, int SIZE>
inline BOOL LLUUIDHashMap<DATA_TYPE, SIZE>::check(const LLUUID &uuid) const
{
const LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]];
// Grab the second byte of the UUID, which is the key for the node data
const S32 second_byte = uuid.mData[1];
while (nodep)
{
S32 i;
const S32 count = nodep->mCount;
// Iterate through all members of this node
for (i = 0; i < count; i++)
{
if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
{
// The second byte matched, and our equality test passed.
// We found it.
return TRUE;
}
}
// Done with all objects in this node, go to the next.
nodep = nodep->mNextNodep;
}
// Didn't find anything
return FALSE;
}
template <class DATA_TYPE, int SIZE>
inline DATA_TYPE &LLUUIDHashMap<DATA_TYPE, SIZE>::set(const LLUUID &uuid, const DATA_TYPE &data)
{
// Set is just like a normal find, except that if we find a match
// we replace it with the input value.
// If we don't find a match, we append to the end of the list.
LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]];
const S32 second_byte = uuid.mData[1];
while (1)
{
const S32 count = nodep->mCount;
S32 i;
for (i = 0; i < count; i++)
{
if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
{
// We found a match for this key, replace the data with
// the incoming data.
nodep->mData[i] = data;
return nodep->mData[i];
}
}
if (!nodep->mNextNodep)
{
// We've iterated through all of the keys without finding a match
if (i < SIZE)
{
// There's still some space on this node, append
// the key and data to it.
nodep->mKey[i] = second_byte;
nodep->mData[i] = data;
nodep->mCount++;
return nodep->mData[i];
}
else
{
// This node is full, append a new node to the end.
nodep->mNextNodep = new LLUUIDHashNode<DATA_TYPE, SIZE>;
nodep->mNextNodep->mKey[0] = second_byte;
nodep->mNextNodep->mData[0] = data;
nodep->mNextNodep->mCount = 1;
return nodep->mNextNodep->mData[0];
}
}
// No match on this node, go to the next
nodep = nodep->mNextNodep;
}
}
template <class DATA_TYPE, int SIZE>
inline BOOL LLUUIDHashMap<DATA_TYPE, SIZE>::remove(const LLUUID &uuid)
{
if (mIterCount)
{
// We don't allow remove when we're iterating, it's bad karma!
llerrs << "Attempted remove while an outstanding iterator in LLUUIDHashMap!" << llendl;
}
// Remove is the trickiest operation.
// What we want to do is swap the last element of the last
// node if we find the one that we want to remove, but we have
// to deal with deleting the node from the tail if it's empty, but
// NOT if it's the only node left.
LLUUIDHashNode<DATA_TYPE, SIZE> *nodep = &mNodes[uuid.mData[0]];
// Not empty, we need to search through the nodes
const S32 second_byte = uuid.mData[1];
// A modification of the standard search algorithm.
while (nodep)
{
const S32 count = nodep->mCount;
S32 i;
for (i = 0; i < count; i++)
{
if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
{
// We found the node that we want to remove.
// Find the last (and next-to-last) node, and the index of the last
// element. We could conceviably start from the node we're on,
// but that makes it more complicated, this is easier.
LLUUIDHashNode<DATA_TYPE, SIZE> *prevp = &mNodes[uuid.mData[0]];
LLUUIDHashNode<DATA_TYPE, SIZE> *lastp = prevp;
// Find the last and next-to-last
while (lastp->mNextNodep)
{
prevp = lastp;
lastp = lastp->mNextNodep;
}
// First, swap in the last to the current location.
nodep->mKey[i] = lastp->mKey[lastp->mCount - 1];
nodep->mData[i] = lastp->mData[lastp->mCount - 1];
// Now, we delete the entry
lastp->mCount--;
lastp->mData[lastp->mCount] = mNull;
if (!lastp->mCount)
{
// We deleted the last element!
if (lastp != &mNodes[uuid.mData[0]])
{
// Only blitz the node if it's not the head
// Set the previous node to point to NULL, then
// blitz the empty last node
prevp->mNextNodep = NULL;
delete lastp;
}
}
return TRUE;
}
}
// Iterate to the next node, we've scanned all the entries in this one.
nodep = nodep->mNextNodep;
}
return FALSE;
}
//
// LLUUIDHashMapIter
//
template <class DATA_TYPE, int SIZE>
class LLUUIDHashMapIter
{
public:
LLUUIDHashMapIter(LLUUIDHashMap<DATA_TYPE, SIZE> *hash_mapp);
~LLUUIDHashMapIter();
inline void reset();
inline void first();
inline void next();
inline BOOL done() const;
DATA_TYPE& operator*() const
{
return mCurHashNodep->mData[mCurHashNodeKey];
}
DATA_TYPE* operator->() const
{
return &(operator*());
}
protected:
LLUUIDHashMap<DATA_TYPE, SIZE> *mHashMapp;
LLUUIDHashNode<DATA_TYPE, SIZE> *mCurHashNodep;
S32 mCurHashMapNodeNum;
S32 mCurHashNodeKey;
DATA_TYPE mNull;
};
//
// LLUUIDHashMapIter Implementation
//
template <class DATA_TYPE, int SIZE>
LLUUIDHashMapIter<DATA_TYPE, SIZE>::LLUUIDHashMapIter(LLUUIDHashMap<DATA_TYPE, SIZE> *hash_mapp)
{
mHashMapp = hash_mapp;
mCurHashNodep = NULL;
mCurHashMapNodeNum = 0;
mCurHashNodeKey = 0;
}
template <class DATA_TYPE, int SIZE>
LLUUIDHashMapIter<DATA_TYPE, SIZE>::~LLUUIDHashMapIter()
{
reset();
}
template <class DATA_TYPE, int SIZE>
inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::reset()
{
if (mCurHashNodep)
{
// We're partway through an iteration, we can clean up now
mHashMapp->mIterCount--;
mCurHashNodep = NULL;
}
}
template <class DATA_TYPE, int SIZE>
inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::first()
{
// Iterate through until we find the first non-empty node;
S32 i;
for (i = 0; i < 256; i++)
{
if (mHashMapp->mNodes[i].mCount)
{
if (!mCurHashNodep)
{
// Increment, since it's no longer safe for us to do a remove
mHashMapp->mIterCount++;
}
mCurHashNodep = &mHashMapp->mNodes[i];
mCurHashMapNodeNum = i;
mCurHashNodeKey = 0;
//return mCurHashNodep->mData[0];
return;
}
}
// Completely empty!
mCurHashNodep = NULL;
//return mNull;
return;
}
template <class DATA_TYPE, int SIZE>
inline BOOL LLUUIDHashMapIter<DATA_TYPE, SIZE>::done() const
{
return mCurHashNodep ? FALSE : TRUE;
}
template <class DATA_TYPE, int SIZE>
inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::next()
{
// No current entry, this iterator is done
if (!mCurHashNodep)
{
//return mNull;
return;
}
// Go to the next element
mCurHashNodeKey++;
if (mCurHashNodeKey < mCurHashNodep->mCount)
{
// We're not done with this node, return the current element
//return mCurHashNodep->mData[mCurHashNodeKey];
return;
}
// Done with this node, move to the next
mCurHashNodep = mCurHashNodep->mNextNodep;
if (mCurHashNodep)
{
// Return the first element
mCurHashNodeKey = 0;
//return mCurHashNodep->mData[0];
return;
}
// Find the next non-empty node (keyed on the first byte)
mCurHashMapNodeNum++;
S32 i;
for (i = mCurHashMapNodeNum; i < 256; i++)
{
if (mHashMapp->mNodes[i].mCount)
{
// We found one that wasn't empty
mCurHashNodep = &mHashMapp->mNodes[i];
mCurHashMapNodeNum = i;
mCurHashNodeKey = 0;
//return mCurHashNodep->mData[0];
return;
}
}
// OK, we're done, nothing else to iterate
mCurHashNodep = NULL;
mHashMapp->mIterCount--; // Decrement since we're safe to do removes now
//return mNull;
}
#endif // LL_LLUUIDHASHMAP_H

View File

@ -83,7 +83,6 @@
#include "llsys.h"
#include "llthread.h"
#include "lltimer.h"
#include "lluuidhashmap.h"
#include "stdenums.h"
#include "stdtypes.h"
#include "timing.h"

View File

@ -52,7 +52,6 @@ set(test_SOURCE_FILES
llstreamtools_tut.cpp
lltemplatemessagebuilder_tut.cpp
lltut.cpp
lluuidhashmap_tut.cpp
message_tut.cpp
test.cpp
)

View File

@ -1,455 +0,0 @@
/**
* @file lluuidhashmap_tut.cpp
* @author Adroit
* @date 2007-02
* @brief Test cases for LLUUIDHashMap
*
* $LicenseInfo:firstyear=2007&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$
*/
#include <tut/tut.hpp>
#include "linden_common.h"
#include "lluuidhashmap.h"
#include "llsdserialize.h"
#include "lldir.h"
#include "stringize.h"
#include <iostream>
#include <fstream>
namespace tut
{
class UUIDTableEntry
{
public:
UUIDTableEntry()
{
mID.setNull();
mValue = 0;
}
UUIDTableEntry(const LLUUID& id, U32 value)
{
mID = id;
mValue = value;
}
~UUIDTableEntry(){};
static BOOL uuidEq(const LLUUID &uuid, const UUIDTableEntry &id_pair)
{
if (uuid == id_pair.mID)
{
return TRUE;
}
return FALSE;
}
const LLUUID& getID() { return mID; }
const U32& getValue() { return mValue; }
protected:
LLUUID mID;
U32 mValue;
};
struct hashmap_test
{
};
typedef test_group<hashmap_test> hash_index_t;
typedef hash_index_t::object hash_index_object_t;
tut::hash_index_t tut_hash_index("hashmap_test");
// stress test
template<> template<>
void hash_index_object_t::test<1>()
{
set_test_name("stress test");
// As of 2012-10-10, I (nat) have observed sporadic failures of this
// test: "set/get did not work." The trouble is that since test data
// are randomly generated with every run, it is impossible to debug a
// test failure. One is left with the uneasy suspicion that
// LLUUID::generate() can sometimes produce duplicates even within the
// moderately small number requested here. Since rerunning the test
// generally allows it to pass, it's too easy to shrug and forget it.
// The following code is intended to support reproducing such test
// failures. The idea is that, on test failure, we save the generated
// data to a canonical filename in a temp directory. Then on every
// subsequent run, we check for that filename. If it exists, we reload
// that specific data rather than generating fresh data -- which
// should presumably reproduce the same test failure. But we inform
// the user that to resume normal (random) test runs, s/he need only
// delete that file. And since it's in a temp directory, sooner or
// later the system will clean it up anyway.
const char* tempvar = "TEMP";
const char* tempdir = getenv(tempvar); // Windows convention
if (! tempdir)
{
tempvar = "TMPDIR";
tempdir = getenv(tempvar); // Mac convention
}
if (! tempdir)
{
// reset tempvar to the first var we check; it's just a
// recommendation
tempvar = "TEMP";
tempdir = "/tmp"; // Posix in general
}
std::string savefile(gDirUtilp->add(tempdir, "lluuidhashmap_tut.save.txt"));
const int numElementsToCheck = 32*256*32;
std::vector<LLUUID> idList;
if ((! getenv("TEAMCITY_PROJECT_NAME")) && gDirUtilp->fileExists(savefile))
{
// This is not a TeamCity build, and we have saved data from a
// previous failed run. Reload that data.
std::ifstream inf(savefile.c_str());
if (! inf.is_open())
{
fail(STRINGIZE("Although save file '" << savefile << "' exists, it cannot be opened"));
}
std::string item;
while (std::getline(inf, item))
{
idList.push_back(LLUUID(item));
}
std::cout << "Reloaded " << idList.size() << " items from '" << savefile << "'";
if (idList.size() != numElementsToCheck)
{
std::cout << " (expected " << numElementsToCheck << ")";
}
std::cout << " -- delete this file to generate new data" << std::endl;
}
else
{
// This is a TeamCity build, or (normal case) savefile does not
// exist: regenerate idList from scratch.
for (int i = 0; i < numElementsToCheck; ++i)
{
LLUUID id;
id.generate();
idList.push_back(id);
}
}
LLUUIDHashMap<UUIDTableEntry, 32> hashTable(UUIDTableEntry::uuidEq, UUIDTableEntry());
int i;
for (i = 0; i < idList.size(); ++i)
{
UUIDTableEntry entry(idList[i], i);
hashTable.set(idList[i], entry);
}
try
{
for (i = 0; i < idList.size(); i++)
{
LLUUID idToCheck = idList[i];
UUIDTableEntry entryToCheck = hashTable.get(idToCheck);
ensure_equals(STRINGIZE("set/get ID (entry " << i << ")").c_str(),
entryToCheck.getID(), idToCheck);
ensure_equals(STRINGIZE("set/get value (ID " << idToCheck << ")").c_str(),
entryToCheck.getValue(), (size_t)i);
}
for (i = 0; i < idList.size(); i++)
{
LLUUID idToCheck = idList[i];
if (i % 2 != 0)
{
hashTable.remove(idToCheck);
}
}
for (i = 0; i < idList.size(); i++)
{
LLUUID idToCheck = idList[i];
ensure("remove or check did not work", (i % 2 == 0 && hashTable.check(idToCheck)) || (i % 2 != 0 && !hashTable.check(idToCheck)));
}
}
catch (const failure&)
{
// One of the above tests failed. Try to save idList to repro with
// a later run.
std::ofstream outf(savefile.c_str());
if (! outf.is_open())
{
// Sigh, don't use fail() here because we want to preserve
// the original test failure.
std::cout << "Cannot open file '" << savefile
<< "' to save data -- check and fix " << tempvar << std::endl;
}
else
{
// outf.is_open()
for (int i = 0; i < idList.size(); ++i)
{
outf << idList[i] << std::endl;
}
std::cout << "Saved " << idList.size() << " entries to '" << savefile
<< "' -- rerun test to debug with these" << std::endl;
}
// re-raise the same exception -- we WANT this test failure to
// be reported! We just needed to save the data on the way out.
throw;
}
}
// test removing all but one element.
template<> template<>
void hash_index_object_t::test<2>()
{
LLUUIDHashMap<UUIDTableEntry, 2> hashTable(UUIDTableEntry::uuidEq, UUIDTableEntry());
const int numElementsToCheck = 5;
std::vector<LLUUID> idList(numElementsToCheck*10);
int i;
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID id;
id.generate();
UUIDTableEntry entry(id, i);
hashTable.set(id, entry);
idList[i] = id;
}
ensure("getLength failed", hashTable.getLength() == numElementsToCheck);
// remove all but the last element
for (i = 0; i < numElementsToCheck-1; i++)
{
LLUUID idToCheck = idList[i];
hashTable.remove(idToCheck);
}
// there should only be one element left now.
ensure("getLength failed", hashTable.getLength() == 1);
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID idToCheck = idList[i];
if (i != numElementsToCheck - 1)
{
ensure("remove did not work", hashTable.check(idToCheck) == FALSE);
}
else
{
UUIDTableEntry entryToCheck = hashTable.get(idToCheck);
ensure("remove did not work", entryToCheck.getID() == idToCheck && entryToCheck.getValue() == (size_t)i);
}
}
}
// test overriding of value already set.
template<> template<>
void hash_index_object_t::test<3>()
{
LLUUIDHashMap<UUIDTableEntry, 5> hashTable(UUIDTableEntry::uuidEq, UUIDTableEntry());
const int numElementsToCheck = 10;
std::vector<LLUUID> idList(numElementsToCheck);
int i;
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID id;
id.generate();
UUIDTableEntry entry(id, i);
hashTable.set(id, entry);
idList[i] = id;
}
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID id = idList[i];
// set new entry with value = i+numElementsToCheck
UUIDTableEntry entry(id, i+numElementsToCheck);
hashTable.set(id, entry);
}
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID idToCheck = idList[i];
UUIDTableEntry entryToCheck = hashTable.get(idToCheck);
ensure("set/get did not work", entryToCheck.getID() == idToCheck && entryToCheck.getValue() == (size_t)(i+numElementsToCheck));
}
}
// test removeAll()
template<> template<>
void hash_index_object_t::test<4>()
{
LLUUIDHashMap<UUIDTableEntry, 5> hashTable(UUIDTableEntry::uuidEq, UUIDTableEntry());
const int numElementsToCheck = 10;
std::vector<LLUUID> idList(numElementsToCheck);
int i;
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID id;
id.generate();
UUIDTableEntry entry(id, i);
hashTable.set(id, entry);
idList[i] = id;
}
hashTable.removeAll();
ensure("removeAll failed", hashTable.getLength() == 0);
}
// test sparse map - force it by creating 256 entries that fall into 256 different nodes
template<> template<>
void hash_index_object_t::test<5>()
{
LLUUIDHashMap<UUIDTableEntry, 2> hashTable(UUIDTableEntry::uuidEq, UUIDTableEntry());
const int numElementsToCheck = 256;
std::vector<LLUUID> idList(numElementsToCheck);
int i;
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID id;
id.generate();
// LLUUIDHashMap uses mData[0] to pick the bucket
// overwrite mData[0] so that it ranges from 0 to 255
id.mData[0] = i;
UUIDTableEntry entry(id, i);
hashTable.set(id, entry);
idList[i] = id;
}
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID idToCheck = idList[i];
UUIDTableEntry entryToCheck = hashTable.get(idToCheck);
ensure("set/get did not work for sparse map", entryToCheck.getID() == idToCheck && entryToCheck.getValue() == (size_t)i);
}
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID idToCheck = idList[i];
if (i % 2 != 0)
{
hashTable.remove(idToCheck);
}
}
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID idToCheck = idList[i];
ensure("remove or check did not work for sparse map", (i % 2 == 0 && hashTable.check(idToCheck)) || (i % 2 != 0 && !hashTable.check(idToCheck)));
}
}
// iterator
template<> template<>
void hash_index_object_t::test<6>()
{
LLUUIDHashMap<UUIDTableEntry, 2> hashTable(UUIDTableEntry::uuidEq, UUIDTableEntry());
LLUUIDHashMapIter<UUIDTableEntry, 2> hashIter(&hashTable);
const int numElementsToCheck = 256;
std::vector<LLUUID> idList(numElementsToCheck);
int i;
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID id;
id.generate();
// LLUUIDHashMap uses mData[0] to pick the bucket
// overwrite mData[0] so that it ranges from 0 to 255
// to create a sparse map
id.mData[0] = i;
UUIDTableEntry entry(id, i);
hashTable.set(id, entry);
idList[i] = id;
}
hashIter.first();
int numElementsIterated = 0;
while(!hashIter.done())
{
numElementsIterated++;
UUIDTableEntry tableEntry = *hashIter;
LLUUID id = tableEntry.getID();
hashIter.next();
ensure("Iteration failed for sparse map", tableEntry.getValue() < (size_t)numElementsToCheck && idList[tableEntry.getValue()] == tableEntry.getID());
}
ensure("iteration count failed", numElementsIterated == numElementsToCheck);
}
// remove after middle of iteration
template<> template<>
void hash_index_object_t::test<7>()
{
LLUUIDHashMap<UUIDTableEntry, 2> hashTable(UUIDTableEntry::uuidEq, UUIDTableEntry());
LLUUIDHashMapIter<UUIDTableEntry, 2> hashIter(&hashTable);
const int numElementsToCheck = 256;
std::vector<LLUUID> idList(numElementsToCheck);
int i;
LLUUID uuidtoSearch;
for (i = 0; i < numElementsToCheck; i++)
{
LLUUID id;
id.generate();
// LLUUIDHashMap uses mData[0] to pick the bucket
// overwrite mData[0] so that it ranges from 0 to 255
// to create a sparse map
id.mData[0] = i;
UUIDTableEntry entry(id, i);
hashTable.set(id, entry);
idList[i] = id;
// pick uuid somewhere in the middle
if (i == 5)
{
uuidtoSearch = id;
}
}
hashIter.first();
int numElementsIterated = 0;
while(!hashIter.done())
{
numElementsIterated++;
UUIDTableEntry tableEntry = *hashIter;
LLUUID id = tableEntry.getID();
if (uuidtoSearch == id)
{
break;
}
hashIter.next();
}
// current iterator implementation will not allow any remove operations
// until ALL elements have been iterated over. this seems to be
// an unnecessary restriction. Iterator should have a method to
// reset() its state so that further operations (inckuding remove)
// can be performed on the HashMap without having to iterate thru
// all the remaining nodes.
// hashIter.reset();
// hashTable.remove(uuidtoSearch);
// ensure("remove after iteration reset failed", hashTable.check(uuidtoSearch) == FALSE);
}
}