From 5b7d9987642f72d44223a8e5e79e013bb2b3d579 Mon Sep 17 00:00:00 2001 From: Roberto I Date: Tue, 11 Nov 2025 14:40:30 -0300 Subject: External strings are as good as internal ones A '__mode' metafield and an "n" key both can be external strings. --- lgc.c | 6 +++--- ltm.c | 2 +- lvm.c | 9 +++++++-- testes/strings.lua | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/lgc.c b/lgc.c index a775b6e5..60f042c7 100644 --- a/lgc.c +++ b/lgc.c @@ -594,10 +594,10 @@ static void traversestrongtable (global_State *g, Table *h) { */ static int getmode (global_State *g, Table *h) { const TValue *mode = gfasttm(g, h->metatable, TM_MODE); - if (mode == NULL || !ttisshrstring(mode)) - return 0; /* ignore non-(short)string modes */ + if (mode == NULL || !ttisstring(mode)) + return 0; /* ignore non-string modes */ else { - const char *smode = getshrstr(tsvalue(mode)); + const char *smode = getstr(tsvalue(mode)); const char *weakkey = strchr(smode, 'k'); const char *weakvalue = strchr(smode, 'v'); return ((weakkey != NULL) << 1) | (weakvalue != NULL); diff --git a/ltm.c b/ltm.c index 92a03e71..8d64235e 100644 --- a/ltm.c +++ b/ltm.c @@ -287,7 +287,7 @@ void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc) { return; } } - else if (ttisshrstring(rc)) { /* short-string value? */ + else if (ttisstring(rc)) { /* string value? */ size_t len; const char *s = getlstr(tsvalue(rc), len); if (len == 1 && s[0] == 'n') { /* key is "n"? */ diff --git a/lvm.c b/lvm.c index 2a9fb67a..2c868c21 100644 --- a/lvm.c +++ b/lvm.c @@ -657,6 +657,11 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { #define tostring(L,o) \ (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) +/* +** Check whether object is a short empty string to optimize concatenation. +** (External strings can be empty too; they will be concatenated like +** non-empty ones.) +*/ #define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) /* copy strings in stack from top - n up to top - 1 to buffer */ @@ -691,8 +696,8 @@ void luaV_concat (lua_State *L, int total) { setobjs2s(L, top - 2, top - 1); /* result is second op. */ } else { - /* at least two non-empty string values; get as many as possible */ - size_t tl = tsslen(tsvalue(s2v(top - 1))); + /* at least two string values; get as many as possible */ + size_t tl = tsslen(tsvalue(s2v(top - 1))); /* total length */ TString *ts; /* collect total length and number of strings */ for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { diff --git a/testes/strings.lua b/testes/strings.lua index 46912d43..84ff1154 100644 --- a/testes/strings.lua +++ b/testes/strings.lua @@ -540,6 +540,23 @@ else assert(y == x) local z = T.externstr(x) -- external allocated long string assert(z == y) + + local e = T.externstr("") -- empty external string + assert(e .. "x" == "x" and "x" .. e == "x") + assert(e .. e == "" and #e == 0) + + -- external string as the "n" key in vararg table + local n = T.externstr("n") + local n0 = T.externstr("n\0") + local function aux (...t) assert(t[n0] == nil); return t[n] end + assert(aux(10, 20, 30) == 3) + + -- external string as mode in weak table + local t = setmetatable({}, {__mode = T.externstr("kv")}) + t[{}] = {} + assert(next(t)) + collectgarbage() + assert(next(t) == nil) end print('OK') -- cgit v1.2.3-55-g6feb