#ifndef listdeclare
#ifndef GENERICH
#include <generic.h>
#endif
#include <stream.h>

#ifndef TRUE
#define FALSE	0
#define TRUE	(!FALSE)
#endif

#ifndef NULL
#define NULL	0
#endif

#ifndef BIT_DEFINED
#define BIT_DEFINED
typedef int	bit;
#endif

struct lnk {
	lnk*	nxt;
	lnk*	prv;
	void	init(lnk* p, lnk* s) { prv = p; nxt = s; }
		lnk() {}
		~lnk() {}
};
struct LstHead {
	lnk	*t;	// tail
	lnk	*h() { return t ? t->nxt : 0; }
	int	sz;
	lnk	*cache;		// a recently retrieved link
	int	cacheNo;	// its index or garbage if cache == NULL
	int	refCount;
		LstHead() { sz = 0; cache = t = NULL; }
		virtual ~LstHead();
	void	insert(lnk*);	// used by put() and unget()
	void	unget(lnk* nl) { insert(nl); cacheNo++; }
	void	put(lnk* nl) { insert(nl); t = nl; }
	lnk*	get();
	lnk*	unput();
	lnk*	getAt(int);
};
struct lstiter;
struct List {
	friend lstiter;
	lstiter	*fI;
	LstHead	*it;
	virtual void	sepWork();
	void	separate() { if (it->refCount > 1) sepWork(); }
	int	length() { return it->sz; }
		List() { fI = NULL; }
		List(List& x) { fI = NULL; it = x.it; it->refCount++; }
		~List();
	lnk*	tail() { return it->t; }
	lnk*	head() { return it->h(); }
	lstiter*	firstIt() { return fI; }
	void	newIt(lstiter*, int=0);
	void	removeIt(lstiter*);
		operator void*() { return length() ? this : 0; }
	List&	operator=(List&);
	List&	unget(lnk*);
	List&	put(lnk*);
	lnk*	get();
	lnk*	unput();
};
struct lstiter {
	friend	List;
	lnk	*pred;
	List	*aList;
	lstiter	*nextIt;
	int	index;
		lstiter(List&, int =0);
		lstiter(lstiter&);
		~lstiter();
	List	*theList() { return aList; }
	lstiter&	operator=(lstiter&);
	bit	operator==(lstiter& oo) {
				return aList == oo.aList &&
				index == oo.index; }
	bit	atEnd() { return index == aList->length(); }
	bit	r_atEnd() { return index == 0 ; }
	lnk*	next();
	lnk*	r_next();
	lnk*	peek();
	lnk*	r_peek();
	void	insert(lnk*);
	void	r_insert(lnk*);
	lnk*	remove();
	lnk*	r_remove();
	void	reset(int =0);
	void	r_reset(int i=0) { reset(aList->length() - i); }
};

extern "C" {
	extern int abort();
}

#define lnnk(type) name2(type,lnnk)
#define list(type) name2(type,_list)
#define ListHead(type) name2(type,ListHead)
#define listiterator(type) name2(type,_list_iterator)
#define listsubitem(type) name2(type,listsubitem)
#define plist(type) name2(type,P_list)
#define plistiterator(type) name2(type,P_list_iterator)
#define plistsubitem(type) name2(type,Plistsubitem)
#define CMPF(type) name2(type,CMPFN)
#define CMPFP(type) name2(type,CMPFNP)

#define listdeclare(type)							\
extern GPT errorhandler(list,type);						\
extern GPT set_handler(list,type,GPT);						\
extern GPT errorhandler(listiterator,type);					\
extern GPT set_handler(listiterator,type,GPT);					\
class list(type);								\
class lnnk(type);								\
class ListHead(type);								\
class listiterator(type);							\
class listsubitem(type);							\
typedef int	(*CMPF(type))(type&, type&);					\
ostream&	operator<<(ostream&, list(type)&);				\
class lnnk(type) : public lnk {							\
	friend ListHead(type);							\
	friend list(type);							\
	friend listsubitem(type);						\
	friend listiterator(type);						\
	friend ostream& operator<<(ostream&, list(type)&);			\
	friend void voidP_list_sort_internal(voidP_list&, CMPF(voidP));		\
	type	val;								\
		lnnk(type)(type& pp) : val(pp) {}				\
		~lnnk(type)() {}						\
};										\
class ListHead(type) : public LstHead {						\
	friend list(type);							\
		ListHead(type)() {}						\
		~ListHead(type)();						\
	lnnk(type)	*tail() { return (lnnk(type)*)t; }			\
	lnnk(type)	*head() { return (lnnk(type)*)h(); }			\
	bit	firstX(type&);							\
	bit	lastX(type&);							\
};										\
class list(type) : public List {						\
	lnnk(type)	*tail() { return (lnnk(type)*)List::tail(); }		\
	lnnk(type)	*head() { return (lnnk(type)*)List::head(); }		\
	void	init() { it = new ListHead(type); it->refCount = 1; }		\
	void	sepWork();							\
public:										\
	friend ostream& operator<<(ostream&, list(type)&);			\
	friend void voidP_list_sort_internal(voidP_list&, CMPF(voidP));		\
		list(type)() { init(); }					\
		list(type)(list(type)& x) : (x) {}				\
		~list(type)() {}						\
		operator void*() { return length() ? this : 0; }		\
	bit	operator==(list(type)&);					\
	bit	operator!=(list(type)& x) { return !(*this == x); }		\
	list(type)&	operator=(list(type)& ll) { return (list(type)&)	\
		(*(List*)this = (List&)ll); }					\
	list(type)&	put(type &x) { return	(list(type)&)			\
				 List::put(new lnnk(type)(x)); }		\
	list(type)&	put(list(type)&);	/* append */			\
	list(type)&	operator+=(list(type)& oo) { return put(oo); }		\
	list(type)&	operator+=(type& t) { return put(t); }			\
	list(type)	operator+(list(type)& ll) { list(type) ans = *this;	\
				ans += ll; return ans; }			\
	list(type)	operator+(type& t) { list(type) ans = *this;		\
				ans += t; return ans; }				\
	bit	unputX(type &t);						\
	bit	unput();							\
	bit	getX(type&);		/* get */				\
	bit	get();		/* get */					\
	list(type)&	unget(type &x) { return	(list(type)&)			\
				 List::unget(new lnnk(type)(x)); }		\
	list(type)&	unget(list(type)&);	/* prepend */			\
	bit	firstX(type& t) { return					\
			((ListHead(type)*)it)->firstX(t); }			\
	bit	lastX(type& t) { return						\
			((ListHead(type)*)it)->lastX(t); }			\
/* getAt(0) returns the head of the list */					\
	type	getAt(int ii) { return ((lnnk(type)*)it->getAt(ii))->val; }	\
	inline listsubitem(type)	operator[](unsigned ii);		\
		list(type)(type& x) { init(); put(x); }				\
		list(type)(type& x, type& y) { init(); put(x); put(y); }	\
		list(type)(type& x, type& y, type& z) { init(); put(x); put(y);	\
			put(z); }						\
		list(type)(type& x, type& y, type& z, type& w) { init();	\
			put(x); put(y); put(z); put(w); }			\
	void	sort(CMPF(type));						\
};										\
class listiterator(type) : public lstiter {					\
	friend listsubitem(type);						\
	friend list(type);							\
public:										\
		listiterator(type)(list(type)& a, int i=0) : (*(List*)&a, i) {}	\
		listiterator(type)(listiterator(type)& a) : (*(lstiter*)&a) {}	\
		~listiterator(type)() {}					\
	listiterator(type)&	operator=(listiterator(type)& a) { return	\
			(listiterator(type)&)(*(lstiter*)this = (lstiter&)a); }	\
	bit	nextX(type&);							\
	bit	nextX(type*&);							\
	bit	next() { return lstiter::next() != 0; }				\
	bit	r_nextX(type&);							\
	bit	r_nextX(type*&);						\
	bit	r_next() { return lstiter::r_next() != 0; }			\
	bit	peekX(type&);							\
	bit	peekX(type*&);							\
	bit	peek() { return !atEnd(); }					\
	bit	r_peekX(type&);							\
	bit	r_peekX(type*&);						\
	bit	r_peek() { return !r_atEnd(); }					\
/* remove -- deletes current from list */					\
	bit	remove();							\
	bit	r_remove();							\
	bit	removeX(type&);							\
	bit	r_removeX(type&);						\
/* insert -- put it at the left of the pointer */				\
	void	insert(type& x) { lstiter::insert(new lnnk(type)(x)); }		\
	void	r_insert(type& x) { lstiter::r_insert(new lnnk(type)(x)); }	\
	bit	replace(type&);							\
	bit	r_replace(type&);						\
};										\
class listsubitem(type) : public listiterator(type) {				\
public:										\
	listsubitem(type)(list(type)& t, unsigned i) : (t, i) {}		\
	listsubitem(type)(listsubitem(type)& a) : ((listiterator(type)&)a) {}	\
	~listsubitem(type)() {}							\
	type&	operator=(type& x) { r_replace(x); return x; }			\
	operator type();							\
};										\
inline listsubitem(type)							\
list(type)::operator[](unsigned ii)						\
{										\
	return listsubitem(type)(*this, ii);					\
}

typedef void*	voidP;
listdeclare(voidP)

#define plistdeclare(type)							\
extern GPT errorhandler(Plist,type);						\
extern GPT set_handler(Plist,type,GPT);						\
extern GPT errorhandler(Plistiterator,type);					\
extern GPT set_handler(Plistiterator,type,GPT);					\
class plist(type);								\
typedef int	(*CMPFP(type))(type*&, type*&);					\
ostream&	operator<<(ostream&, plist(type)&);				\
class plistiterator(type);							\
class plistsubitem(type);							\
class plist(type) : public voidP_list {						\
public:										\
	friend ostream& operator<<(ostream&, plist(type)&);			\
		plist(type)() {}						\
		plist(type)(type* x) : ((voidP) x) {}				\
		plist(type)(type* x, type* y) : ((voidP) x, (voidP) y) {}	\
		plist(type)(type* x, type* y, type* z) :			\
				((voidP) x, (voidP) y, (voidP) z) {}		\
		plist(type)(type* x, type* y, type* z, type* w) :		\
			((voidP) x, (voidP) y, (voidP) z, (voidP) w) {}		\
		plist(type)(plist(type)& ll) : ((voidP_list&) ll) {}		\
		~plist(type)() {}						\
		operator void*() { return voidP_list::operator void*(); }	\
	bit	operator==(plist(type)& ll) { return ((voidP_list&)*this ==	\
			(voidP_list&)ll); }					\
	plist(type)&	operator=(plist(type)& ll) { return (plist(type)&)	\
		((voidP_list&)*this = (voidP_list&)ll); }			\
	plist(type)	operator+(plist(type)& ll) { 				\
		return (plist(type)&)((voidP_list&)*this + (voidP_list&)ll); }	\
	plist(type)	operator+(type* t) {					\
		return (plist(type)&) ((voidP_list&)*this + (voidP)t); }	\
	plist(type)&	put(type *t) { return (plist(type)&)			\
		voidP_list::put((voidP)t); }					\
	plist(type)&	put(plist(type)& ll) { return (plist(type)&)		\
		voidP_list::put((voidP_list&)ll); }				\
	plist(type)&	operator+=(plist(type)& oo) { return put(oo); }		\
	plist(type)&	operator+=(type* t) { return put(t); }			\
	bit	unputX(type *&t) { return voidP_list::unputX((voidP&)t); }	\
	bit	unput() { return voidP_list::unput(); }				\
	bit	getX(type *&t) { return voidP_list::getX((voidP&)t); }		\
	bit	get() { return voidP_list::get(); }				\
	plist(type)&	unget(type *x) { return (plist(type)&)			\
		voidP_list::unget((voidP)x); }					\
	plist(type)&	unget(plist(type)& ll) { return (plist(type)&)		\
		voidP_list::unget((voidP_list&)ll); }				\
	bit	firstX(type *&t) { return voidP_list::firstX((voidP&)t); }	\
	bit	lastX(type *&t) { return voidP_list::lastX((voidP&)t); }	\
/* getAt(0) returns the head of the list */					\
	type*	getAt(int ii) { return (type *) voidP_list::getAt(ii); }	\
	inline plistsubitem(type)	operator[](unsigned ii);		\
	void	sort(CMPFP(type) pf) { voidP_list::sort((CMPF(voidP))pf); }	\
};										\
class plistiterator(type) : public voidP_list_iterator {			\
public:										\
		plistiterator(type)(plist(type)& a, int i=0) :			\
					((voidP_list&)a, i) {}			\
		plistiterator(type)(plistiterator(type)& a) :			\
			((voidP_list_iterator&)a) {}				\
		~plistiterator(type)() {}					\
	plistiterator(type)&	operator=(plistiterator(type)& a) { return	\
			(plistiterator(type)&)((voidP_list_iterator&)*this =	\
			(voidP_list_iterator&)a); }				\
	bit	nextX(type *&t) { return					\
			voidP_list_iterator::nextX((voidP&)t); }		\
	bit	nextX(type **&t) { return					\
			voidP_list_iterator::nextX((voidP*&)t); }		\
	bit	next() { return voidP_list_iterator::next(); }			\
	bit	r_nextX(type *&t) { return					\
			voidP_list_iterator::r_nextX((voidP&)t); }		\
	bit	r_nextX(type **&t) { return					\
			voidP_list_iterator::r_nextX((voidP*&)t); }		\
	bit	r_next() { return voidP_list_iterator::r_next(); }		\
	bit	peekX(type *&t) { return					\
			voidP_list_iterator::peekX((voidP&)t); }		\
	bit	peekX(type **&t) { return					\
			voidP_list_iterator::peekX((voidP*&)t); }		\
	bit	peek() { return voidP_list_iterator::peek(); }			\
	bit	r_peekX(type *&t) { return					\
			voidP_list_iterator::r_peekX((voidP&)t); }		\
	bit	r_peekX(type **&t) { return					\
			voidP_list_iterator::r_peekX((voidP*&)t); }		\
	bit	r_peek() { return voidP_list_iterator::r_peek(); }		\
	bit	remove() { return voidP_list_iterator::remove(); }		\
	bit	r_remove() { return voidP_list_iterator::r_remove(); }		\
	bit	removeX(type *&x) { return					\
			voidP_list_iterator::removeX((voidP&)x); }		\
	bit	r_removeX(type *&x) { return					\
			voidP_list_iterator::r_removeX((voidP&)x); }		\
	void	insert(type *&x) { voidP_list_iterator::insert((voidP&)x); }	\
	void	r_insert(type *&x) {						\
			voidP_list_iterator::r_insert((voidP&)x); }		\
	void	replace(type *x) { voidP_list_iterator::replace((voidP)x); }	\
	void	r_replace(type *x) {						\
			voidP_list_iterator::r_replace((voidP)x); }		\
};										\
class plistsubitem(type) : public voidPlistsubitem {				\
public:										\
	plistsubitem(type)(plist(type)& t, int i) : ((voidP_list&)t, i) {}	\
	plistsubitem(type)(plistsubitem(type)&ll) : ((voidPlistsubitem&)ll){}	\
	~plistsubitem(type)() {}						\
	type*&	operator=(type *&t) { return					\
			(type*&) ((voidPlistsubitem&)*this =(voidP&)t); }	\
	operator type*() { return (type*) voidPlistsubitem::operator voidP(); }	\
};										\
inline										\
plistsubitem(type)								\
plist(type)::operator[](unsigned ii)						\
{										\
	return plistsubitem(type)(*this, ii);					\
}


#define listimplement(type)							\
GPT errorhandler(list,type) = genericerror;					\
GPT errorhandler(listiterator,type) = genericerror;				\
bit										\
ListHead(type)::firstX(type& v)							\
{										\
	lnnk(type)	*aLink = (lnnk(type) *)LstHead::h();			\
	return aLink ? (v = aLink->val, TRUE) : FALSE;				\
}										\
bit										\
ListHead(type)::lastX(type& v)							\
{										\
	lnnk(type)	*aLink = (lnnk(type) *)LstHead::t;			\
	return aLink ? (v = aLink->val, TRUE) : FALSE;				\
}										\
ListHead(type)::~ListHead(type)()						\
{										\
	lnnk(type)	*temp;							\
	while (temp = (lnnk(type) *)LstHead::get())				\
		delete temp;							\
}										\
bit										\
listiterator(type)::remove()							\
{										\
	lnnk(type)	*aLink = (lnnk(type) *)lstiter::remove();		\
	return aLink ? (delete aLink, TRUE) : FALSE;				\
}										\
bit										\
listiterator(type)::removeX(type &x)						\
{										\
	lnnk(type)	*aLink = (lnnk(type) *)lstiter::remove();		\
	return aLink ? (x = aLink->val, delete aLink, TRUE) : FALSE;		\
}										\
bit										\
listiterator(type)::r_remove()							\
{										\
	lnnk(type)	*aLink = (lnnk(type) *)lstiter::r_remove();		\
	return aLink ? (delete aLink, TRUE) : FALSE;				\
}										\
bit										\
listiterator(type)::r_removeX(type &x)						\
{										\
	lnnk(type)	*aLink = (lnnk(type) *)lstiter::r_remove();		\
	return aLink ? (x = aLink->val, delete aLink, TRUE) : FALSE;		\
}										\
bit										\
listiterator(type)::nextX(type& t)						\
{										\
	return atEnd() ? FALSE :						\
	    (t = ((lnnk(type)*)lstiter::next())->val, TRUE);			\
}										\
bit										\
listiterator(type)::nextX(type*& t)						\
{										\
	return atEnd() ? FALSE :						\
	    (theList()->separate(), t = &((lnnk(type)*)lstiter::next())->val,	\
				TRUE);						\
}										\
bit										\
listiterator(type)::r_nextX(type& t)						\
{										\
	return r_atEnd() ? FALSE :						\
	    (t = ((lnnk(type)*)lstiter::r_next())->val, TRUE);			\
}										\
bit										\
listiterator(type)::r_nextX(type*& t)						\
{										\
	return r_atEnd() ? FALSE :						\
	    (theList()->separate(), t = &((lnnk(type)*)lstiter::r_next())->val,	\
				TRUE);						\
}										\
bit										\
listiterator(type)::r_peekX(type& t)						\
{										\
	return r_atEnd() ? FALSE :						\
	    (t = ((lnnk(type)*)lstiter::r_peek())->val, TRUE);			\
}										\
bit										\
listiterator(type)::r_peekX(type*& t)						\
{										\
	return r_atEnd() ? FALSE :						\
	    (theList()->separate(), t = &((lnnk(type)*)lstiter::r_peek())->val,	\
				TRUE);						\
}										\
bit										\
listiterator(type)::peekX(type& t)						\
{										\
	return atEnd() ? FALSE :						\
	    (t = ((lnnk(type)*)lstiter::peek())->val, TRUE);			\
}										\
bit										\
listiterator(type)::peekX(type*& t)						\
{										\
	return atEnd() ? FALSE :						\
	    (theList()->separate(), t = &((lnnk(type)*)lstiter::peek())->val,	\
				TRUE);						\
}										\
bit										\
listiterator(type)::replace(type& x)						\
{										\
	return r_atEnd() ? FALSE :						\
	    (theList()->separate(), ((lnnk(type)*)lstiter::r_peek())->val = x,	\
				TRUE);						\
}										\
bit										\
listiterator(type)::r_replace(type& x)						\
{										\
	return atEnd() ? FALSE :						\
	    (theList()->separate(), ((lnnk(type)*)lstiter::peek())->val = x,	\
				TRUE);						\
}										\
bit										\
list(type)::operator==(list(type)& x)						\
{										\
	if ( length() != x.length() )						\
		return FALSE;							\
	if ( length() == 0 )							\
		return TRUE;							\
	lnnk(type)	*mine = (lnnk(type) *)head();				\
	lnnk(type)	*yours = (lnnk(type) *)x.head();			\
	for ( int i = length(); i--; )						\
		if ( mine->val == yours->val ) {				\
			mine = (lnnk(type) *)mine->nxt;				\
			yours = (lnnk(type) *)yours->nxt;			\
		} else								\
			return FALSE;						\
	return TRUE;								\
}										\
bit										\
list(type)::getX(type& t)							\
{										\
	lnnk(type)	*aLink = (lnnk(type) *)List::get();			\
	return aLink ? (t = aLink->val, delete aLink, TRUE) : FALSE;		\
}										\
bit										\
list(type)::get()								\
{										\
	lnnk(type)	*aLink = (lnnk(type) *)List::get();			\
	return aLink ? (delete aLink, TRUE) : FALSE;				\
}										\
bit										\
list(type)::unputX(type& t)							\
{										\
	lnnk(type)	*aLink = (lnnk(type) *)List::unput();			\
	return aLink ? (t = aLink->val, delete aLink, TRUE) : FALSE;		\
}										\
bit										\
list(type)::unput()								\
{										\
	lnnk(type)	*aLink = (lnnk(type) *)List::unput();			\
	return aLink ? (delete aLink, TRUE) : FALSE;				\
}										\
list(type)&									\
list(type)::put(list(type)& a)							\
{										\
	if (a.length()) {							\
		type	t;							\
		listiterator(type)	ita(a);					\
		while (ita.nextX(t))						\
			put(t);							\
	}									\
	return *this;								\
}										\
list(type)&									\
list(type)::unget(list(type)& a)						\
{										\
	if (a.length()) {							\
		type	t;							\
		listiterator(type)	ita(a);					\
		ita.r_reset();							\
		while (ita.r_nextX(t))						\
			unget(t);						\
	}									\
	return *this;								\
}										\
listsubitem(type)::operator type()						\
{										\
	type	t;								\
	peekX(t);								\
	return t;								\
}										\
void										\
list(type)::sepWork()								\
{										\
	it->refCount--;								\
	ListHead(type)	*newLst = new ListHead(type);				\
	if (tail()) {								\
		for (lnnk(type) *oldLnk = (lnnk(type) *)head();;		\
				oldLnk = (lnnk(type) *)oldLnk->nxt) {		\
			lnnk(type)	*newLnk;				\
			newLst->put(newLnk = new lnnk(type)(oldLnk->val));	\
			/* only be one or two listiterators (I hope) */		\
			for (listiterator(type) *anIt =				\
			    (listiterator(type) *)firstIt(); anIt;		\
			    anIt = (listiterator(type) *)anIt->nextIt) {	\
				if (anIt->pred == oldLnk) {			\
					anIt->pred = newLnk;			\
				}						\
			}							\
			if ( oldLnk == tail() )					\
				break;						\
		}								\
	}									\
	it = newLst;								\
	it->refCount = 1;							\
}										\
void										\
list(type)::sort(CMPF(type) cmp)						\
{										\
	if (length() < 2) return;						\
	separate();								\
	voidP_list_sort_internal(*(voidP_list*)this, (CMPF(voidP))cmp);		\
	for (listiterator(type) *anIt =						\
	    (listiterator(type) *)firstIt(); anIt;				\
	    anIt = (listiterator(type) *)anIt->nextIt)				\
		anIt->reset();							\
}

#define listoutimplement(type)							\
ostream&									\
operator<<(ostream& oo, list(type)& ll)						\
{										\
	oo<<"(";								\
	if ( ll.length() ) {							\
		listiterator(type)	it(ll);					\
		type	t;							\
		it.nextX(t);							\
		oo<<t;								\
		while (it.nextX(t))						\
			oo << " " << t;						\
	} else									\
		oo<<"EMPTYLIST";						\
	oo<<")";								\
	return oo;								\
}

#endif

#define plistimplement(type)							\
GPT errorhandler(Plist,type) = genericerror;					\
GPT errorhandler(Plistiterator,type) = genericerror;

#define plistoutimplement(type)							\
ostream&	operator<<(ostream& oo, plist(type)& ll)			\
{										\
	oo<<"(";								\
	if ( ll.length() ) {							\
		plistiterator(type)	it(ll);					\
		type	*t;							\
		it.nextX(t);							\
		oo<<t;								\
		while (it.nextX(t))						\
			oo << " " << t;						\
	} else									\
		oo<<"EMPTYLIST";						\
	oo<<")";								\
	return oo;								\
}

