OpenMW
libs/openengine/misc/list.hpp
Go to the documentation of this file.
00001 #ifndef MISC_LIST_H
00002 #define MISC_LIST_H
00003 
00004 #include <cassert>
00005 
00006 namespace Misc{
00007 
00008 /*
00009   A simple and completely allocation-less doubly linked list. The
00010   class only manages pointers to and between elements. It leaving all
00011   memory management to the user.
00012 */
00013 template <typename Elem>
00014 struct List
00015 {
00016   List() : head(0), tail(0), totalNum(0) {}
00017 
00018   // Empty the list.
00019   void reset()
00020   {
00021     head = 0;
00022     tail = 0;
00023     totalNum = 0;
00024   }
00025 
00026   // Insert an element at the end of the list. The element cannot be
00027   // part of any other list when this is called.
00028   void insert(Elem *p)
00029   {
00030     if(tail)
00031       {
00032         // There are existing elements. Insert the node at the end of
00033         // the list.
00034         assert(head && totalNum > 0);
00035         tail->next = p;
00036       }
00037     else
00038       {
00039         // This is the first element
00040         assert(head == 0 && totalNum == 0);
00041         head = p;
00042       }
00043 
00044     // These have to be done in either case
00045     p->prev = tail;
00046     p->next = 0;
00047     tail = p;
00048 
00049     totalNum++;
00050   }
00051 
00052   // Remove element from the list. The element MUST be part of the
00053   // list when this is called.
00054   void remove(Elem *p)
00055   {
00056     assert(totalNum > 0);
00057 
00058     if(p->next)
00059       {
00060         // There's an element following us. Set it up correctly.
00061         p->next->prev = p->prev;
00062         assert(tail && tail != p);
00063       }
00064     else
00065       {
00066         // We're the tail
00067         assert(tail == p);
00068         tail = p->prev;
00069       }
00070 
00071     // Now do exactly the same for the previous element
00072     if(p->prev)
00073       {
00074         p->prev->next = p->next;
00075         assert(head && head != p);
00076       }
00077     else
00078       {
00079         assert(head == p);
00080         head = p->next;
00081       }
00082 
00083     totalNum--;
00084   }
00085 
00086   // Pop the first element off the list
00087   Elem *pop()
00088   {
00089     Elem *res = getHead();
00090     if(res) remove(res);
00091     return res;
00092   }
00093 
00094   // Swap the contents of this list with another of the same type
00095   void swap(List &other)
00096   {
00097     Elem *tmp;
00098 
00099     tmp = head;
00100     head = other.head;
00101     other.head = tmp;
00102 
00103     tmp = tail;
00104     tail = other.tail;
00105     other.tail = tmp;
00106 
00107     unsigned int tmp2 = totalNum;
00108     totalNum = other.totalNum;
00109     other.totalNum = tmp2;
00110   }
00111 
00112   /* Absorb the contents of another list. All the elements from the
00113      list are moved to the end of this list, and the other list is
00114      cleared.
00115    */
00116   void absorb(List &other)
00117   {
00118     assert(&other != this);
00119     if(other.totalNum)
00120       {
00121         absorb(other.head, other.tail, other.totalNum);
00122         other.reset();
00123       }
00124     assert(other.totalNum == 0);
00125   }
00126 
00127   /* Absorb a range of elements, endpoints included. The elements are
00128      assumed NOT to belong to any list, but they ARE assumed to be
00129      connected with a chain between them.
00130 
00131      The connection MUST run all the way from 'first' to 'last'
00132      through the ->next pointers, and vice versa through ->prev
00133      pointers.
00134 
00135      The parameter 'num' must give the exact number of elements in the
00136      chain.
00137 
00138      Passing first == last, num == 1 is allowed and is equivalent to
00139      calling insert().
00140   */
00141   void absorb(Elem* first, Elem *last, int num)
00142   {
00143     assert(first && last && num>=1);
00144     if(tail)
00145       {
00146         // There are existing elements. Insert the first node at the
00147         // end of the list.
00148         assert(head && totalNum > 0);
00149         tail->next = first;
00150       }
00151     else
00152       {
00153         // This is the first element
00154         assert(head == 0 && totalNum == 0);
00155         head = first;
00156       }
00157 
00158     // These have to be done in either case
00159     first->prev = tail;
00160     last->next = 0;
00161     tail = last;
00162 
00163     totalNum += num;
00164   }
00165 
00166   Elem* getHead() const { return head; }
00167   Elem* getTail() const { return tail; }
00168   unsigned int getNum() const { return totalNum; }
00169 
00170 private:
00171 
00172   Elem *head;
00173   Elem *tail;
00174   unsigned int totalNum;
00175 };
00176 
00177 }
00178 #endif