#include "pilha_int.H"
#include <new>
/* O construtor por cópia tem de construir uma matriz dinâmica própria
para guardar cópias dos itens da pilha original. Por uma questão de
simplicidade escolhe-se uma capacidade idêntica à da pilha original,
embora qualquer capacidade não-inferior ao nóero de itens da pilha
original bastasse. */
PilhaInt::PilhaInt(PilhaInt const& outra_pilha)
: capacidade(outra_pilha.capacidade),
itens(new Item[capacidade]),
numero_de_itens(outra_pilha.numero_de_itens)
{
/* Depois de inicializados quer a capacidade quer o número de
itens e depois de construída a matriz dinâmica, é necessário
copiar os itens um a um entre a pilha original e a pilha
construída. */
for(int i = 0; i != numero_de_itens; ++i)
itens[i] = outra_pilha.itens[i];
assert(cumpreInvariante());
}
/* O operador de atribuição por cópia tem duas verificações. A
primeira verifica se por acaso não se trata de uma auto-atribuição,
em que a instância implícita é idêntica (é a mesma variável) que a
pilha modelo passada como argumento por referência.
Sem este teste o operador teria o trabalho de copiar os itens para
eles próprios na matriz dinâmcia, o que é uma tarefa inútil.
A segunda verificação serve para reciclar a matriz dinâmica quando
tal for possível. Tal como o cirurgião plástico reciclará (i.e.,
deixará em paz) um nariz com as características desejadas.
É um exercício interessante verificar o que aconteceria se se
fizesse uma auto-atribuição e não existisse nenhuma das
verificações... */
PilhaInt& PilhaInt::operator = (PilhaInt const& outra_pilha)
{
assert(cumpreInvariante() and outra_pilha.cumpreInvariante());
if(this != &outra_pilha) {
if(capacidade != outra_pilha.capacidade) {
capacidade = outra_pilha.capacidade;
delete[] itens;
itens = new Item[capacidade];
}
numero_de_itens = outra_pilha.numero_de_itens;
for(int i = 0; i != numero_de_itens; ++i)
itens[i] = outra_pilha.itens[i];
}
return *this;
assert(cumpreInvariante());
}
/* O ideal seria criar um método privado para aumentar a matriz
dinâmica e chamá-lo na instrução de selecção. Nesse caso o
procedimento poe() passaria a em-linha (inline). */
void PilhaInt::poe(Item const& novo_item)
{
assert(cumpreInvariante());
if(numero_de_itens == capacidade) {
try {
Item* const novos_itens = new Item[capacidade * 2];
capacidade *= 2;
for(int i = 0; i != altura(); ++i)
novos_itens[i] = itens[i];
delete[] itens;
itens = novos_itens;
} catch(std::bad_alloc) {
throw MemoriaEsgotada(capacidade * 2);
}
}
itens[numero_de_itens++] = novo_item;
assert(cumpreInvariante());
}
#ifdef TESTE
#include <iostream>
using namespace std;
#define erro(msg) {cout << __FILE__ << ':' << __LINE__ << ": " << (msg) \
<< endl; \
ocorreu_erro = true; }
int main()
{
bool ocorreu_erro = false;
cout << "Iniciando testes da classe PilhaInt..." << endl;
PilhaInt pilha;
// Coloca 10000 valores na pilha:
for(int i = 0; i != 10000; ++i)
pilha.poe(i);
// Retira 10000 valores na pilha:
for(int i = 9999; i != -1; --i) {
if(pilha.topo() != i)
erro("pilha.topo() devia ser i.");
pilha.tira();
}
// Coloca 10000 valores na pilha:
for(int i = 0; i != 10000; ++i)
pilha.poe(i);
if(pilha.altura() != 10000)
erro("pilha.altura() devia ser 10000.");
PilhaInt copia = pilha;
if(copia.altura() != pilha.altura())
erro("copia.altura() devia ser igual a pilha.altura().");
PilhaInt nova;
nova = pilha;
if(nova.altura() != pilha.altura())
erro("nova.altura() devia ser igual a pilha.altura().");
PilhaInt outra = pilha;
while(not pilha.estaVazia()) {
if(pilha.topo() != outra.topo())
erro("pilha.topo() devia ser igual a outra.topo()");
pilha.tira();
outra.tira();
}
if(pilha.altura() != outra.altura())
erro("pilha.altura() devia ser igual a outra.altura().");
if(pilha.altura() != 0)
erro("pilha.altura() devia ser 0.");
while(not copia.estaVazia()) {
if(copia.topo() != nova.topo())
erro("copia.topo() devia ser igual a nova.topo()");
copia.tira();
nova.tira();
}
if(copia.altura() != nova.altura())
erro("copia.altura() devia ser igual a nova.altura().");
if(copia.altura() != 0)
erro("copia.altura() devia ser 0.");
cout << "Teste finalizados..." << endl;
return ocorreu_erro? 1 : 0;
}
#endif // TESTE