/** * BME_Mem.c jan 2007 * * BMesh memory allocator * * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $ * * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. The Blender * Foundation also sells licenses for use in proprietary software under * the Blender License. See http://www.blender.org/BL/ for information * about this. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2004 Blender Foundation. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): Geoffrey Bantle. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #include "MEM_guardedalloc.h" #include "DNA_listBase.h" #include "BKE_utildefines.h" #include "BLI_blenlib.h" 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 eize, csize, pchunk; /*size of elements and chunks in bytes and number of elements per chunk*/ }BME_mempool; static void bmempool_alloc_internal(BME_mempool *pool, int index){ int i, *flags, offset, mask, *free; char *data; free = (int*)(pool->chunks[index]); data = (char*)free++; 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--; return &data[pool->esize*i]; } } } 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->maxchunk+total), "memory pool chunk pointer array"); pool->flags = MEM_callocN(sizeof(void*)*(pool->maxchunk+total), "memory pool flag pointer array"); memcpy(pool->chunks, oldchunks, sizeof(void*) * pool->maxchunk); memcpy(pool->flags, oldflags, sizeof(int*) * pool->maxchunk); for(i=pool->maxchunk; i < pool->maxchunk + total; i++) bmempool_alloc_chunk_internal(pool,i); pool->maxchunk+=total; MEM_freeN(oldchunks); MEM_freeN(oldflags); } static void bmempool_alloc_chunk_internal(BME_mempool *pool, int index){ pool->chunks[index] = MEM_mallocN(sizeof(int) + pool->csize, "memory pool chunk"); pool->flags[index] = MEM_callocN(sizeof(int) * (pool->pchunk / 32); *((int*)(pool->chunks[i])) = pool->pchunk; } BME_mempool *BME_mempool_create(int esize, int tote, int pchunk) { BME_mempool *pool = NULL; int i; pool = MEM_callocN(sizeof(BME_mempool),"memory pool"); pool->esize = esize; pool->pchunk = pchunk; pool->csize = esize * pchunk; pool->maxchunk = tote / pchunk; /*allocate pointer arrays*/ pool->chunks = MEM_mallocN(sizeof(void*)*pool->maxchunk, "memory pool chunk pointer array"); pool->flags = MEM_mallocN(sizeof(void*)*pool->maxchunk, "memory pool flag pointer array"); /*allocate the actual chunks*/ for(i=0; i < pool->maxchunk; i++) bmempool_alloc_chunk_internal(pool, i); return pool; } void BME_mempool_destroy(BME_mempool *pool) { for(i=0; i < pool->maxchunk; 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){ return bmempool_alloc_internal(pool, i); } } } /*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->elemsize * pool->pchunk); if( address >= firstbyte && 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 = (address - firstbyte) / pool->esize; offset = elemindex / 32; mask = (1 << (elemindex % 32)); flags[offset] &= ~mask; *free--; } 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, i, address); } }