#ifndef STACK_H
#define STACK_H

#include <iostream>

template <class T>
class stack
{
    friend std::ostream &operator<< <> ( std::ostream &os, stack s);
public:
//    class Error { };
//    class Empty : public Error { };
//    class Full  : public Error { };

        stack( int size = 128);
        stack( const stack &rhs);    
        ~stack();                      
    const stack& operator=( const stack &rhs);

    void  push( T d);
    T     pop();

    bool is_empty() const;
    bool is_full()  const;
private:
    int    capacity;
    int    sp;
    T      *v;

    void copy( const stack &other); 
};


template <class T>
stack<T>::stack( int size)
{
    v = new T[capacity = size];
    sp = 0;
}
template <class T>
stack<T>::stack( const stack &other)    
{
    copy(other);   
}
template <class T>
stack<T>::~stack()                     
{
    delete [] v;
}
template <class T>
const stack<T>& stack<T>::operator=( const stack &other) 
{
    if ( this != &other )
    {
        delete [] v;
        copy(other);
    }
    return *this;
}
template <class T>
void stack<T>::copy( const stack &other)
{
    v = new T[capacity = other.capacity];
    sp = other.sp;

    for ( int i = 0 ; i < sp; ++i)
        v[i] = other.v[i];
}
template <class T>
void stack<T>::push( T d) // throws (Full)
{
    if ( ! is_full() )
        v[sp++] = d;
//    else
//        throw Full();
}
template <class T>
T stack<T>::pop() // throws (Empty)
{
    if ( ! is_empty() ) 
        v[--sp];
    else
        return T();
//    else        
//        throw Empty();
}
template <class T>
bool stack<T>::is_empty() const
{
    return 0 == sp;
}
template <class T>
bool stack<T>::is_full() const
{
    return capacity == sp;
}
template <class T>
std::ostream &operator<<( std::ostream &os, stack<T> ds)
{
    os << "[ ";
    for ( int i = 0; i < ds.sp-1; ++i )
        os << ds.v[i] << ", ";
    if ( ds.sp > 0 )
        os << ds.v[ds.sp-1];
    os << " ]";
    return os;
}

#endif /* STACK_H */