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