Code Monkey home page Code Monkey logo

luabridge's Introduction


LuaBridge 2.8

LuaBridge is a lightweight and dependency-free library for mapping data, functions, and classes back and forth between C++ and Lua (a powerful, fast, lightweight, embeddable scripting language). LuaBridge has been tested and works with Lua revisions starting from 5.1.5, although it should work in any version of Lua from 5.1.0 as well as LuaJit.

LuaBridge offers the following features:

  • MIT Licensed
  • A printable Reference Manual.
  • Headers-only: No Makefile, no .cpp files, just one #include!
  • Simple, light, and nothing else needed (like Boost).
  • No macros, settings, or configuration scripts needed.
  • Supports different object lifetime management models.
  • Convenient, type-safe access to the Lua stack.
  • Automatic function parameter type binding.
  • Easy access to Lua objects like tables and functions.
  • Written in a clear and easy to debug style.

Please read the LuaBridge Reference Manual for more details on the API.

Unit Tests

Unit test build requires a CMake and C++11 compliant compiler.

To enable C++17 features (std::optional and std::string_view) specify an extra option: -DLUABRIDGE_CXX17=1.

There are the following unit test flavors:

  • Tests51 - uses Lua 5.1.5
  • Tests51Cxx17 - uses Lua 5.1.5 and C++17 features
  • Tests52 - uses Lua 5.2.4,
  • Tests52Cxx17 - uses Lua 5.2.4 and C++17 features
  • Tests53 - uses Lua 5.3.6
  • Tests53Cxx17 - uses Lua 5.3.6 and C++17 features
  • Tests54 - uses Lua 5.4.4
  • Tests54Cxx17 - uses Lua 5.4.4 and C++17 features

Build using Make on Linux/MacOS:

clone --recurse-submodules [email protected]:vinniefalco/LuaBridge.git
cd LuaBridge
cmake -DCMAKE_BUILD_TYPE=Debug -B build
# or cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -B build
# or cmake -DCMAKE_BUILD_TYPE=Release -B build
cd build
make -j

Generate XCode project on MacOS:

clone --recurse-submodules [email protected]:vinniefalco/LuaBridge.git
cd LuaBridge
cmake -G Xcode -B build
# Generates XCode project build/LuaBridge.xcodeproj

Generate MSVS solution on Windows:

clone --recurse-submodules git@github.com:vinniefalco/LuaBridge.git
cd LuaBridge
mkdir build
cd build
cmake -G "Visual Studio 17 2022 Win64" -B build
# or cmake -G "Visual Studio 15 2017 Win64" -B build
# or cmake -G "Visual Studio 14 2015" -B build
# or cmake -G "Visual Studio 15 2017 Win64" -B build
# or cmake -G "Visual Studio 15 2017" -B build
# or cmake -G "Visual Studio 15 2019" -A Win64 -B build
# or cmake -G "Visual Studio 15 2019" -B build
# Generates MSVS solution build/LuaBridge.sln

Installing LuaBridge (vcpkg)

You can download and install LuaBridge using the vcpkg dependency manager:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh # The name of the script should be "./bootstrap-vcpkg.bat" for Powershell
./vcpkg integrate install
./vcpkg install luabridge

The LuaBridge port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.

Official Repository

LuaBridge is published under the terms of the MIT License.

The original version of LuaBridge was written by Nathan Reed. The project has been taken over by Vinnie Falco, who added new functionality, wrote the new documentation, and incorporated contributions from Nigel Atkinson.

For questions, comments, or bug reports feel free to open a Github issue or contact Vinnie Falco directly at the email address indicated below.

Copyright 2019, Dmitry Tarakanov
Copyright 2012, Vinnie Falco (<[email protected]>)
Copyright 2008, Nigel Atkinson
Copyright 2007, Nathan Reed

Portions from The Loki Library:
Copyright (C) 2001 by Andrei Alexandrescu

Older versions of LuaBridge up to and including 0.2 are distributed under the BSD 3-Clause License. See the corresponding license file in those versions (distributed separately) for more details.

luabridge's People

Contributors

abouvier avatar asomfai avatar chernikovdmitry avatar d-led avatar dmitry-t avatar frankxie05 avatar fulgen301 avatar grandmother avatar luzpaz avatar mcb2003 avatar nikita-yfh avatar pinemarten avatar progschj avatar redbaron avatar reedbeta avatar ricanteja avatar rpatters1 avatar ryanel avatar shenyalei avatar skabyy avatar stefanfrings avatar timgates42 avatar tobiasfunk avatar toski avatar tungfaifong avatar vinniefalco avatar xrl1 avatar zeromus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

luabridge's Issues

LuaBridge version defines

I was just changing my version reporting function, and I didn't see any version defines LuaBridge. Would be trivial to add..

#define LUABRIDGE_VERSION_MAJOR 2
#define LUABRIDGE_VERSION_MINOR 0

Or something to that effect. Its useful for switching code in or out, making strings for display etc, etc

Question: Number of base classes supported

From reading the docs and looking at the source it would seem to me that the library only supports classes with a single base using deriveClass. Is this correct and if so is there some other method that I have not seen to support more base classes?
Thanks

Ownership management policies

Hi Vinnie,

I think it makes sense to continue the discussion here.

Your suggestion to implement policies was the following:

classname can be expanded to include a policy. Given:

struct Policy
{
  virtual void push () = 0;
  virtual void addref () = 0;
  virtual void release () = 0;

  template <class PolicyType>
  static Policy* getPolicy ()
  {
    static PolicyType policy;
    return &policy;
  }
};

We can add this:

template <typename T>
struct classname
{
  static inline Policy& policy()
  {
     return *classname <T>::m_policy;
  }
  template <class PolicyType>
  static inline void set_policy ()
  {
    classname <T>::m_policy = &Policy::getPolicy <PolicyType> ();
  }

private:
  static PolicyType* m_policy;
};

template <typename T>
PolicyType* classname <T>::m_policy = Policy::getPolicy <DefaultPolicy> ();

Then we expand class__ to include an additional PolicyType template parameter, and set the policy in the classname at the same time we associate the name with it:

template <typename T, class PolicyType>
class__<T>::class__ (lua_State *L_, const char *name_): scope(L_, name_)
{
  assert(!classname<T>::is_const());
  classname<T>::set_name(name_);
  classname<T>::set_policy <typename PolicyType> ();

Here are some examples of code using this scheme:

s.class_ <test3> ("test3").method ("f", &test3::f); // default policy
s.class_ <test3, BoostSharedPtrPolicy> ("test3").method ("f", &test3::f); // use boost::shared_ptr
s.class_ <test3, CustomPolicy> ("test3").method ("f", &test3::f); // use domain specific policy
s.class_ <test3, ImmortalPolicy> ("test3").method ("f", &test3::f); // straight pointer with no ref count policy

Comments, criticisms?

Documentation error

In 2.2 Data, Properties, Functions, and CFunctions

...
std::string stringProperty;
std::string getString () { return stringProperty; }
void setString (std::string s) { return s; }

Last line should be:
void setString (std::string s) { stringProperty = s; }

Another way to overload

class A {
public:
    int test(string s);
    int test(int s);
}

getGlobalNamespace (L)
  .beginNamespace ("asd")
    .beginClass<A>("A")
      .addConstructor <void (*)(void)> ()
      .addFunction("tests", (int (A::*)(string)) &A::test)
      .addFunction("testi", (int (A::*)(int)) &A::test)
    .endClass()
  .endNamespace ();

Now just need a simple lua function to choose the right class method.

It's easy and not need to change a lot.

Register functions that take a Lua state

Suggestion by Vinnie:

It seems that it would be useful if a member function that accepts the lua_State* coming from the C function proxy could be registered, like this:

struct test3
{
  static void run (TestHost& host)
  {
    ScopedLuaTestState L (host);

    luabridge::scope s (L);

    s.class_ <test3> ("test3")
      .constructor <void (*) (void)> ()
      .method ("f", &test3::f);

    L.dostring ("test3 (): f();");
  }

  test3 ()
  {
  }

  // How would this work?
  void f (lua_State* L_)
  {
    LuaStateWrapper L (L_);

    L.print ("test3");
  }
};

What are your thoughts on that?

Passing nil to C++ methods

Passing null to C/C++ methods or specifying null as a default argument is very common. This is problematic as LuaBridge doesn't support passing nil to methods. I hacked in some support for this and it seems to work. I am wondering what the implications are in supporting this as it is mentioned in the documentation. Passing nil/null is extremely common in both Lua and C++ and these map very well, is this a temporary limitation?

Using lua functions as parameter/property

Is it possible to declare a lua function as property value?

I tried following:

static int refhandler = 0;

static int getHandler(lua_State* L)
{
return 0;
}

static int setHandler(lua_State* L)
{
luaL_unref(L, LUA_REGISTRYINDEX, refhandler);
luaL_checktype(L, 1, LUA_TFUNCTION);
lua_pushvalue(L, 1); //dup
refhandler = luaL_ref(L, LUA_REGISTRYINDEX);
return 0;
}

getGlobalNamespace(L)
.beginNamespace("test")
.addProperty("handler", getHandler, setHandler)
.endNamespace();

But, it doesn't compile.

Minor patch for userdata.h

commit a5b8e37804f23c1441d7c80452887b3baba39ced
Author: Ryan Ginstrom [email protected]
Date: Mon May 20 10:03:51 2013 -0700

!mismatch will always be true.

diff --git a/Source/LuaBridge/detail/Userdata.h b/Source/LuaBridge/detail/Userdata.h
index be87f90..19451bd 100644
--- a/Source/LuaBridge/detail/Userdata.h
+++ b/Source/LuaBridge/detail/Userdata.h
@@ -96,7 +96,7 @@ private:
assert (lua_istable (L, -1));

 // Make sure we have a userdata.
  • if (!mismatch && !lua_isuserdata (L, index))
  • if (!lua_isuserdata (L, index))
    mismatch = true;

// Make sure it's metatable is ours.

Replace upvalues with compile time instantiations

This is a continuation of the discussion from another issue:

Marton wrote:
Nice. I am reading your code now. In my modifications to luabridge (internal unfortunately) I have had some of the same ideas as you did. For example, to key metatables using process-wide unique ids, only that mine are generated via

template <typename T>
inline void* class_id()
{
    struct x {};
    return (void*) typeid(x).hash_code();
};

But hash_code needs C++11. Your solution might be easier on memory, since typeid() generates a string internally, however, I don't know if it's not optimized away. Also, to get the ID of a const T, I simply use class_id(const T).

Also me I put the const methods additionally into the non-const metatable to save one lookup.

If I'm not mistaken, you also implemented the change I did too, to leave a class and its metatables on stack when registering its methods, to avoid looking it up every time.

Additionally to your changes, I got rid of all closures when pushing the proxies and to calculate the class uid inside the proxies on the fly. It might be faster (haven't benchmarked it though) and for sure it simplifies code.

size_t not working on Windows 64 bit, but works okay on Linux 64, Win 32

Passing a function that returns or uses size_t as a type crashes luabridge in 64 bit windows, when cross compiling with mingw.

Example output (in wine):
DoTest
Assertion failed!

Program: Z:\home\twigger\turf\src\test\luatest\luatest64.exe
File: external/luabridge/detail/Userdata.h, Line 189

Expression: lua_istable (L, -1)

abnormal program termination

I have verified that this doesn't work on a win 7 box, but the cross compiled 32 bit target version does.

Below is my test setup, containing test code, makefiles and precompiled executables:
www.snapperthetwig.com/stuff/luatest.zip

Proper way to add a custom class property ?

Hello,

Let's say I have this:

// Taken from Cocoa Core Graphics
struct CGPoint {
  CGFloat x;  // typedef float CGFloat;
  CGFloat y;
};

class Scene
{
private:
    CGPoint _position;
public:
    void setPosition(CGPoint position) { _position = position; }
    CGPoint &getPosition() const { return _position; }
};

How can I expose that getter/setter as properties ?

Would be great to be able to do something like:

luabridge::getGlobalNamespace(L)
    .beginClass<Scene> ("Scene")
        .addProperty ("position", &Scene::getPosition, &Scene::setPosition)

Additional trait to allow use of shared_ptr

So, the way I understand it the issue with using shared_ptr as container is that there is a priory no way to cleanly create a shared_ptr from a raw ptr (since there could already be another shared_ptr we don't know about). Now in a class that has been accordingly "instrumented" with a method to obtain a shared_ptr (shared_from_this) this could be circumvented though if we could provide a method that tells LuaBridge how to obtain that shared_ptr.
Essentially in addition to a trait that tells LuaBridge how to get a raw pointer form a container there could also be a trait for the inverse operation.

The concept is sketched in this commit: progschj@b0c51a9
(I couldn't really figure out what the trait should be called so I just added a 2)

And here is an example how the usage could look like: https://gist.github.com/4570574

const member functions not recognized as const

It seems that const member functions still get thrown into the regular metatable instead of the __const metatable. Looking through the code, I can't find anything having to do with providing a const "this" pointer to member functions.

Retrieving a pointer with the proper const-ness from a methodProxy is trivial (call getConst() instead of get() to obtain the class pointer). But how to detect when a member function is const?

Object lifetime management

JoshEngebretson wrote:

"Vinnie: Right, but what I am saying is Lua being able to control C++ lifetime. I exposed a virtual deletePointer on Userdata and am able to cleanup native, explicitly, from Lua. This is very useful and was easy to modify LuaBridge to handle.

It is pretty common to get back a pointer in client code that you are supposed to explicitly handle the lifetime.

I am mentioning it in case it sparks any ideas, but I am totally happy with how easy it was to wire this in... and the custom container stuff is simply awesome :)"

THROWSPEC issues with Clang and GCC

Had to manually #undef THROWSPEC while using the latest Clang and GCC.

To fix this issues, simply blacklist them, before you #define THROWSPEC, similar to this:

864 #if defined (__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__clang__) || defined(__GNUC__)

Don't know how specific you have to be, e.g. about the GCC Version number.
But the fix above is good enough for our intergration.

Provided error messages:

LuaBridge.h:1429:8: error: redefinition of โ€˜struct luabridge::FuncTraits<R (*)(), D>โ€™
LuaBridge.h:1015:8: error: previous definition of โ€˜struct luabridge::FuncTraits<R (*)(), D>โ€™

and so on..

Newbie - Juce and LuaBridge, how to return array of c++ objects to Lua

Hey Vinnie, Graeme from the Juce forums here. I'm trying to give Lua a go using Luabridge and have found myself a bit lost. I don't like asking newbie questions but I'm not sure which direction to go in so a bit of guidance would be greatly appreciated.

I can call a juce function from Lua and pass in parameters, that works. But now I'm trying to return a list of objects to lua and I'm unsure of how to do it properly. I've read up on some Lua stuff about tables and working with the stack but it seems like I'm operating outside of the LuaBridge constructs. My biggest problem at the moment is not knowing if I'm using LuaBridge wrong, or if I just need to keep studying using the Lua Capi to accomplish it correctly. i.e. Is there a LuaBridge way of returning a bunch of objects to Lua?

This is how I'm attempting to "return" the list to Lua. It's just pieced together from an example on StackOverflow. http://stackoverflow.com/a/840468

void MyJuceClass::get(std::string param) {

    //...do matching stuf...

    //...create a lua table and set the objects on the stack
    lua_createtable(L, matches.size(), 0);
    int newTableIndex = lua_gettop(L);

    for (int i = 0; i < matches.size(); i++) {
        UXComponent * ux = matches.getUnchecked(i);
        luabridge::push(L, ux);
        lua_rawseti(L, newTableIndex, i + 1);
    }
}

constructor/addConstructor functions do not compile with Visual Studio 2010

A simple example:
class TestClass
{
public:
TestClass(int id)
:_Id(id)
{}
virtual ~TestClass()
{}

void run()
{}
int _Id;

};

...
luabridge::scope s(lua_state);
s .beginClass ("TestClass")
.addConstructor<void (*) (int)> ()
.addMethod("run", &TestClass::run);

will not compile on Visual Studio 2010 (and 2005 I guess)
with the following error:
error C2783: 'luabridge::Namespace::Class &luabridge::Namespace::Class::addConstructor(void)' : could not deduce template argument for 'C'

Is there a workaround to explicetly tell the compiler the Type of C?

LuaRef v = new A;

Hey Vinnie, I'm trying to return a new C++ object to Lua. The luabridge manual says that I can do this with LuaRef using a registered class, but when I try I get a compile error saying "No viable conversion from 'NamQuery *' to 'luabridge::LuaRef'.

I have the class registered with:

        .beginClass<NamQuery>("NamQ")
            .addFunction("set", &NamQuery::set)
            .addFunction("onClick", &NamQuery::onClick)
            .addFunction("toggleVisible", &NamQuery::toggleVisible)
            .addFunction("each", &NamQuery::each)
            .addFunction("eq", &NamQuery::eq)
        .endClass();

And I try to instantiate it like this:

LuaRef v = new NamQuery();

I've run the Unit tests successfully, but there doesn't appear to be a test that uses the same syntax as the example in the manual.

Cannot pass from C++ published classes as argument in Lua ?

I got a small vector class and I have some calculation functions in there like Add. It just adds two vectors and returns the one who called the function. But Lua says

-- main.lua:5: bad argument #2 to 'Add' (TexVector expected, got table)

the main.lua is:

Cheap.Moo( ) -- for generall printing test

a = Cheap.TexVector( 1, 2 )
b = Cheap.TexVector( 3, 4 )
a.Add( b )
print( a.X, a.Y, b.X, b.Y )

So what's the problem there ?

LuaRef, access table keys

Hey Vinnie, is there a means to iterate over a LuaRef and access keys and values? Like pairs() or ipairs()? I'd like to pass lua tables to juce to populate css-like data.

e.g.
in lua:

cssstyle = {
  background = "ff336688",
  font_size = 11,
  font_name = "Arial"
}

in juce: (something to this effect)

void doMap(LuaRef v) {

    HashMap<String, String>::Iterator it (v);

    while (it.next()) {
            String keyId = it.getKey();
            String val = it.getValue();
            //dostuff
    }

}

Setting table variable to an initialized class ?

Hello,

I'm currently binding my GameEntity Class like this

.beginClass<GameEntity> ("GameEntity")
    .addConstructor<void (*) (void)> ()
    .addFunction("setGEC", &GameEntity::setGEC)
    .addProperty("id", &GameEntity::getId)
    .addProperty("active", &GameEntity::getIsActive, &GameEntity::setIsActive)
    .addProperty("x", &GameEntity::getPositionX, &GameEntity::setPositionX)
    .addProperty("y", &GameEntity::getPositionY, &GameEntity::setPositionY)
.endClass();

I'm trying to do something like this on the Lua side:

entity = GameEntity()
entity.components = {}

But I get an error:

SampleFile.lua:23: no member named 'components'

Is there a way to circumvent this issue ?

LuaBridge not "recognizing" types across translation units

Here is the testcase: https://gist.github.com/4564649
Basically if the class registration happens in another translation unit (.cpp fiie) than it is used it will not recognize the types correctly. When I run that testcase (gcc 4.6 on linux) I get:

Error: [string "a = test.A()..."]:2: bad argument #1 to 'printA' (A expected, got userdata)

It works though if the content of A.cpp is put into main.cpp instead.

Need unit tests

With all of the new features and changes, the unit tests are outdated. They need to be rewritten. Each unit test should run in a fresh lua state and provide a line of output describing the test and the pass/fail.

The unit tests should be implemented as a class template so that the test suite can be re-run with different template parameters, such as the choice of shared_ptr container to use.

Primitive type references as return values/arguments of member functions

I tried something along the lines of:

template<class T>
void lua_register_vector(lua_State *L, std::string name)
{
    using namespace luabridge;

    T& (std::vector<T>::*at_ptr)(size_t) = &std::vector<T>::at;

    getGlobalNamespace (L)
    .beginNamespace ("std_vector")
        .beginClass < std::vector<T> > (name.c_str())
            .addProperty ("size", &std::vector<T>::size)
            .addFunction ("at", at_ptr)
        .endClass ()
    .endNamespace ();
}

If T is a primitive type, calling :at on such a vector in lua results in assertions like:

"LuaBridge/LuaBridge.h:2711: static void luabridge::Detail::UserdataPtr::push(lua_State_, void_, const void*): Assertion `(lua_type(L, (-1)) == 5)' failed."
(note how the line number refers to a line with an assertion but not the one that has lua_type in its call... weird)

It seems to work perfectly fine when T is a registered other class though.
I get the same behaviour from trying to register methods that take references to primitive types as arguments.

From quickly skipping though the code I get the impression this is connected with Stack using the T& specialization in these cases while assuming T is a registered class, which the primitive types aren't?

Constructor :new does not work ?

I tried to publish my constructors of my Vertex-Object

luabridge::getGlobalNamespace( L ).
    beginNamespace( "Cheap" ).
        beginClass< Cheap::Math::TexVector >( "TexVector" ).
            addConstructor< void (*) ( ) >( ).
            addConstructor< void (*) ( const double , const double ) >( ).
        endClass( ).
    endNamespace( );

everything works well but it always says that the :new member of Cheap:TexVector is nil and no function. I fixed this with own functions which takes the same parameters as the constructors and returns the constructed result. I always used Object:new in Lua why seems not be supported ?

Extending __index and __newindex

partly inspired by the discussion in #22

the metamethods are rightfully protected by LuaBridge. However, I was thinking about simplifying Lua-side syntax of getter methods in some cases. Imagine having a class

class Map {
...
std::string Get(const char * key) {...}
...
}; 

in Lua that would be then something like map:Get('bla'), however, it could be nicer to write map.bla. Perhaps I'm overlooking a lua-side solution, but wouldn't it be a nice feature for the LuaBridge classes to be extendable in this sense on demand?

In class definition, one could offer a handler for __index and __newindex like .addIndexHandler(&Map::Get). What would be missing in this naive signature is the way to handle the case if the IndexHandler should exit without returning a value, instead letting the standard mechanism continue.

What do you think?

Reflection Interface

I currently using LuaBridge with great success. There is one feature however all users could need: Reflection
The problem with the script interfaces is that they have to be known on the lua-side in detail. I could imagine an interface that allows inspection of registered classes/functions which would return a textual representation of the class/function and the parameters.
Of course we would need to put additional information into the C++-registration part.

I.e. given a namespace ns:

ns.help ->

class MyClass;

ns.MyClass.help ->
MyClass
{
function addFoo(double foo double bar);
function addBar();
}

ns.MyClass.addFoo.help

addFoo(double foo double bar);

What do you think about something like this? Th example above might not be the best way to do it, and I realize I could provide the help functon on my own, but this way I'd have to keep it in sync if I change the interface. At least the function names and parameters could be derived "automagically" as they are put to a table somewhere.

addFunction(name, std::function<R(Args...)>

Another possible usage case:

  • A Lua script might post events with data like a long running computation (something like that, but in a generealized form).
  • The observer of the values is on the C++ side
  • In order to use the observer, one needs a handle to it. In case it's created on the Lua side, it has to be smart to register itself somehow. In other case, one might use static global functions as a channel for the observed values, but then one would need to find the observer again using some kind of matching, i.e. on the basis of the lua_State pointer

Hence, one possibility could be something like that:

.addFunction("NextNumber",std::bind(&Observer::NextNumber,observer,_1)

whereas in Lua that would just mean

local function Compute()
 ...
 NextNumber(42)
 ...
end

I've tried to devise a solution in LuaBridge, but to no avail yet

Memory leak with luabridge::shared_ptr on errors

It seems that when an error occurs during the execution of a bound function, the reference count on a luabridge_shared_ptr object is not adjusted. There's no clean up code for this. When using a compliant container like std::shared_ptr, and Lua is compiled by C++ (in order to use exceptions for properly unwinding the stack, instead of longjmp), memory leaks do not occur when errors are thrown.

We need to decide what to do with the luabridge::shared_ptr implementation. It seems outdated and pointless, but so far none of the changes to LuaBridge have broken any existing code. Taking shared_ptr out might break them.

stdint.h not needed

Perhaps, one could remove the #include <stdint.h> dependency in RefCountedPtr.h

LuaJIT and 5.1 compatibility

Hello,

Thank you for the amazing work you have done on getting LuaBridge 1.0 polished up and improved :)

A lot of folks are on Lua 5.1 and if you're using LuaJIT the 5.2 API isn't available.

Fortunately, this is simple to remedy in LuaBridge right now (and likely in the future) as only some cosmetic 5.2 functions are used. Here are some back ports of these 3 methods to 5.1

// 5.1 backport of 5.2 stuff

/*
** convert an acceptable stack index into an absolute index
*/
LUA_API int lua_absindex (lua_State *L, int idx) {
  return (idx > 0 || idx <= LUA_REGISTRYINDEX)
         ? idx
         : cast_int(L->top - L->ci->func + idx);
}

LUA_API void lua_rawgetp (lua_State *L, int idx, const void *p) {

    idx = lua_absindex(L, idx);
    lua_pushlightuserdata(L, (void *) p);
    lua_rawget(L,idx);

}

LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {

    idx = lua_absindex(L, idx);
    lua_pushlightuserdata(L, (void*) p);
    // put key behind value
    lua_insert(L, -2);
    lua_rawset(L,idx);
}

Using beginClass more than once on the same class

This used to work in the previous incarnation of luabridge (and the docs say it should still work)... Taking the example from the docs - chapter 2.3 (which incidentally is incorrect - does not compile out of the box) - and splitting into two:

  getGlobalNamespace (L)
  .beginNamespace ("test")
  .beginClass <A> ("A")
  .endClass ()
  .endNamespace ();

  getGlobalNamespace (L)
  .beginNamespace ("test")
  .beginClass <A> ("A")
  .addStaticData ("staticData", &A::staticData)
  .addStaticProperty ("staticProperty", &A::getStaticProperty, &A::setStaticProperty)
  .addStaticFunction ("staticFunc", &A::staticFunc)
  .addStaticCFunction ("staticCFunc", &A::staticCFunc)
  .addData ("data", &A::dataMember)
  .addProperty ("prop", &A::getProperty, &A::setProperty)
  .addFunction ("func1", &A::func1)
  .addFunction ("virtualFunc", &A::virtualFunc)
  .addCFunction ("cfunc", &A::cfunc)
  .endClass ()
  .deriveClass <B, A> ("B")
  .addData ("data", &B::dataMember2)
  .addFunction ("func1", &B::func1)
  .addFunction ("func2", &B::func2)
  .endClass ()
  .endNamespace ();

ends up taking the else branch of the class registration ctor as expected (Namespace.h:486) but then hits an assert in the 2nd rawgetfield:

  else
  {
    rawgetfield (L, -1, "__class");
    rawgetfield (L, -1, "__const");

    // Reverse the top 3 stack elements
    lua_insert (L, -3);
    lua_insert (L, -2);
  }

Any ideas?

Mike

Stack::is_a

I think it would be useful to have a is_a function in the stack class, that allows to check whether the object at the given position has a specific type (mimicking the lua_isnumber etc. functions). I tried figuring out how to implement that (I assume it would essentially be similar to the get function without actually pulling the value?) but don't understand the details well enough.

Support for overloaded functions

It would be great to support overloaded functions. An easy way to do it would be to replace the call to rawsetfield after pushing a closure (when registering a method or function) by a call to set_overload. This function is equivalent to rawsetfield if the key is not taken yet. But if the key is taken, it replaces its value by a special function with a table of possible overloads as upvalue:

/*
 * Adds the function at stack top to the table at idx and pops it.
 * If the name is already taken, it adds it as an overload.
 */

void add_overload(lua_State* L, int idx, const char* name)
{    
    if (idx<0)
        idx = lua_absindex(L, idx);

    assert(lua_isfunction(L, -1));

    // try to access the name
    rawgetfield(L, idx, name);

    // if name doesn't exist yet: store it as a regular cfunction
    if (lua_isnil(L, -1))
    {
        lua_pop(L, 1);
        rawsetfield(L, idx, name);
        return;
    }

    // if name exists already, it must be a function
    assert(lua_isfunction(L, -1));

    // stack: -1: old func, -2: new func
    static const char tag[] = "__ovl";

    // test if the current value of idx[name] is already the special function 
    bool needs_setup = true;
    if (lua_getupvalue(L, -1, 2))
    {
        if (lua_type(L, -1) == LUA_TSTRING) {
            lua_pushlstring(L, tag, sizeof(tag)-1);
            needs_setup = !lua_rawequal(L, -1, -2);
            lua_pop(L, 2);
        } else
            lua_pop(L, 1);
    }

    if (needs_setup) {
        // the old closure is a normal function:
        // create new closure of try_overloads with new table
        lua_createtable(L, 4, 0);    // reserve space for 4 overloads
        lua_pushvalue(L, -3);        // push the new function
        lua_pushvalue(L, -3);        // push the original function
        lua_rawseti(L, -3, 1);       // store orig as the table's 1st entry
        lua_rawseti(L, -2, 2);       // store new as the table's 2nd entry
        lua_pushlstring(L, tag, sizeof(tag)-1);
        lua_pushcclosure(L, &try_overloads, 2);
        rawsetfield(L, idx, name);
    } else {
        // the old closure already points to &try_overloads:
        // simply add a new entry to its table
        lua_getupvalue(L, -1, 1);    // get 1st upvalue of the closure
        assert(lua_istable(L, -1));  // it must be a table
        int n = lua_rawlen(L, -1);   // get the number of entries in the table
        lua_pushvalue(L, -3);        // push the new function
        lua_rawseti(L, -2, n+1);     // and store it as the table's next entry
        lua_pop(L, 1);               // pop the table
    }

    lua_pop(L, 2); // pop new and original function
}

The special function for overloads is called try_overloads. Its upvalue is a table of closures, they are all tried until one of them finishes without an error. If all fail, their error messages are concatenated.

/*
 * Callback that is called when a function with overloads is called from Lua
 */

static int try_overloads(lua_State* L)
{
    int nargs = lua_gettop(L);

    // get the list of overloads
    lua_pushvalue(L, lua_upvalueindex(1));
    assert(lua_istable(L, -1));
    const int idx_ovl = nargs + 1;

    // create table to hold error messages
    lua_createtable(L, 8, 0);
    const int idx_err = nargs + 2;
    int nerr = 0;

    // iterate through table, snippet taken from Lua docs
    lua_pushnil(L);  // first key
    while (lua_next(L, idx_ovl) != 0)
    {
        assert(lua_isfunction(L, -1));

        //push arguments
        for (int i=1; i<=nargs; ++i) lua_pushvalue(L, i);

        // call f, this pops the function and its args, pushes result(s)
        int err = lua_pcall(L, nargs, LUA_MULTRET, 0);

        if (err == LUA_OK) {
            // calculate number of return values and return
            int nres = lua_gettop(L) - nargs - 3; // 3: overloads, errors, key
            return nres;
        } else if (err == LUA_ERRRUN) {
            // store error message and try next overload
            lua_rawseti(L, idx_err, ++nerr);
        } else {
            return lua_error(L);  // critical error: rethrow
        }
    }

    lua_Debug debug;
    lua_getstack(L, 0, &debug);
    lua_getinfo(L, "n", &debug);
    lua_pushfstring(L, "All %d overloads of %s returned an error:", nerr, debug.name);

    // Concatenate error messages of each overload
    for (int i=1; i<=nerr; ++i)
    {
        lua_pushfstring(L, "\n%d: ", i);
        lua_rawgeti(L, idx_err, i);
    }
    lua_concat(L, nerr*2+1);

    return lua_error(L); // throw error message just built
}

lua_State* as a bound argument only works as the last parameter

When binding a function whose signature contains a lua_State_, correct behavior only occurs when the lua_State_ argument is in the last parameter position. This is because ArgList iterates through compile-time constant stack positions when retrieving parameters passed by Lua. Since the lua_State* does not occupy a physical position on the stack, the argument list will become out of sync for subsequent parameters.

The fix is to update the documentation to indicate that the lua_State* can only occur as the last (or sole) parameter.

Failed Assertion?

Hey there,

I'm trying to do some simple bindings but for some reason I'm getting:

Assertion failed: (m_stackSize != 0), function Namespace, file /Users/goles/Programming/iPhone/GG/Little-Engine/Libraries/Luabridge/LuaBridge.h, line 4517.

I'm just trying to do:

lua_State *L = lua_open();
luaL_openlibs(L);
luabridge::getGlobalNamespace (L)
.endNamespace();

Don't really know what could be going on here.

LuaRef - Comment on line 221

Yon can probably zap that comment about not changing original, as it doesn't really clarify what is really happening. Strings and numbers in Lua are immutable, so you can not change them! I think what I was getting at is if you had a='Hello' in Lua, took a LuaRef from 'a', then had 'a = 'World', the ref would still point to a string with 'Hello'. The ref of course being a reference to the string 'Hello' itself, not the Lua variable 'a'.

RefCountedObject not declared

The documentation refers to RefCountedObject but there is only class RefCountedObjectType. The documentation should be updated.

Updating the docs is likely preferred over using

typedef RefCountedObjectType <int> RefCountedObject

because this way the lack of thread-safety is made explicit.

Constructors for classes inside C++ namespaces

If a class from a namespace is bound to Lua, the constructor will not work unless that namespace is imported into the current one.

This will register the class, but calls from Lua to a=N.A(); will fail

getGlobalNamespace(L)
    .beginNamespace("N")
        .beginClass<N::A>("A")
            .addConstructor <void (*) (void)> ()
        .endClass()
    .endNamespace()

Adding:

using namespace N;

Fixes it. Maybe this can be included in the documentation to avoid users the surprise :)

Thanks.

'const' type qualifier on return type has no effect

During the compilation of our project with Clang 3.2, we detected some semantic issues in the latest LuaBridge (1.0.2).
I thought you would like to know about them. Seems like those warnings could easily be fixed..

extern/LuaBridge/LuaBridge.h:2316:23: warning: 'const' type qualifier on return type has no effect
  static inline void* const getIdentityKey ()
                      ^~~~~
extern/LuaBridge/LuaBridge.h:2340:24: warning: 'const' type qualifier on return type has no effect
    static void const* const getStaticKey ()
                       ^~~~~
extern/LuaBridge/LuaBridge.h:2353:24: warning: 'const' type qualifier on return type has no effect
    static void const* const getClassKey ()
                       ^~~~~
extern/LuaBridge/LuaBridge.h:2365:24: warning: 'const' type qualifier on return type has no effect
    static void const* const getConstKey ()
                       ^~~~~
extern/LuaBridge/LuaBridge.h:2385:18: warning: 'const' type qualifier on return type has no effect
    inline void* const getPointer ()
                 ^~~~~
extern/LuaBridge/LuaBridge.h:2399:22: warning: 'const' type qualifier on return type has no effect
    static Userdata* const getExactClass (lua_State* L, int narg, void const* const classKey)
                     ^~~~~
extern/LuaBridge/LuaBridge.h:2489:22: warning: 'const' type qualifier on return type has no effect
    static Userdata* const getClass (

RefCountedObject documentation and include files.

Hi Vinnie,

I've been working with RefCountedObject and come across a couple of things. In the docs, both the html, and in the include file for RefCountedObject, it says you can use it like:

class MyClass : public RefCountedObject
{
...

However you really need:

class MyClass : public RefCountedObject<size_t>

or something similar. I was momentarily stumped as to why I was getting "expected class name before { token".

Another thing was that fact that to use RefCountedObject, I needed to include LuaBridge,h, which means also lua.hpp everywhere that I want to use it. This means code that otherwise has no relationship to LuaBridge or Lua still has to include the header files, because it uses a class that also happens to be bound to Lua elsewhere.

Perhaps the RefCountedObject, and RefCountedPtr might be more useful with more separation? As it stands, I might make my own version of RefCountedObject, etc to avoid this. I like to keep things modular as possible.

'ave a good New Years!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.