diff options
Diffstat (limited to 'linden/indra/llcommon/doublelinkedlist.h')
-rw-r--r-- | linden/indra/llcommon/doublelinkedlist.h | 1398 |
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 | ||
35 | template <class DATA_TYPE> class LLDoubleLinkedNode | ||
36 | { | ||
37 | public: | ||
38 | DATA_TYPE *mDatap; | ||
39 | LLDoubleLinkedNode *mNextp; | ||
40 | LLDoubleLinkedNode *mPrevp; | ||
41 | |||
42 | |||
43 | public: | ||
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 | |||
59 | const U32 LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH = 4; | ||
60 | |||
61 | template <class DATA_TYPE> class LLDoubleLinkedList | ||
62 | { | ||
63 | private: | ||
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 | |||
82 | public: | ||
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 | |||
236 | private: | ||
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 | ||
265 | template <class DATA_TYPE> | ||
266 | LLDoubleLinkedNode<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 | ||
274 | template <class DATA_TYPE> | ||
275 | LLDoubleLinkedNode<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 | ||
285 | template <class DATA_TYPE> | ||
286 | void LLDoubleLinkedNode<DATA_TYPE>::deleteData() | ||
287 | { | ||
288 | delete mDatap; | ||
289 | mDatap = NULL; | ||
290 | } | ||
291 | |||
292 | |||
293 | template <class DATA_TYPE> | ||
294 | void 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 | |||
320 | template <class DATA_TYPE> | ||
321 | LLDoubleLinkedList<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 | ||
333 | template <class DATA_TYPE> | ||
334 | LLDoubleLinkedList<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 | ||
342 | template <class DATA_TYPE> | ||
343 | void 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 | ||
375 | template <class DATA_TYPE> | ||
376 | void 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 | ||
395 | template <class DATA_TYPE> | ||
396 | BOOL 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 | ||
459 | template <class DATA_TYPE> | ||
460 | BOOL 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 | ||
521 | template <class DATA_TYPE> | ||
522 | void 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 | ||
545 | template <class DATA_TYPE> | ||
546 | void 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 | |||
567 | template <class DATA_TYPE> | ||
568 | S32 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 | ||
581 | template <class DATA_TYPE> | ||
582 | BOOL 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 | ||
645 | template <class DATA_TYPE> | ||
646 | DATA_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() | ||
665 | template <class DATA_TYPE> | ||
666 | DATA_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 | ||
698 | template <class DATA_TYPE> | ||
699 | DATA_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 | ||
717 | template <class DATA_TYPE> | ||
718 | DATA_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 | ||
735 | template <class DATA_TYPE> | ||
736 | DATA_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) | ||
753 | template <class DATA_TYPE> | ||
754 | void 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) | ||
798 | template <class DATA_TYPE> | ||
799 | void 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) | ||
844 | template <class DATA_TYPE> | ||
845 | void 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 | ||
888 | template <class DATA_TYPE> | ||
889 | void 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 | ||
928 | template <class DATA_TYPE> | ||
929 | void 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 | ||
945 | template <class DATA_TYPE> | ||
946 | void 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 | ||
989 | template <class DATA_TYPE> | ||
990 | void 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 | ||
1030 | template <class DATA_TYPE> | ||
1031 | void 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 | ||
1087 | template <class DATA_TYPE> | ||
1088 | void 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 | |||
1142 | template <class DATA_TYPE> | ||
1143 | void 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 | ||
1151 | template <class DATA_TYPE> | ||
1152 | BOOL 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)! | ||
1211 | template <class DATA_TYPE> | ||
1212 | BOOL 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 | ||
1232 | template <class DATA_TYPE> | ||
1233 | BOOL 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 | |||
1270 | template <class DATA_TYPE> | ||
1271 | BOOL 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 | |||
1284 | template <class DATA_TYPE> | ||
1285 | BOOL 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 | |||
1298 | template <class DATA_TYPE> | ||
1299 | void 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 | ||
1310 | template <class DATA_TYPE> | ||
1311 | void 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 | ||
1334 | template <class DATA_TYPE> | ||
1335 | void 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 | ||
1358 | template <class DATA_TYPE> | ||
1359 | void 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 | |||
1391 | template <class DATA_TYPE> | ||
1392 | BOOL LLDoubleLinkedList<DATA_TYPE>::isEmpty() | ||
1393 | { | ||
1394 | return (mCount == 0); | ||
1395 | } | ||
1396 | |||
1397 | |||
1398 | #endif | ||