I've recently realised the best way to share objects into lua and anything the lua code passes those objects onto without the risk of mixing up pointers from different allocation systems (via mistakes or tom-foolery on user side) is to just use a list of IDs/Indexes in the source library and pass those instead, this is what I've come up with so far for abstracting out details that the object management section of the library doesn't need to know while providing a way other sections of the library can determine if they've been given an invalid id or tell the object manager some custom method needs to be called prior to releaseing the memory of the object being managed:
Code:
...
struct paw_block;
typedef void (*paw__forget)( struct PAW *P, struct paw_block *block );
struct paw_block
{
size_t size;
char const *desc;
void *addr;
/* This should ONLY clean the contents of whatever addr points to, the
* memory & index will be realeased by paw__del_block() */
paw__forget forget;
};
struct paw_blocks
{
size_t size;
int have;
int used;
void *ud;
struct paw_block *array;
};
...
#include "_paw.h"
PAW_HIDDEN void paw__del_block( struct PAW *P, int id )
{
if ( id >= 0 )
{
struct paw_block *block = P->blocks->array + id;
if ( block->forget )
block->forget( P, block );
P->alloc( P->ud, block->addr, block->size, 0 );
memset( block, 0, sizeof(struct paw_block) );
}
}
PAW_HIDDEN struct paw_block* paw__get_block( struct PAW *P, int id )
{
if ( id >= 0 )
{
struct paw_blocks *blocks = P->blocks;
if ( blocks && id < blocks->have )
{
return blocks->array + id;
}
}
return NULL;
}
PAW_HIDDEN int paw__new_block
(
struct PAW *P
, char const *desc
, size_t want
, struct paw_block **BLOCK
)
{
int i = 0;
struct paw_block *block = NULL;
struct paw_blocks *blocks = P->blocks;
if ( blocks )
{
for ( ; !block && i < blocks->have; ++i )
{
block = blocks->array + i;
if ( !(block->addr) )
break;
block = NULL;
}
}
if ( !block )
{
size_t need = blocks ? blocks->size + BUFSIZ : BUFSIZ;
void* temp = P->alloc
(
P->ud, blocks, blocks ? blocks->size : 0, need
);
if ( !temp )
return -1;
P->blocks = blocks = temp;
blocks->array = (struct paw_block*)(blocks + 1);
blocks->size = need;
blocks->have =
(need - sizeof(struct paw_blocks)) / sizeof(struct paw_block);
block = blocks->array + i;
}
block->addr = P->alloc( P->ud, NULL, 0, want );
if ( block->addr )
{
block->size = want;
/* Caller is responsible for giving this a non-null value */
block->forget = NULL;
*BLOCK = block;
return i;
}
*BLOCK = NULL;
return -1;
}
Does anyone have any recommendations or faults to point out?