llptrskiplist.h

Go to the documentation of this file.
00001 
00032 #ifndef LL_LLPTRSKIPLIST_H
00033 #define LL_LLPTRSKIPLIST_H
00034 
00035 #include "llerror.h"
00036 //#include "vmath.h"
00037 
00039 //
00040 //      LLPtrSkipList implementation - skip list for pointers to objects
00041 //
00042 
00043 template <class DATA_TYPE, S32 BINARY_DEPTH = 8>
00044 class LLPtrSkipList
00045 {
00046 public:
00047         friend class LLPtrSkipNode;
00048 
00049         // basic constructor
00050         LLPtrSkipList();
00051         // basic constructor including sorter
00052         LLPtrSkipList(BOOL      (*insert_first)(DATA_TYPE *first, DATA_TYPE *second), 
00053                                   BOOL  (*equals)(DATA_TYPE *first, DATA_TYPE *second));
00054         ~LLPtrSkipList();
00055 
00056         inline void setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second));
00057         inline void setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second));
00058 
00059         inline BOOL addData(DATA_TYPE *data);
00060 
00061         inline BOOL checkData(const DATA_TYPE *data);
00062 
00063         inline S32 getLength(); // returns number of items in the list - NOT constant time!
00064 
00065         inline BOOL removeData(const DATA_TYPE *data);
00066 
00067         // note that b_sort is ignored
00068         inline BOOL moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort);
00069 
00070         inline BOOL moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort);
00071 
00072         // resort -- use when the value we're sorting by changes
00073         /* IW 12/6/02 - This doesn't work!
00074            Instead, remove the data BEFORE you change it
00075            Then re-insert it after you change it
00076         BOOL resortData(DATA_TYPE *data)
00077         */
00078 
00079         // remove all nodes from the list but do not delete data
00080         inline void removeAllNodes();
00081 
00082         inline BOOL deleteData(const DATA_TYPE *data);
00083 
00084         // remove all nodes from the list and delete data
00085         inline void deleteAllData();
00086 
00087         // place mCurrentp on first node
00088         inline void resetList();
00089 
00090         // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
00091         inline DATA_TYPE        *getCurrentData();
00092 
00093         // same as getCurrentData() but a more intuitive name for the operation
00094         inline DATA_TYPE        *getNextData();
00095 
00096         // remove the Node at mCurentOperatingp
00097         // leave mCurrentp and mCurentOperatingp on the next entry
00098         inline void removeCurrentData();
00099 
00100         // delete the Node at mCurentOperatingp
00101         // leave mCurrentp and mCurentOperatingp on the next entry
00102         inline void deleteCurrentData();
00103 
00104         // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
00105         inline DATA_TYPE        *getFirstData();
00106 
00107         // TRUE if nodes are not in sorted order
00108         inline BOOL corrupt();
00109 
00110 protected:
00111         class LLPtrSkipNode
00112         {
00113         public:
00114                 LLPtrSkipNode()
00115                 :       mData(NULL)
00116                 {
00117                         S32 i;
00118                         for (i = 0; i < BINARY_DEPTH; i++)
00119                         {
00120                                 mForward[i] = NULL;
00121                         }
00122                 }
00123 
00124                 LLPtrSkipNode(DATA_TYPE *data)
00125                         : mData(data)
00126                 {
00127                         S32 i;
00128                         for (i = 0; i < BINARY_DEPTH; i++)
00129                         {
00130                                 mForward[i] = NULL;
00131                         }
00132                 }
00133 
00134                 ~LLPtrSkipNode()
00135                 {
00136                         if (mData)
00137                         {
00138                                 llerror("Attempting to call LLPtrSkipNode destructor with a non-null mDatap!", 1);
00139                         }
00140                 }
00141 
00142                 // delete associated data and NULLs out pointer
00143                 void deleteData()
00144                 {
00145                         delete mData;
00146                         mData = NULL;
00147                 }
00148 
00149                 // NULLs out pointer
00150                 void removeData()
00151                 {
00152                         mData = NULL;
00153                 }
00154 
00155                 DATA_TYPE                                       *mData;
00156                 LLPtrSkipNode                           *mForward[BINARY_DEPTH];
00157         };
00158 
00159         static BOOL                                     defaultEquals(const DATA_TYPE *first, const DATA_TYPE *second)
00160         {
00161                 return first == second;
00162         }
00163 
00164 
00165         LLPtrSkipNode                           mHead;
00166         LLPtrSkipNode                           *mUpdate[BINARY_DEPTH];
00167         LLPtrSkipNode                           *mCurrentp;
00168         LLPtrSkipNode                           *mCurrentOperatingp;
00169         S32                                                     mLevel;
00170         BOOL                                            (*mInsertFirst)(const DATA_TYPE *first, const DATA_TYPE *second);
00171         BOOL                                            (*mEquals)(const DATA_TYPE *first, const DATA_TYPE *second);
00172 };
00173 
00174 
00175 // basic constructor
00176 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00177 LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList()
00178         : mInsertFirst(NULL), mEquals(defaultEquals)
00179 {
00180         if (BINARY_DEPTH < 2)
00181         {
00182                 llerrs << "Trying to create skip list with too little depth, "
00183                         "must be 2 or greater" << llendl;
00184         }
00185         S32 i;
00186         for (i = 0; i < BINARY_DEPTH; i++)
00187         {
00188                 mUpdate[i] = NULL;
00189         }
00190         mLevel = 1;
00191         mCurrentp = *(mHead.mForward);
00192         mCurrentOperatingp = *(mHead.mForward);
00193 }
00194 
00195 // basic constructor including sorter
00196 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00197 LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList(BOOL      (*insert_first)(DATA_TYPE *first, DATA_TYPE *second), 
00198                                                                                                           BOOL  (*equals)(DATA_TYPE *first, DATA_TYPE *second)) 
00199         :mInsertFirst(insert_first), mEquals(equals)
00200 {
00201         if (BINARY_DEPTH < 2)
00202         {
00203                 llerrs << "Trying to create skip list with too little depth, "
00204                         "must be 2 or greater" << llendl;
00205         }
00206         mLevel = 1;
00207         S32 i;
00208         for (i = 0; i < BINARY_DEPTH; i++)
00209         {
00210                 mHead.mForward[i] = NULL;
00211                 mUpdate[i] = NULL;
00212         }
00213         mCurrentp = *(mHead.mForward);
00214         mCurrentOperatingp = *(mHead.mForward);
00215 }
00216 
00217 template <class DATA_TYPE, S32 BINARY_DEPTH>
00218 inline LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::~LLPtrSkipList()
00219 {
00220         removeAllNodes();
00221 }
00222 
00223 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00224 inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second))
00225 {
00226         mInsertFirst = insert_first;
00227 }
00228 
00229 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00230 inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second))
00231 {
00232         mEquals = equals;
00233 }
00234 
00235 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00236 inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::addData(DATA_TYPE *data)
00237 {
00238         S32                             level;
00239         LLPtrSkipNode   *current = &mHead;
00240         LLPtrSkipNode   *temp;
00241 
00242         // find the pointer one in front of the one we want
00243         if (mInsertFirst)
00244         {
00245                 for (level = mLevel - 1; level >= 0; level--)
00246                 {
00247                         temp = *(current->mForward + level);
00248                         while (  (temp)
00249                                    &&(mInsertFirst(temp->mData, data)))
00250                         {
00251                                 current = temp;
00252                                 temp = *(current->mForward + level);
00253                         }
00254                         *(mUpdate + level) = current;
00255                 }
00256         }
00257         else
00258         {
00259                 for (level = mLevel - 1; level >= 0; level--)
00260                 {
00261                         temp = *(current->mForward + level);
00262                         while (  (temp)
00263                                    &&(temp->mData < data))
00264                         {
00265                                 current = temp;
00266                                 temp = *(current->mForward + level);
00267                         }
00268                         *(mUpdate + level) = current;
00269                 }
00270         }
00271 
00272         
00273         // we're now just in front of where we want to be . . . take one step forward
00274         current = *current->mForward;
00275 
00276         // now add the new node
00277         S32 newlevel;
00278         for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
00279         {
00280                 if (ll_frand() < 0.5f)
00281                         break;
00282         }
00283 
00284         LLPtrSkipNode *snode = new LLPtrSkipNode(data);
00285 
00286         if (newlevel > mLevel)
00287         {
00288                 mHead.mForward[mLevel] = NULL;
00289                 mUpdate[mLevel] = &mHead;
00290                 mLevel = newlevel;
00291         }
00292 
00293         for (level = 0; level < newlevel; level++)
00294         {
00295                 snode->mForward[level] = mUpdate[level]->mForward[level];
00296                 mUpdate[level]->mForward[level] = snode;
00297         }
00298         return TRUE;
00299 }
00300 
00301 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00302 inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE *data)
00303 {
00304         S32                     level;
00305         LLPtrSkipNode   *current = &mHead;
00306         LLPtrSkipNode   *temp;
00307 
00308         // find the pointer one in front of the one we want
00309         if (mInsertFirst)
00310         {
00311                 for (level = mLevel - 1; level >= 0; level--)
00312                 {
00313                         temp = *(current->mForward + level);
00314                         while (  (temp)
00315                                    &&(mInsertFirst(temp->mData, data)))
00316                         {
00317                                 current = temp;
00318                                 temp = *(current->mForward + level);
00319                         }
00320                         *(mUpdate + level) = current;
00321                 }
00322         }
00323         else
00324         {
00325                 for (level = mLevel - 1; level >= 0; level--)
00326                 {
00327                         temp = *(current->mForward + level);
00328                         while (  (temp)
00329                                    &&(temp->mData < data))
00330                         {
00331                                 current = temp;
00332                                 temp = *(current->mForward + level);
00333                         }
00334                         *(mUpdate + level) = current;
00335                 }
00336         }
00337 
00338         
00339         // we're now just in front of where we want to be . . . take one step forward
00340         current = *current->mForward;
00341         
00342         if (current)
00343         {
00344                 return mEquals(current->mData, data);
00345         }
00346         else
00347         {
00348                 return FALSE;
00349         }
00350 }
00351 
00352 // returns number of items in the list
00353 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00354 inline S32 LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getLength()
00355 {
00356         U32     length = 0;
00357         for (LLPtrSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0])
00358         {
00359                 length++;
00360         }
00361         return length;
00362 }
00363 
00364 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00365 inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE *data)
00366 {
00367         S32                     level;
00368         LLPtrSkipNode   *current = &mHead;
00369         LLPtrSkipNode   *temp;
00370 
00371         // find the pointer one in front of the one we want
00372         if (mInsertFirst)
00373         {
00374                 for (level = mLevel - 1; level >= 0; level--)
00375                 {
00376                         temp = *(current->mForward + level);
00377                         while (  (temp)
00378                                    &&(mInsertFirst(temp->mData, data)))
00379                         {
00380                                 current = temp;
00381                                 temp = *(current->mForward + level);
00382                         }
00383                         *(mUpdate + level) = current;
00384                 }
00385         }
00386         else
00387         {
00388                 for (level = mLevel - 1; level >= 0; level--)
00389                 {
00390                         temp = *(current->mForward + level);
00391                         while (  (temp)
00392                                    &&(temp->mData < data))
00393                         {
00394                                 current = temp;
00395                                 temp = *(current->mForward + level);
00396                         }
00397                         *(mUpdate + level) = current;
00398                 }
00399         }
00400 
00401         
00402         // we're now just in front of where we want to be . . . take one step forward
00403         current = *current->mForward;
00404 
00405         if (!current)
00406         {
00407                 // empty list or beyond the end!
00408                 return FALSE;
00409         }
00410 
00411         // is this the one we want?
00412         if (!mEquals(current->mData, data))
00413         {
00414                 // nope!
00415                         return FALSE;
00416         }
00417         else
00418         {
00419                 // yes it is!  change pointers as required
00420                 for (level = 0; level < mLevel; level++)
00421                 {
00422                         if (mUpdate[level]->mForward[level] != current)
00423                         {
00424                                 // cool, we've fixed all the pointers!
00425                                 break;
00426                         }
00427                         mUpdate[level]->mForward[level] = current->mForward[level];
00428                 }
00429 
00430                 // clean up cuurent
00431                 current->removeData();
00432                 delete current;
00433 
00434                 // clean up mHead
00435                 while (  (mLevel > 1)
00436                            &&(!mHead.mForward[mLevel - 1]))
00437                 {
00438                         mLevel--;
00439                 }
00440         }
00441         return TRUE;
00442 }
00443 
00444 // note that b_sort is ignored
00445 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00446 inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort)
00447 {
00448         BOOL removed = removeData(data);
00449         BOOL added = newlist->addData(data);
00450         return removed && added;
00451 }
00452 
00453 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00454 inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort)
00455 {
00456         if (mCurrentOperatingp)
00457         {
00458                 mCurrentp = mCurrentOperatingp->mForward[0];    
00459                 BOOL removed = removeData(mCurrentOperatingp);
00460                 BOOL added = newlist->addData(mCurrentOperatingp);
00461                 mCurrentOperatingp = mCurrentp;
00462                 return removed && added;
00463         }
00464         return FALSE;
00465 }
00466 
00467 // resort -- use when the value we're sorting by changes
00468 /* IW 12/6/02 - This doesn't work!
00469    Instead, remove the data BEFORE you change it
00470    Then re-insert it after you change it
00471 BOOL resortData(DATA_TYPE *data)
00472 {
00473         removeData(data);
00474         addData(data);
00475 }
00476 */
00477 
00478 // remove all nodes from the list but do not delete data
00479 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00480 inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes()
00481 {
00482         LLPtrSkipNode *temp;
00483         // reset mCurrentp
00484         mCurrentp = *(mHead.mForward);
00485 
00486         while (mCurrentp)
00487         {
00488                 temp = mCurrentp->mForward[0];
00489                 mCurrentp->removeData();
00490                 delete mCurrentp;
00491                 mCurrentp = temp;
00492         }
00493 
00494         S32 i;
00495         for (i = 0; i < BINARY_DEPTH; i++)
00496         {
00497                 mHead.mForward[i] = NULL;
00498                 mUpdate[i] = NULL;
00499         }
00500 
00501         mCurrentp = *(mHead.mForward);
00502         mCurrentOperatingp = *(mHead.mForward);
00503 }
00504 
00505 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00506 inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteData(const DATA_TYPE *data)
00507 {
00508         S32                     level;
00509         LLPtrSkipNode   *current = &mHead;
00510         LLPtrSkipNode   *temp;
00511 
00512         // find the pointer one in front of the one we want
00513         if (mInsertFirst)
00514         {
00515                 for (level = mLevel - 1; level >= 0; level--)
00516                 {
00517                         temp = *(current->mForward + level);
00518                         while (  (temp)
00519                                    &&(mInsertFirst(temp->mData, data)))
00520                         {
00521                                 current = temp;
00522                                 temp = *(current->mForward + level);
00523                         }
00524                         *(mUpdate + level) = current;
00525                 }
00526         }
00527         else
00528         {
00529                 for (level = mLevel - 1; level >= 0; level--)
00530                 {
00531                         temp = *(current->mForward + level);
00532                         while (  (temp)
00533                                    &&(temp->mData < data))
00534                         {
00535                                 current = temp;
00536                                 temp = *(current->mForward + level);
00537                         }
00538                         *(mUpdate + level) = current;
00539                 }
00540         }
00541 
00542         
00543         // we're now just in front of where we want to be . . . take one step forward
00544         current = *current->mForward;
00545 
00546         if (!current)
00547         {
00548                 // empty list or beyond the end!
00549                 return FALSE;
00550         }
00551 
00552         // is this the one we want?
00553         if (!mEquals(current->mData, data))
00554         {
00555                 // nope!
00556                 return FALSE;
00557         }
00558         else
00559         {
00560                 // do we need to fix current or currentop?
00561                 if (current == mCurrentp)
00562                 {
00563                         mCurrentp = current->mForward[0];
00564                 }
00565 
00566                 if (current == mCurrentOperatingp)
00567                 {
00568                         mCurrentOperatingp = current->mForward[0];
00569                 }
00570 
00571                 // yes it is!  change pointers as required
00572                 for (level = 0; level < mLevel; level++)
00573                 {
00574                         if (mUpdate[level]->mForward[level] != current)
00575                         {
00576                                 // cool, we've fixed all the pointers!
00577                                 break;
00578                         }
00579                         mUpdate[level]->mForward[level] = current->mForward[level];
00580                 }
00581 
00582                 // clean up cuurent
00583                 current->deleteData();
00584                 delete current;
00585 
00586                 // clean up mHead
00587                 while (  (mLevel > 1)
00588                            &&(!mHead.mForward[mLevel - 1]))
00589                 {
00590                         mLevel--;
00591                 }
00592         }
00593         return TRUE;
00594 }
00595 
00596 // remove all nodes from the list and delete data
00597 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00598 inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteAllData()
00599 {
00600         LLPtrSkipNode *temp;
00601         // reset mCurrentp
00602         mCurrentp = *(mHead.mForward);
00603 
00604         while (mCurrentp)
00605         {
00606                 temp = mCurrentp->mForward[0];
00607                 mCurrentp->deleteData();
00608                 delete mCurrentp;
00609                 mCurrentp = temp;
00610         }
00611 
00612         S32 i;
00613         for (i = 0; i < BINARY_DEPTH; i++)
00614         {
00615                 mHead.mForward[i] = NULL;
00616                 mUpdate[i] = NULL;
00617         }
00618 
00619         mCurrentp = *(mHead.mForward);
00620         mCurrentOperatingp = *(mHead.mForward);
00621 }
00622 
00623 // place mCurrentp on first node
00624 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00625 inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::resetList()
00626 {
00627         mCurrentp = *(mHead.mForward);
00628         mCurrentOperatingp = *(mHead.mForward);
00629 }
00630 
00631 // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
00632 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00633 inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData()
00634 {
00635         if (mCurrentp)
00636         {
00637                 mCurrentOperatingp = mCurrentp;
00638                 mCurrentp = *mCurrentp->mForward;
00639                 return mCurrentOperatingp->mData;
00640         }
00641         else
00642         {
00643                 //return NULL;          // causes compile warning
00644                 return 0;                       // equivalent, but no warning
00645         }
00646 }
00647 
00648 // same as getCurrentData() but a more intuitive name for the operation
00649 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00650 inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData()
00651 {
00652         if (mCurrentp)
00653         {
00654                 mCurrentOperatingp = mCurrentp;
00655                 mCurrentp = *mCurrentp->mForward;
00656                 return mCurrentOperatingp->mData;
00657         }
00658         else
00659         {
00660                 //return NULL;          // causes compile warning
00661                 return 0;                       // equivalent, but no warning
00662         }
00663 }
00664 
00665 // remove the Node at mCurentOperatingp
00666 // leave mCurrentp and mCurentOperatingp on the next entry
00667 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00668 inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData()
00669 {
00670         if (mCurrentOperatingp)
00671         {
00672                 removeData(mCurrentOperatingp->mData);
00673         }
00674 }
00675 
00676 // delete the Node at mCurentOperatingp
00677 // leave mCurrentp and mCurentOperatingp on the next entry
00678 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00679 inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteCurrentData()
00680 {
00681         if (mCurrentOperatingp)
00682         {
00683                 deleteData(mCurrentOperatingp->mData);
00684         }
00685 }
00686 
00687 // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
00688 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00689 inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getFirstData()
00690 {
00691         mCurrentp = *(mHead.mForward);
00692         mCurrentOperatingp = *(mHead.mForward);
00693         if (mCurrentp)
00694         {
00695                 mCurrentOperatingp = mCurrentp;
00696                 mCurrentp = mCurrentp->mForward[0];
00697                 return mCurrentOperatingp->mData;
00698         }
00699         else
00700         {
00701                 //return NULL;          // causes compile warning
00702                 return 0;                       // equivalent, but no warning
00703         }
00704 }
00705 
00706 template <class DATA_TYPE, S32 BINARY_DEPTH> 
00707 inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::corrupt()
00708 {
00709         LLPtrSkipNode *previous = mHead.mForward[0];
00710 
00711         // Empty lists are not corrupt.
00712         if (!previous) return FALSE;
00713 
00714         LLPtrSkipNode *current = previous->mForward[0];
00715         while(current)
00716         {
00717                 if (!mInsertFirst(previous->mData, current->mData))
00718                 {
00719                         // prev shouldn't be in front of cur!
00720                         return TRUE;
00721                 }
00722                 current = current->mForward[0];
00723         }
00724         return FALSE;
00725 }
00726 
00727 #endif

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