diff --git a/raylib-memory-pool.md b/raylib-memory-pool.md index 72c85ea..3e51dec 100644 --- a/raylib-memory-pool.md +++ b/raylib-memory-pool.md @@ -67,7 +67,7 @@ When we finish using the pool's memory, we clean it up by using `MemPool_Destroy ```c MemPool_Destroy(&pool); ``` - + Alternatively, if you're not in a position to use any kind of dynamic allocation from the operating system, you have the option to utilize an existing buffer as memory for the mempool: ```c char mem[64000]; @@ -79,7 +79,7 @@ To allocate from the pool, we have two functions: void *MemPool_Alloc(MemPool *mempool, size_t bytes); void *MemPool_Realloc(MemPool *mempool, void *ptr, size_t bytes); ``` - + `MemPool_Alloc` returns a (zeroed) pointer to a memory block. ```c // allocate an int pointer. @@ -242,3 +242,83 @@ Which of course is equivalent to: ```c ObjPool_Free(&vector_pool, origin), origin = NULL; ``` + +# Double-Ended aka Bi(furcated) Stack + +By Kevin 'Assyrianic' Yonan @ https://github.com/assyrianic + +**About**: + The raylib BiStack is a fast & efficient bifurcated stack "bi-stack" allocator. + +**Purpose**: + raylib BiStack's purpose is the following list: +* A quick, efficient way of allocating temporary, dynamically-sizeable memory during various operations. +* Bifurcated to allow certain temporary data to have a different lifetime from other, temporary data. + +**Data Implementation**: +The bifurcated stack encapsulates one public struct: +* `mem` which is an unsigned integer large enough to represent a pointer; the pointer value it holds is the memory address of the backing buffer. +* `front` holds a pointer value representing the first aka _front_ portion of the bifurcated stack. +* `back` holds a pointer value representing the second aka _back_ portion of the bifurcated stack. +* and a `size` that holds the amount of bytes of the backing buffer. +```c + typedef struct BiStack { + uintptr_t mem, front, back; + size_t size; + } BiStack; +``` + +**Usage**: + The bi-stack is designed to be used as a direct object. +There are two constructor functions: +```c + BiStack CreateBiStack(size_t len); + BiStack CreateBiStackFromBuffer(void *buf, size_t len); +``` +To which you create a `BiStack` instance and give the function a max amount of memory you wish or require for your data. +Remember not to exceed that memory amount or the allocation functions of the allocator will give you a NULL pointer. + +So we create a bistack that will malloc an internal buffer of 10K bytes. +```c + BiStack bistack = CreateBiStack(10000); +``` + +When the bi-stack is no longer needed, we clean it up by using `DestroyBiStack`. +```c + DestroyBiStack(&bistack); +``` + +Alternatively, if you're not in a position to use any kind of dynamic allocation from the operating system, you have the option to utilize an existing buffer as memory for the bistack: +```c + char mem[64000]; + BiStack pool = CreateBiStackFromBuffer(mem, sizeof mem); +``` + +To allocate from the bistack, we have two functions: +```c + void *BiStackAllocFront(BiStack *destack, size_t len); + void *BiStackAllocBack(BiStack *destack, size_t len); +``` + +**NOTE**: _The two allocator functions do **NOT** zero memory._ +```c + // allocate an int pointer from the front. + int *i = BiStackAllocFront(&bistack, sizeof *i); + + // allocate a float pointer from the back. + float *f = BiStackAllocBack(&bistack, sizeof *f); +``` + +Unlike the other allocators, the Bi-stack does not require you free given pointers back to the allocator. However, you will need to reset the bi-stack in order to "free" the data back to the bi-stack. Here are three functions that resets the bi-stack: +```c + void BiStackResetFront(BiStack *destack); + void BiStackResetBack(BiStack *destack); + void BiStackResetAll(BiStack *destack); +``` +`BiStackResetFront` will reset allocation data for the front portion of the bi-stack. So ALL pointers given from the front portion can be overwritten if any new pointers allocated also point to those parts. Same deal for `BiStackResetBack` and the back portion of the bi-stack. + +If both portions need to be reset, `BiStackResetAll` will do the job. + +An important caveat with the bi-stack is that if the back portion or the front portion collide with one another, you will be given a `NULL` pointer. To check if they will collide, `intptr_t BiStackMargins(BiStack destack);` is used to get the difference between how far, in bytes, the back portion is from the front. + +The way this works is that, when allocating from the front portion, the `front` member is increased. When allocating the back portion, the `back` member is decreased. If the front portion reaches the back, that means the front portion of the bi-stack is out of memory, same deal for the back portion if it reaches the front. Thus, `BiStackMargins` provides you the difference between these two portions; a number of 0 or less means that one of the portions has reached the other and a reset is necessary. \ No newline at end of file