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:
M | lauxlib.c | | | 124 | ++++++++++++++++++++++++++++++++++--------------------------------------------- |
M | lauxlib.h | | | 23 | +++++++++++++---------- |
M | lstrlib.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);