/***************************************************************************
 *   glist.h : Templates for various types of linked lists
 *   
 *   Change Log :
 *		 5-16-1996 Initial version,  Liujian Qian
 *
 *   $Id: glist.h,v 1.2 1998/06/05 19:41:36 qian Exp $
 **************************************************************************/


#ifndef _GLIST_H_
#define _GLIST_H_

#include <iostream.h>

/**
 * @internal
 */
struct dlink {
  dlink* next;
  dlink* prev;
  dlink() {next=0, prev=0;}
  dlink(dlink* p, dlink* s) { prev=p, next=s;}
};

/**
 * @internal
 */
class dlist_base 
{
protected:
  dlink* ptr;     //used in scan of the list
  dlink* head;	  //head of list
  int    n_link;  //number of links in the list
public:
	
  dlist_base() {head=0; n_link=0;}
  dlist_base(dlink* a) {head = a->next = a->prev = a; n_link=1; }
  ~dlist_base() {
                 if(!head) return;
                 dlink *tmp1, *tmp = head->next;
                 while(tmp!=head && tmp) {tmp1 = tmp->next; delete tmp; tmp=tmp1; }
		 delete head;
                }

  void   insert(dlink*);  //insert at head
  void   append(dlink*);  //append at tail
  void   deleteIt(dlink*);  //delete it
  
  int    getNLink() {return n_link;}
  
  dlink* beginScan()  { ptr=head; return ptr; }
  dlink* getNext()    { ptr = ptr->next; 
                        if(ptr == head) return 0;
                        else return ptr;
                      }
};


inline void 
dlist_base::insert(dlink *a) {
  if(head) {
    dlink *temp = head->prev;    
    a->prev = head->prev;
    a->next = head;
    head->prev=a;
    temp->next = a;
    head = a;		
  } 
  else head = a->prev = a->next = a ;	
  n_link++;
}


inline void 
dlist_base::append(dlink *a)
{
  if(!head) {
    head = a->prev = a->next = a;
  }
  else {
    dlink* tail = head->prev;
    tail->next = a;
    a->prev = tail;
    a->next = head;
    head->prev = a;
  }
  n_link++;
}


inline void 
dlist_base::deleteIt(dlink *a)
{
 if(n_link==0) return; //nosense
  
 if(n_link==1) { //this is the only link in the list
    if(head!=a) {cerr<<"corrupt DList"<<endl; return;}
    head = 0;       
    delete a;
    return;
 }else if (head == a) {
   head = a->next;  //elect new head link.
 }
 a->prev->next = a->next;
 a->next->prev = a->prev;
 delete a;
 n_link--;
}


/**
 * @internal
 */
template<class T>
struct Dlink : public dlink {
	T data;
	Dlink(const T& a) : data(a) {};
};



/**
       A template double-linked list.

DESCRIPTION


 A template class for doubly linked list.

 The object to be put into the list is actualy copied
 and stored in it... so this is a content-based list
 instead of a pointer list !!!
 
 
 When use an instant class such as DList<et>, make
 sure that the parameter type 'et' has the operator '=='
 defined on it ( used in DList<et>::lookup(et&) ).
 <pre>
 Usage1::  (using the two const methods first() and next())

 	int cursor;
	T*  el = list.first(&cursor);
	while(el) {
		process(*el);
		el = list.next(&cursor);
	};

 Usage2:: (using methods beginScan() and scan(); they are not const
	     but doesn't need the explictly declared 'cursor')

	T* el = list.beginScan();
	while(el) {
		process(*el);
		el = list.scan();
	};
 </pre>
*/
template<class T>
class GList : private dlist_base
{
public:
    
    ///
    // return true if the list is empty
    bool isEmpty()            { return (n_link==0); }

    ///
    // insert an object into the beginning of the list.
    // the object ('s content) is copied into the list
    void insert(const T& a)   { dlist_base::insert(new Dlink<T>(a)); }

    //
    // insert an oject just before the specified position
    //void insertAt(const T& a, int pos);
    
    ///
    // add an object to the end of the list.
    // the object's content is copied into the list.
    void append(const T& a)   { 
                              Dlink<T>* nd = new Dlink<T>(a);
			      dlist_base::append(nd); 
    }

    ///    
    // delete an object from the list
    void deleteIt(const T& a) { Dlink<T>* tmp = lookup(a);
                                if(tmp) dlist_base::deleteIt(tmp); 
                            }
    ///
    // return the number of links (objects) in the list
    int  getNLink()  { return dlist_base::getNLink(); }

    ///
    // const method for scanning the list
    T*   first(int* cur) const { *cur=1; return (head)? &(((Dlink<T>*)head)->data): (T*)0; }

    ///
    // const method (used with first()) to traverse the list
    T*   next(int *cur) const  { (*cur)++;
                               if(*cur > n_link) return 0;
  			       Dlink<T>* tmp=0;
			       tmp = (Dlink<T>*)head;
			       for(int i=0;i<(*cur-1); i++)
				   tmp = (Dlink<T>*)(tmp->next);
			       return &tmp->data;
                             }
    
    ///
    // return the last link in the list (which is pointing back to the head link)
    T*   last()      { Dlink<T>* tmp= (Dlink<T>*) head->prev;
                     return (tmp)? &(tmp->data) : (T*)0; }

    ///
    // non-const iterator
    T*   beginScan() { Dlink<T>* tmp = (Dlink<T>*) dlist_base::beginScan();
                       return (tmp)? &(tmp->data) : (T*)0; }

    ///
    // non-const iterator
    T*   scan()      { Dlink<T>* tmp = (Dlink<T>*) dlist_base::getNext();
                           return (tmp)? &(tmp->data) : (T*)0; }

    ///
    // find the pointer to a link with given object
    Dlink<T>* lookup(const T& a) {
                                Dlink<T>* tmp = (Dlink<T>*) head;
 
				if(!tmp)return (Dlink<T>*)0;
				do{
				    if(tmp->data == a)return tmp;
				    tmp = (Dlink<T>*)tmp->next;
				} while(tmp!=head);

				return (Dlink<T>*)0;
                               }
    ///
    // clean up the list: delete everything and reset.
    void clean()	   
    { 
	if(n_link==0) return;
	else if(n_link==1) {
	    delete (Dlink<T>*) head;
	    head = 0, n_link = 0;
	    return;
	} else {
	    Dlink<T> *tmp = (Dlink<T>*) head;
	    Dlink<T> *p = (Dlink<T>*) tmp->next;
	    while(p && p!=head) {
		tmp = (Dlink<T>*) p->next;
		delete p;
		p = tmp;
	    }
	    delete (Dlink<T>*) head;
	    head = 0,n_link = 0;
	    return;
	}
    }
};

#endif


Documentation generated by lqian@lqian-sun on Wed Jul 14 09:36:10 EDT 1999