PageRenderTime 65ms CodeModel.GetById 15ms app.highlight 42ms RepoModel.GetById 3ms app.codeStats 0ms

/indra/llcommon/llskipmap.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 1022 lines | 770 code | 141 blank | 111 comment | 99 complexity | 7d6903eb01d575a763f3e9cc8dad502b MD5 | raw file
   1/** 
   2 * @file llskipmap.h
   3 * @brief Associative container based on the skiplist algorithm.
   4 *
   5 * $LicenseInfo:firstyear=2003&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_LLSKIPMAP_H
  28#define LL_LLSKIPMAP_H
  29
  30#include "llerror.h"
  31
  32template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH = 8> 
  33class LLSkipMap
  34{
  35public:
  36	// basic constructor
  37	LLSkipMap();
  38
  39	// basic constructor including sorter
  40	LLSkipMap(BOOL	(*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second), 
  41			   BOOL	(*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second));
  42
  43	~LLSkipMap();
  44
  45	void setInsertFirst(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second));
  46	void setEquals(BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second));
  47
  48	DATA_TYPE &addData(const INDEX_TYPE &index, DATA_TYPE datap);
  49	DATA_TYPE &addData(const INDEX_TYPE &index);
  50	DATA_TYPE &getData(const INDEX_TYPE &index);
  51	DATA_TYPE &operator[](const INDEX_TYPE &index);
  52
  53	// If index present, returns data.
  54	// If index not present, adds <index,NULL> and returns NULL.
  55	DATA_TYPE &getData(const INDEX_TYPE &index, BOOL &b_new_entry);
  56
  57	// Returns TRUE if data present in map.
  58	BOOL checkData(const INDEX_TYPE &index);
  59
  60	// Returns TRUE if key is present in map. This is useful if you
  61	// are potentially storing NULL pointers in the map
  62	BOOL checkKey(const INDEX_TYPE &index);
  63
  64	// If there, returns the data.
  65	// If not, returns NULL.
  66	// Never adds entries to the map.
  67	DATA_TYPE getIfThere(const INDEX_TYPE &index);
  68
  69	INDEX_TYPE reverseLookup(const DATA_TYPE datap);
  70
  71	// returns number of items in the list
  72	S32 getLength(); // WARNING!  getLength is O(n), not O(1)!
  73
  74	BOOL removeData(const INDEX_TYPE &index);
  75
  76	// remove all nodes from the list but do not delete data
  77	void removeAllData();
  78
  79	// place mCurrentp on first node
  80	void resetList();
  81
  82	// return the data currently pointed to
  83	DATA_TYPE	getCurrentDataWithoutIncrement();
  84
  85	// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
  86	DATA_TYPE	getCurrentData();
  87
  88	// same as getCurrentData() but a more intuitive name for the operation
  89	DATA_TYPE	getNextData();
  90
  91	INDEX_TYPE	getNextKey();
  92
  93	// return the key currently pointed to
  94	INDEX_TYPE	getCurrentKeyWithoutIncrement();
  95
  96	// The internal iterator is at the end of the list.
  97	BOOL		notDone() const;
  98
  99	// remove the Node at mCurentOperatingp
 100	// leave mCurrentp and mCurentOperatingp on the next entry
 101	void removeCurrentData();
 102
 103	void deleteCurrentData();
 104
 105	// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
 106	DATA_TYPE	getFirstData();
 107
 108	INDEX_TYPE	getFirstKey();
 109
 110	class LLSkipMapNode
 111	{
 112	public:
 113		LLSkipMapNode()
 114		{
 115			S32 i;
 116			for (i = 0; i < BINARY_DEPTH; i++)
 117			{
 118				mForward[i] = NULL;
 119			}
 120
 121			U8  *zero = (U8 *)&mIndex;
 122
 123			for (i = 0; i < (S32)sizeof(INDEX_TYPE); i++)
 124			{
 125				*(zero + i) = 0;
 126			}
 127
 128			zero = (U8 *)&mData;
 129
 130			for (i = 0; i < (S32)sizeof(DATA_TYPE); i++)
 131			{
 132				*(zero + i) = 0;
 133			}
 134		}
 135
 136		LLSkipMapNode(const INDEX_TYPE &index)
 137		:	mIndex(index)
 138		{
 139
 140			S32 i;
 141			for (i = 0; i < BINARY_DEPTH; i++)
 142			{
 143				mForward[i] = NULL;
 144			}
 145
 146			U8 *zero = (U8 *)&mData;
 147
 148			for (i = 0; i < (S32)sizeof(DATA_TYPE); i++)
 149			{
 150				*(zero + i) = 0;
 151			}
 152		}
 153
 154		LLSkipMapNode(const INDEX_TYPE &index, DATA_TYPE datap)
 155		:	mIndex(index)
 156		{
 157
 158			S32 i;
 159			for (i = 0; i < BINARY_DEPTH; i++)
 160			{
 161				mForward[i] = NULL;
 162			}
 163
 164			mData = datap;
 165		}
 166
 167		~LLSkipMapNode()
 168		{
 169		}
 170
 171
 172		INDEX_TYPE					mIndex;
 173		DATA_TYPE					mData;
 174		LLSkipMapNode				*mForward[BINARY_DEPTH];
 175
 176	private:
 177		// Disallow copying of LLSkipMapNodes by not implementing these methods.
 178		LLSkipMapNode(const LLSkipMapNode &);
 179		LLSkipMapNode &operator=(const LLSkipMapNode &rhs);
 180	};
 181
 182	static BOOL	defaultEquals(const INDEX_TYPE &first, const INDEX_TYPE &second)
 183	{
 184		return first == second;
 185	}
 186
 187private:
 188	// don't generate implicit copy constructor or copy assignment
 189	LLSkipMap(const LLSkipMap &);
 190	LLSkipMap &operator=(const LLSkipMap &);
 191
 192private:
 193	LLSkipMapNode				mHead;
 194	LLSkipMapNode				*mUpdate[BINARY_DEPTH];
 195	LLSkipMapNode				*mCurrentp;
 196	LLSkipMapNode				*mCurrentOperatingp;
 197	S32							mLevel;
 198	BOOL						(*mInsertFirst)(const INDEX_TYPE &first, const INDEX_TYPE &second);
 199	BOOL						(*mEquals)(const INDEX_TYPE &first, const INDEX_TYPE &second);
 200	S32							mNumberOfSteps;
 201};
 202
 203//////////////////////////////////////////////////
 204//
 205// LLSkipMap implementation
 206//
 207
 208template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 209inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap()
 210	:	mInsertFirst(NULL),
 211		mEquals(defaultEquals)
 212{
 213	// Skipmaps must have binary depth of at least 2
 214	cassert(BINARY_DEPTH >= 2);
 215
 216	S32 i;
 217	for (i = 0; i < BINARY_DEPTH; i++)
 218	{
 219		mUpdate[i] = NULL;
 220	}
 221	mLevel = 1;
 222	mCurrentp = *(mHead.mForward);
 223	mCurrentOperatingp = *(mHead.mForward);
 224}
 225
 226template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 227inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap(BOOL	(*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second), 
 228			   BOOL	(*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second)) 
 229	:	mInsertFirst(insert_first),
 230		mEquals(equals)
 231{
 232	// Skipmaps must have binary depth of at least 2
 233	cassert(BINARY_DEPTH >= 2);
 234
 235	mLevel = 1;
 236	S32 i;
 237	for (i = 0; i < BINARY_DEPTH; i++)
 238	{
 239		mHead.mForward[i] = NULL;
 240		mUpdate[i] = NULL;
 241	}
 242	mCurrentp = *(mHead.mForward);
 243	mCurrentOperatingp = *(mHead.mForward);
 244}
 245
 246template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 247inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::~LLSkipMap()
 248{
 249	removeAllData();
 250}
 251
 252template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 253inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::setInsertFirst(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second))
 254{
 255	mInsertFirst = insert_first;
 256}
 257
 258template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 259inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::setEquals(BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second))
 260{
 261	mEquals = equals;
 262}
 263
 264template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 265inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::addData(const INDEX_TYPE &index, DATA_TYPE datap)
 266{
 267	S32			level;
 268	LLSkipMapNode	*current = &mHead;
 269	LLSkipMapNode	*temp;
 270
 271	// find the pointer one in front of the one we want
 272	if (mInsertFirst)
 273	{
 274		for (level = mLevel - 1; level >= 0; level--)
 275		{
 276			temp = *(current->mForward + level);
 277			while (  (temp)
 278				   &&(mInsertFirst(temp->mIndex, index)))
 279			{
 280				current = temp;
 281				temp = *(current->mForward + level);
 282			}
 283			*(mUpdate + level) = current;
 284		}
 285	}
 286	else
 287	{
 288		for (level = mLevel - 1; level >= 0; level--)
 289		{
 290			temp = *(current->mForward + level);
 291			while (  (temp)
 292				   &&(temp->mIndex < index))
 293			{
 294				current = temp;
 295				temp = *(current->mForward + level);
 296			}
 297			*(mUpdate + level) = current;
 298		}
 299	}
 300	
 301	// we're now just in front of where we want to be . . . take one step forward
 302	current = *current->mForward;
 303
 304	// replace the existing data if a node is already there
 305	if (  (current)
 306		&&(mEquals(current->mIndex, index)))
 307	{
 308		current->mData = datap;
 309		return current->mData;
 310	}
 311
 312	// now add the new node
 313	S32 newlevel;
 314	for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
 315	{
 316		if (rand() & 1)
 317		{
 318			break;
 319		}
 320	}
 321
 322	LLSkipMapNode *snode = new LLSkipMapNode(index, datap);
 323
 324	if (newlevel > mLevel)
 325	{
 326		mHead.mForward[mLevel] = NULL;
 327		mUpdate[mLevel] = &mHead;
 328		mLevel = newlevel;
 329	}
 330
 331	for (level = 0; level < newlevel; level++)
 332	{
 333		snode->mForward[level] = mUpdate[level]->mForward[level];
 334		mUpdate[level]->mForward[level] = snode;
 335	}
 336	return snode->mData;
 337}
 338
 339template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 340inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::addData(const INDEX_TYPE &index)
 341{
 342	S32			level;
 343	LLSkipMapNode	*current = &mHead;
 344	LLSkipMapNode	*temp;
 345
 346	// find the pointer one in front of the one we want
 347	if (mInsertFirst)
 348	{
 349		for (level = mLevel - 1; level >= 0; level--)
 350		{
 351			temp = *(current->mForward + level);
 352			while (  (temp)
 353				   &&(mInsertFirst(temp->mIndex, index)))
 354			{
 355				current = temp;
 356				temp = *(current->mForward + level);
 357			}
 358			*(mUpdate + level) = current;
 359		}
 360	}
 361	else
 362	{
 363		for (level = mLevel - 1; level >= 0; level--)
 364		{
 365			temp = *(current->mForward + level);
 366			while (  (temp)
 367				   &&(temp->mIndex < index))
 368			{
 369				current = temp;
 370				temp = *(current->mForward + level);
 371			}
 372			*(mUpdate + level) = current;
 373		}
 374	}
 375	
 376	// we're now just in front of where we want to be . . . take one step forward
 377	current = *current->mForward;
 378
 379	// now add the new node
 380	S32 newlevel;
 381	for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
 382	{
 383		if (rand() & 1)
 384			break;
 385	}
 386
 387	LLSkipMapNode *snode = new LLSkipMapNode(index);
 388
 389	if (newlevel > mLevel)
 390	{
 391		mHead.mForward[mLevel] = NULL;
 392		mUpdate[mLevel] = &mHead;
 393		mLevel = newlevel;
 394	}
 395
 396	for (level = 0; level < newlevel; level++)
 397	{
 398		snode->mForward[level] = mUpdate[level]->mForward[level];
 399		mUpdate[level]->mForward[level] = snode;
 400	}
 401	return snode->mData;
 402}
 403
 404template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 405inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getData(const INDEX_TYPE &index)
 406{
 407	S32			level;
 408	LLSkipMapNode	*current = &mHead;
 409	LLSkipMapNode	*temp;
 410
 411	mNumberOfSteps = 0;
 412
 413	// find the pointer one in front of the one we want
 414	if (mInsertFirst)
 415	{
 416		for (level = mLevel - 1; level >= 0; level--)
 417		{
 418			temp = *(current->mForward + level);
 419			while (  (temp)
 420				   &&(mInsertFirst(temp->mIndex, index)))
 421			{
 422				current = temp;
 423				temp = *(current->mForward + level);
 424				mNumberOfSteps++;
 425			}
 426			*(mUpdate + level) = current;
 427		}
 428	}
 429	else
 430	{
 431		for (level = mLevel - 1; level >= 0; level--)
 432		{
 433			temp = *(current->mForward + level);
 434			while (  (temp)
 435				   &&(temp->mIndex < index))
 436			{
 437				current = temp;
 438				temp = *(current->mForward + level);
 439				mNumberOfSteps++;
 440			}
 441			*(mUpdate + level) = current;
 442		}
 443	}
 444	
 445	// we're now just in front of where we want to be . . . take one step forward
 446	current = *current->mForward;
 447	mNumberOfSteps++;
 448
 449	if (  (current)
 450		&&(mEquals(current->mIndex, index)))
 451	{
 452		
 453		return current->mData;
 454	}
 455	
 456	// now add the new node
 457	S32 newlevel;
 458	for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
 459	{
 460		if (rand() & 1)
 461			break;
 462	}
 463
 464	LLSkipMapNode *snode = new LLSkipMapNode(index);
 465
 466	if (newlevel > mLevel)
 467	{
 468		mHead.mForward[mLevel] = NULL;
 469		mUpdate[mLevel] = &mHead;
 470		mLevel = newlevel;
 471	}
 472
 473	for (level = 0; level < newlevel; level++)
 474	{
 475		snode->mForward[level] = mUpdate[level]->mForward[level];
 476		mUpdate[level]->mForward[level] = snode;
 477	}
 478	
 479	return snode->mData;
 480}
 481
 482template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 483inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::operator[](const INDEX_TYPE &index)
 484{
 485	
 486	return getData(index);
 487}
 488
 489// If index present, returns data.
 490// If index not present, adds <index,NULL> and returns NULL.
 491template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 492inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getData(const INDEX_TYPE &index, BOOL &b_new_entry)
 493{
 494	S32			level;
 495	LLSkipMapNode	*current = &mHead;
 496	LLSkipMapNode	*temp;
 497
 498	mNumberOfSteps = 0;
 499
 500	// find the pointer one in front of the one we want
 501	if (mInsertFirst)
 502	{
 503		for (level = mLevel - 1; level >= 0; level--)
 504		{
 505			temp = *(current->mForward + level);
 506			while (  (temp)
 507				   &&(mInsertFirst(temp->mIndex, index)))
 508			{
 509				current = temp;
 510				temp = *(current->mForward + level);
 511				mNumberOfSteps++;
 512			}
 513			*(mUpdate + level) = current;
 514		}
 515	}
 516	else
 517	{
 518		for (level = mLevel - 1; level >= 0; level--)
 519		{
 520			temp = *(current->mForward + level);
 521			while (  (temp)
 522				   &&(temp->mIndex < index))
 523			{
 524				current = temp;
 525				temp = *(current->mForward + level);
 526				mNumberOfSteps++;
 527			}
 528			*(mUpdate + level) = current;
 529		}
 530	}
 531	
 532	// we're now just in front of where we want to be . . . take one step forward
 533	mNumberOfSteps++;
 534	current = *current->mForward;
 535
 536	if (  (current)
 537		&&(mEquals(current->mIndex, index)))
 538	{
 539		
 540		return current->mData;
 541	}
 542	b_new_entry = TRUE;
 543	addData(index);
 544	
 545	return current->mData;
 546}
 547
 548// Returns TRUE if data present in map.
 549template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 550inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::checkData(const INDEX_TYPE &index)
 551{
 552	S32			level;
 553	LLSkipMapNode	*current = &mHead;
 554	LLSkipMapNode	*temp;
 555
 556	// find the pointer one in front of the one we want
 557	if (mInsertFirst)
 558	{
 559		for (level = mLevel - 1; level >= 0; level--)
 560		{
 561			temp = *(current->mForward + level);
 562			while (  (temp)
 563				   &&(mInsertFirst(temp->mIndex, index)))
 564			{
 565				current = temp;
 566				temp = *(current->mForward + level);
 567			}
 568			*(mUpdate + level) = current;
 569		}
 570	}
 571	else
 572	{
 573		for (level = mLevel - 1; level >= 0; level--)
 574		{
 575			temp = *(current->mForward + level);
 576			while (  (temp)
 577				   &&(temp->mIndex < index))
 578			{
 579				current = temp;
 580				temp = *(current->mForward + level);
 581			}
 582			*(mUpdate + level) = current;
 583		}
 584	}
 585	
 586	// we're now just in front of where we want to be . . . take one step forward
 587	current = *current->mForward;
 588
 589	if (current)
 590	{
 591		// Gets rid of some compiler ambiguity for the LLPointer<> templated class.
 592		if (current->mData)
 593		{
 594			return mEquals(current->mIndex, index);
 595		}
 596	}
 597
 598	return FALSE;
 599}
 600
 601// Returns TRUE if key is present in map. This is useful if you
 602// are potentially storing NULL pointers in the map
 603template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 604inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::checkKey(const INDEX_TYPE &index)
 605{
 606	S32			level;
 607	LLSkipMapNode	*current = &mHead;
 608	LLSkipMapNode	*temp;
 609
 610	// find the pointer one in front of the one we want
 611	if (mInsertFirst)
 612	{
 613		for (level = mLevel - 1; level >= 0; level--)
 614		{
 615			temp = *(current->mForward + level);
 616			while (  (temp)
 617				   &&(mInsertFirst(temp->mIndex, index)))
 618			{
 619				current = temp;
 620				temp = *(current->mForward + level);
 621			}
 622			*(mUpdate + level) = current;
 623		}
 624	}
 625	else
 626	{
 627		for (level = mLevel - 1; level >= 0; level--)
 628		{
 629			temp = *(current->mForward + level);
 630			while (  (temp)
 631				   &&(temp->mIndex < index))
 632			{
 633				current = temp;
 634				temp = *(current->mForward + level);
 635			}
 636			*(mUpdate + level) = current;
 637		}
 638	}
 639	
 640	// we're now just in front of where we want to be . . . take one step forward
 641	current = *current->mForward;
 642
 643	if (current)
 644	{
 645		return mEquals(current->mIndex, index);
 646	}
 647
 648	return FALSE;
 649}
 650
 651// If there, returns the data.
 652// If not, returns NULL.
 653// Never adds entries to the map.
 654template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 655inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getIfThere(const INDEX_TYPE &index)
 656{
 657	S32			level;
 658	LLSkipMapNode	*current = &mHead;
 659	LLSkipMapNode	*temp;
 660
 661	mNumberOfSteps = 0;
 662
 663	// find the pointer one in front of the one we want
 664	if (mInsertFirst)
 665	{
 666		for (level = mLevel - 1; level >= 0; level--)
 667		{
 668			temp = *(current->mForward + level);
 669			while (  (temp)
 670				   &&(mInsertFirst(temp->mIndex, index)))
 671			{
 672				current = temp;
 673				temp = *(current->mForward + level);
 674				mNumberOfSteps++;
 675			}
 676			*(mUpdate + level) = current;
 677		}
 678	}
 679	else
 680	{
 681		for (level = mLevel - 1; level >= 0; level--)
 682		{
 683			temp = *(current->mForward + level);
 684			while (  (temp)
 685				   &&(temp->mIndex < index))
 686			{
 687				current = temp;
 688				temp = *(current->mForward + level);
 689				mNumberOfSteps++;
 690			}
 691			*(mUpdate + level) = current;
 692		}
 693	}
 694	
 695	// we're now just in front of where we want to be . . . take one step forward
 696	mNumberOfSteps++;
 697	current = *current->mForward;
 698
 699	if (current)
 700	{
 701		if (mEquals(current->mIndex, index))
 702		{
 703			return current->mData;
 704		}
 705	}
 706
 707	// Avoid Linux compiler warning on returning NULL.
 708	return DATA_TYPE();
 709}
 710
 711template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 712inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::reverseLookup(const DATA_TYPE datap)
 713{
 714	LLSkipMapNode	*current = &mHead;
 715
 716	while (current)
 717	{
 718		if (datap == current->mData)
 719		{
 720			
 721			return current->mIndex;
 722		}
 723		current = *current->mForward;
 724	}
 725
 726	// not found! return NULL
 727	return INDEX_TYPE();
 728}
 729
 730// returns number of items in the list
 731template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 732inline S32 LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getLength()
 733{
 734	U32	length = 0;
 735	for (LLSkipMapNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0])
 736	{
 737		length++;
 738	}
 739	
 740	return length;
 741}
 742
 743template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 744inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeData(const INDEX_TYPE &index)
 745{
 746	S32			level;
 747	LLSkipMapNode	*current = &mHead;
 748	LLSkipMapNode	*temp;
 749
 750	// find the pointer one in front of the one we want
 751	if (mInsertFirst)
 752	{
 753		for (level = mLevel - 1; level >= 0; level--)
 754		{
 755			temp = *(current->mForward + level);
 756			while (  (temp)
 757				   &&(mInsertFirst(temp->mIndex, index)))
 758			{
 759				current = temp;
 760				temp = *(current->mForward + level);
 761			}
 762			*(mUpdate + level) = current;
 763		}
 764	}
 765	else
 766	{
 767		for (level = mLevel - 1; level >= 0; level--)
 768		{
 769			temp = *(current->mForward + level);
 770			while (  (temp)
 771				   &&(temp->mIndex < index))
 772			{
 773				current = temp;
 774				temp = *(current->mForward + level);
 775			}
 776			*(mUpdate + level) = current;
 777		}
 778	}
 779	
 780	// we're now just in front of where we want to be . . . take one step forward
 781	current = *current->mForward;
 782
 783	if (!current)
 784	{
 785		// empty list or beyond the end!
 786		
 787		return FALSE;
 788	}
 789
 790	// is this the one we want?
 791	if (!mEquals(current->mIndex, index))
 792	{
 793		// nope!
 794		
 795		return FALSE;
 796	}
 797	else
 798	{
 799		// do we need to fix current or currentop?
 800		if (current == mCurrentp)
 801		{
 802			mCurrentp = *current->mForward;
 803		}
 804
 805		if (current == mCurrentOperatingp)
 806		{
 807			mCurrentOperatingp = *current->mForward;
 808		}
 809		// yes it is!  change pointers as required
 810		for (level = 0; level < mLevel; level++)
 811		{
 812			if (*((*(mUpdate + level))->mForward + level) != current)
 813			{
 814				// cool, we've fixed all the pointers!
 815				break;
 816			}
 817			*((*(mUpdate + level))->mForward + level) = *(current->mForward + level);
 818		}
 819
 820		delete current;
 821
 822		// clean up mHead
 823		while (  (mLevel > 1)
 824			   &&(!*(mHead.mForward + mLevel - 1)))
 825		{
 826			mLevel--;
 827		}
 828	}
 829	
 830	return TRUE;
 831}
 832
 833
 834// remove all nodes from the list but do not delete data
 835template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 836void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeAllData()
 837{
 838	LLSkipMapNode *temp;
 839	// reset mCurrentp
 840	mCurrentp = *(mHead.mForward);
 841
 842	while (mCurrentp)
 843	{
 844		temp = mCurrentp->mForward[0];
 845		delete mCurrentp;
 846		mCurrentp = temp;
 847	}
 848
 849	S32 i;
 850	for (i = 0; i < BINARY_DEPTH; i++)
 851	{
 852		mHead.mForward[i] = NULL;
 853		mUpdate[i] = NULL;
 854	}
 855
 856	mCurrentp = *(mHead.mForward);
 857	mCurrentOperatingp = *(mHead.mForward);
 858}
 859
 860
 861// place mCurrentp on first node
 862template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 863inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::resetList()
 864{
 865	mCurrentp = *(mHead.mForward);
 866	mCurrentOperatingp = *(mHead.mForward);
 867}
 868
 869
 870// return the data currently pointed to
 871template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 872inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentDataWithoutIncrement()
 873{
 874	if (mCurrentOperatingp)
 875	{
 876		return mCurrentOperatingp->mData;
 877	}
 878	else
 879	{
 880		return DATA_TYPE();
 881	}
 882}
 883
 884// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
 885template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 886inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentData()
 887{
 888	if (mCurrentp)
 889	{
 890		mCurrentOperatingp = mCurrentp;
 891		mCurrentp = mCurrentp->mForward[0];
 892		return mCurrentOperatingp->mData;
 893	}
 894	else
 895	{
 896		// Basic types, like int, have default constructors that initialize
 897		// them to zero.  g++ 2.95 supports this.  "int()" is zero.
 898		// This also is nice for LLUUID()
 899		return DATA_TYPE();
 900	}
 901}
 902
 903// same as getCurrentData() but a more intuitive name for the operation
 904template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 905inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getNextData()
 906{
 907	if (mCurrentp)
 908	{
 909		mCurrentOperatingp = mCurrentp;
 910		mCurrentp = mCurrentp->mForward[0];
 911		return mCurrentOperatingp->mData;
 912	}
 913	else
 914	{
 915		// Basic types, like int, have default constructors that initialize
 916		// them to zero.  g++ 2.95 supports this.  "int()" is zero.
 917		// This also is nice for LLUUID()
 918		return DATA_TYPE();
 919	}
 920}
 921
 922template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 923inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getNextKey()
 924{
 925	if (mCurrentp)
 926	{
 927		mCurrentOperatingp = mCurrentp;
 928		mCurrentp = mCurrentp->mForward[0];
 929		return mCurrentOperatingp->mIndex;
 930	}
 931	else
 932	{
 933		return mHead.mIndex;
 934	}
 935}
 936
 937// return the key currently pointed to
 938template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 939inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentKeyWithoutIncrement()
 940{
 941	if (mCurrentOperatingp)
 942	{
 943		return mCurrentOperatingp->mIndex;
 944	}
 945	else
 946	{
 947		// See comment for getNextData()
 948		return INDEX_TYPE();
 949	}
 950}
 951
 952template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 953inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::notDone() const
 954{
 955	if (mCurrentOperatingp)
 956	{
 957		return TRUE;
 958	}
 959	else
 960	{
 961		return FALSE;
 962	}
 963}
 964
 965
 966// remove the Node at mCurentOperatingp
 967// leave mCurrentp and mCurentOperatingp on the next entry
 968template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 969inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeCurrentData()
 970{
 971	if (mCurrentOperatingp)
 972	{
 973		removeData(mCurrentOperatingp->mIndex);
 974	}
 975}
 976
 977template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 978inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::deleteCurrentData()
 979{
 980	if (mCurrentOperatingp)
 981	{
 982		deleteData(mCurrentOperatingp->mIndex);
 983	}
 984}
 985
 986// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
 987template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
 988inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getFirstData()
 989{
 990	mCurrentp = *(mHead.mForward);
 991	mCurrentOperatingp = *(mHead.mForward);
 992	if (mCurrentp)
 993	{
 994		mCurrentOperatingp = mCurrentp;
 995		mCurrentp = mCurrentp->mForward[0];
 996		return mCurrentOperatingp->mData;
 997	}
 998	else
 999	{
1000		// See comment for getNextData()
1001		return DATA_TYPE();
1002	}
1003}
1004
1005template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH>
1006inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getFirstKey()
1007{
1008	mCurrentp = *(mHead.mForward);
1009	mCurrentOperatingp = *(mHead.mForward);
1010	if (mCurrentp)
1011	{
1012		mCurrentOperatingp = mCurrentp;
1013		mCurrentp = mCurrentp->mForward[0];
1014		return mCurrentOperatingp->mIndex;
1015	}
1016	else
1017	{
1018		return mHead.mIndex;
1019	}
1020}
1021
1022#endif