#include "c.h"
#define ALLOCSIZE 64*1024
struct block {
	struct block *next;
	char *limit;
	char *avail;
};
union align {
	long l;
	char *p;
	double d;
	int (*f) ARGS((void));
};
union header {
	struct block b;
	union align a;
};
#ifdef PURIFY
union header *arena[4];

void *allocate(n, a) unsigned long n, a; {
	union header *new = malloc(sizeof *new + n);

	assert(a < NELEMS(arena));
	if (new == NULL) {
		error("insufficient memory\n");
		exit(1);
	}
	new->b.next = (void *)arena[a];
	arena[a] = new;
	return new + 1;
}

void deallocate(a) unsigned a; {
	union header *p, *q;

	assert(a < NELEMS(arena));
	for (p = arena[a]; p; p = q) {
		q = (void *)p->b.next;
		free(p);
	}
	arena[a] = NULL;
}

void *newarray(m, n, a) unsigned long m, n; unsigned a; {
	return allocate(m*n, a);
}
#else
#ifndef ASM_LIB
static
#endif
struct block
	 first[] = {  { NULL },  { NULL },  { NULL },{NULL},{NULL} },
	*arena[] = { &first[0], &first[1], &first[2],&first[3],&first[4]};
static struct block *freeblocks;
int memused=0;
void *allocateslow(register unsigned long n, unsigned a);
#ifndef ASM_LIB
void *allocate(unsigned long n,unsigned a)
{
	struct block *ap;
	void *r=NULL;
	ap = arena[a];
	n = roundup(n, sizeof (union align));
	if (ap->avail + n <= ap->limit) {
		r = ap->avail;
		ap->avail += n;
		return r;
	}
	else
	return allocateslow(n,a);
}
#else
extern void *allocate(unsigned long n,unsigned a);
#endif
void *allocateslow(register unsigned long n, unsigned a)
{
	register struct block *ap;

//	assert(a < NELEMS(arena));
//	assert(n > 0);
	ap = arena[a];
//	n = roundup(n, sizeof (union align));
	while (ap->avail + n > ap->limit) {
		if ((ap->next = freeblocks) != NULL) {
			freeblocks = freeblocks->next;
			ap = ap->next;
		} else
			{
				ap->next = malloc(ALLOCSIZE);
				ap = ap->next;
				if (ap == NULL) {
					error("insufficient memory\n");
					exit(1);
				}
				ap->limit = (char *)ap + ALLOCSIZE;
				memused += ALLOCSIZE;
			}
		ap->avail = (char *)((union header *)ap + 1);
		ap->next = NULL;
		arena[a] = ap;

	}
	ap->avail += n;
	return ap->avail - n;
}

void *newarray(unsigned long m,unsigned long n,unsigned a)
{
	return allocate(m*n, a);
}
void deallocate(unsigned a) 
{
	assert(a < NELEMS(arena));
	arena[a]->next = freeblocks;
	freeblocks = first[a].next;
	first[a].next = NULL;
	arena[a] = &first[a];
}
#endif
