Handling binary data between C++ and Lua - c++

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.

Related

package.preload alternative in Lua?

I learned that package.preload can be used to expose a script to other scripts.
Here's my example code.
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_settop(L, 0);
//Script A
luaL_dostring(L, "local A = {} package.preload['A'] = function () return A end A.num = 3");
//Script B
luaL_dostring(L, "local A = require 'A' print(A.num)");
lua_close(L);
The result: 3
Although this works fine, I wonder if Script A's code can be more simplified or if there's other alternative solution to expose a script to other scripts.
ADDED: The main reason I'm asking this is because I think package.preload['A'] = function () return A end is quite long and boring to write.
In this case, where you have some set of in-C strings that represent Lua modules, package.preload is exactly the tool to use. Though your specific use of it leaves something to be desired.
Generally speaking, the modules themselves do not define their names. So hard-coding the module's name into the string is not the correct move. Similarly, modules do not register themselves; they should be registered by the environment around the module.
What you really want is to take an array of name+Lua code strings and register them as module preloads in a loop. So you'd have something like this. I'll be using Lua 5.3; you can translate it to older version of Lua pretty easily.
Also, be warned: this code is untested.
const char *lua_preloads[] =
{
"A", "local A = {}\n"
"A.num = 3\n"
"return A)\n", //Modules are usually tables, not functions.
...
NULL //Null-terminated list.
};
//Loader function
int lua_preloader_func(lua_State *L)
{
int nargs = lua_gettop(L);
int lua_func_ix = lua_upvalueindex(1);
lua_pushvalue(L, lua_func_ix);
//Move the function to the bottom of the stack
lua_insert(lua_func_ix, 1);
//Call with all of the given arguments.
lua_call(L, nargs, LUA_MULTRET);
return lua_gettop(L);
}
int top = lua_gettop(L);
//Get the package.preload table.
lua_getglobal(L, "package");
lua_getfield(L, -1, "preload");
int preload_ix = lua_gettop();
for(const char **position = lua_preloads;
*position;
position += 2)
{
const char *module_name = position[0];
const char *module = position[1];
//Compile the preload script into a Lua function.
int err = luaL_loadbufferx(L, module, strlen(module), module_name, "t");
//Check for errors in `err`.
//Create a Lua C-function with the script as an upvalue.
lua_pushcclosure(L, lua_preloader_func, 1);
//Stick that Lua C-function inside of package.preload[preload.first].
lua_setfield(L, preload_ix, module_name);
}
lua_settop(L, top);
It seems as if you want to prefix local A = {} package.preload['A'] = function () return A end to every chunk defining a module (where A is the module name). I think it would be much easier to just use string concatenation for that.
#include <string>
#include <lua.hpp>
int preload(lua_State *L, std::string const &modname,
std::string const &modcode) {
std::string code = "package.preload['" + modname + "'] = function()\n" +
"local " + modname + " = {}\n" + modcode + "\n"
"return " + modname + " end";
return luaL_dostring(L, code.c_str());
}
int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
// Script A
preload(L, "A", "A.num = 3");
// Script B
luaL_dostring(L, "local A = require 'A' print(A.num)");
lua_close(L);
}

Sharing global variables between different Lua states through require

I'm trying to find a way to share global variables of a specific Lua script(test.lua in the example) between different Lua states.
Here's my simple example code:
In test.lua
num = 2
In main.cpp
#include <iostream>
#include <lua.hpp>
int main()
{
lua_State *L1 = luaL_newstate(); //script A
luaL_openlibs(L1);
lua_settop(L1, 0);
luaL_dostring(L1, "require('test') num = 5");
lua_State *L2 = luaL_newstate(); //script B
luaL_openlibs(L2);
lua_settop(L2, 0);
luaL_dostring(L2, "require('test') print(num)");
lua_close(L1);
lua_close(L2);
}
I expect to get 5 but I get 2.
Is not possible to share global variables between different lua_State* through require?
ADDED :
If it's not possible, would it be a good idea to open test.lua using luaL_loadfile and then create getter/setter methods in C++ to share variable num between script A and B?
For example like this,
Script A:
script = my.Script("test")
script:setVar("num", 5)
Script B:
script = my.Script("test")
print(script:getVar("num"))
I wonder what you think about this design as an alternative to require.
Two distinct lua_States are completely and totally independent. One cannot directly affect anything that happens in another. You can expose some C code to one that allows it to modify the other, or they could both access some external resource (a file, for example) that allows them to share data.
But outside of things like this, no, they cannot interact.
The preferred method for this is to not make them separate lua_States.
Rather than having the global value in a Lua module, you could push a pointer to a C++ value as an upvalue for a metatable to a table which contains those globals. Then you push the globals table with the same metatable to both VMs. When you now access globals.num the getglobal and setglobal metamethods are triggered (depending on whether you read or write). These will update the value on the C++ side, such that it is shared between the two VMs.
N.B.: As you can judge from the lengthy boilerplate this is not a good solution. You should avoid having multiple VMs at the same time. If you require multiple VMs for concurrency purposes, consider using a mature library like Lua Lanes rather than rolling your own (doing this right requires several thousands of lines of code).
#include <string>
#include <lua.hpp>
int setglobal(lua_State *L) {
void *p = luaL_checkudata(L, 1, "globals_meta");
luaL_argcheck(L, p != nullptr, 1, "invalid userdata");
std::string key = lua_tostring(L, 2);
luaL_argcheck(L, key == "num", 2, "unknown global");
int value = luaL_checkinteger(L, 3);
luaL_argcheck(L, lua_isnumber(L, 3), 3, "not a number");
int *num = static_cast<int *>(lua_touserdata(L, lua_upvalueindex(1)));
*num = value;
lua_pop(L, 1);
return 0;
}
int getglobal(lua_State *L) {
void *p = luaL_checkudata(L, 1, "globals_meta");
luaL_argcheck(L, p != nullptr, 1, "invalid userdata");
std::string key = lua_tostring(L, 2);
luaL_argcheck(L, key == "num", 2, "unknown global");
int num = *static_cast<int *>(lua_touserdata(L, lua_upvalueindex(1)));
lua_pop(L, 1);
lua_pushinteger(L, num);
return 1;
}
static const struct luaL_Reg globals_meta[] = {
{"__newindex", setglobal},
{"__index", getglobal},
{nullptr, nullptr} // sentinel
};
int main() {
int num = 2;
// script A
lua_State *L1 = luaL_newstate();
luaL_openlibs(L1);
luaL_newmetatable(L1, "globals_meta");
lua_pushlightuserdata(L1, &num);
luaL_setfuncs(L1, globals_meta, 1);
lua_newuserdata(L1, 0);
luaL_getmetatable(L1, "globals_meta");
lua_setmetatable(L1, -2);
lua_setglobal(L1, "globals");
luaL_dostring(L1, "print('Script A: ' .. globals.num) globals.num = 5");
// script B
lua_State *L2 = luaL_newstate();
luaL_openlibs(L2);
luaL_newmetatable(L2, "globals_meta");
lua_pushlightuserdata(L2, &num);
luaL_setfuncs(L2, globals_meta, 1);
lua_newuserdata(L2, 0);
luaL_getmetatable(L2, "globals_meta");
lua_setmetatable(L2, -2);
lua_setglobal(L2, "globals");
luaL_dostring(L2, "print('Script B: ' .. globals.num)");
lua_close(L1);
lua_close(L2);
}
As a challange to myself I implemented a complete global table which can communicate values of type nil, bool, int, double, and string between two Lua states. They can be named with everything that has a string representation.
-- To be on the safe side, just use numbers and strings as keys
globals[1] = "x"
globals.num = 5
-- Be careful when using table or function literals as keys
-- Two empty tables don't have the same representation
globals[{}] = 2 -- "table: 0x10d55a0" = 2
globals[{}] = 1 -- "table: 0x10ce2c0" = 1
I haven't checked all sorts of exceptional situations exhaustively, so no refunds!
#include <iostream>
#include <string>
#include <unordered_map>
#include <boost/variant.hpp>
#include <lua.hpp>
enum class nil {};
using Variant = boost::variant<nil, bool, int, double, std::string>;
int setglobal(lua_State *L) {
void *p = luaL_checkudata(L, 1, "globals_meta");
luaL_argcheck(L, p != nullptr, 1, "invalid userdata");
std::string key = luaL_tolstring(L, 2, nullptr);
auto &globals = *static_cast<std::unordered_map<std::string, Variant> *>(
lua_touserdata(L, lua_upvalueindex(1)));
Variant &v = globals[key];
switch (lua_type(L, 3)) {
case LUA_TNIL:
v = nil{};
break;
case LUA_TBOOLEAN:
v = static_cast<bool>(lua_toboolean(L, 3));
lua_pop(L, 1);
break;
case LUA_TNUMBER:
if (lua_isinteger(L, 3)) {
v = static_cast<int>(luaL_checkinteger(L, 3));
} else {
v = static_cast<double>(luaL_checknumber(L, 3));
}
lua_pop(L, 1);
break;
case LUA_TSTRING:
v = std::string(lua_tostring(L, 3));
lua_pop(L, 1);
break;
default:
std::string error = "Unsupported global type: ";
error.append(lua_typename(L, lua_type(L, 3)));
lua_pushstring(L, error.c_str());
lua_error(L);
break;
}
return 0;
}
int getglobal(lua_State *L) {
void *p = luaL_checkudata(L, 1, "globals_meta");
luaL_argcheck(L, p != nullptr, 1, "invalid userdata");
std::string key = luaL_tolstring(L, 2, nullptr);
auto globals = *static_cast<std::unordered_map<std::string, Variant> *>(
lua_touserdata(L, lua_upvalueindex(1)));
lua_pop(L, 1);
auto search = globals.find(key);
if (search == globals.end()) {
lua_pushstring(L, ("unknown global: " + key).c_str());
lua_error(L);
return 0;
}
Variant const &v = search->second;
switch (v.which()) {
case 0:
lua_pushnil(L);
break;
case 1:
lua_pushboolean(L, boost::get<bool>(v));
break;
case 2:
lua_pushinteger(L, boost::get<int>(v));
break;
case 3:
lua_pushnumber(L, boost::get<double>(v));
break;
case 4:
lua_pushstring(L, boost::get<std::string>(v).c_str());
break;
default: // Can't happen
std::abort();
break;
}
return 1;
}
static const struct luaL_Reg globals_meta[] = {
{"__newindex", setglobal},
{"__index", getglobal},
{nullptr, nullptr} // sentinel
};
int main() {
std::unordered_map<std::string, Variant> globals;
globals["num"] = 2;
// script A
lua_State *L1 = luaL_newstate();
luaL_openlibs(L1);
luaL_newmetatable(L1, "globals_meta");
lua_pushlightuserdata(L1, &globals);
luaL_setfuncs(L1, globals_meta, 1);
lua_newuserdata(L1, 0);
luaL_getmetatable(L1, "globals_meta");
lua_setmetatable(L1, -2);
lua_setglobal(L1, "globals");
if (luaL_dostring(L1, "print('Script A: ' .. globals.num)\n"
"globals.num = 5") != 0) {
std::cerr << "L1:" << lua_tostring(L1, -1) << '\n';
lua_pop(L1, 1);
}
// script B
lua_State *L2 = luaL_newstate();
luaL_openlibs(L2);
luaL_newmetatable(L2, "globals_meta");
lua_pushlightuserdata(L2, &globals);
luaL_setfuncs(L2, globals_meta, 1);
lua_newuserdata(L2, 0);
luaL_getmetatable(L2, "globals_meta");
lua_setmetatable(L2, -2);
lua_setglobal(L2, "globals");
if (luaL_dostring(L2, "print('Script B: ' .. globals.num)") != 0) {
std::cerr << "L1:" << lua_tostring(L2, -1) << '\n';
lua_pop(L2, 1);
}
lua_close(L1);
lua_close(L2);
}
While Lua states are separate by default, some binding libraries expose functionality to transfer information from one to the other.
For example, in sol, there are methods to serialize fairly arbitrary Lua data, including functions, to C++ data. You can then de-serialize that data into another Lua state, to effectively copy it (code link).
But you still will have two copies, in the end. You can't modify one Lua state from another directly.
Your last point, about exposing some getter/setter, is valid. You can have some data stored in C/C++ and have two different Lua states able to access it. You still have to bind that data to each VM separately.

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.
}

Using lua_call a lot of times in c++ function

first of all I'm sorry for my english.
My question is about how to use lua_call more than one time in C++ function. I have a program that uses lua as primary language, but it accept c++ plugins to add functionalities. I want to call a LUA function from c++, and call that c++ function in LUA Runtime.
I want to write a c++ function with a progress while is working, then pass this progress to a LUA function which is responsible to show that progress to user.
For now I've a test function in LUA:
function ShowText(text)
Dialog.Message("Hi", text);
return true;
end
and a c++ function:
static int Test(lua_State *L){
lua_pushstring(L, "Hi There");
lua_call(L, 1, 1);
lua_pushstring(L, "Again");
lua_call(L, 1, 1);
return 0;
}
Then i call this function from LUA using:
Test.Test(ShowText);
All works fine with the first lua_call but then the LUA pile is cleared, function dissapear and the second lua_call try to use the return boolean of first call instead function.
i want something like this:
static int Test(lua_State *L){
int total = 10;
for (int j; j<total; j++){
lua_pushnumber(L, j);
lua_pushnumber(L, j);
lua_call(L, 2, 1);
bool continue = IRLUA_PLUGIN_CheckBoolean(L, -1);
lua_pop(L, 1); //Delete the last boolean
if (continue == false){
break;
}
}
return 0;
}
and in LUA:
function ShowProgress(actual, final)
local percent = (actual/final)*100;
Dialog.Message("Working", "I'm in "..actual.." from "..final.." ("..percent.."%)");
return true;
end
NOTES:
Dialog.Message is a function of the program tha i'm using to show a message. Is like MessageBox(NULL, Text, Title, MB_OK); in c++.
IRLUA_PLUGIN_CheckBoolean is a function of plugin SDK that check if argument is booleand and return its value, or return an error if not.
I can do it with lua_getfield(L, LUA_GLOBALSINDEX , "FunctionName");, but is not what i want.
Someone knows how to do it?
You have understood the problem well. Here is how you fix it.
In your first example, lua_call pops the function from the stack so you need to duplicate it first. Also, the boolean returned by the function is useless, so you need to pop it or just not ask it to lua_call by setting the last argument to 0:
static int Test(lua_State *L) {
lua_pushvalue(L, 1); /* duplicate function */
lua_pushstring(L, "Hi There");
lua_call(L, 1, 0);
lua_pushstring(L, "Again");
lua_call(L, 1, 0);
return 0;
}
Now applying that to your second example:
static int Test(lua_State *L) {
int total = 10;
for (int j = 0; j<total; j++) {
lua_pushvalue(L, 1); /* duplicate function */
lua_pushnumber(L, j);
lua_pushnumber(L, total);
lua_call(L, 2, 1);
bool keep_going = IRLUA_PLUGIN_CheckBoolean(L, -1);
lua_pop(L, 1); /* pop the boolean */
if (keep_going == false) {
break;
}
}
return 0;
}
(I have fixed a few other issues with your code: the second number passed should probably be total, not j, you don't want to use continue as a variable name...)

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.