PageRenderTime 62ms CodeModel.GetById 25ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llptrskiplist.h

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