//: C05:Nobloat.h
// Z knihy "Myslíme v jazyce C++, část 2" od Bruce Eckela a Chucka Allisona.
// (c) 1995-2004 MindView, Inc. Všechna práva vyhrazena.
// Přečtěte si podmínky používání zdrojových kódů umístěné v souboru 
// 'Licence.txt' dodávaném spolu s balíčkem kódu dostupným na www.MindView.net.
// Sdílení kódu pro ukládání ukazatelů ve třídě Stack.
#ifndef NOBLOAT_H
#define NOBLOAT_H
#include <cassert>
#include <cstddef>
#include <cstring>

// Základní šablona
template<class T> class Stack {
  T* data;
  std::size_t pocet;
  std::size_t kapacita;
  enum { INIT = 5 };
public:
  Stack() {
    pocet = 0;
    kapacita = INIT;
    data = new T[INIT];
  }
  void push(const T& t) {
    if(pocet == kapacita) {
      // Zvětšit pole pro ukládání
      std::size_t novaKapacita = 2 * kapacita;
      T* novaData = new T[novaKapacita];
      for(size_t i = 0; i < pocet; ++i)
        novaData[i] = data[i];
      delete [] data;
      data = novaData;
      kapacita = novaKapacita;
    }
    assert(pocet < kapacita);
    data[pocet++] = t;
  }
  void pop() {
    assert(pocet > 0);
    --pocet;
  }
  T top() const {
    assert(pocet > 0);
    return data[pocet-1];
  }
  std::size_t size() const { return pocet; }
};

// Úplná speciliazce pro void*
template<> class Stack<void *> {
  void** data;
  std::size_t pocet;
  std::size_t kapacita;
  enum { INIT = 5 };
public:
  Stack() {
    pocet = 0;
    kapacita = INIT;
    data = new void*[INIT];
  }
  void push(void* const & t) {
    if(pocet == kapacita) {
      std::size_t novaKapacita = 2*kapacita;
      void** novaData = new void*[novaKapacita];
      std::memcpy(novaData, data, pocet*sizeof(void*));
      delete [] data;
      data = novaData;
      kapacita = novaKapacita;
    }
    assert(pocet < kapacita);
    data[pocet++] = t;
  }
  void pop() {
    assert(pocet > 0);
    --pocet;
  }
  void* top() const {
    assert(pocet > 0);
    return data[pocet-1];
  }
  std::size_t size() const { return pocet; }
};

// Částečná specializace pro další ukazatelové typy
template<class T> class Stack<T*> : private Stack<void *> {
  typedef Stack<void *> Base;
public:
  void push(T* const & t) { Base::push(t); }
  void pop() {Base::pop();}
  T* top() const { return static_cast<T*>(Base::top()); }
  std::size_t size() { return Base::size(); }
};
#endif // NOBLOAT_H ///:~
