Skip to content

Commit

Permalink
Allow instance data to be passed to the allocator.
Browse files Browse the repository at this point in the history
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 b2188b9
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 42 deletions.
92 changes: 56 additions & 36 deletions mojoshader.c
Expand Up @@ -300,6 +300,7 @@ struct Context
{
MOJOSHADER_malloc malloc;
MOJOSHADER_free free;
void *malloc_data;
const uint32 *tokens;
uint32 tokencount;
OutputList *output;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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

Expand All @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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));
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -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


Expand Down
22 changes: 17 additions & 5 deletions mojoshader.h
Expand Up @@ -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);


/*
Expand Down Expand Up @@ -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;


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


/*
* Parse a compiled Direct3D shader's bytecode.
*
Expand All @@ -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
Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion testparse.c
Expand Up @@ -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);
Expand Down

0 comments on commit b2188b9

Please sign in to comment.