Short strings can be external, too

That complicates a little object equality (and therefore table access
for long strings), but the old behavior was somewhat weird. (Short
strings, a concept otherwise absent from the manual, could not be
external.)
This commit is contained in:
Roberto Ierusalimschy
2025-07-15 14:40:27 -03:00
parent c612685d4b
commit 60b6599e83
9 changed files with 168 additions and 120 deletions

106
lvm.c
View File

@@ -573,52 +573,74 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
*/
int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
const TValue *tm;
if (ttypetag(t1) != ttypetag(t2)) { /* not the same variant? */
if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER)
return 0; /* only numbers can be equal with different variants */
else { /* two numbers with different variants */
/* One of them is an integer. If the other does not have an
integer value, they cannot be equal; otherwise, compare their
integer values. */
lua_Integer i1, i2;
return (luaV_tointegerns(t1, &i1, F2Ieq) &&
luaV_tointegerns(t2, &i2, F2Ieq) &&
i1 == i2);
if (ttype(t1) != ttype(t2)) /* not the same type? */
return 0;
else if (ttypetag(t1) != ttypetag(t2)) {
switch (ttypetag(t1)) {
case LUA_VNUMINT: { /* integer == float? */
/* integer and float can only be equal if float has an integer
value equal to the integer */
lua_Integer i2;
return (luaV_flttointeger(fltvalue(t2), &i2, F2Ieq) &&
ivalue(t1) == i2);
}
case LUA_VNUMFLT: { /* float == integer? */
lua_Integer i1; /* see comment in previous case */
return (luaV_flttointeger(fltvalue(t1), &i1, F2Ieq) &&
i1 == ivalue(t2));
}
case LUA_VSHRSTR: case LUA_VLNGSTR: {
/* compare two strings with different variants: they can be
equal when one string is a short string and the other is
an external string */
return luaS_eqstr(tsvalue(t1), tsvalue(t2));
}
default:
/* only numbers (integer/float) and strings (long/short) can have
equal values with different variants */
return 0;
}
}
/* values have same type and same variant */
switch (ttypetag(t1)) {
case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: return 1;
case LUA_VNUMINT: return (ivalue(t1) == ivalue(t2));
case LUA_VNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2));
case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
case LUA_VLCF: return fvalue(t1) == fvalue(t2);
case LUA_VSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2));
case LUA_VLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2));
case LUA_VUSERDATA: {
if (uvalue(t1) == uvalue(t2)) return 1;
else if (L == NULL) return 0;
tm = fasttm(L, uvalue(t1)->metatable, TM_EQ);
if (tm == NULL)
tm = fasttm(L, uvalue(t2)->metatable, TM_EQ);
break; /* will try TM */
else { /* equal variants */
switch (ttypetag(t1)) {
case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
return 1;
case LUA_VNUMINT:
return (ivalue(t1) == ivalue(t2));
case LUA_VNUMFLT:
return (fltvalue(t1) == fltvalue(t2));
case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
case LUA_VSHRSTR:
return eqshrstr(tsvalue(t1), tsvalue(t2));
case LUA_VLNGSTR:
return luaS_eqstr(tsvalue(t1), tsvalue(t2));
case LUA_VUSERDATA: {
if (uvalue(t1) == uvalue(t2)) return 1;
else if (L == NULL) return 0;
tm = fasttm(L, uvalue(t1)->metatable, TM_EQ);
if (tm == NULL)
tm = fasttm(L, uvalue(t2)->metatable, TM_EQ);
break; /* will try TM */
}
case LUA_VTABLE: {
if (hvalue(t1) == hvalue(t2)) return 1;
else if (L == NULL) return 0;
tm = fasttm(L, hvalue(t1)->metatable, TM_EQ);
if (tm == NULL)
tm = fasttm(L, hvalue(t2)->metatable, TM_EQ);
break; /* will try TM */
}
case LUA_VLCF:
return (fvalue(t1) == fvalue(t2));
default: /* functions and threads */
return (gcvalue(t1) == gcvalue(t2));
}
case LUA_VTABLE: {
if (hvalue(t1) == hvalue(t2)) return 1;
else if (L == NULL) return 0;
tm = fasttm(L, hvalue(t1)->metatable, TM_EQ);
if (tm == NULL)
tm = fasttm(L, hvalue(t2)->metatable, TM_EQ);
break; /* will try TM */
if (tm == NULL) /* no TM? */
return 0; /* objects are different */
else {
int tag = luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
return !tagisfalse(tag);
}
default:
return gcvalue(t1) == gcvalue(t2);
}
if (tm == NULL) /* no TM? */
return 0; /* objects are different */
else {
int tag = luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
return !tagisfalse(tag);
}
}