netsurf/utils/pool.c
James Bursa 314a53cd63 [project @ 2004-01-02 12:04:29 by bursa]
Implement memory pools.

svn path=/import/netsurf/; revision=478
2004-01-02 12:04:29 +00:00

203 lines
3.7 KiB
C

/*
* This file is part of NetSurf, http://netsurf.sourceforge.net/
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
*/
/** \file
* Memory pool manager (implementation).
*
* A memory pool is implemented as a linked list of blocks. The current
* position and end of the last block are stored for fast access, so that
* pool_alloc() can allocate space very fast if available.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "netsurf/utils/pool.h"
struct pool_block {
char desc[20];
struct pool_block *prev;
};
struct pool {
struct pool_block *last_block;
char *current_pos;
char *end;
size_t block_size;
unsigned int block_count;
};
/**
* Create a memory pool.
*
* \param block_size suggested size of each block
* \return opaque pool handle, 0 on failure
*/
pool pool_create(size_t block_size)
{
pool p;
struct pool_block *b;
p = malloc(sizeof *p);
if (!p)
return 0;
b = malloc(sizeof *b + block_size + 8);
if (!b) {
free(p);
return 0;
}
p->last_block = b;
p->current_pos = (char *) b + sizeof *b;
p->end = (char *) b + sizeof *b + block_size;
p->block_size = block_size;
p->block_count = 0;
sprintf(b->desc, "POOL %p %u", p, p->block_count++);
b->prev = 0;
strcpy(p->end, "POOLEND");
return p;
}
/**
* Frees a memory pool.
*
* \param p a memory pool handle as returned by pool_create()
*/
void pool_destroy(pool p)
{
struct pool_block *b, *prev;
for (b = (struct pool_block *) p->last_block; b; b = prev) {
prev = b->prev;
free(b);
}
free(p);
}
/**
* Allocates space from a memory pool.
*
* \param p a memory pool handle as returned by pool_create()
* \param size number of bytes to allocate
* \return pointer to the space in the pool, 0 on failure
*/
void *pool_alloc(pool p, size_t size)
{
void *r;
if (p->end < p->current_pos + size) {
/* insufficient space: allocate new block */
struct pool_block *b;
size_t block_size = p->block_size;
if (block_size < size)
block_size += size;
b = malloc(sizeof *b + block_size + 8);
if (!b)
return 0;
sprintf(b->desc, "POOL %p %u", p, p->block_count++);
b->prev = p->last_block;
strcpy(p->end, "POOLEND");
p->last_block = b;
p->current_pos = (char *) b + sizeof *b;
p->end = (char *) b + sizeof *b + block_size;
}
r = p->current_pos;
p->current_pos += size;
return r;
}
/**
* Copies a string into a memory pool.
*
* \param p a memory pool handle as returned by pool_create()
* \param s zero-terminated character string
* \return pointer to the string in the pool, 0 on failure
*/
char *pool_string(pool p, const char *s)
{
size_t len = strlen(s);
char *buf = pool_alloc(p, len);
if (!buf)
return 0;
memcpy(buf, s, len + 1);
return buf;
}
#ifdef TEST
int main(void)
{
unsigned int i;
pool p1, p2;
puts("testing pool_create()");
p1 = pool_create(10000);
assert(p1);
p2 = pool_create(1000);
assert(p2);
puts("testing pool_alloc()");
for (i = 0; i != 100000; i++) {
size_t s = random() % 200;
char *b1, *b2;
unsigned int j;
b1 = pool_alloc(p1, s);
//b1 = malloc(s);
assert(b1);
b2 = pool_alloc(p2, s);
//b2 = malloc(s);
assert(b2);
for (j = 0; j != s; j++)
b1[j] = b2[j] = i % 256;
}
puts("testing pool_string()");
for (i = 0; i != 10000; i++) {
size_t s = random() % 200;
char str[201];
unsigned int j;
char *b;
for (j = 0; j != s; j++)
str[j] = 'A' + j % 26;
str[s] = 0;
b = pool_string(p1, str);
//b = strdup(str);
assert(b);
assert(strcmp(str, b) == 0);
}
puts("testing pool_destroy() (press enter)");
getc(stdin);
pool_destroy(p1);
pool_destroy(p2);
puts("done");
return 0;
}
#endif