//----------------------------------------------------------------------- // // Copyright (c) SekraSoft. All rights reserved. // //----------------------------------------------------------------------- #include "alloc.h" // определения, чтобы другие файлы не страдали #define obj MCALC_ALLOC_obj #define freeobj MCALC_ALLOC_freeobj #define objsizes MCALC_ALLOC_objsizes #define objcur MCALC_ALLOC_objcur #define objfree MCALC_ALLOC_objfree #define objmax MCALC_ALLOC_objmax #define data MCALC_ALLOC_data #define cur MCALC_ALLOC_cur #define dfree MCALC_ALLOC_dfree #define max MCALC_ALLOC_max #ifdef ALLOC_DEBUG #define DBG(a) a #else #define DBG(a) #endif #ifdef ALLOC_COUNT_BALANCE long ALLOC_BALANCE = 0; #define ALLOC_BALANCE_ADD(bytes) (ALLOC_BALANCE += (bytes)) #else #define ALLOC_BALANCE_ADD(bytes) #endif void **obj = 0; // ссылки на объекты size_t *freeobj = 0; // ссылки на свободные номера объектов size_t *objsizes = 0; // размеры объектов size_t objcur = 0; // текущее положение в obj size_t objfree = 0; // свободно объектов в obj size_t objmax = 0; // размер obj int mem_locked = 0; // запрет сдвига памяти, если 1 void *data = 0; // кусок памяти size_t cur = 0; // положение в data size_t dfree = 0; // свободно в data size_t max = 0; // размер data int mem_init(size_t _objmax, size_t _max){ DBG(printf("[mem_init]\n");) if (_objmax < 2 || _max < 2) return 0; if(!(obj = (void**)malloc(_objmax * sizeof(void*)))) goto vi0; if(!(objsizes = (size_t*)malloc(_objmax * sizeof(size_t)))) goto vi1; if(!(freeobj = (size_t*)malloc(_objmax * sizeof(size_t)))) goto vi2; if(!(data = malloc(_max))) goto vi3; goto vi4; vi3: free(freeobj); vi2: free(objsizes); vi1: free(obj); vi0: return 0; vi4: objcur = 0; objfree = 0; objmax = _objmax; cur = 0; dfree = 0; max = _max; mem_locked = 0; obj[0] = data; objsizes[0] = 0; return 1; } void mem_deinit(){ DBG(printf("[mem_deinit]\n");) if (obj) free(obj); if (objsizes) free(objsizes); if (freeobj) free(freeobj); if (data) free(data); obj = 0; objsizes = 0; freeobj = 0; data = 0; objmax = 0; objfree = 0; max = 0; } int mem_optimize(){ // mem_optimize может быть оптимизирована :) static void *new_data; static size_t i; DBG(printf("[mem_optimize]\n");) if (mem_locked) return 0; new_data = malloc(max); if (!new_data) return 0; cur = 0; dfree = 0; obj[0] = new_data; for (i = 1; i <= objcur; ++i) if (objsizes[i]) { memcpy((size_t)new_data + cur, obj[i], objsizes[i]); obj[i] = (size_t)new_data + cur; cur += objsizes[i]; } free(data); data = new_data; return 1; } int mem_recycle(size_t i_want){ static void *new_data; static void **new_obj; static size_t *new_freeobj; static size_t *new_objsizes; static size_t i, objd; #ifdef _DEBUG printf ("[MEM_RECYCLE : O c%d f%d m%d M c%d f%d m%d]\n",objcur,objfree,objmax,cur,dfree,max); #endif DBG(printf("[mem_recycle ");) if (objcur + 1 >= objmax && !objfree){ // подошли к концу объектов DBG(printf("end_obj ");) objd = objmax>>1; new_obj = realloc(obj, (objmax + objd) * sizeof(void*)); if (!new_obj) goto vr0; new_objsizes = realloc(objsizes, (objmax + objd) * sizeof(size_t)); if (!new_objsizes) goto vr1; new_freeobj = realloc(freeobj, (objmax + objd) * sizeof(size_t)); if (!new_freeobj) goto vr2; obj = new_obj; objsizes = new_objsizes; freeobj = new_freeobj; objmax += objd; goto vr3; vr2: free(new_objsizes); vr1: free(new_obj); vr0: DBG(printf("error]\n");) return 0; } vr3: if (cur + i_want >= max){ // подошли к концу памяти DBG(printf("end_mem ");) objd = max>>1; if (dfree > (i_want ? objd : i_want)) { // велика фрагментация DBG(printf("fragmentation >\n");) mem_optimize(); } else { // недостаточно свободной памяти DBG(printf("!end_mem ");) if (mem_locked) { DBG(printf("mem_locked]\n");) return 0; } new_data = malloc(max + i_want + objd); if (!new_data){ DBG(printf("error]\n");) return 0; } max += i_want + objd; cur = 0; dfree = 0; obj[0] = new_data; for (i = 1; i <= objcur; ++i) if (objsizes[i]) { memcpy((size_t)new_data + cur, obj[i], objsizes[i]); obj[i] = (size_t)new_data + cur; cur += objsizes[i]; } free(data); data = new_data; DBG(printf("ok]\n");) return 1; } } return 1; } size_t mem_alloc(size_t vsize){ static size_t c; DBG(printf("[mem_alloc %db ", vsize);) if (cur + vsize > max){ DBG(printf("end_mem >\n")); if(!mem_recycle(vsize)) { DBG(printf("= objmax){ --objcur; DBG(printf("end_obj >\n");) if (mem_recycle(0)) goto ma; else{ DBG(printf("= vsize) { dfree += objsizes[handle] - vsize; ALLOC_BALANCE_ADD( -(objsizes[handle] - vsize)); objsizes[handle] = vsize; DBG(printf("truncate]\n");) return 1; } if (cur + vsize > max && !mem_recycle(vsize)){ DBG(printf("recycle nomem]\n");) return 0; } dfree += objsizes[handle]; memcpy((size_t)data + cur, obj[handle], objsizes[handle]); objsizes[handle] = vsize; ALLOC_BALANCE_ADD(vsize); obj[handle] = (size_t)data + cur; cur += vsize; DBG(printf("add]\n");) return 1; } size_t mem_free(size_t handle){ DBG( printf("[mem_free handle=%d ", handle); if (handle > objcur) { DBG(printf("bad_handle]\n");) return; } ) ALLOC_BALANCE_ADD(-objsizes[handle]); dfree += objsizes[handle]; freeobj[objfree] = handle; ++objfree; DBG(if(objsizes[handle] == 0) { printf("already_empty]\n");} printf("ok]\n"); ) objsizes[handle] = 0; } size_t mem_assign(void*pointer){ static size_t c; DBG(printf("[mem_assign %h ", pointer);) if (objfree){ c = freeobj[--objfree]; objsizes[c] = 0; obj[c] = pointer; DBG(printf("free handle=%d]\n",c);) return c; } ma: ++objcur; if (objcur >= objmax){ --objcur; DBG(printf("end_obj >\n");) if (mem_recycle(0)) goto ma; else{ DBG(printf(" objcur) { DBG(printf("bad_handle]\n");) return; } ) freeobj[objfree] = handle; ++objfree; DBG(printf("ok]\n");) }