NptList.h

00001 /*****************************************************************
00002 |
00003 |   Neptune - Lists
00004 |
00005 |   (c) 2001-2006 Gilles Boccon-Gibod
00006 |   Author: Gilles Boccon-Gibod (bok@bok.net)
00007 |
00008  ****************************************************************/
00009 
00010 #ifndef _NPT_LIST_H_
00011 #define _NPT_LIST_H_
00012 
00013 /*----------------------------------------------------------------------
00014 |   includes
00015 +---------------------------------------------------------------------*/
00016 #include "NptResults.h"
00017 #include "NptTypes.h"
00018 #include "NptConstants.h"
00019 #include "NptCommon.h"
00020 
00021 /*----------------------------------------------------------------------
00022 |   constants
00023 +---------------------------------------------------------------------*/
00024 const int NPT_ERROR_LIST_EMPTY              = NPT_ERROR_BASE_LIST - 0;
00025 const int NPT_ERROR_LIST_OPERATION_ABORTED  = NPT_ERROR_BASE_LIST - 1;
00026 const int NPT_ERROR_LIST_OPERATION_CONTINUE = NPT_ERROR_BASE_LIST - 2;
00027 
00028 /*----------------------------------------------------------------------
00029 |   NPT_List
00030 +---------------------------------------------------------------------*/
00031 template <typename T> 
00032 class NPT_List 
00033 {
00034 protected:
00035     class Item;
00036 
00037 public:
00038     // types
00039     typedef T Element;
00040 
00041     class Iterator {
00042     public:
00043         Iterator() : m_Item(NULL) {}
00044         explicit Iterator(Item* item) : m_Item(item) {}
00045         Iterator(const Iterator& copy) : m_Item(copy.m_Item) {}
00046         T&  operator*()  const { return m_Item->m_Data; }
00047         T*  operator->() const { return &m_Item->m_Data;}
00048         Iterator& operator++()  { // prefix
00049             m_Item = m_Item->m_Next;
00050             return (*this); 
00051         }
00052         Iterator operator++(int) { // postfix
00053             Iterator saved_this = *this;
00054             m_Item = m_Item->m_Next;
00055             return saved_this;
00056         }
00057         Iterator& operator--() { // prefix
00058             m_Item = m_Item->m_Prev;
00059             return (*this); 
00060         }
00061         Iterator operator--(int) { // postfix
00062             Iterator saved_this = *this;
00063             m_Item = m_Item->m_Prev;
00064             return saved_this;
00065         }
00066         operator bool() const {
00067             return m_Item != NULL;
00068         }
00069         bool operator==(const Iterator& other) const {
00070             return m_Item == other.m_Item;
00071         }
00072         bool operator!=(const Iterator& other) const {
00073             return m_Item != other.m_Item;
00074         }
00075         void operator=(const Iterator& other) {
00076             m_Item = other.m_Item;
00077         }
00078         void operator=(Item* item) {
00079             m_Item = item;
00080         }
00081 
00082     private:
00083         Item* m_Item;
00084 
00085         // friends
00086         friend class NPT_List<T>;
00087     };
00088 
00089     // methods
00090                  NPT_List<T>();
00091                  NPT_List<T>(const NPT_List<T>& list);
00092                 ~NPT_List<T>();
00093     NPT_Result   Add(const T& data);
00094     NPT_Result   Insert(const Iterator where, const T& data);
00095     NPT_Result   Remove(const T& data, bool all=false);
00096     NPT_Result   Erase(const Iterator position);
00097     NPT_Result   PopHead(T& data);
00098     bool         Contains(const T& data) const;
00099     NPT_Result   Clear();
00100     NPT_Result   Get(NPT_Ordinal index, T& data) const;
00101     NPT_Result   Get(NPT_Ordinal index, T*& data) const;
00102     NPT_Cardinal GetItemCount() const { return m_ItemCount; }
00103     Iterator     GetFirstItem() const { return Iterator(m_Head); }
00104     Iterator     GetLastItem() const  { return Iterator(m_Tail); }
00105     Iterator     GetItem(NPT_Ordinal index) const;
00106 
00107     // item manipulation
00108     NPT_Result   Add(Item& item);
00109     NPT_Result   Detach(Item& item);
00110     NPT_Result   Insert(const Iterator where, Item& item);
00111 
00112     // list operations
00113     // keep these template members defined here because MSV6 does not let
00114     // us define them later
00115     template <typename X> 
00116     NPT_Result Apply(const X& function) const
00117     {                          
00118         Item* item = m_Head;
00119         while (item) {
00120             function(item->m_Data);
00121             item = item->m_Next;
00122         }
00123 
00124         return NPT_SUCCESS;
00125     }
00126 
00127     template <typename X, typename P> 
00128     NPT_Result ApplyUntil(const X& function, const P& predicate, bool* match = NULL) const
00129     {                          
00130         Item* item = m_Head;
00131         while (item) {
00132             NPT_Result return_value;
00133             if (predicate(function(item->m_Data), return_value)) {
00134                 if (match) *match = true;
00135                 return return_value;
00136             }
00137             item = item->m_Next;
00138         }
00139         
00140         if (match) *match = false;
00141         return NPT_SUCCESS;
00142     }
00143 
00144     template <typename P> 
00145     Iterator Find(const P& predicate, NPT_Ordinal n=0) const
00146     {
00147         Item* item = m_Head;
00148         while (item) {
00149             if (predicate(item->m_Data)) {
00150                 if (n == 0) {
00151                     return Iterator(item);
00152                 }
00153                 --n;
00154             }
00155             item = item->m_Next;
00156         }
00157 
00158         return Iterator(NULL);
00159     }
00160 
00161     // operators
00162     void operator=(const NPT_List<T>& other);
00163     bool operator==(const NPT_List<T>& other) const;
00164     bool operator!=(const NPT_List<T>& other) const;
00165 
00166 protected:
00167     // types
00168     class Item 
00169     {
00170     public:
00171         // methods
00172         Item(const T& data) : m_Next(0), m_Prev(0), m_Data(data) {}
00173 
00174         // members
00175         Item* m_Next;
00176         Item* m_Prev;
00177         T     m_Data;
00178 
00179         // friends
00180         //friend class NPT_List<T>;
00181         //friend class NPT_List<T>::Iterator;
00182     };
00183 
00184     // members
00185     NPT_Cardinal m_ItemCount;
00186     Item*        m_Head;
00187     Item*        m_Tail;
00188 };
00189 
00190 /*----------------------------------------------------------------------
00191 |   NPT_List<T>::NPT_List
00192 +---------------------------------------------------------------------*/
00193 template <typename T>
00194 inline
00195 NPT_List<T>::NPT_List() : m_ItemCount(0), m_Head(0), m_Tail(0) 
00196 {
00197 }
00198 
00199 /*----------------------------------------------------------------------
00200 |   NPT_List<T>::NPT_List
00201 +---------------------------------------------------------------------*/
00202 template <typename T>
00203 inline
00204 NPT_List<T>::NPT_List(const NPT_List<T>& list) : m_ItemCount(0), m_Head(0), m_Tail(0) 
00205 {
00206     *this = list;
00207 }
00208 
00209 /*----------------------------------------------------------------------
00210 |   NPT_List<T>::~NPT_List<T>
00211 +---------------------------------------------------------------------*/
00212 template <typename T>
00213 inline
00214 NPT_List<T>::~NPT_List()
00215 {
00216     Clear();
00217 }
00218  
00219 /*----------------------------------------------------------------------
00220 |   NPT_List<T>::operator=
00221 +---------------------------------------------------------------------*/
00222 template <typename T>
00223 void
00224 NPT_List<T>::operator=(const NPT_List<T>& list)
00225 {
00226     // cleanup
00227     Clear();
00228 
00229     // copy the new list
00230     Item* item = list.m_Head;
00231     while (item) {
00232         Add(item->m_Data);
00233         item = item->m_Next;
00234     }
00235 }
00236 
00237 /*----------------------------------------------------------------------
00238 |   NPT_List<T>::operator==
00239 +---------------------------------------------------------------------*/
00240 template <typename T>
00241 bool
00242 NPT_List<T>::operator==(const NPT_List<T>& other) const
00243 {
00244     // quick test
00245     if (m_ItemCount != other.m_ItemCount) return false;
00246 
00247     // compare all elements one by one
00248     Item* our_item = m_Head;
00249     Item* their_item = other.m_Head;
00250     while (our_item && their_item) {
00251         if (our_item->m_Data != their_item->m_Data) return false;
00252         our_item   = our_item->m_Next;
00253         their_item = their_item->m_Next;
00254     }
00255     
00256     return our_item == NULL && their_item == NULL;
00257 }
00258 
00259 /*----------------------------------------------------------------------
00260 |   NPT_List<T>::operator!=
00261 +---------------------------------------------------------------------*/
00262 template <typename T>
00263 inline
00264 bool
00265 NPT_List<T>::operator!=(const NPT_List<T>& other) const
00266 {
00267     return !(*this == other);
00268 }
00269 
00270 /*----------------------------------------------------------------------
00271 |   NPT_List<T>::Clear
00272 +---------------------------------------------------------------------*/
00273 template <typename T>
00274 NPT_Result
00275 NPT_List<T>::Clear()
00276 {
00277     // delete all items
00278     Item* item = m_Head;
00279     while (item) {
00280         Item* next = item->m_Next;
00281         delete item;
00282         item = next;
00283     }
00284 
00285     m_ItemCount = 0;
00286     m_Head      = NULL;
00287     m_Tail      = NULL;
00288 
00289     return NPT_SUCCESS;
00290 }
00291 
00292 /*----------------------------------------------------------------------
00293 |   NPT_List<T>::Add
00294 +---------------------------------------------------------------------*/
00295 template <typename T>
00296 NPT_Result
00297 NPT_List<T>::Add(Item& item)
00298 {
00299     // add element at the tail
00300     if (m_Tail) {
00301         item.m_Prev = m_Tail;
00302         item.m_Next = NULL;
00303         m_Tail->m_Next = &item;
00304         m_Tail = &item;
00305     } else {
00306         m_Head = &item;
00307         m_Tail = &item;
00308         item.m_Next = NULL;
00309         item.m_Prev = NULL;
00310     }
00311 
00312     // one more item in the list now
00313     ++m_ItemCount;
00314  
00315     return NPT_SUCCESS;
00316 }
00317 
00318 /*----------------------------------------------------------------------
00319 |   NPT_List<T>::Add
00320 +---------------------------------------------------------------------*/
00321 template <typename T>
00322 inline
00323 NPT_Result
00324 NPT_List<T>::Add(const T& data)
00325 {
00326     return Add(*new Item(data));
00327 }
00328 
00329 /*----------------------------------------------------------------------
00330 |   NPT_List<T>::GetItem
00331 +---------------------------------------------------------------------*/
00332 template <typename T>
00333 typename NPT_List<T>::Iterator
00334 NPT_List<T>::GetItem(NPT_Ordinal n) const
00335 {
00336     Iterator result;
00337     if (n >= m_ItemCount) return result;
00338     
00339     result = m_Head;
00340     for (unsigned int i=0; i<n; i++) {
00341         ++result;
00342     }
00343 
00344     return result;
00345 }
00346 
00347 /*----------------------------------------------------------------------
00348 |   NPT_List<T>::Insert
00349 +---------------------------------------------------------------------*/
00350 template <typename T>
00351 inline NPT_Result
00352 NPT_List<T>::Insert(Iterator where, const T&data)
00353 {
00354     return Insert(where, *new Item(data));
00355 }
00356 
00357 /*----------------------------------------------------------------------
00358 |   NPT_List<T>::Insert
00359 +---------------------------------------------------------------------*/
00360 template <typename T>
00361 NPT_Result
00362 NPT_List<T>::Insert(Iterator where, Item& item)
00363 {
00364     // insert the item in the list
00365     Item* position = where.m_Item;
00366     if (position) {
00367         // insert at position
00368         item.m_Next = position;
00369         item.m_Prev = position->m_Prev;
00370         position->m_Prev = &item;
00371         if (item.m_Prev) {
00372             item.m_Prev->m_Next = &item;
00373         } else {
00374             // this is the new head
00375             m_Head = &item;
00376         }
00377 
00378         // one more item in the list now
00379         ++m_ItemCount;
00380     } else {
00381         // insert at tail
00382         return Add(item);
00383     }
00384  
00385     return NPT_SUCCESS;
00386 }
00387 
00388 /*----------------------------------------------------------------------
00389 |   NPT_List<T>::Erase
00390 +---------------------------------------------------------------------*/
00391 template <typename T>
00392 NPT_Result
00393 NPT_List<T>::Erase(Iterator position) 
00394 {
00395     if (!position) return NPT_ERROR_NO_SUCH_ITEM;
00396     Detach(*position.m_Item);
00397     delete position.m_Item;
00398 
00399     return NPT_SUCCESS;
00400 }
00401 
00402 /*----------------------------------------------------------------------
00403 |   NPT_List<T>::Remove
00404 +---------------------------------------------------------------------*/
00405 template <typename T>
00406 NPT_Result
00407 NPT_List<T>::Remove(const T& data, bool all)
00408 {
00409     Item* item = m_Head;
00410     NPT_Cardinal matches = 0;
00411 
00412     while (item) {
00413         Item* next = item->m_Next;
00414         if (item->m_Data == data) {
00415             // we found a match
00416             ++matches;
00417 
00418             // detach item
00419             Detach(*item);
00420             
00421             // destroy the item
00422             delete item;
00423 
00424             if (!all) return NPT_SUCCESS;
00425         }
00426         item = next;
00427     }
00428  
00429     return matches?NPT_SUCCESS:NPT_ERROR_NO_SUCH_ITEM;
00430 }
00431 
00432 /*----------------------------------------------------------------------
00433 |   NPT_List<T>::Detach
00434 +---------------------------------------------------------------------*/
00435 template <typename T>
00436 NPT_Result
00437 NPT_List<T>::Detach(Item& item)
00438 {
00439     // remove item
00440     if (item.m_Prev) {
00441         // item is not the head
00442         if (item.m_Next) {
00443             // item is not the tail
00444             item.m_Next->m_Prev = item.m_Prev;
00445             item.m_Prev->m_Next = item.m_Next;
00446         } else {
00447             // item is the tail
00448             m_Tail = item.m_Prev;
00449             m_Tail->m_Next = NULL;
00450         }
00451     } else {
00452         // item is the head
00453         m_Head = item.m_Next;
00454         if (m_Head) {
00455             // item is not the tail
00456             m_Head->m_Prev = NULL;
00457         } else {
00458             // item is also the tail
00459             m_Tail = NULL;
00460         }
00461     }
00462 
00463     // one less item in the list now
00464     --m_ItemCount;
00465 
00466     return NPT_SUCCESS;
00467 }
00468 
00469 /*----------------------------------------------------------------------
00470 |   NPT_List<T>::Get
00471 +---------------------------------------------------------------------*/
00472 template <typename T>
00473 NPT_Result
00474 NPT_List<T>::Get(NPT_Ordinal index, T& data) const
00475 {
00476     T* data_pointer;
00477     NPT_CHECK(Get(index, data_pointer));
00478     data = *data_pointer;
00479     return NPT_SUCCESS;
00480 }
00481 
00482 /*----------------------------------------------------------------------
00483 |   NPT_List<T>::Get
00484 +---------------------------------------------------------------------*/
00485 template <typename T>
00486 NPT_Result
00487 NPT_List<T>::Get(NPT_Ordinal index, T*& data) const
00488 {
00489     Item* item = m_Head;
00490 
00491     if (index < m_ItemCount) {
00492         while (index--) item = item->m_Next;
00493         data = &item->m_Data;
00494         return NPT_SUCCESS;
00495     } else {
00496         data = NULL;
00497         return NPT_ERROR_NO_SUCH_ITEM;
00498     }
00499 }
00500 
00501 /*----------------------------------------------------------------------
00502 |   NPT_List<T>::PopHead
00503 +---------------------------------------------------------------------*/
00504 template <typename T>
00505 NPT_Result
00506 NPT_List<T>::PopHead(T& data)
00507 {
00508     // check that we have an element
00509     if (m_Head == NULL) return NPT_ERROR_LIST_EMPTY;
00510 
00511     // copy the head item's data
00512     data = m_Head->m_Data;
00513 
00514     // discard the head item
00515     Item* head = m_Head;
00516     m_Head = m_Head->m_Next;
00517     if (m_Head) {
00518         m_Head->m_Prev = NULL;
00519     } else {
00520         m_Tail = NULL;
00521     }
00522     delete head;
00523 
00524     // update the count
00525     --m_ItemCount;
00526 
00527     return NPT_SUCCESS;
00528 }
00529 
00530 /*----------------------------------------------------------------------
00531 |   NPT_List<T>::Contains
00532 +---------------------------------------------------------------------*/
00533 template <typename T>
00534 bool
00535 NPT_List<T>::Contains(const T& data) const
00536 {
00537     Item* item = m_Head;
00538     while (item) {
00539         if (item->m_Data == data) return true;
00540         item = item->m_Next;
00541     }
00542 
00543     return false;
00544 }
00545 
00546 #endif // _NPT_LIST_H_