Alternative C++ binding

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Alternative C++ binding

benjamin sunshine-hill
I've posted a page on the Wiki with code snippets describing a method of easily and flexibly gluing Lua and C++ together without a binding generator, that is conducive to space and execution efficiency. Comments, criticisms, and additions are requested.

http://lua-users.org/wiki/DoItYourselfCppBinding

Ben

P.S. there's a bug in the templated gc, which I wasn't able to edit out; some error when I tried to save the changes.


Reply | Threaded
Open this post in threaded view
|

RE: Alternative C++ binding

Virgil Smith
Looks like a great small start for a binding system.
I have to admit that I'm just now taking some time to look into Lua5 and
convert some personal tools from Lua4 to Lua5, and your "new" trick occurred
to me yesterday.

As for the GC template I have an answer to your problem.
The problem is that it is illegal to directly call destructors.
You have to go through delete.

So, how do you keep delete from deallocating any memory, simple, you just
write a new delete the same way that you wrote a new new.

The trick is that your delete operator will have to take some arguments
(just like your new operator did).  In fact it is at least good form (if not
required by the language, I'm not sure) that your delete operator accepts
the same argument list as your new operator.  This "balances" them, which in
general is a good idea since whatever your "new" new operator did will have
to be undone by your "new" delete operator.  In this case there is nothing
to do.

This may seem weird (as your delete operator will do absolutely nothing in
this case), but it means that you can put...

    delete(L, "") Instance; //OK, I'm not sure if the "size"
    return 0;               // argument should be repeated

in your GC method.

----

One last thing!
You have to get the value of Instance so that you can delete it!
This just means that you have to retrieve the userdata and it cast to T*.


-----Original Message-----
From: [hidden email]
[[hidden email] Behalf Of benjamin
sunshine-hill
Sent: Friday, August 15, 2003 1:48 PM
To: [hidden email]
Subject: Alternative C++ binding


I've posted a page on the Wiki with code snippets describing a method of
easily and flexibly gluing Lua and C++ together without a binding generator,
that is conducive to space and execution efficiency. Comments, criticisms,
and additions are requested.

http://lua-users.org/wiki/DoItYourselfCppBinding

Ben

P.S. there's a bug in the templated gc, which I wasn't able to edit out;
some error when I tried to save the changes.


Reply | Threaded
Open this post in threaded view
|

Re: Alternative C++ binding

Wim Couwenberg-2
> As for the GC template I have an answer to your problem.
> The problem is that it is illegal to directly call destructors.
> You have to go through delete.

No, it's perfectly legal to explicitly call a destructor.  Ben's example
could read something like this:

template<typename T>
int GCMethod(lua_State *L)
{
    T *p = lua_userdata_cast(L, 1, T);
    if (p)
        p->~T();
}

This destructs the instance while Lua takes care of freeing the memory.

--
Wim



Reply | Threaded
Open this post in threaded view
|

RE: Alternative C++ binding

Daniel Wallin-2
In reply to this post by Virgil Smith
At 21:27 2003-08-15, Virgil Smith wrote:
Looks like a great small start for a binding system.
I have to admit that I'm just now taking some time to look into Lua5 and
convert some personal tools from Lua4 to Lua5, and your "new" trick occurred
to me yesterday.

As for the GC template I have an answer to your problem.
The problem is that it is illegal to directly call destructors.
You have to go through delete.

This is of course a completely false statement. The problem with the
template is that he tries to call the destructor without an object.

---
Daniel Wallin


Reply | Threaded
Open this post in threaded view
|

Re: Alternative C++ binding

Wim Couwenberg-2
In reply to this post by Wim Couwenberg-2
> Ben's
> example could read something like this:

>     T *p = lua_userdata_cast(L, 1, T);

Unfortunately, by the clever macro stuff, this will not work at all of
course...  Well, OK...

--
Wim



Reply | Threaded
Open this post in threaded view
|

RE: Alternative C++ binding

Virgil Smith
In reply to this post by Daniel Wallin-2
OK, OK, I checked and I was passing on bad statements.
Explicitly calling destructors is OK.

Now if I can just remember <why> that bad statement was fixed in my belief
system (probably from some screwy compiler).


-----Original Message-----
From: [hidden email]
[[hidden email] Behalf Of Daniel Wallin
Sent: Friday, August 15, 2003 2:58 PM
To: Lua list
Subject: RE: Alternative C++ binding


At 21:27 2003-08-15, Virgil Smith wrote:
>Looks like a great small start for a binding system.
>I have to admit that I'm just now taking some time to look into Lua5 and
>convert some personal tools from Lua4 to Lua5, and your "new" trick
occurred
>to me yesterday.
>
>As for the GC template I have an answer to your problem.
>The problem is that it is illegal to directly call destructors.
>You have to go through delete.

This is of course a completely false statement. The problem with the
template is that he tries to call the destructor without an object.

---
Daniel Wallin


Reply | Threaded
Open this post in threaded view
|

Re: Alternative C++ binding

Wim Couwenberg-2
In reply to this post by Wim Couwenberg-2
> Unfortunately, by the clever macro stuff, this will not work at all of
> course...  Well, OK...

So maybe we could take a more C++ approach (using just a single convenience
macro) along the following lines (operator new remains unchanged):

template<class T> struct lua_traits
{
    static const char *const name;
    // other interesting stuff about T could go here as well...
};

template<class T>
T *lua_userdata_cast(lua_State *L, int pos)
{
    return static_cast<T *>(luaL_checkudata(L, pos, lua_traits<T>::name));
}

template<class T>
int GCMethod(lua_State *L)
{
    T *p = lua_userdata_cast<T>(L, 1);
    if (p)
        p->~T();
    else
        ;  // hum?
    return 0;
}

// this macro just avoids some tedious typing...
#define lua_userdata_type(T) \
    template<> const char *const lua_traits<T>::name = #T

All type specific stuff for T, like its name, goes into lua_traits<T>.  The
lua_userdata_type can quickly introduce the name of T:

    lua_userdata_type(X);  // now lua_traits<X>::name equals "X"

Makes sense??

--
Wim



Reply | Threaded
Open this post in threaded view
|

Re: Alternative C++ binding

Mark Hamburg-4
One thing I've done instead of using luaL_newmetatable, etc. is to use
essentially identical code but with a light user data replacing the string
for the name. If you can count on there being exactly one instance of the
class name, I would presume that this would avoid the cost of the string
canonization on every pass through the API. (Another choice would be to
register the string and store a registry index. That works so long as you
only plan on having one Lua state and threads thereon in your application.)

One thing to watch out for in all of these bindings whether via luaL or an
equivalent such as I've just described is that if you build with something
like LuaThreads, you get a lot of traffic on the mutex which becomes a big
performance hit. My userdata intensive benchmarks suffered a much worse hit
for LuaThreads than did my benchmarks which stuck to straight Lua. (Even the
latter showed a noticeable degradation in performance, but not as dramatic.)

Then one can get into the issue that if you want to store references from
userdata objects to other Lua objects, the best way to do it appears to be
via the metatable for the object. Now you are into a custom metatable per
object which of course further adds to the cost of type-checking when you
come across the Lua boundary. (Sol's method tables look more and more
attractive.)

Don't, however, be tempted to forego the type-checking. I did recently and I
got burned by writing foo.method() instead of foo:method() and ending up
with a crashing bug.

Mark