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
00043
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:
00057 ListNode() :
00058 m_pvItem(NULL),m_pPrev(NULL),m_pNext(NULL),m_pCurrent(NULL),m_id(0) {}
00059 public:
00060 void* m_pvItem;
00061
00062
00063 ListNode* m_pPrev;
00064 ListNode* m_pNext;
00065 ListNode* m_pCurrent;
00066 int m_id;
00067
00068 private:
00069
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
00087
00088
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
00104 if(l.m_nNumEntries)
00105 {
00106 ListNode* pCurrentNode = l.m_pHead;
00107
00108
00109 ListNode* pHeadNode = new ListNode;
00110 pHeadNode->m_pvItem = pCurrentNode->m_pvItem;
00111 m_pHead = m_pTail = m_pCurrent = pHeadNode;
00112
00113
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
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)
00136 return *this;
00137
00138 purge();
00139 m_nNumEntries = l.m_nNumEntries;
00140 m_uniqueID = l.m_uniqueID;
00141
00142 m_pHead = m_pTail = m_pCurrent = NULL;
00143 m_bMasterList = false;
00144
00145
00146 if(l.m_nNumEntries)
00147 {
00148 ListNode* pCurrentNode = l.m_pHead;
00149
00150
00151 ListNode* pHeadNode = new ListNode;
00152 pHeadNode->m_pvItem = pCurrentNode->m_pvItem;
00153 m_pHead = m_pTail = m_pCurrent = pHeadNode;
00154
00155
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
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
00177
00178 void forceMasterList() {m_bMasterList = true;}
00179 void clearMasterList() {m_bMasterList = false;}
00180
00181
00182
00183
00184
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
00221
00222
00223 template <class T>
00224 void LinkedList<T>::purge()
00225 {
00226
00227
00228 assert(m_bMasterList);
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
00253
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);
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
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);
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
00311 pNode->m_pPrev = NULL;
00312 pNode->m_pNext = pHead;
00313
00314 m_pHead = pNode;
00315 if(!m_pTail)
00316 m_pTail=m_pHead;
00317
00318
00319
00320 if(pHead)
00321 pHead->m_pPrev = pNode;
00322
00323
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
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;
00394
00395 delete pNode;
00396 m_nNumEntries--;
00397 }
00398 return o;
00399 }
00400
00401
00402
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;
00417
00418 delete pNode;
00419 m_nNumEntries--;
00420 }
00421 return o;
00422 }
00423
00424
00425
00426
00427
00428
00429
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;
00458 }
00459 else
00460 {
00461 m_pHead=pNode->m_pNext;
00462 if(pNode->m_pNext)
00463 pNode->m_pNext->m_pPrev = NULL;
00464 }
00465 switch(direction)
00466 {
00467 case listPREV:
00468
00469 m_pCurrent = pNode->m_pPrev;
00470 break;
00471
00472 case listNEXT:
00473
00474 m_pCurrent = pNode->m_pNext;
00475 break;
00476
00477 default: assert(0);
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
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