mirror of
https://github.com/Drezil/imgui.git
synced 2024-11-15 01:17:00 +00:00
211 lines
5.5 KiB
C
211 lines
5.5 KiB
C
|
/***********************************************************************************
|
||
|
* Author: Sepehr Taghdisian (sep.tagh@gmail.com)
|
||
|
*/
|
||
|
|
||
|
#ifndef IMMEM_H
|
||
|
#define IMMEM_H
|
||
|
|
||
|
// Note: This file is meant to included only inside imgui.cpp
|
||
|
|
||
|
#ifndef IMGUI_INTERNAL_USE
|
||
|
#error "This file is intented for internal use only (as include)"
|
||
|
#endif
|
||
|
|
||
|
/* Linked-List ************************************************************************************/
|
||
|
struct LinkedList
|
||
|
{
|
||
|
LinkedList *next;
|
||
|
LinkedList *prev;
|
||
|
void *data;
|
||
|
|
||
|
LinkedList() : next(NULL), prev(NULL) {}
|
||
|
};
|
||
|
|
||
|
|
||
|
static void list_add(struct LinkedList** plist, struct LinkedList* item, void* data)
|
||
|
{
|
||
|
item->next = (*plist);
|
||
|
item->prev = NULL;
|
||
|
if (*plist != NULL)
|
||
|
(*plist)->prev = item;
|
||
|
*plist = item;
|
||
|
item->data = data;
|
||
|
}
|
||
|
|
||
|
static void list_addlast(struct LinkedList** plist, struct LinkedList* item, void* data)
|
||
|
{
|
||
|
if (*plist != NULL) {
|
||
|
struct LinkedList* last = *plist;
|
||
|
while (last->next != NULL) last = last->next;
|
||
|
last->next = item;
|
||
|
item->prev = last;
|
||
|
item->next = NULL;
|
||
|
} else {
|
||
|
*plist = item;
|
||
|
item->prev = item->next = NULL;
|
||
|
}
|
||
|
|
||
|
item->data = data;
|
||
|
}
|
||
|
|
||
|
static void list_remove(struct LinkedList** plist, struct LinkedList* item)
|
||
|
{
|
||
|
if (item->next != NULL) item->next->prev = item->prev;
|
||
|
if (item->prev != NULL) item->prev->next = item->next;
|
||
|
if (*plist == item) *plist = item->next;
|
||
|
item->next = item->prev = NULL;
|
||
|
}
|
||
|
|
||
|
/* PoolAlloc **************************************************************************************/
|
||
|
template <typename T>
|
||
|
class PoolAlloc
|
||
|
{
|
||
|
private:
|
||
|
LinkedList *m_blocks; /* first node of m_blocks */
|
||
|
int m_block_cnt;
|
||
|
int m_items_max; /* maximum number of items allowed (per block) */
|
||
|
ImGui_MallocCallback m_malloc;
|
||
|
ImGui_FreeCallback m_free;
|
||
|
|
||
|
private:
|
||
|
struct Block
|
||
|
{
|
||
|
LinkedList node; /* linked-list node */
|
||
|
unsigned char *buffer; /* memory buffer that holds all objects */
|
||
|
void **ptrs; /* pointer references to the buffer */
|
||
|
int iter; /* iterator for current buffer position */
|
||
|
};
|
||
|
|
||
|
private:
|
||
|
Block* create_block(int block_size)
|
||
|
{
|
||
|
// Allocate in one call
|
||
|
size_t total_sz =
|
||
|
sizeof(Block) +
|
||
|
sizeof(T)*block_size +
|
||
|
sizeof(void*)*block_size;
|
||
|
unsigned char *buff = (unsigned char*)m_malloc(total_sz);
|
||
|
if (buff == NULL)
|
||
|
return NULL;
|
||
|
memset(buff, 0x00, total_sz);
|
||
|
|
||
|
Block *block = (Block*)buff;
|
||
|
buff += sizeof(Block);
|
||
|
block->buffer = buff;
|
||
|
buff += sizeof(T)*block_size;
|
||
|
block->ptrs = (void**)buff;
|
||
|
|
||
|
// Assign pointer refs
|
||
|
for (int i = 0; i < block_size; i++)
|
||
|
block->ptrs[block_size-i-1] = block->buffer + i*sizeof(T);
|
||
|
block->iter = block_size;
|
||
|
|
||
|
/* add to linked-list of the pool */
|
||
|
list_addlast(&m_blocks, &block->node, block);
|
||
|
m_block_cnt++;
|
||
|
return block;
|
||
|
}
|
||
|
|
||
|
void destroy_block(Block *block)
|
||
|
{
|
||
|
list_remove(&m_blocks, &block->node);
|
||
|
m_free(block);
|
||
|
m_block_cnt--;
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
PoolAlloc()
|
||
|
{
|
||
|
m_blocks = NULL;
|
||
|
m_block_cnt = 0;
|
||
|
m_items_max = 0;
|
||
|
m_malloc = NULL;
|
||
|
m_free = NULL;
|
||
|
}
|
||
|
|
||
|
bool create(int block_sz, ImGui_MallocCallback malloc_fn, ImGui_FreeCallback free_fn)
|
||
|
{
|
||
|
m_items_max = block_sz;
|
||
|
m_malloc = malloc_fn;
|
||
|
m_free = free_fn;
|
||
|
|
||
|
// First block
|
||
|
Block *block = create_block(block_sz);
|
||
|
if (block == NULL) {
|
||
|
destroy();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void destroy()
|
||
|
{
|
||
|
LinkedList* node = m_blocks;
|
||
|
while (node != NULL) {
|
||
|
LinkedList* next = node->next;
|
||
|
destroy_block((Block*)node->data);
|
||
|
node = next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
T* alloc()
|
||
|
{
|
||
|
LinkedList* node = m_blocks;
|
||
|
|
||
|
while (node != NULL) {
|
||
|
Block *block = (Block*)node->data;
|
||
|
if (block->iter > 0)
|
||
|
return (T*)block->ptrs[--block->iter];
|
||
|
|
||
|
node = node->next;
|
||
|
}
|
||
|
|
||
|
/* couldn't find a free block, create a new one */
|
||
|
Block *block = create_block(m_items_max);
|
||
|
if (block == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
return (T*)block->ptrs[--block->iter];
|
||
|
}
|
||
|
|
||
|
void free(T *ptr)
|
||
|
{
|
||
|
// find the block that pointer belongs to, and free the pointer from that block
|
||
|
LinkedList *node = m_blocks;
|
||
|
int buffer_sz = m_items_max*sizeof(T);
|
||
|
unsigned char *u8ptr = (unsigned char*)ptr;
|
||
|
|
||
|
while (node != NULL) {
|
||
|
Block *block = (Block*)node->data;
|
||
|
if (u8ptr >= block->buffer && u8ptr < (block->buffer + buffer_sz)) {
|
||
|
IM_ASSERT(block->iter != m_items_max);
|
||
|
block->ptrs[block->iter++] = ptr;
|
||
|
return;
|
||
|
}
|
||
|
node = node->next;
|
||
|
}
|
||
|
|
||
|
// Memory block does not belong to the pool?!
|
||
|
IM_ASSERT(0);
|
||
|
}
|
||
|
|
||
|
void clear()
|
||
|
{
|
||
|
int block_size = m_items_max;
|
||
|
LinkedList* node = m_blocks;
|
||
|
while (node != NULL) {
|
||
|
Block *block = (Block*)node->data;
|
||
|
|
||
|
/* only re-assign pointer references to buffer */
|
||
|
for (int i = 0; i < block_size; i++)
|
||
|
block->ptrs[block_size-i-1] = block->buffer + i*sizeof(T);
|
||
|
block->iter = block_size;
|
||
|
|
||
|
node = node->next;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#endif // IMMEM_H
|