#ifndef REFSTACK_H
#define REFSTACK_H

#include <iostream>

template <typename T> class stack;

template <typename T>
std::ostream &operator<<( std::ostream &os, const stack<T> &s);

template <typename T>
class stack
{
    friend std::ostream &operator<< <>( std::ostream &os, const stack &s);
public:
           stack() : cap(ibs), sp(0), v(new T[ibs]), cnt(new int(1)) { }
           stack( const stack &other) { attach(other); }
          ~stack() { detach(); }
    stack& operator=( const stack &other);

    void   push( const T &t);
    const T &pop() { return v[--sp]; }

    bool   empty() const { return 0 == sp; }
    void  *test_address() const { return v; }
private:
    int     cap;
    int     sp;
    double *v;
    int    *cnt;

    static const int ibs = 8;
    void detach();
    void attach( const stack &other);
    void copy( const T *ov);
    void grow();
};

template <typename T>
void stack<T>::detach()
{
    // Nem thread-safe!
    if ( 0 == --*cnt )
    {
        delete cnt;
        delete [] v;
    }
}

template <typename T>
void stack<T>::attach( const stack &other)
{
    // Nem thread-safe!
    cap = other.cap;
    sp  = other.sp;
    v   = other.v;
    cnt = other.cnt;

    ++*cnt;
}

template <typename T>
stack<T>& stack<T>::operator=( const stack &other)
{
    if ( this != &other )   // x = x
    {
        detach();
        attach(other);
    }
    return *this;
}

template <typename T>
void stack<T>::push( const T &t)
{
    // Nem thread-safe!
    if ( 1 < *cnt )
    {
        --*cnt;
        if ( cap == sp )
            cap *= 2;
        copy(v);
        cnt = new int(1);
    }
    if ( cap == sp )
        grow();

    v[sp++] = t;
}

template <typename T>
void stack<T>::copy( const T *oldv)
{
    v  = new T[cap];
    for ( int i = 0 ; i < sp; ++i)
        v[i] = oldv[i];
}

template <typename T>
void stack<T>::grow()
{
    T* oldv = v;
    cap *= 2;
    copy(oldv);
    delete [] oldv;
}

template <typename T>
std::ostream &operator<<( std::ostream &os, const stack<T> &s)
{
    os << "[ ";
    for ( int i = 0; i < s.sp-1; ++i )
        os << s.v[i] << ", ";
    if ( s.sp > 0 )
        os << s.v[s.sp-1];
    os << " ]";

    return os;
}

#endif /* REFSTACK_H */