#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <yafl_usr.h>
#include <yafl_rnt.h>

typedef struct { 
                 char data[YMALLOC_ITEMS_PER_PAGE * YMALLOC_THRESHOLD];
               } PAGE;
               
typedef PAGE * PPAGE;               

static PPAGE page[YMALLOC_MAX_PAGES] = {NULL};

static void * next_free = NULL;
static last_page = 0;

static unsigned small_allocs = 0;
static unsigned big_allocs = 0;

#define NEXT(p)  ((void*)(*(char**)p))
#define SET_NEXT(p,val)  (*((void**)p) = (void*)val)
/************************************************/
void yafl_free YPARAMS4(void*, p, int, size)
{
  assertp(p);
  assert(size > 0);
  if (size > YMALLOC_THRESHOLD)
    free (p);
   else
    {
    SET_NEXT(p, next_free);
    next_free = p;
    }
}
/************************************************/
static int alloc_page YPARAMS0
{
  int i;
  char *p;
                
  if (last_page >= YMALLOC_MAX_PAGES)
    return FALSE;
  page[last_page] = (PPAGE) malloc (sizeof(PAGE));
  if (page[last_page] == NULL)
    return FALSE;
  p = page[last_page]->data;
  for (i = 0; i < YMALLOC_ITEMS_PER_PAGE; i++)
    {
    SET_NEXT(p, next_free);
    next_free = (void*) p;
    p += YMALLOC_THRESHOLD;
    }      
  last_page ++;
  return TRUE;
}
/************************************************/
void * yafl_malloc YPARAMS2(int, size)
{
  void *p;
  static int recurse = 0;
  
  if (size > YMALLOC_THRESHOLD)
    {
    big_allocs ++;
    return (void*) malloc(size);
    }
   else
    {
    small_allocs ++;
    if (next_free)
      {
      p = next_free;
      next_free = NEXT(next_free);
      return p;
      }
     else if (alloc_page())
      {
      assert(next_free != NULL);
      p = next_free;
      next_free = NEXT(next_free);
      return p;
      }
     else 
      {
      if (recurse)
        return NULL;
       else
        {
        garbage_collect();
        recurse = TRUE;
        p = yafl_malloc(size);
        recurse = FALSE;
        return p;
        }
      }
    }
}
/*************************************************************/
void dump_mallocs YPARAMS0
{ 
  void *p;
  int i = 0; 
  char a[100];
  
  sprintf (a, "Small: %u  Bigs: %u\n", small_allocs, big_allocs);
  emit_stdout(a);
  p = next_free;
  while (p)
    {
    p = NEXT(p);
    i ++;
    }
  sprintf (a, "Pages: %d  Holes: %d\n", last_page, i);
  emit_stdout(a);
}



/*************************************************************
static unsigned yt_sizes[] = {48, 64, 128, 256, 512, 1024, 2048, 999999,
                              0};
static unsigned yt_lost[16];
static unsigned yt_used[16];

void yt_init YPARAMS0
{
  int i;
  
  for (i=0; i < 16; i++)
    yt_lost[i] = yt_used[i] = 0;
}

void yt_use YPARAMS2 (int, size)
{
  int i;
  
  for (i=0; i<16; i++)
    if (size <= yt_sizes[i])
      {
      yt_used[i] ++;
      yt_lost[i] += (yt_sizes[i] - size);
      return;
      }
}

void yt_dump YPARAMS0
{
  int i;
  
  for (i=0; i<16; i++)
    if (yt_sizes[i] > 0)
      printf ("Size: %u Count: %u Lost: %u\n", yt_sizes[i], yt_used[i],
                                                  yt_lost[i]);
     else
      return;                                                  
}
*************************************************************/



