/*
   Mass object allocator

   Daisuke Minato, s1090202@u-aizu.ac.jp
   
   LastUpdate: 2003, 20 Setember 
*/

#ifndef MINATO__TALLOCATOR_H
#define MINATO__TALLOCATOR_H

#include <stdlib.h>

template <class T>
class TAllocator {
private:
   struct sObject {
      union {
         T mObject;
         sObject* mNext;
         };
      };

   sObject** mPool;         // objects
   sObject** mActivePool;
   sObject** mPoolMax;
   
   int mSize;               // allocate size

   sObject* mFreeObject;

   static const int kFirstPoolSize = 3;

   inline void extend_pool() {
      *mActivePool = (sObject*)malloc(sizeof(sObject) * mSize);

      /// add new objects to mFreeObject ///
      sObject* p;
      const sObject* max = *mActivePool + mSize;
      for(p = *mActivePool; p < max; p++) p->mNext = p + 1;
      (p-1)->mNext = mFreeObject;
      mFreeObject = *mActivePool;
      
      mActivePool++;

      if(mActivePool >= mPoolMax) {
         const int size = mActivePool - mPool;
         mPool = (sObject**)realloc(mPool, sizeof(sObject*) * size*2);
         mPoolMax = mPool + size*2;
         mActivePool = mPool + size;
         }
      }
public:
   TAllocator(int size):mSize(size), mFreeObject(NULL) {
      mPool = (sObject**)malloc(sizeof(sObject*) * kFirstPoolSize);
      mPoolMax = mPool + kFirstPoolSize;
      
      mActivePool = mPool;
      extend_pool();
      }
   ~TAllocator() {
      for(sObject** p=mPool; p<mActivePool; p++) FREE(*p);
      free(mPool);
      }
      
   T* Allocate() {
      if(mFreeObject == NULL) { mSize *= 2; extend_pool(); }

      T* result = &mFreeObject->mObject;
      mFreeObject = mFreeObject->mNext;
      return result;
      }

   void Free(T* object) {
      ((sObject*)object)->mNext = mFreeObject;
      mFreeObject = (sObject*)object;
      }
   };

#endif
