/*
** {========================================================
** Memory manipulation
*/
static const size_t _SIZEOF_4BYTES = 4;
static const size_t _SIZEOF_8BYTES = 8;
static const size_t _SIZEOF_32BYTES = 32;
static const size_t _SIZEOF_64BYTES = 64;
static const size_t _SIZEOF_128BYTES = 128;
static const size_t _SIZEOF_256BYTES = 256;
static const size_t _SIZEOF_512BYTES = 512;
typedef unsigned _pool_chunk_size_t;
typedef union _pool_tag_t {
_pool_chunk_size_t size;
void* ptr;
} _pool_tag_t;
typedef struct _pool_t {
size_t size;
char* stack;
} _pool_t;
static int pool_count = 0;
static _pool_t* pool = 0;
static long alloc_count = 0;
static long alloc_bytes = 0;
static long in_pool_count = 0;
static long in_pool_bytes = 0;
static long _POOL_THRESHOLD_COUNT = 0;
static long _POOL_THRESHOLD_BYTES = 1024 * 1024 * 32;
#define _POOL_NODE_ALLOC(size) (((char*)malloc(sizeof(_pool_tag_t) + size)) + sizeof(_pool_tag_t))
#define _POOL_NODE_PTR(s) (s - sizeof(_pool_tag_t))
#define _POOL_NODE_NEXT(s) (*((void**)(s - sizeof(_pool_tag_t))))
#define _POOL_NODE_SIZE(s) (*((_pool_chunk_size_t*)(s - sizeof(_pool_tag_t))))
#define _POOL_NODE_FREE(s) do { free(_POOL_NODE_PTR(s)); } while(0)
static int _cmp_size_t(const void* l, const void* r) {
size_t* pl = (size_t*)l;
size_t* pr = (size_t*)r;
if(*pl > *pr) return 1;
else if(*pl < *pr) return -1;
else return 0;
}
static void _tidy_mem_pool(bool_t force) {
int i = 0;
char* s = 0;
if(!force) {
if(_POOL_THRESHOLD_COUNT > 0 && in_pool_count < _POOL_THRESHOLD_COUNT)
return;
if(_POOL_THRESHOLD_BYTES > 0 && in_pool_bytes < _POOL_THRESHOLD_BYTES)
return;
}
if(!pool_count)
return;
for(i = 0; i < pool_count; i++) {
while((s = pool[i].stack)) {
pool[i].stack = (char*)_POOL_NODE_NEXT(s);
_POOL_NODE_FREE(s);
}
}
in_pool_count = 0;
in_pool_bytes = 0;
}
static void _open_mem_pool(void) {
#define N 7
size_t szs[N];
size_t lst[N];
int i = 0;
int j = 0;
size_t s = 0;
pool_count = 0;
szs[i++] = _SIZEOF_4BYTES;
szs[i++] = _SIZEOF_8BYTES;
szs[i++] = _SIZEOF_32BYTES;
szs[i++] = _SIZEOF_64BYTES;
szs[i++] = _SIZEOF_128BYTES;
szs[i++] = _SIZEOF_256BYTES;
szs[i++] = _SIZEOF_512BYTES;
mb_assert(i == N);
/* Find all unduplicated sizes */
for(i = 0; i < N; i++) {
s = szs[i];
for(j = 0; j < N; j++) {
if(!lst[j]) {
lst[j] = s;
pool_count++;
break;
} else if(lst[j] == s) {
break;
}
}
}
qsort(lst
, pool_count
, sizeof(lst
[0]), _cmp_size_t
);
pool
= (_pool_t
*)malloc(sizeof(_pool_t
) * pool_count
); for(i = 0; i < pool_count; i++) {
pool[i].size = lst[i];
pool[i].stack = 0;
}
#undef N
}
static void _close_mem_pool(void) {
int i = 0;
char* s = 0;
if(!pool_count)
return;
for(i = 0; i < pool_count; i++) {
while((s = pool[i].stack)) {
pool[i].stack = (char*)_POOL_NODE_NEXT(s);
_POOL_NODE_FREE(s);
}
}
pool = 0;
pool_count = 0;
}
static char* _pop_mem(unsigned s) {
int i = 0;
_pool_t* pl = 0;
char* result = 0;
++alloc_count;
alloc_bytes += s;
if(pool_count) {
for(i = 0; i < pool_count; i++) {
pl = &pool[i];
if(s <= pl->size) {
if(pl->stack) {
in_pool_count--;
in_pool_bytes -= (long)(_pool_chunk_size_t)s;
/* Pop from stack */
result = pl->stack;
pl->stack = (char*)_POOL_NODE_NEXT(result);
_POOL_NODE_SIZE(result) = (_pool_chunk_size_t)s;
return result;
} else {
/* Create a new node */
result = _POOL_NODE_ALLOC(pl->size);
if((intptr_t)result == sizeof(_pool_tag_t)) {
result = 0;
} else {
_POOL_NODE_SIZE(result) = (_pool_chunk_size_t)s;
}
return result;
}
}
}
}
/* Allocate directly */
result = _POOL_NODE_ALLOC(s);
if((intptr_t)result == sizeof(_pool_tag_t)) {
result = 0;
} else {
_POOL_NODE_SIZE(result) = (_pool_chunk_size_t)s;
}
return result;
}
static void _push_mem(char* p) {
int i = 0;
_pool_t* pl = 0;
if(--alloc_count < 0) {
mb_assert(0 && "Multiple free.");
}
alloc_bytes -= _POOL_NODE_SIZE(p);
if(pool_count) {
for(i = 0; i < pool_count; i++) {
pl = &pool[i];
if(_POOL_NODE_SIZE(p) <= pl->size) {
in_pool_count++;
in_pool_bytes += _POOL_NODE_SIZE(p);
/* Push to stack */
_POOL_NODE_NEXT(p) = pl->stack;
pl->stack = p;
_tidy_mem_pool(false);
return;
}
}
}
/* Free directly */
_POOL_NODE_FREE(p);
}
/* ========================================================} */