C++ - Lua: get caller table name - c++

How can i get in a c++ function the name of the table who calls it?
Here is the c++ sourcecode, i need to store objects in a c++ map and in lua tables, the c++ map->first is the same name of the table in lua.
see the function static int move_to(lua_State* L) i need to modify the lua table who calls that function.
Test.cpp
#include <lua.hpp>
#include <lauxlib.h>
#include <iostream>
#include <map>
#include <string>
struct Point{
int x=0, y=0;
};
std::map<std::string, Point> points;
static int move_to(lua_State* L){
int num_args=lua_gettop(L);
if(num_args>=2){
int new_x=lua_tonumber(L, 1);//first argument: x.
int new_y=lua_tonumber(L, 2);//second argument: y.
std::string name=???;//i need to get the name of the lua table who calls this function.
lua_getglobal(L, name.c_str());
lua_pushnumber(L, new_x);
// modify point in the lua table.
lua_setfield(L, -2, "x");// point.x=x
lua_pushnumber(L, new_y);
lua_setfield(L, -2, "y");// point.x=x
// modify point in the c++ map.
points.find(name)->second.x=new_x;
points.find(name)->second.y=new_y;
};
return 0;
};
static int create_point(lua_State* L){
int num_args=lua_gettop(L);
if(num_args>=2){
std::string name=lua_tostring(L, 1);//first argument: name.
int x=lua_tonumber(L, 2);//second argument: x.
int y=lua_tonumber(L, 3);//third argument: y.
static const luaL_Reg functions[]={{ "move_to", move_to},{ NULL, NULL }};
lua_createtable(L, 0, 4);
luaL_setfuncs(L, functions, 0);
lua_pushnumber(L, x); lua_setfield(L, -2, "x");// point.x=x
lua_pushnumber(L, y); lua_setfield(L, -2, "y");// point.y=y
lua_setglobal(L, name.c_str());
points.insert(std::pair<std::string, Point>(name, Point()));// insert point in the c++ map.
};
return 0;
};
int main(){
lua_State * L=luaL_newstate();
luaL_openlibs(L);
luaL_loadfile(L, "script.lua");
lua_pushcfunction(L, create_point); lua_setglobal(L, "create_point");//Register create_point to L.
lua_call(L, 0, 0);
std::cout<<"c++: a.x: "<<points.find("a")->second.x<<", a.y: "<<points.find("a")->second.y<<std::endl;
return 0;
};
Here is the lua script.
Test.lua
-- name, x, y
create_point("a", 10, 11)
print("lua: a.x: " .. a.x .. ", a.y: " .. a.y)
a.move_to(1,2)
print("lua: a.x: " .. a.x .. ", a.y: " .. a.y)

How can i get in a c++ function the name of the table who calls it?
You can't get table's name, since values don't have names.
Just pass that table as first argument, the very much like this pointer in C++. Lua has special syntax to make it easy:
a:move_to(1,2)
Note the difference - colon is used instead of dot. That syntactic sugar is shorter equivalent to:
a.move_to(a,1,2)

Related

Handling binary data between C++ and Lua

i need to make a program that will handle binary data, lots of it.
in short, the C++ program will load a binary file (some of them exceed 20mb) into a buffer.
then it will run a Lua script and pass all this loaded data to the script, which will do some manipulation and return the result to the C++ program.
I need to do this as quickly as possible, perform at the best and get the job done faster.
A while ago I already made this program using the conventional methods of Lua, but it was extremely slow.
So I lost the files, and now I want to redo it in a better, faster way that doesn't compromise performance.
Searching a bit, I found this.
I had to make some small changes to adapt to the new version of Lua, but I can't get it to work.
Can you help me with this?
And if there's a better way to do the job I said, what would it be?
#include "stdafx.h"
// metatable method for handling "array[index]"
static int array_index(lua_State* L) {
int** parray = (int**)luaL_checkudata(L, 1, "array");
int index = luaL_checkinteger(L, 2);
lua_pushnumber(L, (*parray)[index - 1]);
return 1;
}
// metatable method for handle "array[index] = value"
static int array_newindex(lua_State* L) {
int** parray = (int**)luaL_checkudata(L, 1, "array");
int index = luaL_checkinteger(L, 2);
int value = luaL_checkinteger(L, 3);
(*parray)[index - 1] = value;
return 0;
}
// create a metatable for our array type
static void create_array_type(lua_State* L) {
static const struct luaL_Reg array[] = {
{ "__index", array_index },
{ "__newindex", array_newindex },
NULL, NULL
};
luaL_newmetatable(L, "array");
luaL_setfuncs(L, array, 0);
}
// expose an array to lua, by storing it in a userdata with the array metatable
static int expose_array(lua_State* L, int array[]) {
int** parray = (int**)lua_newuserdata(L, sizeof(int**));
*parray = array;
luaL_getmetatable(L, "array");
lua_setmetatable(L, -2);
return 1;
}
// test data
int mydata[] = { 1, 2, 3, 4 };
// test routine which exposes our test array to Lua
static int getarray(lua_State* L) {
return expose_array(L, mydata);
}
int __declspec(dllexport) __cdecl luaopen_array(lua_State* L) {
create_array_type(L);
// make our test routine available to Lua
lua_register(L, "array", getarray);
return 0;
}
int main()
{
lua_State* L = luaL_newstate();
luaL_dostring(L, "require 'array'");
luaL_dostring(L, "foo = array()");
luaL_dostring(L, "x = foo[1]");
lua_getglobal(L, "x");
lua_Number x = lua_tonumber(L, 1);
printf("foo[1] = %d\n", (int)x);
}
Consider using lightuserdata to avoid copying file contents excessively.
lightuserdata is just a pointer, so you need to define some methods to work with it as well.
The idea looks like this:
#include <lauxlib.h>
#include <lualib.h>
#define BIN_DATA_MT_ID "bin data"
int get_byte(lua_State *L) {
const char *file_contents = luaL_checkudata(L, 1, BIN_DATA_MT_ID);
size_t byte_index = luaL_checknumber(L, 2);
// checking OOB is your custody here, omitted for simplicity
lua_pushlstring(L, file_contents + byte_index, 1);
return 1;
}
static const luaL_Reg __index[] = {
{"get_byte", get_byte},
{NULL, NULL}
};
int main() {
const char file_contents[4] = { 0x25, 0xAA, 0xBB, 0xCC };
lua_State *L = luaL_newstate();
luaopen_base(L); // adds "print" function
lua_pushlightuserdata(L, (void *)file_contents);
luaL_newmetatable(L, BIN_DATA_MT_ID);
luaL_newlib(L, __index);
lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2);
lua_setglobal(L, "mybindata");
luaL_dostring(L, "print(mybindata:get_byte(0))");
lua_close(L);
return 0;
}
The fastest way for Lua to access the bytes of a large byte array is to expose that array directly as a string within Lua. Now because Lua does reference counting for strings, this means that Lua will always allocate its own storage for the string. So to efficiently load the string into Lua (ie: avoiding a 20+MiB copy), you need to use the lua_Buffer-based API to load it directly into Lua's storage.
But outside of that quirk, it will certainly be faster inside Lua to use array accesses of a string to access bytes compared to doing a function call for each byte accessed from the buffer.

Accessing user data as a member of another user data in LUA C++

I am trying to index into a user data called entity to get to another user data called transform component. I am relatively new to lua w/ c++ binding but after I got my entity up and running with metatables and an index method that would allow me to do stuff like this in Lua:
entity1 = Entity.create()
entity1:setID(4)
print(entity1)
This works perfectly but I also have a user data called TransformComponent that looks like this in LUA
transform1 = TransformComponent.create()
transform1:setPosition(4,3)
print(transform1)
Here is where I get stuck. What I WANT to be able to do in LUA is something like this:
entity1 = Entity.create()
entity1.transform:setPosition(4,3)
print(entity1)
How do I (in C++) set up this kind of relationship where Entity is a table that contains all its methods but also contains a key called "transform" that maps to the TransformComponent table. In C++ I tried setting it as a key and I tried reading the "transform" key from the index method and placing the TransformComponent methods in the table but that didn't work.
Any help is extremely appreciated.
EDIT
I initially didn't want to include the attempts I made because they were futile and I knew it but what I attempted to do was during the entity index, I would push the table for TransformComponent and hope the next part of the index (i.e. the methods for TransformComponent)
So here is the index method for Entity
static int _LUA_index(lua_State* L) {
assert(lua_isstring(L, -1));
Entity* luaEntity1 = (Entity*)lua_touserdata(L, -2); assert(luaEntity1);
std::string index = lua_tostring(L, -1);
if (index == "transform") {
lua_getglobal(L, "TransformComponent");
return 1;
}
lua_getglobal(L, "Entity");
lua_pushstring(L, index.c_str());
lua_rawget(L, -2);
return 1;
}
If i print out the result of "index" its just transform, I can never get it to try and parse "setPosition". I have no Idea how to progress here. Here is the code to setup the tables:
lua_State* L = luaL_newstate();
luaL_openlibs(L);
/* --------- Transform table ----------- */
lua_newtable(L);
int transformTableIndex = lua_gettop(L);
lua_pushvalue(L, transformTableIndex);
lua_setglobal(L, "TransformComponent");
lua_pushcfunction(L, TransformComponent::_LUA_CreateTransform);
lua_setfield(L, -2, "create");
lua_pushcfunction(L, TransformComponent::_LUA_SetPosition);
lua_setfield(L, -2, "setPosition");
/* --------- Transform Meta table ----------- */
luaL_newmetatable(L, "TransformComponentMetaTable");
lua_pushcfunction(L, TransformComponent::_LUA_gc);
lua_setfield(L, -2, "__gc");
lua_pushcfunction(L, TransformComponent::_LUA_eq);
lua_setfield(L, -2, "__eq");
lua_pushcfunction(L, TransformComponent::_LUA_tostring);
lua_setfield(L, -2, "__tostring");
lua_pushcfunction(L, TransformComponent::_LUA_index);
lua_setfield(L, -2, "__index");
/* --------- Entity table --------- */
lua_newtable(L);
int entityTableIndex = lua_gettop(L);
lua_pushvalue(L, entityTableIndex);
lua_setglobal(L, "Entity");
constexpr int NUM_OF_UPVALUES = 1;
lua_pushlightuserdata(L, &manager);
lua_pushcclosure(L, Entity::_LUA_CreateEntity, NUM_OF_UPVALUES);
//lua_pushcfunction(L, Entity::_LUA_CreateEntity);
lua_setfield(L, -2, "create");
lua_pushcfunction(L, Entity::_LUA_MoveEntity);
lua_setfield(L, -2, "move");
lua_pushcfunction(L, Entity::_LUA_DrawEntity);
lua_setfield(L, -2, "draw");
/* --------- Entity Meta table --------- */
luaL_newmetatable(L, "EntityMetaTable");
lua_pushstring(L, "__gc");
lua_pushcfunction(L, Entity::_LUA_gc);
lua_settable(L, -3);
lua_pushstring(L, "__eq");
lua_pushcfunction(L, Entity::_LUA_eq);
lua_settable(L, -3);
lua_pushstring(L, "__tostring");
lua_pushcfunction(L, Entity::_LUA_tostring);
lua_settable(L, -3);
lua_pushstring(L, "__index");
lua_pushcfunction(L, Entity::_LUA_index);
lua_settable(L, -3);
I started thinking this was impossible to accomplish or I am just unable to do this Lua. I am unsure but I am definitely not talented enough to figure this out.
EDIT2
EntityClass + TransformComponent:
struct _API SpriteComponent {
const char* fileName;
};
struct _API TransformComponent {
glm::vec2 position;
glm::vec3 rotation;
TransformComponent();
~TransformComponent();
static int _LUA_CreateTransform(lua_State* L);
static int _LUA_SetPosition(lua_State* L);
static int _LUA_gc(lua_State* L);
static int _LUA_eq(lua_State* L);
static int _LUA_index(lua_State* L);
static int _LUA_tostring(lua_State* L);
};
class _API Entity{
public:
TransformComponent transform;
SpriteComponent sprite;
Entity();
~Entity();
void moveEntity(float x, float y);
void drawEntity();
static int _LUA_CreateEntity(lua_State* L);
..etc etc
EDIT3
_LUA_CreateTransform method
int TransformComponent::_LUA_CreateTransform(lua_State* L) {
void* entityPointer = lua_newuserdata(L, sizeof(TransformComponent));
new(entityPointer) TransformComponent(); assert(entityPointer);
luaL_getmetatable(L, "TransformComponentMetaTable");
lua_setmetatable(L, -2);
return 1;
}
Again any help is super appreciated.
Your _LUA_index C++ function is more-or-less equivalent to this in pure Lua:
function EntityMetaTable.__index(luaEntity1, index)
if tostring(index) == 'transform' then
return TransformComponent
end
return rawget(Entity, index)
end
Thus, when you do entity1.transform:setPosition(4,3), it's basically equivalent to TransformComponent:setPosition(4,3). The problem is that you can't do setPosition directly on the TransformComponent table. You need to do it on a userdata that TransformComponent.create() gives you, like transform1 is, instead. If you want to avoid making a fresh TransformComponent userdata every time, you can save the result as a uservalue (or environment if you're on Lua 5.1 still) on your entity userdata.
Edit: Now that I see more of your code, here's what you should do. In your Entity class, change TransformComponent transform to TransformComponent *transform. Then, in your _LUA_CreateEntity function, set up transform the same way that you do in _LUA_CreateTransform. Then set the transform userdata as the environment or uservalue (depending on Lua version) of the entity userdata. Finally, in your index method, return that environment/uservalue instead of doing lua_getglobal(L, "TransformComponent");.
You are returning a static class/table (TransformComponent in this case) when your entity's index transform is called. What you really need is the actual instance of your transform that is present inside your entity class. So technically, you want properties of your object to be accessible from Lua easily by calling ent.transform.
To achieve this, you can use sol which is "a fast, simple C++ and Lua Binding".
class _API Entity{
public:
TransformComponent transform;
TransformComponent get_transform() {
return transform;
}
void set_transform(TransformComponent value) {
transform = value;
}
...
#include <sol/sol.hpp>
int main (int, char*[]) {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<Entity>( "Entity",
"transform", sol::property(&Entity::get_transform, &Entity::set_transform)
);
Additionally, you can have properties that are read-only which would fit your transform property perfectly since you do not want it to be replaced with a new transform and rather you want the transform properties to be changed.
sol::usertype<Entity> type_ent = lua.new_usertype<Entity>("Entity",
sol::constructors<Entity()>());
// Read only property (Still, you can call your Transform methods on it).
type_ent.set("transform", sol::readonly(&Entity::get_transform));
As a side note, be sure to first register your TransformComponent with all it's functions and properties and then register your Entity.
Have a look at sol properties and sol classes instruction for more details.

Lua Array and Object Oriented Access for the Same Userdata

I have an CArray class written in C++ and is exposed to Lua as Array.
1) Create a new userdata:
int Array_new(lua_State* L)
{
int len = luaL_checkint(L, 1);
CArray<std::string> **Arr = (CArray<std::string>**)lua_newuserdata(L, sizeof(CArray<std::string>*));
*Arr = new CArray<std::string>(len);
luaL_getmetatable(L, "ArrayMetatable");
lua_setmetatable(L, -2);
return 1;
}
2) Access an element:
int Array_getValue(lua_State* L)
{
CArray<std::string>* arr = *(CArray<std::string>**)lua_touserdata(L, 1);
int pos=luaL_checknumber(L, 2)-1;
//Omitted for brevity
lua_pushstring(L, stdStr.c_str());
return 1;
}
3) Register to Lua:
int luaopen_Array(lua_State* L)
{
luaL_newmetatable(L, "ArrayMetatable"); // metatable1
luaL_setfuncs(L, Array_metatable, 0);
lua_pushstring(L, "__index");
lua_pushvalue(L, -2); // metatable1 __index metatable1
lua_settable(L, -3); // metatable1[__index]=metatable1
/*luaL_newmetatable(L, "ArrayMetatable_2"); // metatable1 metatable2
lua_pushstring(L, "__index"); // metatable1 metatable2 __index
lua_pushstring(L, "get"); // metatable1 metatable2 __index get
lua_gettable(L, 1); // metatable1 metatable2 __index
lua_settable(L, 2);
lua_pushvalue(L, 1); //metatable1 metatable2 metatable1*/
lua_setglobal(L, "Array");
return 0;
}
The problem is I have to prefer either Lua code to access an element in the array: a) arr:get(1) to get the first element, b) arr[1] to get the first element.
However a and b does not work at the same time, so either I have to prefer style a or style b. Is it possible to do a and b at the same time by modifying the 3rd step?
So far the code I presented gives an error at step 2 if I try a Lua expression such as arr[2] such that the variable arr's address is 0xcccccc.
You can add an __index method and a get method, just add them separately.
The registration function looks a little messed up.
Normally you would have two meta-tables - the global functions, and the member functions.
static const struct luaL_Reg Array_globals[] = {
{ "new", Array_new },
{ NULL,NULL }
};
static const struct luaL_Reg Array_members[] = {
{ "get", Array_getValue},
{ "__index", Array_getValue },
{ NULL,NULL }
};
the luaopen_ function merely needs to build the tables with the appropriate methods.
I would recommend also writing __len, and __setindex
int luaopen_Array(lua_State* L)
{
luaL_newmetatable(L, "ArrayMetatable"); // metatable1
luaL_setfuncs(L, Array_members, 0);
luaL_newlib( L, Array_globals );
return 1; // return table to caller.
}

Creating new classes/members at run-time in scripting languages used in C++ [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
Improve this question
I've been working on this problem off and on for a few months, and now wanted to really come up with a proper solution that will handle the case of creating new user-defined classes (and instances of those classes) with member functions/properties at run-time in a C++11 project.
So far, I've been using SWIG (formerly with Python, now with Lua, exploring Squirrel). Like all the C++ binding/embedding libraries I've encountered so far (Luna*, luabinder, luabind, OOLua, Sqrat/Sqext, Squall), all expect your classes to be predefined in C++ prior to code execution because they either rely on preprocessor directives or templates.
So my question is, are there any libraries out there that use a more procedural approach to wrapping a language, or are there any good tutorials/examples for something like Lua or Squirrel, that one would recommend for handling the creation of custom-named classes with custom members and functions? Some direction would be greatly appreciated.
Even simply a good example showing how to create a custom class with a function and a property, in either Lua, Squirrel, via their respective C++ APIs without the use of macros/templates/dynamically-generated code, would be hugely helpful.
EDIT: I have gone as far as creating an Instance class that contains a std::vector of members key/value pairs, and a member identifying the type so functions can be looked up. However, there is very little documentation out there on creating simple classes in Lua/Squirrel without the use of static code.
EDIT 2: I would like a solution that works on any platform and without having to dynamically link.
Creating a class derived from some existing C++ class is the only way (known to me) to bring a new class into a running C++ program. Short of dynamically compiling actual C++ source and loading the resulting library, there is no way to physically add a new class. The next best thing is to create a proxy object in C++ that wraps a Python (Lua etc) object, and make that Python (Lua) object an instance of a class that extends an existing C++ class mirrored to the Python (Lua) side.
C++
+---------+ mirrors +--------------+
| class X | ...............................> | class X |
+---------+ | mirrored to |
| | Python |
| inherits +--------------+
v inherits |
+-----------------+ v
| class X_Wrapper | references +--------------+
| | python obj -------------------------> | class CX(X): |
+-----------------+ | def met() |
+--------------+
Here's an example of extending a C++ class with Python, using boost::python as a bridge.
C++ side:
#include <boost/python.hpp>
#include <iostream>
using namespace boost::python;
// this is the interface we will implement in Python
struct World
{
virtual std::string greet() = 0;
virtual ~World() {}
};
// this is a helper class needed to access Python-overrided methods
struct WorldWrap : World, wrapper<World>
{
std::string greet()
{
return this->get_override("greet")();
}
};
// This function tests our class implemented in Python
std::string test(World* w)
{
std::cout << "Calling w->greet() on some World-derived object\n";
return w->greet();
}
// This is what the Python side will see
BOOST_PYTHON_MODULE(hello)
{
class_<WorldWrap, boost::noncopyable>("World")
.def("greet", pure_virtual(&World::greet));
def("test", test);
}
Python side:
import hello
class HomeWorld(hello.World):
""" Implements a function defined in C++ as pure virtual """
def greet(self):
return "howdy"
home = HomeWorld()
print (hello.test(home))
Consider following Lua multimap example.
Multimap = {};
function Multimap:__index(key)
if (key == 'keys') then
local ret = {}
for k,_ in pairs(self) do
ret[#ret+1] = k;
end
return ret;
else
return rawget(getmetatable(self), key)
end
end
function Multimap.Create()
local self = {};
setmetatable(self, Multimap);
return self;
end
function Multimap:Insert(key, value)
local list = self[key];
if (list == nil) then
list = {};
self[key] = list;
end
table.insert(list, value);
end
function Multimap:Remove(key, value)
local list = self[key];
assert(list ~= nil, "key not found");
for i = 1,#list do
if (list[i] == value) then
table.remove(list, i);
if (#list == 0) then
self[key] = nil;
end
return;
end
end
error("value not found");
end
-- testing
m = Multimap.Create()
m:Insert(1,5)
m:Insert(2,6)
m:Insert(3,7)
m:Insert(1,8)
m:Remove(2,6)
print(pcall(function()
m:Remove(2,6) -- will produce assert exception
end))
print("keys left: ", table.concat(m.keys, ','))
You can implement this in C++ in several ways.
Use heavy Lua API. The code below is almost exact to Lua.
#include <Lua/src/lua.hpp>
int Multimap_Index(lua_State* L) {
lua_settop(L, 2); // force 2 arguments
const char *key_value = "key";
size_t key_len;
const char *key = lua_tolstring(L, 2, &key_len);
if (!strncmp(key, key_value, strlen(key_value))) {
int i = 0;
lua_newtable(L); // stack : self, key, ret = {}
int ret = lua_gettop(L);
lua_pushnil(L); // stack : self, key, ret, nil
while (lua_next(L, 1) != 0) { // stack : self, key, ret, k, v
lua_pop(L, 1); // stack : self, key, ret, k
lua_len(L, ret); // stack : self, key, ret, k, #ret
lua_pushvalue(L, -2); // stack : self, key, ret, k, #ret, k
lua_rawseti(L, ret, lua_tointeger(L, -2)+1); // ret[#ret+1] = k ; || stack : self, key, ret, k, #ret
lua_pop(L, 1); // stack : self, key, ret, k
}
// stack : self, key, ret
return 1;
}
else {
lua_getmetatable(L, 1); // stack : self, key, metatable(self)
lua_pushvalue(L, 2); // stack : self, key, metatable(self), key
lua_rawget(L, -2); // stack : self, key, metatable(self), rawget(metatable(self), key)
return 1;
}
}
int Multimap_Remove(lua_State* L) {
lua_settop(L, 3); // force 3 arguments: self, key, value
lua_checkstack(L, 12); // reserve 12 arguments on stack (just in case)
lua_pushvalue(L, 2); // stack: self, key, value, key
lua_gettable(L, 1); // stack: self, key, value, list = self[key]
if (lua_isnil(L, -1))
luaL_error(L, "key not found");
lua_len(L, -1); // stack: self, key, value, list, #list
int count = lua_tointeger(L, -1);
lua_pop(L, 1); // stack: self, key, value, list
for (int i = 1; i <= count; ++i) {
lua_rawgeti(L, -1, i); // stack: self, key, value, list, v = list[i]
if (lua_compare(L, 3, 5, LUA_OPEQ)) { // if (list[i] == value)
lua_getglobal(L, "table"); // stack : self, key, value, list, v, table
lua_getfield(L, -1, "remove"); // stack : self, key, value, list, v, table, table.remove
lua_pushvalue(L, 4);
lua_pushinteger(L, i); // stack : self, key, value, list, v, table, table.remove, list, i
lua_call(L, 2, 0); // table.remove(list, i); || stack : self, key, value, list, v, table
lua_pushnil(L);
if (lua_next(L, 4) == 0) { // if list is empty table
lua_pushvalue(L, 2);
lua_pushnil(L);
lua_settable(L, 1); // self[key] = nil
}
return 0;
}
}
luaL_error(L, "value not found");
}
int main() {
auto L = luaL_newstate();
luaL_openlibs(L);
lua_newtable(L);
int Multimap = lua_gettop(L); // Multimap = {}
lua_pushvalue(L, Multimap);
lua_setglobal(L, "Multimap"); // _G.Multimap = Multimap;
// option 1: create a C function for operation
// Multimap.__index = &Multimap_Index
lua_pushcfunction(L, Multimap_Index);
lua_setfield(L, Multimap, "__index");
// option 2: compile Lua code and use it
luaL_loadstring(L,
"local self = {};\n"
"setmetatable(self, Multimap);\n"
"return self;\n"
);
lua_setfield(L, Multimap, "Create"); // Multimap.Create = &Multimap_Create
luaL_loadstring(L,
"local self, key, value = ...;\n" // initialize local variables from parameters here
"local list = self[key];\n"
"if (list == nil) then\n"
" list = {};\n"
" self[key] = list;\n"
"end\n"
"table.insert(list, value);\n"
);
lua_setfield(L, Multimap, "Insert"); // Multimap.Create = &Multimap_Insert
lua_pushcfunction(L, Multimap_Remove);
lua_setfield(L, Multimap, "Remove"); // Multimap.Create = &Multimap_Remove
lua_getfield(L, Multimap, "Create");
lua_call(L, 0, 1);
int m = lua_gettop(L);
lua_getfield(L, m, "Insert"); // stack : m, m.insert
int Insert = lua_gettop(L);
// m.Insert(m, 1, 5)
lua_pushvalue(L, Insert);
lua_pushvalue(L, m);
lua_pushinteger(L, 1);
lua_pushinteger(L, 5);
lua_call(L, 3, 0);
// m.Insert(m, 2, 6)
lua_pushvalue(L, Insert);
lua_pushvalue(L, m);
lua_pushinteger(L, 2);
lua_pushinteger(L, 6);
lua_call(L, 3, 0);
// m.Insert(m, 3, 7)
lua_pushvalue(L, Insert);
lua_pushvalue(L, m);
lua_pushinteger(L, 3);
lua_pushinteger(L, 7);
lua_call(L, 3, 0);
// m.Insert(m, 1, 8)
lua_pushvalue(L, Insert);
lua_pushvalue(L, m);
lua_pushinteger(L, 1);
lua_pushinteger(L, 8);
lua_call(L, 3, 0);
// m.Remove(m, 2, 6)
lua_getfield(L, m, "Remove");
lua_pushvalue(L, m);
lua_pushinteger(L, 2);
lua_pushinteger(L, 6);
lua_call(L, 3, 0);
// m.Remove(m, 2, 6)
lua_getfield(L, m, "Remove");
lua_pushvalue(L, m);
lua_pushinteger(L, 2);
lua_pushinteger(L, 6);
lua_pcall(L, 3, 0, 0);
printf("%s\n", lua_tostring(L, -1));
lua_getglobal(L, "table");
lua_getfield(L, -1, "concat");
lua_getfield(L, m, "keys");
lua_pushstring(L, ",");
lua_call(L, 2, 1);
printf("keys left: %s\n", lua_tostring(L, -1));
lua_close(L);
return 0;
}
OR you can use Lua userdata that uses std::multimap (I would need another hour to implement this, so ask if you really need that -- that doesn't follow from your question)
Disclaimer: I'm posting this contribution as an answer because I don't have enough reputation points to add a comment.
Comment: Setting aside the problematic of binding with a specific scripting language, it seems that you are facing a fundamental limitation of the C++ language: it is not "dynamic" (as pointed out by other comments). That is, the language does not provide any functionality to extend or modify a compiled program.
Maybe all hope is not lost, though. Searching the web for "c++ dynamic loading" reveals that some systems (such and Linux and Windows) do seem to implement a dynamic loading mechanism.
Here are the links to two (old) articles that talk about the subject.
Dynamic Class Loading for C++ on Linux in the Linux Journal.
Dynamically Loaded C++ Objects in Dr.Dobb's.
They seem interesting at first glance. I'm not sure they are still relevant, though.
This is but a shot in the dark.

Registering a C++ class for use in Lua 5.2

So I was reading up on how to create and register a c++ class for Lua via THIS little blog tutorial.
But as simple, informative and legible as it is, it appears to be for an older version of Lua.
So some of the functions/macros are either missing or just have different signatures.
What would the following code look like in Lua C version 5.2?
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <stringstream>
#include <string>
using namespace std;
// Just a useless test class
class MyClass
{
private:
int _X;
public:
MyClass(int x) : _X(x) {};
~MyClass() { Release() };
// Displays your number in a welcoming message box
void Hello()
{
stringstream ss;
ss << "Hello!" << endl << "Your number is: " << _X;
string s(ss.str());
MessageBoxA(NULL, s.c_str(), "MyClass", MB_ICONINFORMATION);
}
void Release() {
//release code goes here
}
};
// Functions that will create/destroy MyClass instances
static int newMyClass(lua_State* L)
{
int n = lua_gettop(L); // Number of arguments
if (n != 2)
return luaL_error(L, "Got %d arguments, expected 2 (class, x)", n);
// First argument is now a table that represent the class to instantiate
luaL_checktype(L, 1, LUA_TTABLE);
lua_newtable(L); // Create table to represent instance
// Set first argument of new to metatable of instance
lua_pushvalue(L, 1);
lua_setmetatable(L, -2);
// Do function lookups in metatable
lua_pushvalue(L, 1);
lua_setfield(L, 1, "__index");
// Allocate memory for a pointer to to object
MyClass** s = (MyClass**)lua_newuserdata(L, sizeof(MyClass*));
int x = luaL_checknumber(L, 2);
*s = new MyClass(x);
luaL_getmetatable(L, "Lua.MyClass");
lua_setmetatable(L, -2);
lua_setfield(L, -2, "__self");
return 1;
}
static int doSomethingMyClass(lua_State* L)
{
MyClass* c = nullptr;
checkUserData(L, "Lua.MyClass", c);
c->Hello();
return 0;
}
static int destroyMyClass(lua_State* L)
{
MyClass* c = nullptr;
checkUserData(L, "Lua.MyClass", c);
c->Release();
return 0;
}
// Functions that will show up in our Lua environment
static const luaL_Reg gMyClassFuncs[] = {
// Creation
{ "new", newMyClass) },
{ "hello", helloMyClass },
{ NULL, NULL }
};
static const luaL_Reg gDestroyMyClassFuncs[] = {
{"__gc", destroyMyClass},
{NULL, NULL}
};
// Registers the class for use in Lua
void registerMyClass(lua_State *L)
{
// Register metatable for user data in registry
luaL_newmetatable(L, "Lua.MyClass");
luaL_register(L, 0, gDestroyMyClassFuncs);
luaL_register(L, 0, gMyClassFuncs);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
// Register the base class for instances of Sprite
luaL_register(L, "MyClass", gSpriteFuncs);
}
Basically, the goal here is to be able to write the following in Lua:
-- Create a new MyClass instance
local c = MyClass:new(5)
-- Show message
c:Hello() -- Should say something like "Hello! Your number is: 5"
What would I need to change in order to make this work for 5.2?
The only function in that code that is not part of Lua 5.2 is luaL_register. You should use luaL_setfuncs instead.
You should also set the global MyClass by hand or use local MyClass=require"MyClass" in your Lua code because require no longer sets globals.
If you are embedding Lua, you can just compile it and your code with -DLUA_COMPAT_MODULE and get the 5.1 functions. But consider that now is a good time to move your code to Lua 5.2, if you plan to use this version.