I'm writing a Lua library which registers some metatables using luaL_newmetatable(). Since other libraries might do that as well, I'd like to ask what is a good strategy to avoid having the same name used twice. I was thinking about using a reverse DNS name like com.mydomain.mylibrary which should be pretty safe I guess. However, I'd like to ask if there maybe is a better or standard way of choosing unique names for libraries using luaL_newmetatable().
I like use lightuserdata with pointer to string.
#define LCURL_EASY_NAME LCURL_PREFIX" Easy"
static const char *LCURL_EASY = LCURL_EASY_NAME;
It just requires simple functions to use it.
int lutil_newmetatablep (lua_State *L, const void *p) {
lua_rawgetp(L, LUA_REGISTRYINDEX, p);
if (!lua_isnil(L, -1))
return 0;
lua_pop(L, 1);
lua_newtable(L); /* create metatable */
lua_pushvalue(L, -1); /* duplicate metatable to set*/
lua_rawsetp(L, LUA_REGISTRYINDEX, p);
return 1;
}
Similar for get/set. Checkout e.g. my Lua-cURL library.
I would use a string that describes what is in the "object" as this string is output in Lua error message eventually:
e.g. if the metatable is named "database connection":
stdin:1: bad argument #1 to 'status' (database connection expected, got no value)
If you use a UUID, nobody can make sense of the output.
Related
I'm a bit confused about the implications of the using declaration. The keyword implies that a new type is merely declared. This would allow for incomplete types. However, in some cases it is also a definition, no? Compare the following code:
#include <variant>
#include <iostream>
struct box;
using val = std::variant<std::monostate, box, int, char>;
struct box
{
int a;
long b;
double c;
box(std::initializer_list<val>) {
}
};
int main()
{
std::cout << sizeof(val) << std::endl;
}
In this case I'm defining val to be some instantiation of variant. Is this undefined behaviour? If the using-declaration is in fact a declaration and not a definition, incomplete types such as box would be allowed to instantiate the variant type. However, if it is also a definition, it would be UB no?
For the record, both gcc and clang both create "32" as output.
Since you've not included language-lawyer, I'm attempting a non-lawyer answer.
Why should that be UB?
With a using delcaration, you're just providing a synonym for std::variant<whatever>. That doesn't require an instantiation of the object, nor of the class std::variant, pretty much like a function declaration with a parameter of that class doesn't require it:
void f(val); // just fine
The problem would occur as soon as you give to that function a definition (if val is still incomplete because box is still incomplete):
void f(val) {}
But it's enough just to change val to val& for allowing a definition,
void f(val&) {}
because the compiler doesn't need to know anything else of val than its name.
Furthermore, and here I'm really inventing, "incomplete type" means that some definition is lacking at the point it's needed, so I expect you should discover such an issue at compile/link time, and not by being hit by UB. As in, how can the compiler and linker even finish their job succesfully if a definition to do something wasn't found?
Use case: I am converting data from a very old program of mine to a database friendly format. There are parts where I have to do multiple passes over the old data, because in particular the keys have to first exist before I can reference them in relationships. So I thought why not put the incomplete parts in a vector of references during the first pass and return it from the working function, so I can easily use that vector to make the second pass over whatever is still incomplete. I like to avoid pointers when possible so I looked into std::reference_wrapper<T> which seemes like exactly what I need .. except I don't understand it's behavior at all.
I have both vector<OldData> old_data and vector<NewData> new_data as member of my conversion class. The converting member function essentially does:
//...
vector<reference_wrapper<NewData>> incomplete;
for(const auto& old_elem : old_data) {
auto& new_ref = *new_data.insert(new_data.end(), convert(old_elem));
if(is_incomplete(new_ref)) incomplete.push_back(ref(new_ref));
}
return incomplete;
However, incomplete is already broken immediately after the for loop. The program compiles, but crashes and produces gibberish. Now I don't know if I placed ref correctly, but this is only one of many tries where I tried to put it somewhere else, use push_back or emplace_back instead, etc. ..
Something seems to be going out of scope, but what? both new_data and old_data are class members, incomplete also lives outside the loop, and according to the documentation, reference_wrapper is copyable.
Here's a simplified MWE that compiles, crashes, and produces gibberish:
// includes ..
using namespace std;
int main() {
int N = 2; // works correctly for N = 1 without any other changes ... ???
vector<string> strs;
vector<reference_wrapper<string>> refs;
for(int i = 0; i < N; ++i) {
string& sref = ref(strs.emplace_back("a"));
refs.push_back(sref);
}
for (const auto& r : refs) cout << r.get(); // crash & gibberish
}
This is g++ 10.2.0 with -std=c++17 if it means anything. Now I will probably just use pointers and be done, but I would like to understand what is going on here, documentation / search does not seem to help..
The problem here is that you are using vector data structure which might re-allocate memory for the entire vector any time that you add an element, so all previous references on that vector most probably get invalidated, you can resolve your problem by using list instead of vector.
I am having an issue with Luabind that I am unsure of how to fix without some over-simplified solution.
Luabind appears to only allow binding to functions using the __cdecl calling convention. In my current project all of the functionality exposed to extensions/plugins is exposed using __stdcall. This leaves me unable to bind the exposed objects directly and instead I have to make wrappers for the objects exposed. This would be fine but there are a lot of objects that would need to be wrapped.
For example, an object can look like this:
struct IObject
{
void __stdcall SomeFunc1( void );
void __stdcall SomeFunc2( const char* );
};
struct IObjectContainer
{
IObject* __stdcall GetObject( int );
IObject* __stdcall GetObject( const char* );
};
struct IObjectCore
{
IObjectContainer* __stdcall GetObjectContainer();
};
I don't have the option of changing the entire projects calling convention currently so I am seeing if someone has a solution to perhaps patch Luabind to work with __stdcall functions. I am not the best with templates and with boost things, so I'm personally unsure where to even start trying to add the ability to use __stdcall functions.
For reference, I am using:
Lua 5.1.4
Luabind 0.9.1
VS2010
Both Lua and Luabind are stock latest versions of their rev. (Not using Lua 5.2 for project restriction reasons, but if there is a __stdcall fix for 5.2/Luabind I will gladly take that as well.)
I could only find a fix for a very old version of Luabind to do this but the patch floating on the net still for that does not line up with the current Luabind code at all.
If there is any other information needed feel free to ask.
Sadly due to inactivity and no further answers from more searching I spoke with the project developer and have gotten the entire project stripped of __stdcall. So the bindings all work fine now via __cdecl. Not the route I wanted to take but things are working as planned now.
I faced the exact same problem when binding OpenGL (with GLEW functions) to Lua, and solved it using variadic templates.
Now if the function is global and you know its address in compile time, you can be good with something like this:
template<typename Signature>
struct wrap_known;
template<typename Ret, typename... Args>
struct wrap_known<Ret __stdcall (Args...)> {
template <Ret __stdcall functor(Args...)>
static Ret invoke(Args... arguments) {
return functor(arguments...);
}
};
// I know using macro is generally a bad idea but it's just shorter
#define wrap(f) wrap_known<decltype(f)>::invoke<f>
and then, when binding, use the macro like this:
luabind::def("Clear", wrap(glClear)),
luabind::def("Vertex4f", wrap(glVertex4f))
However, in your case, we have a bunch of member functions and not globals like above.
Here is the code for wrapping member functions with __stdcall calling convention:
template<typename Signature>
struct wrap_mem;
template<typename Sub, typename Ret, typename... Args>
struct wrap_mem<Ret(__stdcall Sub::*) (Args...)> {
template <Ret(__stdcall Sub::*functor) (Args...)>
static Ret invoke(Sub* subject, Args... arguments) {
return (subject->*functor)(arguments...);
}
};
#define wrap_member(f) wrap_mem<decltype(f)>::invoke<f>
Use it like this:
struct A {
int __stdcall my_method(double b) {
return 2;
}
};
// ...
luabind::class_<A>("A")
.def("my_method", wrap_member(&A::my_method))
Sometimes, however, you are not that lucky to know the function's address in compile time, and this happens with GLEW for example. For functions like glUniform*f, glGetUniformLocation, the "wrap" macro will not work, so I made another version for wrapping functions known at runtime:
template<typename Signature>
struct wrap_unknown;
template<typename Ret, typename... Args>
struct wrap_unknown<Ret (__stdcall*) (Args...)> {
template <Ret (__stdcall** functor)(Args...)>
static Ret invoke(Args... arguments) {
return (**functor)(arguments...);
}
};
#define wrap_ptr(f) wrap_unknown<decltype(f)>::invoke<&f>
(if above code scares you, it is actually a good sign)
Now you can bind GLEW functions like this:
luabind::def("Uniform4f", wrap_ptr(glUniform4f)),
luabind::def("GetUniformLocation", wrap_ptr(glGetUniformLocation))
Just don't ask me to write another version for binding pointers to members known at runtime :)
If you don't want to use C++11 for some reason, here you can find out how to pass function arguments and return value as template parameters in C++03.
I don't really want to go down the metatables etc. route as it seems rather complicated.
To crudely access 'C' structs in Lua I do:
void execute_lua_script(char *name)
{
lua_pushstring (L,name);
lua_gettable (L, LUA_GLOBALSINDEX);
lua_pushstring(L,"junk");
lua_pushinteger(L,7);
lua_pushlightuserdata(L, avatar_obj);
lua_pcall (L, 3, 2, 0);
}
The registered C func is:
int get_obj_struct(lua_State *L)
{
const char *str;
OBJECT_DEF *obj;
int stack;
obj=(OBJECT_DEF *)lua_touserdata(L,1);
str=lua_tostring(L,2);
//printf("\nIN OBJ:%d %s",obj,str);
if (!strcmp(str,"body->p.x"))
lua_pushnumber(L,obj->body->p.x);
if (!strcmp(str,"collided_with"))
lua_pushlightuserdata(L, obj->collided_with);
if (!strcmp(str,"type"))
lua_pushnumber(L,obj->type);
stack=lua_gettop(L);
//printf("\n%d",stack);
if (stack<3)
report_error("Unknown structure request ",(char *)str);
return 1;
}
Although crude; it works! :-)
The problem is when I request "collided_with" (a pointer); I need to return that back to my script; but for reasons I don't understand 'obj' ends up as nil.
My lua script:
function test(a,b,obj)
--print("\nLUA! test:",a,b);
b=b+1;
c=get_obj_struct(obj,"body->p.x");
--print("x:",c);
collided_with=get_obj_struct(obj,"collided_with");
type=get_obj_struct(collided_with,"type");
print("type:",type);
return a,b;
end
I am expecting 'collided_with' to be a pointer that I can then pass back into get_obj_struct and look for type.
I know it's something to do with me mis-using pushlightuserdata and also reading for the obj.
So an explanation would be great!. Also if someone wishes to give a version that uses 'tables' (as I assume that would be much more efficient) then I would be grateful for the help.
The online "Programming In Lua" book provides a good description of how to implement Lua types in C. In my opinion, your best bet would be to follow the examples provided in Chapter 28 to "do it right" and create a complete Lua wrapper for your object. In addition to being easier to maintain, it will almost certainly be more faster than a strcmp based implementation.
I want users of my C++ application to be able to provide anonymous functions to perform small chunks of work.
Small fragments like this would be ideal.
function(arg) return arg*5 end
Now I'd like to be able to write something as simple as this for my C code,
// Push the function onto the lua stack
lua_xxx(L, "function(arg) return arg*5 end" )
// Store it away for later
int reg_index = luaL_ref(L, LUA_REGISTRY_INDEX);
However I dont think lua_loadstring will do "the right thing".
Am I left with what feels to me like a horrible hack?
void push_lua_function_from_string( lua_State * L, std::string code )
{
// Wrap our string so that we can get something useful for luaL_loadstring
std::string wrapped_code = "return "+code;
luaL_loadstring(L, wrapped_code.c_str());
lua_pcall( L, 0, 1, 0 );
}
push_lua_function_from_string(L, "function(arg) return arg*5 end" );
int reg_index = luaL_ref(L, LUA_REGISTRY_INDEX);
Is there a better solution?
If you need access to parameters, the way you have written is correct. lua_loadstring returns a function that represents the chunk/code you are compiling. If you want to actually get a function back from the code, you have to return it. I also do this (in Lua) for little "expression evaluators", and I don't consider it a "horrible hack" :)
If you only need some callbacks, without any parameters, you can directly write the code and use the function returned by lua_tostring. You can even pass parameters to this chunk, it will be accessible as the ... expression. Then you can get the parameters as:
local arg1, arg2 = ...
-- rest of code
You decide what is better for you - "ugly code" inside your library codebase, or "ugly code" in your Lua functions.
Have a look at my ae. It caches functions from expressions so you can simply say ae_eval("a*x^2+b*x+c") and it'll only compile it once.