Skip to content
Permalink
Browse files
Allow instance data to be passed to the allocator.
This lets an app, for example, use a separate pool for each parsing, or do
 per-thread allocators, etc.

--HG--
branch : trunk
  • Loading branch information
icculus committed Apr 4, 2008
1 parent 7a60727 commit b2188b91d996bb0b42807704cbe96b768ddd6cc4
Showing with 74 additions and 42 deletions.
  1. +56 −36 mojoshader.c
  2. +17 −5 mojoshader.h
  3. +1 −1 testparse.c
@@ -300,6 +300,7 @@ struct Context
{
MOJOSHADER_malloc malloc;
MOJOSHADER_free free;
void *malloc_data;
const uint32 *tokens;
uint32 tokencount;
OutputList *output;
@@ -338,6 +339,21 @@ struct Context
};


// Convenience functions for allocators...

static inline void *Malloc(Context *ctx, int len)
{
return ctx->malloc(len, ctx->malloc_data);
} // Malloc


static inline void Free(Context *ctx, void *ptr)
{
ctx->free(ptr, ctx->malloc_data);
} // Free



// jump between output sections in the context...

static inline void push_output(Context *ctx, OutputList *section)
@@ -422,7 +438,7 @@ static int failf(Context *ctx, const char *fmt, ...)
const int len = vsnprintf(scratch,SCRATCH_BUFFER_SIZE,fmt,ap);
va_end(ap);

char *failstr = (char *) ctx->malloc(len + 1);
char *failstr = (char *) Malloc(ctx, len + 1);
if (failstr == NULL)
out_of_memory(ctx);
else
@@ -469,11 +485,11 @@ static int output_line(Context *ctx, const char *fmt, ...)
const int len = vsnprintf(scratch+indent, SCRATCH_BUFFER_SIZE-indent, fmt, ap) + indent;
va_end(ap);

item = (OutputListNode *) ctx->malloc(sizeof (OutputListNode));
item = (OutputListNode *) Malloc(ctx, sizeof (OutputListNode));
if (item == NULL)
return out_of_memory(ctx);

item->str = (char *) ctx->malloc(len + 1);
item->str = (char *) Malloc(ctx, len + 1);
if (item->str == NULL)
{
free(item);
@@ -546,12 +562,12 @@ static void floatstr(Context *ctx, char *buf, size_t bufsize, float f,

// Deal with register lists... !!! FIXME: I sort of hate this.

static void free_reglist(MOJOSHADER_free f, RegisterList *item)
static void free_reglist(MOJOSHADER_free f, void *d, RegisterList *item)
{
while (item != NULL)
{
RegisterList *next = item->next;
f(item);
f(item, d);
item = next;
} // while
} // free_reglist
@@ -582,7 +598,7 @@ static void reglist_insert(Context *ctx, RegisterList *prev,
} // while

// we need to insert an entry after (prev).
item = (RegisterList *) ctx->malloc(sizeof (RegisterList));
item = (RegisterList *) Malloc(ctx, sizeof (RegisterList));
if (item == NULL)
out_of_memory(ctx);
else
@@ -3303,7 +3319,7 @@ static int parse_comment_token(Context *ctx)
str = get_scratch_buffer(ctx);
else
{
str = (char *) ctx->malloc(len + 1);
str = (char *) Malloc(ctx, len + 1);
if (str == NULL)
return out_of_memory(ctx);
} // else
@@ -3313,7 +3329,7 @@ static int parse_comment_token(Context *ctx)
ctx->profile->comment_emitter(ctx, str);

if (needmalloc)
ctx->free(str);
Free(ctx, str);

return commenttoks + 1; // comment data plus the initial token.
} // else
@@ -3374,8 +3390,8 @@ static int parse_token(Context *ctx)
} // parse_token


static void *internal_malloc(int bytes) { return malloc(bytes); }
static void internal_free(void *ptr) { free(ptr); }
static void *internal_malloc(int bytes, void *d) { return malloc(bytes); }
static void internal_free(void *ptr, void *d) { free(ptr); }


static int find_profile_id(const char *profile)
@@ -3394,18 +3410,19 @@ static int find_profile_id(const char *profile)
static Context *build_context(const char *profile,
const unsigned char *tokenbuf,
const unsigned int bufsize,
MOJOSHADER_malloc m, MOJOSHADER_free f)
MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
{
if (m == NULL) m = internal_malloc;
if (f == NULL) f = internal_free;

Context *ctx = m(sizeof (Context));
Context *ctx = m(sizeof (Context), d);
if (ctx == NULL)
return NULL;

memset(ctx, '\0', sizeof (Context));
ctx->malloc = m;
ctx->free = f;
ctx->malloc_data = d;
ctx->tokens = (const uint32 *) tokenbuf;
ctx->tokencount = bufsize / sizeof (uint32);
ctx->endline = endline_str;
@@ -3428,14 +3445,14 @@ static Context *build_context(const char *profile,
} // build_context


static void free_output_list(MOJOSHADER_free f, OutputListNode *item)
static void free_output_list(MOJOSHADER_free f, void *d, OutputListNode *item)
{
while (item != NULL)
{
OutputListNode *next = item->next;
if (item->str != NULL)
f(item->str);
f(item);
f(item->str, d);
f(item, d);
item = next;
} // while
} // free_output_list
@@ -3446,17 +3463,18 @@ static void destroy_context(Context *ctx)
if (ctx != NULL)
{
MOJOSHADER_free f = ((ctx->free != NULL) ? ctx->free : internal_free);
free_output_list(f, ctx->globals.head.next);
free_output_list(f, ctx->helpers.head.next);
free_output_list(f, ctx->subroutines.head.next);
free_output_list(f, ctx->mainline.head.next);
free_output_list(f, ctx->ignore.head.next);
free_reglist(f, ctx->used_registers.next);
free_reglist(f, ctx->defined_registers.next);
free_reglist(f, ctx->uniforms.next);
void *d = ctx->malloc_data;
free_output_list(f, d, ctx->globals.head.next);
free_output_list(f, d, ctx->helpers.head.next);
free_output_list(f, d, ctx->subroutines.head.next);
free_output_list(f, d, ctx->mainline.head.next);
free_output_list(f, d, ctx->ignore.head.next);
free_reglist(f, d, ctx->used_registers.next);
free_reglist(f, d, ctx->defined_registers.next);
free_reglist(f, d, ctx->uniforms.next);
if ((ctx->failstr != NULL) && (ctx->failstr != out_of_mem_str))
f((void *) ctx->failstr);
f(ctx);
f((void *) ctx->failstr, d);
f(ctx, d);
} // if
} // destroy_context

@@ -3481,7 +3499,7 @@ static void append_list(char **_wptr, const char *endline,

static char *build_output(Context *ctx)
{
char *retval = (char *) ctx->malloc(ctx->output_len + 1);
char *retval = (char *) Malloc(ctx, ctx->output_len + 1);
if (retval == NULL)
out_of_memory(ctx);
else
@@ -3503,7 +3521,7 @@ static char *build_output(Context *ctx)
static MOJOSHADER_uniform *build_uniforms(Context *ctx)
{
MOJOSHADER_uniform *retval = (MOJOSHADER_uniform *)
ctx->malloc(sizeof (MOJOSHADER_uniform) * ctx->uniform_count);
Malloc(ctx, sizeof (MOJOSHADER_uniform) * ctx->uniform_count);

if (retval == NULL)
out_of_memory(ctx);
@@ -3573,7 +3591,7 @@ static MOJOSHADER_parseData *build_parsedata(Context *ctx)
MOJOSHADER_uniform *uniforms = NULL;
MOJOSHADER_parseData *retval;

if ((retval = ctx->malloc(sizeof (MOJOSHADER_parseData))) == NULL)
if ((retval = Malloc(ctx, sizeof (MOJOSHADER_parseData))) == NULL)
return &out_of_mem_data;

memset(retval, '\0', sizeof (MOJOSHADER_parseData));
@@ -3588,9 +3606,9 @@ static MOJOSHADER_parseData *build_parsedata(Context *ctx)
if (isfail(ctx))
{
if (output != NULL)
ctx->free(output);
Free(ctx, output);
if (uniforms != NULL)
ctx->free(uniforms);
Free(ctx, uniforms);
retval->error = ctx->failstr; // we recycle. :)
ctx->failstr = NULL; // don't let this get free()'d too soon.
} // if
@@ -3608,6 +3626,7 @@ static MOJOSHADER_parseData *build_parsedata(Context *ctx)

retval->malloc = (ctx->malloc == internal_malloc) ? NULL : ctx->malloc;
retval->free = (ctx->free == internal_free) ? NULL : ctx->free;
retval->malloc_data = ctx->malloc_data;

return retval;
} // build_parsedata
@@ -3673,7 +3692,7 @@ const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile,
const unsigned char *tokenbuf,
const unsigned int bufsize,
MOJOSHADER_malloc m,
MOJOSHADER_free f)
MOJOSHADER_free f, void *d)
{
MOJOSHADER_parseData *retval = NULL;
Context *ctx = NULL;
@@ -3682,7 +3701,7 @@ const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile,
if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
return &out_of_mem_data; // supply both or neither.

if ((ctx = build_context(profile, tokenbuf, bufsize, m, f)) == NULL)
if ((ctx = build_context(profile, tokenbuf, bufsize, m, f, d)) == NULL)
return &out_of_mem_data;

// Version token always comes first.
@@ -3715,17 +3734,18 @@ void MOJOSHADER_freeParseData(const MOJOSHADER_parseData *_data)
return; // no-op.

MOJOSHADER_free f = (data->free == NULL) ? internal_free : data->free;
void *d = data->malloc_data;

if (data->output != NULL) // check for NULL in case of dumb free() impl.
f((void *) data->output);
f((void *) data->output, d);

if (data->uniforms != NULL)
f((void *) data->uniforms);
f((void *) data->uniforms, d);

if ((data->error != NULL) && (data->error != out_of_mem_str))
f((void *) data->error);
f((void *) data->error, d);

f(data);
f(data, d);
} // MOJOSHADER_freeParseData


@@ -28,9 +28,12 @@ int MOJOSHADER_version(void);
* These allocators work just like the C runtime's malloc() and free()
* (in fact, they probably use malloc() and free() internally if you don't
* specify your own allocator, but don't rely on that behaviour).
* (data) is the pointer you supplied when specifying these allocator
* callbacks, in case you need instance-specific data...it is passed through
* to your allocator unmolested, and can be NULL if you like.
*/
typedef void *(*MOJOSHADER_malloc)(int bytes);
typedef void (*MOJOSHADER_free)(void *ptr);
typedef void *(*MOJOSHADER_malloc)(int bytes, void *data);
typedef void (*MOJOSHADER_free)(void *ptr, void *data);


/*
@@ -142,6 +145,11 @@ typedef struct
* This is the free implementation you passed to MOJOSHADER_parse().
*/
MOJOSHADER_free free;

/*
* This is the pointer you passed as opaque data for your allocator.
*/
void *malloc_data;
} MOJOSHADER_parseData;


@@ -155,6 +163,7 @@ typedef struct
*/
#define MOJOSHADER_PROFILE_GLSL "glsl"


/*
* Parse a compiled Direct3D shader's bytecode.
*
@@ -169,9 +178,11 @@ typedef struct
* As parsing requires some memory to be allocated, you may provide a custom
* allocator to this function, which will be used to allocate/free memory.
* They function just like malloc() and free(). We do not use realloc().
* If you don't care, pass NULL in for the allocator functions.
* If you don't care, pass NULL in for the allocator functions. If your
* allocator needs instance-specific data, you may supply it with the
* (d) parameter. This pointer is passed as-is to your (m) and (f) functions.
*
* This function returns a MOJOSHADER_parseData
* This function returns a MOJOSHADER_parseData.
*
* This function will never return NULL, even if the system is completely
* out of memory upon entry (in which case, this function returns a static
@@ -186,7 +197,8 @@ const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile,
const unsigned char *tokenbuf,
const unsigned int bufsize,
MOJOSHADER_malloc m,
MOJOSHADER_free f);
MOJOSHADER_free f,
void *d);

/*
* Call this to dispose of parsing results when you are done with them.
@@ -46,7 +46,7 @@ static void do_parse(const unsigned char *buf, const int len, const char *prof)
{
const MOJOSHADER_parseData *pd;

pd = MOJOSHADER_parse(prof, buf, len, Malloc, Free);
pd = MOJOSHADER_parse(prof, buf, len, Malloc, Free, NULL);
printf("PROFILE: %s\n", prof);
if (pd->error != NULL)
printf("ERROR: %s\n", pd->error);

0 comments on commit b2188b9

Please sign in to comment.