diff -urN lua-5.1.2/src/lapi.c luaprestring-5.1.2/src/lapi.c --- lua-5.1.2/src/lapi.c 2006-06-07 07:37:17.000000000 -0500 +++ luaprestring-5.1.2/src/lapi.c 2007-12-09 13:11:36.000000000 -0500 @@ -338,8 +338,16 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { StkId o = index2adr(L, idx); - if (!ttisstring(o)) { - lua_lock(L); /* `luaV_tostring' may create a new string */ + if (ttisstring(o)) { + if (tsvalue(o)->isprestring) { + lua_lock(L); + if (tsvalue(o)->isprestring) + setsvalue(L, o, luaS_finishprestring(L, rawtsvalue(o))); + lua_unlock(L); + } + } + else { + lua_lock(L); if (!luaV_tostring(L, o)) { /* conversion failed? */ if (len != NULL) *len = 0; lua_unlock(L); @@ -408,6 +416,48 @@ } +LUA_API char *lua_toprestring (lua_State *L, int idx, size_t *len) { + StkId o; + api_check(L, len); /* len must point to a valid length */ + o = index2adr(L, idx); + if (ttisstring(o)) { + *len = tsvalue(o)->len; + if (!tsvalue(o)->isprestring) { + lua_lock(L); + if (!tsvalue(o)->isprestring) + setsvalue(L, o, luaS_newprestring(L, *len)); + lua_unlock(L); + } + } + else if (ttisnil(o)) { + lua_lock(L); + setsvalue(L, o, luaS_newprestring(L, *len)); + lua_unlock(L); + } + else { + return NULL; + } + return cast(char *, rawtsvalue(o) + 1); +} + + +LUA_API char *lua_rawtoprestring (lua_State *L, int idx, size_t *len) { + StkId o = index2adr(L, idx); + if (!ttisstring(o) || !tsvalue(o)->isprestring) + return NULL; + if (len != NULL) *len = tsvalue(o)->len; + return cast(char *, rawtsvalue(o) + 1); +} + + +LUA_API const char *lua_rawtolstring (lua_State *L, int idx, size_t *len) { + StkId o = index2adr(L, idx); + if (!ttisstring(o)) + return NULL; + if (len != NULL) *len = tsvalue(o)->len; + return svalue(o); +} + /* ** push functions (C -> stack) @@ -555,7 +605,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); } @@ -633,6 +683,17 @@ } +LUA_API char *lua_newprestring (lua_State *L, size_t len) { + TString *ts; + lua_lock(L); + luaC_checkGC(L); + ts = luaS_newprestring(L, len); + setsvalue(L, L->top, ts); + api_incr_top(L); + lua_unlock(L); + return cast(char *, ts + 1); +} + /* ** set functions (stack -> Lua) */ diff -urN lua-5.1.2/src/lauxlib.c luaprestring-5.1.2/src/lauxlib.c --- lua-5.1.2/src/lauxlib.c 2006-03-21 14:31:09.000000000 -0500 +++ luaprestring-5.1.2/src/lauxlib.c 2007-12-09 13:34:26.000000000 -0500 @@ -162,6 +162,13 @@ } +LUALIB_API const char *luaL_checkrawlstring (lua_State *L, int narg, size_t *len) { + const char *s = lua_rawtolstring(L, narg, len); + if (!s) tag_error(L, narg, LUA_TSTRING); + return s; +} + + LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, const char *def, size_t *len) { if (lua_isnoneornil(L, narg)) { @@ -173,6 +180,17 @@ } +LUALIB_API const char *luaL_optrawlstring (lua_State *L, int narg, + const char *def, size_t *len) { + if (lua_isnoneornil(L, narg)) { + if (len) + *len = (def ? strlen(def) : 0); + return def; + } + else return luaL_checkrawlstring(L, narg, len); +} + + LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { lua_Number d = lua_tonumber(L, narg); if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ diff -urN lua-5.1.2/src/lauxlib.h luaprestring-5.1.2/src/lauxlib.h --- lua-5.1.2/src/lauxlib.h 2006-04-12 15:31:15.000000000 -0500 +++ luaprestring-5.1.2/src/lauxlib.h 2007-12-09 13:34:58.000000000 -0500 @@ -49,8 +49,12 @@ LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, size_t *l); +LUALIB_API const char *(luaL_checkrawlstring) (lua_State *L, int numArg, + size_t *l); LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, const char *def, size_t *l); +LUALIB_API const char *(luaL_optrawlstring) (lua_State *L, int numArg, + const char *def, size_t *l); LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); diff -urN lua-5.1.2/src/lbuftest.c luaprestring-5.1.2/src/lbuftest.c --- lua-5.1.2/src/lbuftest.c 1969-12-31 19:00:00.000000000 -0500 +++ luaprestring-5.1.2/src/lbuftest.c 2007-12-11 15:41:35.000000000 -0500 @@ -0,0 +1,169 @@ +#include +#include + +#include +#include +#include + + +#define RINGSIZE 16363 + +typedef struct RingBuf { + unsigned int p; + unsigned int ncycles; + size_t szleft; + char buf[RINGSIZE]; +} RingBuf; + + +static RingBuf *ring_refill(RingBuf *rb) { + int i; + for (i = 0; i < RINGSIZE; ++i) + rb->buf[i] = 32 + (char) (95.0 * (rand() / (RAND_MAX + 1.0))); + rb->ncycles = rb->p = RINGSIZE; + return rb; +} + + +static RingBuf *ring_open (lua_State *L, size_t sz) { + RingBuf *rb = lua_newuserdata(L, sizeof(*rb)); + rb->szleft = sz; + return ring_refill(rb); +} + + +/* eltsize currently needs to be 1. sorry */ +static size_t ring_read(char *b, size_t eltsize, size_t nelts, void *urb) { + RingBuf *rb = urb; + if (nelts > rb->szleft) nelts = rb->szleft; + if (nelts) { + int p = rb->p; + int avail = RINGSIZE - p; + int tocopy = nelts; + if (--rb->ncycles == 0) + ring_refill(rb); + rb->szleft -= nelts; + + while (avail < tocopy) { + memcpy(b, &rb->buf[p], avail); + b += avail; + tocopy -= avail; + p = 0; + avail = RINGSIZE; + } + memcpy(b, &rb->buf[p], tocopy); + rb->p = p + tocopy; + } + return nelts; +} + +/* iterators all take three upvalues: + * 1: ud of a RingBuf * + * 2: size of the prestring + * 3: (initially nil) + */ + +/* Try to use the same prestring each time */ +static int aux_iter_recycle (lua_State *L) { + void *urb = lua_touserdata(L, lua_upvalueindex(1)); + size_t sz = lua_tointeger(L, lua_upvalueindex(2)); + char *b = lua_toprestring(L, lua_upvalueindex(3), &sz); + size_t nr = ring_read(b, 1, sz, urb); + if (nr == sz) + lua_pushvalue(L, lua_upvalueindex(3)); + else if (nr > 0) + lua_pushlstring(L, b, nr); + else + lua_pushnil(L); + return 1; +} + +/* Create a new prestring each time, and return it */ +static int aux_iter_nohashnocopy (lua_State *L) { + void *urb = lua_touserdata(L, lua_upvalueindex(1)); + size_t sz = lua_tointeger(L, lua_upvalueindex(2)); + char *b = lua_newprestring(L, sz); + size_t nr = ring_read(b, 1, sz, urb); + if (nr != sz) { + if (nr > 0) + lua_pushlstring(L, b, nr); + else + lua_pushnil(L); + } + return 1; +} + +/* Create a new prestring each time, and return it as a string */ +static int aux_iter_hashnocopy (lua_State *L) { + void *urb = lua_touserdata(L, lua_upvalueindex(1)); + size_t sz = lua_tointeger(L, lua_upvalueindex(2)); + char *b = lua_newprestring(L, sz); + size_t nr = ring_read(b, 1, sz, urb); + if (nr == sz) + lua_tostring(L, -1); + else if (nr > 0) + lua_pushlstring(L, b, nr); + else + lua_pushnil(L); + return 1; +} + +/* Close to the normal lua implementation, but using a prestring + * as a temporary buffer + */ +static int aux_iter_hashcopy(lua_State *L) { + void *urb = lua_touserdata(L, lua_upvalueindex(1)); + size_t sz = lua_tointeger(L, lua_upvalueindex(2)); + char *b = lua_toprestring(L, lua_upvalueindex(3), &sz); + size_t nr = ring_read(b, 1, sz, urb); + if (nr > 0) + lua_pushlstring(L, b, nr); + else + lua_pushnil(L); + return 1; +} + +/* Takes the iters[] table as upvalue 1 */ +/* Arguments: + * 1 iter type (from iters) + * 2 file size + * 3 buffer size + */ +static int l_buffers (lua_State *L) { + size_t filesize, bufsize; + const luaL_Reg *iterreg; + lua_pushvalue(L, 1); + lua_gettable(L, lua_upvalueindex(1)); + iterreg = lua_touserdata(L, -1); + luaL_argcheck(L, iterreg, 1, "Incorrect iterator type"); + filesize = luaL_checklong(L, 2); + luaL_argcheck(L, filesize >= 0, 2, "Filesize must be a non-negative integer"); + bufsize = luaL_checklong(L, 3); + luaL_argcheck(L, bufsize >= 1, 3, "Buffersize must be a positive integer"); + ring_open(L, filesize); + lua_pushvalue(L, 3); + lua_pushnil(L); + lua_pushcclosure(L, iterreg->func, 3); + return 1; +} + +static const luaL_Reg iters[] = { + {"recycle", aux_iter_recycle}, + {"prestring", aux_iter_nohashnocopy}, + {"inplace", aux_iter_hashnocopy}, + {"string", aux_iter_hashcopy}, + {NULL, NULL} +}; + +int luaopen_buftest (lua_State *L) { + const luaL_Reg *r = iters; + lua_createtable(L, 0, 4); + for (; r->name; ++r) { + lua_pushlightuserdata(L, (void *)r); + lua_setfield(L, -2, r->name); + } + lua_pushcclosure(L, l_buffers, 1); + lua_setglobal(L, "test"); + return 0; +} + diff -urN lua-5.1.2/src/lgc.c luaprestring-5.1.2/src/lgc.c --- lua-5.1.2/src/lgc.c 2006-05-24 09:34:06.000000000 -0500 +++ luaprestring-5.1.2/src/lgc.c 2007-12-09 13:03:20.000000000 -0500 @@ -387,7 +387,7 @@ break; } case LUA_TSTRING: { - G(L)->strt.nuse--; + if (!gco2ts(o)->isprestring) G(L)->strt.nuse--; luaM_freemem(L, o, sizestring(gco2ts(o))); break; } @@ -428,6 +428,28 @@ } +static void sweepprestring (lua_State *L) { + global_State *g = G(L); + GCObject *p = obj2gco(&G(L)->rootprestring); + GCObject *curr = p->gch.next; + int deadmask = otherwhite(g); + while ((curr = p->gch.next) != obj2gco(&G(L)->rootprestring)) { + lua_assert(ttisstring(curr) && gco2ts(curr)->isprestring); + if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ + lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); + makewhite(g, curr); + gco2ts(curr)->hp.prev = p; + p = curr; + } + else { /* must erase `curr' */ + lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); + p->gch.next = curr->gch.next; + freeobj(L, curr); + } + } +} + + static void checkSizes (lua_State *L) { global_State *g = G(L); /* check size of string hash */ @@ -573,9 +595,17 @@ lu_mem old = g->totalbytes; sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ - g->gcstate = GCSsweep; /* end sweep-string phase */ + g->gcstate = GCSsweepprestring; /* end sweep-string phase */ + lua_assert(old >= g->totalbytes); + g->estimate -= old - g->totalbytes; + return GCSWEEPCOST; + } + case GCSsweepprestring: { + lu_mem old = g->totalbytes; + sweepprestring(L); lua_assert(old >= g->totalbytes); g->estimate -= old - g->totalbytes; + g->gcstate = GCSsweep; return GCSWEEPCOST; } case GCSsweep: { diff -urN lua-5.1.2/src/lgc.h luaprestring-5.1.2/src/lgc.h --- lua-5.1.2/src/lgc.h 2005-08-24 11:15:49.000000000 -0500 +++ luaprestring-5.1.2/src/lgc.h 2007-12-08 20:44:28.000000000 -0500 @@ -17,8 +17,9 @@ #define GCSpause 0 #define GCSpropagate 1 #define GCSsweepstring 2 -#define GCSsweep 3 -#define GCSfinalize 4 +#define GCSsweepprestring 3 +#define GCSsweep 4 +#define GCSfinalize 5 /* diff -urN lua-5.1.2/src/linit.c luaprestring-5.1.2/src/linit.c --- lua-5.1.2/src/linit.c 2005-12-29 10:32:11.000000000 -0500 +++ luaprestring-5.1.2/src/linit.c 2007-12-11 09:31:11.000000000 -0500 @@ -13,6 +13,7 @@ #include "lualib.h" #include "lauxlib.h" +int luaopen_buftest (lua_State *L); static const luaL_Reg lualibs[] = { {"", luaopen_base}, @@ -23,6 +24,7 @@ {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, + {"buftest", luaopen_buftest}, {NULL, NULL} }; diff -urN lua-5.1.2/src/liolib.c luaprestring-5.1.2/src/liolib.c --- lua-5.1.2/src/liolib.c 2006-05-08 15:14:16.000000000 -0500 +++ luaprestring-5.1.2/src/liolib.c 2007-12-10 02:29:20.000000000 -0500 @@ -247,6 +247,57 @@ } +static int io_readbuf (lua_State *L) { + FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); + if (f == NULL) + luaL_error(L, "file is already closed"); + else { + size_t toread, nread; + char *buf = lua_toprestring(L, lua_upvalueindex(2), &toread); + nread = fread(buf, 1, toread, f); + if (nread == toread) + lua_pushvalue(L, lua_upvalueindex(2)); + else if (nread > 0) + lua_pushlstring(L, buf, nread); + else if (ferror(f)) + luaL_error(L, "%s", strerror(errno)); + else + lua_pushnil(L); + } + return 1; +} + + +static int io_readbuf2 (lua_State *L) { + FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); + if (f == NULL) + luaL_error(L, "file is already closed"); + else { + size_t toread, nread; + char *buf = lua_rawtoprestring(L, lua_upvalueindex(2), &toread); + nread = fread(buf, 1, toread, f); + if (nread > 0) + lua_pushlstring(L, buf, nread); + else if (ferror(f)) + luaL_error(L, "%s", strerror(errno)); + else + lua_pushnil(L); + } + return 1; +} + + +static int f_buffers (lua_State *L) { + size_t bufsize; + int news = lua_toboolean(L, 3); + tofile(L); + bufsize = luaL_optinteger(L, 2, LUAL_BUFFERSIZE); + lua_settop(L, 1); + lua_newprestring(L, bufsize); + lua_pushcclosure(L, news ? io_readbuf2 : io_readbuf, 2); + return 1; +} + /* ** {====================================================== ** READ @@ -402,7 +453,7 @@ } else { size_t l; - const char *s = luaL_checklstring(L, arg, &l); + const char *s = luaL_checkrawlstring(L, arg, &l); status = status && (fwrite(s, sizeof(char), l, f) == l); } } @@ -478,6 +529,7 @@ {"close", io_close}, {"flush", f_flush}, {"lines", f_lines}, + {"buffers", f_buffers}, {"read", f_read}, {"seek", f_seek}, {"setvbuf", f_setvbuf}, diff -urN lua-5.1.2/src/lobject.h luaprestring-5.1.2/src/lobject.h --- lua-5.1.2/src/lobject.h 2006-01-18 06:37:34.000000000 -0500 +++ luaprestring-5.1.2/src/lobject.h 2007-12-09 13:03:56.000000000 -0500 @@ -201,7 +201,11 @@ struct { CommonHeader; lu_byte reserved; - unsigned int hash; + lu_byte isprestring; + union { + unsigned int hash; + GCObject *prev; + } hp; size_t len; } tsv; } TString; diff -urN lua-5.1.2/src/lstate.c luaprestring-5.1.2/src/lstate.c --- lua-5.1.2/src/lstate.c 2006-05-24 09:15:50.000000000 -0500 +++ luaprestring-5.1.2/src/lstate.c 2007-12-09 13:05:02.000000000 -0500 @@ -174,6 +174,13 @@ g->grayagain = NULL; g->weak = NULL; g->tmudata = NULL; + g->rootprestring.tsv.next = obj2gco(&g->rootprestring); + g->rootprestring.tsv.tt = LUA_TSTRING; + g->rootprestring.tsv.marked = 0; + g->rootprestring.tsv.reserved = 0; + g->rootprestring.tsv.isprestring = 1; + g->rootprestring.tsv.hp.prev = obj2gco(&g->rootprestring); + g->rootprestring.tsv.len = 0; g->totalbytes = sizeof(LG); g->gcpause = LUAI_GCPAUSE; g->gcstepmul = LUAI_GCMUL; diff -urN lua-5.1.2/src/lstate.h luaprestring-5.1.2/src/lstate.h --- lua-5.1.2/src/lstate.h 2006-02-06 13:27:59.000000000 -0500 +++ luaprestring-5.1.2/src/lstate.h 2007-12-08 19:00:20.000000000 -0500 @@ -78,6 +78,7 @@ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of weak tables (to be cleared) */ GCObject *tmudata; /* last element of list of userdata to be GC */ + TString rootprestring; /* header of doubly-linked list of collectable prestrings */ Mbuffer buff; /* temporary buffer for string concatentation */ lu_mem GCthreshold; lu_mem totalbytes; /* number of bytes currently allocated */ diff -urN lua-5.1.2/src/lstring.c luaprestring-5.1.2/src/lstring.c --- lua-5.1.2/src/lstring.c 2005-12-22 11:19:56.000000000 -0500 +++ luaprestring-5.1.2/src/lstring.c 2007-12-10 21:28:34.000000000 -0500 @@ -33,7 +33,7 @@ GCObject *p = tb->hash[i]; while (p) { /* for each node in the list */ GCObject *next = p->gch.next; /* save next */ - unsigned int h = gco2ts(p)->hash; + unsigned int h = gco2ts(p)->hp.hash; int h1 = lmod(h, newsize); /* new position */ lua_assert(cast_int(h%newsize) == lmod(h, newsize)); p->gch.next = newhash[h1]; /* chain it */ @@ -47,20 +47,23 @@ } -static TString *newlstr (lua_State *L, const char *str, size_t l, - unsigned int h) { +static TString *newlstrobj (lua_State *L, size_t l) { TString *ts; - stringtable *tb; if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) luaM_toobig(L); ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); ts->tsv.len = l; - ts->tsv.hash = h; ts->tsv.marked = luaC_white(G(L)); ts->tsv.tt = LUA_TSTRING; ts->tsv.reserved = 0; - memcpy(ts+1, str, l*sizeof(char)); - ((char *)(ts+1))[l] = '\0'; /* ending 0 */ + return ts; +} + + +static TString *addlstr (lua_State *L, TString *ts, unsigned int h) { + stringtable *tb; + ts->tsv.hp.hash = h; + ts->tsv.isprestring = 0; tb = &G(L)->strt; h = lmod(h, tb->size); ts->tsv.next = tb->hash[h]; /* chain new entry */ @@ -72,13 +75,18 @@ } -TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { - GCObject *o; +static unsigned int hashstr (const char *str, size_t l) { unsigned int h = cast(unsigned int, l); /* seed */ size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ size_t l1; for (l1=l; l1>=step; l1-=step) /* compute hash */ h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); + return h; +} + + +TString *findstr (lua_State *L, const char *str, size_t l, unsigned int h) { + GCObject *o; for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; o != NULL; o = o->gch.next) { @@ -89,7 +97,50 @@ return ts; } } - return newlstr(L, str, l, h); /* not found */ + return NULL; +} + + +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + unsigned h = hashstr(str, l); + TString *ts = findstr(L, str, l, h); + if (ts) + return ts; + else { + ts = newlstrobj(L, l); + memcpy(ts+1, str, l*sizeof(char)); + ((char *)(ts+1))[l] = '\0'; /* ending 0 */ + return addlstr(L, ts, h); + } +} + + +TString *luaS_newprestring (lua_State *L, size_t l) { + TString *ts = newlstrobj(L, l); + ts->tsv.isprestring = 1; + ts->tsv.next = G(L)->rootprestring.tsv.next; + ts->tsv.hp.prev = obj2gco(&G(L)->rootprestring); + gco2ts(G(L)->rootprestring.tsv.next)->hp.prev = obj2gco(ts); + G(L)->rootprestring.tsv.next = obj2gco(ts); + ((char *)(ts+1))[l] = '\0'; + return ts; +} + + +TString *luaS_finishprestring (lua_State *L, TString *ts) { + size_t l = ts->tsv.len; + unsigned h = hashstr(getstr(ts), l); + TString *ts1 = findstr(L, getstr(ts), l, h); + if (ts1) + return ts1; + else { + ((char *)(ts+1))[l] = '\0'; + /* Unhook ts from prestring doubly-linked list */ + gco2ts(ts->tsv.next)->hp.prev = ts->tsv.hp.prev; + ts->tsv.hp.prev->gch.next = ts->tsv.next; + /* Hook ts into string table */ + return addlstr(L, ts, h); + } } diff -urN lua-5.1.2/src/lstring.h luaprestring-5.1.2/src/lstring.h --- lua-5.1.2/src/lstring.h 2005-04-25 14:24:10.000000000 -0500 +++ luaprestring-5.1.2/src/lstring.h 2007-12-08 19:50:21.000000000 -0500 @@ -26,6 +26,11 @@ 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 TString *luaS_newprestring (lua_State *L, size_t l); +LUAI_FUNC TString *luaS_finishprestring (lua_State *L, TString *prestr); +#define luaS_tostring(L, ts) (((ts)->tsv.isprestring) \ + ? luaS_finishprestring(L, ts) \ + : (ts)) #endif diff -urN lua-5.1.2/src/ltable.c luaprestring-5.1.2/src/ltable.c --- lua-5.1.2/src/ltable.c 2006-01-18 06:49:02.000000000 -0500 +++ luaprestring-5.1.2/src/ltable.c 2007-12-09 13:29:33.000000000 -0500 @@ -32,6 +32,7 @@ #include "lmem.h" #include "lobject.h" #include "lstate.h" +#include "lstring.h" #include "ltable.h" @@ -49,7 +50,12 @@ #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) -#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) +#if 0 +#define hashstr(t,str) hashpow2(t, luaS_tostring(L, str)->tsv.hp.hash) +#else +#define hashstr(t,str) hashpow2(t, (str)->tsv.hp.hash) +#endif + #define hashboolean(t,p) hashpow2(t, p) @@ -396,7 +402,7 @@ ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ -static TValue *newkey (lua_State *L, Table *t, const TValue *key) { +static TValue *newkey (lua_State *L, Table *t, TValue *key) { Node *mp = mainposition(t, key); if (!ttisnil(gval(mp)) || mp == dummynode) { Node *othern; @@ -466,10 +472,14 @@ /* ** main search function */ -const TValue *luaH_get (Table *t, const TValue *key) { +const TValue *luaH_get (lua_State *L, Table *t, TValue *key) { switch (ttype(key)) { case LUA_TNIL: return luaO_nilobject; - case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); + case LUA_TSTRING: { + if (tsvalue(key)->isprestring) + setsvalue(L, key, luaS_finishprestring(L, rawtsvalue(key))); + return luaH_getstr(t, rawtsvalue(key)); + } case LUA_TNUMBER: { int k; lua_Number n = nvalue(key); @@ -491,8 +501,8 @@ } -TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { - const TValue *p = luaH_get(t, key); +TValue *luaH_set (lua_State *L, Table *t, TValue *key) { + const TValue *p = luaH_get(L, t, key); t->flags = 0; if (p != luaO_nilobject) return cast(TValue *, p); diff -urN lua-5.1.2/src/ltable.h luaprestring-5.1.2/src/ltable.h --- lua-5.1.2/src/ltable.h 2006-01-10 08:13:06.000000000 -0500 +++ luaprestring-5.1.2/src/ltable.h 2007-12-09 13:12:10.000000000 -0500 @@ -22,8 +22,8 @@ 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 TValue *luaH_set (lua_State *L, Table *t, const TValue *key); +LUAI_FUNC const TValue *luaH_get (lua_State *l, Table *t, TValue *key); +LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, 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); LUAI_FUNC void luaH_free (lua_State *L, Table *t); diff -urN lua-5.1.2/src/lua.c luaprestring-5.1.2/src/lua.c --- lua-5.1.2/src/lua.c 2006-06-02 10:34:00.000000000 -0500 +++ luaprestring-5.1.2/src/lua.c 2007-12-12 12:23:47.000000000 -0500 @@ -10,6 +10,10 @@ #include #include +#ifdef LUA_USE_LINUX +#include +#endif + #define lua_c #include "lua.h" @@ -371,11 +375,14 @@ return 0; } - int main (int argc, char **argv) { int status; struct Smain s; - lua_State *L = lua_open(); /* create state */ + lua_State *L; +#ifdef LUA_USE_LINUX + mtrace(); +#endif + L = lua_open(); /* create state */ if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; diff -urN lua-5.1.2/src/lua.h luaprestring-5.1.2/src/lua.h --- lua-5.1.2/src/lua.h 2007-03-23 12:12:31.000000000 -0500 +++ luaprestring-5.1.2/src/lua.h 2007-12-08 17:33:04.000000000 -0500 @@ -152,7 +152,12 @@ LUA_API void *(lua_touserdata) (lua_State *L, int idx); LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); LUA_API const void *(lua_topointer) (lua_State *L, int idx); - +LUA_API char *(lua_toprestring) (lua_State *L, int idx, + size_t *len); +LUA_API char *(lua_rawtoprestring) (lua_State *L, int idx, + size_t *len); +LUA_API const char *(lua_rawtolstring) (lua_State *L, int idx, + size_t *len); /* ** push functions (C -> stack) @@ -182,6 +187,7 @@ LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); LUA_API void (lua_getfenv) (lua_State *L, int idx); +LUA_API char *(lua_newprestring) (lua_State *L, size_t len); /* diff -urN lua-5.1.2/src/lvm.c luaprestring-5.1.2/src/lvm.c --- lua-5.1.2/src/lvm.c 2007-03-26 09:32:38.000000000 -0500 +++ luaprestring-5.1.2/src/lvm.c 2007-12-09 13:18:44.000000000 -0500 @@ -113,7 +113,7 @@ 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); @@ -250,7 +250,7 @@ } -int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { +int luaV_equalval (lua_State *L, TValue *t1, TValue *t2) { const TValue *tm; lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { @@ -269,6 +269,13 @@ tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } + case LUA_TSTRING: { + TString *ts1 = rawtsvalue(t1); + TString *ts2 = rawtsvalue(t2); + if (ts1->tsv.isprestring) setsvalue(L, t1, (ts1 = luaS_finishprestring(L, ts1))); + if (ts2->tsv.isprestring) setsvalue(L, t2, (ts2 = luaS_finishprestring(L, ts2))); + return ts1 == ts2; + } default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) return 0; /* no TM? */ diff -urN lua-5.1.2/src/lvm.h luaprestring-5.1.2/src/lvm.h --- lua-5.1.2/src/lvm.h 2005-08-22 13:54:49.000000000 -0500 +++ luaprestring-5.1.2/src/lvm.h 2007-12-09 13:17:30.000000000 -0500 @@ -23,7 +23,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 int luaV_equalval (lua_State *L, TValue *t1, TValue *t2); LUAI_FUNC const TValue *luaV_tonumber (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, diff -urN lua-5.1.2/src/Makefile luaprestring-5.1.2/src/Makefile --- lua-5.1.2/src/Makefile 2007-12-07 00:48:50.000000000 -0500 +++ luaprestring-5.1.2/src/Makefile 2007-12-11 09:31:57.000000000 -0500 @@ -8,7 +8,7 @@ PLAT= none CC= gcc -CFLAGS= -O2 -Wall $(MYCFLAGS) +CFLAGS= -g -DLUA_USE_APICHECK -O2 -Wall -I. $(MYCFLAGS) AR= ar rcu RANLIB= ranlib RM= rm -f @@ -27,7 +27,11 @@ lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \ lundump.o lvm.o lzio.o LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \ - lstrlib.o loadlib.o linit.o + lstrlib.o loadlib.o lbuftest.o linit.o + +SOLIB_C= lbuftest.c +SOLIB_T= buftest.so +SOLIB_O= buftest.o LUA_T= lua LUA_O= lua.o @@ -57,6 +61,12 @@ $(LUAC_T): $(LUAC_O) $(LUA_A) $(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS) +$(SOLIB_O): $(SOLIB_C) + $(CC) -c -o $@ -fPIC $(CFLAGS) $(MYLDFLAGS) $(SOLIB_C) + +$(SOLIB_T): $(SOLIB_O) + $(CC) -shared -o $@ $(SOLIB_O) + clean: $(RM) $(ALL_T) $(ALL_O) diff -urN lua-5.1.2/test/buftest.lua luaprestring-5.1.2/test/buftest.lua --- lua-5.1.2/test/buftest.lua 1969-12-31 19:00:00.000000000 -0500 +++ luaprestring-5.1.2/test/buftest.lua 2007-12-11 16:30:33.000000000 -0500 @@ -0,0 +1,55 @@ +local function whinef(cond, err) + if not cond then + io.stderr:write(("Usage: %s kind bufsize [reps]\n") + :format(arg[0])) + if err then + io.stderr:write(("%s: %s\n"):format(arg[0], tostring(err))) + end + os.exit(1) + end + return cond +end +local kinds = {"recycle", "prestring", "inplace", "string"} + +local kind, bufsize, reps = ... +if kind == "log" then + local fn = whinef(bufsize) + local f = whinef(io.open(fn)) + local times = {} + for l in f:lines() do + local kind, bufsize, time = l:match"(%w+)%s+(%d+)%s+([%d%.eE]+)" + bufsize = tonumber(bufsize) + time = tonumber(time) + local timesforsize = times[bufsize] or {} + times[bufsize] = timesforsize + if not timesforsize[kind] or timesforsize[kind] > time then + timesforsize[kind] = time + end + end + f:close() + local keys = {} + for size in pairs(times) do keys[#keys+1] = size end + table.sort(keys) + for _, size in ipairs(keys) do + io.stdout:write(("%8d"):format(size)) + local timesforsize = times[size] + for _, kind in ipairs(kinds) do + io.stdout:write((" %7.3f"):format(timesforsize[kind])) + end + io.stdout:write"\n" + end +else + bufsize = whinef(tonumber(bufsize)) + reps = reps and whinef(tonumber(reps)) or 1e6 + local filesize = bufsize * reps + local count = 0 + for b in test(kind, filesize, bufsize) do + count = count + #b + end + if count ~= filesize then + io.stderr:write(("Size mismatch, expected %s, got %s\n") + :format(filesize, count)) + end + local now = os.clock() + print(("%s\t%8d\t%8.3f"):format(kind, bufsize, now)) +end diff -urN lua-5.1.2/test/memlog.lua luaprestring-5.1.2/test/memlog.lua --- lua-5.1.2/test/memlog.lua 1969-12-31 19:00:00.000000000 -0500 +++ luaprestring-5.1.2/test/memlog.lua 2007-12-10 15:34:08.000000000 -0500 @@ -0,0 +1,92 @@ +local f = ... and assert(io.open(..., "r")) or io.stdin +local allocs = {} +local realloc +local lineno = 0 +local evtno = 0 +local used = 0 +local maxused = 0 + +local function memerr(fmt, ...) + io.stderr:write(("At line %d: "):format(lineno), fmt:format(...), "\n") +end + +local function memerrf(cond, ...) + if not cond then memerr(...) end + return cond +end + +local function seqcheck(kind) + local needrealloc = kind == '>' + return memerrf(not not needrealloc ~= not realloc, + "Sequence error, '%s' %s '<'", + kind, needrealloc and "does not follow" or "follows" + ) +end + +local function memevt(delta, nolog) + evtno = evtno + 1 + used = used + delta + if used > maxused then maxused = used end + if not nolog then + io.stdout:write(("%8d %12d %12d\n"):format(evtno, used, maxused)) + end +end + +local function amatch_aux(l, ...) + if ... then return ... end + memerr("Invalid trace: %s", l) +end + +local function amatch(l, pat, st) + return amatch_aux(l, l:match(pat, st)) +end + +local handle = {} +handle['+'] = function(addr, size) + memerrf(not allocs[addr], "Malloc duplicated for %s", addr) + allocs[addr] = size + memevt(size) +end + +handle['-'] = function(addr) + local size = memerrf(allocs[addr], "Free of unallocated storage at %s", addr) + memevt(-(size or 0)) + allocs[addr] = nil +end + +handle['<'] = function(addr) + realloc = addr + memerrf(allocs[realloc], "Realloc of unallocated storage at %s", addr) +end + +handle['>'] = function(addr, newsize) + local oldsize = allocs[realloc] + memevt(newsize or 0, "don't log") + memevt(-(oldsize or 0)) + if addr ~= realloc then allocs[realloc] = nil end + allocs[addr] = newsize + realloc = nil +end + +local parse = {} +local function parse2(kind, l, p) + local a, s = amatch(l, "^(0x%x+) 0x(%x+)$", p) + if a then return handle[kind](a, tonumber(s, 16)) end +end + +local function parse1(kind, l, p) + local a = amatch(l, "^(0x%x+)$", p) + if a then return handle[kind](a) end +end +parse['+'] = parse2 +parse['-'] = parse1 +parse['<'] = parse1 +parse['>'] = parse2 + +for l in f:lines() do + lineno = lineno + 1 + if l:sub(1,1) == "@" then + local kind, p = amatch(l, " ([-+<>]) ()") + if kind and seqcheck(kind) then parse[kind](kind, l, p) end + end +end