// ---------------------------------------------------------------------------
// SimpleBoundedStack.h
//
// A generic bounded stack class. (There is already a stack class in the
// Standard C++ Library; this class is just an illustration of how such a
// class is written from scratch!) Copying and assignment are prohibited
// because this is just a simple example. A real class would have copy
// constructors and an assignment operator defined.
//
// Stack(n) Constructor: declares a stack with room for n elements;
// default size is 256 elements. Throws a bad_alloc if there
// is not enough memory to construct the stack. Note: many
// compilers do not correctly implement Standard C++ and if
// you build this class with a non-standard compiler then the
// behavior is undefined if there is not enough memory for
// the stack.
// ~Stack() Destructor.
// s.size() Returns the number of elements in the stack.
// s.isEmpty() Returns whether the stack is empty.
// s.isFull() Returns whether the stack is full.
// s.push(x) If not full, pushes x, else throws a standard
// overflow_error.
// s.pop() If not empty, pops and returns the element that was
// popped, else throws a standard underflow_error.
// s.peek() If not empty, returns the top element, else throws a
// standard overflow_error.
// ---------------------------------------------------------------------------
#ifndef _SIMPLE_BOUNDED_STACK_H
#define _SIMPLE_BOUNDED_STACK_H
#include <stdexcept>
using namespace std;
// A stack object wraps a low-level array indexed from 0 to capacity-1 where
// the bottommost element (if it exists) will be in slot 0. The member top is
// the index of the slot above the top element, i.e. the next available slot
// that an element can go into. Therefore if top==0 the stack is empty and
// if top==capacity it is full.
template<class T>
class Stack {
T* data;
int capacity;
int top;
// Constructors and Destructors
public:
explicit Stack(int n = 256): top(0), data(new T[n]), capacity(n) {}
~Stack() {delete[] data;}
// Behavior
public:
int getSize() {return top;}
bool isEmpty() {return top == 0;}
bool isFull() {return top == capacity;}
void push(T x) {
if (isFull()) throw overflow_error("cannot push on full stack");
data[top++] = x;
}
T pop() {
if (isEmpty()) throw underflow_error("cannot pop from empty stack");
return data[--top];
}
T peek() {
if (isEmpty()) throw underflow_error("cannot peek into empty stack");
return data[top - 1];
}
// Prohibit copying and assignment
private:
Stack(Stack&);
Stack& operator=(Stack&);
};
#endif
// ---------------------------------------------------------------------------
// testboundedstack.cpp
//
// A test script for the SimpleBoundedStack class.
// ---------------------------------------------------------------------------
#include <iostream>
#include <cassert>
#include <cmath>
#include <stdexcept>
using namespace std;
#include "SimpleBoundedStack.h"
int main(int argc, char** argv) {
// Test that the default stack has capacity 256, is created empty,
// fills after 256, and overflow_errors are thrown correctly.
Stack<char> s1;
assert(s1.isEmpty() && !s1.isFull() && s1.getSize() == 0);
for (int i = 0; i < 256; i++) {
s1.push('*');
}
assert(!s1.isEmpty() && s1.isFull());
bool overflowHappened = false;
try {
s1.push('@');
}
catch (overflow_error e) {
overflowHappened = true;
}
assert(overflowHappened);
// Test an integer stack of capacity 8 for empty, full, and that
// pushing then popping produces predicatble (LIFO) results.
const int capacity = 8;
Stack<int> s2(capacity);
assert(s2.isEmpty() && !s2.isFull());
s2.push(0);
assert(!s2.isEmpty() && !s2.isFull() && s2.getSize() == 1);
for (int i = 1; i < capacity; i++) {
s2.push(i);
}
assert(!s2.isEmpty() && s2.isFull() && s2.getSize() == capacity);
for (int i = capacity - 1; i >= 0; i--) {
assert(s2.peek() == i);
assert(s2.pop() == i);
}
// Test underflow_errors are properly thrown on pops and peeks
// when empty. Also test that if an underflow is thrown, the stack
// is not disturbed, i.e., it remains empty.
assert(s2.isEmpty());
bool underflowHappened = false;
try {
s2.pop();
}
catch (underflow_error e) {
underflowHappened = true;
}
assert(underflowHappened);
assert(s2.isEmpty());
underflowHappened = false;
try {
s2.peek();
}
catch (underflow_error e) {
underflowHappened = true;
}
assert(underflowHappened);
cout << "All tests have passed\n";
return 0;
}