Skip to content

Instantly share code, notes, and snippets.

@MCJack123
Last active October 1, 2022 18:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MCJack123/f1d6ca961260e93e806f89f4451e2c86 to your computer and use it in GitHub Desktop.
Save MCJack123/f1d6ca961260e93e806f89f4451e2c86 to your computer and use it in GitHub Desktop.
Rope concatenation for Lua 5.1 inspired by SquidDev/Cobalt
diff -ruN lua-5.1.5-clean/src/Makefile lua-5.1.5-ropes/src/Makefile
--- lua-5.1.5-clean/src/Makefile 2012-02-13 15:41:22.000000000 -0500
+++ lua-5.1.5-ropes/src/Makefile 2021-06-19 08:03:46.000000000 -0400
@@ -135,7 +135,7 @@
ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h lstring.h \
ltable.h lundump.h lvm.h
-ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \
+ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h lstring.h ltm.h \
lzio.h lmem.h lundump.h
lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \
lstate.h ltm.h lzio.h
@@ -162,7 +162,7 @@
ltm.h lzio.h lstring.h lgc.h
lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h
ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
- ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h
+ ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h lstring.h
ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h
ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \
lmem.h lstring.h lgc.h ltable.h
diff -ruN lua-5.1.5-clean/src/lapi.c lua-5.1.5-ropes/src/lapi.c
--- lua-5.1.5-clean/src/lapi.c 2008-07-04 14:41:18.000000000 -0400
+++ lua-5.1.5-ropes/src/lapi.c 2021-06-19 08:04:27.000000000 -0400
@@ -241,7 +241,7 @@
LUA_API int lua_type (lua_State *L, int idx) {
StkId o = index2adr(L, idx);
- return (o == luaO_nilobject) ? LUA_TNONE : ttype(o);
+ return (o == luaO_nilobject) ? LUA_TNONE : (ttisrope(o) ? LUA_TSTRING : ttype(o));
}
@@ -260,13 +260,13 @@
LUA_API int lua_isnumber (lua_State *L, int idx) {
TValue n;
const TValue *o = index2adr(L, idx);
- return tonumber(o, &n);
+ return tonumber(L, o, &n);
}
LUA_API int lua_isstring (lua_State *L, int idx) {
int t = lua_type(L, idx);
- return (t == LUA_TSTRING || t == LUA_TNUMBER);
+ return (t == LUA_TSTRING || t == LUA_TNUMBER || t == LUA_TROPE);
}
@@ -313,7 +313,7 @@
LUA_API lua_Number lua_tonumber (lua_State *L, int idx) {
TValue n;
const TValue *o = index2adr(L, idx);
- if (tonumber(o, &n))
+ if (tonumber(L, o, &n))
return nvalue(o);
else
return 0;
@@ -323,7 +323,7 @@
LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) {
TValue n;
const TValue *o = index2adr(L, idx);
- if (tonumber(o, &n)) {
+ if (tonumber(L, o, &n)) {
lua_Integer res;
lua_Number num = nvalue(o);
lua_number2integer(res, num);
@@ -362,6 +362,7 @@
StkId o = index2adr(L, idx);
switch (ttype(o)) {
case LUA_TSTRING: return tsvalue(o)->len;
+ case LUA_TROPE: return trvalue(o)->len;
case LUA_TUSERDATA: return uvalue(o)->len;
case LUA_TTABLE: return luaH_getn(hvalue(o));
case LUA_TNUMBER: {
@@ -559,7 +560,7 @@
lua_lock(L);
t = index2adr(L, idx);
api_check(L, ttistable(t));
- setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
+ setobj2s(L, L->top - 1, luaH_get(L, hvalue(t), L->top - 1));
lua_unlock(L);
}
@@ -597,6 +598,9 @@
case LUA_TUSERDATA:
mt = uvalue(obj)->metatable;
break;
+ case LUA_TROPE:
+ mt = G(L)->mt[LUA_TSTRING];
+ break;
default:
mt = G(L)->mt[ttype(obj)];
break;
diff -ruN lua-5.1.5-clean/src/ldebug.c lua-5.1.5-ropes/src/ldebug.c
--- lua-5.1.5-clean/src/ldebug.c 2008-05-08 12:56:26.000000000 -0400
+++ lua-5.1.5-ropes/src/ldebug.c 2021-06-19 07:59:07.000000000 -0400
@@ -579,15 +579,15 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
- if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
+ if (ttisstring(p1) || ttisnumber(p1) || ttisrope(p1)) p1 = p2;
lua_assert(!ttisstring(p1) && !ttisnumber(p1));
luaG_typeerror(L, p1, "concatenate");
}
void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) {
TValue temp;
- if (luaV_tonumber(p1, &temp) == NULL)
+ if (luaV_tonumber(L, p1, &temp) == NULL)
p2 = p1; /* first operand is wrong */
luaG_typeerror(L, p2, "perform arithmetic on");
}
diff -ruN lua-5.1.5-clean/src/ldump.c lua-5.1.5-ropes/src/ldump.c
--- lua-5.1.5-clean/src/ldump.c 2007-12-27 08:02:25.000000000 -0500
+++ lua-5.1.5-ropes/src/ldump.c 2021-06-19 07:59:07.000000000 -0400
@@ -13,6 +13,7 @@
#include "lobject.h"
#include "lstate.h"
+#include "lstring.h"
#include "lundump.h"
typedef struct {
@@ -98,6 +99,9 @@
case LUA_TSTRING:
DumpString(rawtsvalue(o),D);
break;
+ case LUA_TROPE:
+ DumpString(luaS_build(D->L, rawtrvalue(o)), D);
+ break;
default:
lua_assert(0); /* cannot happen */
break;
diff -ruN lua-5.1.5-clean/src/lgc.c lua-5.1.5-ropes/src/lgc.c
--- lua-5.1.5-clean/src/lgc.c 2011-03-18 14:05:38.000000000 -0400
+++ lua-5.1.5-ropes/src/lgc.c 2021-06-19 18:47:38.000000000 -0400
@@ -107,6 +107,11 @@
g->gray = o;
break;
}
+ case LUA_TROPE: {
+ gco2tr(o)->gclist = g->gray;
+ g->gray = o;
+ break;
+ }
default: lua_assert(0);
}
}
@@ -188,8 +193,8 @@
removeentry(n); /* remove empty entries */
else {
lua_assert(!ttisnil(gkey(n)));
- if (!weakkey) markvalue(g, gkey(n));
- if (!weakvalue) markvalue(g, gval(n));
+ if (!weakkey || ttisrope(gkey(n))) markvalue(g, gkey(n));
+ if (!weakvalue || ttisrope(gval(n))) markvalue(g, gval(n));
}
}
return weakkey || weakvalue;
@@ -270,6 +275,19 @@
}
+static void traverserope (global_State *g, TRope *r) {
+ if (r->tsr.left) {
+ if (r->tsr.left->tsr.tt == LUA_TSTRING) stringmark(cast(TString *, r->tsr.left));
+ else markobject(g, r->tsr.left);
+ }
+ if (r->tsr.right) {
+ if (r->tsr.right->tsr.tt == LUA_TSTRING) stringmark(cast(TString *, r->tsr.right));
+ else markobject(g, r->tsr.right);
+ }
+ if (r->tsr.res) stringmark(r->tsr.res);
+}
+
+
/*
** traverse one gray object, turning it to black.
** Returns `quantity' traversed.
@@ -315,6 +328,12 @@
sizeof(LocVar) * p->sizelocvars +
sizeof(TString *) * p->sizeupvalues;
}
+ case LUA_TROPE: {
+ TRope *r = rawgco2tr(o);
+ g->gray = r->tsr.gclist;
+ traverserope(g, r);
+ return sizeof(TRope);
+ }
default: lua_assert(0); return 0;
}
}
@@ -334,11 +353,14 @@
** other objects: if really collected, cannot keep them; for userdata
** being finalized, keep them in keys, but not in values
*/
-static int iscleared (const TValue *o, int iskey) {
+static int iscleared (global_State *g, const TValue *o, int iskey) {
if (!iscollectable(o)) return 0;
if (ttisstring(o)) {
stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */
return 0;
+ } else if (ttisrope(o)) {
+ markobject(g, o); /* ropes are strings -> which are values, so are never weak either */
+ return 0;
}
return iswhite(gcvalue(o)) ||
(ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
@@ -348,7 +370,7 @@
/*
** clear collected entries from weaktables
*/
-static void cleartable (GCObject *l) {
+static void cleartable (global_State *g, GCObject *l) {
while (l) {
Table *h = gco2h(l);
int i = h->sizearray;
@@ -357,7 +379,7 @@
if (testbit(h->marked, VALUEWEAKBIT)) {
while (i--) {
TValue *o = &h->array[i];
- if (iscleared(o, 0)) /* value was collected? */
+ if (iscleared(g, o, 0)) /* value was collected? */
setnilvalue(o); /* remove value */
}
}
@@ -365,7 +387,7 @@
while (i--) {
Node *n = gnode(h, i);
if (!ttisnil(gval(n)) && /* non-empty entry? */
- (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) {
+ (iscleared(g, key2tval(n), 1) || iscleared(g, gval(n), 0))) {
setnilvalue(gval(n)); /* remove value ... */
removeentry(n); /* remove entry from table */
}
@@ -380,6 +402,7 @@
case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
+ case LUA_TROPE: luaS_freerope(L, rawgco2tr(o)); break;
case LUA_TTABLE: luaH_free(L, gco2h(o)); break;
case LUA_TTHREAD: {
lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread);
@@ -543,7 +566,7 @@
udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */
marktmu(g); /* mark `preserved' userdata */
udsize += propagateall(g); /* remark, to propagate `preserveness' */
- cleartable(g->weak); /* remove collected objects from weak tables */
+ cleartable(g, g->weak); /* remove collected objects from weak tables */
/* flip current white */
g->currentwhite = cast_byte(otherwhite(g));
g->sweepstrgc = 0;
diff -ruN lua-5.1.5-clean/src/lobject.c lua-5.1.5-ropes/src/lobject.c
--- lua-5.1.5-clean/src/lobject.c 2007-12-27 08:02:25.000000000 -0500
+++ lua-5.1.5-ropes/src/lobject.c 2021-06-19 11:00:46.000000000 -0400
@@ -165,6 +165,7 @@
pushstr(L, fmt);
luaV_concat(L, n+1, cast_int(L->top - L->base) - 1);
L->top -= n;
+ if (ttisrope(L->top - 1)) setsvalue(L, L->top - 1, luaS_build(L, rawtrvalue(L->top - 1)));
return svalue(L->top - 1);
}
diff -ruN lua-5.1.5-clean/src/lobject.h lua-5.1.5-ropes/src/lobject.h
--- lua-5.1.5-clean/src/lobject.h 2008-08-06 09:29:48.000000000 -0400
+++ lua-5.1.5-ropes/src/lobject.h 2021-06-19 07:59:07.000000000 -0400
@@ -28,6 +28,7 @@
#define LUA_TPROTO (LAST_TAG+1)
#define LUA_TUPVAL (LAST_TAG+2)
#define LUA_TDEADKEY (LAST_TAG+3)
+#define LUA_TROPE (LAST_TAG+4)
/*
@@ -85,6 +86,7 @@
#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA)
#define ttisthread(o) (ttype(o) == LUA_TTHREAD)
#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA)
+#define ttisrope(o) (ttype(o) == LUA_TROPE)
/* Macros to access values */
#define ttype(o) ((o)->tt)
@@ -99,6 +101,8 @@
#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h)
#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b)
#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th)
+#define rawtrvalue(o) check_exp(ttisrope(o), &(o)->value.gc->r)
+#define trvalue(o) (&rawtrvalue(o)->tsr)
#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
@@ -155,6 +159,11 @@
i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
checkliveness(G(L),i_o); }
+#define setrvalue(L,obj,x) \
+ { TValue *i_o=(obj); \
+ i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TROPE; \
+ checkliveness(G(L),i_o); }
+
@@ -224,6 +233,17 @@
+typedef union TRope {
+ L_Umaxalign dummy; /* ensures maximum alignment for ropes */
+ struct {
+ CommonHeader;
+ GCObject *gclist;
+ union TRope * left;
+ union TRope * right;
+ size_t len;
+ TString *res;
+ } tsr;
+} TRope;
/*
** Function Prototypes
diff -ruN lua-5.1.5-clean/src/lstate.c lua-5.1.5-ropes/src/lstate.c
--- lua-5.1.5-clean/src/lstate.c 2008-01-03 10:20:39.000000000 -0500
+++ lua-5.1.5-ropes/src/lstate.c 2021-06-19 07:59:07.000000000 -0400
@@ -77,6 +77,7 @@ static void f_luaopen (lua_State *L, void *ud) {
luaT_init(L);
luaX_init(L);
luaS_fix(luaS_newliteral(L, MEMERRMSG));
+ g->ropestack = luaM_newvector(L, g->ropestacksize, TRope *);
g->GCthreshold = 4*g->totalbytes;
}
@@ -111,6 +112,7 @@ static void close_state (lua_State *L) {
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *);
luaZ_freebuffer(L, &g->buff);
freestack(L, L);
+ luaM_freearray(L, g->ropestack, g->ropestacksize, TRope *);
lua_assert(g->totalbytes == sizeof(LG));
(*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0);
}
@@ -178,6 +180,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->gcpause = LUAI_GCPAUSE;
g->gcstepmul = LUAI_GCMUL;
g->gcdept = 0;
+ g->ropestacksize = 8;
for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL;
if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {
/* memory allocation error: free partial state */
diff -ruN lua-5.1.5-clean/src/lstate.h lua-5.1.5-ropes/src/lstate.h
--- lua-5.1.5-clean/src/lstate.h 2008-01-03 10:20:39.000000000 -0500
+++ lua-5.1.5-ropes/src/lstate.h 2021-06-19 07:59:07.000000000 -0400
@@ -91,6 +91,8 @@ typedef struct global_State {
UpVal uvhead; /* head of double-linked list of all open upvalues */
struct Table *mt[NUM_TAGS]; /* metatables for basic types */
TString *tmname[TM_N]; /* array with tag-method names */
+ TRope **ropestack; /* temporary stack used to store ropes when constructing strings */
+ int ropestacksize; /* size of above stack */
} global_State;
@@ -142,6 +142,7 @@
struct Proto p;
struct UpVal uv;
struct lua_State th; /* thread */
+ union TRope r;
};
@@ -157,6 +158,8 @@
#define ngcotouv(o) \
check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv))
#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th))
+#define rawgco2tr(o) check_exp((o)->gch.tt == LUA_TROPE, &((o)->r))
+#define gco2tr(o) (&rawgco2tr(o)->tsr)
/* macro to convert any Lua object into a GCObject */
#define obj2gco(v) (cast(GCObject *, (v)))
diff -ruN lua-5.1.5-clean/src/lstring.c lua-5.1.5-ropes/src/lstring.c
--- lua-5.1.5-clean/src/lstring.c 2007-12-27 08:02:25.000000000 -0500
+++ lua-5.1.5-ropes/src/lstring.c 2021-06-19 18:47:38.000000000 -0400
@@ -18,6 +18,8 @@
#include "lstring.h"
+#define ROPE_ALLOC_MIN_SIZE 32768
+
void luaS_resize (lua_State *L, int newsize) {
GCObject **newhash;
@@ -109,3 +109,72 @@
return u;
}
+TRope *luaS_concat (lua_State *L, TRope *l, TRope *r) {
+ TRope *rope;
+ rope = cast(TRope *, luaM_malloc(L, sizeof(TRope)));
+ luaC_link(L, obj2gco(rope), LUA_TROPE);
+ rope->tsr.left = l;
+ rope->tsr.right = r;
+ rope->tsr.len = (l->tsr.tt == LUA_TSTRING ? cast(TString *, l)->tsv.len : l->tsr.len) + (r->tsr.tt == LUA_TSTRING ? cast(TString *, r)->tsv.len : r->tsr.len);
+ rope->tsr.res = NULL;
+ return rope;
+}
+
+TString *luaS_build (lua_State *L, TRope *rope) {
+ char *buffer, *cur;
+ TString *s;
+ TRope **stack;
+ TRope *orig = rope;
+ if (rope->tsr.tt == LUA_TSTRING) return cast(TString *, rope);
+ if (rope->tsr.res || rope->tsr.left == NULL || rope->tsr.right == NULL) return rope->tsr.res;
+ if (rope->tsr.len >= ROPE_ALLOC_MIN_SIZE) buffer = cur = luaM_newvector(L, rope->tsr.len, char);
+ else buffer = cur = luaZ_openspace(L, &G(L)->buff, rope->tsr.len);
+ stack = G(L)->ropestack;
+ do {
+ int b = 0;
+ while (rope->tsr.left->tsr.tt == LUA_TROPE && rope->tsr.left->tsr.res == NULL) {
+ if (stack - G(L)->ropestack == G(L)->ropestacksize - 1) {
+ TRope **oldbase = G(L)->ropestack;
+ luaM_reallocvector(L, G(L)->ropestack, G(L)->ropestacksize, G(L)->ropestacksize + G(L)->ropestacksize, TRope *);
+ stack = G(L)->ropestack + (stack - oldbase);
+ G(L)->ropestacksize += G(L)->ropestacksize;
+ }
+ *stack++ = rope;
+ rope = rope->tsr.left;
+ }
+ if (rope->tsr.left->tsr.tt == LUA_TSTRING) {
+ memcpy(cur, getstr(cast(TString *, rope->tsr.left)), cast(TString *, rope->tsr.left)->tsv.len);
+ cur += cast(TString *, rope->tsr.left)->tsv.len;
+ } else {
+ memcpy(cur, getstr(rope->tsr.left->tsr.res), rope->tsr.left->tsr.res->tsv.len);
+ cur += rope->tsr.left->tsr.res->tsv.len;
+ }
+ while (rope->tsr.right->tsr.tt == LUA_TSTRING || rope->tsr.right->tsr.res) {
+ if (rope->tsr.right->tsr.tt == LUA_TSTRING) {
+ memcpy(cur, getstr(cast(TString *, rope->tsr.right)), cast(TString *, rope->tsr.right)->tsv.len);
+ cur += cast(TString *, rope->tsr.right)->tsv.len;
+ } else {
+ memcpy(cur, getstr(rope->tsr.right->tsr.res), rope->tsr.right->tsr.res->tsv.len);
+ cur += rope->tsr.right->tsr.res->tsv.len;
+ }
+ if (stack <= G(L)->ropestack) {b = 1; break;}
+ rope = *--stack;
+ }
+ if (b) break;
+ rope = rope->tsr.right;
+ } while (stack >= G(L)->ropestack);
+ s = luaS_newlstr(L, buffer, cur - buffer);
+ if (orig->tsr.len >= ROPE_ALLOC_MIN_SIZE) luaM_free(L, buffer);
+ orig->tsr.res = s;
+ orig->tsr.left = orig->tsr.right = NULL; /* release left & right nodes (we don't need them anymore) */
+ /* mark the string as black so it doesn't accidentally get freed */
+ /* (apparently this is a problem?) */
+ resetbits(s->tsv.marked, WHITEBITS);
+ setbits(s->tsv.marked, bitmask(BLACKBIT));
+ return s;
+}
+
+void luaS_freerope (lua_State *L, TRope *rope) {
+ luaM_free(L, rope);
+}
+
diff -ruN lua-5.1.5-clean/src/lstring.h lua-5.1.5-ropes/src/lstring.h
--- lua-5.1.5-clean/src/lstring.h 2007-12-27 08:02:25.000000000 -0500
+++ lua-5.1.5-ropes/src/lstring.h 2021-06-19 07:59:07.000000000 -0400
@@ -26,6 +26,9 @@
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
+LUAI_FUNC TRope *luaS_concat (lua_State *L, TRope *l, TRope *r);
+LUAI_FUNC TString *luaS_build (lua_State *L, TRope *rope);
+LUAI_FUNC void luaS_freerope (lua_State *L, TRope *rope);
#endif
diff -ruN lua-5.1.5-clean/src/lstrlib.c lua-5.1.5-ropes/src/lstrlib.c
--- lua-5.1.5-clean/src/lstrlib.c 2007-12-27 08:02:25.000000000 -0500
+++ lua-5.1.5-ropes/src/lstrlib.c 2021-06-19 07:59:07.000000000 -0400
@@ -18,6 +18,8 @@
#include "lauxlib.h"
#include "lualib.h"
+
+#include "lstring.h"
/* macro to `unsign' a character */
@@ -92,13 +94,17 @@ static int str_upper (lua_State *L) {
static int str_rep (lua_State *L) {
size_t l;
- luaL_Buffer b;
+ char * str;
const char *s = luaL_checklstring(L, 1, &l);
- int n = luaL_checkint(L, 2);
- luaL_buffinit(L, &b);
- while (n-- > 0)
- luaL_addlstring(&b, s, l);
- luaL_pushresult(&b);
+ int n = luaL_checkint(L, 2), i;
+ if (n <= 0) lua_pushliteral(L, "");
+ else if (n == 1) lua_pushvalue(L, 1);
+ else {
+ str = luaM_newvector(L, l * n, char);
+ for (i = 0; i < l*n; i+=l) memcpy(str + i, s, l);
+ lua_pushlstring(L, str, l * n);
+ luaM_free(L, str);
+ }
return 1;
}
diff -ruN lua-5.1.5-clean/src/ltable.c lua-5.1.5-ropes/src/ltable.c
--- lua-5.1.5-clean/src/ltable.c 2007-12-28 10:32:23.000000000 -0500
+++ lua-5.1.5-ropes/src/ltable.c 2021-06-19 07:59:07.000000000 -0400
@@ -32,6 +32,7 @@
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
+#include "lstring.h"
#include "ltable.h"
@@ -466,10 +467,11 @@
/*
** main search function
*/
-const TValue *luaH_get (Table *t, const TValue *key) {
+const TValue *luaH_get (lua_State *L, Table *t, const TValue *key) {
switch (ttype(key)) {
case LUA_TNIL: return luaO_nilobject;
case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
+ case LUA_TROPE: return luaH_getstr(t, luaS_build(L, rawtrvalue(key)));
case LUA_TNUMBER: {
int k;
lua_Number n = nvalue(key);
@@ -492,7 +494,7 @@
TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
- const TValue *p = luaH_get(t, key);
+ const TValue *p = luaH_get(L, t, key);
t->flags = 0;
if (p != luaO_nilobject)
return cast(TValue *, p);
diff -ruN lua-5.1.5-clean/src/ltable.h lua-5.1.5-ropes/src/ltable.h
--- lua-5.1.5-clean/src/ltable.h 2007-12-27 08:02:25.000000000 -0500
+++ lua-5.1.5-ropes/src/ltable.h 2021-06-19 07:59:07.000000000 -0400
@@ -22,7 +22,7 @@
LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key);
-LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
+LUAI_FUNC const TValue *luaH_get (lua_State *L, Table *t, const TValue *key);
LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key);
LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash);
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize);
diff -ruN lua-5.1.5-clean/src/ltm.c lua-5.1.5-ropes/src/ltm.c
--- lua-5.1.5-clean/src/ltm.c 2007-12-27 08:02:25.000000000 -0500
+++ lua-5.1.5-ropes/src/ltm.c 2021-06-19 07:59:07.000000000 -0400
@@ -23,7 +23,7 @@
const char *const luaT_typenames[] = {
"nil", "boolean", "userdata", "number",
"string", "table", "function", "userdata", "thread",
- "proto", "upval"
+ "proto", "upval", "dead key", "rope", "substring"
};
@@ -67,6 +67,9 @@
case LUA_TUSERDATA:
mt = uvalue(o)->metatable;
break;
+ case LUA_TROPE:
+ mt = G(L)->mt[LUA_TSTRING];
+ break;
default:
mt = G(L)->mt[ttype(o)];
}
diff -ruN lua-5.1.5-clean/src/lvm.c lua-5.1.5-ropes/src/lvm.c
--- lua-5.1.5-clean/src/lvm.c 2011-08-17 16:43:11.000000000 -0400
+++ lua-5.1.5-ropes/src/lvm.c 2021-06-19 10:52:48.000000000 -0400
@@ -32,9 +32,13 @@
#define MAXTAGLOOP 100
-const TValue *luaV_tonumber (const TValue *obj, TValue *n) {
+#define resolverope(L, o) {if (ttisrope(o)) setsvalue(L, o, luaS_build(L, rawtrvalue(o)));}
+
+
+const TValue *luaV_tonumber (lua_State *L, const TValue *obj, TValue *n) {
lua_Number num;
if (ttisnumber(obj)) return obj;
+ resolverope(L, obj);
if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {
setnvalue(n, num);
return n;
@@ -45,7 +49,11 @@
int luaV_tostring (lua_State *L, StkId obj) {
- if (!ttisnumber(obj))
+ if (ttisrope(obj)) {
+ resolverope(L, obj);
+ return 1;
+ }
+ else if (!ttisnumber(obj))
return 0;
else {
char s[LUAI_MAXNUMBER2STR];
@@ -107,11 +115,12 @@
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
int loop;
+ resolverope(L, key);
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (ttistable(t)) { /* `t' is a table? */
Table *h = hvalue(t);
- const TValue *res = luaH_get(h, key); /* do a primitive get */
+ const TValue *res = luaH_get(L, h, key); /* do a primitive get */
if (!ttisnil(res) || /* result is no nil? */
(tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
setobj2s(L, val, res);
@@ -134,6 +143,7 @@
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
int loop;
TValue temp;
+ resolverope(L, key);
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (ttistable(t)) { /* `t' is a table? */
@@ -224,6 +234,8 @@
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
int res;
+ resolverope(L, l);
+ resolverope(L, r);
if (ttype(l) != ttype(r))
return luaG_ordererror(L, l, r);
else if (ttisnumber(l))
@@ -238,6 +250,8 @@
static int lessequal (lua_State *L, const TValue *l, const TValue *r) {
int res;
+ resolverope(L, l);
+ resolverope(L, r);
if (ttype(l) != ttype(r))
return luaG_ordererror(L, l, r);
else if (ttisnumber(l))
@@ -254,6 +268,8 @@
int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) {
const TValue *tm;
+ resolverope(L, t1);
+ resolverope(L, t2);
lua_assert(ttype(t1) == ttype(t2));
switch (ttype(t1)) {
case LUA_TNIL: return 1;
@@ -279,34 +295,35 @@
}
+static TRope *makerope(lua_State *L, StkId start, int len) {
+ switch (len) {
+ case 1: return cast(TRope *, gcvalue(start)); /* this should never happen */
+ case 2: return luaS_concat(L, cast(TRope *, gcvalue(start)), cast(TRope *, gcvalue(start + 1)));
+ case 3: return luaS_concat(L, cast(TRope *, gcvalue(start)), luaS_concat(L, cast(TRope *, gcvalue(start + 1)), cast(TRope *, gcvalue(start + 2))));
+ default: return luaS_concat(L, makerope(L, start, len / 2), makerope(L, start + (len / 2), len - (len / 2)));
+ }
+}
+
+
void luaV_concat (lua_State *L, int total, int last) {
do {
StkId top = L->base + last + 1;
int n = 2; /* number of elements handled in this pass (at least 2) */
- if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
+ if (!(ttisstring(top-2) || ttisnumber(top-2) || ttisrope(top-2)) || !tostring(L, top-1)) {
if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
luaG_concaterror(L, top-2, top-1);
} else if (tsvalue(top-1)->len == 0) /* second op is empty? */
(void)tostring(L, top - 2); /* result is first op (as string) */
else {
- /* at least two string values; get as many as possible */
+ /* concatenate by creating a rope */
size_t tl = tsvalue(top-1)->len;
- char *buffer;
- int i;
/* collect total length */
- for (n = 1; n < total && tostring(L, top-n-1); n++) {
- size_t l = tsvalue(top-n-1)->len;
+ for (n = 1; n < total && (ttisrope(top-n-1) || tostring(L, top-n-1)); n++) {
+ size_t l = ttisrope(top-n-1) ? trvalue(top-n-1)->len : tsvalue(top-n-1)->len;
if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
tl += l;
}
- buffer = luaZ_openspace(L, &G(L)->buff, tl);
- tl = 0;
- for (i=n; i>0; i--) { /* concat all strings */
- size_t l = tsvalue(top-i)->len;
- memcpy(buffer+tl, svalue(top-i), l);
- tl += l;
- }
- setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
+ setrvalue(L, top-n, makerope(L, top-n, n));
}
total -= n-1; /* got `n' strings to create 1 new */
last -= n-1;
@@ -318,8 +335,8 @@
const TValue *rc, TMS op) {
TValue tempb, tempc;
const TValue *b, *c;
- if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
- (c = luaV_tonumber(rc, &tempc)) != NULL) {
+ if ((b = luaV_tonumber(L, rb, &tempb)) != NULL &&
+ (c = luaV_tonumber(L, rc, &tempc)) != NULL) {
lua_Number nb = nvalue(b), nc = nvalue(c);
switch (op) {
case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
@@ -522,6 +539,10 @@
setnvalue(ra, cast_num(tsvalue(rb)->len));
break;
}
+ case LUA_TROPE: {
+ setnvalue(ra, cast_num(trvalue(rb)->len));
+ break;
+ }
default: { /* try metamethod */
Protect(
if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
@@ -545,6 +566,8 @@
case OP_EQ: {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
+ resolverope(L, rb);
+ resolverope(L, rc);
Protect(
if (equalobj(L, rb, rc) == GETARG_A(i))
dojump(L, pc, GETARG_sBx(*pc));
@@ -668,11 +691,11 @@
const TValue *plimit = ra+1;
const TValue *pstep = ra+2;
L->savedpc = pc; /* next steps may throw errors */
- if (!tonumber(init, ra))
+ if (!tonumber(L, init, ra))
luaG_runerror(L, LUA_QL("for") " initial value must be a number");
- else if (!tonumber(plimit, ra+1))
+ else if (!tonumber(L, plimit, ra+1))
luaG_runerror(L, LUA_QL("for") " limit must be a number");
- else if (!tonumber(pstep, ra+2))
+ else if (!tonumber(L, pstep, ra+2))
luaG_runerror(L, LUA_QL("for") " step must be a number");
setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
dojump(L, pc, GETARG_sBx(i));
diff -ruN lua-5.1.5-clean/src/lvm.h lua-5.1.5-ropes/src/lvm.h
--- lua-5.1.5-clean/src/lvm.h 2007-12-27 08:02:25.000000000 -0500
+++ lua-5.1.5-ropes/src/lvm.h 2021-06-19 07:59:07.000000000 -0400
@@ -15,8 +15,8 @@
#define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o)))
-#define tonumber(o,n) (ttype(o) == LUA_TNUMBER || \
- (((o) = luaV_tonumber(o,n)) != NULL))
+#define tonumber(L, o,n) (ttype(o) == LUA_TNUMBER || \
+ (((o) = luaV_tonumber(L,o,n)) != NULL))
#define equalobj(L,o1,o2) \
(ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2))
@@ -24,7 +24,7 @@
LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2);
-LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n);
+LUAI_FUNC const TValue *luaV_tonumber (lua_State *L, const TValue *obj, TValue *n);
LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj);
LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
StkId val);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment