/*
 * bucket.c
 *
 *  Created July 13, 1990 by Raymie Stata
 *  C port September 15, 1990 by RS
 *  (c) 1990 Raymie Stata, All Rights Reserved
 */

#include <stdio.h>
#include <assert.h>
#include "bucket.h"

#define LOCAL static
#define ENTRY /* */

union bucket {
  union bucket *next;
  char data[1];
};

struct bucketstruct {
  int bucket_size, buckets_per_chunk;
  union bucket *free_list;
  union bucket *chain_list;  
};


LOCAL int myalign(s)
  int s;
{ return( (s+3)&0xfffffffc ); }

ENTRY Bucket bk_create(s)
  int s;
{
  Bucket bk = (Bucket) malloc(sizeof(struct bucketstruct));
  if (! bk) return(NULL);
  bk->bucket_size = myalign(s);
  bk->buckets_per_chunk = 512; /* Set according to machine. */
  bk->free_list = bk->chain_list = NULL;
  return(bk);
}

ENTRY Bucket bk_create2(s, c)
  int s, c;
{
  Bucket bk = (Bucket) malloc(sizeof(struct bucketstruct));
  if (! bk) return(NULL);
  bk->bucket_size = myalign(s);
  bk->buckets_per_chunk = c;
  bk->free_list = bk->chain_list = NULL;
  return(bk);
}

ENTRY int bk_destroy(bk)
  Bucket bk;
{
  union bucket *next = bk->chain_list, *old;

  while(next) { old = next; next = next->next; free(old); }
  free(bk);
  return(0);
}

ENTRY char *bk_alloc(bk)
  Bucket bk;
{
  char *tmp;
  union bucket *b;
  int i;

  if (! bk->free_list) { /* Get another chunk of chains. */
    tmp = (char *) malloc(bk->bucket_size * bk->buckets_per_chunk);
    if (! (b = (union bucket *)tmp)) return(NULL);
    b->next = bk->chain_list; bk->chain_list = b;
    tmp += bk->bucket_size;
    b = bk->free_list = (union bucket *)tmp;
    for(i = 0; i < bk->buckets_per_chunk - 2; i++) {
      tmp += bk->bucket_size;
      b->next = (union bucket *)tmp; b = b->next;
    }
    b->next = NULL;
  };

  b = bk->free_list; bk->free_list = bk->free_list->next;
  return((char *)b);
};

ENTRY int bk_free(bk, bp)
  Bucket bk;
  union bucket *bp;
{
  bp->next = bk->free_list; bk->free_list = bp;
}
