Przeglądaj źródła

First attempt at memory management

Sepehr Taghdisian 11 lat temu
rodzic
commit
1956703c42
4 zmienionych plików z 341 dodań i 40 usunięć
  1. 94 28
      imgui.cpp
  2. 35 11
      imgui.h
  3. 210 0
      immem.h
  4. 2 1
      libimgui.pro

+ 94 - 28
imgui.cpp

@@ -166,6 +166,15 @@
 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
 #endif
 
+#include <new>
+#define IMGUI_INTERNAL_USE
+#include "immem.h"
+#undef IMGUI_INTERNAL_USE
+
+// Block sizes for each memory. Don't really know about the optimized values
+#define DRAWLIST_BLOCK_SIZE 128
+#define GUIWINDOW_BLOCK_SIZE 64
+
 //-------------------------------------------------------------------------
 // Forward Declarations
 //-------------------------------------------------------------------------
@@ -194,6 +203,9 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs);
 
 }; // namespace ImGui
 
+static char*        StrDup(const char *str);
+static void         StrDup_Free(char *str);
+
 //-----------------------------------------------------------------------------
 // Platform dependant default implementations
 //-----------------------------------------------------------------------------
@@ -262,6 +274,10 @@ ImGuiStyle::ImGuiStyle()
 ImGuiIO::ImGuiIO()
 {
 	memset(this, 0, sizeof(*this));
+
+    MallocFn = malloc;
+    FreeFn = free;
+
 	DeltaTime = 1.0f/60.0f;
 	IniSavingRate = 5.0f;
 	IniFilename = "imgui.ini";
@@ -585,7 +601,7 @@ struct ImGuiIniData
 	bool	Collapsed;
 
 	ImGuiIniData() { memset(this, 0, sizeof(*this)); }
-	~ImGuiIniData() { if (Name) { free(Name); Name = NULL; } }
+    ~ImGuiIniData() { if (Name) { StrDup_Free(Name); Name = NULL; } }
 };
 
 struct ImGuiState
@@ -624,9 +640,13 @@ struct ImGuiState
 	// Logging
 	bool					LogEnabled;
 	FILE*					LogFile;
-	ImGuiTextBuffer			LogClipboard;
+    ImGuiTextBuffer			LogClipboard;
 	int						LogAutoExpandMaxDepth;
 
+    // Memory Pools
+    PoolAlloc<ImDrawList>   DrawListPool;
+    PoolAlloc<ImGuiWindow>  GuiWindowPool;
+
 	ImGuiState()
 	{
 		Initialized = false;
@@ -646,7 +666,7 @@ struct ImGuiState
 		PrivateClipboard = NULL;
 		LogEnabled = false;
 		LogFile = NULL;
-		LogAutoExpandMaxDepth = 2;
+        LogAutoExpandMaxDepth = 2;
 	}
 };
 
@@ -907,7 +927,7 @@ void ImGuiTextBuffer::append(const char* fmt, ...)
 
 ImGuiWindow::ImGuiWindow(const char* name, ImVec2 default_pos, ImVec2 default_size)
 {
-	Name = strdup(name);
+    Name = StrDup(name);
 	ID = GetID(name); 
 	IDStack.push_back(ID);
 
@@ -932,14 +952,17 @@ ImGuiWindow::ImGuiWindow(const char* name, ImVec2 default_pos, ImVec2 default_si
 	FocusIdxRequestCurrent = IM_INT_MAX;
 	FocusIdxRequestNext = IM_INT_MAX;
 
-	DrawList = new ImDrawList();
+    ImDrawList *buff = GImGui.DrawListPool.alloc();
+    IM_ASSERT(buff);
+    DrawList = new(buff) ImDrawList();
 }
 
 ImGuiWindow::~ImGuiWindow()
 {
-	delete DrawList;
+    DrawList->~ImDrawList();
+    GImGui.DrawListPool.free(DrawList);
 	DrawList = NULL;
-	free(Name);
+    StrDup_Free(Name);
 	Name = NULL;
 }
 
@@ -1019,9 +1042,9 @@ static ImGuiIniData* FindWindowSettings(const char* name)
 		if (ImStricmp(ini->Name, name) == 0)
 			return ini;
 	}
-	ImGuiIniData* ini = new ImGuiIniData();
-	ini->Name = strdup(name);
-	ini->Collapsed = false;
+    ImGuiIniData* ini = new ImGuiIniData();
+    ini->Name = StrDup(name);
+    ini->Collapsed = false;
 	ini->Pos = ImVec2(FLT_MAX,FLT_MAX);
 	ini->Size = ImVec2(0,0);
 	g.Settings.push_back(ini);
@@ -1156,8 +1179,14 @@ void NewFrame()
 
 	if (!g.Initialized)
 	{
-		// Initialize on first frame
+        // Initialize on first frame
 		IM_ASSERT(g.Settings.empty());
+
+        g.LogClipboard.init();
+
+        g.DrawListPool.create(DRAWLIST_BLOCK_SIZE, g.IO.MallocFn, g.IO.FreeFn);
+        g.GuiWindowPool.create(GUIWINDOW_BLOCK_SIZE, g.IO.MallocFn, g.IO.FreeFn);
+
 		LoadSettings();
 		if (!g.IO.Font)
 		{
@@ -1169,6 +1198,7 @@ void NewFrame()
 			g.IO.Font->LoadFromMemory(fnt_data, fnt_size);
 			g.IO.FontHeight = g.IO.Font->GetFontSize();
 		}
+
 		g.Initialized = true;
 	}
 
@@ -1282,8 +1312,10 @@ void Shutdown()
 
 	SaveSettings();
 
-	for (size_t i = 0; i < g.Windows.size(); i++)
-		delete g.Windows[i];
+    for (size_t i = 0; i < g.Windows.size(); i++)   {
+        g.Windows[i]->~ImGuiWindow();
+        g.GuiWindowPool.free(g.Windows[i]);
+    }
 	g.Windows.clear();
 	g.CurrentWindowStack.clear();
 	g.FocusedWindow = NULL;
@@ -1292,6 +1324,7 @@ void Shutdown()
 	for (size_t i = 0; i < g.Settings.size(); i++)
 		delete g.Settings[i];
 	g.Settings.clear();
+    g.RenderDrawLists.clear();
 	g.ColorEditModeStorage.Clear();
 	if (g.LogFile && g.LogFile != stdout)
 	{
@@ -1306,10 +1339,15 @@ void Shutdown()
 
 	if (g.PrivateClipboard)
 	{
-		free(g.PrivateClipboard);
+        GImGui.IO.FreeFn(g.PrivateClipboard);
 		g.PrivateClipboard = NULL;
 	}
 
+    g.DrawListPool.destroy();
+    g.GuiWindowPool.destroy();
+
+    g.LogClipboard.destroy();
+
 	g.Initialized = false;
 }
 
@@ -1783,9 +1821,12 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
 	ImGuiWindow* window = FindWindow(name);
 	if (!window)
 	{
+        ImGuiWindow *buff = GImGui.GuiWindowPool.alloc();
+        IM_ASSERT(buff);
+
 		if (flags & ImGuiWindowFlags_ChildWindow)
 		{
-			window = new ImGuiWindow(name, ImVec2(0,0), size);
+            window = new(buff) ImGuiWindow(name, ImVec2(0,0), size);
 		}
 		else
 		{
@@ -1793,7 +1834,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
 			if (settings && ImLength(settings->Size) > 0.0f && !(flags & ImGuiWindowFlags_NoResize))// && ImLengthsize) == 0.0f)
 				size = settings->Size;
 
-			window = new ImGuiWindow(name, g.NewWindowDefaultPos, size);
+            window = new(buff) ImGuiWindow(name, g.NewWindowDefaultPos, size);
 
 			if (settings->Pos.x != FLT_MAX)
 			{
@@ -3809,7 +3850,7 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
 				{
 					// Remove new-line from pasted buffer
 					size_t clipboard_len = strlen(clipboard);
-					char* clipboard_filtered = (char*)malloc(clipboard_len+1);
+                    char* clipboard_filtered = (char*)GImGui.IO.MallocFn(clipboard_len+1);
 					int clipboard_filtered_len = 0;
 					for (int i = 0; clipboard[i]; i++)
 					{
@@ -3820,7 +3861,7 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
 					}
 					clipboard_filtered[clipboard_filtered_len] = 0;
 					stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len);
-					free(clipboard_filtered);
+                    GImGui.IO.FreeFn(clipboard_filtered);
 				}
 		}
 		else if (g.IO.InputCharacters[0])
@@ -4422,7 +4463,7 @@ static bool ClipAdvance(const ImGuiAabb& bb)
 		window->DC.LastItemHovered = false;
 		return true;
 	}
-	window->DC.LastItemHovered = ImGui::IsMouseHoveringBox(bb);		// this is a sensible default but widgets are free to override it after calling ClipAdvance
+    window->DC.LastItemHovered = ImGui::IsMouseHoveringBox(bb);		// this is a sensible default but widgets are GImGui.IO.FreeFn to override it after calling ClipAdvance
 	return false;
 }
 
@@ -4941,7 +4982,7 @@ ImBitmapFont::ImBitmapFont()
 void	ImBitmapFont::Clear()
 {
 	if (Data && DataOwned)
-		free(Data);
+        GImGui.IO.FreeFn(Data);
 	Data = NULL;
 	DataOwned = false;
 	Info = NULL;
@@ -4964,7 +5005,7 @@ bool	ImBitmapFont::LoadFromFile(const char* filename)
 		return false;
 	if (fseek(f, 0, SEEK_SET)) 
 		return false;
-	if ((Data = (unsigned char*)malloc(DataSize)) == NULL)
+    if ((Data = (unsigned char*)GImGui.IO.MallocFn(DataSize)) == NULL)
 	{
 		fclose(f);
 		return false;
@@ -4972,7 +5013,7 @@ bool	ImBitmapFont::LoadFromFile(const char* filename)
 	if ((int)fread(Data, 1, DataSize, f) != DataSize)
 	{
 		fclose(f);
-		free(Data);
+        GImGui.IO.FreeFn(Data);
 		return false;
 	}
 	fclose(f);
@@ -5215,7 +5256,7 @@ static const char*	GetClipboardTextFn_DefaultImpl()
 	static char* buf_local = NULL;
 	if (buf_local)
 	{
-		free(buf_local);
+        GImGui.IO.FreeFn(buf_local);
 		buf_local = NULL;
 	}
 	if (!OpenClipboard(NULL)) 
@@ -5224,7 +5265,7 @@ static const char*	GetClipboardTextFn_DefaultImpl()
 	if (buf_handle == NULL)
 		return NULL;
 	if (char* buf_global = (char*)GlobalLock(buf_handle))
-		buf_local = strdup(buf_global);
+        buf_local = StrDup(buf_global);
 	GlobalUnlock(buf_handle); 
 	CloseClipboard(); 
 	return buf_local;
@@ -5263,12 +5304,12 @@ static void SetClipboardTextFn_DefaultImpl(const char* text, const char* text_en
 {
 	if (GImGui.PrivateClipboard)
 	{
-		free(GImGui.PrivateClipboard);
+        GImGui.IO.FreeFn(GImGui.PrivateClipboard);
 		GImGui.PrivateClipboard = NULL;
 	}
 	if (!text_end)
 		text_end = text + strlen(text);
-	GImGui.PrivateClipboard = (char*)malloc(text_end - text + 1);
+    GImGui.PrivateClipboard = (char*)GImGui.IO.MallocFn(text_end - text + 1);
 	memcpy(GImGui.PrivateClipboard, text, text_end - text);
 	GImGui.PrivateClipboard[text_end - text] = 0;
 }
@@ -5718,8 +5759,9 @@ void ShowTestWindow(bool* open)
 
 	if (ImGui::CollapsingHeader("Long text"))
 	{
-		static ImGuiTextBuffer log;
+        /*static*/ ImGuiTextBuffer log;
 		static int lines = 0;
+        log.init();
 		ImGui::Text("Printing unusually long amount of text.");
 		ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
 		if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
@@ -5741,6 +5783,20 @@ void ShowTestWindow(bool* open)
 
 }; // namespace ImGui
 
+static char* StrDup(const char *str)
+{
+    char *buff = (char*)GImGui.IO.MallocFn(strlen(str) + 1);
+    IM_ASSERT(buff);
+    strcpy(buff, str);
+    return buff;
+}
+
+static void StrDup_Free(char *str)
+{
+    IM_ASSERT(str);
+    GImGui.IO.FreeFn(str);
+}
+
 //-----------------------------------------------------------------------------
 // Font data
 // Bitmap exported from proggy_clean.fon (c) by Tristan Grimmer http://www.proggyfonts.net
@@ -5748,7 +5804,7 @@ void ShowTestWindow(bool* open)
 /*
 // Copyright (c) 2004, 2005 Tristan Grimmer
 
-// Permission is hereby granted, free of charge, to any person obtaining a copy 
+// Permission is hereby granted, GImGui.IO.FreeFn of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // in the Software without restriction, including without limitation the rights
 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
@@ -5950,3 +6006,13 @@ void GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const voi
 };
 
 //-----------------------------------------------------------------------------
+
+void* ImGui_ProxyMalloc(size_t size)
+{
+    return GImGui.IO.MallocFn(size);
+}
+
+void ImGui_ProxyFree(void *ptr)
+{
+    GImGui.IO.FreeFn(ptr);
+}

+ 35 - 11
imgui.h

@@ -18,6 +18,7 @@ struct ImGuiWindow;
 #include <float.h>			// FLT_MAX
 #include <stdarg.h>			// va_list
 #include <stdlib.h>			// NULL
+#include <string.h>
 
 #ifndef IM_ASSERT
 #include <assert.h>
@@ -33,6 +34,9 @@ typedef int ImGuiWindowFlags;		// enum ImGuiWindowFlags_
 typedef int ImGuiInputTextFlags;	// enum ImGuiInputTextFlags_
 typedef ImBitmapFont* ImFont;
 
+typedef void* (*ImGui_MallocCallback)(size_t size);
+typedef void (*ImGui_FreeCallback)(void *ptr);
+
 struct ImVec2
 {
 	float x, y;
@@ -58,6 +62,11 @@ struct ImVec4
 // std::vector<> like class to avoid dragging dependencies (also: windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug). 
 // this implementation does NOT call c++ constructors! we don't need them! also only provide the minimum functionalities we need.
 #ifndef ImVector
+
+// Forward declarations for Malloc/Free proxies
+void* ImGui_ProxyMalloc(size_t size);
+void ImGui_ProxyFree(void *ptr);
+
 template<typename T>
 class ImVector
 {
@@ -72,7 +81,7 @@ public:
 	typedef const value_type*	const_iterator;
 
 	ImVector()					{ _size = _capacity = 0; _data = NULL; }
-	~ImVector()					{ if (_data) free(_data); }
+    ~ImVector()					{ if (_data) ImGui_ProxyFree(_data); }
 
 	inline bool					empty() const					{ return _size == 0; }
 	inline size_t				size() const					{ return _size; }
@@ -83,7 +92,7 @@ public:
     inline value_type&			operator[](size_t i)			{ IM_ASSERT(i < _size); return _data[i]; }
     inline const value_type&	operator[](size_t i) const		{ IM_ASSERT(i < _size); return _data[i]; }
 
-	inline void					clear()							{ if (_data) { _size = _capacity = 0; free(_data); _data = NULL; } }
+    inline void					clear()							{ if (_data) { _size = _capacity = 0; ImGui_ProxyFree(_data); _data = NULL; } }
 	inline iterator				begin()							{ return _data; }
 	inline const_iterator		begin() const					{ return _data; }
 	inline iterator				end()							{ return _data + _size; }
@@ -94,7 +103,18 @@ public:
 	inline const value_type&	back() const					{ IM_ASSERT(_size > 0); return at(_size-1); }
 	inline void					swap(ImVector<T>& rhs)			{ const size_t rhs_size = rhs._size; rhs._size = _size; _size = rhs_size; const size_t rhs_cap = rhs._capacity; rhs._capacity = _capacity; _capacity = rhs_cap; value_type* rhs_data = rhs._data; rhs._data = _data; _data = rhs_data; }
 
-	inline void					reserve(size_t new_capacity)	{ _data = (value_type*)realloc(_data, new_capacity * sizeof(value_type)); _capacity = new_capacity; }
+    inline void                 reserve(size_t new_capacity)
+    {
+        if (!_data) {
+            _data = (value_type*)ImGui_ProxyMalloc(new_capacity*sizeof(value_type));
+        }   else    {
+            void *tmp = ImGui_ProxyMalloc(new_capacity*sizeof(value_type));
+            memcpy(tmp, _data, sizeof(value_type)*_capacity);
+            ImGui_ProxyFree(_data);
+            _data = (value_type*)tmp;
+        }
+        _capacity = new_capacity;
+    }
 	inline void					resize(size_t new_size)			{ if (new_size > _capacity) reserve(new_size); _size = new_size; }
 
 	inline void					push_back(const value_type& v)	{ if (_size == _capacity) reserve(_capacity ? _capacity * 2 : 4); _data[_size++] = v; }
@@ -371,7 +391,9 @@ struct ImGuiStyle
 struct ImGuiIO
 {
 	// Settings (fill once)					// Default value:
-	ImVec2		DisplaySize;				// <unset>					// Display size, in pixels. For clamping windows positions.
+    ImGui_MallocCallback MallocFn;
+    ImGui_FreeCallback FreeFn;
+    ImVec2		DisplaySize;				// <unset>					// Display size, in pixels. For clamping windows positions.
 	float		DeltaTime;					// = 1.0f/60.0f				// Time elapsed since last frame, in seconds.
 	float		IniSavingRate;				// = 5.0f					// Maximum time between saving .ini file, in seconds. Set to a negative value to disable .ini saving.
 	const char* IniFilename;				// = "imgui.ini"			// Absolute path to .ini file.
@@ -476,13 +498,15 @@ struct ImGuiTextBuffer
 {
 	ImVector<char>		Buf;
 
-	ImGuiTextBuffer()	{ Buf.push_back(0); }
-	const char*			begin() const { return Buf.begin(); }
-	const char*			end() const { return Buf.end()-1; }
-	size_t				size() const { return Buf.size()-1; }
-	bool				empty() { return Buf.empty(); }
-	void				clear() { Buf.clear(); Buf.push_back(0); }
-	void				append(const char* fmt, ...);
+    ImGuiTextBuffer()	{  }
+    void init() { if (Buf.empty())  Buf.push_back(0); }
+    const char*			begin() const { return Buf.begin(); }
+    const char*			end() const { return Buf.end()-1; }
+    size_t				size() const { return Buf.size()-1; }
+    bool				empty() { return Buf.empty(); }
+    void				clear() { Buf.clear(); Buf.push_back(0); }
+    void				append(const char* fmt, ...);
+    void                destroy() { Buf.clear();    }
 };
 
 // Helper: Key->value storage

+ 210 - 0
immem.h

@@ -0,0 +1,210 @@
+/***********************************************************************************
+ * Author: Sepehr Taghdisian ([email protected])
+ */
+
+#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

+ 2 - 1
libimgui.pro

@@ -17,4 +17,5 @@ SOURCES += \
 
 HEADERS += \
     imgui.h \
-    imconfig.h
+    imconfig.h \
+    immem.h