//! STACK.H: STACK TEMPLATE 
//. J.L.Villar 9/5/95 (BorlandC++ 4.0)
//.
//. Items must be able to be copied.
//. Error conditions throw exceptions.
//.
//. Revised: 11/03/2019 (linux)
//. Added arguments to the constructor and overflow
//. exception object.

#ifndef _STACK_H_
#define _STACK_H_	1
#ifndef __cplusplus
#error	STACK.H requires C++.
#endif

#ifdef NOEXC
#define throw
class x_underflow {
public:
	x_underflow(const char *id = 0) {exit(0);}
};
class x_overflow {
public:
	x_overflow(const char *id = 0) {exit(0);}
};
class x_badindex {
public:
	x_badindex(const char *id = 0) {exit(0);}
};
#else
class x_underflow {
public:
	const char *id;
	x_underflow(const char *_id = 0) : id(_id) {}
};
class x_overflow {
public:
	const char *id;
	x_overflow(const char *_id = 0) : id(_id) {}
};
class x_badindex {
public:
	const char *id;
	x_badindex(const char *_id = 0) : id(_id) {}
};
#endif

//: STACK class template
template<class T>
class DynStack {
	const char* id;
	T *p;
	unsigned int s;
	int sp; // index of the top of stack (occupied position)
	unsigned int growrate;
	bool shrinkable;
	enum {DEFSIZE = 10,DEFGROWRATE = 10};
public:
	DynStack(const char *_id = 0,unsigned int _s = DEFSIZE,unsigned int _gr = DEFGROWRATE,bool _shr = false);
	~DynStack() {delete[] p; p = 0;}
	void shrink();
	void grow();
	bool empty() const {return (sp < 0) ? true : false;}
	T &pop();
	void push() {
		if (sp+1 >= s) grow();
		++sp;
	}
	void push(const T &t) {
		if (sp+1 >= s) grow();
		p[++sp] = t;
	}
	void flush() {sp = -1;}
	int depth() const {return sp+1;}
	T &currit() {
		if (empty()) throw x_underflow(id);
		return p[sp];
	}
	int curridx() {
		if (empty()) throw x_underflow(id);
		return sp;
	}
	T &operator[] (int idx) {
		if (idx < 0 || idx > sp) throw x_badindex(id);
		return p[idx];
	}
};

template <class T>
DynStack<T>::DynStack(const char *_id,unsigned int _s,unsigned int _gr,bool _shr) : id(_id),growrate(_gr),s(0),sp(-1),p(0),shrinkable(_shr) {
	if (_s > 0) {
		p = new T[_s];
		s = _s;
	}
}

template <class T>
T &DynStack<T>::pop() {
	if (sp < 0) throw x_underflow(id);
	return p[sp--];
}

template <class T>
void DynStack<T>::grow() {
	if (growrate > 0) {
		T *p1 = new T[s+growrate];
		s += growrate;
		for (unsigned int i = 0; i <= sp; ++i) p1[i] = p[i];
		delete[] p;
		p = p1;
	} else throw x_overflow(id);
}

template <class T>
void DynStack<T>::shrink() {
	if (shrinkable) {
		T *p1 = new T[sp+1];
		s = sp+1;
		for (unsigned int i = 0; i <= sp; ++i) p1[i] = p[i];
		delete[] p;
		p = p1;
	}
}

#endif	// _STACK_H_
//@
