#define C_KINO_MEMORYPOOL
#include "KinoSearch/Util/ToolSet.h"
#include "KinoSearch/Util/MemoryPool.h"
static
void
S_init_arena(MemoryPool *self,
size_t
amount);
#define DEFAULT_BUF_SIZE 0x100000 // 1 MiB
#define INCREASE_TO_WORD_MULTIPLE(_amount) \
do
{ \
const
size_t
_remainder = _amount %
sizeof
(
void
*); \
if
(_remainder) { \
_amount +=
sizeof
(
void
*); \
_amount -= _remainder; \
} \
}
while
(0)
MemoryPool*
MemPool_new(uint32_t arena_size)
{
MemoryPool *self = (MemoryPool*)VTable_Make_Obj(MEMORYPOOL);
return
MemPool_init(self, arena_size);
}
MemoryPool*
MemPool_init(MemoryPool *self, uint32_t arena_size)
{
self->arena_size = arena_size == 0 ? DEFAULT_BUF_SIZE : arena_size;
self->arenas = VA_new(16);
self->tick = -1;
self->buf = NULL;
self->limit = NULL;
self->consumed = 0;
return
self;
}
void
MemPool_destroy(MemoryPool *self)
{
DECREF(self->arenas);
SUPER_DESTROY(self, MEMORYPOOL);
}
static
void
S_init_arena(MemoryPool *self,
size_t
amount)
{
ByteBuf *bb;
int32_t i;
self->tick++;
if
(self->tick < (int32_t)VA_Get_Size(self->arenas)) {
bb = (ByteBuf*)VA_Fetch(self->arenas, self->tick);
if
(amount >= BB_Get_Size(bb)) {
BB_Grow(bb, amount);
BB_Set_Size(bb, amount);
}
}
else
{
size_t
buf_size = (amount + 1) > self->arena_size
? (amount + 1)
: self->arena_size;
char
*ptr = (
char
*)MALLOCATE(buf_size);
bb = BB_new_steal_bytes(ptr, buf_size - 1, buf_size);
VA_Push(self->arenas, (Obj*)bb);
}
self->consumed = 0;
for
(i = 0; i < self->tick; i++) {
ByteBuf *bb = (ByteBuf*)VA_Fetch(self->arenas, i);
self->consumed += BB_Get_Size(bb);
}
self->buf = BB_Get_Buf(bb);
self->limit = self->buf + BB_Get_Size(bb);
}
size_t
MemPool_get_consumed(MemoryPool *self) {
return
self->consumed; }
void
*
MemPool_grab(MemoryPool *self,
size_t
amount)
{
INCREASE_TO_WORD_MULTIPLE(amount);
self->last_buf = self->buf;
self->buf += amount;
if
(self->buf >= self->limit) {
S_init_arena(self, amount);
self->last_buf = self->buf;
self->buf += amount;
}
self->consumed += amount;
return
self->last_buf;
}
void
MemPool_resize(MemoryPool *self,
void
*ptr,
size_t
new_amount)
{
const
size_t
last_amount = self->buf - self->last_buf;
INCREASE_TO_WORD_MULTIPLE(new_amount);
if
(ptr != self->last_buf) {
THROW(ERR,
"Not the last pointer allocated."
);
}
else
{
if
(new_amount <= last_amount) {
const
size_t
difference = last_amount - new_amount;
self->buf -= difference;
self->consumed -= difference;
}
else
{
THROW(ERR,
"Can't resize to greater amount: %u64 > %u64"
,
(uint64_t)new_amount, (uint64_t)last_amount);
}
}
}
void
MemPool_release_all(MemoryPool *self)
{
self->tick = -1;
self->buf = NULL;
self->last_buf = NULL;
self->limit = NULL;
}
void
MemPool_eat(MemoryPool *self, MemoryPool *other) {
int32_t i;
if
(self->buf != NULL)
THROW(ERR,
"Memory pool is not empty"
);
for
(i = 0; i <= other->tick; i++) {
ByteBuf *arena = (ByteBuf*)VA_Shift(other->arenas);
VA_Store(self->arenas, i, (Obj*)arena);
}
self->tick = other->tick;
self->last_buf = other->last_buf;
self->buf = other->buf;
self->limit = other->limit;
}