///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//  Copyright (C) 1995-1998 by the Board of Trustees of Leland Stanford      //
//  Junior University.  See LICENSE for details.                             //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#ifndef _linklist_h_
#define _linklist_h_


#include "misc.h"

template <class _Data> class Link;
template <class _Data> class Link_List;
template <class _Data> class Link_Ptr;

template <class _Data>
class Link {
private:
  _Data _data;
  Link *_next;

public:
  Link(_Data d) : _data(d), _next(NULL) {}
  _Data& Data() { return _data; }
  Link* &Next() { return _next; }
};


template <class _Data>
class Link_List {
protected:
  Link<_Data> *_head;
  Link<_Data> **_tail;

public:
  Link_List() : _head(NULL), _tail(&_head) {}
  Link_List(const Link_List<_Data> &l) : _head(l._head), _tail(l._tail) {}
  void Destroy();
  void Append(_Data d);
  void Restore(Link_List<_Data> &l);
  friend class Link_Ptr<_Data>;
};


template <class _Data>
class Link_Ptr {
private:
  Link<_Data> *_ptr;

public:
  Link_Ptr() : _ptr(NULL) {}
  Link_Ptr(const Link_List<_Data> &l) : _ptr(l._head) {}
  void operator++() { _ptr = _ptr->Next(); }
  _Data& operator*() { return _ptr->Data(); }
  Bool EOL() { return _ptr==NULL; }
};


template <class _Data>
void Link_List<_Data>::Append(_Data d) 
{
  *_tail = new Link<_Data>(d);
  _tail = &(*_tail)->Next();
}


template <class _Data>
void Link_List<_Data>::Destroy()
{
  Link<_Data> *tmp = _head;
  while (tmp) {
    _head = tmp->Next();
    delete tmp;
    tmp = _head;
  }
  _tail = &_head;
}


template <class _Data>
void Link_List<_Data>::Restore(Link_List<_Data> &l)
{
  Link<_Data> *next = *l._tail;
  while (next) {
    Link<_Data> *tmp = next;
    next = tmp->Next();
    delete tmp;
  }

  _tail = l._tail;
  *_tail = NULL;
}


#endif
