/*
 $Id: alloc.c,v 1.1 1996/10/10 10:01:08 roitzsch Exp $
 (C)opyright 1996 by Konrad-Zuse-Center, Berlin
 All rights reserved.
 Part of the Kaskade distribution
*/

#include "utils.h"
#include "alloc.h"

template<class T>  StaticAllocator<T>:: StaticAllocator(int maxElementsInBlock0)

	: returnedElements(1,10)
{ 
    if (maxElementsInBlock0 < 1)
    {
	cout << "\n*** Allocator: maxElementsInBlock must be > 1\n"
	     << "\t (read: " << maxElementsInBlock << ")\n";
	cout.flush(); abort();
    }

    maxElementsInBlock  = maxElementsInBlock0; 
    noOfElementsInBlock = maxElementsInBlock0;
    lastBlock = 0;

    noOfBlocks  = 0;
    freeElement = 0;
    noOfBlocksSinceIncrement = 0;
    memSpace = 0;
}
//-------------------------------------------------------------------------

template<class T> int StaticAllocator<T>:: MemSpace()  const
{ 
    return memSpace + returnedElements.memSpace();
}
//-------------------------------------------------------------------------

template<class T> void StaticAllocator<T>:: Info() const
{ 
    cout << "\n\tAllocator: " << noOfBlocks << " blocks (" 
	    	<< Form("%1.6f MB)", float(MemSpace())/1e6)
		<< "  on stack: " << returnedElements.high() << "\n";
}
//-------------------------------------------------------------------------

template<class T> T* StaticAllocator<T>:: Get()
{
    T* elem;

    if (returnedElements.h == 0) elem = getFromBlock();
    else  			 elem = returnedElements.pop();
    return elem;
}
//-------------------------------------------------------------------------


template<class T> T* StaticAllocator<T>:: getFromBlock()
{
    ++noOfElementsInBlock;
    ++freeElement;

    if (noOfElementsInBlock > maxElementsInBlock) 
    {
	if (noOfBlocksSinceIncrement > 100) 	// dynamic size extension
	{
	    maxElementsInBlock *= 2;
	    noOfBlocksSinceIncrement = 0;
	}

	MemoryBlock* newBlock = ::new MemoryBlock;
	if (newBlock == 0) allocationError();

	newBlock->space = ::new T[maxElementsInBlock];  
	if (newBlock->space == 0) allocationError();

	newBlock->next = lastBlock;
	lastBlock = newBlock;

	++noOfBlocks;
	++noOfBlocksSinceIncrement;
	memSpace += maxElementsInBlock*sizeof(T) + sizeof(MemoryBlock);

	noOfElementsInBlock = 1;
	freeElement = newBlock->space;

    }
    return freeElement;
}
//-------------------------------------------------------------------------

template<class T> void StaticAllocator<T>:: allocationError()
{
    cout << "\n*** Allocator: could not allocate MemoryBlock\n";
    cout.flush(); abort();
}
//-------------------------------------------------------------------------

template<class T> Allocator<T>:: ~Allocator()
{ 
    MemoryBlock* toDel;

    while(lastBlock)
    {
	toDel = lastBlock;
	lastBlock = lastBlock->next;
	delete [] toDel->space;
	delete toDel;
    }

    int i;
    FORALL(returnedElements,i) returnedElements[i] = 0;
}
//-------------------------------------------------------------------------


template<class T> T* Allocator<T>:: Get()
{
    T* elem;

    if (returnedElements.h == 0) elem = getFromBlock();
    else 
    { 
	elem = returnedElements.pop(); 
	elem->reset(); 
    }
    return elem;
}
