1

I'm trying to send multiple float arrays from C++ to Lua function as arguments and then return multiple tables from the function so I can use them again as float arrays in C++.

So my Lua function will look like this.

function perform(arg1, arg2)
    local ret1, ret2 = {}, {}
    for i=1, #arg1 do
        ret1[i] = arg1[i] * 0.2;
        ret2[i] = arg2[i] * 0.3;
    end
    return ret1, ret2
end

And this is how I send and return multiple tables to/from Lua function in C++.

lua_getglobal(L, "perform");

for (int i=0; i<numArgs; ++i) {

    lua_newtable(L);
    float *in = reinterpret_cast<float*>(w[i]);

    for (int j=0; j<64; ++j) {

        lua_pushinteger(L, j+1);
        lua_pushnumber(L, in[j]);
        lua_settable(L, -3);
    }
}
lua_call(L, numArgs, numRets);

for (int i=0; i<numRets; ++i) {

    float *out = reinterpret_cast<float*>(w[numArgs+i]);

    for (int j=0; j<64; ++j) {

        lua_pushinteger(L, j+1);
        lua_gettable(L, -2);
        out[j] = lua_tonumber(L, -1);
        lua_pop(L, 1);
    }
    //how to detect next returned table?
}

But if I try the code, the returned arrays have same values.

I think it's because I'm not correctly getting the returned tables.

Could anybody please teach me how to get multiple returned tables correctly?

P.S: I would also like to know if my code can be optimized for better performance.

EDIT : Would it be faster(more efficient) to pass and return one table that has multiple sub-tables? If so, I'd appreciate if anyone can teach me how to do it.

2
  • 1
    why have 2 table ? Why a not have one table which has two element on each entry ? Commented Jun 14, 2018 at 9:50
  • @Clonk Would it be faster to pass one table that has 2 sub-tables? and also, would it be faster to return one table that has 2 sub-tables? Commented Jun 14, 2018 at 10:01

1 Answer 1

1

I have no idea what you are trying to do here, but the second table returned from the function is easily accessible on the stack. You just have to perform some arithmetic on the stack index to get to the correct position.

Those reinterpret_casts look extremely fishy to me. You are quite likely to be doing something wrong.

#include <iostream>
#include <vector>

#include <lua.hpp>

int main(int argc, char *argv[]) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    if (argc != 2) {
        std::cerr << "Usage: " << argv[0] << " <script.lua>\n";
        return 1;
    }

    luaL_dofile(L, argv[1]);

    // Mock data
    int numArgs = 2;
    int numRets = 2;
    std::vector<float> w1(64, 1.0f);
    std::vector<float> w2(64, 1.0f);
    std::vector<float> w3(64, 1.0f);
    std::vector<float> w4(64, 1.0f);
    std::vector<float *> w = {w1.data(), w2.data(), w3.data(), w4.data()};

    lua_getglobal(L, "perform");

    for (int i = 0; i < numArgs; ++i) {

        lua_newtable(L);
        float *in = reinterpret_cast<float *>(w[i]);

        for (int j = 0; j < 64; ++j) {
            lua_pushinteger(L, j + 1);
            lua_pushnumber(L, in[j]);
            lua_settable(L, -3);
        }
    }

    lua_call(L, numArgs, numRets);

    for (int i = 0; i < numRets; ++i) {

        float *out = reinterpret_cast<float *>(w[numArgs + i]);

        for (int j = 0; j < 64; ++j) {
            lua_pushinteger(L, j + 1);
            lua_gettable(L, -2 - i); // Just some stack index arithmetic
            out[j] = lua_tonumber(L, -1);
            lua_pop(L, 1);
        }
    }

    lua_close(L);
}
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you so much! It works now. But I had to set the stack index as -numRets-1 + i instead of -2 - i in order to match arg1=ret1, arg2=ret2. And reinterpret_cast was used because w is long * type.(for storing any pointers)
Could you please answer the question I wrote at the end of my post?
I don't think using subtables would be faster but you'd need considerably more boilerplate on the C++ side. However, the only way to know for sure is to benchmark.
You mean I'd need considerably more boilerplate on the C++ side if I use subtables right? Then I will stick with the current design. :) Thank you so much!
@ZackLee Yes, you'd need more boilerplate in C++ because you'd have to index the parent table first before you can index the subtables which requires an extra loop and an extra lua_gettable. In the current solutions, the two tables are already on the stack, ready to be traversed.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.