lua-users home
lua-l archive

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


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.