/* Copyright (c) 1991-2002 Doshita Lab. Speech Group, Kyoto University */
/* Copyright (c) 2000-2002 Speech and Acoustics Processing Lab., NAIST */
/*   All rights reserved   */

/* mybmalloc.c ---  malloc by large segment */
/* this will help when huge number of small memories will be allocated for
   LM and AM */

/* !!! NOTIVE !!! you CANNOT FREET the memories allocated by these functions */

/* $Id: mybmalloc.c,v 1.4 2002/09/11 22:01:50 ri Exp $ */


#undef DEBUG			/* output debug message */

#include <sent/stddefs.h>

static boolean initialized = FALSE;
static char *current, *nowp, *endp;
static unsigned int blocksize;
static int align;
static unsigned int align_mask;


/* set block size and memory alignment factor */
void
mybmalloc_set_param()
{
  long pagesize, blockpagenum;

  /* block size should be rounded up by page size */
  pagesize = getpagesize();
  blockpagenum = (MYBMALLOC_BLOCK_SIZE + (pagesize - 1)) / pagesize;
  blocksize = pagesize * blockpagenum;

  /* alignment by a word (= pointer size?) */
#ifdef NO_ALIGN_DOUBLE
  align = sizeof(void *);
#else
  /* better for floating points */
  align = sizeof(double);
#endif
  align_mask = ~(align - 1);	/* assume power or 2 */
#ifdef DEBUG
  j_printerr("pagesize=%d blocksize=%d align=%d (bytes)\n", (int)pagesize, blocksize, align);
#endif
  
  initialized = TRUE;
}

/* malloc specified size and return the pointer */
void *
mybmalloc(int size)
{
  void *allocated;
  if (!initialized) mybmalloc_set_param();  /* initialize if not yet */
  /* malloc segment should be aligned to a word boundary */
  size = (size + align - 1) & align_mask;
  if (!current || nowp + size >= endp) {
    if (size > blocksize) {
      /* large block, fall to normal malloc */
      return(mymalloc(size));
    }
    /* allocate next block */
    current = (char *)mymalloc(blocksize);
    endp = current + blocksize;
    nowp = current;
  }
  /* return current pointer */
  allocated = nowp;
  nowp += size;
  return(allocated);
}

/* duplicate string using mybmalloc */
char *
mybstrdup(char *s)
{
  char *allocated;
  int size = strlen(s) + 1;
  allocated = mybmalloc(size);
  memcpy(allocated, s, size);
  return(allocated);
}

/* new block malloc: keep base pointers on outside to enable free later */
void *
mybmalloc2(int size, BMALLOC_BASE **list)
{
  void *allocated;
  BMALLOC_BASE *new;
  if (!initialized) mybmalloc_set_param();  /* initialize if not yet */
  /* malloc segment should be aligned to a word boundary */
  size = (size + align - 1) & align_mask;
  if (*list == NULL || (*list)->now + size >= (*list)->end) {
    new = (BMALLOC_BASE *)mymalloc(sizeof(BMALLOC_BASE));
    if (size > blocksize) {
      /* large block, allocate a whole block */
      new->base = mymalloc(size);
      new->end = (char *)new->base + size;
    } else {
      /* allocate per blocksize */
      new->base = mymalloc(blocksize);
      new->end = (char *)new->base + blocksize;
    }
    new->now = (char *)new->base;
    new->next = (*list);
    *list = new;
  }
  /* return current pointer */
  allocated = (*list)->now;
  (*list)->now += size;
  return(allocated);
}

/* free all base pointer */
void
mybfree2(BMALLOC_BASE **list)
{
  BMALLOC_BASE *b, *btmp;
  b = *list;
  while (b) {
    btmp = b->next;
    free(b->base);
    free(b);
    b = btmp;
  }
  *list = NULL;
}
