#include "BSprivate.h"
/*
Space management routines
*/
/*
Allocator for large numbers of small blocks of equal size:
Data is double alligned, as is expected by most routines.
Data structure:
A list of blocks.
*/
typedef struct __BSMBlock {
int base_size;
int num_units;
double *top, *bottom; /* bounds of memory for this block */
/* used for free'ing quickly */
struct __BSMBlock *next; /* Pointer to next BSMBlock */
double *free_blocks;
int num_allocated;
double v; /* Dummy for top */
} BSMBlock;
/*
Create a new block of base_size in size
*/
BSMBlock *BSsbinit(long base_size, int num_units)
{
BSMBlock *B;
double *tmp, *oldtmp;
double **ptr;
int true_base_size, test_size, true_size;
int i;
true_base_size = (base_size + sizeof(double) - 1) / sizeof(double);
/* double aligned */
true_base_size++; /* account for next pointers */
/* try to find the next highest power of two */
test_size = (num_units*true_base_size)*sizeof(double) + sizeof(BSMBlock);
true_size = sizeof(double);
while (true_size-1 < test_size) {
true_size *= 2;
}
true_size--;
num_units = (true_size - sizeof(BSMBlock)) / sizeof(double);
num_units /= true_base_size;
MY_MALLOCN(B,(BSMBlock *),true_size,1);
B->base_size = base_size;
B->num_units = num_units;
B->top = &B->v;
B->bottom = &(B->top[num_units*true_base_size]);
B->num_allocated = 0;
B->next = NULL;
/* set up the free list */
tmp = B->top;
B->free_blocks = tmp;
oldtmp = tmp;
for (i=1;i<num_units;i++) {
tmp += true_base_size;
ptr = (double **) oldtmp;
ptr[0] = tmp; /* set next of previous ptr to current */
oldtmp = tmp;
}
ptr = (double **) tmp;
ptr[0] = NULL;
return(B);
}
double *BSsbmalloc(BSMBlock **B )
{
double *p;
BSMBlock *BB = *B;
BSMBlock *tmp_next, *prev;
double **ptr;
int found;
/* Find a block with free space, or create one */
found = 0;
prev = NULL;
while ((BB != NULL) && (!found)) {
if (BB->free_blocks != NULL) {
found = 1;
} else {
prev = BB;
BB = BB->next;
}
}
if (found == 0) {
BB = (*B);
/* get new block */
(*B) = BSsbinit( BB->base_size, BB->num_units*2 ); CHKERRN(0);
if ((*B) == NULL) return(NULL);
(*B)->next = BB;
BB = (*B);
} else if (BB != (*B)) {
tmp_next = BB->next;
BB->next = (*B);
prev->next = tmp_next;
(*B) = BB;
}
BB->num_allocated++;
ptr = (double **) BB->free_blocks;
p = &(BB->free_blocks[1]);
BB->free_blocks = ptr[0];
return(p);
}
/*
Free a block allocated with sbmalloc
*/
void BSsbfree(double *p, BSMBlock **B)
{
BSMBlock *t, *prev;
double **ptr;
prev= NULL;
t = *B;
while (t != NULL) {
/* is p in this block ? */
if (p >= t->top && p< t->bottom) {
t->num_allocated--;
ptr = (double **) (p - 1);
ptr[0] = t->free_blocks;
t->free_blocks = (double *) ptr;
/* we don't free the main blocks, that is done when BSmem_clean */
/* is called to clean all the blocks up */
/* move this block to the front */
if (prev != NULL) {
prev->next = t->next;
t->next = (*B);
(*B) = t;
}
return;
}
prev = t;
t = (BSMBlock *)t->next;
}
MY_SETERRC(MEM_ERROR,"Bad free, could not find block\n");
}
void BSmem_clean(BSMBlock **B)
{
BSMBlock *cur, *prev;
cur = *B;
while (cur != NULL) {
prev = cur;
cur = cur->next;
MY_FREE(prev);
}
(*B) = NULL;
}
syntax highlighted by Code2HTML, v. 0.9.1