All pastes #995452 Raw Edit

Stuff

public text v1 · immutable
#995452 ·published 2008-04-24 05:08 UTC
rendered paste body
typedef struct BME_mempool{
	void 	**chunks;				/*pointer will be null if chunk is freed*/
	int 	**flags;				/*element freed pointer arrays. aligned to chunks*/
	int maxchunks;					/*Maximum number of chunks.*/
	int esize, csize, pchunk;		/*size of elements and chunks in bytes and number of elements per chunk*/
}BME_mempool;

static char *bmempool_alloc_internal(BME_mempool *pool, int index){
	int i, *flags, offset, mask, *free;
	char *data;
	
	free = (int*)(pool->chunks[index]);
	data = (char*)(&(free[1]));
	flags = pool->flags[index];
	for(i=0; i < pool->pchunk; i++){
		offset = i / 32; 
		mask = (1 << (i % 32));
		if(!(flags[offset] & mask)){
			flags[offset] |= mask;
			(*free)--;
			memset(&(data[pool->esize*i]), 0, pool->esize); /*clear memory*/
			return &(data[pool->esize*i]);
		}
	}
	return NULL;
}
static void bmempool_alloc_chunk_internal(BME_mempool *pool, int index){
	pool->chunks[index] = MEM_callocN(sizeof(int) + pool->csize, "memory pool chunk");
	pool->flags[index] = MEM_callocN(sizeof(int) * (pool->pchunk / 32), "memory pool flags");
	*((int*)(pool->chunks[index])) = pool->pchunk;
}
static void bmempool_grow(BME_mempool *pool, int total){
	int i;
	void **oldchunks, **oldflags;
	oldchunks = pool->chunks;
	oldflags = pool->flags;
	pool->chunks = MEM_callocN(sizeof(void*)*(pool->maxchunks+total), "memory pool chunk pointer array");
	pool->flags = MEM_callocN(sizeof(int*)*(pool->maxchunks+total), "memory pool flag pointer array");
	memcpy(pool->chunks, oldchunks, sizeof(void*) * pool->maxchunks);
	memcpy(pool->flags, oldflags, sizeof(int*) * pool->maxchunks);
	for(i=pool->maxchunks; i < (pool->maxchunks + total); i++) bmempool_alloc_chunk_internal(pool,i);
	pool->maxchunks+=total;
	MEM_freeN(oldchunks);
	MEM_freeN(oldflags);
}

/*do some arg checking here!*/
BME_mempool *BME_mempool_create(int esize, int tote, int pchunk)
{	BME_mempool  *pool = NULL;
	int i;
	
	if(tote % 32 || pchunk % 32) return NULL; //total amount of elements and elements per memory chunk must be multiples of 32!

	pool = MEM_callocN(sizeof(BME_mempool),"memory pool");
	pool->esize = esize;
	pool->pchunk = pchunk;	
	pool->csize = esize * pchunk;
	pool->maxchunks = tote / pchunk;

	/*allocate pointer arrays*/
	pool->chunks = MEM_callocN(sizeof(void*)*pool->maxchunks, "memory pool chunk pointer array");
	pool->flags = MEM_callocN(sizeof(int*)*pool->maxchunks, "memory pool flag pointer array");
	
	/*allocate the actual chunks*/
	for(i=0; i < pool->maxchunks; i++) bmempool_alloc_chunk_internal(pool, i);
	return pool;
}
void BME_mempool_destroy(BME_mempool *pool)
{
	int i;

	for(i=0; i < pool->maxchunks; i++){
		if(pool->chunks[i]){ 
			MEM_freeN(pool->chunks[i]);
			MEM_freeN(pool->flags[i]);
		}
	}
	MEM_freeN(pool->chunks);
	MEM_freeN(pool->flags);
	MEM_freeN(pool);
}
void *BME_mempool_alloc(BME_mempool *pool)
{
	int i, free;	
	/*1st test: Find a chunk with free elements*/
	for(i=0; i < pool->maxchunks; i++){
		if(pool->chunks[i]){
			free = *((int*)pool->chunks[i]);
			if(free > 0){
				return bmempool_alloc_internal(pool, i);
			}
			if(free < 0){
				printf("Warning: Corrupted free counter!");
			}
		}
	}	
	/*2nd test: Find an empty slot in chunk pointer array*/
	for(i=0; i < pool->maxchunks; i++){
		if(!pool->chunks[i]){
			bmempool_alloc_chunk_internal(pool,i);
			return bmempool_alloc_internal(pool,i);
		}
	}
	/*Final option: grow the pool by one chunk*/
	bmempool_grow(pool,1);
	return bmempool_alloc_internal(pool,pool->maxchunks-1);
}
static int bmempool_address_in_chunk(BME_mempool *pool, void *address, int index){
	char *firstbyte, *lastbyte;
	firstbyte = (char*)(&(((int*)(pool->chunks[index]))[1]));
	lastbyte = firstbyte + (pool->esize * pool->pchunk);
	if( ((char*)address) >= firstbyte && ((char*)address) < lastbyte) return 1;
	return 0;
}
static void bmempool_free_internal(BME_mempool *pool, void *address, int index){
	int elemindex, *flags = pool->flags[index], *free = (int*)(pool->chunks[index]), offset, mask;
	char *firstbyte;
	firstbyte = (char*)(&(((int*)(pool->chunks[index]))[1]));
	elemindex = (((char*)address) - firstbyte) / pool->esize;
	offset = elemindex / 32; 
	mask = (1 << (elemindex % 32));
	/*protect against double frees!*/
	if(flags[offset] & mask){
		flags[offset] &= ~mask;	
		(*free)++;
	}
	else
		printf("Warning! Attempted Double free of pooled memory element!");
	
}
void BME_mempool_free(BME_mempool *pool, void *address)
{
	int i;
	for(i=0;i<pool->maxchunks; i++){
		if(pool->chunks[i] && bmempool_address_in_chunk(pool, address, i)){
			bmempool_free_internal(pool, address, i);
			return;
		}
	}
	printf("Error: Pointer not in Pool!");
}