Files
EPANET/src/mempool.c
2019-04-03 15:55:23 -04:00

149 lines
3.6 KiB
C
Executable File

/*
******************************************************************************
Project: OWA EPANET
Version: 2.2
Module: mempool.c
Description: a simple fast poooled memory allocation package
Authors: see AUTHORS
Copyright: see AUTHORS
License: see LICENSE
Last Updated: 11/27/2018
This module is based code by Steve Hill in Graphics Gems III,
David Kirk (ed.), Academic Press, Boston, MA, 1992
******************************************************************************
*/
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include "mempool.h"
/*
** ALLOC_BLOCK_SIZE - adjust this size to suit your installation - it
** should be reasonably large otherwise you will be mallocing a lot.
*/
#define ALLOC_BLOCK_SIZE 64000 /*(62*1024)*/
struct MemBlock
{
struct MemBlock *next; // Next block
char *block, // Start of block
*free, // Next free position in block
*end; // block + block size
};
struct Mempool
{
struct MemBlock *first;
struct MemBlock *current;
};
static struct MemBlock* createMemBlock()
{
struct MemBlock* memBlock = malloc(sizeof(struct MemBlock));
if (memBlock)
{
memBlock->block = malloc(ALLOC_BLOCK_SIZE * sizeof(char));
if (memBlock->block == NULL)
{
free(memBlock);
return NULL;
}
memBlock->free = memBlock->block;
memBlock->next = NULL;
memBlock->end = memBlock->block + ALLOC_BLOCK_SIZE;
}
return memBlock;
}
static void deleteMemBlock(struct MemBlock* memBlock)
{
free(memBlock->block);
free(memBlock);
}
struct Mempool * mempool_create()
{
struct Mempool *mempool;
mempool = (struct Mempool *)malloc(sizeof(struct Mempool));
if (mempool == NULL) return NULL;
mempool->first = createMemBlock();
mempool->current = mempool->first;
if (mempool->first == NULL) return NULL;
return mempool;
}
void mempool_delete(struct Mempool *mempool)
{
if (mempool == NULL) return;
while (mempool->first)
{
mempool->current = mempool->first->next;
deleteMemBlock(mempool->first);
mempool->first = mempool->current;
}
free(mempool);
mempool = NULL;
}
void mempool_reset(struct Mempool *mempool)
{
mempool->current = mempool->first;
mempool->current->free = mempool->current->block;
}
char * mempool_alloc(struct Mempool *mempool, size_t size)
{
char* ptr;
/*
** Align to 4 byte boundary - should be ok for most machines.
** Change this if your machine has weird alignment requirements.
*/
size = (size + 3) & 0xfffffffc;
if (!mempool->current) return NULL;
ptr = mempool->current->free;
mempool->current->free += size;
// Check if the current block is exhausted
if (mempool->current->free >= mempool->current->end)
{
// Is the next block already allocated?
if (mempool->current->next)
{
// re-use block
mempool->current->next->free = mempool->current->next->block;
mempool->current = mempool->current->next;
}
else
{
// extend the pool with a new block
mempool->current->next = createMemBlock();
if (!mempool->current->next) return NULL;
mempool->current = mempool->current->next;
}
// set ptr to the first location in the next block
ptr = mempool->current->free;
mempool->current->free += size;
}
// Return pointer to allocated memory
return ptr;
}