[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Converting strings to enum values (C API)
- From: William Ahern <william@...>
- Date: Thu, 5 Dec 2013 15:12:22 -0800
On Wed, Dec 04, 2013 at 06:04:43PM -0500, Marc Lepage wrote:
> Ah, luaL_checkoption, I knew I had seen that somewhere.
>
> I see it used here:
> http://www.lua.org/source/5.1/lbaselib.c.html#luaB_collectgarbage
>
> I can see it's fairly convenient. However in this case, collectgarbage
> probably isn't (or at least shouldn't) be called a lot. For functions that
> are called a lot, would it be more efficient to pre-create the table of
> strings/values for lookup?
You usually define the table as static const, just like in that code. It's
only built once, at compile-time.
There are other problems with luaL_checkoption, though.
* It's O(N), although except for huge tables this is completely
inconsequential and it would be foolhardy to care about it. (Benchmark it
and prove me otherwise. This also applies similarly to smallish tables
defined in automatic storage and built on function invocation.)
* Enumerations sometimes have gaps, but there's no way to easily specify
gaps, especially when a set is particularly sparse. I can only use
luaL_checkoption a fraction of the time I need to map strings to integer
values. In the best case scenario I end up doing something like:
static const char *table[] = {
[FOO_A] = "a",
[FOO_B] = "b",
[FOO_C] = "c",
[FOO_MAX] = NULL,
};
Using GCC/clang extensions, and where the 0 value (FOO_NONE) means
invalid, I sometimes do something like:
static const char *table[FOO_MAX + 2 /* ensure NULL at end */] = {
[FOO_NONE ... FOO_MAX] = "",
[FOO_A] = "a",
[FOO_B] = "b",
...
};
But most of the time I just create a simple name=value mapping table and
loop over it using a tiny function I copy+paste into my module source files.
Then I export that mapping as part of module, so it's all O(1) at run-time.
Alternatively, it's often cleaner to redefine the interface. For example for
the :shutdown method of my BSD sockets bindings, instead of mapping the C
macros SHUT_RD, SHUT_WR, and SHUT_RDWR, I take a string. It works like
so:shutdown"r", so:shutdown"w", or so:shutdown"rw". Then I use strchr() and
an if-else tree. Simplicity of the interface is far more important to me.