/* $Id: fifo.h,v 1.17 1998/04/19 15:44:31 dps Exp $ */
/* Generalised fifo */

#ifndef __FIFO_H__
#define __FIFO_H__

#include <iostream.h>
#include <stddef.h>
#ifndef NULL
#define NULL (void *) 0
#endif /* NULL */

template<class T>
class fifo
{
private:
   typedef struct queue
   {
       const T *data;
       struct queue *next;
   } queue;
   struct queue *start;
   struct queue **end;
   int length;

public:
   inline fifo(void)
   {
       start=NULL;
       end=&start;
       length=0;
   }
   inline int is_empty(void)
   {
#ifdef CONSIST_CHECK
       if (end==NULL)
       {
           cerr<<"Oops! end of list is NULL\n";
           exit(1);
       }
#endif
       return (length==0) ? 1 : 0;
   }
   inline int qlen(void)
   {
       return length;
   }
   ~fifo(void);
   void enqueue(const T *d);   /* Add to end of queue */
   void insert(const T *d);    /* Add to start of queue */
   void ins_trans(fifo *f);    /* Insert fifo */
   void rev(void);             /* Reverse */
   void clear(void);           /* Wipe list to empty */
   void transfer(fifo *f);
   const T *dequeue(void);
   ostream &__print_fifo(ostream &) const; /* Print */
};

#ifndef __NO_FIFO_FUNCTIONS__

template<class T>
void fifo<T>::clear(void)
{
   struct queue *ptr, *next;

   ptr=start;
   while (ptr!=NULL)
   {
       next=ptr->next;
       delete(ptr->data);
       delete(ptr);
       ptr=next;
   }
   start=NULL;
   end=&start;
   length=0;
}

template<class T>
fifo<T>::~fifo(void)
{
   struct queue *ptr, *next;

   ptr=start;
   while (ptr!=NULL)
   {
       next=ptr->next;
       delete(ptr->data);
       delete(ptr);
       ptr=next;
   }
}

template<class T>
void fifo<T>::enqueue(const T *d)
{
   struct queue *q;

#ifdef DEBUG_FIFO
   cerr<<"Queue "<<(void *) d<<"\n";
#endif
   q=new(struct queue);
   q->next=NULL;
   q->data=d;
   *end=q;
   end=&(q->next);
   length++;
}

template<class T>
void fifo<T>::insert(const T *d)
{
   struct queue *q;
#ifdef CONSIST_CHECK
   if (end==NULL)
   {
       cerr<<"Oops! end of list is NULL\n";
       exit(1);
   }
#endif

   q=new(struct queue);
   q->next=start;
   q->data=d;
   start=q;
   if (q->next==NULL)
       end=&(q->next);
   length++;
}

template<class T>
const T *fifo<T>::dequeue(void)
{
   const T *d;
   struct queue *q;
#ifdef CONSIST_CHECK
   if (end==NULL)
   {
       cerr<<"Oops! end of list is NULL\n";
       exit(1);
   }
#endif

   if (length==0)
       return NULL;

   q=start;
   d=q->data;
#ifdef DEBUG_FIFO
   cerr<<"Dequeue "<<(void *) d<<"\n";
#endif
   start=start->next;
   if (--length==0)
       end=&start;
   delete(q);
   return d;
}

template <class T>
void fifo<T>::transfer(fifo<T> *d)
{
#ifdef CONSIST_CHECK
   if (end==NULL || d->end==NULL)
   {
       cerr<<"Oops! end of list is NULL\n";
       exit(1);
   }
#endif

   if (d==NULL || d->length==0)
       return;

   *end=d->start;
   end=d->end;
   length+=d->length;
   d->start=NULL;
   d->end=&(d->start);
   d->length=0;
}

template<class T>
void fifo<T>::ins_trans(fifo<T> *d)
{
#ifdef CONSIST_CHECK
   if (end==NULL || d->end==NULL)
   {
       cerr<<"Oops! end of list is NULL\n";
       exit(1);
   }
#endif

   if (d==NULL || d->length==0)
       return;

   *(d->end)=start;
   start=d->start;
   if (*(d->end)==NULL)
       end=d->end;
   length+=d->length;

   d->length=0;
   d->start=NULL;
   d->end=&(d->start);
}

template<class T>
void fifo<T>::rev(void)
{
   struct queue *p, *n, *hdr, **ep;
#ifdef CONSIST_CHECK
   if (end==NULL || d->end==NULL)
   {
       cerr<<"Oops! end of list is NULL\n";
       exit(1);
   }
#endif

   if (length==0)
       return;

   ep=&(start->next);
   for (hdr=NULL, p=start; p!=NULL; )
   {
       n=p->next;
       p->next=hdr;
       hdr=p;
       p=n;
   }
   start=hdr;
   end=ep;
}


template<class T>
ostream &fifo<T>::__print_fifo(ostream &os) const
{
   const struct fifo<T>::queue *q;

#ifdef CONSIST_CHECK
   if (end==NULL || this->end==NULL)
   {
       cerr<<"Oops! end of list is NULL\n";
       exit(1);
   }
#endif

   q=this->start;
   while (q!=NULL)
   {
       os<<(q->data)<<',';
       q=q->next;
   }
   return os;
}

template<class T>
inline ostream &operator << (ostream &os, const fifo<T> *d)
{
   d->__print_fifo(os);
   return os;
}


#endif /* not __NO_FIFO_FUNCTIONS__ */
#endif /* __FIFO_H__ */