Wrapping C 'objects' in tables

The problem

Let’s say you’re managing all your primary data in C. You’ll probably have some C structures (called objects here for brevity) wrapped nicely in userdata proxy objects for access in Lua. But how do you easily get access to the data? Well, there’re a lot of different possibilies here:

  1. You can have functions to find and return individual objects
  2. If your data organisation allows (e.g. if you have lists or trees) you can wrap those data organisation structures as well

But here I’m going to present something much simpler.

A solution

How simple? Very much so, just create a table of all userdata proxies. If you already use lists, arrays or trees you may want to map one level to one table. If you have lots of objects and typically only need few in your processing you might want to add a filter to your table creation.

So how might this look?

static int lget_childs (lua_State *L)
{
        struct my_object_ud *ud;
        struct my_object_ud *tud;
        my_object *obj;
        int i = 1;

        tud = (struct my_object_ud *) luaL_checkudata (L, 1, "myobject");

        lua_newtable (L);

        obj = my_object_get_first_child (tud->o);
        while (obj != NULL)
        {
                ud = (struct my_object_ud *) lua_newuserdata (L, sizeof (*ud));
                ud->o = obj;
                luaL_getmetatable (L, "myobject");
                lua_setmetatable (L, -2);
                lua_rawseti (L, -2, i++);

                obj = my_object_get_next (obj);
        }

        return 1;
}

Here the data is stored in trees and what this function does is take the passed tree node (the userdata the function is called on), retrieves the first child, takes each of the childs and wraps them into a myobject proxy and adds that to a table using the incremented variable i as index. This table is then returned.

Since the userdata setup and the pointer chasing is really lightweight it doesn’t hurt too badly if this is called a few times, but of course further adaptation to the use case or optimization might be worthwhile.

So how do you use that? That’s equally simple:

for _, v in ipairs (fancyobject:childs ()) do
        print (tostring (v))
end

Or you could count the amount of children:

print (#fancyobject:childs ())

NB: lget_childs is set up as the childs function in the metatable of myobject in case you haven’t noted.

In closing

Once the initial setup and mapping of C structure to Lua structures is done it is really easy to reap the benefits by providing transparent and easy access to a table of your userdata proxies. And once you have that your options are almost limitless – you can sort, filter, map, iterate and manipulate your data in any imaginable way and since you’re working on proxy objects in Lua you don’t need to worry at all about allocation, freeing and other nastiness you might face in C.