From 024f9064f1b43758eb36aba52547edc0312bf4ba Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Thu, 9 Nov 2023 17:05:42 -0300 Subject: External strings Strings can use external buffers to store their contents. --- lstring.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 3 deletions(-) (limited to 'lstring.c') diff --git a/lstring.c b/lstring.c index c4b3c7ba..8701b705 100644 --- a/lstring.c +++ b/lstring.c @@ -136,6 +136,20 @@ void luaS_init (lua_State *L) { } +size_t luaS_sizelngstr (size_t len, int kind) { + switch (kind) { + case LSTRREG: /* regular long string */ + /* don't need 'falloc'/'ud', but need space for content */ + return offsetof(TString, falloc) + (len + 1) * sizeof(char); + case LSTRFIX: /* fixed external long string */ + /* don't need 'falloc'/'ud' */ + return offsetof(TString, falloc); + default: /* external long string with deallocation */ + lua_assert(kind == LSTRMEM); + return sizeof(TString); + } +} + /* ** creates a new string object @@ -153,11 +167,11 @@ static TString *createstrobj (lua_State *L, size_t totalsize, int tag, TString *luaS_createlngstrobj (lua_State *L, size_t l) { - size_t totalsize = sizestrlng(l); + size_t totalsize = luaS_sizelngstr(l, LSTRREG); TString *ts = createstrobj(L, totalsize, LUA_VLNGSTR, G(L)->seed); ts->u.lnglen = l; - ts->shrlen = -1; /* signals that it is a long string */ - ts->contents = cast_charp(ts) + sizeof(TString); + ts->shrlen = LSTRREG; /* signals that it is a regular long string */ + ts->contents = cast_charp(ts) + offsetof(TString, falloc); ts->contents[l] = '\0'; /* ending 0 */ return ts; } @@ -275,3 +289,61 @@ Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) { return u; } + +struct NewExt { + int kind; + const char *s; + size_t len; + TString *ts; /* output */ +}; + + +static void f_newext (lua_State *L, void *ud) { + struct NewExt *ne = cast(struct NewExt *, ud); + size_t size = luaS_sizelngstr(0, ne->kind); + ne->ts = createstrobj(L, size, LUA_VLNGSTR, G(L)->seed); +} + + +static void f_pintern (lua_State *L, void *ud) { + struct NewExt *ne = cast(struct NewExt *, ud); + ne->ts = internshrstr(L, ne->s, ne->len); +} + + +TString *luaS_newextlstr (lua_State *L, + const char *s, size_t len, lua_Alloc falloc, void *ud) { + struct NewExt ne; + if (len <= LUAI_MAXSHORTLEN) { /* short string? */ + ne.s = s; ne.len = len; + if (!falloc) + f_pintern(L, &ne); /* just internalize string */ + else { + int status = luaD_rawrunprotected(L, f_pintern, &ne); + (*falloc)(ud, cast_voidp(s), len + 1, 0); /* free external string */ + if (status != LUA_OK) /* memory error? */ + luaM_error(L); /* re-raise memory error */ + } + return ne.ts; + } + /* "normal" case: long strings */ + if (!falloc) { + ne.kind = LSTRFIX; + f_newext(L, &ne); /* just create header */ + } + else { + ne.kind = LSTRMEM; + if (luaD_rawrunprotected(L, f_newext, &ne) != LUA_OK) { /* mem. error? */ + (*falloc)(ud, cast_voidp(s), len + 1, 0); /* free external string */ + luaM_error(L); /* re-raise memory error */ + } + ne.ts->falloc = falloc; + ne.ts->ud = ud; + } + ne.ts->shrlen = ne.kind; + ne.ts->u.lnglen = len; + ne.ts->contents = cast_charp(s); + return ne.ts; +} + + -- cgit v1.2.3-55-g6feb