PageRenderTime 29ms CodeModel.GetById 2ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llskiplist.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 517 lines | 379 code | 65 blank | 73 comment | 44 complexity | 2799fe9dc9bd8cf8040d3d62af05de83 MD5 | raw file
  1/** 
  2 * @file llskiplist.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#ifndef LL_LLSKIPLIST_H
 27#define LL_LLSKIPLIST_H
 28
 29#include "llrand.h"
 30#include "llrand.h"
 31
 32// NOTA BENE: Insert first needs to be < NOT <=
 33// Binary depth must be >= 2
 34template <class DATA_TYPE, S32 BINARY_DEPTH = 10>
 35class LLSkipList
 36{
 37public:
 38	typedef BOOL (*compare)(const DATA_TYPE& first, const DATA_TYPE& second);
 39	typedef compare insert_func;
 40	typedef compare equals_func;
 41
 42	void init();
 43
 44	// basic constructor
 45	LLSkipList();
 46
 47	// basic constructor including sorter
 48	LLSkipList(insert_func insert_first, equals_func equals);
 49	~LLSkipList();
 50
 51	inline void setInsertFirst(insert_func insert_first);
 52	inline void setEquals(equals_func equals);
 53
 54	inline BOOL addData(const DATA_TYPE& data);
 55	inline BOOL checkData(const DATA_TYPE& data);
 56
 57	// returns number of items in the list
 58	inline S32 getLength() const; // NOT a constant time operation, traverses entire list!
 59
 60	inline BOOL moveData(const DATA_TYPE& data, LLSkipList *newlist);
 61
 62	inline BOOL removeData(const DATA_TYPE& data);
 63
 64	// remove all nodes from the list but do not delete data
 65	inline void removeAllNodes();
 66
 67	// place mCurrentp on first node
 68	inline void resetList();
 69
 70	// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
 71	inline DATA_TYPE getCurrentData();
 72
 73	// same as getCurrentData() but a more intuitive name for the operation
 74	inline DATA_TYPE getNextData();
 75
 76	// remove the Node at mCurentOperatingp
 77	// leave mCurrentp and mCurentOperatingp on the next entry
 78	inline void removeCurrentData();
 79
 80	// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
 81	inline DATA_TYPE getFirstData();
 82
 83	class LLSkipNode
 84	{
 85	public:
 86		LLSkipNode()
 87		:	mData(0)
 88		{
 89			S32 i;
 90			for (i = 0; i < BINARY_DEPTH; i++)
 91			{
 92				mForward[i] = NULL;
 93			}
 94		}
 95
 96		LLSkipNode(DATA_TYPE data)
 97			: mData(data)
 98		{
 99			S32 i;
100			for (i = 0; i < BINARY_DEPTH; i++)
101			{
102				mForward[i] = NULL;
103			}
104		}
105
106		~LLSkipNode()
107		{
108		}
109
110		DATA_TYPE					mData;
111		LLSkipNode					*mForward[BINARY_DEPTH];
112
113	private:
114		// Disallow copying of LLSkipNodes by not implementing these methods.
115		LLSkipNode(const LLSkipNode &);
116		LLSkipNode &operator=(const LLSkipNode &);
117	};
118
119	static BOOL defaultEquals(const DATA_TYPE& first, const DATA_TYPE& second)
120	{
121		return first == second;
122	}
123
124private:
125	LLSkipNode					mHead;
126	LLSkipNode					*mUpdate[BINARY_DEPTH];
127	LLSkipNode					*mCurrentp;
128	LLSkipNode					*mCurrentOperatingp;
129	S32							mLevel;
130	insert_func mInsertFirst;
131	equals_func mEquals;
132
133private:
134	// Disallow copying of LLSkipNodes by not implementing these methods.
135	LLSkipList(const LLSkipList &);
136	LLSkipList &operator=(const LLSkipList &);
137};
138
139
140///////////////////////
141//
142// Implementation
143//
144
145
146// Binary depth must be >= 2
147template <class DATA_TYPE, S32 BINARY_DEPTH>
148inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::init()
149{
150	S32 i;
151	for (i = 0; i < BINARY_DEPTH; i++)
152	{
153		mHead.mForward[i] = NULL;
154		mUpdate[i] = NULL;
155	}
156	mLevel = 1;
157	mCurrentp = *(mHead.mForward);
158	mCurrentOperatingp = *(mHead.mForward);
159}
160
161
162// basic constructor
163template <class DATA_TYPE, S32 BINARY_DEPTH>
164inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList()
165:	mInsertFirst(NULL), 
166	mEquals(defaultEquals)
167{
168	init();
169}
170
171// basic constructor including sorter
172template <class DATA_TYPE, S32 BINARY_DEPTH>
173inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList(insert_func insert,
174													   equals_func equals)
175:	mInsertFirst(insert), 
176	mEquals(equals)
177{
178	init();
179}
180
181template <class DATA_TYPE, S32 BINARY_DEPTH>
182inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::~LLSkipList()
183{
184	removeAllNodes();
185}
186
187template <class DATA_TYPE, S32 BINARY_DEPTH>
188inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(insert_func insert_first)
189{
190	mInsertFirst = insert_first;
191}
192
193template <class DATA_TYPE, S32 BINARY_DEPTH>
194inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(equals_func equals)
195{
196	mEquals = equals;
197}
198
199template <class DATA_TYPE, S32 BINARY_DEPTH>
200inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::addData(const DATA_TYPE& data)
201{
202	S32			level;
203	LLSkipNode	*current = &mHead;
204	LLSkipNode	*temp;
205	// find the pointer one in front of the one we want
206	if (mInsertFirst)
207	{
208		for (level = mLevel - 1; level >= 0; level--)
209		{
210			temp = *(current->mForward + level);
211			while (  (temp)
212				   &&(mInsertFirst(temp->mData, data)))
213			{
214				current = temp;
215				temp = *(current->mForward + level);
216			}
217			*(mUpdate + level) = current;
218		}
219	}
220	else
221	{
222		for (level = mLevel - 1; level >= 0; level--)
223		{
224			temp = *(current->mForward + level);
225			while (  (temp)
226				   &&(temp->mData < data))
227			{
228				current = temp;
229				temp = *(current->mForward + level);
230			}
231			*(mUpdate + level) = current;
232		}
233	}
234	// we're now just in front of where we want to be . . . take one step forward
235	current = *current->mForward;
236
237	// now add the new node
238	S32 newlevel;
239	for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
240	{
241		if (ll_frand() < 0.5f)
242			break;
243	}
244
245	LLSkipNode *snode = new LLSkipNode(data);
246
247	if (newlevel > mLevel)
248	{
249		mHead.mForward[mLevel] = NULL;
250		mUpdate[mLevel] = &mHead;
251		mLevel = newlevel;
252	}
253
254	for (level = 0; level < newlevel; level++)
255	{
256		snode->mForward[level] = mUpdate[level]->mForward[level];
257		mUpdate[level]->mForward[level] = snode;
258	}
259	return TRUE;
260}
261
262template <class DATA_TYPE, S32 BINARY_DEPTH>
263inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE& data)
264{
265	S32			level;
266	LLSkipNode	*current = &mHead;
267	LLSkipNode	*temp;
268	// find the pointer one in front of the one we want
269	if (mInsertFirst)
270	{
271		for (level = mLevel - 1; level >= 0; level--)
272		{
273			temp = *(current->mForward + level);
274			while (  (temp)
275				   &&(mInsertFirst(temp->mData, data)))
276			{
277				current = temp;
278				temp = *(current->mForward + level);
279			}
280			*(mUpdate + level) = current;
281		}
282	}
283	else
284	{
285		for (level = mLevel - 1; level >= 0; level--)
286		{
287			temp = *(current->mForward + level);
288			while (  (temp)
289				   &&(temp->mData < data))
290			{
291				current = temp;
292				temp = *(current->mForward + level);
293			}
294			*(mUpdate + level) = current;
295		}
296	}
297	// we're now just in front of where we want to be . . . take one step forward
298	current = *current->mForward;
299
300
301	if (current)
302	{
303		return mEquals(current->mData, data);
304	}
305
306	return FALSE;
307}
308
309// returns number of items in the list
310template <class DATA_TYPE, S32 BINARY_DEPTH>
311inline S32 LLSkipList<DATA_TYPE, BINARY_DEPTH>::getLength() const
312{
313	U32	length = 0;
314	for (LLSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0])
315	{
316		length++;
317	}
318	return length;
319}
320
321
322template <class DATA_TYPE, S32 BINARY_DEPTH>
323inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE& data, LLSkipList *newlist)
324{
325	BOOL removed = removeData(data);
326	BOOL added = newlist->addData(data);
327	return removed && added;
328}
329
330
331template <class DATA_TYPE, S32 BINARY_DEPTH>
332inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE& data)
333{
334	S32			level;
335	LLSkipNode	*current = &mHead;
336	LLSkipNode	*temp;
337	// find the pointer one in front of the one we want
338	if (mInsertFirst)
339	{
340		for (level = mLevel - 1; level >= 0; level--)
341		{
342			temp = *(current->mForward + level);
343			while (  (temp)
344				   &&(mInsertFirst(temp->mData, data)))
345			{
346				current = temp;
347				temp = *(current->mForward + level);
348			}
349			*(mUpdate + level) = current;
350		}
351	}
352	else
353	{
354		for (level = mLevel - 1; level >= 0; level--)
355		{
356			temp = *(current->mForward + level);
357			while (  (temp)
358				   &&(temp->mData < data))
359			{
360				current = temp;
361				temp = *(current->mForward + level);
362			}
363			*(mUpdate + level) = current;
364		}
365	}
366	// we're now just in front of where we want to be . . . take one step forward
367	current = *current->mForward;
368
369
370	if (!current)
371	{
372		// empty list or beyond the end!
373		return FALSE;
374	}
375
376	// is this the one we want?
377	if (!mEquals(current->mData, data))
378	{
379		// nope!
380		return FALSE;
381	}
382	else
383	{
384		// do we need to fix current or currentop?
385		if (current == mCurrentp)
386		{
387			mCurrentp = current->mForward[0];
388		}
389
390		if (current == mCurrentOperatingp)
391		{
392			mCurrentOperatingp = current->mForward[0];
393		}
394		// yes it is!  change pointers as required
395		for (level = 0; level < mLevel; level++)
396		{
397			if (mUpdate[level]->mForward[level] != current)
398			{
399				// cool, we've fixed all the pointers!
400				break;
401			}
402			mUpdate[level]->mForward[level] = current->mForward[level];
403		}
404
405		// clean up cuurent
406		delete current;
407
408		// clean up mHead
409		while (  (mLevel > 1)
410			   &&(!mHead.mForward[mLevel - 1]))
411		{
412			mLevel--;
413		}
414	}
415	return TRUE;
416}
417
418// remove all nodes from the list but do not delete data
419template <class DATA_TYPE, S32 BINARY_DEPTH>
420inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes()
421{
422	LLSkipNode *temp;
423	// reset mCurrentp
424	mCurrentp = *(mHead.mForward);
425
426	while (mCurrentp)
427	{
428		temp = mCurrentp->mForward[0];
429		delete mCurrentp;
430		mCurrentp = temp;
431	}
432
433	S32 i;
434	for (i = 0; i < BINARY_DEPTH; i++)
435	{
436		mHead.mForward[i] = NULL;
437		mUpdate[i] = NULL;
438	}
439
440	mCurrentp = *(mHead.mForward);
441	mCurrentOperatingp = *(mHead.mForward);
442}
443
444// place mCurrentp on first node
445template <class DATA_TYPE, S32 BINARY_DEPTH>
446inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::resetList()
447{
448	mCurrentp = *(mHead.mForward);
449	mCurrentOperatingp = *(mHead.mForward);
450}
451
452// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
453template <class DATA_TYPE, S32 BINARY_DEPTH>
454inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData()
455{
456	if (mCurrentp)
457	{
458		mCurrentOperatingp = mCurrentp;
459		mCurrentp = mCurrentp->mForward[0];
460		return mCurrentOperatingp->mData;
461	}
462	else
463	{
464		//return NULL;		// causes compile warning
465		return (DATA_TYPE)0; 			// equivalent, but no warning
466	}
467}
468
469// same as getCurrentData() but a more intuitive name for the operation
470template <class DATA_TYPE, S32 BINARY_DEPTH>
471inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData()
472{
473	if (mCurrentp)
474	{
475		mCurrentOperatingp = mCurrentp;
476		mCurrentp = mCurrentp->mForward[0];
477		return mCurrentOperatingp->mData;
478	}
479	else
480	{
481		//return NULL;		// causes compile warning
482		return (DATA_TYPE)0; 			// equivalent, but no warning
483	}
484}
485
486// remove the Node at mCurentOperatingp
487// leave mCurrentp and mCurentOperatingp on the next entry
488template <class DATA_TYPE, S32 BINARY_DEPTH>
489inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData()
490{
491	if (mCurrentOperatingp)
492	{
493		removeData(mCurrentOperatingp->mData);
494	}
495}
496
497// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
498template <class DATA_TYPE, S32 BINARY_DEPTH>
499inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getFirstData()
500{
501	mCurrentp = *(mHead.mForward);
502	mCurrentOperatingp = *(mHead.mForward);
503	if (mCurrentp)
504	{
505		mCurrentOperatingp = mCurrentp;
506		mCurrentp = mCurrentp->mForward[0];
507		return mCurrentOperatingp->mData;
508	}
509	else
510	{
511		//return NULL;		// causes compile warning
512		return (DATA_TYPE)0; 			// equivalent, but no warning
513	}
514}
515
516
517#endif