2001-11-28 12:13:00 +03:00
/*
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
*
* This file is released under the LGPL .
*/
# include "pool.h"
# include "dbg_malloc.h"
# include "log.h"
# include <assert.h>
struct block {
struct block * next ;
2001-12-12 17:25:20 +03:00
size_t size ;
2001-11-28 12:13:00 +03:00
char data [ 0 ] ;
} ;
struct pool {
2001-12-12 17:25:20 +03:00
int object ;
2001-11-28 12:13:00 +03:00
struct block * blocks ;
struct block * tail ;
} ;
/* by default things come out aligned for doubles */
# define DEFAULT_ALIGNMENT __alignof__ (double)
struct pool * pool_create ( size_t chunk_hint )
{
struct pool * mem = dbg_malloc ( sizeof ( * mem ) ) ;
if ( ! mem ) {
stack ;
return NULL ;
}
2001-12-12 17:25:20 +03:00
mem - > object = 0 ;
2001-11-28 12:13:00 +03:00
mem - > blocks = mem - > tail = NULL ;
return mem ;
}
static void _free_blocks ( struct block * b )
{
struct block * n ;
while ( b ) {
n = b - > next ;
dbg_free ( b ) ;
b = n ;
}
}
void pool_destroy ( struct pool * p )
{
_free_blocks ( p - > blocks ) ;
dbg_free ( p ) ;
}
void * pool_alloc ( struct pool * p , size_t s )
{
return pool_alloc_aligned ( p , s , DEFAULT_ALIGNMENT ) ;
}
2001-12-12 17:25:20 +03:00
static void _append_block ( struct pool * p , struct block * b )
{
if ( p - > tail ) {
p - > tail - > next = b ;
p - > tail = b ;
} else
p - > blocks = p - > tail = b ;
}
2001-11-28 12:13:00 +03:00
void * pool_alloc_aligned ( struct pool * p , size_t s , unsigned alignment )
{
/* FIXME: I'm currently ignoring the alignment arg. */
size_t len = sizeof ( struct block ) + s ;
struct block * b = dbg_malloc ( len ) ;
if ( ! b ) {
stack ;
return NULL ;
}
b - > next = NULL ;
2001-12-12 17:25:20 +03:00
b - > size = s ;
2001-11-28 12:13:00 +03:00
2001-12-12 17:25:20 +03:00
_append_block ( p , b ) ;
2001-11-28 17:58:33 +03:00
return & b - > data [ 0 ] ;
2001-11-28 12:13:00 +03:00
}
void pool_empty ( struct pool * p )
{
_free_blocks ( p - > blocks ) ;
p - > blocks = p - > tail = NULL ;
}
void pool_free ( struct pool * p , void * ptr )
{
struct block * b , * prev = NULL ;
for ( b = p - > blocks ; b ; b = b - > next ) {
2001-11-28 17:58:33 +03:00
if ( ( void * ) & b - > data [ 0 ] = = ptr )
2001-11-28 12:13:00 +03:00
break ;
2001-11-28 17:58:33 +03:00
prev = b ;
2001-11-28 12:13:00 +03:00
}
/*
* If this fires then you tried to free a
* pointer that either wasn ' t from this
* pool , or isn ' t the start of a block .
*/
assert ( b ) ;
_free_blocks ( b ) ;
if ( prev ) {
p - > tail = prev ;
prev - > next = NULL ;
} else
p - > blocks = p - > tail = NULL ;
}
2001-12-12 17:25:20 +03:00
void * pool_begin_object ( struct pool * p , size_t init_size )
2001-11-28 12:13:00 +03:00
{
2001-12-12 17:25:20 +03:00
assert ( ! p - > object ) ;
pool_alloc_aligned ( p , hint ) ;
p - > object = 1 ;
2001-11-28 12:13:00 +03:00
}
2001-12-12 17:25:20 +03:00
void * pool_grow_object ( struct pool * p , unsigned char * buffer , size_t delta )
2001-11-28 12:13:00 +03:00
{
2001-12-12 17:25:20 +03:00
struct block * old = p - > tail , * new ;
assert ( buffer = = & old - > data ) ;
if ( ! pool_alloc ( p , old - > size + n ) )
return NULL ;
new = p - > tail ;
memcpy ( & new - > data , & old - > data , old - > size ) ;
old - > next = NULL ;
pool_free ( p , buffer ) ;
_append_block ( p , new ) ;
return & new - > data ;
2001-11-28 12:13:00 +03:00
}
void * pool_end_object ( struct pool * p )
{
2001-12-12 17:25:20 +03:00
assert ( p - > object ) ;
p - > object = 0 ;
2001-11-28 12:13:00 +03:00
}
void pool_abandon_object ( struct pool * p )
{
2001-12-12 17:25:20 +03:00
assert ( p - > object ) ;
pool_free ( p , & p - > tail - > data ) ;
p - > object = 0 ;
2001-11-28 12:13:00 +03:00
}
char * pool_strdup ( struct pool * p , const char * str )
{
char * ret = pool_alloc ( p , strlen ( str ) + 1 ) ;
if ( ret )
strcpy ( ret , str ) ;
return ret ;
}