diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcommon/lllocalidhashmap.h | |
parent | README.txt (diff) | |
download | meta-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.h | 896 |
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 | |||
34 | const S32 MAX_ITERS = 4; | ||
35 | // LocalID hash map | ||
36 | |||
37 | // | ||
38 | // LLLocalIDHashNode | ||
39 | // | ||
40 | |||
41 | template <class DATA, int SIZE> | ||
42 | class LLLocalIDHashNode | ||
43 | { | ||
44 | public: | ||
45 | LLLocalIDHashNode(); | ||
46 | |||
47 | public: | ||
48 | S32 mCount; | ||
49 | U32 mKey[SIZE]; | ||
50 | DATA mData[SIZE]; | ||
51 | LLLocalIDHashNode<DATA, SIZE> *mNextNodep; | ||
52 | }; | ||
53 | |||
54 | |||
55 | // | ||
56 | // LLLocalIDHashNode implementation | ||
57 | // | ||
58 | template <class DATA, int SIZE> | ||
59 | LLLocalIDHashNode<DATA, SIZE>::LLLocalIDHashNode() | ||
60 | { | ||
61 | mCount = 0; | ||
62 | mNextNodep = NULL; | ||
63 | } | ||
64 | |||
65 | // | ||
66 | // LLLocalIDHashMapIter | ||
67 | // | ||
68 | template <class DATA_TYPE, int SIZE> | ||
69 | class LLLocalIDHashMap; | ||
70 | |||
71 | template <class DATA_TYPE, int SIZE> | ||
72 | class LLLocalIDHashMapIter | ||
73 | { | ||
74 | public: | ||
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 | |||
108 | template <class DATA_TYPE, int SIZE> | ||
109 | class LLLocalIDHashMap | ||
110 | { | ||
111 | public: | ||
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 | |||
135 | protected: | ||
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 | |||
144 | protected: | ||
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 | |||
158 | template <class DATA_TYPE, int SIZE> | ||
159 | LLLocalIDHashMap<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 | |||
170 | template <class DATA_TYPE, int SIZE> | ||
171 | LLLocalIDHashMap<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 | |||
182 | template <class DATA_TYPE, int SIZE> | ||
183 | LLLocalIDHashMap<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 | |||
197 | template <class DATA_TYPE, int SIZE> | ||
198 | void 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 | |||
237 | template <class DATA_TYPE, int SIZE> | ||
238 | void 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 | |||
257 | template <class DATA_TYPE, int SIZE> | ||
258 | void 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 | |||
284 | template <class DATA_TYPE, int SIZE> | ||
285 | inline 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 | |||
301 | template <class DATA_TYPE, int SIZE> | ||
302 | inline 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 | |||
329 | template <class DATA_TYPE, int SIZE> | ||
330 | inline 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 | |||
358 | template <class DATA_TYPE, int SIZE> | ||
359 | inline 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 | |||
413 | template <class DATA_TYPE, int SIZE> | ||
414 | inline 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 | |||
565 | template <class DATA_TYPE, int SIZE> | ||
566 | BOOL 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 | |||
686 | template <class DATA_TYPE, int SIZE> | ||
687 | void 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 | |||
702 | template <class DATA_TYPE, int SIZE> | ||
703 | void 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 | // | ||
723 | template <class DATA_TYPE, int SIZE> | ||
724 | LLLocalIDHashMapIter<DATA_TYPE, SIZE>::LLLocalIDHashMapIter(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp) | ||
725 | { | ||
726 | mHashMapp = NULL; | ||
727 | setMap(hash_mapp); | ||
728 | } | ||
729 | |||
730 | template <class DATA_TYPE, int SIZE> | ||
731 | LLLocalIDHashMapIter<DATA_TYPE, SIZE>::~LLLocalIDHashMapIter() | ||
732 | { | ||
733 | if (mHashMapp) | ||
734 | { | ||
735 | mHashMapp->removeIter(this); | ||
736 | } | ||
737 | } | ||
738 | |||
739 | template <class DATA_TYPE, int SIZE> | ||
740 | void 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 | |||
757 | template <class DATA_TYPE, int SIZE> | ||
758 | inline 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 | |||
781 | template <class DATA_TYPE, int SIZE> | ||
782 | inline BOOL LLLocalIDHashMapIter<DATA_TYPE, SIZE>::done() const | ||
783 | { | ||
784 | return mCurHashNodep ? FALSE : TRUE; | ||
785 | } | ||
786 | |||
787 | template <class DATA_TYPE, int SIZE> | ||
788 | inline 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 | |||
801 | template <class DATA_TYPE, int SIZE> | ||
802 | inline 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 | |||
833 | template <class DATA_TYPE, int SIZE> | ||
834 | inline DATA_TYPE &LLLocalIDHashMapIter<DATA_TYPE, SIZE>::current() | ||
835 | { | ||
836 | if (!mCurHashNodep) | ||
837 | { | ||
838 | return mNull; | ||
839 | } | ||
840 | return mCurHashNodep->mData[mCurHashNodeKey]; | ||
841 | } | ||
842 | |||
843 | template <class DATA_TYPE, int SIZE> | ||
844 | inline 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 | ||