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;imaxchunks; 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!"); }