dlink.H

00001 
00002 /*
00003   This file is part of Aleph system
00004 
00005   Copyright (c) 2002, 2003, 2004, 2005, 2006
00006   UNIVERSITY LOS ANDES (ULA) Merida - REPÚBLICA BOLIVARIANA DE VENEZUELA  
00007 
00008   - Center of Studies in Microelectronics & Distributed Systems (CEMISID) 
00009   - ULA Computer Science Department
00010   - FUNDACITE Mérida - Ministerio de Ciencia y Tecnología
00011 
00012   PERMISSION TO USE, COPY, MODIFY AND DISTRIBUTE THIS SOFTWARE AND ITS
00013   DOCUMENTATION IS HEREBY GRANTED, PROVIDED THAT BOTH THE COPYRIGHT
00014   NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES OF THE
00015   SOFTWARE, DERIVATIVE WORKS OR MODIFIED VERSIONS, AND ANY PORTIONS
00016   THEREOF, AND THAT BOTH NOTICES APPEAR IN SUPPORTING DOCUMENTATION.
00017 
00018   Aleph is distributed in the hope that it will be useful, but WITHOUT
00019   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00020   or FITNESS FOR A PARTICULAR PURPOSE.
00021 
00022   UNIVERSIDAD DE LOS ANDES requests users of this software to return to 
00023 
00024   Leandro Leon
00025   CEMISID 
00026   Ed La Hechicera 
00027   3er piso, ala sur
00028   Facultad de Ingenieria 
00029   Universidad de Los Andes 
00030   Merida - REPÚBLICA BOLIVARIANA DE VENEZUELA    or
00031 
00032   lrleon@ula.ve
00033 
00034   any improvements or extensions that they make and grant Universidad 
00035   de Los Andes (ULA) the rights to redistribute these changes. 
00036 
00037   Aleph is (or was) granted by: 
00038   - Consejo de Desarrollo Cientifico, Humanistico, Tecnico de la ULA 
00039     (CDCHT)
00040   - Fundacite Mérida
00041 */
00042 
00043 
00044 # ifndef DLINK_H
00045 # define DLINK_H
00046 
00047 # include <aleph.H>
00048 
00049 using namespace Aleph;
00050 
00051 namespace Aleph {
00052 
00066 class Dlink 
00067 {
00068   protected: 
00069   mutable Dlink * prev; 
00070   mutable Dlink * next;
00071 
00072 public:
00073 
00074   Dlink() : prev(this), next(this) { /* empty */ }
00076   Dlink(const Dlink &) { reset(); } 
00077 
00086   Dlink & operator = (const Dlink & l) 
00087   {
00088 
00089     if (this == &l)
00090       return *this;
00091 
00092     if (not is_empty())
00093       throw std::invalid_argument ("left list must be empty");
00094 
00095     reset();
00096 
00097     return *this;
00098   }      
00099   void reset() 
00100   {
00101 
00102     I(this != NULL);
00103 
00104     next = prev = this; 
00105   }
00110   void swap(Dlink * link) 
00111   {
00112     if (is_empty() and link->is_empty())
00113       return;
00114 
00115     if (is_empty())
00116       {
00117         link->next->prev = this;
00118         link->prev->next = this;
00119         next = link->next;
00120         prev = link->prev;
00121         link->reset();
00122 
00123         return;
00124       }
00125 
00126     if (link->is_empty())
00127       {
00128         next->prev = link;
00129         prev->next = link;
00130         link->next = next;
00131         link->prev = prev;
00132         reset();
00133 
00134         return;
00135       }
00136 
00137     Aleph::swap(prev->next, link->prev->next);
00138     Aleph::swap(next->prev, link->next->prev);
00139     Aleph::swap(prev, link->prev);
00140     Aleph::swap(next, link->next);
00141   }
00143   bool is_empty() const { return this == next and this == prev; }
00144 
00146   bool is_unitarian() const { return this != next and next == prev; }
00147 
00149   bool is_unitarian_or_empty() const { return next == prev; }
00155   void insert(Dlink * node) 
00156   {
00157 
00158     I((this != NULL) and (next != NULL) and (prev != NULL));
00159     I(node != NULL); 
00160     I(node->is_empty());
00161 
00162     node->prev = this;
00163     node->next = next;
00164     next->prev = node;
00165     next       = node;
00166   }
00171   void append(Dlink * node) 
00172   {
00173 
00174     I((this != NULL) and (next != NULL) and (prev != NULL));
00175     I(node != NULL);
00176     I(node->is_empty());
00177 
00178     node->next = this;
00179     node->prev = prev;
00180     prev->next = node;
00181     prev       = node;
00182   }
00184   Dlink *& get_next()
00185   {
00186 
00187     I((this != NULL) and (next != NULL) and (prev != NULL));
00188 
00189     return next; 
00190   }
00191       
00193   Dlink *& get_prev()
00194   {
00195 
00196     I((this != NULL) and (next != NULL) and (prev != NULL));
00197 
00198     return prev; 
00199   }
00209   void insert_list(Dlink * head)
00210   {
00211     if (head->is_empty())
00212       return;
00213 
00214     head->prev->next = next;
00215     head->next->prev = this;
00216     next->prev       = head->prev;
00217     next             = head->next;
00218     head->reset();
00219   }
00220 
00230   void append_list(Dlink * head)
00231   {
00232     if (head->is_empty())
00233       return;
00234 
00235     head->next->prev = prev;
00236     head->prev->next = this;
00237     prev->next       = head->next;
00238     prev             = head->prev;
00239     head->reset();
00240   }
00250   void concat_list(Dlink * head) 
00251   { 
00252 
00253     I(head != NULL);
00254 
00255     if (head->is_empty())
00256       return;
00257 
00258     if (this->is_empty())
00259       {
00260         swap(head);
00261 
00262         return;
00263       }
00264 
00265     prev->next       = head->next;
00266     head->next->prev = prev;
00267     prev             = head->prev;
00268     head->prev->next = this;
00269 
00270     head->reset();
00271   }
00272   void del() 
00273   {
00274 
00275     I((this != NULL) and (next != NULL) and (prev != NULL));
00276 
00277     prev->next = next;
00278     next->prev = prev;
00279     reset();
00280   } 
00287   Dlink * remove_prev() 
00288   {
00289 
00290     I((this != NULL) and (next != NULL) and (prev != NULL));
00291     I(prev != this); 
00292     I(next != this); 
00293 
00294     Dlink* retValue = prev;
00295     retValue->del();
00296 
00297     return retValue;
00298   }
00299 
00300   Dlink * remove_next() 
00301   {
00302 
00303     I((this != NULL) and (next != NULL) and (prev != NULL));
00304     I(prev != this); 
00305     I(next != this); 
00306 
00307     Dlink* retValue = next;
00308     retValue->del();
00309 
00310     return retValue;
00311   }
00317   int reverse_list() 
00318   {
00319     if (is_empty())
00320       return 0;
00321 
00322     Dlink tmp_head; // cabecera temporal donde se guarda lista invertida
00323 
00324     int counter = 0; 
00325 
00326         // recorrer toda la lista this, eliminar primero e insertar en tmp_head
00327     while (not is_empty())
00328       {
00329         Dlink * current = remove_next(); // eliminar primero de la lista
00330 
00331         tmp_head.insert(current); // insertarlo de primero en tmp_head
00332 
00333         counter++;
00334       }  
00335 
00336         // tmp_head contiene la lista invertida y this está vacía ==> swap
00337     swap(&tmp_head);
00338 
00339     return counter;
00340   }
00356   size_t split_list(Dlink & l, Dlink & r) 
00357   {
00358 
00359     I(l.is_empty() and r.is_empty()); // l y r deben estar vacías
00360 
00361     size_t count = 0;
00362     
00363     while (not is_empty())
00364       {
00365         l.append(remove_next()); ++count;
00366 
00367         if (is_empty())
00368           break;
00369 
00370         r.insert(remove_prev()); ++count;
00371       }
00372 
00373     return count;
00374   }
00389   void cut_list(Dlink * link, Dlink * list) 
00390   {
00391 
00392     I(list->is_empty()); // list debe estar vacía
00393 
00394         // enlazar list a list
00395     list->prev = prev; // último nodo
00396     list->next = link; // primer nodo que es link
00397 
00398         // quitar de this todo lo que está a partir de link
00399     prev = link->prev; 
00400     link->prev->next = this;
00401 
00402     link->prev = list;
00403     list->prev->next = list;
00404   }
00409   class Iterator 
00410   {
00411 
00412   private:
00413 
00414     Dlink * head;
00415     Dlink * curr;
00416 
00417   public:
00418 
00427     Iterator(Dlink * head_ptr) : head(head_ptr), curr(head->get_next())
00428     {
00429       // Empty
00430     }
00431 
00439     Iterator(Dlink & _head) : head(&_head), curr(head->get_next())
00440     {
00441       // Empty
00442     }
00443 
00455     Iterator(Dlink * head_ptr, Dlink * curr_ptr) : head(head_ptr), curr(curr_ptr)
00456     {
00457       // Empty
00458     }
00459 
00467     Iterator(const Iterator &  itor) : head(itor.head), curr(itor.curr)
00468     {
00469       // Empty
00470     }
00471 
00473     Iterator() : head(NULL), curr(NULL) { /* Empty */ }
00474 
00482     Iterator & operator = (const Iterator & itor)
00483     {
00484 
00485       if (this == &itor)
00486         return *this;
00487 
00488       head = itor.head;
00489       curr = itor.curr;
00490 
00491       return *this;
00492     }
00493 
00502     Iterator & operator = (Dlink * head_ptr)
00503     {
00504       head = head_ptr;
00505       curr = head->get_next();
00506 
00507       return *this;
00508     }
00509 
00510     void reset_first() 
00511     {
00512 
00513       I(curr != NULL and head != NULL);
00514 
00515       curr = head->get_next();
00516     }
00517 
00518     void reset_last() 
00519     {
00520 
00521       I(curr != NULL and head != NULL);
00522 
00523       curr = head->get_prev();
00524     }
00535     void set(Dlink * new_curr) 
00536     {
00537 
00538       I(curr != NULL and head != NULL);
00539 
00540       curr = new_curr;
00541     }
00542 
00553     void reset(Dlink * new_head, Dlink * new_curr)
00554     {
00555       head = new_head;
00556       curr = new_curr;
00557     }
00558 
00559 
00568     void reset(Dlink * new_head)
00569     {
00570       head = new_head;
00571       curr = head->get_next();;
00572     }
00574     bool has_current() const 
00575     {
00576 
00577       I(curr != NULL and head != NULL);
00578 
00579       return curr != head;
00580     }
00581 
00583     Dlink * get_current() const
00584     {
00585 
00586       I(curr != NULL and head != NULL);
00587 
00588       if (not has_current())
00589         throw std::overflow_error("Not element in list");
00590 
00591       return curr;
00592     }
00593 
00595     bool is_in_first() const 
00596     {
00597       return curr == head->next;
00598     }
00599 
00601     bool is_in_last() const 
00602     {
00603       return curr == head->prev;
00604     }
00606     void prev() throw(std::exception, std::underflow_error)
00607     {
00608       if (not has_current())
00609         throw std::underflow_error("Not previous element in list");
00610 
00611       curr = curr->get_prev();
00612     }
00613 
00615     void next() throw(std::exception, std::overflow_error)
00616     {
00617       if (not has_current())
00618         throw std::overflow_error("Not next element in list");
00619 
00620       curr = curr->get_next();
00621     }
00623     bool operator == (const Iterator & it) const
00624     {
00625       return curr == it.curr;
00626     }
00627 
00629     bool operator != (const Iterator & it) const
00630     {
00631       return curr != it.curr;
00632     }
00638     Dlink * del() 
00639     {
00640 
00641       I(curr != NULL and head != NULL);
00642       I(has_current());
00643 
00644       Dlink * current = get_current(); // obtener nodo actual
00645       next(); // avanzar al siguiente nodo
00646       current->del(); // eliminar de la lista antiguo nodo actual 
00647 
00648       return current;
00649     } 
00650     bool verify(Dlink * l) const { return head == l; }
00651 
00652     bool verify(const Iterator & it) const { return head == it.head; }
00653   };
00658   void remove_all_and_delete() 
00659   {
00660     Dlink * node;
00661     Iterator itor(this);
00662     
00663         // recorrer y eliminar los nodos
00664     while (itor.has_current())
00665       {
00666         node = itor.get_current();
00667         itor.next();
00668         node->del();
00669         delete node;
00670       }
00671   }
00672   bool check()
00673   {
00674     Iterator itor(this);
00675     Dlink* node;
00676 
00677     for (/* nothing */; itor.has_current(); itor.next())
00678       {
00679         node = itor.get_current();
00680         if (not (node->get_next()->get_prev() == node))
00681           return false;
00682         if (not (node->get_prev()->get_next() == node))
00683           return false;
00684       }
00685 
00686     for (itor.reset_last(); itor.has_current(); itor.prev())
00687       {
00688         node = itor.get_current();
00689         if (not (node->get_next()->get_prev() == node))
00690           return false;
00691         if (not (node->get_prev()->get_next() == node))
00692           return false;
00693       }
00694 
00695     return true;
00696   }
00697 };
00698 
00726 # define DLINK_TO_TYPE(type_name, link_name) \
00727 inline static type_name * dlink_to_##type_name(Dlink * link) \
00728 { \
00729   type_name * ptr_zero = 0; \
00730   size_t offset_link   = reinterpret_cast<size_t>(&(ptr_zero->link_name)); \
00731   char * address_type  = reinterpret_cast<char*>(link) - offset_link; \
00732   return reinterpret_cast<type_name *>(address_type); \
00733 } 
00734 
00772 # define LINKNAME_TO_TYPE(type_name, link_name) \
00773 inline static type_name * link_name##_to_##type_name(Dlink * link) \
00774 { \
00775   type_name * ptr_zero = 0; \
00776   size_t offset_link   = reinterpret_cast<size_t>(&(ptr_zero->link_name)); \
00777   char * address_type  = reinterpret_cast<char*>(link) - offset_link; \
00778   return reinterpret_cast<type_name *>(address_type); \
00779 } 
00780 
00781 }
00782 # endif /* DLINK_H */ 
00783 

Leandro R. León