lua-users home
lua-l archive

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


Dear Mr. Conner,

     If I'm understanding how lua_get/setuservalue works, I need the userdata to make it work. Per your example, I would do it so the __index of the userdata's metatable is a function. Then I have access to the userdata and can use `lua_getuservalue` on the userdata to get the lookup table. This is more or less how I was doing it before (except instead of using a lua table with lua_getuservalue, I was looking up into a std::map/boost::map of functions/variables I had stored with the userdata).

     The performance bottleneck wasn't the lookup (I had reduced the performance impact to nothing by switching from a C++ unordered_map to a map since there were a very small number of elements and then using "transparent lookup" introduced in the new C++ standard for `map` to not have to create a temporary string). The performance bottleneck for the member function implementation was having to return the retrieved function to lua so it could then call it again when doing `myfoo:blah()`. (If that makes sense).

     Since I already had it working before, my goal here isn't whether or not I can do it (I know a way to do it, like the way you said, which makes me somewhat happy that I'm on the right track here!), but I'm trying to get the utmost performance possible, so that this code has no overhead compared to regular C code. This is why I'm trying not to drop into a C function unless I absolutely have to (e.g., with the uncommon case of using member variables in lua code).

     As a side question, is it possible to set fields to a userdata directly? When I tried I seemed to crash lua, so I don't think I could set the member functions as "fields" on the userdata itself and then have the __index function like you described?

On Wed, Feb 17, 2016 at 2:17 AM, Sean Conner <sean@conman.org> wrote:
It was thus said that the Great JeanHeyd Meneide once stated:
>      I hope this message finds you well.
>
>      I am developing a lua <-> C++ binding (like the several other that
> exist), and I've made significant headway into getting a very performant
> and easy to use wrapper. My final challenge in increasing the performance
> comes from trying to make basic "variable" get/sets on userdata made by C
> code work.
>
>      The Question: Is there a way to get the original object that a lookup
> was performed on in a cascading series of `__index` queries? Right now, lua
> hands you the current object in the `__index` cascade that lookup failed on
> and the key name it is trying to find. This is all well and good and based
> on the specification, but my problem is that I want what the original
> lookup failed on (e.g. the userdata that started it all, in my case).
>
> This tree might help explain what my dilemma is (pseudo code):
>
> myuserdata -- userdata
> myuserdata.mt -- metatable
> myuserdata.mt.__index -- table
> myuserdata.mt.__index.mt -- second metatable
> mysuserdata.mt.__index.mt.__index -- function that performs variable lookup
>
> When I do
> myuserdata.x -- cascades down to second function, but the provided "lookup
> failed" argument is userdata.mt.__index, the table, not myuserdata. How do
> I get to 'userdata' ?

  It sounds like you might want to use lua_setuservalue()/lua_getuservalue()
(available in Lua 5.2 or higher).  With this, you can associate an addtional
table with your userdata (while sharing a metatable with all instances of a
given userdata type).  Then your __index method (a function) can call
lua_getuservalue() to get a table just for that instance where you can fetch
values from.  Something like:

static int myfoo___index(lua_State *L)
{
  /*----------------------------------------
  ; Assuming that the value associated with the userdata is a Lua table.
  ; Then push the key being looked for onto the stack, and reference said
  ; table for said value.  Once it's on the stack, we can return.
  ;--------------------------*/

  lua_getuservalue(L,1);
  lua_pushvalue(L,2);
  lua_gettable(L,-2);
  return 1;
}

  -spc