PageRenderTime 50ms CodeModel.GetById 2ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/lllocalidhashmap.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 895 lines | 612 code | 120 blank | 163 comment | 102 complexity | 5fd34cdb6c3c498871e028e588bde9e9 MD5 | raw file
  1/** 
  2 * @file lllocalidhashmap.h
  3 * @brief Map specialized for dealing with local ids
  4 *
  5 * $LicenseInfo:firstyear=2003&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#ifndef LL_LLLOCALIDHASHMAP_H
 28#define LL_LLLOCALIDHASHMAP_H
 29
 30#include "stdtypes.h"
 31#include "llerror.h"
 32
 33const S32 MAX_ITERS = 4;
 34// LocalID hash map
 35
 36//
 37// LLLocalIDHashNode
 38//
 39
 40template <class DATA, int SIZE>
 41class LLLocalIDHashNode
 42{
 43public:
 44	LLLocalIDHashNode();
 45
 46public:
 47	S32 mCount;
 48	U32	mKey[SIZE];
 49	DATA mData[SIZE];
 50	LLLocalIDHashNode<DATA, SIZE> *mNextNodep;
 51};
 52
 53
 54//
 55// LLLocalIDHashNode implementation
 56//
 57template <class DATA, int SIZE>
 58LLLocalIDHashNode<DATA, SIZE>::LLLocalIDHashNode()
 59{
 60	mCount = 0;
 61	mNextNodep = NULL;
 62}
 63
 64//
 65// LLLocalIDHashMapIter
 66//
 67template <class DATA_TYPE, int SIZE>
 68class LLLocalIDHashMap;
 69
 70template <class DATA_TYPE, int SIZE>
 71class LLLocalIDHashMapIter
 72{
 73public:
 74	LLLocalIDHashMapIter(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp);
 75	~LLLocalIDHashMapIter();
 76
 77	void setMap(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp);
 78	inline void first();
 79	inline void next();
 80	inline DATA_TYPE& current(); // *NOTE: Deprecate? Phoenix 2005-04-15
 81	inline BOOL done() const;
 82	inline S32  currentBin() const;
 83	inline void setBin(S32 bin);
 84
 85	DATA_TYPE& operator*() const
 86	{
 87		return mCurHashNodep->mData[mCurHashNodeKey];
 88	}
 89	DATA_TYPE* operator->() const
 90	{
 91		return &(operator*());
 92	}
 93
 94	LLLocalIDHashMap<DATA_TYPE, SIZE> *mHashMapp;
 95	LLLocalIDHashNode<DATA_TYPE, SIZE> *mCurHashNodep;
 96
 97	S32 mCurHashMapNodeNum;
 98	S32 mCurHashNodeKey;
 99
100	DATA_TYPE mNull;
101
102	S32 mIterID;
103};
104
105
106
107template <class DATA_TYPE, int SIZE>
108class LLLocalIDHashMap
109{
110public:
111	friend class LLLocalIDHashMapIter<DATA_TYPE, SIZE>;
112
113	LLLocalIDHashMap(); // DO NOT use this unless you explicitly setNull, or the data type constructs a "null"
114						// object by default
115	// basic constructor including sorter
116	LLLocalIDHashMap(const DATA_TYPE &null_data);
117	// Hack, this should really be a const ref, but I'm not doing it that way because the sim
118	// usually uses pointers.
119	~LLLocalIDHashMap();
120
121	inline DATA_TYPE &get(const U32 local_id);
122	inline BOOL check(const U32 local_id) const;
123	inline DATA_TYPE &set(const U32 local_id, const DATA_TYPE data);
124	inline BOOL remove(const U32 local_id);
125	void removeAll();
126
127	void setNull(const DATA_TYPE data) { mNull = data; }
128
129	inline S32 getLength() const; // Warning, NOT O(1!)
130
131	void dumpIter();
132	void dumpBin(U32 bin);
133
134protected:
135	// Only used by the iterator.
136	void addIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter);
137	void removeIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter);
138
139	// Remove the item and shift all items afterward down the list,
140	// fixing up iterators as we go.
141	BOOL removeWithShift(const U32 local_id);
142
143protected:
144	LLLocalIDHashNode<DATA_TYPE, SIZE> mNodes[256];
145
146	S32 mIterCount;
147	LLLocalIDHashMapIter<DATA_TYPE, SIZE> *mIters[MAX_ITERS];
148
149	DATA_TYPE mNull;
150};
151
152
153//
154// LLLocalIDHashMap implementation
155//
156
157template <class DATA_TYPE, int SIZE>
158LLLocalIDHashMap<DATA_TYPE, SIZE>::LLLocalIDHashMap()
159:	mIterCount(0),
160	mNull()
161{
162	S32 i;
163	for (i = 0; i < MAX_ITERS; i++)
164	{
165		mIters[i] = NULL;
166	}
167}
168
169template <class DATA_TYPE, int SIZE>
170LLLocalIDHashMap<DATA_TYPE, SIZE>::LLLocalIDHashMap(const DATA_TYPE &null_data)
171:	mIterCount(0),
172	mNull(null_data)
173{
174	S32 i;
175	for (i = 0; i < MAX_ITERS; i++)
176	{
177		mIters[i] = NULL;
178	}
179}
180
181template <class DATA_TYPE, int SIZE>
182LLLocalIDHashMap<DATA_TYPE, SIZE>::~LLLocalIDHashMap()
183{
184	S32 i;
185	for (i = 0; i < MAX_ITERS; i++)
186	{
187		if (mIters[i])
188		{
189			mIters[i]->mHashMapp = NULL;
190			mIterCount--;
191		}
192	}
193	removeAll();
194}
195
196template <class DATA_TYPE, int SIZE>
197void LLLocalIDHashMap<DATA_TYPE, SIZE>::removeAll()
198{
199	S32 bin;
200	for (bin = 0; bin < 256; bin++)
201	{
202		LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
203
204		BOOL first = TRUE;
205		do // First node guaranteed to be there
206		{
207			S32 i;
208			const S32 count = nodep->mCount;
209
210			// Iterate through all members of this node
211			for (i = 0; i < count; i++)
212			{
213				nodep->mData[i] = mNull;
214			}
215
216			nodep->mCount = 0;
217			// Done with all objects in this node, go to the next.
218
219			LLLocalIDHashNode<DATA_TYPE, SIZE>* curp = nodep;
220			nodep = nodep->mNextNodep;
221
222			// Delete the node if it's not the first node
223			if (first)
224			{
225				first = FALSE;
226				curp->mNextNodep = NULL;
227			}
228			else
229			{
230				delete curp;
231			}
232		} while (nodep);
233	}
234}
235
236template <class DATA_TYPE, int SIZE>
237void LLLocalIDHashMap<DATA_TYPE, SIZE>::dumpIter()
238{
239	std::cout << "Hash map with " << mIterCount << " iterators" << std::endl;
240
241	std::cout << "Hash Map Iterators:" << std::endl;
242	S32 i;
243	for (i = 0; i < MAX_ITERS; i++)
244	{
245		if (mIters[i])
246		{
247			llinfos << i << " " << mIters[i]->mCurHashNodep << " " << mIters[i]->mCurHashNodeKey << llendl;
248		}
249		else
250		{
251			llinfos << i << "null" << llendl;
252		}
253	}
254}
255
256template <class DATA_TYPE, int SIZE>
257void LLLocalIDHashMap<DATA_TYPE, SIZE>::dumpBin(U32 bin)
258{
259	std::cout << "Dump bin " << bin << std::endl;
260
261	LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
262	S32 node = 0;
263	do // First node guaranteed to be there.
264	{
265		std::cout << "Bin " << bin 
266			<< " node " << node
267			<< " count " << nodep->mCount
268			<< " contains " << std::flush;
269
270		S32 i;
271		for (i = 0; i < nodep->mCount; i++)
272		{
273			std::cout << nodep->mData[i] << " " << std::flush;
274		}
275
276		std::cout << std::endl;
277
278		nodep = nodep->mNextNodep;
279		node++;
280	} while (nodep);
281}
282
283template <class DATA_TYPE, int SIZE>
284inline S32 LLLocalIDHashMap<DATA_TYPE, SIZE>::getLength() const
285{
286	S32 count = 0;
287	S32 bin;
288	for (bin = 0; bin < 256; bin++)
289	{
290		const LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
291		while (nodep)
292		{
293			count += nodep->mCount;
294			nodep = nodep->mNextNodep;
295		}
296	}
297	return count;
298}
299
300template <class DATA_TYPE, int SIZE>
301inline DATA_TYPE &LLLocalIDHashMap<DATA_TYPE, SIZE>::get(const U32 local_id)
302{
303	LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff];
304
305	do // First node guaranteed to be there
306	{
307		S32 i;
308		const S32 count = nodep->mCount;
309
310		// Iterate through all members of this node
311		for (i = 0; i < count; i++)
312		{
313			if (nodep->mKey[i] == local_id)
314			{
315				// We found it.
316				return nodep->mData[i];
317			}
318		}
319
320		// Done with all objects in this node, go to the next.
321		nodep = nodep->mNextNodep;
322	} while (nodep);
323
324	return mNull;
325}
326
327
328template <class DATA_TYPE, int SIZE>
329inline BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::check(const U32 local_id) const
330{
331	const LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff];
332
333	do // First node guaranteed to be there
334	{
335		S32 i;
336		const S32 count = nodep->mCount;
337
338		// Iterate through all members of this node
339		for (i = 0; i < count; i++)
340		{
341			if (nodep->mKey[i] == local_id)
342			{
343				// We found it.
344				return TRUE;
345			}
346		}
347
348		// Done with all objects in this node, go to the next.
349		nodep = nodep->mNextNodep;
350	} while (nodep);
351
352	// Didn't find anything
353	return FALSE;
354}
355
356
357template <class DATA_TYPE, int SIZE>
358inline DATA_TYPE &LLLocalIDHashMap<DATA_TYPE, SIZE>::set(const U32 local_id, const DATA_TYPE data)
359{
360	// Set is just like a normal find, except that if we find a match
361	// we replace it with the input value.
362	// If we don't find a match, we append to the end of the list.
363
364	LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff];
365
366	while (1)
367	{
368		const S32 count = nodep->mCount;
369
370		S32 i;
371		for (i = 0; i < count; i++)
372		{
373			if (nodep->mKey[i] == local_id)
374			{
375				// We found a match for this key, replace the data with
376				// the incoming data.
377				nodep->mData[i] = data;
378				return nodep->mData[i];
379			}
380		}
381		if (!nodep->mNextNodep)
382		{
383			// We've iterated through all of the keys without finding a match
384			if (i < SIZE)
385			{
386				// There's still some space on this node, append
387				// the key and data to it.
388				nodep->mKey[i] = local_id;
389				nodep->mData[i] = data;
390				nodep->mCount++;
391
392				return nodep->mData[i];
393			}
394			else
395			{
396				// This node is full, append a new node to the end.
397				nodep->mNextNodep = new LLLocalIDHashNode<DATA_TYPE, SIZE>;
398				nodep->mNextNodep->mKey[0] = local_id;
399				nodep->mNextNodep->mData[0] = data;
400				nodep->mNextNodep->mCount = 1;
401
402				return nodep->mNextNodep->mData[0];
403			}
404		}
405
406		// No match on this node, go to the next
407		nodep = nodep->mNextNodep;
408	}
409}
410
411
412template <class DATA_TYPE, int SIZE>
413inline BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::remove(const U32 local_id)
414{
415	// Remove is the trickiest operation.
416	// What we want to do is swap the last element of the last
417	// node if we find the one that we want to remove, but we have
418	// to deal with deleting the node from the tail if it's empty, but
419	// NOT if it's the only node left.
420
421	const S32 node_index = local_id & 0xff;
422
423	LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[node_index];
424
425	// A modification of the standard search algorithm.
426	do // First node guaranteed to be there
427	{
428		const S32 count = nodep->mCount;
429
430		S32 i;
431		for (i = 0; i < count; i++)
432		{
433			if (nodep->mKey[i] == local_id)
434			{
435				// If we're removing the item currently pointed to by one
436				// or more iterators, we can just swap in the last item
437				// and back the iterator(s) up by one.
438				// Otherwise, we need to do a slow and safe shift of all
439				// items back to one position to fill the hole and fix up 
440				// all iterators we find.
441				BOOL need_shift = FALSE;
442				S32 cur_iter;
443				if (mIterCount)
444				{
445					for (cur_iter = 0; cur_iter < MAX_ITERS; cur_iter++)
446					{
447						if (mIters[cur_iter])
448						{
449							// We only care if the hash map node is on the one
450							// that we're working on.  If it's before, we've already
451							// traversed it, if it's after, changing the order doesn't
452							// matter.
453							if (mIters[cur_iter]->mCurHashMapNodeNum == node_index)
454							{
455								if ((mIters[cur_iter]->mCurHashNodep == nodep)
456									&& (mIters[cur_iter]->mCurHashNodeKey == i))
457								{
458									// it's on the one we're deleting, we'll
459									// fix the iterator quickly below.
460								}
461								else
462								{
463									// We're trying to remove an item on this
464									// iterator's chain that this
465									// iterator doesn't point to!  We need to do
466									// the slow remove-and-shift-down case.
467									need_shift = TRUE;
468								}
469							}
470						}
471					}
472				}
473
474				// Removing an item that isn't pointed to by all iterators
475				if (need_shift)
476				{
477					return removeWithShift(local_id);
478				}
479
480				// Fix the iterators that point to this node/i pair, the
481				// one we're deleting
482				for (cur_iter = 0; cur_iter < MAX_ITERS; cur_iter++)
483				{
484					if (mIters[cur_iter])
485					{
486						// We only care if the hash map node is on the one
487						// that we're working on.  If it's before, we've already
488						// traversed it, if it's after, changing the order doesn't
489						// matter.
490						if (mIters[cur_iter]->mCurHashMapNodeNum == node_index)
491						{
492							if ((mIters[cur_iter]->mCurHashNodep == nodep)
493								&& (mIters[cur_iter]->mCurHashNodeKey == i))
494							{
495								// We can handle the case where we're deleting 
496								// the element we're on trivially (sort of).
497								if (nodep->mCount > 1)
498								{
499									// If we're not going to delete this node,
500									// it's OK.
501									mIters[cur_iter]->mCurHashNodeKey--;
502								}
503								else
504								{
505									// We're going to delete this node, because this
506									// is the last element on it.
507									
508									// Find the next node, and then back up one.
509									mIters[cur_iter]->next();
510									mIters[cur_iter]->mCurHashNodeKey--;
511								}
512							}
513						}
514					}
515				}
516
517				// We found the node that we want to remove.
518				// Find the last (and next-to-last) node, and the index of the last
519				// element.  We could conceviably start from the node we're on,
520				// but that makes it more complicated, this is easier.
521
522				LLLocalIDHashNode<DATA_TYPE, SIZE> *prevp = &mNodes[node_index];
523				LLLocalIDHashNode<DATA_TYPE, SIZE> *lastp = prevp;
524
525				// Find the last and next-to-last
526				while (lastp->mNextNodep)
527				{
528					prevp = lastp;
529					lastp = lastp->mNextNodep;
530				}
531
532				// First, swap in the last to the current location.
533				nodep->mKey[i] = lastp->mKey[lastp->mCount - 1];
534				nodep->mData[i] = lastp->mData[lastp->mCount - 1];
535
536				// Now, we delete the entry
537				lastp->mCount--;
538				lastp->mData[lastp->mCount] = mNull;
539
540				if (!lastp->mCount)
541				{
542					// We deleted the last element!
543					if (lastp != &mNodes[local_id & 0xff])
544					{
545						// Only blitz the node if it's not the head
546						// Set the previous node to point to NULL, then
547						// blitz the empty last node
548						prevp->mNextNodep = NULL;
549						delete lastp;
550					}
551				}
552
553				return TRUE;
554			}
555		}
556
557		// Iterate to the next node, we've scanned all the entries in this one.
558		nodep = nodep->mNextNodep;
559	} while (nodep);
560
561	return FALSE;
562}
563
564template <class DATA_TYPE, int SIZE>
565BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::removeWithShift(const U32 local_id)
566{
567	const S32 node_index = local_id & 0xFF;
568	LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[node_index];
569	LLLocalIDHashNode<DATA_TYPE, SIZE>* prevp = NULL;
570	BOOL found = FALSE;
571
572	do // First node guaranteed to be there
573	{
574		const S32 count = nodep->mCount;
575		S32 i;
576		for (i = 0; i < count; i++)
577		{
578			if (nodep->mKey[i] == local_id)
579			{
580				// Found the item.  Start shifting items from later
581				// in the list over this item.
582				found = TRUE;
583			}
584
585			if (found)
586			{
587				// If there is an iterator on this node, we need to 
588				// back it up.
589				S32 cur_iter;
590				for (cur_iter = 0; cur_iter <MAX_ITERS; cur_iter++)
591				{
592					LLLocalIDHashMapIter<DATA_TYPE, SIZE>* iter;
593					iter = mIters[cur_iter];
594					// If an iterator is on this node,i pair, then back it up.
595					if (iter
596						&& iter->mCurHashMapNodeNum == node_index
597						&& iter->mCurHashNodep == nodep
598						&& iter->mCurHashNodeKey == i)
599					{
600						if (i > 0)
601						{
602							// Don't need to move iterator nodep, since 
603							// we're in the same node.
604							iter->mCurHashNodeKey--;
605						}
606						else if (prevp)
607						{
608							// need to go the previous node, last item
609							iter->mCurHashNodep = prevp;
610							iter->mCurHashNodeKey = prevp->mCount - 1;
611						}
612						else
613						{
614							// we're on the first item in the list, but
615							// need to go back anyhow.
616
617							// BUG: If this deletion empties the list, 
618							// iter->done() will be wrong until
619							// iter->next() is called.
620							iter->mCurHashNodeKey = -1;
621						}
622					}
623				}
624
625				// Copy data from the next position into this position.
626				if (i < count-1)
627				{
628					// we're not on the last item in the node,
629					// so we can copy within the node
630					nodep->mKey[i] = nodep->mKey[i+1];
631					nodep->mData[i] = nodep->mData[i+1];
632				}
633				else if (nodep->mNextNodep)
634				{
635					// we're on the last item in the node,
636					// but there's a next node we can copy from
637					nodep->mKey[i] = nodep->mNextNodep->mKey[0];
638					nodep->mData[i] = nodep->mNextNodep->mData[0];
639				}
640				else
641				{
642					// We're on the last position in the list.
643					// No one to copy from.  Replace with nothing.
644					nodep->mKey[i] = 0;
645					nodep->mData[i] = mNull;
646				}
647			}
648		}
649
650		// Last node in chain, so delete the last node
651		if (found
652			&& !nodep->mNextNodep)
653		{
654			// delete the last item off the last node
655			nodep->mCount--;
656
657			if (nodep->mCount == 0)
658			{
659				// We deleted the last element!
660				if (nodep != &mNodes[node_index])
661				{
662					// Always have a prevp if we're not the head.
663					llassert(prevp);
664
665					// Only blitz the node if it's not the head
666					// Set the previous node to point to NULL, then
667					// blitz the empty last node
668					prevp->mNextNodep = NULL;
669					delete nodep;
670					nodep = NULL;
671				}
672			}
673
674			// Deleted last item in chain, so we're done.
675			return found;
676		}
677
678		prevp = nodep;
679		nodep = nodep->mNextNodep;
680	} while (nodep);
681
682	return found;
683}
684
685template <class DATA_TYPE, int SIZE>
686void LLLocalIDHashMap<DATA_TYPE, SIZE>::removeIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter)
687{
688	S32 i;
689	for (i = 0; i < MAX_ITERS; i++)
690	{
691		if (mIters[i] == iter)
692		{
693			mIters[i] = NULL;
694			mIterCount--;
695			return;
696		}
697	}
698	llerrs << "Iterator " << iter << " not found for removal in hash map!" << llendl;
699}
700
701template <class DATA_TYPE, int SIZE>
702void LLLocalIDHashMap<DATA_TYPE, SIZE>::addIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter)
703{
704	S32 i;
705	for (i = 0; i < MAX_ITERS; i++)
706	{
707		if (mIters[i] == NULL)
708		{
709			mIters[i] = iter;
710			mIterCount++;
711			return;
712		}
713	}
714	llerrs << "More than " << MAX_ITERS << " iterating over a map simultaneously!" << llendl;
715}
716
717
718
719//
720// LLLocalIDHashMapIter Implementation
721//
722template <class DATA_TYPE, int SIZE>
723LLLocalIDHashMapIter<DATA_TYPE, SIZE>::LLLocalIDHashMapIter(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp)
724{
725	mHashMapp = NULL;
726	setMap(hash_mapp);
727}
728
729template <class DATA_TYPE, int SIZE>
730LLLocalIDHashMapIter<DATA_TYPE, SIZE>::~LLLocalIDHashMapIter()
731{
732	if (mHashMapp)
733	{
734		mHashMapp->removeIter(this);
735	}
736}
737
738template <class DATA_TYPE, int SIZE>
739void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::setMap(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp)
740{
741	if (mHashMapp)
742	{
743		mHashMapp->removeIter(this);
744	}
745	mHashMapp = hash_mapp;
746	if (mHashMapp)
747	{
748		mHashMapp->addIter(this);
749	}
750
751	mCurHashNodep = NULL;
752	mCurHashMapNodeNum = -1;
753	mCurHashNodeKey = 0;
754}
755
756template <class DATA_TYPE, int SIZE>
757inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::first()
758{
759	// Iterate through until we find the first non-empty node;
760	S32 i;
761	for (i = 0; i < 256; i++)
762	{
763		if (mHashMapp->mNodes[i].mCount)
764		{
765
766			mCurHashNodep = &mHashMapp->mNodes[i];
767			mCurHashMapNodeNum = i;
768			mCurHashNodeKey = 0;
769			//return mCurHashNodep->mData[0];
770			return;
771		}
772	}
773
774	// Completely empty!
775	mCurHashNodep = NULL;
776	//return mNull;
777	return;
778}
779
780template <class DATA_TYPE, int SIZE>
781inline BOOL LLLocalIDHashMapIter<DATA_TYPE, SIZE>::done() const
782{
783	return mCurHashNodep ? FALSE : TRUE;
784}
785
786template <class DATA_TYPE, int SIZE>
787inline S32 LLLocalIDHashMapIter<DATA_TYPE, SIZE>::currentBin() const
788{
789	if (  (mCurHashMapNodeNum > 255)
790		||(mCurHashMapNodeNum < 0))
791	{
792		return 0;
793	}
794	else
795	{
796		return mCurHashMapNodeNum;
797	}
798}
799
800template <class DATA_TYPE, int SIZE>
801inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::setBin(S32 bin)
802{
803	// Iterate through until we find the first non-empty node;
804	S32 i;
805	bin = llclamp(bin, 0, 255);
806	for (i = bin; i < 256; i++)
807	{
808		if (mHashMapp->mNodes[i].mCount)
809		{
810
811			mCurHashNodep = &mHashMapp->mNodes[i];
812			mCurHashMapNodeNum = i;
813			mCurHashNodeKey = 0;
814			return;
815		}
816	}
817	for (i = 0; i < bin; i++)
818	{
819		if (mHashMapp->mNodes[i].mCount)
820		{
821
822			mCurHashNodep = &mHashMapp->mNodes[i];
823			mCurHashMapNodeNum = i;
824			mCurHashNodeKey = 0;
825			return;
826		}
827	}
828	// Completely empty!
829	mCurHashNodep = NULL;
830}
831
832template <class DATA_TYPE, int SIZE>
833inline DATA_TYPE &LLLocalIDHashMapIter<DATA_TYPE, SIZE>::current()
834{
835	if (!mCurHashNodep)
836	{
837		return mNull;
838	}
839	return mCurHashNodep->mData[mCurHashNodeKey];
840}
841
842template <class DATA_TYPE, int SIZE>
843inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::next()
844{
845	// No current entry, this iterator is done
846	if (!mCurHashNodep)
847	{
848		//return mNull;
849		return;
850	}
851
852	// Go to the next element
853	mCurHashNodeKey++;
854	if (mCurHashNodeKey < mCurHashNodep->mCount)
855	{
856		// We're not done with this node, return the current element
857		//return mCurHashNodep->mData[mCurHashNodeKey];
858		return;
859	}
860
861	// Done with this node, move to the next
862	mCurHashNodep = mCurHashNodep->mNextNodep;
863	if (mCurHashNodep)
864	{
865		// Return the first element
866		mCurHashNodeKey = 0;
867		//return mCurHashNodep->mData[0];
868		return;
869	}
870
871	// Find the next non-empty node (keyed on the first byte)
872	mCurHashMapNodeNum++;
873
874	S32 i;
875	for (i = mCurHashMapNodeNum; i < 256; i++)
876	{
877		if (mHashMapp->mNodes[i].mCount)
878		{
879			// We found one that wasn't empty
880			mCurHashNodep = &mHashMapp->mNodes[i];
881			mCurHashMapNodeNum = i;
882			mCurHashNodeKey = 0;
883			//return mCurHashNodep->mData[0];
884			return;
885		}
886	}
887
888	// OK, we're done, nothing else to iterate
889	mCurHashNodep = NULL;
890	mHashMapp->mIterCount--; // Decrement since we're safe to do removes now
891	//return mNull;
892	return;
893}
894
895#endif // LL_LLLOCALIDHASHMAP_H