PageRenderTime 49ms CodeModel.GetById 13ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/linked_lists.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 937 lines | 615 code | 137 blank | 185 comment | 73 complexity | 98c6bcbfc27b0fa50bd6f4cd59c937d0 MD5 | raw file
  1/** 
  2 * @file linked_lists.h
  3 * @brief LLLinkedList class header amd implementation file.
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#ifndef LL_LINKED_LISTS_H
 28#define LL_LINKED_LISTS_H
 29
 30/** 
 31 * Provides a standard doubly linked list for fun and profit
 32 * Utilizes a neat trick off of Flipcode where the back pointer is a
 33 * pointer to a pointer, allowing easier transfer of nodes between lists, &c
 34 * And a template class, of course
 35 */
 36
 37#include "llerror.h"
 38
 39
 40template <class DATA_TYPE> class LLLinkedList
 41{
 42public:
 43	friend class LLLinkNode;
 44	// External interface
 45
 46	// basic constructor
 47	LLLinkedList() : mHead(NULL), mCurrentp(NULL), mInsertBefore(NULL)
 48	{
 49		mCurrentp = mHead.mNextp;
 50		mCurrentOperatingp = mHead.mNextp;
 51		mCount = 0;
 52	}
 53
 54	// basic constructor
 55	LLLinkedList(BOOL	(*insert_before)(DATA_TYPE *data_new, DATA_TYPE *data_tested)) : mHead(NULL), mCurrentp(NULL), mInsertBefore(insert_before)
 56	{
 57		mCurrentp = mHead.mNextp;
 58		mCurrentOperatingp = mHead.mNextp;
 59		mCount = 0;
 60	}
 61
 62	// destructor destroys list and nodes, but not data in nodes
 63	~LLLinkedList()
 64	{
 65		removeAllNodes();
 66	}
 67
 68	// set mInsertBefore
 69	void setInsertBefore(BOOL (*insert_before)(DATA_TYPE *data_new, DATA_TYPE *data_tested))
 70	{
 71		mInsertBefore = insert_before;
 72	}
 73
 74	//
 75	// WARNING!!!!!!!
 76	// addData and addDataSorted are NOT O(1) operations, but O(n) because they check
 77	// for existence of the data in the linked list first.  Why, I don't know - djs
 78	// If you don't care about dupes, use addDataNoCheck
 79	//
 80
 81	// put data into a node and stick it at the front of the list
 82	inline BOOL addData(DATA_TYPE *data);
 83
 84	// put data into a node and sort into list by mInsertBefore()
 85	// calls normal add if mInsertBefore isn't set
 86	inline BOOL addDataSorted(DATA_TYPE *data);
 87
 88	inline BOOL addDataNoCheck(DATA_TYPE *data);
 89
 90	// bubbleSortList
 91	// does an improved bubble sort of the list . . . works best with almost sorted data
 92	// does nothing if mInsertBefore isn't set
 93	// Nota Bene: Swaps are accomplished by swapping data pointers
 94	inline void bubbleSortList();
 95
 96	// put data into a node and stick it at the end of the list
 97	inline BOOL addDataAtEnd(DATA_TYPE *data);
 98
 99	// returns number of items in the list
100	inline S32 getLength() const;
101
102	inline BOOL isEmpty();
103
104	// search the list starting at mHead.mNextp and remove the link with mDatap == data
105	// leave mCurrentp and mCurrentOperatingp on the next entry
106	// return TRUE if found, FALSE if not found
107	inline BOOL removeData(DATA_TYPE *data);
108
109		// search the list starting at mHead.mNextp and delete the link with mDatap == data
110	// leave mCurrentp and mCurrentOperatingp on the next entry
111	// return TRUE if found, FALSE if not found
112	inline BOOL deleteData(DATA_TYPE *data);
113
114	// remove all nodes from the list and delete the associated data
115	inline void deleteAllData();
116
117	// remove all nodes from the list but do not delete data
118	inline void removeAllNodes();
119
120	// check to see if data is in list
121	// if TRUE then mCurrentp and mCurrentOperatingp point to data
122	inline BOOL	checkData(DATA_TYPE *data);
123
124	// place mCurrentp on first node
125	inline void resetList();
126
127	// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
128	inline DATA_TYPE	*getCurrentData();
129
130	// same as getCurrentData() but a more intuitive name for the operation
131	inline DATA_TYPE	*getNextData();
132
133	// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
134	inline DATA_TYPE	*getFirstData();
135
136	// reset the list and return the data at position n, set mCurentOperatingp to that node and bump mCurrentp
137	// Note: n is zero-based
138	inline DATA_TYPE	*getNthData( U32 n);
139
140	// reset the list and return the last data in it, set mCurentOperatingp to that node and bump mCurrentp
141	inline DATA_TYPE	*getLastData();
142
143	// remove the Node at mCurentOperatingp
144	// leave mCurrentp and mCurentOperatingp on the next entry
145	inline void removeCurrentData();
146
147	// remove the Node at mCurentOperatingp and add it to newlist
148	// leave mCurrentp and mCurentOperatingp on the next entry
149	void moveCurrentData(LLLinkedList *newlist, BOOL b_sort);
150
151	BOOL moveData(DATA_TYPE *data, LLLinkedList *newlist, BOOL b_sort);
152
153	// delete the Node at mCurentOperatingp
154	// leave mCurrentp anf mCurentOperatingp on the next entry
155	void deleteCurrentData();
156
157private:
158	// node that actually contains the data
159	class LLLinkNode
160	{
161	public:
162		// assign the mDatap pointer
163		LLLinkNode(DATA_TYPE *data) : mDatap(data), mNextp(NULL), mPrevpp(NULL)
164		{
165		}
166
167		// destructor does not, by default, destroy associated data
168		// however, the mDatap must be NULL to ensure that we aren't causing memory leaks
169		~LLLinkNode()
170		{
171			if (mDatap)
172			{
173				llerror("Attempting to call LLLinkNode destructor with a non-null mDatap!", 1);
174			}
175		}
176
177		// delete associated data and NULL out pointer
178		void deleteData()
179		{
180			delete mDatap;
181			mDatap = NULL;
182		}
183
184		// NULL out pointer
185		void removeData()
186		{
187			mDatap = NULL;
188		}
189
190		DATA_TYPE	*mDatap;
191		LLLinkNode	*mNextp;
192		LLLinkNode	**mPrevpp;
193	};
194
195	// add a node at the front of the list
196	void addData(LLLinkNode *node)
197	{
198		// don't allow NULL to be passed to addData
199		if (!node)
200		{
201			llerror("NULL pointer passed to LLLinkedList::addData", 0);
202		}
203
204		// add the node to the front of the list
205		node->mPrevpp = &mHead.mNextp;
206		node->mNextp = mHead.mNextp;
207
208		// if there's something in the list, fix its back pointer
209		if (node->mNextp)
210		{
211			node->mNextp->mPrevpp = &node->mNextp;
212		}
213
214		mHead.mNextp = node;
215	}
216
217	LLLinkNode			mHead;															// fake head node. . . makes pointer operations faster and easier
218	LLLinkNode			*mCurrentp;														// mCurrentp is the Node that getCurrentData returns
219	LLLinkNode			*mCurrentOperatingp;											// this is the node that the various mumbleCurrentData functions act on
220	BOOL				(*mInsertBefore)(DATA_TYPE *data_new, DATA_TYPE *data_tested);	// user function set to allow sorted lists
221	U32					mCount;
222};
223
224template <class DATA_TYPE>
225BOOL LLLinkedList<DATA_TYPE>::addData(DATA_TYPE *data)
226{
227	// don't allow NULL to be passed to addData
228	if (!data)
229	{
230		llerror("NULL pointer passed to LLLinkedList::addData", 0);
231	}
232
233	LLLinkNode *tcurr = mCurrentp;
234	LLLinkNode *tcurrop = mCurrentOperatingp;
235
236	if ( checkData(data))
237	{
238		mCurrentp = tcurr;
239		mCurrentOperatingp = tcurrop;
240		return FALSE;
241	}
242
243	// make the new node
244	LLLinkNode *temp = new LLLinkNode(data);
245
246	// add the node to the front of the list
247	temp->mPrevpp = &mHead.mNextp;
248	temp->mNextp = mHead.mNextp;
249
250	// if there's something in the list, fix its back pointer
251	if (temp->mNextp)
252	{
253		temp->mNextp->mPrevpp = &temp->mNextp;
254	}
255
256	mHead.mNextp = temp;
257	mCurrentp = tcurr;
258	mCurrentOperatingp = tcurrop;
259	mCount++;
260	return TRUE;
261}
262
263
264template <class DATA_TYPE>
265BOOL LLLinkedList<DATA_TYPE>::addDataNoCheck(DATA_TYPE *data)
266{
267	// don't allow NULL to be passed to addData
268	if (!data)
269	{
270		llerror("NULL pointer passed to LLLinkedList::addData", 0);
271	}
272
273	LLLinkNode *tcurr = mCurrentp;
274	LLLinkNode *tcurrop = mCurrentOperatingp;
275
276	// make the new node
277	LLLinkNode *temp = new LLLinkNode(data);
278
279	// add the node to the front of the list
280	temp->mPrevpp = &mHead.mNextp;
281	temp->mNextp = mHead.mNextp;
282
283	// if there's something in the list, fix its back pointer
284	if (temp->mNextp)
285	{
286		temp->mNextp->mPrevpp = &temp->mNextp;
287	}
288
289	mHead.mNextp = temp;
290	mCurrentp = tcurr;
291	mCurrentOperatingp = tcurrop;
292	mCount++;
293	return TRUE;
294}
295
296
297template <class DATA_TYPE>
298BOOL LLLinkedList<DATA_TYPE>::addDataSorted(DATA_TYPE *data)
299{
300	LLLinkNode *tcurr = mCurrentp;
301	LLLinkNode *tcurrop = mCurrentOperatingp;
302	// don't allow NULL to be passed to addData
303	if (!data)
304	{
305		llerror("NULL pointer passed to LLLinkedList::addDataSorted", 0);
306	}
307
308	if (checkData(data))
309	{
310		// restore
311		mCurrentp = tcurr;
312		mCurrentOperatingp = tcurrop;
313		return FALSE;
314	}
315
316	// mInsertBefore not set?
317	if (!mInsertBefore)
318	{
319		addData(data);
320		// restore
321		mCurrentp = tcurr;
322		mCurrentOperatingp = tcurrop;
323		return FALSE;
324	}
325
326	// empty list?
327	if (!mHead.mNextp)
328	{
329		addData(data);
330		// restore
331		mCurrentp = tcurr;
332		mCurrentOperatingp = tcurrop;
333		return TRUE;
334	}
335
336	// make the new node
337	LLLinkNode *temp = new LLLinkNode(data);
338
339	// walk the list until mInsertBefore returns true 
340	mCurrentp = mHead.mNextp;
341	while (mCurrentp->mNextp)
342	{
343		if (mInsertBefore(data, mCurrentp->mDatap))
344		{
345			// insert before the current one
346			temp->mPrevpp = mCurrentp->mPrevpp;
347			temp->mNextp = mCurrentp;
348			*(temp->mPrevpp) = temp;
349			mCurrentp->mPrevpp = &temp->mNextp;
350			// restore
351			mCurrentp = tcurr;
352			mCurrentOperatingp = tcurrop;
353			mCount++;
354			return TRUE;
355		}
356		else
357		{
358			mCurrentp = mCurrentp->mNextp;
359		}
360	}
361
362	// on the last element, add before?
363	if (mInsertBefore(data, mCurrentp->mDatap))
364	{
365		// insert before the current one
366		temp->mPrevpp = mCurrentp->mPrevpp;
367		temp->mNextp = mCurrentp;
368		*(temp->mPrevpp) = temp;
369		mCurrentp->mPrevpp = &temp->mNextp;
370		// restore
371		mCurrentp = tcurr;
372		mCurrentOperatingp = tcurrop;
373	}
374	else // insert after
375	{
376		temp->mPrevpp = &mCurrentp->mNextp;
377		temp->mNextp = NULL;
378		mCurrentp->mNextp = temp;
379
380		// restore
381		mCurrentp = tcurr;
382		mCurrentOperatingp = tcurrop;
383	}
384	mCount++;
385	return TRUE;
386}
387
388template <class DATA_TYPE>
389void LLLinkedList<DATA_TYPE>::bubbleSortList()
390{
391	// mInsertBefore not set
392	if (!mInsertBefore)
393	{
394		return;
395	}
396
397	LLLinkNode *tcurr = mCurrentp;
398	LLLinkNode *tcurrop = mCurrentOperatingp;
399
400	BOOL		b_swapped = FALSE;
401	DATA_TYPE	*temp;
402
403	// Nota Bene: This will break if more than 0x7FFFFFFF members in list!
404	S32			length = 0x7FFFFFFF;
405	S32			count = 0;
406	do
407	{
408		b_swapped = FALSE;
409		mCurrentp = mHead.mNextp;
410		count = 0;
411		while (  (count + 1 < length)
412			   &&(mCurrentp))
413		{
414			if (mCurrentp->mNextp)
415			{
416				if (!mInsertBefore(mCurrentp->mDatap, mCurrentp->mNextp->mDatap))
417				{
418					// swap data pointers!
419					temp = mCurrentp->mDatap;
420					mCurrentp->mDatap = mCurrentp->mNextp->mDatap;
421					mCurrentp->mNextp->mDatap = temp;
422					b_swapped = TRUE;
423				}
424			}
425			else
426			{
427				break;
428			}
429			count++;
430			mCurrentp = mCurrentp->mNextp;
431		}
432		length = count;
433	} while (b_swapped);
434
435	// restore
436	mCurrentp = tcurr;
437	mCurrentOperatingp = tcurrop;
438}
439
440
441template <class DATA_TYPE>
442BOOL LLLinkedList<DATA_TYPE>::addDataAtEnd(DATA_TYPE *data)
443{
444	LLLinkNode *tcurr = mCurrentp;
445	LLLinkNode *tcurrop = mCurrentOperatingp;
446
447	// don't allow NULL to be passed to addData
448	if (!data)
449	{
450		llerror("NULL pointer passed to LLLinkedList::addData", 0);
451	}
452
453	if (checkData(data))
454	{
455		mCurrentp = tcurr;
456		mCurrentOperatingp = tcurrop;
457		return FALSE;
458	}
459
460	// make the new node
461	LLLinkNode *temp = new LLLinkNode(data);
462
463	// add the node to the end of the list
464
465	// if empty, add to the front and be done with it
466	if (!mHead.mNextp)
467	{
468		temp->mPrevpp = &mHead.mNextp;
469		temp->mNextp = NULL;
470		mHead.mNextp = temp;
471	}
472	else
473	{
474		// otherwise, walk to the end of the list
475		mCurrentp = mHead.mNextp;
476		while (mCurrentp->mNextp)
477		{
478			mCurrentp = mCurrentp->mNextp;
479		}
480		temp->mPrevpp = &mCurrentp->mNextp;
481		temp->mNextp = NULL;
482		mCurrentp->mNextp = temp;
483	}
484
485	// restore
486	mCurrentp = tcurr;
487	mCurrentOperatingp = tcurrop;
488	mCount++;
489	return TRUE;
490}
491
492
493// returns number of items in the list
494template <class DATA_TYPE>
495S32 LLLinkedList<DATA_TYPE>::getLength() const
496{
497//	S32	length = 0;
498//	for (LLLinkNode* temp = mHead.mNextp; temp != NULL; temp = temp->mNextp)
499//	{
500//		length++;
501//	}
502	return mCount;
503}
504
505
506template <class DATA_TYPE>
507BOOL LLLinkedList<DATA_TYPE>::isEmpty()
508{
509	return (mCount == 0);
510}
511
512
513// search the list starting at mHead.mNextp and remove the link with mDatap == data
514// leave mCurrentp and mCurrentOperatingp on the next entry
515// return TRUE if found, FALSE if not found
516template <class DATA_TYPE>
517BOOL LLLinkedList<DATA_TYPE>::removeData(DATA_TYPE *data)
518{
519	BOOL b_found = FALSE;
520	// don't allow NULL to be passed to addData
521	if (!data)
522	{
523		llerror("NULL pointer passed to LLLinkedList::removeData", 0);
524	}
525
526	LLLinkNode *tcurr = mCurrentp;
527	LLLinkNode *tcurrop = mCurrentOperatingp;
528
529	mCurrentp = mHead.mNextp;
530	mCurrentOperatingp = mHead.mNextp;
531
532	while (mCurrentOperatingp)
533	{
534		if (mCurrentOperatingp->mDatap == data)
535		{
536			b_found = TRUE;
537
538			// remove the node
539
540			// if there is a next one, fix it
541			if (mCurrentOperatingp->mNextp)
542			{
543				mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
544			}
545			*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
546
547			// remove the LLLinkNode
548
549			// if we were on the one we want to delete, bump the cached copies
550			if (mCurrentOperatingp == tcurrop)
551			{
552				tcurrop = tcurr = mCurrentOperatingp->mNextp;
553			}
554			else if (mCurrentOperatingp == tcurr)
555			{
556				tcurrop = tcurr = mCurrentOperatingp->mNextp;
557			}
558
559			mCurrentp = mCurrentOperatingp->mNextp;
560
561			mCurrentOperatingp->removeData();
562			delete mCurrentOperatingp;
563			mCurrentOperatingp = mCurrentp;
564			mCount--;
565			break;
566		}
567		mCurrentOperatingp = mCurrentOperatingp->mNextp;
568	}
569	// restore
570	mCurrentp = tcurr;
571	mCurrentOperatingp = tcurrop;
572	return b_found;
573}
574
575// search the list starting at mHead.mNextp and delete the link with mDatap == data
576// leave mCurrentp and mCurrentOperatingp on the next entry
577// return TRUE if found, FALSE if not found
578template <class DATA_TYPE>
579BOOL LLLinkedList<DATA_TYPE>::deleteData(DATA_TYPE *data)
580{
581	BOOL b_found = FALSE;
582	// don't allow NULL to be passed to addData
583	if (!data)
584	{
585		llerror("NULL pointer passed to LLLinkedList::removeData", 0);
586	}
587
588	LLLinkNode *tcurr = mCurrentp;
589	LLLinkNode *tcurrop = mCurrentOperatingp;
590
591	mCurrentp = mHead.mNextp;
592	mCurrentOperatingp = mHead.mNextp;
593
594	while (mCurrentOperatingp)
595	{
596		if (mCurrentOperatingp->mDatap == data)
597		{
598			b_found = TRUE;
599
600			// remove the node
601			// if there is a next one, fix it
602			if (mCurrentOperatingp->mNextp)
603			{
604				mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
605			}
606			*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
607
608			// delete the LLLinkNode
609			// if we were on the one we want to delete, bump the cached copies
610			if (mCurrentOperatingp == tcurrop)
611			{
612				tcurrop = tcurr = mCurrentOperatingp->mNextp;
613			}
614
615			// and delete the associated data
616			llassert(mCurrentOperatingp);
617			mCurrentp = mCurrentOperatingp->mNextp;
618			mCurrentOperatingp->deleteData();
619			delete mCurrentOperatingp;
620			mCurrentOperatingp = mCurrentp;
621			mCount--;
622			break;
623		}
624		mCurrentOperatingp = mCurrentOperatingp->mNextp;
625	}
626	// restore
627	mCurrentp = tcurr;
628	mCurrentOperatingp = tcurrop;
629	return b_found;
630}
631
632	// remove all nodes from the list and delete the associated data
633template <class DATA_TYPE>
634void LLLinkedList<DATA_TYPE>::deleteAllData()
635{
636	LLLinkNode *temp;
637	// reset mCurrentp
638	mCurrentp = mHead.mNextp;
639
640	while (mCurrentp)
641	{
642		temp = mCurrentp->mNextp;
643		mCurrentp->deleteData();
644		delete mCurrentp;
645		mCurrentp = temp;
646	}
647
648	// reset mHead and mCurrentp
649	mHead.mNextp = NULL;
650	mCurrentp = mHead.mNextp;
651	mCurrentOperatingp = mHead.mNextp;
652	mCount = 0;
653}
654
655// remove all nodes from the list but do not delete data
656template <class DATA_TYPE>
657void LLLinkedList<DATA_TYPE>::removeAllNodes()
658{
659	LLLinkNode *temp;
660	// reset mCurrentp
661	mCurrentp = mHead.mNextp;
662
663	while (mCurrentp)
664	{
665		temp = mCurrentp->mNextp;
666		mCurrentp->removeData();
667		delete mCurrentp;
668		mCurrentp = temp;
669	}
670
671	// reset mHead and mCurrentp
672	mHead.mNextp = NULL;
673	mCurrentp = mHead.mNextp;
674	mCurrentOperatingp = mHead.mNextp;
675	mCount = 0;
676}
677
678// check to see if data is in list
679// if TRUE then mCurrentp and mCurrentOperatingp point to data
680template <class DATA_TYPE>
681BOOL LLLinkedList<DATA_TYPE>::checkData(DATA_TYPE *data)
682{
683	// reset mCurrentp
684	mCurrentp = mHead.mNextp;
685
686	while (mCurrentp)
687	{
688		if (mCurrentp->mDatap == data)
689		{
690			mCurrentOperatingp = mCurrentp;
691			return TRUE;
692		}
693		mCurrentp = mCurrentp->mNextp;
694	}
695	mCurrentOperatingp = mCurrentp;
696	return FALSE;
697}
698
699// place mCurrentp on first node
700template <class DATA_TYPE>
701void LLLinkedList<DATA_TYPE>::resetList()
702{
703	mCurrentp = mHead.mNextp;
704	mCurrentOperatingp = mHead.mNextp;
705}
706
707// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
708template <class DATA_TYPE>
709DATA_TYPE *LLLinkedList<DATA_TYPE>::getCurrentData()
710{
711	if (mCurrentp)
712	{
713		mCurrentOperatingp = mCurrentp;
714		mCurrentp = mCurrentp->mNextp;
715		return mCurrentOperatingp->mDatap;
716	}
717	else
718	{
719		return NULL;
720	}
721}
722
723// same as getCurrentData() but a more intuitive name for the operation
724template <class DATA_TYPE>
725DATA_TYPE *LLLinkedList<DATA_TYPE>::getNextData()
726{
727	if (mCurrentp)
728	{
729		mCurrentOperatingp = mCurrentp;
730		mCurrentp = mCurrentp->mNextp;
731		return mCurrentOperatingp->mDatap;
732	}
733	else
734	{
735		return NULL;
736	}
737}
738
739// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
740template <class DATA_TYPE>
741DATA_TYPE *LLLinkedList<DATA_TYPE>::getFirstData()
742{
743	mCurrentp = mHead.mNextp;
744	mCurrentOperatingp = mHead.mNextp;
745	if (mCurrentp)
746	{
747		mCurrentOperatingp = mCurrentp;
748		mCurrentp = mCurrentp->mNextp;
749		return mCurrentOperatingp->mDatap;
750	}
751	else
752	{
753		return NULL;
754	}
755}
756
757// Note: n is zero-based
758template <class DATA_TYPE>
759DATA_TYPE	*LLLinkedList<DATA_TYPE>::getNthData( U32 n )
760{
761	mCurrentOperatingp = mHead.mNextp;
762
763	// if empty, return NULL
764	if (!mCurrentOperatingp)
765	{
766		return NULL;
767	}
768
769	for( U32 i = 0; i < n; i++ )
770	{
771		mCurrentOperatingp = mCurrentOperatingp->mNextp;
772		if( !mCurrentOperatingp )
773		{
774			return NULL;
775		}
776	}
777
778	mCurrentp = mCurrentOperatingp->mNextp;
779	return mCurrentOperatingp->mDatap;
780}
781
782
783// reset the list and return the last data in it, set mCurentOperatingp to that node and bump mCurrentp
784template <class DATA_TYPE>
785DATA_TYPE *LLLinkedList<DATA_TYPE>::getLastData()
786{
787	mCurrentOperatingp = mHead.mNextp;
788
789	// if empty, return NULL
790	if (!mCurrentOperatingp)
791		return NULL;
792
793	// walk until we're pointing at the last entry
794	while (mCurrentOperatingp->mNextp)
795	{
796		mCurrentOperatingp = mCurrentOperatingp->mNextp;
797	}
798	mCurrentp = mCurrentOperatingp->mNextp;
799	return mCurrentOperatingp->mDatap;
800}
801
802// remove the Node at mCurentOperatingp
803// leave mCurrentp and mCurentOperatingp on the next entry
804// return TRUE if found, FALSE if not found
805template <class DATA_TYPE>
806void LLLinkedList<DATA_TYPE>::removeCurrentData()
807{
808	if (mCurrentOperatingp)
809	{
810		// remove the node
811		// if there is a next one, fix it
812		if (mCurrentOperatingp->mNextp)
813		{
814			mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
815		}
816		*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
817
818		// remove the LLLinkNode
819		mCurrentp = mCurrentOperatingp->mNextp;
820
821		mCurrentOperatingp->removeData();
822		delete mCurrentOperatingp;
823		mCount--;
824		mCurrentOperatingp = mCurrentp;
825	}
826}
827
828// remove the Node at mCurentOperatingp and add it to newlist
829// leave mCurrentp and mCurentOperatingp on the next entry
830// return TRUE if found, FALSE if not found
831template <class DATA_TYPE>
832void LLLinkedList<DATA_TYPE>::moveCurrentData(LLLinkedList *newlist, BOOL b_sort)
833{
834	if (mCurrentOperatingp)
835	{
836		// remove the node
837		// if there is a next one, fix it
838		if (mCurrentOperatingp->mNextp)
839		{
840			mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
841		}
842		*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
843
844		// remove the LLLinkNode
845		mCurrentp = mCurrentOperatingp->mNextp;
846		// move the node to the new list
847		newlist->addData(mCurrentOperatingp);
848		if (b_sort)
849			bubbleSortList();
850		mCurrentOperatingp = mCurrentp;
851	}
852}
853
854template <class DATA_TYPE>
855BOOL LLLinkedList<DATA_TYPE>::moveData(DATA_TYPE *data, LLLinkedList *newlist, BOOL b_sort)
856{
857	BOOL b_found = FALSE;
858	// don't allow NULL to be passed to addData
859	if (!data)
860	{
861		llerror("NULL pointer passed to LLLinkedList::removeData", 0);
862	}
863
864	LLLinkNode *tcurr = mCurrentp;
865	LLLinkNode *tcurrop = mCurrentOperatingp;
866
867	mCurrentp = mHead.mNextp;
868	mCurrentOperatingp = mHead.mNextp;
869
870	while (mCurrentOperatingp)
871	{
872		if (mCurrentOperatingp->mDatap == data)
873		{
874			b_found = TRUE;
875
876			// remove the node
877
878			// if there is a next one, fix it
879			if (mCurrentOperatingp->mNextp)
880			{
881				mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
882			}
883			*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
884
885			// if we were on the one we want to delete, bump the cached copies
886			if (  (mCurrentOperatingp == tcurrop)
887				||(mCurrentOperatingp == tcurr))
888			{
889				tcurrop = tcurr = mCurrentOperatingp->mNextp;
890			}
891
892			// remove the LLLinkNode
893			mCurrentp = mCurrentOperatingp->mNextp;
894			// move the node to the new list
895			newlist->addData(mCurrentOperatingp);
896			if (b_sort)
897				newlist->bubbleSortList();
898			mCurrentOperatingp = mCurrentp;
899			break;
900		}
901		mCurrentOperatingp = mCurrentOperatingp->mNextp;
902	}
903	// restore
904	mCurrentp = tcurr;
905	mCurrentOperatingp = tcurrop;
906	return b_found;
907}
908
909// delete the Node at mCurentOperatingp
910// leave mCurrentp anf mCurentOperatingp on the next entry
911// return TRUE if found, FALSE if not found
912template <class DATA_TYPE>
913void LLLinkedList<DATA_TYPE>::deleteCurrentData()
914{
915	if (mCurrentOperatingp)
916	{
917		// remove the node
918		// if there is a next one, fix it
919		if (mCurrentOperatingp->mNextp)
920		{
921			mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp;
922		}
923		*(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp;
924
925		// remove the LLLinkNode
926		mCurrentp = mCurrentOperatingp->mNextp;
927
928		mCurrentOperatingp->deleteData();
929		if (mCurrentOperatingp->mDatap)
930			llerror("This is impossible!", 0);
931		delete mCurrentOperatingp;
932		mCurrentOperatingp = mCurrentp;
933		mCount--;
934	}
935}
936
937#endif