CrystalSpace

Public API Reference

csutil/list.h

Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2003 by Marten Svanfeldt
00003     influenced by Aapl by Adrian Thurston <[email protected]>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009     
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014     
00015     You should have received a copy of the GNU Library General Public
00016     License along with this library; if not, write to the Free
00017     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 */
00019 
00020 #ifndef __CS_UTIL_LIST_H__
00021 #define __CS_UTIL_LIST_H__
00022 
00027 #include "csextern.h"
00028 
00033 template <class T>
00034 class csList
00035 {
00036 protected:
00041   struct csListElement
00042   {
00044     csListElement(const T& d, csListElement* newnext, csListElement* newprev) :
00045       next(newnext), prev(newprev), data(d) {}
00046 
00048     csListElement* next;
00049 
00051     csListElement* prev;
00052 
00054     T data;
00055   };
00056 
00058   void Delete (csListElement *el);
00059 
00060 public:
00062   csList() : head(0), tail(0) {}
00063 
00065   csList(const csList<T> &other);
00066 
00068   ~csList()
00069   { DeleteAll (); }
00070 
00072   class Iterator
00073   {
00074   public:
00076     Iterator() : ptr(0), visited(false), reversed(false)
00077     { }
00079     Iterator(const Iterator& r)
00080     { ptr = r.ptr; visited = r.visited; reversed = r.reversed; }
00082     Iterator(const csList<T> &list, bool reverse = false) :
00083       visited(false), reversed(reverse)
00084     {
00085       if (reverse) ptr = list.tail;
00086       else ptr = list.head;
00087     }
00089     Iterator& operator= (const Iterator& r)
00090     { ptr = r.ptr; visited = r.visited; reversed = r.reversed; return *this; }
00092     bool HasCurrent() const
00093     { return visited && ptr != 0; }
00095     bool HasNext() const
00096     { return ptr && (ptr->next || !visited); }
00098     bool HasPrevious() const
00099     { return ptr && (ptr->prev || !visited); }
00101     bool IsFirst() const
00102     { return ptr && ptr->prev == 0; }
00104     bool IsLast() const
00105     { return ptr && ptr->next == 0; }
00107     bool IsReverse() const
00108     { return reversed; }
00109 
00111     operator T*() const
00112     { return visited && ptr ? &ptr->data : 0; }
00114     T& operator *() const
00115     { CS_ASSERT(ptr != 0); return ptr->data; }
00117     T* operator->() const
00118     { return visited && ptr ? &ptr->data : 0; }
00119 
00121     void Clear ()
00122     {
00123       ptr = 0;
00124       visited = true;
00125     }
00127     T& Next ()
00128     {
00129       if (visited && ptr != 0)
00130         ptr = ptr->next;
00131       visited = true;
00132       CS_ASSERT(ptr != 0);
00133       return ptr->data;
00134     }
00136     T& Previous()
00137     {
00138       if (visited && ptr != 0)
00139         ptr = ptr->prev;
00140       visited = true;
00141       CS_ASSERT(ptr != 0);
00142       return ptr->data;
00143     }
00144     T& Prev() { return Previous(); } // Backward compatibility.
00145 
00147     Iterator& operator++()
00148     {
00149       if (visited && ptr != 0)
00150         ptr = ptr->next;
00151       visited = true;
00152       return *this;
00153     }
00155     Iterator& operator--()
00156     {
00157       if (visited && ptr != 0)
00158         ptr = ptr->prev;
00159       visited = true;
00160       return *this;
00161     }
00162 
00167     T& FetchCurrent () const
00168     {
00169       CS_ASSERT(visited && ptr != 0);
00170       return ptr->data;
00171     }
00176     T& FetchNext () const
00177     {
00178       CS_ASSERT(ptr != 0);
00179       return visited ? ptr->next->data : ptr->data;
00180     }
00185     T& FetchPrevious () const
00186     {
00187       CS_ASSERT(ptr != 0);
00188       return visited ? ptr->prev->data : ptr->data;
00189     }
00190     T& FetchPrev () const { return FetchPrevious(); } // Backward compat.
00191 
00192   protected:
00193     friend class csList<T>;
00194     Iterator (csListElement* element, bool visit = true, bool rev = false) :
00195       ptr(element), visited(visit), reversed(rev)
00196     {}
00197 
00198   private:
00199     csListElement* ptr;
00200     bool visited;
00201     bool reversed;
00202   };
00203 
00205   csList& operator=(const csList<T>& other);
00206 
00208   Iterator PushFront (const T& item);
00209 
00211   Iterator PushBack (const T& item);
00212 
00214   void InsertBefore(Iterator& it, const T& item);
00215 
00217   void InsertAfter(Iterator& it, const T& item);
00218 
00220   void MoveBefore(const Iterator& it, const Iterator& item);
00221 
00223   void MoveAfter(const Iterator& it, const Iterator& item);
00224 
00226   void Delete (Iterator& it);
00227 
00229   void DeleteAll();
00230 
00232   T& Front () const
00233   { return head->data; }
00235   T& Last () const
00236   { return tail->data; }
00237 
00239   bool PopFront ()
00240   {
00241     if (!head)
00242       return false;
00243     Delete (head);
00244     return true;
00245   }
00246 
00248   bool PopBack ()
00249   {
00250     if (!tail)
00251       return false;
00252     Delete (tail);
00253     return true;
00254   }
00255   
00256   bool IsEmpty () const
00257   {
00258     CS_ASSERT((head == 0 && tail == 0) || (head !=0 && tail != 0));
00259     return head == 0;
00260   }
00261 
00262 private:
00263   friend class Iterator;
00264   csListElement *head, *tail;
00265 };
00266 
00268 template <class T>
00269 inline csList<T>::csList(const csList<T> &other) : head(0), tail(0)
00270 {
00271   csListElement* e = other.head;
00272   while (e != 0)
00273   {
00274     PushBack (e->data);
00275     e = e->next;
00276   }
00277 }
00278 
00280 template <class T>
00281 inline csList<T>& csList<T>::operator= (const csList<T> &other)
00282 {
00283   DeleteAll ();
00284   csListElement* e = other.head;
00285   while (e != 0)
00286   {
00287     PushBack (e->data);
00288     e = e->next;
00289   }
00290   return *this;
00291 }
00292 
00294 template <class T>
00295 inline void csList<T>::DeleteAll ()
00296 {
00297   csListElement *cur = head, *next = 0;
00298   while (cur != 0)
00299   {
00300     next = cur->next;
00301     delete cur;
00302     cur = next;
00303   }
00304   head = tail = 0;
00305 }
00306 
00308 template <class T>
00309 inline typename csList<T>::Iterator csList<T>::PushBack (const T& e)
00310 {
00311   csListElement* el = new csListElement (e, 0, tail);
00312   if (tail)
00313     tail->next = el;
00314   else
00315     head = el;
00316   tail = el;
00317   return Iterator(el);
00318 }
00319 
00321 template <class T>
00322 inline typename csList<T>::Iterator csList<T>::PushFront (const T& e)
00323 {
00324   csListElement* el = new csListElement (e, head, 0);
00325   if (head)
00326     head->prev = el;
00327   else
00328     tail = el;
00329   head = el;
00330   return Iterator (el);
00331 }
00332 
00333 template <class T>
00334 inline void csList<T>::InsertAfter (Iterator &it, const T& item)
00335 {
00336   CS_ASSERT(it.HasCurrent());
00337   csListElement* el = it.ptr;
00338   csListElement* next = el->next;
00339   csListElement* prev = el;
00340   csListElement* newEl = new csListElement (item, next, prev);
00341   if (!next) // this is the last element
00342     tail = newEl;
00343   else
00344     el->next->prev = newEl;
00345   el->next = newEl;
00346 }
00347 
00348 template <class T>
00349 inline void csList<T>::InsertBefore (Iterator &it, const T& item)
00350 {
00351   CS_ASSERT(it.HasCurrent());
00352   csListElement* el = it.ptr;
00353   csListElement* next = el;
00354   csListElement* prev = el->prev;
00355   csListElement* newEl = new csListElement (item, next, prev);
00356   if (!prev) // this is the first element
00357     head = newEl;
00358   else
00359     el->prev->next = newEl;
00360   el->prev = newEl;
00361 }
00362 
00363 template <class T>
00364 inline void csList<T>::MoveAfter (const Iterator &it, const Iterator &item)
00365 {
00366   CS_ASSERT(item.HasCurrent());
00367   csListElement* el_item = item.ptr;
00368 
00369   // Unlink the item.
00370   if (el_item->prev)
00371     el_item->prev->next = el_item->next;
00372   else
00373     head = el_item->next;
00374   if (el_item->next)
00375     el_item->next->prev = el_item->prev;
00376   else
00377     tail = el_item->prev;
00378 
00379   CS_ASSERT(it.HasCurrent());
00380   csListElement* el = it.ptr;
00381   csListElement* next = el->next;
00382   csListElement* prev = el;
00383 
00384   el_item->next = next;
00385   el_item->prev = prev;
00386   if (!next) // this is the last element
00387     tail = el_item;
00388   else
00389     el->next->prev = el_item;
00390   el->next = el_item;
00391 }
00392 
00393 template <class T>
00394 inline void csList<T>::MoveBefore (const Iterator &it, const Iterator &item)
00395 {
00396   CS_ASSERT(item.HasCurrent());
00397   csListElement* el_item = item.ptr;
00398 
00399   // Unlink the item.
00400   if (el_item->prev)
00401     el_item->prev->next = el_item->next;
00402   else
00403     head = el_item->next;
00404   if (el_item->next)
00405     el_item->next->prev = el_item->prev;
00406   else
00407     tail = el_item->prev;
00408 
00409   CS_ASSERT(it.HasCurrent());
00410   csListElement* el = it.ptr;
00411   csListElement* next = el;
00412   csListElement* prev = el->prev;
00413 
00414   el_item->next = next;
00415   el_item->prev = prev;
00416   if (!prev) // this is the first element
00417     head = el_item;
00418   else
00419     el->prev->next = el_item;
00420   el->prev = el_item;
00421 }
00422 
00423 template <class T>
00424 inline void csList<T>::Delete (Iterator &it)
00425 {
00426   CS_ASSERT(it.HasCurrent());
00427   csListElement* el = it.ptr;
00428 
00429   // Advance the iterator so we can delete the data it's using
00430   if (it.IsReverse())
00431     --it;
00432   else
00433     ++it;
00434 
00435   Delete(el);
00436 }
00437 
00438 template <class T>
00439 inline void csList<T>::Delete (csListElement *el)
00440 {
00441   CS_ASSERT(el != 0);
00442 
00443   // Fix the pointers of the 2 surrounding elements
00444   if (el->prev)
00445     el->prev->next = el->next;
00446   else
00447     head = el->next;
00448 
00449   if (el->next)
00450     el->next->prev = el->prev;
00451   else
00452     tail = el->prev;
00453 
00454   delete el;
00455 }
00456 
00457 #endif //__CS_UTIL_LIST_H__

Generated for Crystal Space by doxygen 1.4.7