瀏覽代碼

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

Roberto Ierusalimschy 15 年之前
父節點
當前提交
9100f7479a
共有 3 個文件被更改,包括 93 次插入103 次删除
  1. 53 71
      lauxlib.c
  2. 13 10
      lauxlib.h
  3. 27 22
      lstrlib.c

+ 53 - 71
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);
 }
 
 /* }====================================================== */

+ 13 - 10
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)
 
 /* }====================================================== */
 

+ 27 - 22
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);