aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/llptrskiplist.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/llptrskiplist.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 'linden/indra/llcommon/llptrskiplist.h')
-rw-r--r--linden/indra/llcommon/llptrskiplist.h723
1 files changed, 723 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llptrskiplist.h b/linden/indra/llcommon/llptrskiplist.h
new file mode 100644
index 0000000..bae40b8
--- /dev/null
+++ b/linden/indra/llcommon/llptrskiplist.h
@@ -0,0 +1,723 @@
1/**
2 * @file llptrskiplist.h
3 * @brief Skip list implementation.
4 *
5 * Copyright (c) 2001-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_LLPTRSKIPLIST_H
29#define LL_LLPTRSKIPLIST_H
30
31#include "llerror.h"
32//#include "vmath.h"
33
34/////////////////////////////////////////////
35//
36// LLPtrSkipList implementation - skip list for pointers to objects
37//
38
39template <class DATA_TYPE, S32 BINARY_DEPTH = 8>
40class LLPtrSkipList
41{
42public:
43 friend class LLPtrSkipNode;
44
45 // basic constructor
46 LLPtrSkipList();
47 // basic constructor including sorter
48 LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second),
49 BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second));
50 ~LLPtrSkipList();
51
52 inline void setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second));
53 inline void setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second));
54
55 inline BOOL addData(DATA_TYPE *data);
56
57 inline BOOL checkData(const DATA_TYPE *data);
58
59 inline S32 getLength(); // returns number of items in the list - NOT constant time!
60
61 inline BOOL removeData(const DATA_TYPE *data);
62
63 // note that b_sort is ignored
64 inline BOOL moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort);
65
66 inline BOOL moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort);
67
68 // resort -- use when the value we're sorting by changes
69 /* IW 12/6/02 - This doesn't work!
70 Instead, remove the data BEFORE you change it
71 Then re-insert it after you change it
72 BOOL resortData(DATA_TYPE *data)
73 */
74
75 // remove all nodes from the list but do not delete data
76 inline void removeAllNodes();
77
78 inline BOOL deleteData(const DATA_TYPE *data);
79
80 // remove all nodes from the list and delete data
81 inline void deleteAllData();
82
83 // place mCurrentp on first node
84 inline void resetList();
85
86 // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
87 inline DATA_TYPE *getCurrentData();
88
89 // same as getCurrentData() but a more intuitive name for the operation
90 inline DATA_TYPE *getNextData();
91
92 // remove the Node at mCurentOperatingp
93 // leave mCurrentp and mCurentOperatingp on the next entry
94 inline void removeCurrentData();
95
96 // delete the Node at mCurentOperatingp
97 // leave mCurrentp and mCurentOperatingp on the next entry
98 inline void deleteCurrentData();
99
100 // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
101 inline DATA_TYPE *getFirstData();
102
103 // TRUE if nodes are not in sorted order
104 inline BOOL corrupt();
105
106protected:
107 class LLPtrSkipNode
108 {
109 public:
110 LLPtrSkipNode()
111 : mData(NULL)
112 {
113 S32 i;
114 for (i = 0; i < BINARY_DEPTH; i++)
115 {
116 mForward[i] = NULL;
117 }
118 }
119
120 LLPtrSkipNode(DATA_TYPE *data)
121 : mData(data)
122 {
123 S32 i;
124 for (i = 0; i < BINARY_DEPTH; i++)
125 {
126 mForward[i] = NULL;
127 }
128 }
129
130 ~LLPtrSkipNode()
131 {
132 if (mData)
133 {
134 llerror("Attempting to call LLPtrSkipNode destructor with a non-null mDatap!", 1);
135 }
136 }
137
138 // delete associated data and NULLs out pointer
139 void deleteData()
140 {
141 delete mData;
142 mData = NULL;
143 }
144
145 // NULLs out pointer
146 void removeData()
147 {
148 mData = NULL;
149 }
150
151 DATA_TYPE *mData;
152 LLPtrSkipNode *mForward[BINARY_DEPTH];
153 };
154
155 static BOOL defaultEquals(const DATA_TYPE *first, const DATA_TYPE *second)
156 {
157 return first == second;
158 }
159
160
161 LLPtrSkipNode mHead;
162 LLPtrSkipNode *mUpdate[BINARY_DEPTH];
163 LLPtrSkipNode *mCurrentp;
164 LLPtrSkipNode *mCurrentOperatingp;
165 S32 mLevel;
166 BOOL (*mInsertFirst)(const DATA_TYPE *first, const DATA_TYPE *second);
167 BOOL (*mEquals)(const DATA_TYPE *first, const DATA_TYPE *second);
168};
169
170
171// basic constructor
172template <class DATA_TYPE, S32 BINARY_DEPTH>
173LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList()
174 : mInsertFirst(NULL), mEquals(defaultEquals)
175{
176 if (BINARY_DEPTH < 2)
177 {
178 llerrs << "Trying to create skip list with too little depth, "
179 "must be 2 or greater" << llendl;
180 }
181 S32 i;
182 for (i = 0; i < BINARY_DEPTH; i++)
183 {
184 mUpdate[i] = NULL;
185 }
186 mLevel = 1;
187 mCurrentp = *(mHead.mForward);
188 mCurrentOperatingp = *(mHead.mForward);
189}
190
191// basic constructor including sorter
192template <class DATA_TYPE, S32 BINARY_DEPTH>
193LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second),
194 BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second))
195 :mInsertFirst(insert_first), mEquals(equals)
196{
197 if (BINARY_DEPTH < 2)
198 {
199 llerrs << "Trying to create skip list with too little depth, "
200 "must be 2 or greater" << llendl;
201 }
202 mLevel = 1;
203 S32 i;
204 for (i = 0; i < BINARY_DEPTH; i++)
205 {
206 mHead.mForward[i] = NULL;
207 mUpdate[i] = NULL;
208 }
209 mCurrentp = *(mHead.mForward);
210 mCurrentOperatingp = *(mHead.mForward);
211}
212
213template <class DATA_TYPE, S32 BINARY_DEPTH>
214inline LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::~LLPtrSkipList()
215{
216 removeAllNodes();
217}
218
219template <class DATA_TYPE, S32 BINARY_DEPTH>
220inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second))
221{
222 mInsertFirst = insert_first;
223}
224
225template <class DATA_TYPE, S32 BINARY_DEPTH>
226inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second))
227{
228 mEquals = equals;
229}
230
231template <class DATA_TYPE, S32 BINARY_DEPTH>
232inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::addData(DATA_TYPE *data)
233{
234 S32 level;
235 LLPtrSkipNode *current = &mHead;
236 LLPtrSkipNode *temp;
237
238 // find the pointer one in front of the one we want
239 if (mInsertFirst)
240 {
241 for (level = mLevel - 1; level >= 0; level--)
242 {
243 temp = *(current->mForward + level);
244 while ( (temp)
245 &&(mInsertFirst(temp->mData, data)))
246 {
247 current = temp;
248 temp = *(current->mForward + level);
249 }
250 *(mUpdate + level) = current;
251 }
252 }
253 else
254 {
255 for (level = mLevel - 1; level >= 0; level--)
256 {
257 temp = *(current->mForward + level);
258 while ( (temp)
259 &&(temp->mData < data))
260 {
261 current = temp;
262 temp = *(current->mForward + level);
263 }
264 *(mUpdate + level) = current;
265 }
266 }
267
268
269 // we're now just in front of where we want to be . . . take one step forward
270 current = *current->mForward;
271
272 // now add the new node
273 S32 newlevel;
274 for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
275 {
276 if (frand(1.f) < 0.5f)
277 break;
278 }
279
280 LLPtrSkipNode *snode = new LLPtrSkipNode(data);
281
282 if (newlevel > mLevel)
283 {
284 mHead.mForward[mLevel] = NULL;
285 mUpdate[mLevel] = &mHead;
286 mLevel = newlevel;
287 }
288
289 for (level = 0; level < newlevel; level++)
290 {
291 snode->mForward[level] = mUpdate[level]->mForward[level];
292 mUpdate[level]->mForward[level] = snode;
293 }
294 return TRUE;
295}
296
297template <class DATA_TYPE, S32 BINARY_DEPTH>
298inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE *data)
299{
300 S32 level;
301 LLPtrSkipNode *current = &mHead;
302 LLPtrSkipNode *temp;
303
304 // find the pointer one in front of the one we want
305 if (mInsertFirst)
306 {
307 for (level = mLevel - 1; level >= 0; level--)
308 {
309 temp = *(current->mForward + level);
310 while ( (temp)
311 &&(mInsertFirst(temp->mData, data)))
312 {
313 current = temp;
314 temp = *(current->mForward + level);
315 }
316 *(mUpdate + level) = current;
317 }
318 }
319 else
320 {
321 for (level = mLevel - 1; level >= 0; level--)
322 {
323 temp = *(current->mForward + level);
324 while ( (temp)
325 &&(temp->mData < data))
326 {
327 current = temp;
328 temp = *(current->mForward + level);
329 }
330 *(mUpdate + level) = current;
331 }
332 }
333
334
335 // we're now just in front of where we want to be . . . take one step forward
336 current = *current->mForward;
337
338 if (current)
339 {
340 return mEquals(current->mData, data);
341 }
342 else
343 {
344 return FALSE;
345 }
346}
347
348// returns number of items in the list
349template <class DATA_TYPE, S32 BINARY_DEPTH>
350inline S32 LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getLength()
351{
352 U32 length = 0;
353 for (LLPtrSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0])
354 {
355 length++;
356 }
357 return length;
358}
359
360template <class DATA_TYPE, S32 BINARY_DEPTH>
361inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE *data)
362{
363 S32 level;
364 LLPtrSkipNode *current = &mHead;
365 LLPtrSkipNode *temp;
366
367 // find the pointer one in front of the one we want
368 if (mInsertFirst)
369 {
370 for (level = mLevel - 1; level >= 0; level--)
371 {
372 temp = *(current->mForward + level);
373 while ( (temp)
374 &&(mInsertFirst(temp->mData, data)))
375 {
376 current = temp;
377 temp = *(current->mForward + level);
378 }
379 *(mUpdate + level) = current;
380 }
381 }
382 else
383 {
384 for (level = mLevel - 1; level >= 0; level--)
385 {
386 temp = *(current->mForward + level);
387 while ( (temp)
388 &&(temp->mData < data))
389 {
390 current = temp;
391 temp = *(current->mForward + level);
392 }
393 *(mUpdate + level) = current;
394 }
395 }
396
397
398 // we're now just in front of where we want to be . . . take one step forward
399 current = *current->mForward;
400
401 if (!current)
402 {
403 // empty list or beyond the end!
404 return FALSE;
405 }
406
407 // is this the one we want?
408 if (!mEquals(current->mData, data))
409 {
410 // nope!
411 return FALSE;
412 }
413 else
414 {
415 // yes it is! change pointers as required
416 for (level = 0; level < mLevel; level++)
417 {
418 if (mUpdate[level]->mForward[level] != current)
419 {
420 // cool, we've fixed all the pointers!
421 break;
422 }
423 mUpdate[level]->mForward[level] = current->mForward[level];
424 }
425
426 // clean up cuurent
427 current->removeData();
428 delete current;
429
430 // clean up mHead
431 while ( (mLevel > 1)
432 &&(!mHead.mForward[mLevel - 1]))
433 {
434 mLevel--;
435 }
436 }
437 return TRUE;
438}
439
440// note that b_sort is ignored
441template <class DATA_TYPE, S32 BINARY_DEPTH>
442inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort)
443{
444 BOOL removed = removeData(data);
445 BOOL added = newlist->addData(data);
446 return removed && added;
447}
448
449template <class DATA_TYPE, S32 BINARY_DEPTH>
450inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort)
451{
452 if (mCurrentOperatingp)
453 {
454 mCurrentp = mCurrentOperatingp->mForward[0];
455 BOOL removed = removeData(mCurrentOperatingp);
456 BOOL added = newlist->addData(mCurrentOperatingp);
457 mCurrentOperatingp = mCurrentp;
458 return removed && added;
459 }
460 return FALSE;
461}
462
463// resort -- use when the value we're sorting by changes
464/* IW 12/6/02 - This doesn't work!
465 Instead, remove the data BEFORE you change it
466 Then re-insert it after you change it
467BOOL resortData(DATA_TYPE *data)
468{
469 removeData(data);
470 addData(data);
471}
472*/
473
474// remove all nodes from the list but do not delete data
475template <class DATA_TYPE, S32 BINARY_DEPTH>
476inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes()
477{
478 LLPtrSkipNode *temp;
479 // reset mCurrentp
480 mCurrentp = *(mHead.mForward);
481
482 while (mCurrentp)
483 {
484 temp = mCurrentp->mForward[0];
485 mCurrentp->removeData();
486 delete mCurrentp;
487 mCurrentp = temp;
488 }
489
490 S32 i;
491 for (i = 0; i < BINARY_DEPTH; i++)
492 {
493 mHead.mForward[i] = NULL;
494 mUpdate[i] = NULL;
495 }
496
497 mCurrentp = *(mHead.mForward);
498 mCurrentOperatingp = *(mHead.mForward);
499}
500
501template <class DATA_TYPE, S32 BINARY_DEPTH>
502inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteData(const DATA_TYPE *data)
503{
504 S32 level;
505 LLPtrSkipNode *current = &mHead;
506 LLPtrSkipNode *temp;
507
508 // find the pointer one in front of the one we want
509 if (mInsertFirst)
510 {
511 for (level = mLevel - 1; level >= 0; level--)
512 {
513 temp = *(current->mForward + level);
514 while ( (temp)
515 &&(mInsertFirst(temp->mData, data)))
516 {
517 current = temp;
518 temp = *(current->mForward + level);
519 }
520 *(mUpdate + level) = current;
521 }
522 }
523 else
524 {
525 for (level = mLevel - 1; level >= 0; level--)
526 {
527 temp = *(current->mForward + level);
528 while ( (temp)
529 &&(temp->mData < data))
530 {
531 current = temp;
532 temp = *(current->mForward + level);
533 }
534 *(mUpdate + level) = current;
535 }
536 }
537
538
539 // we're now just in front of where we want to be . . . take one step forward
540 current = *current->mForward;
541
542 if (!current)
543 {
544 // empty list or beyond the end!
545 return FALSE;
546 }
547
548 // is this the one we want?
549 if (!mEquals(current->mData, data))
550 {
551 // nope!
552 return FALSE;
553 }
554 else
555 {
556 // do we need to fix current or currentop?
557 if (current == mCurrentp)
558 {
559 mCurrentp = current->mForward[0];
560 }
561
562 if (current == mCurrentOperatingp)
563 {
564 mCurrentOperatingp = current->mForward[0];
565 }
566
567 // yes it is! change pointers as required
568 for (level = 0; level < mLevel; level++)
569 {
570 if (mUpdate[level]->mForward[level] != current)
571 {
572 // cool, we've fixed all the pointers!
573 break;
574 }
575 mUpdate[level]->mForward[level] = current->mForward[level];
576 }
577
578 // clean up cuurent
579 current->deleteData();
580 delete current;
581
582 // clean up mHead
583 while ( (mLevel > 1)
584 &&(!mHead.mForward[mLevel - 1]))
585 {
586 mLevel--;
587 }
588 }
589 return TRUE;
590}
591
592// remove all nodes from the list and delete data
593template <class DATA_TYPE, S32 BINARY_DEPTH>
594inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteAllData()
595{
596 LLPtrSkipNode *temp;
597 // reset mCurrentp
598 mCurrentp = *(mHead.mForward);
599
600 while (mCurrentp)
601 {
602 temp = mCurrentp->mForward[0];
603 mCurrentp->deleteData();
604 delete mCurrentp;
605 mCurrentp = temp;
606 }
607
608 S32 i;
609 for (i = 0; i < BINARY_DEPTH; i++)
610 {
611 mHead.mForward[i] = NULL;
612 mUpdate[i] = NULL;
613 }
614
615 mCurrentp = *(mHead.mForward);
616 mCurrentOperatingp = *(mHead.mForward);
617}
618
619// place mCurrentp on first node
620template <class DATA_TYPE, S32 BINARY_DEPTH>
621inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::resetList()
622{
623 mCurrentp = *(mHead.mForward);
624 mCurrentOperatingp = *(mHead.mForward);
625}
626
627// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
628template <class DATA_TYPE, S32 BINARY_DEPTH>
629inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData()
630{
631 if (mCurrentp)
632 {
633 mCurrentOperatingp = mCurrentp;
634 mCurrentp = *mCurrentp->mForward;
635 return mCurrentOperatingp->mData;
636 }
637 else
638 {
639 //return NULL; // causes compile warning
640 return 0; // equivalent, but no warning
641 }
642}
643
644// same as getCurrentData() but a more intuitive name for the operation
645template <class DATA_TYPE, S32 BINARY_DEPTH>
646inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData()
647{
648 if (mCurrentp)
649 {
650 mCurrentOperatingp = mCurrentp;
651 mCurrentp = *mCurrentp->mForward;
652 return mCurrentOperatingp->mData;
653 }
654 else
655 {
656 //return NULL; // causes compile warning
657 return 0; // equivalent, but no warning
658 }
659}
660
661// remove the Node at mCurentOperatingp
662// leave mCurrentp and mCurentOperatingp on the next entry
663template <class DATA_TYPE, S32 BINARY_DEPTH>
664inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData()
665{
666 if (mCurrentOperatingp)
667 {
668 removeData(mCurrentOperatingp->mData);
669 }
670}
671
672// delete the Node at mCurentOperatingp
673// leave mCurrentp and mCurentOperatingp on the next entry
674template <class DATA_TYPE, S32 BINARY_DEPTH>
675inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteCurrentData()
676{
677 if (mCurrentOperatingp)
678 {
679 deleteData(mCurrentOperatingp->mData);
680 }
681}
682
683// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
684template <class DATA_TYPE, S32 BINARY_DEPTH>
685inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getFirstData()
686{
687 mCurrentp = *(mHead.mForward);
688 mCurrentOperatingp = *(mHead.mForward);
689 if (mCurrentp)
690 {
691 mCurrentOperatingp = mCurrentp;
692 mCurrentp = mCurrentp->mForward[0];
693 return mCurrentOperatingp->mData;
694 }
695 else
696 {
697 //return NULL; // causes compile warning
698 return 0; // equivalent, but no warning
699 }
700}
701
702template <class DATA_TYPE, S32 BINARY_DEPTH>
703inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::corrupt()
704{
705 LLPtrSkipNode *previous = mHead.mForward[0];
706
707 // Empty lists are not corrupt.
708 if (!previous) return FALSE;
709
710 LLPtrSkipNode *current = previous->mForward[0];
711 while(current)
712 {
713 if (!mInsertFirst(previous->mData, current->mData))
714 {
715 // prev shouldn't be in front of cur!
716 return TRUE;
717 }
718 current = current->mForward[0];
719 }
720 return FALSE;
721}
722
723#endif