Skip to content

Commit 99c1624

Browse files
author
q66
committed
refactor table initializers to allow struct init inside array init
While at it, simplify the code to remove a special path for single initializer. Fixes #54
1 parent dfd6d43 commit 99c1624

2 files changed

Lines changed: 32 additions & 25 deletions

File tree

src/ffi.cc

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,9 +1150,7 @@ static void from_lua_table(
11501150
);
11511151

11521152
static void from_lua_str(
1153-
lua_State *L, ast::c_type const &decl,
1154-
void *stor, std::size_t dsz, int idx, std::size_t nelems = 1,
1155-
std::size_t bsize = 0
1153+
lua_State *L, ast::c_type const &decl, void *stor, std::size_t dsz, int idx
11561154
) {
11571155
std::size_t vsz;
11581156
ffi::scalar_stor_t sv{};
@@ -1173,16 +1171,11 @@ static void from_lua_str(
11731171
/* char-like array, string value */
11741172
vp = lua_tolstring(L, idx, &vsz);
11751173
/* add 1 because of null terminator, but use at most the given space */
1176-
vsz = util::min(vsz + 1, dsz);
1177-
goto cloop;
1174+
std::memcpy(val, vp, util::min(vsz + 1, dsz));
1175+
return;
11781176
fallback:
11791177
vp = from_lua(L, decl, &sv, idx, vsz, RULE_CONV);
1180-
cloop:
1181-
while (nelems) {
1182-
std::memcpy(val, vp, vsz);
1183-
val += bsize;
1184-
--nelems;
1185-
}
1178+
std::memcpy(val, vp, vsz);
11861179
}
11871180

11881181
static void from_lua_table_record(
@@ -1275,37 +1268,41 @@ static void from_lua_table(
12751268
}
12761269

12771270
auto *val = static_cast<unsigned char *>(stor);
1271+
auto *oval = val;
12781272
auto &pb = decl.ptr_base();
12791273
auto bsize = pb.alloc_size();
12801274
auto nelems = rsz / bsize;
1275+
auto flex = decl.flex();
12811276

12821277
bool base_array = (pb.type() == ast::C_BUILTIN_ARRAY);
12831278
bool base_struct = (pb.type() == ast::C_BUILTIN_RECORD);
12841279

1285-
if (!decl.flex()) {
1286-
if (ninit > int(nelems)) {
1287-
luaL_error(L, "too many initializers");
1288-
return;
1289-
} else if (ninit == 1) {
1290-
/* special case: initialize aggregate with a single value */
1291-
push_init(L, tidx, sidx);
1292-
from_lua_str(L, pb, val, bsize, -1, nelems, bsize);
1293-
lua_pop(L, 1);
1294-
return;
1295-
}
1280+
if (!flex && (ninit > int(nelems))) {
1281+
luaL_error(L, "too many initializers");
1282+
return;
12961283
}
12971284

12981285
for (int rinit = ninit; rinit; --rinit) {
1286+
push_init(L, tidx, sidx++);
12991287
if ((base_array || base_struct) && lua_istable(L, -1)) {
1300-
from_lua_table(L, pb, val, bsize, lua_gettop(L));
1288+
from_lua_table(L, pb, val, bsize, -1);
13011289
} else {
1302-
push_init(L, tidx, sidx++);
13031290
from_lua_str(L, pb, val, bsize, -1);
13041291
}
13051292
val += bsize;
13061293
lua_pop(L, 1);
13071294
}
1308-
if (ninit < int(nelems)) {
1295+
if (!flex && (ninit == 1)) {
1296+
/* special case: initialize aggregate with a single value
1297+
*
1298+
* initialize the first element in the memory space and then
1299+
* replicate across the rest evenly until the end of it
1300+
*/
1301+
while (nelems-- > 1) {
1302+
std::memcpy(val, oval, bsize);
1303+
val += bsize;
1304+
}
1305+
} else if (ninit < int(nelems)) {
13091306
/* fill possible remaining space with zeroes */
13101307
std::memset(val, 0, bsize * (nelems - ninit));
13111308
}

tests/table_init.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,16 @@ x = ffi.new("struct dsinit", {{5}, {10}})
104104
assert(x.a.x == 5)
105105
assert(x.b.x == 10)
106106

107+
x = ffi.new("struct sstr[3]", {[0] = {x = 5}})
108+
assert(x[0].x == 5)
109+
assert(x[1].x == 5)
110+
assert(x[2].x == 5)
111+
112+
x = ffi.new("struct sstr[3]", {{x = 5}})
113+
assert(x[0].x == 5)
114+
assert(x[1].x == 5)
115+
assert(x[2].x == 5)
116+
107117
x = ffi.new("struct flex", 2, { 5, 10, 15 })
108118
assert(x.x == 5)
109119
assert(x.y[0] == 10)

0 commit comments

Comments
 (0)