Expose C functions/variables via Lua metatable without large if/else block? - c

I want to create a global interface for a struct instance accessible in Lua. For example, I would create a global instance of a metatable called window as main_window, I would want to then do things like this from Lua:
main_window.color = {1, 2, 3}
main_window.position.x = 64
main_window.show(true)
In an attempt to do this, I used the code from this answer as a base since it's the closest thing I could find. I ended up with an API like this
lua_create_window_type(L);
lua_expose_window(L, main_window);
lua_setglobal(L, "main_window");
...
static int lua_window_index(lua_State* L)
{
struct window_state** w = luaL_checkudata(L, 1, "window");
char* index = luaL_checkstring(L, 2);
if (strcmp(index, "x") == 0) {
lua_pushnumber(L, (*w)->x);
} else if (strcmp(index, "show") == 0) {
lua_pushcfunction(L, lua_window_show);
} else {
...
}
return 1;
}
static int lua_window_newindex(lua_State* L)
{
struct window_state** w = luaL_checkudata(L, 1, "window");
char* index = luaL_checkstring(L, 2);
if (strcmp(index, "x") == 0) {
(*w)->x = luaL_checkinteger(L, 3);
} else {
...
}
return 0;
}
I am inevitably going to end up with tens or hundreds of functions and variables I want to be accessible. Using this template I would have to manually create a if strcmp == 0 else if for every single one. I'd have to duplicate the entire block to allow assignment. I also don't want to end up with functions near the end being comparatively slow to call due to the amount of string comparisons. Overall this does not seem like a "maintainable" solution, nor one the Lua authors would have intended.
When I only needed functions all I had to do was push a standard global table and whatever functions I needed, but trying to allow direct variable access like a native Lua table makes this more difficult (before you ask why not just use functions, I've tried and only having "getter/setter" function access from Lua is very painful and ugly for my uses).
Suggestions for more maintainable alternatives to duplicated if/else blocks?

Related

Stack overflow for huge file with many variables in different scopes

I have a autogenerated file creating structs and doing some calculations with them.
Each struct has its dedicated scope.
typedef struct
{
uint16_t a;
uint16_t b;
} Addition_t;
uint8_t StructsOverflow(void)
{
{ // use new scope to declare same variable multiple times
Addition_t x = {.a = 5, .b=6};
if (x.a == x.b)
return 1;
}
{
Addition_t x = {.a = 3, .b=6};
if (x.a == x.b)
return 1;
}
{
Addition_t x = {.a = 3, .b=5};
if (x.a == x.b)
return 1;
}
// and so on
// here other structs are created in the same fashion as above
return 0;
}
For a huge number of Lines (about 100,000 structs), running the .exe stops with a StackOverflow: Exception thrown at 0x00007FF7F2C8B6C8 in EnergyPredictionMain.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x0000001815603000)..
Im using the MSVC 2019 compiler and cppvsdbg for debugging.
Why is there an stackoverflow? In my understanding the variables are destroyed after the scope, so only the memory of one struct should be used.
Why? Because, in a Debug build (IIRC), MSVC doesn't deallocate local variables when they go out of scope in this way. In a Release build, it will probably work.
But what's really broken here, IMO, is whatever it is that autogenerates that file. Would it be practical to change it to generate 100,000 separate sub-functions, each initialising (and then processing) one struct? Then invoke each of them in turn from an (also auto-generated) 'master' function.
If you can do that, it should provide a robust and future-proof fix.

Determine the number of return values expected by Lua from inside a C extension function

Every time a function in Lua is called, the number of return values is immediately known at the call site:
f() --0
local a, b = f() --2
local t = {f()} --LUA_MULTRET
local t = {f(), nil} --1
The same is true for the C API: both lua_call and lua_pcall are always provided with the expected number of return values (or LUA_MULTRET).
Thinking about performance, it might be advantageous for a Lua function to be able to determine the number of expected return values expressed by their callers, so as to avoid computing return values that the caller did not request (if the computation takes a long time):
int getstrings(lua_State *L)
{
if(lua_numresults(L) > 0)
{
lua_pushstring(L, "a");
if(lua_numresults(L) > 1)
{
lua_pushstring(L, "b");
if(lua_numresults(L) > 2)
{
lua_pushstring(L, "c");
return 3
}
return 2;
}
return 1
}
return 0;
}
Assuming a hypothetical lua_numresults returns size_t, this function would produce only the that are really needed and will not take time to compute values that are guaranteed to be lost.
Another interesting example would be functions that return sequences:
int range(lua_State *L)
{
size_t num = lua_numresults(L);
for(size_t i = 1; i <= num; i++)
{
lua_pushinteger(L, i);
}
return num;
}
The sequence is not "lazy" so something like f(range()) cannot be done, but local a, b, c = range() returning 1, 2, 3 etc. might find its uses.
Is there anything like lua_numresults or a way to implement its functionality?
Judging from Lua 5.3 sources, the expected number of results is located in the CallInfo structure. A new call info is created for every Lua call, and the most recent one is stored in lua_State::ci There doesn't appear to be any function that can return this value, but if one has access to the structure, it is fairly straightforward to get it:
#include "lua/lstate.h"
size_t lua_numresults(lua_State *L)
{
return (size_t)L->ci->nresults;
}

Can gcc/clang optimize initialization computing?

I recently wrote a parser generator tool that takes a BNF grammar (as a string) and a set of actions (as a function pointer array) and output a parser (= a state automaton, allocated on the heap). I then use another function to use that parser on my input data and generates a abstract syntax tree.
In the initial parser generation, there is quite a lot of steps, and i was wondering if gcc or clang are able to optimize this, given constant inputs to the parser generation function (and never using the pointers values, only dereferencing them) ? Is is possible to run the function at compile time, and embed the result (aka, the allocated memory) in the executable ?
(obviously, that would be using link time optimization, since the compiler would need to be able to check that the whole function does indeed have the same result with the same parameters)
What you could do in this case is have code that generates code.
Have your initial parser generator as a separate piece of code that runs independently. The output of this code would be a header file containing a set of variable definitions initialized to the proper values. You then use this file in your main code.
As an example, suppose you have a program that needs to know the number of bits that are set in a given byte. You could do this manually whenever you need:
int count_bits(uint8_t b)
{
int count = 0;
while (b) {
count += b & 1;
b >>= 1;
}
return count;
}
Or you can generate the table in a separate program:
int main()
{
FILE *header = fopen("bitcount.h", "w");
if (!header) {
perror("fopen failed");
exit(1);
}
fprintf(header, "int bit_counts[256] = {\n");
int count;
unsigned v;
for (v=0,count=0; v<256; v++) {
uint8_t b = v;
while (b) {
count += b & 1;
b >>= 1;
}
fprintf(header, " %d,\n" count);
}
fprintf(header, "};\n");
fclose(header);
return 0;
}
This create a file called bitcount.h that looks like this:
int bit_counts[256] = {
0,
1,
1,
2,
...
7,
};
That you can include in your "real" code.

passing struct to function C

I have initialised 3 instances of a cache I have defined using typedef. I have done some processing on them in a serious of if statements in the following way :
cache cache1;
cache cache2;
cache cache3;
int a;
void main(...) {
if (a == 0) {
cache1.attribute = 5;
}
else if (a == 1) {
cache2.attribute = 1;
}
else if (a == 2) {
cache3.attribute = 2 ;
}
However now I need to make the design modular in the following way:
cache cache1;
cache cache2;
cache cache3;
void cache_operator( cache user_cache, int a ) {
user_cache.attribute = a;
}
void main(...) {
if (a == 0) {
cache_operator(cache1,5);
}
else if (a == 1) {
cache_operator(cache2,1);
}
...
I am having trouble with passing the cache to the method. I'm used to java programming and I'm not very familiar with c pointers. However, if I pass the cache itself as shown above I am passing a copy of the cache on the stack which then produces results different to the original code. How do I properly transform the first design into the second design when it comes to passing the appropriate cache to the function and making sure it is accessed properly.
In C language, if you want to keep track of the original 'data' instead of creating a copy in the function, you have to pass the pointer of that data to that function.
Pointer in C is just like the reference to object in JAVA.
Following is how you do it.
void cache_operator( cache *user_cache, int a )
{
user_cache->attribute = a;
}
Following is how you call the function.
cache_operator(&cache1,5);
I also started with JAVA. I don't know why some universities nowadays use JAVA as beginning language... It is quite strange, since JAVA is a high-level language making the abstraction of low-level detail, whereas C is a rather low-level language. In the past, this will never be the case..

Nested lua_CFunction calls

What is the best way to deal with nested lua_CFunction calls? Assume I have two function like this:
static int function2(lua_State *L) {
int i = luaL_checkint(L, 1);
/* do something */
return 1;
};
static int function1(lua_State *L) {
struct udata *u = luaL_checkudata(L, 1, UDATA_METATABLE);
int i = luaL_checkint(L, 2);
/* do something */
/* this does not work, first on call stack is udata, not int */
return function2(L);
};
The function call as above does not work. One option is to modify function2() to use the last element (index -1) on stack, but this is not a sollution in general since function2() might be called from various places with different call stacks.
Another way would be to replace the return function2(L); by
lua_pushcfunction(L, function2);
lua_pushvalue(L, 2);
lua_call(L, 1, 1); /* need to know number of results */
I assume this gives function2() its own call stack so there is no need to modify it. But this sollution seems overly complicated for functions with more parameters since it requires duplicating all of them on the stack.
tl;dr: What is the recommended way/a good way to call a lua_CFunction from inside another one?
In function1 you are expecting the bottom of the stack to be user data.
When you call function2 directly, the LuaState has not changed and therefore the bottom is still user data.
You can successfully call function2 from function1 by ensuring an integer is at index 1.
You could do this by calling lua_insert(L, 1) which will move the top (assuming index 2), to index 1.
You could also do this by popping all values the pushing the integer back on:
lua_pop(L, lua_gettop(L));
lua_pushnumber(L, i);
return function2(L);
lua_CFunction is not fully Lua function. It just a way to create Lua function/closure.
static int function1(lua_State *L) {
....
int top = lua_gettop(L);
lua_pushcfunction(L, function2);
lua_pushvalue(L, 2);
lua_call(L, 1, LUA_MULTRET);
return lua_gettop(L) - 1;
}
The Lua equivalent is
function function1(arg)
return (function(arg) --[[body of f2]] end)(arg)
end
So you create each time new function and call it.
For C function it is quite ok because it no need to compile and you do not need upvalue.
Also Lua 5.2 introduce light function for that.
But if you want equivalent for
int i = 1
local function function2(arg)
i = i + 1
...
end
function function1(arg)
return function2(arg)
end
You need a way to find real Lua function e.g. (not tested)
int f2_ref;
static int function1(lua_State *L) {
...
-- push `function2` on stack
lua_rawgeti(L, LUA_REGISTRYINDEX, f2_ref);
-- as above
}
static int function2(lua_State *L) {
int my_upvalue = lua_tonumber(L, lua_upvalueindex(1));
my_upvalue++;
lua_pushnumber(L, my_upvalue);
lua_replace(L, lua_upvalueindex(1));
...
}
int luaopen_foo(lua_State *L){
-- Here we create instance of Lua function(closure)
lua_pushnumber(L, 1);
lua_pushcclosure(L, function2, 1);
f2_ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushcclosure(L, function1, 0);
return 1;
}
I'd say that calling it through lua is the recommended way to do that but if you don't want to do that for some reason then Timma's suggestions are the right ones.

Resources