Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

linkedlist.h

Go to the documentation of this file.
00001 /********************************************************************
00002         Copyright (c) 2001, Lee Patterson & Ant Works Software
00003 
00004         created  :  3/20/2000 1:00am
00005         filename :  linkedlist.hpp
00006         author   :  Lee Patterson (lee@antws.com)
00007         
00008         purpose  :  Template double linked list class for storing any type of data
00009 
00010         notes    :  A linked list is either a master list, or a copy of a list. A
00011                     master list is the original list. A copy is a copy of the
00012                     master. A copied list points to the same data, but you can
00013                     travers the copy and not mess up the position information of
00014                     the master list. A copy should be treated as a read only
00015                     version of the master. You are able to force a copy to be a
00016                     master using forceMasterList() and clearMasterList methods;
00017                     if in the case of the master being only a temporary list
00018                     being passed to a method call, and this method call needs to
00019                     keep a copy of the list. Use this feature carefully!
00020 
00021                     The following actions are NOT allowed to be performed on a
00022                     copied list:
00023 
00024                     1) You are not allowed to remove the data that the list
00025                        points to. Use empty() instead of purge() to clear the
00026                        copied list. The LinkedList destructor knows when to purge or
00027                        empty the list.
00028 
00029                     2) You are not allowed to add items to the list. Since this
00030                        is a copy, a purge() call will not work, and you will end
00031                        up with memory leaks.
00032 
00033                     You ARE allowed to remove items in the list, as this does
00034                     not delete the data pointed to by the list. This is allowed
00035                     so you are able to for example, as a check list, remove
00036                     things from the list that have been worked with or
00037                     completed. Be aware that if you delete the items returned by
00038                     the remove methods, the master list will still point to the
00039                     data you just deleted.
00040 
00041 *********************************************************************/
00042 //TODO: RemoveHead and removeTail need to reassign the current pointer
00043 //TODO  when the current pointer is at the head or tail. See removeCurrent()
00044 
00045 #ifndef LINKEDLIST_H
00046 #define LINKEDLIST_H
00047 
00048 #include <stdlib.h>
00049 #include <assert.h>
00050 
00051 namespace ssobjects
00052 {
00053 
00054 class ListNode
00055 {
00056     public: //methods
00057         ListNode() :
00058           m_pvItem(NULL),/*m_pHead(NULL),m_pTail(NULL),*/m_pPrev(NULL),m_pNext(NULL),m_pCurrent(NULL),m_id(0) {}
00059     public: //attributes
00060         void*   m_pvItem;
00061 //        ListNode* m_pHead;
00062 //        ListNode* m_pTail;
00063         ListNode* m_pPrev;
00064         ListNode* m_pNext;
00065         ListNode* m_pCurrent;
00066         int m_id;
00067 
00068     private:
00069         //unused overloads
00070         ListNode(const ListNode&);
00071         ListNode& operator=(const ListNode&);
00072 };
00073 
00074 enum ListDirection {listPREV,listNEXT};
00075 
00076 template <class T>
00077 class LinkedList
00078 {
00079   protected:
00080     unsigned long m_nNumEntries;
00081     unsigned long m_uniqueID;
00082     ListNode* m_pHead;
00083     ListNode* m_pTail;
00084     ListNode* m_pCurrent;
00085 
00086     // When m_bMasterList is NOT set, this is a copy of a list. As such, only list
00087     // attribues should be modified. The data that the list points to should not
00088     // be modified, as the master list should take care of that.
00089     bool m_bMasterList;
00090 
00091   public:
00092     LinkedList();
00093     ~LinkedList();
00094 
00095     LinkedList(const LinkedList& l)
00096       : m_nNumEntries(l.m_nNumEntries),
00097         m_uniqueID(l.m_uniqueID),
00098         m_pHead(NULL),
00099         m_pTail(NULL),
00100         m_pCurrent(NULL),
00101         m_bMasterList(false)
00102     {
00103       //make a copy of the list
00104       if(l.m_nNumEntries)
00105       {
00106         ListNode* pCurrentNode = l.m_pHead;
00107 
00108         //get the head item of the list
00109         ListNode* pHeadNode = new ListNode;
00110         pHeadNode->m_pvItem = pCurrentNode->m_pvItem;
00111         m_pHead = m_pTail = m_pCurrent = pHeadNode;
00112 
00113         //get the rest of the items in the list
00114         ListNode* pPrevNode = pHeadNode;
00115         while((pCurrentNode = pCurrentNode->m_pNext))
00116         {
00117           ListNode* pNewNode = new ListNode;
00118           pNewNode->m_pPrev = pPrevNode;
00119           pNewNode->m_pvItem = pCurrentNode->m_pvItem;
00120 
00121           // figure out if we are on the current node
00122           if(l.m_pCurrent  == pCurrentNode)
00123             m_pCurrent = pNewNode;
00124 
00125           pPrevNode->m_pNext = pNewNode;
00126           pPrevNode = pNewNode;
00127 
00128           m_pTail = pNewNode;
00129         }
00130       }
00131     }
00132 
00133     LinkedList& operator=(const LinkedList& l)
00134     {
00135       if(&l==this)        //object assigned to itself
00136         return *this;
00137 
00138       purge();
00139       m_nNumEntries = l.m_nNumEntries;
00140       m_uniqueID    = l.m_uniqueID;   //TODO: we should probably make this unique. should have a static id and thread safe if
00141 
00142       m_pHead = m_pTail = m_pCurrent = NULL;
00143       m_bMasterList = false;
00144 
00145       //make a copy of the list
00146       if(l.m_nNumEntries)
00147       {
00148         ListNode* pCurrentNode = l.m_pHead;
00149 
00150         //get the head item of the list
00151         ListNode* pHeadNode = new ListNode;
00152         pHeadNode->m_pvItem = pCurrentNode->m_pvItem;
00153         m_pHead = m_pTail = m_pCurrent = pHeadNode;
00154 
00155         //get the rest of the items in the list
00156         ListNode* pPrevNode = pHeadNode;
00157         while((pCurrentNode = pCurrentNode->m_pNext))
00158         {
00159           ListNode* pNewNode = new ListNode;
00160           pNewNode->m_pPrev = pPrevNode;
00161           pNewNode->m_pvItem = pCurrentNode->m_pvItem;
00162 
00163           // figure out if we are on the current node
00164           if(l.m_pCurrent  == pCurrentNode)
00165             m_pCurrent = pNewNode;
00166 
00167           pPrevNode->m_pNext = pNewNode;
00168           pPrevNode = pNewNode;
00169 
00170           m_pTail = pNewNode;
00171         }
00172       }
00173       return *this;
00174     }
00175 
00176     // See comments in notes section above when using these methods. They are
00177     // not be used casually.
00178     void forceMasterList() {m_bMasterList = true;}
00179     void clearMasterList() {m_bMasterList = false;}
00180 
00181     //adding and removing from the list
00182     //note: you can't add a const item, as when stored in list as a ListNode, it is 
00183     //  stored as void* and that breaks const rules. Also, if you retrieve a const
00184     //  list item, you wouldn't be able to change it's contents because of the const.
00185     void addTail(T* pItem);         
00186     void addHead(T* pItem);
00187 
00188     void empty();
00189     void purge();
00190     T* removeHead();
00191     T* removeTail();
00192     T* removeCurrent(const ListDirection direction = listNEXT);
00193 
00194     unsigned long getNumEntries(){return m_nNumEntries;}
00195     T* getHead();
00196     T* getTail();
00197     T* getNext();
00198     T* getPrev();
00199     T* getCurrent();
00200     T* getAt(unsigned long index);
00201 };
00202 
00203 template <class T>
00204 LinkedList<T>::LinkedList()
00205         : m_nNumEntries(0),m_uniqueID(0),m_pHead(NULL),m_pTail(NULL),
00206           m_pCurrent(NULL),m_bMasterList(true)
00207 {
00208 }
00209 
00210 template <class T>
00211 LinkedList<T>::~LinkedList()
00212 {
00213   if(m_bMasterList)
00214     purge();
00215   else
00216     empty();
00217 }
00218 
00219 //
00220 //  Removes all nodes from the list, and deletes.
00221 //  the objects accociated to the node.
00222 //
00223 template <class T>
00224 void LinkedList<T>::purge()
00225 {
00226   // You can only delete data pointed to by a list via a master list.
00227   // You should use the empty() method to clear this list.
00228   assert(m_bMasterList);  //see comment above
00229   if(!m_bMasterList)
00230     empty();
00231 
00232   if(m_nNumEntries)
00233   {
00234     T* o;
00235     ListNode* pNode = m_pHead;
00236     ListNode* pNext;
00237     while (pNode)
00238     {
00239       m_nNumEntries--;
00240       pNext = pNode->m_pNext;
00241       o=static_cast<T*>(pNode->m_pvItem);
00242       delete o;
00243       delete pNode;
00244       pNode = pNext;  
00245     }
00246     m_pHead=m_pTail=m_pCurrent=NULL;
00247     m_nNumEntries=0;
00248   }
00249 }
00250 
00251 //
00252 //  Removes all nodes from the list, and deletes.
00253 //  Objects are left untouched.
00254 //
00255 template <class T>
00256 void LinkedList<T>::empty()
00257 {
00258   if(m_nNumEntries)
00259   {
00260     ListNode* pNode = m_pHead;
00261     ListNode* pNext;
00262     while (pNode)
00263     {
00264       m_nNumEntries--;
00265       pNext = pNode->m_pNext;
00266       delete pNode;
00267       pNode = pNext;  
00268     }
00269     m_pHead=m_pTail=m_pCurrent=NULL;
00270     m_nNumEntries=0;
00271   }
00272 }
00273 
00274 template <class T>
00275 void LinkedList<T>::addTail(T* pItem)
00276 {
00277     assert(m_bMasterList);  // you can only add data to a master list, copies are read only
00278 
00279     ListNode* pTail = m_pTail;
00280     ListNode* pNode = new ListNode;
00281 
00282     pNode->m_pvItem = pItem;
00283     pNode->m_id=m_uniqueID++;
00284     pNode->m_pPrev = pTail;
00285 
00286     if(!pTail)
00287         m_pHead=pNode;
00288     else
00289         pTail->m_pNext = pNode;
00290 
00291     m_pTail = pNode;
00292 
00293     //if this is the first item in the list, make it the current item
00294     m_nNumEntries++;
00295     if(1 == m_nNumEntries)
00296       m_pCurrent = m_pTail;
00297 }
00298 
00299 template <class T>
00300 void LinkedList<T>::addHead(T* pItem)
00301 {
00302     assert(m_bMasterList);  // you can only add data to a master list, copies are read only
00303 
00304     ListNode* pHead = m_pHead;
00305     ListNode* pNode = new ListNode;
00306 
00307     pNode->m_pvItem = pItem;
00308     pNode->m_id=m_uniqueID++;
00309     
00310     //setup next & prev for new item
00311     pNode->m_pPrev = NULL;
00312     pNode->m_pNext = pHead;
00313 
00314     m_pHead = pNode;        //new head item
00315     if(!m_pTail)
00316         m_pTail=m_pHead;
00317     
00318     //setup next & prev for adjacent items
00319 
00320     if(pHead)
00321         pHead->m_pPrev = pNode;
00322 
00323     //if this is the first item in the list, make it the current item
00324     m_nNumEntries++;
00325     if(1 == m_nNumEntries)
00326       m_pCurrent = m_pHead;
00327 }
00328 
00329 template <class T>
00330 T* LinkedList<T>::getHead()
00331 {
00332     if(!m_pHead) return NULL;
00333     T* pItem = static_cast<T*>(m_pHead->m_pvItem);
00334     m_pCurrent = m_pHead;
00335     return pItem;
00336 }
00337 
00338 template <class T>
00339 T* LinkedList<T>::getTail()
00340 {
00341     if(!m_pTail) return NULL;
00342     T* pItem = static_cast<T*>(m_pTail->m_pvItem);
00343     m_pCurrent = m_pTail;
00344     return pItem;
00345 }
00346 
00347 template <class T>
00348 T* LinkedList<T>::getNext()
00349 {
00350     if(!m_pCurrent) return NULL;
00351     m_pCurrent = m_pCurrent->m_pNext;
00352     if(!m_pCurrent) return NULL;
00353 
00354     T* pItem = static_cast<T*>(m_pCurrent->m_pvItem);
00355     return pItem;
00356 }
00357 
00358 template <class T>
00359 T* LinkedList<T>::getPrev()
00360 {
00361     if(!m_pCurrent) return NULL;
00362     m_pCurrent = m_pCurrent->m_pPrev;
00363     if(!m_pCurrent) return NULL;
00364 
00365     T* pItem = static_cast<T*>(m_pCurrent->m_pvItem);
00366     return pItem;
00367 }
00368 
00369 template <class T>
00370 T* LinkedList<T>::getCurrent()
00371 {
00372     if(!m_pCurrent) return NULL;
00373     
00374     T* pItem = static_cast<T*>(m_pCurrent->m_pvItem);
00375     return pItem;
00376 }
00377 
00378 //
00379 //RETURNS: the item you just removed
00380 //    
00381 template <class T>
00382 T* LinkedList<T>::removeHead()
00383 {
00384     T* o=NULL;
00385     ListNode* pNode = m_pHead;
00386     if(pNode)
00387     {
00388         o=static_cast<T*>(pNode->m_pvItem);
00389         if(pNode->m_pNext)
00390             pNode->m_pNext->m_pPrev=NULL;
00391         m_pHead=pNode->m_pNext;
00392         if(m_pHead==NULL)
00393             m_pTail=NULL;       //nothing left on the list
00394 
00395         delete pNode;
00396         m_nNumEntries--;
00397     }
00398     return o;
00399 }
00400 
00401 //
00402 //RETURNS: the item you just removed
00403 //    
00404 template <class T>
00405 T* LinkedList<T>::removeTail()
00406 {
00407     T* o=NULL;
00408     ListNode*  pNode = m_pTail;
00409     if(pNode)
00410     {
00411         o=static_cast<T*>(pNode->m_pvItem);
00412         if(pNode->m_pPrev)
00413             pNode->m_pPrev->m_pNext=NULL;
00414         m_pTail=pNode->m_pPrev;
00415         if(m_pTail==NULL)
00416             m_pHead=NULL;       //nothing left on the list
00417         
00418         delete pNode;
00419         m_nNumEntries--;
00420     }
00421     return o;
00422 }
00423 
00424 //
00425 //Removes the current node from the list, but does not free the 
00426 //object itself. The current pointer will be moved either to the next
00427 //item in the list, or prev, as specified by direction.
00428 //
00429 //RETURNS: the item you just removed
00430 //    
00431 template <class T>
00432 T* LinkedList<T>::removeCurrent(const ListDirection direction)
00433 {
00434     ListNode* pNode = m_pCurrent;
00435 
00436     if(!pNode)
00437         return NULL;
00438 
00439     T* pItem = NULL;
00440     pItem = static_cast<T*>(m_pCurrent->m_pvItem);
00441     m_nNumEntries--;
00442     if(!m_nNumEntries)
00443     {
00444         m_pHead=NULL;
00445         m_pTail=NULL;
00446         m_pCurrent = NULL;
00447         delete pNode;
00448         return pItem;
00449     }
00450 
00451     if (pNode->m_pPrev)
00452     {
00453         pNode->m_pPrev->m_pNext = pNode->m_pNext;
00454         if (pNode->m_pNext)
00455             pNode->m_pNext->m_pPrev = pNode->m_pPrev;
00456         else
00457             m_pTail=pNode->m_pPrev;         //this was the last item in the list
00458     }
00459     else 
00460     {
00461         m_pHead=pNode->m_pNext;         //this was the first item in the list
00462         if(pNode->m_pNext)
00463             pNode->m_pNext->m_pPrev = NULL;
00464     }
00465     switch(direction)
00466     { 
00467         case listPREV: 
00468             //move current pointer to the prev item. 
00469             m_pCurrent = pNode->m_pPrev; 
00470             break; 
00471 
00472         case listNEXT: 
00473             //move current pointer to the next item. 
00474             m_pCurrent = pNode->m_pNext; 
00475             break; 
00476 
00477         default: assert(0); //should be PREV or NEXT only
00478     }
00479 
00480     delete pNode;
00481     return pItem;
00482 }
00483 
00484 template <class T>
00485 T* LinkedList<T>::getAt(unsigned long index)
00486 {
00487     if(m_nNumEntries)
00488     {
00489         ListNode* pNode = m_pHead;
00490         ListNode* pNext;
00491                 while(pNode)
00492         {
00493             if(!index)
00494             {
00495                 //we have reached the desired item
00496                 T* pItem = static_cast<T*>(pNode->m_pvItem);
00497                 return pItem;
00498             }
00499             index--;
00500             pNext = pNode->m_pNext;
00501             pNode = pNext;
00502         }
00503     }
00504     return NULL;
00505 }
00506 
00507 };
00508 
00509 #endif //LINKEDLIST_H

Generated on Thu Nov 8 12:39:25 2001 for SimpleServerObjects by doxygen1.2.11 written by Dimitri van Heesch, © 1997-2001