aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/lluuidhashmap.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/lluuidhashmap.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/lluuidhashmap.h576
1 files changed, 576 insertions, 0 deletions
diff --git a/linden/indra/llcommon/lluuidhashmap.h b/linden/indra/llcommon/lluuidhashmap.h
new file mode 100644
index 0000000..44cd925
--- /dev/null
+++ b/linden/indra/llcommon/lluuidhashmap.h
@@ -0,0 +1,576 @@
1/**
2 * @file lluuidhashmap.h
3 * @brief A uuid based hash map.
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_LLUUIDHASHMAP_H
29#define LL_LLUUIDHASHMAP_H
30
31#include "stdtypes.h"
32#include "llerror.h"
33#include "lluuid.h"
34
35// UUID hash map
36
37 /*
38 LLUUIDHashMap<uuid_pair, 32> foo(test_equals);
39 LLUUIDHashMapIter<uuid_pair, 32> bar(&foo);
40
41 LLDynamicArray<LLUUID> source_ids;
42 const S32 COUNT = 100000;
43 S32 q;
44 for (q = 0; q < COUNT; q++)
45 {
46 llinfos << "Creating" << llendl;
47 LLUUID id;
48 id.generate();
49 //llinfos << q << ":" << id << llendl;
50 uuid_pair pair;
51 pair.mUUID = id;
52 pair.mValue = q;
53 foo.set(id, pair);
54 source_ids.put(id);
55 //ms_sleep(1);
56 }
57
58 uuid_pair cur;
59 llinfos << "Iterating" << llendl;
60 for (cur = bar.first(); !bar.done(); cur = bar.next())
61 {
62 if (source_ids[cur.mValue] != cur.mUUID)
63 {
64 llerrs << "Incorrect value iterated!" << llendl;
65 }
66 //llinfos << cur.mValue << ":" << cur.mUUID << llendl;
67 //ms_sleep(1);
68 }
69
70 llinfos << "Finding" << llendl;
71 for (q = 0; q < COUNT; q++)
72 {
73 cur = foo.get(source_ids[q]);
74 if (source_ids[cur.mValue] != cur.mUUID)
75 {
76 llerrs << "Incorrect value found!" << llendl;
77 }
78 //llinfos << res.mValue << ":" << res.mUUID << llendl;
79 //ms_sleep(1);
80 }
81
82 llinfos << "Removing" << llendl;
83 for (q = 0; q < COUNT/2; q++)
84 {
85 if (!foo.remove(source_ids[q]))
86 {
87 llerrs << "Remove failed!" << llendl;
88 }
89 //ms_sleep(1);
90 }
91
92 llinfos << "Iterating" << llendl;
93 for (cur = bar.first(); !bar.done(); cur = bar.next())
94 {
95 if (source_ids[cur.mValue] != cur.mUUID)
96 {
97 llerrs << "Incorrect value found!" << llendl;
98 }
99 //llinfos << cur.mValue << ":" << cur.mUUID << llendl;
100 //ms_sleep(1);
101 }
102 llinfos << "Done with UUID map test" << llendl;
103
104 return 0;
105 */
106
107
108//
109// LLUUIDHashNode
110//
111
112template <class DATA, int SIZE>
113class LLUUIDHashNode
114{
115public:
116 LLUUIDHashNode();
117
118public:
119 S32 mCount;
120 U8 mKey[SIZE];
121 DATA mData[SIZE];
122 LLUUIDHashNode<DATA, SIZE> *mNextNodep;
123};
124
125
126//
127// LLUUIDHashNode implementation
128//
129template <class DATA, int SIZE>
130LLUUIDHashNode<DATA, SIZE>::LLUUIDHashNode()
131{
132 mCount = 0;
133 mNextNodep = NULL;
134}
135
136
137template <class DATA_TYPE, int SIZE>
138class LLUUIDHashMap
139{
140public:
141 // basic constructor including sorter
142 LLUUIDHashMap(BOOL (*equals)(const LLUUID &uuid, const DATA_TYPE &data),
143 const DATA_TYPE &null_data);
144 ~LLUUIDHashMap();
145
146 inline DATA_TYPE &get(const LLUUID &uuid);
147 inline BOOL check(const LLUUID &uuid) const;
148 inline DATA_TYPE &set(const LLUUID &uuid, const DATA_TYPE &type);
149 inline BOOL remove(const LLUUID &uuid);
150 void removeAll();
151
152 inline S32 getLength() const; // Warning, NOT O(1!)
153public:
154 BOOL (*mEquals)(const LLUUID &uuid, const DATA_TYPE &data);
155 LLUUIDHashNode<DATA_TYPE, SIZE> mNodes[256];
156
157 S32 mIterCount;
158protected:
159 DATA_TYPE mNull;
160};
161
162
163//
164// LLUUIDHashMap implementation
165//
166
167template <class DATA_TYPE, int SIZE>
168LLUUIDHashMap<DATA_TYPE, SIZE>::LLUUIDHashMap(BOOL (*equals)(const LLUUID &uuid, const DATA_TYPE &data),
169 const DATA_TYPE &null_data)
170: mEquals(equals),
171 mIterCount(0),
172 mNull(null_data)
173{ }
174
175template <class DATA_TYPE, int SIZE>
176LLUUIDHashMap<DATA_TYPE, SIZE>::~LLUUIDHashMap()
177{
178 removeAll();
179}
180
181template <class DATA_TYPE, int SIZE>
182void LLUUIDHashMap<DATA_TYPE, SIZE>::removeAll()
183{
184 S32 bin;
185 for (bin = 0; bin < 256; bin++)
186 {
187 LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
188
189 BOOL first = TRUE;
190 while (nodep)
191 {
192 S32 i;
193 const S32 count = nodep->mCount;
194
195 // Iterate through all members of this node
196 for (i = 0; i < count; i++)
197 {
198 nodep->mData[i] = mNull;
199 }
200
201 nodep->mCount = 0;
202 // Done with all objects in this node, go to the next.
203
204 LLUUIDHashNode<DATA_TYPE, SIZE>* curp = nodep;
205 nodep = nodep->mNextNodep;
206
207 // Delete the node if it's not the first node
208 if (first)
209 {
210 first = FALSE;
211 curp->mNextNodep = NULL;
212 }
213 else
214 {
215 delete curp;
216 }
217 }
218 }
219}
220
221template <class DATA_TYPE, int SIZE>
222inline S32 LLUUIDHashMap<DATA_TYPE, SIZE>::getLength() const
223{
224 S32 count = 0;
225 S32 bin;
226 for (bin = 0; bin < 256; bin++)
227 {
228 LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
229 while (nodep)
230 {
231 count += nodep->mCount;
232 nodep = nodep->mNextNodep;
233 }
234 }
235 return count;
236}
237
238template <class DATA_TYPE, int SIZE>
239inline DATA_TYPE &LLUUIDHashMap<DATA_TYPE, SIZE>::get(const LLUUID &uuid)
240{
241 LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]];
242
243 // Grab the second byte of the UUID, which is the key for the node data
244 const S32 second_byte = uuid.mData[1];
245 while (nodep)
246 {
247 S32 i;
248 const S32 count = nodep->mCount;
249
250 // Iterate through all members of this node
251 for (i = 0; i < count; i++)
252 {
253 if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
254 {
255 // The second byte matched, and our equality test passed.
256 // We found it.
257 return nodep->mData[i];
258 }
259 }
260
261 // Done with all objects in this node, go to the next.
262 nodep = nodep->mNextNodep;
263 }
264 return mNull;
265}
266
267
268template <class DATA_TYPE, int SIZE>
269inline BOOL LLUUIDHashMap<DATA_TYPE, SIZE>::check(const LLUUID &uuid) const
270{
271 const LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]];
272
273 // Grab the second byte of the UUID, which is the key for the node data
274 const S32 second_byte = uuid.mData[1];
275 while (nodep)
276 {
277 S32 i;
278 const S32 count = nodep->mCount;
279
280 // Iterate through all members of this node
281 for (i = 0; i < count; i++)
282 {
283 if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
284 {
285 // The second byte matched, and our equality test passed.
286 // We found it.
287 return TRUE;
288 }
289 }
290
291 // Done with all objects in this node, go to the next.
292 nodep = nodep->mNextNodep;
293 }
294
295 // Didn't find anything
296 return FALSE;
297}
298
299
300template <class DATA_TYPE, int SIZE>
301inline DATA_TYPE &LLUUIDHashMap<DATA_TYPE, SIZE>::set(const LLUUID &uuid, const DATA_TYPE &data)
302{
303 // Set is just like a normal find, except that if we find a match
304 // we replace it with the input value.
305 // If we don't find a match, we append to the end of the list.
306
307 LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]];
308
309 const S32 second_byte = uuid.mData[1];
310 while (1)
311 {
312 const S32 count = nodep->mCount;
313
314 S32 i;
315 for (i = 0; i < count; i++)
316 {
317 if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
318 {
319 // We found a match for this key, replace the data with
320 // the incoming data.
321 nodep->mData[i] = data;
322 return nodep->mData[i];
323 }
324 }
325 if (!nodep->mNextNodep)
326 {
327 // We've iterated through all of the keys without finding a match
328 if (i < SIZE)
329 {
330 // There's still some space on this node, append
331 // the key and data to it.
332 nodep->mKey[i] = second_byte;
333 nodep->mData[i] = data;
334 nodep->mCount++;
335
336 return nodep->mData[i];
337 }
338 else
339 {
340 // This node is full, append a new node to the end.
341 nodep->mNextNodep = new LLUUIDHashNode<DATA_TYPE, SIZE>;
342 nodep->mNextNodep->mKey[0] = second_byte;
343 nodep->mNextNodep->mData[0] = data;
344 nodep->mNextNodep->mCount = 1;
345
346 return nodep->mNextNodep->mData[0];
347 }
348 }
349
350 // No match on this node, go to the next
351 nodep = nodep->mNextNodep;
352 }
353}
354
355
356template <class DATA_TYPE, int SIZE>
357inline BOOL LLUUIDHashMap<DATA_TYPE, SIZE>::remove(const LLUUID &uuid)
358{
359 if (mIterCount)
360 {
361 // We don't allow remove when we're iterating, it's bad karma!
362 llerrs << "Attempted remove while an outstanding iterator in LLUUIDHashMap!" << llendl;
363 }
364 // Remove is the trickiest operation.
365 // What we want to do is swap the last element of the last
366 // node if we find the one that we want to remove, but we have
367 // to deal with deleting the node from the tail if it's empty, but
368 // NOT if it's the only node left.
369
370 LLUUIDHashNode<DATA_TYPE, SIZE> *nodep = &mNodes[uuid.mData[0]];
371
372 // Not empty, we need to search through the nodes
373 const S32 second_byte = uuid.mData[1];
374
375 // A modification of the standard search algorithm.
376 while (nodep)
377 {
378 const S32 count = nodep->mCount;
379
380 S32 i;
381 for (i = 0; i < count; i++)
382 {
383 if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i]))
384 {
385 // We found the node that we want to remove.
386 // Find the last (and next-to-last) node, and the index of the last
387 // element. We could conceviably start from the node we're on,
388 // but that makes it more complicated, this is easier.
389
390 LLUUIDHashNode<DATA_TYPE, SIZE> *prevp = &mNodes[uuid.mData[0]];
391 LLUUIDHashNode<DATA_TYPE, SIZE> *lastp = prevp;
392
393 // Find the last and next-to-last
394 while (lastp->mNextNodep)
395 {
396 prevp = lastp;
397 lastp = lastp->mNextNodep;
398 }
399
400 // First, swap in the last to the current location.
401 nodep->mKey[i] = lastp->mKey[lastp->mCount - 1];
402 nodep->mData[i] = lastp->mData[lastp->mCount - 1];
403
404 // Now, we delete the entry
405 lastp->mCount--;
406 lastp->mData[lastp->mCount] = mNull;
407
408 if (!lastp->mCount)
409 {
410 // We deleted the last element!
411 if (lastp != &mNodes[uuid.mData[0]])
412 {
413 // Only blitz the node if it's not the head
414 // Set the previous node to point to NULL, then
415 // blitz the empty last node
416 prevp->mNextNodep = NULL;
417 delete lastp;
418 }
419 }
420 return TRUE;
421 }
422 }
423
424 // Iterate to the next node, we've scanned all the entries in this one.
425 nodep = nodep->mNextNodep;
426 }
427 return FALSE;
428}
429
430
431//
432// LLUUIDHashMapIter
433//
434
435template <class DATA_TYPE, int SIZE>
436class LLUUIDHashMapIter
437{
438public:
439 LLUUIDHashMapIter(LLUUIDHashMap<DATA_TYPE, SIZE> *hash_mapp);
440 ~LLUUIDHashMapIter();
441
442
443 inline void first();
444 inline void next();
445 inline BOOL done() const;
446
447 DATA_TYPE& operator*() const
448 {
449 return mCurHashNodep->mData[mCurHashNodeKey];
450 }
451 DATA_TYPE* operator->() const
452 {
453 return &(operator*());
454 }
455
456protected:
457 LLUUIDHashMap<DATA_TYPE, SIZE> *mHashMapp;
458 LLUUIDHashNode<DATA_TYPE, SIZE> *mCurHashNodep;
459
460 S32 mCurHashMapNodeNum;
461 S32 mCurHashNodeKey;
462
463 DATA_TYPE mNull;
464};
465
466
467//
468// LLUUIDHashMapIter Implementation
469//
470template <class DATA_TYPE, int SIZE>
471LLUUIDHashMapIter<DATA_TYPE, SIZE>::LLUUIDHashMapIter(LLUUIDHashMap<DATA_TYPE, SIZE> *hash_mapp)
472{
473 mHashMapp = hash_mapp;
474 mCurHashNodep = NULL;
475 mCurHashMapNodeNum = 0;
476 mCurHashNodeKey = 0;
477}
478
479template <class DATA_TYPE, int SIZE>
480LLUUIDHashMapIter<DATA_TYPE, SIZE>::~LLUUIDHashMapIter()
481{
482 if (mCurHashNodep)
483 {
484 // We're partway through an iteration, we can clean up now
485 mHashMapp->mIterCount--;
486 }
487}
488
489template <class DATA_TYPE, int SIZE>
490inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::first()
491{
492 // Iterate through until we find the first non-empty node;
493 S32 i;
494 for (i = 0; i < 256; i++)
495 {
496 if (mHashMapp->mNodes[i].mCount)
497 {
498 if (!mCurHashNodep)
499 {
500 // Increment, since it's no longer safe for us to do a remove
501 mHashMapp->mIterCount++;
502 }
503
504 mCurHashNodep = &mHashMapp->mNodes[i];
505 mCurHashMapNodeNum = i;
506 mCurHashNodeKey = 0;
507 //return mCurHashNodep->mData[0];
508 return;
509 }
510 }
511
512 // Completely empty!
513 mCurHashNodep = NULL;
514 //return mNull;
515 return;
516}
517
518template <class DATA_TYPE, int SIZE>
519inline BOOL LLUUIDHashMapIter<DATA_TYPE, SIZE>::done() const
520{
521 return mCurHashNodep ? FALSE : TRUE;
522}
523
524template <class DATA_TYPE, int SIZE>
525inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::next()
526{
527 // No current entry, this iterator is done
528 if (!mCurHashNodep)
529 {
530 //return mNull;
531 return;
532 }
533
534 // Go to the next element
535 mCurHashNodeKey++;
536 if (mCurHashNodeKey < mCurHashNodep->mCount)
537 {
538 // We're not done with this node, return the current element
539 //return mCurHashNodep->mData[mCurHashNodeKey];
540 return;
541 }
542
543 // Done with this node, move to the next
544 mCurHashNodep = mCurHashNodep->mNextNodep;
545 if (mCurHashNodep)
546 {
547 // Return the first element
548 mCurHashNodeKey = 0;
549 //return mCurHashNodep->mData[0];
550 return;
551 }
552
553 // Find the next non-empty node (keyed on the first byte)
554 mCurHashMapNodeNum++;
555
556 S32 i;
557 for (i = mCurHashMapNodeNum; i < 256; i++)
558 {
559 if (mHashMapp->mNodes[i].mCount)
560 {
561 // We found one that wasn't empty
562 mCurHashNodep = &mHashMapp->mNodes[i];
563 mCurHashMapNodeNum = i;
564 mCurHashNodeKey = 0;
565 //return mCurHashNodep->mData[0];
566 return;
567 }
568 }
569
570 // OK, we're done, nothing else to iterate
571 mCurHashNodep = NULL;
572 mHashMapp->mIterCount--; // Decrement since we're safe to do removes now
573 //return mNull;
574}
575
576#endif // LL_LLUUIDHASHMAP_H