/***************************************************************************
* 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