Reputation: 713
I would like improve my code below by sending a C++ Pre-formatted Lua Table:
int GetCategory(lua_State* L)
{
uint32 Type = CHECKVAL<int>(L, 1);
lua_newtable(L);
int tbl = lua_gettop(L);
uint32 counter = 1;
// Struct CT { string CategoryBrandName, CategoryName }; > Vector<CT>
auto list = sManagerMgr->GetAll();
// Hack modify this to send a metatable/UserData/Table whatever is called
for (auto& elem : list)
{
switch (Type)
{
case 1:
lua_pushstring(L, elem->CategoryBrandName);
break;
case 2:
lua_pushstring(L, elem->CategoryName);
break;
}
lua_rawseti(L, tbl, counter);
counter++;
}
lua_settop(L, tbl);
return 1;
}
Basically, lua_newtable pushes a table to the lua stack, lua_gettop will take the top index, so the index where the table is at. Then lua_pushstring(L, ELEMENT); lua_rawseti(L, tbl, counter); will put the ELEMENT to the table at the index tbl we got with gettop. The index of the element is the value of counter.
But The issue here is that i'm forced to call twice the fonction GetCategory to fill it as follow in my .lua file.
table.insert(Group, { GetCategory(1), GetCategory(2) });
Current Use :
print(i, Group(1)[i], Group(2)[i]);
So.. I would prefer to call it once and get something like this directly :
local Group =
{
[1] = { "elem->CategoryBrandName[1]", "elem->CategoryName[1]" },
[2] = { "elem->CategoryBrandName[2]", "elem->CategoryName[2]" }
--etc
};
I've tried filling elem into an 2D Array[1][2] and then pushing Array unsuccessfully
I've made a lot of research about Table, Metatables, MultiDimentional Arrays etc but I couldn't find something that would fit my need or works.
Does anyone has a solution ?
Upvotes: 0
Views: 1946
Reputation: 713
In case if anyone is looking to something similar, here's how I managed by using lua_createtable. It works as intended, It may need some improvement thought.
int GetCategory(lua_State* L)
{
int counter = 1;
int MaxListSize = 2;
auto Categories = sManagerMgr->GetAll();
lua_createtable(L, Categories.size(), 0);
for (auto& elem : Categories)
{
vector<string> list;
list.reserve(MaxListSize);
list.emplace_back(elem->CategoryBrandName);
list.emplace_back(elem->CategoryName);
Macro::Push(L, counter); // custom
lua_createtable(L, 0, MaxListSize);
for (int i = 1; i <= MaxListSize; i++)
{
Macro::Push(L, list.at(i - 1)); // custom
lua_rawseti(L, -2, i);
}
lua_settable(L, -3);
list.clear();
counter++;
}
return 1;
}
Would produce an output similar to
local Group =
{
[1] = { "elem->CategoryBrandName[1]", "elem->CategoryName[2]" },
[2] = { "elem->CategoryBrandName[1]", "elem->CategoryName[2]" }
--etc
};
Upvotes: 0
Reputation: 7056
Why don't you just have your function return both values? Then you could just write
local Group = { GetCategories }
I am no expert with the C API, but I think this could be done fairly easily by just calling lua_newtable(L)
, so something like this:
int GetCategories(lua_State* L) {
lua_settop(L, 0);
// Discard arguments so we don't have to save the top of the stack
// and can just use numbers instead (see following lines)
lua_newtable(L); // Index 1 on stack
lua_newtable(L); // Index 2 on stack
// Do your magic
lua_settop(L, 2); // Get rid of your temp variables
return 2; // number of values we return in Lua
}
Optimization hint: you can use lua_createtable
and tell it how many elements each of the tables will have so Lua can pre-allocate some memory for it.
EDIT: I just noticed this, but in your code:
for (auto& elem : list) {
switch (Type) {
case 1:
lua_pushstring(L, elem->CategoryBrandName);
break;
case 2:
lua_pushstring(L, elem->CategoryName);
break;
}
lua_rawseti(L, tbl, counter);
counter++;
}
You just keep pushing values to the stack. This may, for long vectors, overflow the stack (sooner rather than later), leading to trouble. A better approach would be to 1) push to stack 2) insert into table 3) pop them back off:
// Modified for my suggested implementation that returns
// two tables. They can easily be turned around here.
for (auto& elem : list) {
lua_pushstring(L, elem->CategoryBrandName);
lua_rawseti(L, 1, counter++);
lua_pop(L, 1);
lua_pushstring(L, elem->CategoryName);
lua_rawseti(L, 2, counter++);
lua_pop(L, 1);
}
It's always a good idea to be aware of what is and what isn't on the stack. Saving some memory can not only improve performance, but also avoid potential problems due to (Lua) stack overflow.
One last detail: You don't need ;
in Lua, and it is considered bad style to use them unless you have two statements in one line print('more readable'); print('like this')
.
Upvotes: 1