/*
 * Simple stack class & templates
 * Header file
 * $Id: stack.h,v 1.8 1998/11/24 00:41:16 hsteoh Exp hsteoh $
 * ---------------------------------------------------------------------------
 * DESIGN
 *
 * The stack implementation found here is based on a careful design of
 * how to cleanly implement C++ containers. Unfortunately, due to a hard drive
 * crash, the original document is lost. So the design as it applies to this
 * stack implementation will be repeated here.
 *
 * Basically, the stack as the user sees it has two distinct 'flavours':
 * the 'e' and 'o' flavours. In the original document, three flavours, 'e',
 * 'p' and 'op' were described. The 'p' flavour is now deemed unnecessary; and
 * the 'op' flavour has been renamed to 'o'. These are templates that should
 * be used by ordinary users of the stack. The template names are 'estack' and
 * 'ostack', respectively.
 *	estack		is a stack that uses the copy constructor and
 *			operator=() of the objects that it stores. That is to
 *			say, objects are 'embedded' in the stack: pushing an
 *			object involves making a copy of the passed object
 *			and popping an object returns a copy of the contained
 *			object.
 *	ostack		is a stack that uses 'owner' pointers to the contained
 *			objects. This means that if the stack is destroyed,
 *			all contained objects will be destructed. Once the
 *			object is pushed onto the stack, the stack becomes the
 *			'owner' of the object: the caller should no longer
 *			deallocate the object via the pointer. Popping an
 *			object off the stack restores ownership to the caller
 *			-- ie., after popping, the caller is responsible for
 *			deallocating the object.
 * These templates are implemented on top of a base-level non-template stack
 * implementation. This base implementation should NOT be used directly by
 * normal users -- normal users should only peruse the templates. The base
 * implementation is available only for developers who want to implement their
 * own 'flavour' of stack templates.
 *
 * The base-level stack class is also for use when developing containers
 * that extend the basic stack implementation here. It is intended that the
 * class hierarchy of containers be amongst the base-level classes, and that
 * the user should see only the 'e' and 'o' templates built on each of the
 * classes.
 */

#ifndef STACK_H
#define STACK_H


/* CLASSES */

// Internal class to be used only by stack implementation.
// Programmer's notes:
// - the destructor does NOT deallocate subsequent nodes in the linked list!
//   You need class _stackbase::clear() for correct deallocation of the list.
class _stacknode {
  friend class _stackbase;
  friend class _stackiter;
protected:
  _stacknode *next;

  _stacknode() : next(0) {}
public:
  virtual ~_stacknode();		// (destruct derived classes properly)
};

// Internal class to be used only by stack implementation.
class _stackiter {
  friend class _stackbase;
protected:
  _stacknode *ptr;

  _stackiter(_stacknode *node) : ptr(node) {}
public:
  // operator int() returns a boolean value indicating whether the
  // iterator is pointing to a valid stack node or not. When operator++()
  // steps beyond the end of the list, operator int() will return false; so
  // this is useful for stopping loops involving iterators.
  inline operator int() { return (ptr!=0); }
  inline void invalidate() { ptr=0; }	// useful when NULL stands for
					// something (eg. insert at list head)

  inline _stackiter &operator++ () {
    if (ptr) ptr=(_stacknode *)ptr->next;
    return *this;
  }
};

// Internal class to be used only by stack templates.
class _stackbase {
protected:
  _stacknode *_top;
public:
  _stackbase() { _top=0; }
  void clear();
  ~_stackbase() { clear(); }

  void operator=(_stackbase &s);
  inline void push(_stacknode *n) {
    n->next = _top;
    _top = n;
  }
  inline _stacknode *pop() {
    _stacknode *n=_top;
    if (_top) _top = _top->next;
    return n;
  }
  inline int empty() {
    return (_top==0);
  }
};


/* PRIVATE TEMPLATES */

// Private template used by template class estack.
template <class type> class estack;	// (required forward declaration)
template <class type> class estackiter;	// (ditto)
template <class type> class estacknode : public _stacknode {
  friend class estack<type>;
  friend class estackiter<type>;
  type data;				// embedded object constructed using
					// copy constructor.
  estacknode(type d) : data(d) {}
  ~estacknode() {}
};

// Private template used by template class opstack.
template <class type> class ostack;	// (required forward declaration)
template <class type> class ostackiter;	// (ditto)
template <class type> class ostacknode : public _stacknode {
  friend class ostack<type>;
  friend class ostackiter<type>;
  type *ptr;				// owner pointer to contained object

  ostacknode(type *p) : ptr(p) {}
  ~ostacknode() { if (ptr) delete ptr; }
};


/* PUBLIC TEMPLATES */

// Iterator for estack template.
template <class type> class estackiter : public _stackiter {
  friend class estack<type>;
protected:
  estackiter(estacknode<type> *node) : _stackiter(node) {}
public:
  estackiter() : _stackiter(0) {}

  inline type &operator*() { return ((estacknode<type> *)ptr)->data; }
  inline estackiter<type> &operator++() {
    _stackiter::operator++();
    return *this;
  }
  inline estackiter<type> operator++(int) {
    estackiter<type> old(*this);
    _stackiter::operator++();
    return old;
  }
};

// 'Embedded' stack template.
template <class type> class estack : public _stackbase {
public:
  estack() {}
  ~estack() {}

  inline void push(type d);
  inline type pop();
  inline estackiter<type> top();
};

// Iterator for ostack template.
template <class type> class ostackiter : public _stackiter {
  friend class ostack<type>;
protected:
  ostackiter(ostacknode<type> *p) : _stackiter(p) {}
public:
  ostackiter() : _stackiter(0) {}

  inline type *operator*() { return ((ostacknode<type> *)ptr)->ptr; }
  inline ostackiter<type> &operator++() {
    _stackiter::operator++();
    return *this;
  }
  inline ostackiter<type> operator++(int) {
    ostackiter<type> old(*this);
    _stackiter::operator++();
    return old;
  }
};

// 'Owner-pointer' stack template.
template <class type> class ostack : public _stackbase {
public:
  ostack() {}
  ~ostack() {}

  inline void push(type *d);
  inline type *pop();
  inline ostackiter<type> top();
};


/* TEMPLATE MEMBER DEFINITIONS */

template <class type>
void estack<type>::push(type d) {
  estacknode<type> *n;
  n = new estacknode<type>(d);
  _stackbase::push(n);
}

template <class type>
type estack<type>::pop() {
  estacknode<type> *n;
  n = (estacknode<type> *)_stackbase::pop();
  type d(n->data);			// use copy constructor to construct
					// return data value.
  delete n;
  return d;
}

template <class type>
estackiter<type> estack<type>::top() {
  return estackiter<type>((estacknode<type> *)_top);
}

template <class type>
void ostack<type>::push(type *d) {
  ostacknode<type> *n;
  n = new ostacknode<type>(d);
  _stackbase::push(n);
}

template <class type>
type *ostack<type>::pop() {
  ostacknode<type> *n;
  type *d=0;

  n = (ostacknode<type> *)_stackbase::pop();
  if (n) {
    d = n->ptr;
    n->ptr = 0;				// (so that destructor won't attempt
					//  to deallocate returned object)
    delete n;
  }
  return d;
}

template <class type>
ostackiter<type> ostack<type>::top() {
  return ostackiter<type>((ostacknode<type> *)_top);
}


#endif // STACK_H
