[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Lua binding: How to implement C enum
- From: Mark Hamburg <mark@...>
- Date: Sat, 17 Dec 2011 11:26:59 -0800
If worrying about speed, the answer is probably to stash a table or two somewhere that can be used to the string-to-enum and enum-to-string mappings. Say, for example, that you define your mapping in C code as something like (untested, uncompiled, written in e-mail, caveat, caveat, caveat):
typedef struct MappingEntry {
const char* text;
int value;
} MappingEntry;
static MappingEntry mapping[] = {
{ "foo", (int) enumFoo },
{ "baz", (int) enumBaz },
{ NULL, 0 }
};
Then you can write C wrappers for converting enums:
static void buildmapping( lua_State* L, MappingEntry* mapping ) {
lua_newtable( L );
for( ; mapping->text != NULL; ++mapping ) {
lua_pushstring( L, mapping->text ); // table text
lua_pushinteger( L, mapping->value ); // table text value
lua_pushvalue( L, -1 ); // table text value value
lua_pushvalue( L, -3 ); // table text value value text
lua_settable( L, -5 ); // table text value
lua_settable( L, -3 ); // table
}
}
static void getmapping( lua_State* L, MappingEntry* mapping ) {
lua_pushlightuserdata( L, mapping );
lua_gettable( L, LUA_REGISTRYINDEX );
if( lua_isnil( L, -1 ) ) {
lua_pop( L, 1 );
buildMappingTable( L, mapping );
lua_pushlightuserdata( L, mapping );
lua_pushvalue( L, -2 );
lua_settable( L, LUA_REGISTRYINDEX );
}
}
int checkenum( lua_State* L, int idx, MappingEntry* mapping ) {
int result = 0;
if( idx < 0 ) {
int top = lua_gettop( L );
if( 0 < idx + top + 1 )
idx = idx + top + 1;
}
getmapping( L, mapping );
lua_pushvalue( L, idx );
lua_gettable( L, -2 );
if( lua_type( L, -1 ) != LUA_TNUMBER ) {
// Signal error here. We got a bad enum value
}
result = lua_tointeger( L, -1 );
lua_pop( L, 2 ); // mapping and result
return result;
}
void pushenum( lua_State* L, MappingEntry* mapping, int value ) {
getmapping( L, mapping );
lua_pushinteger( L, value );
lua_gettable( L, -2 );
lua_remove( L, -2 ); // mapping table
}
In the push case, I suspect this pretty much always wins because it avoids rehashing the string. In the check case, the speed probably depends on how many enum values there are and how expensive the string comparisons are.
Mark