blob: 8ee7c9adc28bbb5b67b4ea0d07fee228fda67e2c [file] [log] [blame]
/* This is a modified version of the file "arena.c" from
"C Interfaces and Implementations", by David R. Hanson.
The license is below.
*/
/*
The author of this software is David R. Hanson.
Copyright (c) 1994,1995,1996,1997 by David R. Hanson. All Rights Reserved.
Permission to use, copy, modify, and distribute this software for any
purpose, subject to the provisions described below, without fee is
hereby granted, provided that this entire notice is included in all
copies of any software that is or includes a copy or modification of
this software and in all copies of the supporting documentation for
such software.
THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
WARRANTY. IN PARTICULAR, THE AUTHOR DOES MAKE ANY REPRESENTATION OR
WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR
ITS FITNESS FOR ANY PARTICULAR PURPOSE.
David Hanson / drh@microsoft.com / http://www.research.microsoft.com/~drh/
$Id: CPYRIGHT,v 1.2 1997/11/04 22:31:40 drh Exp $
*/
//static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/arena.doc,v 1.10 1997/02/21 19:45:19 drh Exp $";
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "basictypes.h"
//#include "assert.h"
//#include "except.h"
#include "arena.h"
#define T Arena_T
//const Except_T Arena_NewFailed =
// { "Arena Creation Failed" };
//const Except_T Arena_Failed =
// { "Arena Allocation Failed" };
#define THRESHOLD 10
struct T {
T prev;
char *avail;
char *limit;
};
union align {
#ifdef MAXALIGN
char pad[MAXALIGN];
#else
int i;
long l;
long *lp;
void *p;
void (*fp)(void);
float f;
double d;
long double ld;
#endif
};
union header {
struct T b;
union align a;
};
static T freechunks;
static int nfree;
T Arena_new(void) {
T arena = malloc(sizeof (*arena));
if (arena == NULL)
panic("Arena_NewFailed");
arena->prev = NULL;
arena->limit = arena->avail = NULL;
return arena;
}
void Arena_dispose(T *ap) {
assert(ap && *ap);
Arena_free(*ap);
free(*ap);
*ap = NULL;
}
void *Arena_alloc(T arena, long nbytes,
const char *file, int line) {
assert(arena);
assert(nbytes > 0);
nbytes = ((nbytes + sizeof (union align) - 1)/
(sizeof (union align)))*(sizeof (union align));
while (nbytes > arena->limit - arena->avail) {
T ptr;
char *limit;
if ((ptr = freechunks) != NULL) {
freechunks = freechunks->prev;
nfree--;
limit = ptr->limit;
} else {
long m = sizeof (union header) + nbytes + 10*1024;
ptr = malloc(m);
if (ptr == NULL)
{
if (file == NULL)
panic("Arena_Failed");
else
{
fprintf(stderr, "\nArena_alloc: allocation failed at %s:%d\n", file, line);
panic("Arena_alloc: allocation failed");
//Except_raise(&Arena_Failed, file, line);
}
}
limit = (char *)ptr + m;
}
*ptr = *arena;
arena->avail = (char *)((union header *)ptr + 1);
arena->limit = limit;
arena->prev = ptr;
}
arena->avail += nbytes;
return arena->avail - nbytes;
}
void *Arena_calloc(T arena, long count, long nbytes,
const char *file, int line) {
void *ptr;
assert(count > 0);
ptr = Arena_alloc(arena, count*nbytes, file, line);
memset(ptr, '\0', count*nbytes);
return ptr;
}
void Arena_free(T arena) {
assert(arena);
while (arena->prev) {
struct T tmp = *arena->prev;
if (nfree < THRESHOLD) {
arena->prev->prev = freechunks;
freechunks = arena->prev;
nfree++;
freechunks->limit = arena->limit;
} else
free(arena->prev);
*arena = tmp;
}
assert(arena->limit == NULL);
assert(arena->avail == NULL);
}