1029 lines
24 KiB
C++
1029 lines
24 KiB
C++
/**
|
|
* @file llskipmap.h
|
|
* @brief Associative container based on the skiplist algorithm.
|
|
*
|
|
* $LicenseInfo:firstyear=2003&license=viewergpl$
|
|
*
|
|
* Copyright (c) 2003-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_LLSKIPMAP_H
|
|
#define LL_LLSKIPMAP_H
|
|
|
|
#include "llerror.h"
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH = 8>
|
|
class LLSkipMap
|
|
{
|
|
public:
|
|
// basic constructor
|
|
LLSkipMap();
|
|
|
|
// basic constructor including sorter
|
|
LLSkipMap(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second),
|
|
BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second));
|
|
|
|
~LLSkipMap();
|
|
|
|
void setInsertFirst(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second));
|
|
void setEquals(BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second));
|
|
|
|
DATA_TYPE &addData(const INDEX_TYPE &index, DATA_TYPE datap);
|
|
DATA_TYPE &addData(const INDEX_TYPE &index);
|
|
DATA_TYPE &getData(const INDEX_TYPE &index);
|
|
DATA_TYPE &operator[](const INDEX_TYPE &index);
|
|
|
|
// If index present, returns data.
|
|
// If index not present, adds <index,NULL> and returns NULL.
|
|
DATA_TYPE &getData(const INDEX_TYPE &index, BOOL &b_new_entry);
|
|
|
|
// Returns TRUE if data present in map.
|
|
BOOL checkData(const INDEX_TYPE &index);
|
|
|
|
// Returns TRUE if key is present in map. This is useful if you
|
|
// are potentially storing NULL pointers in the map
|
|
BOOL checkKey(const INDEX_TYPE &index);
|
|
|
|
// If there, returns the data.
|
|
// If not, returns NULL.
|
|
// Never adds entries to the map.
|
|
DATA_TYPE getIfThere(const INDEX_TYPE &index);
|
|
|
|
INDEX_TYPE reverseLookup(const DATA_TYPE datap);
|
|
|
|
// returns number of items in the list
|
|
S32 getLength(); // WARNING! getLength is O(n), not O(1)!
|
|
|
|
BOOL removeData(const INDEX_TYPE &index);
|
|
|
|
// remove all nodes from the list but do not delete data
|
|
void removeAllData();
|
|
|
|
// place mCurrentp on first node
|
|
void resetList();
|
|
|
|
// return the data currently pointed to
|
|
DATA_TYPE getCurrentDataWithoutIncrement();
|
|
|
|
// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
|
|
DATA_TYPE getCurrentData();
|
|
|
|
// same as getCurrentData() but a more intuitive name for the operation
|
|
DATA_TYPE getNextData();
|
|
|
|
INDEX_TYPE getNextKey();
|
|
|
|
// return the key currently pointed to
|
|
INDEX_TYPE getCurrentKeyWithoutIncrement();
|
|
|
|
// The internal iterator is at the end of the list.
|
|
BOOL notDone() const;
|
|
|
|
// remove the Node at mCurentOperatingp
|
|
// leave mCurrentp and mCurentOperatingp on the next entry
|
|
void removeCurrentData();
|
|
|
|
void deleteCurrentData();
|
|
|
|
// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
|
|
DATA_TYPE getFirstData();
|
|
|
|
INDEX_TYPE getFirstKey();
|
|
|
|
class LLSkipMapNode
|
|
{
|
|
public:
|
|
LLSkipMapNode()
|
|
{
|
|
S32 i;
|
|
for (i = 0; i < BINARY_DEPTH; i++)
|
|
{
|
|
mForward[i] = NULL;
|
|
}
|
|
|
|
U8 *zero = (U8 *)&mIndex;
|
|
|
|
for (i = 0; i < (S32)sizeof(INDEX_TYPE); i++)
|
|
{
|
|
*(zero + i) = 0;
|
|
}
|
|
|
|
zero = (U8 *)&mData;
|
|
|
|
for (i = 0; i < (S32)sizeof(DATA_TYPE); i++)
|
|
{
|
|
*(zero + i) = 0;
|
|
}
|
|
}
|
|
|
|
LLSkipMapNode(const INDEX_TYPE &index)
|
|
: mIndex(index)
|
|
{
|
|
|
|
S32 i;
|
|
for (i = 0; i < BINARY_DEPTH; i++)
|
|
{
|
|
mForward[i] = NULL;
|
|
}
|
|
|
|
U8 *zero = (U8 *)&mData;
|
|
|
|
for (i = 0; i < (S32)sizeof(DATA_TYPE); i++)
|
|
{
|
|
*(zero + i) = 0;
|
|
}
|
|
}
|
|
|
|
LLSkipMapNode(const INDEX_TYPE &index, DATA_TYPE datap)
|
|
: mIndex(index)
|
|
{
|
|
|
|
S32 i;
|
|
for (i = 0; i < BINARY_DEPTH; i++)
|
|
{
|
|
mForward[i] = NULL;
|
|
}
|
|
|
|
mData = datap;
|
|
}
|
|
|
|
~LLSkipMapNode()
|
|
{
|
|
}
|
|
|
|
|
|
INDEX_TYPE mIndex;
|
|
DATA_TYPE mData;
|
|
LLSkipMapNode *mForward[BINARY_DEPTH];
|
|
|
|
private:
|
|
// Disallow copying of LLSkipMapNodes by not implementing these methods.
|
|
LLSkipMapNode(const LLSkipMapNode &);
|
|
LLSkipMapNode &operator=(const LLSkipMapNode &rhs);
|
|
};
|
|
|
|
static BOOL defaultEquals(const INDEX_TYPE &first, const INDEX_TYPE &second)
|
|
{
|
|
return first == second;
|
|
}
|
|
|
|
private:
|
|
// don't generate implicit copy constructor or copy assignment
|
|
LLSkipMap(const LLSkipMap &);
|
|
LLSkipMap &operator=(const LLSkipMap &);
|
|
|
|
private:
|
|
LLSkipMapNode mHead;
|
|
LLSkipMapNode *mUpdate[BINARY_DEPTH];
|
|
LLSkipMapNode *mCurrentp;
|
|
LLSkipMapNode *mCurrentOperatingp;
|
|
S32 mLevel;
|
|
BOOL (*mInsertFirst)(const INDEX_TYPE &first, const INDEX_TYPE &second);
|
|
BOOL (*mEquals)(const INDEX_TYPE &first, const INDEX_TYPE &second);
|
|
S32 mNumberOfSteps;
|
|
};
|
|
|
|
//////////////////////////////////////////////////
|
|
//
|
|
// LLSkipMap implementation
|
|
//
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap()
|
|
: mInsertFirst(NULL),
|
|
mEquals(defaultEquals)
|
|
{
|
|
// Skipmaps must have binary depth of at least 2
|
|
cassert(BINARY_DEPTH >= 2);
|
|
|
|
S32 i;
|
|
for (i = 0; i < BINARY_DEPTH; i++)
|
|
{
|
|
mUpdate[i] = NULL;
|
|
}
|
|
mLevel = 1;
|
|
mCurrentp = *(mHead.mForward);
|
|
mCurrentOperatingp = *(mHead.mForward);
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second),
|
|
BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second))
|
|
: mInsertFirst(insert_first),
|
|
mEquals(equals)
|
|
{
|
|
// Skipmaps must have binary depth of at least 2
|
|
cassert(BINARY_DEPTH >= 2);
|
|
|
|
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 INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::~LLSkipMap()
|
|
{
|
|
removeAllData();
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::setInsertFirst(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second))
|
|
{
|
|
mInsertFirst = insert_first;
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::setEquals(BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second))
|
|
{
|
|
mEquals = equals;
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::addData(const INDEX_TYPE &index, DATA_TYPE datap)
|
|
{
|
|
S32 level;
|
|
LLSkipMapNode *current = &mHead;
|
|
LLSkipMapNode *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->mIndex, index)))
|
|
{
|
|
current = temp;
|
|
temp = *(current->mForward + level);
|
|
}
|
|
*(mUpdate + level) = current;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (level = mLevel - 1; level >= 0; level--)
|
|
{
|
|
temp = *(current->mForward + level);
|
|
while ( (temp)
|
|
&&(temp->mIndex < index))
|
|
{
|
|
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;
|
|
|
|
// replace the existing data if a node is already there
|
|
if ( (current)
|
|
&&(mEquals(current->mIndex, index)))
|
|
{
|
|
current->mData = datap;
|
|
return current->mData;
|
|
}
|
|
|
|
// now add the new node
|
|
S32 newlevel;
|
|
for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
|
|
{
|
|
if (rand() & 1)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
LLSkipMapNode *snode = new LLSkipMapNode(index, datap);
|
|
|
|
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 snode->mData;
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::addData(const INDEX_TYPE &index)
|
|
{
|
|
S32 level;
|
|
LLSkipMapNode *current = &mHead;
|
|
LLSkipMapNode *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->mIndex, index)))
|
|
{
|
|
current = temp;
|
|
temp = *(current->mForward + level);
|
|
}
|
|
*(mUpdate + level) = current;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (level = mLevel - 1; level >= 0; level--)
|
|
{
|
|
temp = *(current->mForward + level);
|
|
while ( (temp)
|
|
&&(temp->mIndex < index))
|
|
{
|
|
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 (rand() & 1)
|
|
break;
|
|
}
|
|
|
|
LLSkipMapNode *snode = new LLSkipMapNode(index);
|
|
|
|
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 snode->mData;
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getData(const INDEX_TYPE &index)
|
|
{
|
|
S32 level;
|
|
LLSkipMapNode *current = &mHead;
|
|
LLSkipMapNode *temp;
|
|
|
|
mNumberOfSteps = 0;
|
|
|
|
// 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->mIndex, index)))
|
|
{
|
|
current = temp;
|
|
temp = *(current->mForward + level);
|
|
mNumberOfSteps++;
|
|
}
|
|
*(mUpdate + level) = current;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (level = mLevel - 1; level >= 0; level--)
|
|
{
|
|
temp = *(current->mForward + level);
|
|
while ( (temp)
|
|
&&(temp->mIndex < index))
|
|
{
|
|
current = temp;
|
|
temp = *(current->mForward + level);
|
|
mNumberOfSteps++;
|
|
}
|
|
*(mUpdate + level) = current;
|
|
}
|
|
}
|
|
|
|
// we're now just in front of where we want to be . . . take one step forward
|
|
current = *current->mForward;
|
|
mNumberOfSteps++;
|
|
|
|
if ( (current)
|
|
&&(mEquals(current->mIndex, index)))
|
|
{
|
|
|
|
return current->mData;
|
|
}
|
|
|
|
// now add the new node
|
|
S32 newlevel;
|
|
for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
|
|
{
|
|
if (rand() & 1)
|
|
break;
|
|
}
|
|
|
|
LLSkipMapNode *snode = new LLSkipMapNode(index);
|
|
|
|
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 snode->mData;
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::operator[](const INDEX_TYPE &index)
|
|
{
|
|
|
|
return getData(index);
|
|
}
|
|
|
|
// If index present, returns data.
|
|
// If index not present, adds <index,NULL> and returns NULL.
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getData(const INDEX_TYPE &index, BOOL &b_new_entry)
|
|
{
|
|
S32 level;
|
|
LLSkipMapNode *current = &mHead;
|
|
LLSkipMapNode *temp;
|
|
|
|
mNumberOfSteps = 0;
|
|
|
|
// 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->mIndex, index)))
|
|
{
|
|
current = temp;
|
|
temp = *(current->mForward + level);
|
|
mNumberOfSteps++;
|
|
}
|
|
*(mUpdate + level) = current;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (level = mLevel - 1; level >= 0; level--)
|
|
{
|
|
temp = *(current->mForward + level);
|
|
while ( (temp)
|
|
&&(temp->mIndex < index))
|
|
{
|
|
current = temp;
|
|
temp = *(current->mForward + level);
|
|
mNumberOfSteps++;
|
|
}
|
|
*(mUpdate + level) = current;
|
|
}
|
|
}
|
|
|
|
// we're now just in front of where we want to be . . . take one step forward
|
|
mNumberOfSteps++;
|
|
current = *current->mForward;
|
|
|
|
if ( (current)
|
|
&&(mEquals(current->mIndex, index)))
|
|
{
|
|
|
|
return current->mData;
|
|
}
|
|
b_new_entry = TRUE;
|
|
addData(index);
|
|
|
|
return current->mData;
|
|
}
|
|
|
|
// Returns TRUE if data present in map.
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::checkData(const INDEX_TYPE &index)
|
|
{
|
|
S32 level;
|
|
LLSkipMapNode *current = &mHead;
|
|
LLSkipMapNode *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->mIndex, index)))
|
|
{
|
|
current = temp;
|
|
temp = *(current->mForward + level);
|
|
}
|
|
*(mUpdate + level) = current;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (level = mLevel - 1; level >= 0; level--)
|
|
{
|
|
temp = *(current->mForward + level);
|
|
while ( (temp)
|
|
&&(temp->mIndex < index))
|
|
{
|
|
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)
|
|
{
|
|
// Gets rid of some compiler ambiguity for the LLPointer<> templated class.
|
|
if (current->mData)
|
|
{
|
|
return mEquals(current->mIndex, index);
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Returns TRUE if key is present in map. This is useful if you
|
|
// are potentially storing NULL pointers in the map
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::checkKey(const INDEX_TYPE &index)
|
|
{
|
|
S32 level;
|
|
LLSkipMapNode *current = &mHead;
|
|
LLSkipMapNode *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->mIndex, index)))
|
|
{
|
|
current = temp;
|
|
temp = *(current->mForward + level);
|
|
}
|
|
*(mUpdate + level) = current;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (level = mLevel - 1; level >= 0; level--)
|
|
{
|
|
temp = *(current->mForward + level);
|
|
while ( (temp)
|
|
&&(temp->mIndex < index))
|
|
{
|
|
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->mIndex, index);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// If there, returns the data.
|
|
// If not, returns NULL.
|
|
// Never adds entries to the map.
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getIfThere(const INDEX_TYPE &index)
|
|
{
|
|
S32 level;
|
|
LLSkipMapNode *current = &mHead;
|
|
LLSkipMapNode *temp;
|
|
|
|
mNumberOfSteps = 0;
|
|
|
|
// 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->mIndex, index)))
|
|
{
|
|
current = temp;
|
|
temp = *(current->mForward + level);
|
|
mNumberOfSteps++;
|
|
}
|
|
*(mUpdate + level) = current;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (level = mLevel - 1; level >= 0; level--)
|
|
{
|
|
temp = *(current->mForward + level);
|
|
while ( (temp)
|
|
&&(temp->mIndex < index))
|
|
{
|
|
current = temp;
|
|
temp = *(current->mForward + level);
|
|
mNumberOfSteps++;
|
|
}
|
|
*(mUpdate + level) = current;
|
|
}
|
|
}
|
|
|
|
// we're now just in front of where we want to be . . . take one step forward
|
|
mNumberOfSteps++;
|
|
current = *current->mForward;
|
|
|
|
if (current)
|
|
{
|
|
if (mEquals(current->mIndex, index))
|
|
{
|
|
return current->mData;
|
|
}
|
|
}
|
|
|
|
// Avoid Linux compiler warning on returning NULL.
|
|
return DATA_TYPE();
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::reverseLookup(const DATA_TYPE datap)
|
|
{
|
|
LLSkipMapNode *current = &mHead;
|
|
|
|
while (current)
|
|
{
|
|
if (datap == current->mData)
|
|
{
|
|
|
|
return current->mIndex;
|
|
}
|
|
current = *current->mForward;
|
|
}
|
|
|
|
// not found! return NULL
|
|
return INDEX_TYPE();
|
|
}
|
|
|
|
// returns number of items in the list
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline S32 LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getLength()
|
|
{
|
|
U32 length = 0;
|
|
for (LLSkipMapNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0])
|
|
{
|
|
length++;
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeData(const INDEX_TYPE &index)
|
|
{
|
|
S32 level;
|
|
LLSkipMapNode *current = &mHead;
|
|
LLSkipMapNode *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->mIndex, index)))
|
|
{
|
|
current = temp;
|
|
temp = *(current->mForward + level);
|
|
}
|
|
*(mUpdate + level) = current;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (level = mLevel - 1; level >= 0; level--)
|
|
{
|
|
temp = *(current->mForward + level);
|
|
while ( (temp)
|
|
&&(temp->mIndex < index))
|
|
{
|
|
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->mIndex, index))
|
|
{
|
|
// nope!
|
|
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// do we need to fix current or currentop?
|
|
if (current == mCurrentp)
|
|
{
|
|
mCurrentp = *current->mForward;
|
|
}
|
|
|
|
if (current == mCurrentOperatingp)
|
|
{
|
|
mCurrentOperatingp = *current->mForward;
|
|
}
|
|
// 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);
|
|
}
|
|
|
|
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 INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeAllData()
|
|
{
|
|
LLSkipMapNode *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 INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::resetList()
|
|
{
|
|
mCurrentp = *(mHead.mForward);
|
|
mCurrentOperatingp = *(mHead.mForward);
|
|
}
|
|
|
|
|
|
// return the data currently pointed to
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentDataWithoutIncrement()
|
|
{
|
|
if (mCurrentOperatingp)
|
|
{
|
|
return mCurrentOperatingp->mData;
|
|
}
|
|
else
|
|
{
|
|
return DATA_TYPE();
|
|
}
|
|
}
|
|
|
|
// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentData()
|
|
{
|
|
if (mCurrentp)
|
|
{
|
|
mCurrentOperatingp = mCurrentp;
|
|
mCurrentp = mCurrentp->mForward[0];
|
|
return mCurrentOperatingp->mData;
|
|
}
|
|
else
|
|
{
|
|
// Basic types, like int, have default constructors that initialize
|
|
// them to zero. g++ 2.95 supports this. "int()" is zero.
|
|
// This also is nice for LLUUID()
|
|
return DATA_TYPE();
|
|
}
|
|
}
|
|
|
|
// same as getCurrentData() but a more intuitive name for the operation
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getNextData()
|
|
{
|
|
if (mCurrentp)
|
|
{
|
|
mCurrentOperatingp = mCurrentp;
|
|
mCurrentp = mCurrentp->mForward[0];
|
|
return mCurrentOperatingp->mData;
|
|
}
|
|
else
|
|
{
|
|
// Basic types, like int, have default constructors that initialize
|
|
// them to zero. g++ 2.95 supports this. "int()" is zero.
|
|
// This also is nice for LLUUID()
|
|
return DATA_TYPE();
|
|
}
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getNextKey()
|
|
{
|
|
if (mCurrentp)
|
|
{
|
|
mCurrentOperatingp = mCurrentp;
|
|
mCurrentp = mCurrentp->mForward[0];
|
|
return mCurrentOperatingp->mIndex;
|
|
}
|
|
else
|
|
{
|
|
return mHead.mIndex;
|
|
}
|
|
}
|
|
|
|
// return the key currently pointed to
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentKeyWithoutIncrement()
|
|
{
|
|
if (mCurrentOperatingp)
|
|
{
|
|
return mCurrentOperatingp->mIndex;
|
|
}
|
|
else
|
|
{
|
|
// See comment for getNextData()
|
|
return INDEX_TYPE();
|
|
}
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::notDone() const
|
|
{
|
|
if (mCurrentOperatingp)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
// remove the Node at mCurentOperatingp
|
|
// leave mCurrentp and mCurentOperatingp on the next entry
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeCurrentData()
|
|
{
|
|
if (mCurrentOperatingp)
|
|
{
|
|
removeData(mCurrentOperatingp->mIndex);
|
|
}
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::deleteCurrentData()
|
|
{
|
|
if (mCurrentOperatingp)
|
|
{
|
|
deleteData(mCurrentOperatingp->mIndex);
|
|
}
|
|
}
|
|
|
|
// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getFirstData()
|
|
{
|
|
mCurrentp = *(mHead.mForward);
|
|
mCurrentOperatingp = *(mHead.mForward);
|
|
if (mCurrentp)
|
|
{
|
|
mCurrentOperatingp = mCurrentp;
|
|
mCurrentp = mCurrentp->mForward[0];
|
|
return mCurrentOperatingp->mData;
|
|
}
|
|
else
|
|
{
|
|
// See comment for getNextData()
|
|
return DATA_TYPE();
|
|
}
|
|
}
|
|
|
|
template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
|
|
inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getFirstKey()
|
|
{
|
|
mCurrentp = *(mHead.mForward);
|
|
mCurrentOperatingp = *(mHead.mForward);
|
|
if (mCurrentp)
|
|
{
|
|
mCurrentOperatingp = mCurrentp;
|
|
mCurrentp = mCurrentp->mForward[0];
|
|
return mCurrentOperatingp->mIndex;
|
|
}
|
|
else
|
|
{
|
|
return mHead.mIndex;
|
|
}
|
|
}
|
|
|
|
#endif
|