902 lines
21 KiB
C++
902 lines
21 KiB
C++
/**
|
|
* @file lllocalidhashmap.h
|
|
* @brief Map specialized for dealing with local ids
|
|
*
|
|
* $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_LLLOCALIDHASHMAP_H
|
|
#define LL_LLLOCALIDHASHMAP_H
|
|
|
|
#include "stdtypes.h"
|
|
#include "llerror.h"
|
|
|
|
const S32 MAX_ITERS = 4;
|
|
// LocalID hash map
|
|
|
|
//
|
|
// LLLocalIDHashNode
|
|
//
|
|
|
|
template <class DATA, int SIZE>
|
|
class LLLocalIDHashNode
|
|
{
|
|
public:
|
|
LLLocalIDHashNode();
|
|
|
|
public:
|
|
S32 mCount;
|
|
U32 mKey[SIZE];
|
|
DATA mData[SIZE];
|
|
LLLocalIDHashNode<DATA, SIZE> *mNextNodep;
|
|
};
|
|
|
|
|
|
//
|
|
// LLLocalIDHashNode implementation
|
|
//
|
|
template <class DATA, int SIZE>
|
|
LLLocalIDHashNode<DATA, SIZE>::LLLocalIDHashNode()
|
|
{
|
|
mCount = 0;
|
|
mNextNodep = NULL;
|
|
}
|
|
|
|
//
|
|
// LLLocalIDHashMapIter
|
|
//
|
|
template <class DATA_TYPE, int SIZE>
|
|
class LLLocalIDHashMap;
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
class LLLocalIDHashMapIter
|
|
{
|
|
public:
|
|
LLLocalIDHashMapIter(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp);
|
|
~LLLocalIDHashMapIter();
|
|
|
|
void setMap(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp);
|
|
inline void first();
|
|
inline void next();
|
|
inline DATA_TYPE& current(); // *NOTE: Deprecate? Phoenix 2005-04-15
|
|
inline BOOL done() const;
|
|
inline S32 currentBin() const;
|
|
inline void setBin(S32 bin);
|
|
|
|
DATA_TYPE& operator*() const
|
|
{
|
|
return mCurHashNodep->mData[mCurHashNodeKey];
|
|
}
|
|
DATA_TYPE* operator->() const
|
|
{
|
|
return &(operator*());
|
|
}
|
|
|
|
LLLocalIDHashMap<DATA_TYPE, SIZE> *mHashMapp;
|
|
LLLocalIDHashNode<DATA_TYPE, SIZE> *mCurHashNodep;
|
|
|
|
S32 mCurHashMapNodeNum;
|
|
S32 mCurHashNodeKey;
|
|
|
|
DATA_TYPE mNull;
|
|
|
|
S32 mIterID;
|
|
};
|
|
|
|
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
class LLLocalIDHashMap
|
|
{
|
|
public:
|
|
friend class LLLocalIDHashMapIter<DATA_TYPE, SIZE>;
|
|
|
|
LLLocalIDHashMap(); // DO NOT use this unless you explicitly setNull, or the data type constructs a "null"
|
|
// object by default
|
|
// basic constructor including sorter
|
|
LLLocalIDHashMap(const DATA_TYPE &null_data);
|
|
// Hack, this should really be a const ref, but I'm not doing it that way because the sim
|
|
// usually uses pointers.
|
|
~LLLocalIDHashMap();
|
|
|
|
inline DATA_TYPE &get(const U32 local_id);
|
|
inline BOOL check(const U32 local_id) const;
|
|
inline DATA_TYPE &set(const U32 local_id, const DATA_TYPE data);
|
|
inline BOOL remove(const U32 local_id);
|
|
void removeAll();
|
|
|
|
void setNull(const DATA_TYPE data) { mNull = data; }
|
|
|
|
inline S32 getLength() const; // Warning, NOT O(1!)
|
|
|
|
void dumpIter();
|
|
void dumpBin(U32 bin);
|
|
|
|
protected:
|
|
// Only used by the iterator.
|
|
void addIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter);
|
|
void removeIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter);
|
|
|
|
// Remove the item and shift all items afterward down the list,
|
|
// fixing up iterators as we go.
|
|
BOOL removeWithShift(const U32 local_id);
|
|
|
|
protected:
|
|
LLLocalIDHashNode<DATA_TYPE, SIZE> mNodes[256];
|
|
|
|
S32 mIterCount;
|
|
LLLocalIDHashMapIter<DATA_TYPE, SIZE> *mIters[MAX_ITERS];
|
|
|
|
DATA_TYPE mNull;
|
|
};
|
|
|
|
|
|
//
|
|
// LLLocalIDHashMap implementation
|
|
//
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
LLLocalIDHashMap<DATA_TYPE, SIZE>::LLLocalIDHashMap()
|
|
: mIterCount(0),
|
|
mNull()
|
|
{
|
|
S32 i;
|
|
for (i = 0; i < MAX_ITERS; i++)
|
|
{
|
|
mIters[i] = NULL;
|
|
}
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
LLLocalIDHashMap<DATA_TYPE, SIZE>::LLLocalIDHashMap(const DATA_TYPE &null_data)
|
|
: mIterCount(0),
|
|
mNull(null_data)
|
|
{
|
|
S32 i;
|
|
for (i = 0; i < MAX_ITERS; i++)
|
|
{
|
|
mIters[i] = NULL;
|
|
}
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
LLLocalIDHashMap<DATA_TYPE, SIZE>::~LLLocalIDHashMap()
|
|
{
|
|
S32 i;
|
|
for (i = 0; i < MAX_ITERS; i++)
|
|
{
|
|
if (mIters[i])
|
|
{
|
|
mIters[i]->mHashMapp = NULL;
|
|
mIterCount--;
|
|
}
|
|
}
|
|
removeAll();
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
void LLLocalIDHashMap<DATA_TYPE, SIZE>::removeAll()
|
|
{
|
|
S32 bin;
|
|
for (bin = 0; bin < 256; bin++)
|
|
{
|
|
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
|
|
|
|
BOOL first = TRUE;
|
|
do // First node guaranteed to be there
|
|
{
|
|
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.
|
|
|
|
LLLocalIDHashNode<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;
|
|
}
|
|
} while (nodep);
|
|
}
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
void LLLocalIDHashMap<DATA_TYPE, SIZE>::dumpIter()
|
|
{
|
|
std::cout << "Hash map with " << mIterCount << " iterators" << std::endl;
|
|
|
|
std::cout << "Hash Map Iterators:" << std::endl;
|
|
S32 i;
|
|
for (i = 0; i < MAX_ITERS; i++)
|
|
{
|
|
if (mIters[i])
|
|
{
|
|
LL_INFOS() << i << " " << mIters[i]->mCurHashNodep << " " << mIters[i]->mCurHashNodeKey << LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
LL_INFOS() << i << "null" << LL_ENDL;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
void LLLocalIDHashMap<DATA_TYPE, SIZE>::dumpBin(U32 bin)
|
|
{
|
|
std::cout << "Dump bin " << bin << std::endl;
|
|
|
|
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
|
|
S32 node = 0;
|
|
do // First node guaranteed to be there.
|
|
{
|
|
std::cout << "Bin " << bin
|
|
<< " node " << node
|
|
<< " count " << nodep->mCount
|
|
<< " contains " << std::flush;
|
|
|
|
S32 i;
|
|
for (i = 0; i < nodep->mCount; i++)
|
|
{
|
|
std::cout << nodep->mData[i] << " " << std::flush;
|
|
}
|
|
|
|
std::cout << std::endl;
|
|
|
|
nodep = nodep->mNextNodep;
|
|
node++;
|
|
} while (nodep);
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
inline S32 LLLocalIDHashMap<DATA_TYPE, SIZE>::getLength() const
|
|
{
|
|
S32 count = 0;
|
|
S32 bin;
|
|
for (bin = 0; bin < 256; bin++)
|
|
{
|
|
const LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
|
|
while (nodep)
|
|
{
|
|
count += nodep->mCount;
|
|
nodep = nodep->mNextNodep;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
inline DATA_TYPE &LLLocalIDHashMap<DATA_TYPE, SIZE>::get(const U32 local_id)
|
|
{
|
|
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff];
|
|
|
|
do // First node guaranteed to be there
|
|
{
|
|
S32 i;
|
|
const S32 count = nodep->mCount;
|
|
|
|
// Iterate through all members of this node
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (nodep->mKey[i] == local_id)
|
|
{
|
|
// We found it.
|
|
return nodep->mData[i];
|
|
}
|
|
}
|
|
|
|
// Done with all objects in this node, go to the next.
|
|
nodep = nodep->mNextNodep;
|
|
} while (nodep);
|
|
|
|
return mNull;
|
|
}
|
|
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
inline BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::check(const U32 local_id) const
|
|
{
|
|
const LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff];
|
|
|
|
do // First node guaranteed to be there
|
|
{
|
|
S32 i;
|
|
const S32 count = nodep->mCount;
|
|
|
|
// Iterate through all members of this node
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (nodep->mKey[i] == local_id)
|
|
{
|
|
// We found it.
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// Done with all objects in this node, go to the next.
|
|
nodep = nodep->mNextNodep;
|
|
} while (nodep);
|
|
|
|
// Didn't find anything
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
inline DATA_TYPE &LLLocalIDHashMap<DATA_TYPE, SIZE>::set(const U32 local_id, 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.
|
|
|
|
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff];
|
|
|
|
while (1)
|
|
{
|
|
const S32 count = nodep->mCount;
|
|
|
|
S32 i;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (nodep->mKey[i] == local_id)
|
|
{
|
|
// 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] = local_id;
|
|
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 LLLocalIDHashNode<DATA_TYPE, SIZE>;
|
|
nodep->mNextNodep->mKey[0] = local_id;
|
|
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 LLLocalIDHashMap<DATA_TYPE, SIZE>::remove(const U32 local_id)
|
|
{
|
|
// 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.
|
|
|
|
const S32 node_index = local_id & 0xff;
|
|
|
|
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[node_index];
|
|
|
|
// A modification of the standard search algorithm.
|
|
do // First node guaranteed to be there
|
|
{
|
|
const S32 count = nodep->mCount;
|
|
|
|
S32 i;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (nodep->mKey[i] == local_id)
|
|
{
|
|
// If we're removing the item currently pointed to by one
|
|
// or more iterators, we can just swap in the last item
|
|
// and back the iterator(s) up by one.
|
|
// Otherwise, we need to do a slow and safe shift of all
|
|
// items back to one position to fill the hole and fix up
|
|
// all iterators we find.
|
|
BOOL need_shift = FALSE;
|
|
S32 cur_iter;
|
|
if (mIterCount)
|
|
{
|
|
for (cur_iter = 0; cur_iter < MAX_ITERS; cur_iter++)
|
|
{
|
|
if (mIters[cur_iter])
|
|
{
|
|
// We only care if the hash map node is on the one
|
|
// that we're working on. If it's before, we've already
|
|
// traversed it, if it's after, changing the order doesn't
|
|
// matter.
|
|
if (mIters[cur_iter]->mCurHashMapNodeNum == node_index)
|
|
{
|
|
if ((mIters[cur_iter]->mCurHashNodep == nodep)
|
|
&& (mIters[cur_iter]->mCurHashNodeKey == i))
|
|
{
|
|
// it's on the one we're deleting, we'll
|
|
// fix the iterator quickly below.
|
|
}
|
|
else
|
|
{
|
|
// We're trying to remove an item on this
|
|
// iterator's chain that this
|
|
// iterator doesn't point to! We need to do
|
|
// the slow remove-and-shift-down case.
|
|
need_shift = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Removing an item that isn't pointed to by all iterators
|
|
if (need_shift)
|
|
{
|
|
return removeWithShift(local_id);
|
|
}
|
|
|
|
// Fix the iterators that point to this node/i pair, the
|
|
// one we're deleting
|
|
for (cur_iter = 0; cur_iter < MAX_ITERS; cur_iter++)
|
|
{
|
|
if (mIters[cur_iter])
|
|
{
|
|
// We only care if the hash map node is on the one
|
|
// that we're working on. If it's before, we've already
|
|
// traversed it, if it's after, changing the order doesn't
|
|
// matter.
|
|
if (mIters[cur_iter]->mCurHashMapNodeNum == node_index)
|
|
{
|
|
if ((mIters[cur_iter]->mCurHashNodep == nodep)
|
|
&& (mIters[cur_iter]->mCurHashNodeKey == i))
|
|
{
|
|
// We can handle the case where we're deleting
|
|
// the element we're on trivially (sort of).
|
|
if (nodep->mCount > 1)
|
|
{
|
|
// If we're not going to delete this node,
|
|
// it's OK.
|
|
mIters[cur_iter]->mCurHashNodeKey--;
|
|
}
|
|
else
|
|
{
|
|
// We're going to delete this node, because this
|
|
// is the last element on it.
|
|
|
|
// Find the next node, and then back up one.
|
|
mIters[cur_iter]->next();
|
|
mIters[cur_iter]->mCurHashNodeKey--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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.
|
|
|
|
LLLocalIDHashNode<DATA_TYPE, SIZE> *prevp = &mNodes[node_index];
|
|
LLLocalIDHashNode<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[local_id & 0xff])
|
|
{
|
|
// 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;
|
|
} while (nodep);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::removeWithShift(const U32 local_id)
|
|
{
|
|
const S32 node_index = local_id & 0xFF;
|
|
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[node_index];
|
|
LLLocalIDHashNode<DATA_TYPE, SIZE>* prevp = NULL;
|
|
BOOL found = FALSE;
|
|
|
|
do // First node guaranteed to be there
|
|
{
|
|
const S32 count = nodep->mCount;
|
|
S32 i;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (nodep->mKey[i] == local_id)
|
|
{
|
|
// Found the item. Start shifting items from later
|
|
// in the list over this item.
|
|
found = TRUE;
|
|
}
|
|
|
|
if (found)
|
|
{
|
|
// If there is an iterator on this node, we need to
|
|
// back it up.
|
|
S32 cur_iter;
|
|
for (cur_iter = 0; cur_iter <MAX_ITERS; cur_iter++)
|
|
{
|
|
LLLocalIDHashMapIter<DATA_TYPE, SIZE>* iter;
|
|
iter = mIters[cur_iter];
|
|
// If an iterator is on this node,i pair, then back it up.
|
|
if (iter
|
|
&& iter->mCurHashMapNodeNum == node_index
|
|
&& iter->mCurHashNodep == nodep
|
|
&& iter->mCurHashNodeKey == i)
|
|
{
|
|
if (i > 0)
|
|
{
|
|
// Don't need to move iterator nodep, since
|
|
// we're in the same node.
|
|
iter->mCurHashNodeKey--;
|
|
}
|
|
else if (prevp)
|
|
{
|
|
// need to go the previous node, last item
|
|
iter->mCurHashNodep = prevp;
|
|
iter->mCurHashNodeKey = prevp->mCount - 1;
|
|
}
|
|
else
|
|
{
|
|
// we're on the first item in the list, but
|
|
// need to go back anyhow.
|
|
|
|
// BUG: If this deletion empties the list,
|
|
// iter->done() will be wrong until
|
|
// iter->next() is called.
|
|
iter->mCurHashNodeKey = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Copy data from the next position into this position.
|
|
if (i < count-1)
|
|
{
|
|
// we're not on the last item in the node,
|
|
// so we can copy within the node
|
|
nodep->mKey[i] = nodep->mKey[i+1];
|
|
nodep->mData[i] = nodep->mData[i+1];
|
|
}
|
|
else if (nodep->mNextNodep)
|
|
{
|
|
// we're on the last item in the node,
|
|
// but there's a next node we can copy from
|
|
nodep->mKey[i] = nodep->mNextNodep->mKey[0];
|
|
nodep->mData[i] = nodep->mNextNodep->mData[0];
|
|
}
|
|
else
|
|
{
|
|
// We're on the last position in the list.
|
|
// No one to copy from. Replace with nothing.
|
|
nodep->mKey[i] = 0;
|
|
nodep->mData[i] = mNull;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Last node in chain, so delete the last node
|
|
if (found
|
|
&& !nodep->mNextNodep)
|
|
{
|
|
// delete the last item off the last node
|
|
nodep->mCount--;
|
|
|
|
if (nodep->mCount == 0)
|
|
{
|
|
// We deleted the last element!
|
|
if (nodep != &mNodes[node_index])
|
|
{
|
|
// Always have a prevp if we're not the head.
|
|
llassert(prevp);
|
|
|
|
// 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 nodep;
|
|
nodep = NULL;
|
|
}
|
|
}
|
|
|
|
// Deleted last item in chain, so we're done.
|
|
return found;
|
|
}
|
|
|
|
prevp = nodep;
|
|
nodep = nodep->mNextNodep;
|
|
} while (nodep);
|
|
|
|
return found;
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
void LLLocalIDHashMap<DATA_TYPE, SIZE>::removeIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter)
|
|
{
|
|
S32 i;
|
|
for (i = 0; i < MAX_ITERS; i++)
|
|
{
|
|
if (mIters[i] == iter)
|
|
{
|
|
mIters[i] = NULL;
|
|
mIterCount--;
|
|
return;
|
|
}
|
|
}
|
|
LL_ERRS() << "Iterator " << iter << " not found for removal in hash map!" << LL_ENDL;
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
void LLLocalIDHashMap<DATA_TYPE, SIZE>::addIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter)
|
|
{
|
|
S32 i;
|
|
for (i = 0; i < MAX_ITERS; i++)
|
|
{
|
|
if (mIters[i] == NULL)
|
|
{
|
|
mIters[i] = iter;
|
|
mIterCount++;
|
|
return;
|
|
}
|
|
}
|
|
LL_ERRS() << "More than " << MAX_ITERS << " iterating over a map simultaneously!" << LL_ENDL;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// LLLocalIDHashMapIter Implementation
|
|
//
|
|
template <class DATA_TYPE, int SIZE>
|
|
LLLocalIDHashMapIter<DATA_TYPE, SIZE>::LLLocalIDHashMapIter(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp)
|
|
{
|
|
mHashMapp = NULL;
|
|
setMap(hash_mapp);
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
LLLocalIDHashMapIter<DATA_TYPE, SIZE>::~LLLocalIDHashMapIter()
|
|
{
|
|
if (mHashMapp)
|
|
{
|
|
mHashMapp->removeIter(this);
|
|
}
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::setMap(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp)
|
|
{
|
|
if (mHashMapp)
|
|
{
|
|
mHashMapp->removeIter(this);
|
|
}
|
|
mHashMapp = hash_mapp;
|
|
if (mHashMapp)
|
|
{
|
|
mHashMapp->addIter(this);
|
|
}
|
|
|
|
mCurHashNodep = NULL;
|
|
mCurHashMapNodeNum = -1;
|
|
mCurHashNodeKey = 0;
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
inline void LLLocalIDHashMapIter<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)
|
|
{
|
|
|
|
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 LLLocalIDHashMapIter<DATA_TYPE, SIZE>::done() const
|
|
{
|
|
return mCurHashNodep ? FALSE : TRUE;
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
inline S32 LLLocalIDHashMapIter<DATA_TYPE, SIZE>::currentBin() const
|
|
{
|
|
if ( (mCurHashMapNodeNum > 255)
|
|
||(mCurHashMapNodeNum < 0))
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return mCurHashMapNodeNum;
|
|
}
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::setBin(S32 bin)
|
|
{
|
|
// Iterate through until we find the first non-empty node;
|
|
S32 i;
|
|
bin = llclamp(bin, 0, 255);
|
|
for (i = bin; i < 256; i++)
|
|
{
|
|
if (mHashMapp->mNodes[i].mCount)
|
|
{
|
|
|
|
mCurHashNodep = &mHashMapp->mNodes[i];
|
|
mCurHashMapNodeNum = i;
|
|
mCurHashNodeKey = 0;
|
|
return;
|
|
}
|
|
}
|
|
for (i = 0; i < bin; i++)
|
|
{
|
|
if (mHashMapp->mNodes[i].mCount)
|
|
{
|
|
|
|
mCurHashNodep = &mHashMapp->mNodes[i];
|
|
mCurHashMapNodeNum = i;
|
|
mCurHashNodeKey = 0;
|
|
return;
|
|
}
|
|
}
|
|
// Completely empty!
|
|
mCurHashNodep = NULL;
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
inline DATA_TYPE &LLLocalIDHashMapIter<DATA_TYPE, SIZE>::current()
|
|
{
|
|
if (!mCurHashNodep)
|
|
{
|
|
return mNull;
|
|
}
|
|
return mCurHashNodep->mData[mCurHashNodeKey];
|
|
}
|
|
|
|
template <class DATA_TYPE, int SIZE>
|
|
inline void LLLocalIDHashMapIter<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;
|
|
return;
|
|
}
|
|
|
|
#endif // LL_LLLOCALIDHASHMAP_H
|