/* ----------------------------------------------------------------------------- 
 * memory.c
 *
 *     This file implements all of DOH's memory management including allocation
 *     of objects and checking of objects.
 * 
 * Author(s) : David Beazley (beazley@cs.uchicago.edu)
 *
 * Copyright (C) 1999-2000.  The University of Chicago
 * See the file LICENSE for information on usage and redistribution.	
 * ----------------------------------------------------------------------------- */

static char cvsroot[] = "$Header: /cvsroot/swill/SWILL/Source/Objects/memory.c,v 1.2 2006/12/22 14:37:37 gonzalodiethelm Exp $";

#include "dohint.h"

#ifndef DOH_POOL_SIZE
#define DOH_POOL_SIZE         512
#endif

static int   PoolSize = DOH_POOL_SIZE;

DOH    *DohNone = 0;    /* The DOH None object */

typedef struct pool {
   DohBase       *ptr;            /* Start of pool */
   int            len;            /* Length of pool */
   int            blen;           /* Byte length of pool */
   int            current;        /* Current position for next allocation */
   struct  pool  *next;           /* Next pool */
} Pool;

static DohBase  *FreeList = 0;          /* List of free objects */
static Pool    *Pools = 0;
static int      pools_initialized = 0;

/* ----------------------------------------------------------------------
 * CreatePool() - Create a new memory pool 
 * ---------------------------------------------------------------------- */

static void
CreatePool() {
   Pool *p = 0;
   p = (Pool *) DohMalloc(sizeof(Pool));
   assert(p);
   p->ptr = (DohBase *) DohMalloc(sizeof(DohBase)*PoolSize);
   assert(p->ptr);
   p->len = PoolSize;
   p->blen = PoolSize*sizeof(DohBase);
   p->current = 0;
   p->next = Pools;
   Pools = p;
}

/* ----------------------------------------------------------------------
 * InitPools() - Initialize the memory allocator
 * ---------------------------------------------------------------------- */

static void 
InitPools() {
   if (pools_initialized) return;
   CreatePool();                       /* Create initial pool */
   pools_initialized = 1;
   DohNone = NewVoid(0,0);             /* Create the None object */
   DohIntern(DohNone);
}

/* ----------------------------------------------------------------------
 * DohCheck()
 *
 * Returns 1 if an arbitrary pointer is a DOH object.
 * ---------------------------------------------------------------------- */

int 
DohCheck(const DOH *ptr) {
   Pool *p = Pools;
   register char *cptr = (char *) ptr;
   register char *pptr;
   while (p) {
      pptr = (char *) p->ptr;
      if ((cptr >= pptr) && (cptr < (pptr + p->blen))) return 1;
      /*
	pptr = (char *) p->ptr;
	if ((cptr >= pptr) && (cptr < (pptr+(p->current*sizeof(DohBase))))) return 1; */
      p = p->next;
   }
   return 0;
}

/* -----------------------------------------------------------------------------
 * DohIntern()
 * ----------------------------------------------------------------------------- */

void
DohIntern(DOH *obj) {
   DohBase *b = (DohBase *) obj;
   b->flag_intern = 1;
}

/* ----------------------------------------------------------------------
 * DohObjMalloc()
 *
 * Allocate memory for a new object.
 * ---------------------------------------------------------------------- */

DOH *
DohObjMalloc(DohObjInfo *type, void *data) {
   DohBase *obj;
   if (!pools_initialized) InitPools();
   if (FreeList) {
      obj = FreeList;
      FreeList = (DohBase *) obj->data;
   } else {
      while (Pools->current == Pools->len) {
	 PoolSize *= 2;
	 CreatePool();
      }
      obj = Pools->ptr + Pools->current;
      Pools->current++;
   }
   obj->type = type;
   obj->data = data;
   obj->meta = 0;
   obj->refcount = 1;
   obj->flag_intern = 0;
   obj->flag_marked = 0;
   return (DOH *) obj;
}

/* ----------------------------------------------------------------------
 * DohObjFree() - Free a DOH object
 * ---------------------------------------------------------------------- */

void 
DohObjFree(DOH *ptr) {
   DohBase  *b;
   b = (DohBase *) ptr;
   if (b->flag_intern) return;
   b->data = (void *) FreeList;
   if (b->meta) {
      Delete(b->meta);
      b->meta = 0;
   }
   b->type = 0;
   FreeList = b;
}

