aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/doublelinkedlist.h
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llcommon/doublelinkedlist.h')
-rw-r--r--linden/indra/llcommon/doublelinkedlist.h1398
1 files changed, 1398 insertions, 0 deletions
diff --git a/linden/indra/llcommon/doublelinkedlist.h b/linden/indra/llcommon/doublelinkedlist.h
new file mode 100644
index 0000000..ef289b2
--- /dev/null
+++ b/linden/indra/llcommon/doublelinkedlist.h
@@ -0,0 +1,1398 @@
1/**
2 * @file doublelinkedlist.h
3 * @brief Provides a standard doubly linked list for fun and profit.
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_DOUBLELINKEDLIST_H
29#define LL_DOUBLELINKEDLIST_H
30
31#include "llerror.h"
32#include "llrand.h"
33
34// node that actually contains the data
35template <class DATA_TYPE> class LLDoubleLinkedNode
36{
37public:
38 DATA_TYPE *mDatap;
39 LLDoubleLinkedNode *mNextp;
40 LLDoubleLinkedNode *mPrevp;
41
42
43public:
44 // assign the mDatap pointer
45 LLDoubleLinkedNode(DATA_TYPE *data);
46
47 // destructor does not, by default, destroy associated data
48 // however, the mDatap must be NULL to ensure that we aren't causing memory leaks
49 ~LLDoubleLinkedNode();
50
51 // delete associated data and NULL out pointer
52 void deleteData();
53
54 // remove associated data and NULL out pointer
55 void removeData();
56};
57
58
59const U32 LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH = 4;
60
61template <class DATA_TYPE> class LLDoubleLinkedList
62{
63private:
64 LLDoubleLinkedNode<DATA_TYPE> mHead; // head node
65 LLDoubleLinkedNode<DATA_TYPE> mTail; // tail node
66 LLDoubleLinkedNode<DATA_TYPE> *mQueuep; // The node in the batter's box
67 LLDoubleLinkedNode<DATA_TYPE> *mCurrentp; // The node we're talking about
68
69 // The state stack allows nested exploration of the LLDoubleLinkedList
70 // but should be used with great care
71 LLDoubleLinkedNode<DATA_TYPE> *mQueuepStack[LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH];
72 LLDoubleLinkedNode<DATA_TYPE> *mCurrentpStack[LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH];
73 U32 mStateStackDepth;
74 U32 mCount;
75
76 // mInsertBefore is a pointer to a user-set function that returns
77 // TRUE if "first" should be located before "second"
78 // NOTE: mInsertBefore() should never return TRUE when ("first" == "second")
79 // or never-ending loops can occur
80 BOOL (*mInsertBefore)(DATA_TYPE *first, DATA_TYPE *second);
81
82public:
83 LLDoubleLinkedList();
84
85 // destructor destroys list and nodes, but not data in nodes
86 ~LLDoubleLinkedList();
87
88 // put data into a node and stick it at the front of the list
89 // set mCurrentp to mQueuep
90 void addData(DATA_TYPE *data);
91
92 // put data into a node and stick it at the end of the list
93 // set mCurrentp to mQueuep
94 void addDataAtEnd(DATA_TYPE *data);
95
96 S32 getLength() const;
97 // search the list starting at mHead.mNextp and remove the link with mDatap == data
98 // set mCurrentp to mQueuep
99 // return TRUE if found, FALSE if not found
100 BOOL removeData(const DATA_TYPE *data);
101
102 // search the list starting at mHead.mNextp and delete the link with mDatap == data
103 // set mCurrentp to mQueuep
104 // return TRUE if found, FALSE if not found
105 BOOL deleteData(DATA_TYPE *data);
106
107 // remove all nodes from the list and delete the associated data
108 void deleteAllData();
109
110 // remove all nodes from the list but do not delete data
111 void removeAllNodes();
112
113 BOOL isEmpty();
114
115 // check to see if data is in list
116 // set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep
117 // return TRUE if found, FALSE if not found
118 BOOL checkData(const DATA_TYPE *data);
119
120 // NOTE: This next two funtions are only included here
121 // for those too familiar with the LLLinkedList template class.
122 // They are depreciated. resetList() is unecessary while
123 // getCurrentData() is identical to getNextData() and has
124 // a misleading name.
125 //
126 // The recommended way to loop through a list is as follows:
127 //
128 // datap = list.getFirstData();
129 // while (datap)
130 // {
131 // /* do stuff */
132 // datap = list.getNextData();
133 // }
134
135 // place mQueuep on mHead node
136 void resetList();
137
138 // return the data currently pointed to,
139 // set mCurrentp to that node and bump mQueuep down the list
140 // NOTE: this function is identical to getNextData()
141 DATA_TYPE *getCurrentData();
142
143
144 // reset the list and return the data currently pointed to,
145 // set mCurrentp to that node and bump mQueuep down the list
146 DATA_TYPE *getFirstData();
147
148
149 // reset the list and return the data at position n, set mCurentp
150 // to that node and bump mQueuep down the list
151 // Note: n=0 will behave like getFirstData()
152 DATA_TYPE *getNthData(U32 n);
153
154 // reset the list and return the last data in it,
155 // set mCurrentp to that node and bump mQueuep up the list
156 DATA_TYPE *getLastData();
157
158 // return data in mQueuep,
159 // set mCurrentp mQueuep and bump mQueuep down the list
160 DATA_TYPE *getNextData();
161
162 // return the data in mQueuep,
163 // set mCurrentp to mQueuep and bump mQueuep up the list
164 DATA_TYPE *getPreviousData();
165
166 // remove the Node at mCurrentp
167 // set mCurrentp to mQueuep
168 void removeCurrentData();
169
170 // delete the Node at mCurrentp
171 // set mCurrentp to mQueuep
172 void deleteCurrentData();
173
174 // remove the Node at mCurrentp and insert it into newlist
175 // set mCurrentp to mQueuep
176 void moveCurrentData(LLDoubleLinkedList<DATA_TYPE> *newlist);
177
178 // insert the node in front of mCurrentp
179 // set mCurrentp to mQueuep
180 void insertNode(LLDoubleLinkedNode<DATA_TYPE> *node);
181
182 // insert the data in front of mCurrentp
183 // set mCurrentp to mQueuep
184 void insertData(DATA_TYPE *data);
185
186 // if mCurrentp has a previous node then :
187 // * swaps mCurrentp with its previous
188 // * set mCurrentp to mQueuep
189 // (convenient for forward bubble-sort)
190 // otherwise does nothing
191 void swapCurrentWithPrevious();
192
193 // if mCurrentp has a next node then :
194 // * swaps mCurrentp with its next
195 // * set mCurrentp to mQueuep
196 // (convenient for backwards bubble-sort)
197 // otherwise does nothing
198 void swapCurrentWithNext();
199
200 // move mCurrentp to the front of the list
201 // set mCurrentp to mQueuep
202 void moveCurrentToFront();
203
204 // move mCurrentp to the end of the list
205 // set mCurrentp to mQueuep
206 void moveCurrentToEnd();
207
208 // set mInsertBefore
209 void setInsertBefore(BOOL (*insert_before)(DATA_TYPE *first, DATA_TYPE *second));
210
211 // add data in front of first node for which mInsertBefore(datap, node->mDatap) returns TRUE
212 // set mCurrentp to mQueuep
213 BOOL addDataSorted(DATA_TYPE *datap);
214
215 // sort the list using bubble-sort
216 // Yes, this is a different name than the same function in LLLinkedList.
217 // When it comes time for a name consolidation hopefully this one will win.
218 BOOL bubbleSort();
219
220 // does a single bubble sort pass on the list
221 BOOL lazyBubbleSort();
222
223 // returns TRUE if state successfully pushed (state stack not full)
224 BOOL pushState();
225
226 // returns TRUE if state successfully popped (state stack not empty)
227 BOOL popState();
228
229 // empties the state stack
230 void clearStateStack();
231
232 // randomly move the the links in the list for debug or (Discordian) purposes
233 // sets mCurrentp and mQueuep to top of list
234 void scramble();
235
236private:
237 // add node to beginning of list
238 // set mCurrentp to mQueuep
239 void addNode(LLDoubleLinkedNode<DATA_TYPE> *node);
240
241 // add node to end of list
242 // set mCurrentp to mQueuep
243 void addNodeAtEnd(LLDoubleLinkedNode<DATA_TYPE> *node);
244};
245
246//#endif
247
248////////////////////////////////////////////////////////////////////////////////////////////
249
250// doublelinkedlist.cpp
251// LLDoubleLinkedList template class implementation file.
252// Provides a standard doubly linked list for fun and profit.
253//
254// Copyright 2001, Linden Research, Inc.
255
256//#include "llerror.h"
257//#include "doublelinkedlist.h"
258
259//////////////////////////////////////////////////////////////////////////////////////////
260// LLDoubleLinkedNode
261//////////////////////////////////////////////////////////////////////////////////////////
262
263
264// assign the mDatap pointer
265template <class DATA_TYPE>
266LLDoubleLinkedNode<DATA_TYPE>::LLDoubleLinkedNode(DATA_TYPE *data) :
267 mDatap(data), mNextp(NULL), mPrevp(NULL)
268{
269}
270
271
272// destructor does not, by default, destroy associated data
273// however, the mDatap must be NULL to ensure that we aren't causing memory leaks
274template <class DATA_TYPE>
275LLDoubleLinkedNode<DATA_TYPE>::~LLDoubleLinkedNode()
276{
277 if (mDatap)
278 {
279 llerror("Attempting to call LLDoubleLinkedNode destructor with a non-null mDatap!", 1);
280 }
281}
282
283
284// delete associated data and NULL out pointer
285template <class DATA_TYPE>
286void LLDoubleLinkedNode<DATA_TYPE>::deleteData()
287{
288 delete mDatap;
289 mDatap = NULL;
290}
291
292
293template <class DATA_TYPE>
294void LLDoubleLinkedNode<DATA_TYPE>::removeData()
295{
296 mDatap = NULL;
297}
298
299
300//////////////////////////////////////////////////////////////////////////////////////
301// LLDoubleLinkedList
302//////////////////////////////////////////////////////////////////////////////////////
303
304// <------- up -------
305//
306// mCurrentp
307// mQueuep |
308// | |
309// | |
310// .------. .------. .------. .------.
311// | |---->| |---->| |----->| |-----> NULL
312// NULL <-----| |<----| |<----| |<-----| |
313// _'------' '------' '------' '------:_
314// .------. /| | | |\ .------.
315// NULL <-----|mHead |/ | mQueuep \|mTail |-----> NULL
316// | | mCurrentp | |
317// '------' '------'
318// -------- down --------->
319
320template <class DATA_TYPE>
321LLDoubleLinkedList<DATA_TYPE>::LLDoubleLinkedList()
322: mHead(NULL), mTail(NULL), mQueuep(NULL)
323{
324 mCurrentp = mHead.mNextp;
325 mQueuep = mHead.mNextp;
326 mStateStackDepth = 0;
327 mCount = 0;
328 mInsertBefore = NULL;
329}
330
331
332// destructor destroys list and nodes, but not data in nodes
333template <class DATA_TYPE>
334LLDoubleLinkedList<DATA_TYPE>::~LLDoubleLinkedList()
335{
336 removeAllNodes();
337}
338
339
340// put data into a node and stick it at the front of the list
341// doesn't change mCurrentp nor mQueuep
342template <class DATA_TYPE>
343void LLDoubleLinkedList<DATA_TYPE>::addData(DATA_TYPE *data)
344{
345 // don't allow NULL to be passed to addData
346 if (!data)
347 {
348 llerror("NULL pointer passed to LLDoubleLinkedList::addData()", 0);
349 }
350
351 // make the new node
352 LLDoubleLinkedNode<DATA_TYPE> *temp = new LLDoubleLinkedNode<DATA_TYPE> (data);
353
354 // add the node to the front of the list
355 temp->mPrevp = NULL;
356 temp->mNextp = mHead.mNextp;
357 mHead.mNextp = temp;
358
359 // if there's something in the list, fix its back pointer
360 if (temp->mNextp)
361 {
362 temp->mNextp->mPrevp = temp;
363 }
364 // otherwise, fix the tail of the list
365 else
366 {
367 mTail.mPrevp = temp;
368 }
369
370 mCount++;
371}
372
373
374// put data into a node and stick it at the end of the list
375template <class DATA_TYPE>
376void LLDoubleLinkedList<DATA_TYPE>::addDataAtEnd(DATA_TYPE *data)
377{
378 // don't allow NULL to be passed to addData
379 if (!data)
380 {
381 llerror("NULL pointer passed to LLDoubleLinkedList::addData()", 0);
382 }
383
384 // make the new node
385 LLDoubleLinkedNode<DATA_TYPE> *nodep = new LLDoubleLinkedNode<DATA_TYPE>(data);
386
387 addNodeAtEnd(nodep);
388 mCount++;
389}
390
391
392// search the list starting at mHead.mNextp and remove the link with mDatap == data
393// set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data
394// return TRUE if found, FALSE if not found
395template <class DATA_TYPE>
396BOOL LLDoubleLinkedList<DATA_TYPE>::removeData(const DATA_TYPE *data)
397{
398 BOOL b_found = FALSE;
399 // don't allow NULL to be passed to addData
400 if (!data)
401 {
402 llerror("NULL pointer passed to LLDoubleLinkedList::removeData()", 0);
403 }
404
405 mCurrentp = mHead.mNextp;
406
407 while (mCurrentp)
408 {
409 if (mCurrentp->mDatap == data)
410 {
411 b_found = TRUE;
412
413 // if there is a next one, fix it
414 if (mCurrentp->mNextp)
415 {
416 mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
417 }
418 else // we are at end of list
419 {
420 mTail.mPrevp = mCurrentp->mPrevp;
421 }
422
423 // if there is a previous one, fix it
424 if (mCurrentp->mPrevp)
425 {
426 mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
427 }
428 else // we are at beginning of list
429 {
430 mHead.mNextp = mCurrentp->mNextp;
431 }
432
433 // remove the node
434 mCurrentp->removeData();
435 delete mCurrentp;
436 mCount--;
437 break;
438 }
439 mCurrentp = mCurrentp->mNextp;
440 }
441
442 // reset the list back to where it was
443 if (mCurrentp == mQueuep)
444 {
445 mCurrentp = mQueuep = NULL;
446 }
447 else
448 {
449 mCurrentp = mQueuep;
450 }
451
452 return b_found;
453}
454
455
456// search the list starting at mHead.mNextp and delete the link with mDatap == data
457// set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data
458// return TRUE if found, FALSE if not found
459template <class DATA_TYPE>
460BOOL LLDoubleLinkedList<DATA_TYPE>::deleteData(DATA_TYPE *data)
461{
462 BOOL b_found = FALSE;
463 // don't allow NULL to be passed to addData
464 if (!data)
465 {
466 llerror("NULL pointer passed to LLDoubleLinkedList::deleteData()", 0);
467 }
468
469 mCurrentp = mHead.mNextp;
470
471 while (mCurrentp)
472 {
473 if (mCurrentp->mDatap == data)
474 {
475 b_found = TRUE;
476
477 // if there is a next one, fix it
478 if (mCurrentp->mNextp)
479 {
480 mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
481 }
482 else // we are at end of list
483 {
484 mTail.mPrevp = mCurrentp->mPrevp;
485 }
486
487 // if there is a previous one, fix it
488 if (mCurrentp->mPrevp)
489 {
490 mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
491 }
492 else // we are at beginning of list
493 {
494 mHead.mNextp = mCurrentp->mNextp;
495 }
496
497 // remove the node
498 mCurrentp->deleteData();
499 delete mCurrentp;
500 mCount--;
501 break;
502 }
503 mCurrentp = mCurrentp->mNextp;
504 }
505
506 // reset the list back to where it was
507 if (mCurrentp == mQueuep)
508 {
509 mCurrentp = mQueuep = NULL;
510 }
511 else
512 {
513 mCurrentp = mQueuep;
514 }
515
516 return b_found;
517}
518
519
520// remove all nodes from the list and delete the associated data
521template <class DATA_TYPE>
522void LLDoubleLinkedList<DATA_TYPE>::deleteAllData()
523{
524 mCurrentp = mHead.mNextp;
525
526 while (mCurrentp)
527 {
528 mQueuep = mCurrentp->mNextp;
529 mCurrentp->deleteData();
530 delete mCurrentp;
531 mCurrentp = mQueuep;
532 }
533
534 // reset mHead and mQueuep
535 mHead.mNextp = NULL;
536 mTail.mPrevp = NULL;
537 mCurrentp = mHead.mNextp;
538 mQueuep = mHead.mNextp;
539 mStateStackDepth = 0;
540 mCount = 0;
541}
542
543
544// remove all nodes from the list but do not delete associated data
545template <class DATA_TYPE>
546void LLDoubleLinkedList<DATA_TYPE>::removeAllNodes()
547{
548 mCurrentp = mHead.mNextp;
549
550 while (mCurrentp)
551 {
552 mQueuep = mCurrentp->mNextp;
553 mCurrentp->removeData();
554 delete mCurrentp;
555 mCurrentp = mQueuep;
556 }
557
558 // reset mHead and mCurrentp
559 mHead.mNextp = NULL;
560 mTail.mPrevp = NULL;
561 mCurrentp = mHead.mNextp;
562 mQueuep = mHead.mNextp;
563 mStateStackDepth = 0;
564 mCount = 0;
565}
566
567template <class DATA_TYPE>
568S32 LLDoubleLinkedList<DATA_TYPE>::getLength() const
569{
570// U32 length = 0;
571// for (LLDoubleLinkedNode<DATA_TYPE>* temp = mHead.mNextp; temp != NULL; temp = temp->mNextp)
572// {
573// length++;
574// }
575 return mCount;
576}
577
578// check to see if data is in list
579// set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep
580// return TRUE if found, FALSE if not found
581template <class DATA_TYPE>
582BOOL LLDoubleLinkedList<DATA_TYPE>::checkData(const DATA_TYPE *data)
583{
584 mCurrentp = mHead.mNextp;
585
586 while (mCurrentp)
587 {
588 if (mCurrentp->mDatap == data)
589 {
590 mQueuep = mCurrentp;
591 return TRUE;
592 }
593 mCurrentp = mCurrentp->mNextp;
594 }
595
596 mCurrentp = mQueuep;
597 return FALSE;
598}
599
600// NOTE: This next two funtions are only included here
601// for those too familiar with the LLLinkedList template class.
602// They are depreciated. resetList() is unecessary while
603// getCurrentData() is identical to getNextData() and has
604// a misleading name.
605//
606// The recommended way to loop through a list is as follows:
607//
608// datap = list.getFirstData();
609// while (datap)
610// {
611// /* do stuff */
612// datap = list.getNextData();
613// }
614
615 // place mCurrentp and mQueuep on first node
616 template <class DATA_TYPE>
617 void LLDoubleLinkedList<DATA_TYPE>::resetList()
618 {
619 mCurrentp = mHead.mNextp;
620 mQueuep = mHead.mNextp;
621 mStateStackDepth = 0;
622 }
623
624
625 // return the data currently pointed to,
626 // set mCurrentp to that node and bump mQueuep down the list
627 template <class DATA_TYPE>
628 DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getCurrentData()
629 {
630 if (mQueuep)
631 {
632 mCurrentp = mQueuep;
633 mQueuep = mQueuep->mNextp;
634 return mCurrentp->mDatap;
635 }
636 else
637 {
638 return NULL;
639 }
640 }
641
642
643// reset the list and return the data currently pointed to,
644// set mCurrentp to that node and bump mQueuep down the list
645template <class DATA_TYPE>
646DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getFirstData()
647{
648 mQueuep = mHead.mNextp;
649 mCurrentp = mQueuep;
650 if (mQueuep)
651 {
652 mQueuep = mQueuep->mNextp;
653 return mCurrentp->mDatap;
654 }
655 else
656 {
657 return NULL;
658 }
659}
660
661
662// reset the list and return the data at position n, set mCurentp
663// to that node and bump mQueuep down the list
664// Note: n=0 will behave like getFirstData()
665template <class DATA_TYPE>
666DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getNthData(U32 n)
667{
668 mCurrentp = mHead.mNextp;
669
670 if (mCurrentp)
671 {
672 for (U32 i=0; i<n; i++)
673 {
674 mCurrentp = mCurrentp->mNextp;
675 if (!mCurrentp)
676 {
677 break;
678 }
679 }
680 }
681
682 if (mCurrentp)
683 {
684 // bump mQueuep down the list
685 mQueuep = mCurrentp->mNextp;
686 return mCurrentp->mDatap;
687 }
688 else
689 {
690 mQueuep = NULL;
691 return NULL;
692 }
693}
694
695
696// reset the list and return the last data in it,
697// set mCurrentp to that node and bump mQueuep up the list
698template <class DATA_TYPE>
699DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getLastData()
700{
701 mQueuep = mTail.mPrevp;
702 mCurrentp = mQueuep;
703 if (mQueuep)
704 {
705 mQueuep = mQueuep->mPrevp;
706 return mCurrentp->mDatap;
707 }
708 else
709 {
710 return NULL;
711 }
712}
713
714
715// return the data in mQueuep,
716// set mCurrentp to mQueuep and bump mQueuep down the list
717template <class DATA_TYPE>
718DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getNextData()
719{
720 if (mQueuep)
721 {
722 mCurrentp = mQueuep;
723 mQueuep = mQueuep->mNextp;
724 return mCurrentp->mDatap;
725 }
726 else
727 {
728 return NULL;
729 }
730}
731
732
733// return the data in mQueuep,
734// set mCurrentp to mQueuep and bump mQueuep up the list
735template <class DATA_TYPE>
736DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getPreviousData()
737{
738 if (mQueuep)
739 {
740 mCurrentp = mQueuep;
741 mQueuep = mQueuep->mPrevp;
742 return mCurrentp->mDatap;
743 }
744 else
745 {
746 return NULL;
747 }
748}
749
750
751// remove the Node at mCurrentp
752// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep)
753template <class DATA_TYPE>
754void LLDoubleLinkedList<DATA_TYPE>::removeCurrentData()
755{
756 if (mCurrentp)
757 {
758 // if there is a next one, fix it
759 if (mCurrentp->mNextp)
760 {
761 mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
762 }
763 else // otherwise we are at end of list
764 {
765 mTail.mPrevp = mCurrentp->mPrevp;
766 }
767
768 // if there is a previous one, fix it
769 if (mCurrentp->mPrevp)
770 {
771 mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
772 }
773 else // otherwise we are at beginning of list
774 {
775 mHead.mNextp = mCurrentp->mNextp;
776 }
777
778 // remove the node
779 mCurrentp->removeData();
780 delete mCurrentp;
781 mCount--;
782
783 // check for redundant pointing
784 if (mCurrentp == mQueuep)
785 {
786 mCurrentp = mQueuep = NULL;
787 }
788 else
789 {
790 mCurrentp = mQueuep;
791 }
792 }
793}
794
795
796// delete the Node at mCurrentp
797// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep)
798template <class DATA_TYPE>
799void LLDoubleLinkedList<DATA_TYPE>::deleteCurrentData()
800{
801 if (mCurrentp)
802 {
803 // remove the node
804 // if there is a next one, fix it
805 if (mCurrentp->mNextp)
806 {
807 mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
808 }
809 else // otherwise we are at end of list
810 {
811 mTail.mPrevp = mCurrentp->mPrevp;
812 }
813
814 // if there is a previous one, fix it
815 if (mCurrentp->mPrevp)
816 {
817 mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
818 }
819 else // otherwise we are at beginning of list
820 {
821 mHead.mNextp = mCurrentp->mNextp;
822 }
823
824 // remove the LLDoubleLinkedNode
825 mCurrentp->deleteData();
826 delete mCurrentp;
827 mCount--;
828
829 // check for redundant pointing
830 if (mCurrentp == mQueuep)
831 {
832 mCurrentp = mQueuep = NULL;
833 }
834 else
835 {
836 mCurrentp = mQueuep;
837 }
838 }
839}
840
841
842// remove the Node at mCurrentp and insert it into newlist
843// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep)
844template <class DATA_TYPE>
845void LLDoubleLinkedList<DATA_TYPE>::moveCurrentData(LLDoubleLinkedList<DATA_TYPE> *newlist)
846{
847 if (mCurrentp)
848 {
849 // remove the node
850 // if there is a next one, fix it
851 if (mCurrentp->mNextp)
852 {
853 mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
854 }
855 else // otherwise we are at end of list
856 {
857 mTail.mPrevp = mCurrentp->mPrevp;
858 }
859
860 // if there is a previous one, fix it
861 if (mCurrentp->mPrevp)
862 {
863 mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
864 }
865 else // otherwise we are at beginning of list
866 {
867 mHead.mNextp = mCurrentp->mNextp;
868 }
869
870 // move the node to the new list
871 newlist->addNode(mCurrentp);
872
873 // check for redundant pointing
874 if (mCurrentp == mQueuep)
875 {
876 mCurrentp = mQueuep = NULL;
877 }
878 else
879 {
880 mCurrentp = mQueuep;
881 }
882 }
883}
884
885
886// Inserts the node previous to mCurrentp
887// set mCurrentp to mQueuep
888template <class DATA_TYPE>
889void LLDoubleLinkedList<DATA_TYPE>::insertNode(LLDoubleLinkedNode<DATA_TYPE> *nodep)
890{
891 // don't allow pointer to NULL to be passed
892 if (!nodep)
893 {
894 llerror("NULL pointer passed to LLDoubleLinkedList::insertNode()", 0);
895 }
896 if (!nodep->mDatap)
897 {
898 llerror("NULL data pointer passed to LLDoubleLinkedList::insertNode()", 0);
899 }
900
901 if (mCurrentp)
902 {
903 if (mCurrentp->mPrevp)
904 {
905 nodep->mPrevp = mCurrentp->mPrevp;
906 nodep->mNextp = mCurrentp;
907 mCurrentp->mPrevp->mNextp = nodep;
908 mCurrentp->mPrevp = nodep;
909 }
910 else // at beginning of list
911 {
912 nodep->mPrevp = NULL;
913 nodep->mNextp = mCurrentp;
914 mHead.mNextp = nodep;
915 mCurrentp->mPrevp = nodep;
916 }
917 mCurrentp = mQueuep;
918 }
919 else // add to front of list
920 {
921 addNode(nodep);
922 }
923}
924
925
926// insert the data in front of mCurrentp
927// set mCurrentp to mQueuep
928template <class DATA_TYPE>
929void LLDoubleLinkedList<DATA_TYPE>::insertData(DATA_TYPE *data)
930{
931 if (!data)
932 {
933 llerror("NULL data pointer passed to LLDoubleLinkedList::insertNode()", 0);
934 }
935 LLDoubleLinkedNode<DATA_TYPE> *node = new LLDoubleLinkedNode<DATA_TYPE>(data);
936 insertNode(node);
937 mCount++;
938}
939
940
941// if mCurrentp has a previous node then :
942// * swaps mCurrentp with its previous
943// * set mCurrentp to mQueuep
944// otherwise does nothing
945template <class DATA_TYPE>
946void LLDoubleLinkedList<DATA_TYPE>::swapCurrentWithPrevious()
947{
948 if (mCurrentp)
949 {
950 if (mCurrentp->mPrevp)
951 {
952 // Pull mCurrentp out of list
953 mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
954 if (mCurrentp->mNextp)
955 {
956 mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
957 }
958 else // mCurrentp was at end of list
959 {
960 mTail.mPrevp = mCurrentp->mPrevp;
961 }
962
963 // Fix mCurrentp's pointers
964 mCurrentp->mNextp = mCurrentp->mPrevp;
965 mCurrentp->mPrevp = mCurrentp->mNextp->mPrevp;
966 mCurrentp->mNextp->mPrevp = mCurrentp;
967
968 if (mCurrentp->mPrevp)
969 {
970 // Fix the backward pointer of mCurrentp's new previous
971 mCurrentp->mPrevp->mNextp = mCurrentp;
972 }
973 else // mCurrentp is now at beginning of list
974 {
975 mHead.mNextp = mCurrentp;
976 }
977
978 // Set the list back to the way it was
979 mCurrentp = mQueuep;
980 }
981 }
982}
983
984
985// if mCurrentp has a next node then :
986// * swaps mCurrentp with its next
987// * set mCurrentp to mQueuep
988// otherwise does nothing
989template <class DATA_TYPE>
990void LLDoubleLinkedList<DATA_TYPE>::swapCurrentWithNext()
991{
992 if (mCurrentp)
993 {
994 if (mCurrentp->mNextp)
995 {
996 // Pull mCurrentp out of list
997 mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
998 if (mCurrentp->mPrevp)
999 {
1000 mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
1001 }
1002 else // mCurrentp was at beginning of list
1003 {
1004 mHead.mNextp = mCurrentp->mNextp;
1005 }
1006
1007 // Fix mCurrentp's pointers
1008 mCurrentp->mPrevp = mCurrentp->mNextp;
1009 mCurrentp->mNextp = mCurrentp->mPrevp->mNextp;
1010 mCurrentp->mPrevp->mNextp = mCurrentp;
1011
1012 if (mCurrentp->mNextp)
1013 {
1014 // Fix the back pointer of mCurrentp's new next
1015 mCurrentp->mNextp->mPrevp = mCurrentp;
1016 }
1017 else // mCurrentp is now at end of list
1018 {
1019 mTail.mPrevp = mCurrentp;
1020 }
1021
1022 // Set the list back to the way it was
1023 mCurrentp = mQueuep;
1024 }
1025 }
1026}
1027
1028// move mCurrentp to the front of the list
1029// set mCurrentp to mQueuep
1030template <class DATA_TYPE>
1031void LLDoubleLinkedList<DATA_TYPE>::moveCurrentToFront()
1032{
1033 if (mCurrentp)
1034 {
1035 // if there is a previous one, fix it
1036 if (mCurrentp->mPrevp)
1037 {
1038 mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
1039 }
1040 else // otherwise we are at beginning of list
1041 {
1042 // check for redundant pointing
1043 if (mCurrentp == mQueuep)
1044 {
1045 mCurrentp = mQueuep = NULL;
1046 }
1047 else
1048 {
1049 mCurrentp = mQueuep;
1050 }
1051 return;
1052 }
1053
1054 // if there is a next one, fix it
1055 if (mCurrentp->mNextp)
1056 {
1057 mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
1058 }
1059 else // otherwise we are at end of list
1060 {
1061 mTail.mPrevp = mCurrentp->mPrevp;
1062 }
1063
1064 // add mCurrentp to beginning of list
1065 mCurrentp->mNextp = mHead.mNextp;
1066 mHead.mNextp->mPrevp = mCurrentp; // mHead.mNextp MUST be valid,
1067 // or the list had only one node
1068 // and we would have returned already
1069 mCurrentp->mPrevp = NULL;
1070 mHead.mNextp = mCurrentp;
1071
1072 // check for redundant pointing
1073 if (mCurrentp == mQueuep)
1074 {
1075 mCurrentp = mQueuep = NULL;
1076 }
1077 else
1078 {
1079 mCurrentp = mQueuep;
1080 }
1081 }
1082
1083}
1084
1085// move mCurrentp to the end of the list
1086// set mCurrentp to mQueuep
1087template <class DATA_TYPE>
1088void LLDoubleLinkedList<DATA_TYPE>::moveCurrentToEnd()
1089{
1090 if (mCurrentp)
1091 {
1092 // if there is a next one, fix it
1093 if (mCurrentp->mNextp)
1094 {
1095 mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp;
1096 }
1097 else // otherwise we are at end of list and we're done
1098 {
1099 // check for redundant pointing
1100 if (mCurrentp == mQueuep)
1101 {
1102 mCurrentp = mQueuep = NULL;
1103 }
1104 else
1105 {
1106 mCurrentp = mQueuep;
1107 }
1108 return;
1109 }
1110
1111 // if there is a previous one, fix it
1112 if (mCurrentp->mPrevp)
1113 {
1114 mCurrentp->mPrevp->mNextp = mCurrentp->mNextp;
1115 }
1116 else // otherwise we are at beginning of list
1117 {
1118 mHead.mNextp = mCurrentp->mNextp;
1119 }
1120
1121 // add mCurrentp to end of list
1122 mCurrentp->mPrevp = mTail.mPrevp;
1123 mTail.mPrevp->mNextp = mCurrentp; // mTail.mPrevp MUST be valid,
1124 // or the list had only one node
1125 // and we would have returned already
1126 mCurrentp->mNextp = NULL;
1127 mTail.mPrevp = mCurrentp;
1128
1129 // check for redundant pointing
1130 if (mCurrentp == mQueuep)
1131 {
1132 mCurrentp = mQueuep = NULL;
1133 }
1134 else
1135 {
1136 mCurrentp = mQueuep;
1137 }
1138 }
1139}
1140
1141
1142template <class DATA_TYPE>
1143void LLDoubleLinkedList<DATA_TYPE>::setInsertBefore(BOOL (*insert_before)(DATA_TYPE *first, DATA_TYPE *second) )
1144{
1145 mInsertBefore = insert_before;
1146}
1147
1148
1149// add data in front of the first node for which mInsertBefore(datap, node->mDatap) returns TRUE
1150// set mCurrentp to mQueuep
1151template <class DATA_TYPE>
1152BOOL LLDoubleLinkedList<DATA_TYPE>::addDataSorted(DATA_TYPE *datap)
1153{
1154 // don't allow NULL to be passed to addData()
1155 if (!datap)
1156 {
1157 llerror("NULL pointer passed to LLDoubleLinkedList::addDataSorted()", 0);
1158 }
1159
1160 // has mInsertBefore not been set?
1161 if (!mInsertBefore)
1162 {
1163 addData(datap);
1164 return FALSE;
1165 }
1166
1167 // is the list empty?
1168 if (!mHead.mNextp)
1169 {
1170 addData(datap);
1171 return TRUE;
1172 }
1173
1174 // Note: this step has been added so that the behavior of LLDoubleLinkedList
1175 // is as rigorous as the LLLinkedList class about adding duplicate nodes.
1176 // Duplicate nodes can cause a problem when sorting if mInsertBefore(foo, foo)
1177 // returns TRUE. However, if mInsertBefore(foo, foo) returns FALSE, then there
1178 // shouldn't be any reason to exclude duplicate nodes (as we do here).
1179 if (checkData(datap))
1180 {
1181 return FALSE;
1182 }
1183
1184 mCurrentp = mHead.mNextp;
1185 while (mCurrentp)
1186 {
1187 // check to see if datap is already in the list
1188 if (datap == mCurrentp->mDatap)
1189 {
1190 return FALSE;
1191 }
1192 else if (mInsertBefore(datap, mCurrentp->mDatap))
1193 {
1194 insertData(datap);
1195 return TRUE;
1196 }
1197 mCurrentp = mCurrentp->mNextp;
1198 }
1199
1200 addDataAtEnd(datap);
1201 return TRUE;
1202}
1203
1204
1205// bubble-sort until sorted and return TRUE if anything was sorted
1206// leaves mQueuep pointing at last node that was swapped with its mNextp
1207//
1208// NOTE: if you find this function looping for really long times, then you
1209// probably need to check your implementation of mInsertBefore(a,b) and make
1210// sure it does not return TRUE when (a == b)!
1211template <class DATA_TYPE>
1212BOOL LLDoubleLinkedList<DATA_TYPE>::bubbleSort()
1213{
1214 BOOL b_swapped = FALSE;
1215 U32 count = 0;
1216 while (lazyBubbleSort())
1217 {
1218 b_swapped = TRUE;
1219 if (count++ > 0x7FFFFFFF)
1220 {
1221 llwarning("LLDoubleLinkedList::bubbleSort() : too many passes...", 1);
1222 llwarning(" make sure the mInsertBefore(a, b) does not return TRUE for a == b", 1);
1223 break;
1224 }
1225 }
1226 return b_swapped;
1227}
1228
1229
1230// do a single bubble-sort pass and return TRUE if anything was sorted
1231// leaves mQueuep pointing at last node that was swapped with its mNextp
1232template <class DATA_TYPE>
1233BOOL LLDoubleLinkedList<DATA_TYPE>::lazyBubbleSort()
1234{
1235 // has mInsertBefore been set?
1236 if (!mInsertBefore)
1237 {
1238 return FALSE;
1239 }
1240
1241 // is list empty?
1242 mCurrentp = mHead.mNextp;
1243 if (!mCurrentp)
1244 {
1245 return FALSE;
1246 }
1247
1248 BOOL b_swapped = FALSE;
1249
1250 // the sort will exit after 0x7FFFFFFF nodes or the end of the list, whichever is first
1251 S32 length = 0x7FFFFFFF;
1252 S32 count = 0;
1253
1254 while (mCurrentp && mCurrentp->mNextp && count<length)
1255 {
1256 if (mInsertBefore(mCurrentp->mNextp->mDatap, mCurrentp->mDatap))
1257 {
1258 b_swapped = TRUE;
1259 mQueuep = mCurrentp;
1260 swapCurrentWithNext(); // sets mCurrentp to mQueuep
1261 }
1262 count++;
1263 mCurrentp = mCurrentp->mNextp;
1264 }
1265
1266 return b_swapped;
1267}
1268
1269
1270template <class DATA_TYPE>
1271BOOL LLDoubleLinkedList<DATA_TYPE>::pushState()
1272{
1273 if (mStateStackDepth < LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH)
1274 {
1275 *(mQueuepStack + mStateStackDepth) = mQueuep;
1276 *(mCurrentpStack + mStateStackDepth) = mCurrentp;
1277 mStateStackDepth++;
1278 return TRUE;
1279 }
1280 return FALSE;
1281}
1282
1283
1284template <class DATA_TYPE>
1285BOOL LLDoubleLinkedList<DATA_TYPE>::popState()
1286{
1287 if (mStateStackDepth > 0)
1288 {
1289 mStateStackDepth--;
1290 mQueuep = *(mQueuepStack + mStateStackDepth);
1291 mCurrentp = *(mCurrentpStack + mStateStackDepth);
1292 return TRUE;
1293 }
1294 return FALSE;
1295}
1296
1297
1298template <class DATA_TYPE>
1299void LLDoubleLinkedList<DATA_TYPE>::clearStateStack()
1300{
1301 mStateStackDepth = 0;
1302}
1303
1304//////////////////////////////////////////////////////////////////////////////////////////
1305// private members
1306//////////////////////////////////////////////////////////////////////////////////////////
1307
1308// add node to beginning of list
1309// set mCurrentp to mQueuep
1310template <class DATA_TYPE>
1311void LLDoubleLinkedList<DATA_TYPE>::addNode(LLDoubleLinkedNode<DATA_TYPE> *nodep)
1312{
1313 // add the node to the front of the list
1314 nodep->mPrevp = NULL;
1315 nodep->mNextp = mHead.mNextp;
1316 mHead.mNextp = nodep;
1317
1318 // if there's something in the list, fix its back pointer
1319 if (nodep->mNextp)
1320 {
1321 nodep->mNextp->mPrevp = nodep;
1322 }
1323 else // otherwise fix the tail node
1324 {
1325 mTail.mPrevp = nodep;
1326 }
1327
1328 mCurrentp = mQueuep;
1329}
1330
1331
1332// add node to end of list
1333// set mCurrentp to mQueuep
1334template <class DATA_TYPE>
1335void LLDoubleLinkedList<DATA_TYPE>::addNodeAtEnd(LLDoubleLinkedNode<DATA_TYPE> *node)
1336{
1337 // add the node to the end of the list
1338 node->mNextp = NULL;
1339 node->mPrevp = mTail.mPrevp;
1340 mTail.mPrevp = node;
1341
1342 // if there's something in the list, fix its back pointer
1343 if (node->mPrevp)
1344 {
1345 node->mPrevp->mNextp = node;
1346 }
1347 else // otherwise fix the head node
1348 {
1349 mHead.mNextp = node;
1350 }
1351
1352 mCurrentp = mQueuep;
1353}
1354
1355
1356// randomly move nodes in the list for DEBUG (or Discordian) purposes
1357// sets mCurrentp and mQueuep to top of list
1358template <class DATA_TYPE>
1359void LLDoubleLinkedList<DATA_TYPE>::scramble()
1360{
1361 S32 random_number;
1362 DATA_TYPE *datap = getFirstData();
1363 while(datap)
1364 {
1365 random_number = gLindenLabRandomNumber.llrand() % 5;
1366
1367 if (0 == random_number)
1368 {
1369 removeCurrentData();
1370 addData(datap);
1371 }
1372 else if (1 == random_number)
1373 {
1374 removeCurrentData();
1375 addDataAtEnd(datap);
1376 }
1377 else if (2 == random_number)
1378 {
1379 swapCurrentWithPrevious();
1380 }
1381 else if (3 == random_number)
1382 {
1383 swapCurrentWithNext();
1384 }
1385 datap = getNextData();
1386 }
1387 mQueuep = mHead.mNextp;
1388 mCurrentp = mQueuep;
1389}
1390
1391template <class DATA_TYPE>
1392BOOL LLDoubleLinkedList<DATA_TYPE>::isEmpty()
1393{
1394 return (mCount == 0);
1395}
1396
1397
1398#endif