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