lua

A copy of the Lua development repository
Log | Files | Refs | README

commit 9100f7479afabc4bb2926c619b5ef09693cf9a94
parent 055104f5b6a0264974c5d9f2a55499420a1c9c2a
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date:   Fri,  9 Apr 2010 13:14:22 -0300

new implementation for Generic Buffer manipulation (using userdata as
temporary buffer space)

Diffstat:
Mlauxlib.c | 124++++++++++++++++++++++++++++++++++---------------------------------------------
Mlauxlib.h | 23+++++++++++++----------
Mlstrlib.c | 49+++++++++++++++++++++++++++----------------------
3 files changed, 93 insertions(+), 103 deletions(-)

diff --git a/lauxlib.c b/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.205 2010/03/22 17:28:31 roberto Exp roberto $ +** $Id: lauxlib.c,v 1.206 2010/03/29 17:44:31 roberto Exp roberto $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -347,64 +347,40 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, ** ======================================================= */ - -#define bufflen(B) ((B)->p - (B)->buffer) -#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) - -#define LIMIT (LUA_MINSTACK/2) - - -static int emptybuffer (luaL_Buffer *B) { - size_t l = bufflen(B); - if (l == 0) return 0; /* put nothing on stack */ - else { - lua_pushlstring(B->L, B->buffer, l); - B->p = B->buffer; - B->lvl++; - return 1; - } -} +/* +** check whether buffer is using a userdata on the stack as a temporary +** buffer +*/ +#define buffonstack(B) ((B)->b != (B)->initb) -static void adjuststack (luaL_Buffer *B) { - if (B->lvl > 1) { - lua_State *L = B->L; - int toget = 1; /* number of levels to concat */ - size_t toplen = lua_rawlen(L, -1); - do { - size_t l = lua_rawlen(L, -(toget+1)); - if (B->lvl - toget + 1 >= LIMIT || toplen > l) { - toplen += l; - toget++; - } - else break; - } while (toget < B->lvl); - lua_concat(L, toget); - B->lvl = B->lvl - toget + 1; +/* +** returns a pointer to a free area with at least 'sz' bytes +*/ +LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { + lua_State *L = B->L; + if (B->size - B->n < sz) { /* not enough space? */ + char *newbuff; + size_t newsize = B->size * 2; /* double buffer size */ + if (newsize - B->n < sz) /* not bit enough? */ + newsize = B->n + sz; + if (newsize < B->n || newsize - B->n < sz) + luaL_error(L, "string too large"); + newbuff = (char *)lua_newuserdata(L, newsize); /* create larger buffer */ + memcpy(newbuff, B->b, B->n); /* move content to new buffer */ + if (buffonstack(B)) + lua_remove(L, -2); /* remove old buffer */ + B->b = newbuff; + B->size = newsize; } -} - - -LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { - if (emptybuffer(B)) - adjuststack(B); - return B->buffer; + return &B->b[B->n]; } LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { - while (l) { - size_t space = bufffree(B); - if (space == 0) { - luaL_prepbuffer(B); - space = LUAL_BUFFERSIZE; /* bufffree(B) == LUAL_BUFFERSIZE */ - } - if (space > l) space = l; - memcpy(B->p, s, space); - B->p += space; - s += space; - l -= space; - } + char *b = luaL_prepbuffsize(B, l); + memcpy(b, s, l); + luaL_addsize(B, l); } @@ -414,35 +390,41 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { LUALIB_API void luaL_pushresult (luaL_Buffer *B) { - emptybuffer(B); - lua_concat(B->L, B->lvl); - B->lvl = 1; + lua_State *L = B->L; + lua_pushlstring(L, B->b, B->n); + if (buffonstack(B)) + lua_remove(L, -2); /* remove old buffer */ +} + + +LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { + luaL_addsize(B, sz); + luaL_pushresult(B); } LUALIB_API void luaL_addvalue (luaL_Buffer *B) { lua_State *L = B->L; - size_t vl; - const char *s = lua_tolstring(L, -1, &vl); - if (vl <= bufffree(B)) { /* fit into buffer? */ - memcpy(B->p, s, vl); /* put it there */ - B->p += vl; - lua_pop(L, 1); /* remove from stack */ - } - else { - if (emptybuffer(B)) - lua_insert(L, -2); /* put buffer before new value */ - B->lvl++; /* add new value into B stack */ - adjuststack(B); - } + size_t l; + const char *s = lua_tolstring(L, -1, &l); + if (buffonstack(B)) + lua_insert(L, -2); /* put value below buffer */ + luaL_addlstring(B, s, l); + lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ } LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { - luaL_checkstack(L, LIMIT + LUA_MINSTACK, "no space for new buffer"); B->L = L; - B->p = B->buffer; - B->lvl = 0; + B->b = B->initb; + B->n = 0; + B->size = LUAL_BUFFERSIZE; +} + + +LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { + luaL_buffinit(L, B); + return luaL_prepbuffsize(B, sz); } /* }====================================================== */ diff --git a/lauxlib.h b/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.100 2010/01/21 16:49:21 roberto Exp roberto $ +** $Id: lauxlib.h,v 1.101 2010/03/17 21:37:37 roberto Exp roberto $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -122,28 +122,31 @@ LUALIB_API int (luaL_cpcall) (lua_State *L, lua_CFunction f, int nargs, ** ======================================================= */ - - typedef struct luaL_Buffer { - char *p; /* current position in buffer */ - int lvl; /* number of strings in the stack (level) */ + char *b; /* buffer address */ + size_t size; /* buffer size */ + size_t n; /* number of characters in buffer */ lua_State *L; - char buffer[LUAL_BUFFERSIZE]; + char initb[LUAL_BUFFERSIZE]; /* initial buffer */ } luaL_Buffer; + #define luaL_addchar(B,c) \ - ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ - (*(B)->p++ = (char)(c))) + ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ + ((B)->b[(B)->n++] = (c))) -#define luaL_addsize(B,n) ((B)->p += (n)) +#define luaL_addsize(B,s) ((B)->n += (s)) LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); -LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); +LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); +LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz); +LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); +#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) /* }====================================================== */ diff --git a/lstrlib.c b/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.147 2009/12/17 12:50:20 roberto Exp roberto $ +** $Id: lstrlib.c,v 1.148 2010/01/04 16:37:19 roberto Exp roberto $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -65,12 +65,13 @@ static int str_sub (lua_State *L) { static int str_reverse (lua_State *L) { - size_t l; + size_t l, i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); - while (l--) luaL_addchar(&b, s[l]); - luaL_pushresult(&b); + char *p = luaL_buffinitsize(L, &b, l); + for (i = 0; i < l; i++) + p[i] = s[l - i - 1]; + luaL_pushresultsize(&b, l); return 1; } @@ -80,10 +81,10 @@ static int str_lower (lua_State *L) { size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); + char *p = luaL_buffinitsize(L, &b, l); for (i=0; i<l; i++) - luaL_addchar(&b, tolower(uchar(s[i]))); - luaL_pushresult(&b); + p[i] = tolower(uchar(s[i])); + luaL_pushresultsize(&b, l); return 1; } @@ -93,10 +94,10 @@ static int str_upper (lua_State *L) { size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); + char *p = luaL_buffinitsize(L, &b, l); for (i=0; i<l; i++) - luaL_addchar(&b, toupper(uchar(s[i]))); - luaL_pushresult(&b); + p[i] = toupper(uchar(s[i])); + luaL_pushresultsize(&b, l); return 1; } @@ -136,13 +137,13 @@ static int str_char (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; luaL_Buffer b; - luaL_buffinit(L, &b); + char *p = luaL_buffinitsize(L, &b, n); for (i=1; i<=n; i++) { int c = luaL_checkint(L, i); luaL_argcheck(L, uchar(c) == c, i, "invalid value"); - luaL_addchar(&b, uchar(c)); + p[i - 1] = uchar(c); } - luaL_pushresult(&b); + luaL_pushresultsize(&b, n); return 1; } @@ -773,6 +774,9 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { } +/* +** add length modifier into integer formats +*/ static void addintlen (char *form) { size_t l = strlen(form); char spec = form[l - 1]; @@ -796,12 +800,13 @@ static int str_format (lua_State *L) { luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format (`%...') */ - char buff[MAX_ITEM]; /* to store the formatted item */ + char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ + int nb = 0; /* number of bytes in added item */ arg++; strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { - sprintf(buff, form, luaL_checkint(L, arg)); + nb = sprintf(buff, form, luaL_checkint(L, arg)); break; } case 'd': case 'i': @@ -810,17 +815,17 @@ static int str_format (lua_State *L) { LUA_INTFRM_T r = (n < 0) ? (LUA_INTFRM_T)n : (LUA_INTFRM_T)(unsigned LUA_INTFRM_T)n; addintlen(form); - sprintf(buff, form, r); + nb = sprintf(buff, form, r); break; } case 'e': case 'E': case 'f': case 'g': case 'G': { - sprintf(buff, form, (double)luaL_checknumber(L, arg)); + nb = sprintf(buff, form, (double)luaL_checknumber(L, arg)); break; } case 'q': { addquoted(L, &b, arg); - continue; /* skip the 'addsize' at the end */ + break; } case 's': { size_t l; @@ -830,10 +835,10 @@ static int str_format (lua_State *L) { keep original string */ lua_pushvalue(L, arg); luaL_addvalue(&b); - continue; /* skip the `addsize' at the end */ + break; } else { - sprintf(buff, form, s); + nb = sprintf(buff, form, s); break; } } @@ -842,7 +847,7 @@ static int str_format (lua_State *L) { LUA_QL("format"), *(strfrmt - 1)); } } - luaL_addlstring(&b, buff, strlen(buff)); + luaL_addsize(&b, nb); } } luaL_pushresult(&b);