// Copyright 1994 by Jon Dart.  All Rights Reserved.

#include "stdafx.h"
#include "pool.h"

Pool::Pool()
{
   memChain = freeChunks = NULL;
   nextMem = NULL;
   freeChain = NULL;
#ifdef _WINDOWS
   InitializeCriticalSection(&memCriticalSection);
#endif
}

Pool::~Pool()
{
#ifdef _WINDOWS
   DeleteCriticalSection(&memCriticalSection);
#endif
}

void *Pool::allocate( size_t size )
{
#ifdef _WINDOWS
    EnterCriticalSection(&memCriticalSection);
#endif
    if (!freeChain)
    {
        // allow room for "next" pointer
        size += sizeof(void*);
        // align it
        if (size % 4) size += (4 - (size % 4));
        if (!memChain || 
            size >= (int)BLOCK_SIZE - (nextMem - memChain->blk->mem))
                                
        {
           chunk *newChunk;
           if (freeChunks)
           {
                newChunk = freeChunks;
                freeChunks = freeChunks->next;
           }
           else
           {
                 newChunk = new chunk;
#ifdef _WINDOWS
                 HGLOBAL hNewMem = ::GlobalAlloc(GMEM_MOVEABLE,sizeof(block));
                 newChunk->blk = (block_ptr)GlobalLock(hNewMem);
                 newChunk->blk->hMem = hNewMem;
#else                 
                 newChunk->blk = new block;
#endif                 
           }
           newChunk->next = memChain;
           memChain = newChunk;
           nextMem = newChunk->blk->mem;
        }

        alloc_ptr p = (alloc_ptr)nextMem;
        nextMem += size;
        p->next = NULL;
#ifdef _WINDOWS
        LeaveCriticalSection(&memCriticalSection);
#endif
        return &(p->mem);
    }
    else
    {
        alloc_ptr aFreeAlloc = freeChain;
        freeChain = aFreeAlloc->next;
#ifdef _WINDOWS
        LeaveCriticalSection(&memCriticalSection);
#endif
        return &(aFreeAlloc->mem);
    }
}

void Pool::free( void *p )
{
#ifdef _WINDOWS
    EnterCriticalSection(&memCriticalSection);
#endif
    alloc_ptr q = (alloc_ptr)((char*)p-sizeof(void*));
    q->next = freeChain;
    freeChain = q;
#ifdef _WINDOWS
    LeaveCriticalSection(&memCriticalSection);
#endif
}

void Pool::freeAll(BOOL final)
{
#ifdef _WINDOWS
    EnterCriticalSection(&memCriticalSection);
#endif
    if (final)
    {
       // delete free chunks
       chunk *c = freeChunks;
       while (c)
       {
          chunk *nxt = c->next;
#ifdef _WINDOWS          
          HGLOBAL hMem = c->blk->hMem;
          GlobalUnlock(hMem);
          GlobalFree(hMem);
#else
          delete [] c->blk;
#endif          
          delete c;
          c = nxt;
       }
    }
    chunk *c = memChain;
    while(c)
    {
        chunk *nxt = c->next;
        if (final)
        {
#ifdef _WINDOWS          
          HGLOBAL hMem = c->blk->hMem;
          GlobalUnlock(hMem);
          GlobalFree(hMem);
#else
           delete [] c->blk;
#endif           
           delete c;
        }
        else
        {
           c->next = freeChunks;
           freeChunks = c;
        }
        c = nxt;
    }
    memChain = NULL;
    nextMem = NULL;
    freeChain = NULL;
    if (final)
        freeChunks = NULL;
#ifdef _WINDOWS
    LeaveCriticalSection(&memCriticalSection);
#endif
}
