Last active
February 16, 2019 18:00
-
-
Save Voltra/ea60e7d1187ac72b34f1a4b2d5731684 to your computer and use it in GitHub Desktop.
Dank memory pool in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "./memory_pool.h" | |
#include <string.h> | |
struct memory_pool{ | |
size_t batchSize, allocSize, elemSize; | |
void** available; | |
void** inUse; | |
int availableCursor, inUseCursor; | |
/* | |
Semantically, the available vector is used as a stack (from end to begin) | |
inUse is used a a regular vector but would be more performant as a doubly linked list | |
*/ | |
}; | |
memory_pool make_memory_pool(size_t batchSize, size_t elemSize){ | |
memory_pool this; | |
this.batchSize = batchSize; | |
this.allocSize = 0; | |
this.elemSize = elemSize; | |
this.available = malloc(sizeof(void*)); //start with a nullptr at the end | |
this.inUse = malloc(sizeof(void*)); //start with a nullptr at the end | |
memset(this.available, 0, sizeof(void*)); | |
memset(this.inUse, 0, sizeof(void*)); | |
this.availableCursor = -1; | |
this.inUseCursor = 0; | |
return this; | |
} | |
void destroy_memory_pool(memory_pool this){ | |
if(this.available != NULL){ | |
for(int i = 0 ; this.available[i] != NULL ; ++i) | |
free(this.available[i]); | |
} | |
if(this.inUse != NULL){ | |
for(int i = 0 ; this.inUse[i] != NULL ; ++i) | |
free(this.inUse[i]); | |
} | |
} | |
memory_pool* new_memory_pool(size_t batchSize, size_t elemSize){ | |
memory_pool* this = malloc(sizeof(memory_pool)); | |
*this = make_memory_pool(batchSize, elemSize); | |
return this; | |
} | |
void delete_memory_pool(memory_pool* this){ | |
destroy_memory_pool(*this); | |
free(this); | |
} | |
/** | |
* Allocates memory for this memory_pool | |
* @param this being the memory_pool to allocate memory for | |
* @pre mustn't allocate if there's still available memory | |
*/ | |
void allocate(memory_pool* this){ //TODO: handle realloc failures | |
//+1 for the NULL terminator | |
size_t size = this->allocSize + (this->batchSize + 1); | |
this->available = realloc(this->available, size * sizeof(void*)); | |
this->inUse = realloc(this->inUse, size * sizeof(void*)); | |
for(size_t i = 0 ; i < this->batchSize ; ++i){ | |
this->available[i] = malloc(this->elemSize); | |
memset(this->available[i], 0 , this->elemSize); | |
} | |
this->allocSize = size - 1; | |
this->availableCursor = this->batchSize - 1; | |
} | |
void* acquire(memory_pool* this){ | |
if(this->allocSize == 0 || this->availableCursor < 0) | |
allocate(this); | |
void* ptr = this->available[this->availableCursor]; | |
this->available[this->availableCursor] = NULL; | |
this->availableCursor -= 1; | |
this->inUse[this->inUseCursor] = ptr; | |
this->inUseCursor += 1; | |
return ptr; | |
} | |
bool release(memory_pool* this, void* ptr){ //TODO: Fix pb where ptr appears both in available and inUse | |
if(this->allocSize == 0 || ptr == NULL) | |
return false; | |
if(ptr != NULL) | |
memset(ptr, 0, this->elemSize); | |
if(this->inUseCursor > 0 && this->inUse[this->inUseCursor-1] == ptr){ | |
//case when releasing the last acquired | |
this->inUseCursor -= 1; | |
this->inUse[this->inUseCursor] = NULL; | |
this->availableCursor += 1; | |
this->available[this->availableCursor] = ptr; | |
return true; | |
} | |
//case when not releasing the last acquired | |
//shift everything on its right to the left | |
void* cur; | |
size_t i = 0; | |
do{ //Look for its index | |
cur = this->inUse[i]; | |
i += 1; | |
}while(cur != NULL && cur != ptr); | |
if(cur == NULL) | |
return false; | |
size_t j;//i-1 bc increment in do_while even if found | |
for(j = i-1 ; j < this->allocSize-1 && this->inUse[j+1] != NULL ; ++j) | |
//in case of early NULL, exit early | |
this->inUse[j] = this->inUse[j+1]; | |
this->inUse[j+1] = NULL; | |
this->inUseCursor -= 1; | |
this->inUse[this->inUseCursor] = NULL; | |
this->availableCursor += 1; | |
this->available[this->availableCursor] = ptr; | |
/* | |
We can save a lot of time and performance by | |
replacing inUse with a doubly linked list | |
*/ | |
return true; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <stdlib.h> | |
#include <stdbool.h> | |
typedef struct memory_pool memory_pool; | |
/** | |
* Constructor for a memory pool | |
* @param batchSize being the amount of allocation per batch | |
* @param elemSize being the size of a single elements | |
* @return the constructed memory_pool | |
* | |
* @pre batchSize > 0 | |
*/ | |
memory_pool make_memory_pool(size_t batchSize, size_t elemSize); | |
/** | |
* Destructor for a memory pool | |
* @param this being the memory pool to destroy | |
*/ | |
void destroy_memory_pool(memory_pool this); | |
/** | |
* Allocate a pointer to a memory pool | |
* @param batchSize being the amount of allocation per batch | |
* @param elemSize being the size of a single elements | |
* @return the constructed memory_pool pointer | |
*/ | |
memory_pool* new_memory_pool(size_t batchSize, size_t elemSize); | |
/** | |
* Free memory occupied by the memory_pool | |
* @param this being the memory pool to destroy | |
*/ | |
void delete_memory_pool(memory_pool* this); | |
// void allocate(memory_pool*); | |
/** | |
* Demand a pointer from the pool | |
* @param this being the memory pool to use | |
* @return the allocated pointer | |
*/ | |
void* acquire(memory_pool* this); | |
/** | |
* Release memory acquired from this memory pool | |
* @param this being the memory pool to use | |
* @param ptr being the pointer to release | |
* @return TRUE if everything went well, FALSE otherwise | |
* | |
* @pre ptr must have been acquired using the acquire function | |
* with the given memory_pool | |
*/ | |
bool release(memory_pool* this, void* ptr); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment