lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


If you need bitfield logic, however, you probably want to build that on top of this (and potentially implement other caching).

Mark

On Dec 17, 2011, at 11:26 AM, Mark Hamburg wrote:

> 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
>