llskiplist.h

Go to the documentation of this file.
00001 
00031 #ifndef LL_LLSKIPLIST_H
00032 #define LL_LLSKIPLIST_H
00033 
00034 #include "llrand.h"
00035 
00036 // NOTA BENE: Insert first needs to be < NOT <=
00037 // Binary depth must be >= 2
00038 template <class DATA_TYPE, S32 BINARY_DEPTH = 10>
00039 class LLSkipList
00040 {
00041 public:
00042         typedef BOOL (*compare)(const DATA_TYPE& first, const DATA_TYPE& second);
00043         typedef compare insert_func;
00044         typedef compare equals_func;
00045 
00046         void init();
00047 
00048         // basic constructor
00049         LLSkipList();
00050 
00051         // basic constructor including sorter
00052         LLSkipList(insert_func insert_first, equals_func equals);
00053         ~LLSkipList();
00054 
00055         inline void setInsertFirst(insert_func insert_first);
00056         inline void setEquals(equals_func equals);
00057 
00058         inline BOOL addData(const DATA_TYPE& data);
00059         inline BOOL checkData(const DATA_TYPE& data);
00060 
00061         // returns number of items in the list
00062         inline S32 getLength() const; // NOT a constant time operation, traverses entire list!
00063 
00064         inline BOOL moveData(const DATA_TYPE& data, LLSkipList *newlist);
00065 
00066         inline BOOL removeData(const DATA_TYPE& data);
00067 
00068         // remove all nodes from the list but do not delete data
00069         inline void removeAllNodes();
00070 
00071         // place mCurrentp on first node
00072         inline void resetList();
00073 
00074         // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
00075         inline DATA_TYPE getCurrentData();
00076 
00077         // same as getCurrentData() but a more intuitive name for the operation
00078         inline DATA_TYPE getNextData();
00079 
00080         // remove the Node at mCurentOperatingp
00081         // leave mCurrentp and mCurentOperatingp on the next entry
00082         inline void removeCurrentData();
00083 
00084         // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
00085         inline DATA_TYPE getFirstData();
00086 
00087         class LLSkipNode
00088         {
00089         public:
00090                 LLSkipNode()
00091                 :       mData(0)
00092                 {
00093                         S32 i;
00094                         for (i = 0; i < BINARY_DEPTH; i++)
00095                         {
00096                                 mForward[i] = NULL;
00097                         }
00098                 }
00099 
00100                 LLSkipNode(DATA_TYPE data)
00101                         : mData(data)
00102                 {
00103                         S32 i;
00104                         for (i = 0; i < BINARY_DEPTH; i++)
00105                         {
00106                                 mForward[i] = NULL;
00107                         }
00108                 }
00109 
00110                 ~LLSkipNode()
00111                 {
00112                 }
00113 
00114                 DATA_TYPE                                       mData;
00115                 LLSkipNode                                      *mForward[BINARY_DEPTH];
00116 
00117         private:
00118                 // Disallow copying of LLSkipNodes by not implementing these methods.
00119                 LLSkipNode(const LLSkipNode &);
00120                 LLSkipNode &operator=(const LLSkipNode &);
00121         };
00122 
00123         static BOOL defaultEquals(const DATA_TYPE& first, const DATA_TYPE& second)
00124         {
00125                 return first == second;
00126         }
00127 
00128 private:
00129         LLSkipNode                                      mHead;
00130         LLSkipNode                                      *mUpdate[BINARY_DEPTH];
00131         LLSkipNode                                      *mCurrentp;
00132         LLSkipNode                                      *mCurrentOperatingp;
00133         S32                                                     mLevel;
00134         insert_func mInsertFirst;
00135         equals_func mEquals;
00136 
00137 private:
00138         // Disallow copying of LLSkipNodes by not implementing these methods.
00139         LLSkipList(const LLSkipList &);
00140         LLSkipList &operator=(const LLSkipList &);
00141 };
00142 
00143 
00145 //
00146 // Implementation
00147 //
00148 
00149 
00150 // Binary depth must be >= 2
00151 template <class DATA_TYPE, S32 BINARY_DEPTH>
00152 inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::init()
00153 {
00154         S32 i;
00155         for (i = 0; i < BINARY_DEPTH; i++)
00156         {
00157                 mHead.mForward[i] = NULL;
00158                 mUpdate[i] = NULL;
00159         }
00160         mLevel = 1;
00161         mCurrentp = *(mHead.mForward);
00162         mCurrentOperatingp = *(mHead.mForward);
00163 }
00164 
00165 
00166 // basic constructor
00167 template <class DATA_TYPE, S32 BINARY_DEPTH>
00168 inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList()
00169 :       mInsertFirst(NULL), 
00170         mEquals(defaultEquals)
00171 {
00172         init();
00173 }
00174 
00175 // basic constructor including sorter
00176 template <class DATA_TYPE, S32 BINARY_DEPTH>
00177 inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList(insert_func insert,
00178                                                                                                            equals_func equals)
00179 :       mInsertFirst(insert), 
00180         mEquals(equals)
00181 {
00182         init();
00183 }
00184 
00185 template <class DATA_TYPE, S32 BINARY_DEPTH>
00186 inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::~LLSkipList()
00187 {
00188         removeAllNodes();
00189 }
00190 
00191 template <class DATA_TYPE, S32 BINARY_DEPTH>
00192 inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(insert_func insert_first)
00193 {
00194         mInsertFirst = insert_first;
00195 }
00196 
00197 template <class DATA_TYPE, S32 BINARY_DEPTH>
00198 inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(equals_func equals)
00199 {
00200         mEquals = equals;
00201 }
00202 
00203 template <class DATA_TYPE, S32 BINARY_DEPTH>
00204 inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::addData(const DATA_TYPE& data)
00205 {
00206         S32                     level;
00207         LLSkipNode      *current = &mHead;
00208         LLSkipNode      *temp;
00209         // find the pointer one in front of the one we want
00210         if (mInsertFirst)
00211         {
00212                 for (level = mLevel - 1; level >= 0; level--)
00213                 {
00214                         temp = *(current->mForward + level);
00215                         while (  (temp)
00216                                    &&(mInsertFirst(temp->mData, data)))
00217                         {
00218                                 current = temp;
00219                                 temp = *(current->mForward + level);
00220                         }
00221                         *(mUpdate + level) = current;
00222                 }
00223         }
00224         else
00225         {
00226                 for (level = mLevel - 1; level >= 0; level--)
00227                 {
00228                         temp = *(current->mForward + level);
00229                         while (  (temp)
00230                                    &&(temp->mData < data))
00231                         {
00232                                 current = temp;
00233                                 temp = *(current->mForward + level);
00234                         }
00235                         *(mUpdate + level) = current;
00236                 }
00237         }
00238         // we're now just in front of where we want to be . . . take one step forward
00239         current = *current->mForward;
00240 
00241         // now add the new node
00242         S32 newlevel;
00243         for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
00244         {
00245                 if (ll_frand() < 0.5f)
00246                         break;
00247         }
00248 
00249         LLSkipNode *snode = new LLSkipNode(data);
00250 
00251         if (newlevel > mLevel)
00252         {
00253                 mHead.mForward[mLevel] = NULL;
00254                 mUpdate[mLevel] = &mHead;
00255                 mLevel = newlevel;
00256         }
00257 
00258         for (level = 0; level < newlevel; level++)
00259         {
00260                 snode->mForward[level] = mUpdate[level]->mForward[level];
00261                 mUpdate[level]->mForward[level] = snode;
00262         }
00263         return TRUE;
00264 }
00265 
00266 template <class DATA_TYPE, S32 BINARY_DEPTH>
00267 inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE& data)
00268 {
00269         S32                     level;
00270         LLSkipNode      *current = &mHead;
00271         LLSkipNode      *temp;
00272         // find the pointer one in front of the one we want
00273         if (mInsertFirst)
00274         {
00275                 for (level = mLevel - 1; level >= 0; level--)
00276                 {
00277                         temp = *(current->mForward + level);
00278                         while (  (temp)
00279                                    &&(mInsertFirst(temp->mData, data)))
00280                         {
00281                                 current = temp;
00282                                 temp = *(current->mForward + level);
00283                         }
00284                         *(mUpdate + level) = current;
00285                 }
00286         }
00287         else
00288         {
00289                 for (level = mLevel - 1; level >= 0; level--)
00290                 {
00291                         temp = *(current->mForward + level);
00292                         while (  (temp)
00293                                    &&(temp->mData < data))
00294                         {
00295                                 current = temp;
00296                                 temp = *(current->mForward + level);
00297                         }
00298                         *(mUpdate + level) = current;
00299                 }
00300         }
00301         // we're now just in front of where we want to be . . . take one step forward
00302         current = *current->mForward;
00303 
00304 
00305         if (current)
00306         {
00307                 return mEquals(current->mData, data);
00308         }
00309 
00310         return FALSE;
00311 }
00312 
00313 // returns number of items in the list
00314 template <class DATA_TYPE, S32 BINARY_DEPTH>
00315 inline S32 LLSkipList<DATA_TYPE, BINARY_DEPTH>::getLength() const
00316 {
00317         U32     length = 0;
00318         for (LLSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0])
00319         {
00320                 length++;
00321         }
00322         return length;
00323 }
00324 
00325 
00326 template <class DATA_TYPE, S32 BINARY_DEPTH>
00327 inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE& data, LLSkipList *newlist)
00328 {
00329         BOOL removed = removeData(data);
00330         BOOL added = newlist->addData(data);
00331         return removed && added;
00332 }
00333 
00334 
00335 template <class DATA_TYPE, S32 BINARY_DEPTH>
00336 inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE& data)
00337 {
00338         S32                     level;
00339         LLSkipNode      *current = &mHead;
00340         LLSkipNode      *temp;
00341         // find the pointer one in front of the one we want
00342         if (mInsertFirst)
00343         {
00344                 for (level = mLevel - 1; level >= 0; level--)
00345                 {
00346                         temp = *(current->mForward + level);
00347                         while (  (temp)
00348                                    &&(mInsertFirst(temp->mData, data)))
00349                         {
00350                                 current = temp;
00351                                 temp = *(current->mForward + level);
00352                         }
00353                         *(mUpdate + level) = current;
00354                 }
00355         }
00356         else
00357         {
00358                 for (level = mLevel - 1; level >= 0; level--)
00359                 {
00360                         temp = *(current->mForward + level);
00361                         while (  (temp)
00362                                    &&(temp->mData < data))
00363                         {
00364                                 current = temp;
00365                                 temp = *(current->mForward + level);
00366                         }
00367                         *(mUpdate + level) = current;
00368                 }
00369         }
00370         // we're now just in front of where we want to be . . . take one step forward
00371         current = *current->mForward;
00372 
00373 
00374         if (!current)
00375         {
00376                 // empty list or beyond the end!
00377                 return FALSE;
00378         }
00379 
00380         // is this the one we want?
00381         if (!mEquals(current->mData, data))
00382         {
00383                 // nope!
00384                 return FALSE;
00385         }
00386         else
00387         {
00388                 // do we need to fix current or currentop?
00389                 if (current == mCurrentp)
00390                 {
00391                         mCurrentp = current->mForward[0];
00392                 }
00393 
00394                 if (current == mCurrentOperatingp)
00395                 {
00396                         mCurrentOperatingp = current->mForward[0];
00397                 }
00398                 // yes it is!  change pointers as required
00399                 for (level = 0; level < mLevel; level++)
00400                 {
00401                         if (mUpdate[level]->mForward[level] != current)
00402                         {
00403                                 // cool, we've fixed all the pointers!
00404                                 break;
00405                         }
00406                         mUpdate[level]->mForward[level] = current->mForward[level];
00407                 }
00408 
00409                 // clean up cuurent
00410                 delete current;
00411 
00412                 // clean up mHead
00413                 while (  (mLevel > 1)
00414                            &&(!mHead.mForward[mLevel - 1]))
00415                 {
00416                         mLevel--;
00417                 }
00418         }
00419         return TRUE;
00420 }
00421 
00422 // remove all nodes from the list but do not delete data
00423 template <class DATA_TYPE, S32 BINARY_DEPTH>
00424 inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes()
00425 {
00426         LLSkipNode *temp;
00427         // reset mCurrentp
00428         mCurrentp = *(mHead.mForward);
00429 
00430         while (mCurrentp)
00431         {
00432                 temp = mCurrentp->mForward[0];
00433                 delete mCurrentp;
00434                 mCurrentp = temp;
00435         }
00436 
00437         S32 i;
00438         for (i = 0; i < BINARY_DEPTH; i++)
00439         {
00440                 mHead.mForward[i] = NULL;
00441                 mUpdate[i] = NULL;
00442         }
00443 
00444         mCurrentp = *(mHead.mForward);
00445         mCurrentOperatingp = *(mHead.mForward);
00446 }
00447 
00448 // place mCurrentp on first node
00449 template <class DATA_TYPE, S32 BINARY_DEPTH>
00450 inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::resetList()
00451 {
00452         mCurrentp = *(mHead.mForward);
00453         mCurrentOperatingp = *(mHead.mForward);
00454 }
00455 
00456 // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
00457 template <class DATA_TYPE, S32 BINARY_DEPTH>
00458 inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData()
00459 {
00460         if (mCurrentp)
00461         {
00462                 mCurrentOperatingp = mCurrentp;
00463                 mCurrentp = mCurrentp->mForward[0];
00464                 return mCurrentOperatingp->mData;
00465         }
00466         else
00467         {
00468                 //return NULL;          // causes compile warning
00469                 return (DATA_TYPE)0;                    // equivalent, but no warning
00470         }
00471 }
00472 
00473 // same as getCurrentData() but a more intuitive name for the operation
00474 template <class DATA_TYPE, S32 BINARY_DEPTH>
00475 inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData()
00476 {
00477         if (mCurrentp)
00478         {
00479                 mCurrentOperatingp = mCurrentp;
00480                 mCurrentp = mCurrentp->mForward[0];
00481                 return mCurrentOperatingp->mData;
00482         }
00483         else
00484         {
00485                 //return NULL;          // causes compile warning
00486                 return (DATA_TYPE)0;                    // equivalent, but no warning
00487         }
00488 }
00489 
00490 // remove the Node at mCurentOperatingp
00491 // leave mCurrentp and mCurentOperatingp on the next entry
00492 template <class DATA_TYPE, S32 BINARY_DEPTH>
00493 inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData()
00494 {
00495         if (mCurrentOperatingp)
00496         {
00497                 removeData(mCurrentOperatingp->mData);
00498         }
00499 }
00500 
00501 // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
00502 template <class DATA_TYPE, S32 BINARY_DEPTH>
00503 inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getFirstData()
00504 {
00505         mCurrentp = *(mHead.mForward);
00506         mCurrentOperatingp = *(mHead.mForward);
00507         if (mCurrentp)
00508         {
00509                 mCurrentOperatingp = mCurrentp;
00510                 mCurrentp = mCurrentp->mForward[0];
00511                 return mCurrentOperatingp->mData;
00512         }
00513         else
00514         {
00515                 //return NULL;          // causes compile warning
00516                 return (DATA_TYPE)0;                    // equivalent, but no warning
00517         }
00518 }
00519 
00520 
00521 #endif

Generated on Thu Jul 1 06:09:10 2010 for Second Life Viewer by  doxygen 1.4.7