فهرست منبع

New function 'lua_numbertostrbuff'

It converts a Lua number to a string in a buffer, without creating
a new Lua string.
Roberto Ierusalimschy 10 ماه پیش
والد
کامیت
e3ce88c9e8
7فایلهای تغییر یافته به همراه67 افزوده شده و 40 حذف شده
  1. 12 0
      lapi.c
  2. 3 4
      lauxlib.c
  3. 9 13
      liolib.c
  4. 23 21
      lobject.c
  5. 1 0
      lobject.h
  6. 3 1
      lua.h
  7. 16 1
      manual/manual.of

+ 12 - 0
lapi.c

@@ -368,6 +368,18 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
 }
 
 
+LUA_API unsigned (lua_numbertostrbuff) (lua_State *L, int idx, char *buff) {
+  const TValue *o = index2value(L, idx);
+  if (ttisnumber(o)) {
+    unsigned len = luaO_tostringbuff(o, buff);
+    buff[len++] = '\0';  /* add final zero */
+    return len;
+  }
+  else
+    return 0;
+}
+
+
 LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
   size_t sz = luaO_str2num(s, s2v(L->top.p));
   if (sz != 0)

+ 3 - 4
lauxlib.c

@@ -920,10 +920,9 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
   else {
     switch (lua_type(L, idx)) {
       case LUA_TNUMBER: {
-        if (lua_isinteger(L, idx))
-          lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx));
-        else
-          lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx));
+        char buff[LUA_N2SBUFFSZ];
+        lua_numbertostrbuff(L, idx, buff);
+        lua_pushstring(L, buff);
         break;
       }
       case LUA_TSTRING:

+ 9 - 13
liolib.c

@@ -665,20 +665,16 @@ static int g_write (lua_State *L, FILE *f, int arg) {
   int status = 1;
   errno = 0;
   for (; nargs--; arg++) {
-    if (lua_type(L, arg) == LUA_TNUMBER) {
-      /* optimization: could be done exactly as for strings */
-      int len = lua_isinteger(L, arg)
-                ? fprintf(f, LUA_INTEGER_FMT,
-                             (LUAI_UACINT)lua_tointeger(L, arg))
-                : fprintf(f, LUA_NUMBER_FMT,
-                             (LUAI_UACNUMBER)lua_tonumber(L, arg));
-      status = status && (len > 0);
-    }
-    else {
-      size_t l;
-      const char *s = luaL_checklstring(L, arg, &l);
-      status = status && (fwrite(s, sizeof(char), l, f) == l);
+    char buff[LUA_N2SBUFFSZ];
+    const char *s;
+    size_t len = lua_numbertostrbuff(L, arg, buff);  /* try as a number */
+    if (len > 0) {  /* did conversion work (value was a number)? */
+      s = buff;
+      len--;
     }
+    else  /* must be a string */
+      s = luaL_checklstring(L, arg, &len);
+    status = status && (fwrite(s, sizeof(char), len, f) == len);
   }
   if (l_likely(status))
     return 1;  /* file handle already on stack top */

+ 23 - 21
lobject.c

@@ -400,15 +400,17 @@ int luaO_utf8esc (char *buff, unsigned long x) {
 
 
 /*
-** Maximum length of the conversion of a number to a string. Must be
-** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT.
-** For a long long int, this is 19 digits plus a sign and a final '\0',
-** adding to 21. For a long double, it can go to a sign, the dot, an
-** exponent letter, an exponent sign, 4 exponent digits, the final
-** '\0', plus the significant digits, which are approximately the *_DIG
-** attribute.
+** The size of the buffer for the conversion of a number to a string
+** 'LUA_N2SBUFFSZ' must be enough to accommodate both LUA_INTEGER_FMT
+** and LUA_NUMBER_FMT.  For a long long int, this is 19 digits plus a
+** sign and a final '\0', adding to 21. For a long double, it can go to
+** a sign, the dot, an exponent letter, an exponent sign, 4 exponent
+** digits, the final '\0', plus the significant digits, which are
+** approximately the *_DIG attribute.
 */
-#define MAXNUMBER2STR	(20 + l_floatatt(DIG))
+#if LUA_N2SBUFFSZ < (20 + l_floatatt(DIG))
+#error "invalid value for LUA_N2SBUFFSZ"
+#endif
 
 
 /*
@@ -422,12 +424,12 @@ int luaO_utf8esc (char *buff, unsigned long x) {
 */
 static int tostringbuffFloat (lua_Number n, char *buff) {
   /* first conversion */
-  int len = l_sprintf(buff, MAXNUMBER2STR, LUA_NUMBER_FMT,
+  int len = l_sprintf(buff, LUA_N2SBUFFSZ, LUA_NUMBER_FMT,
                             (LUAI_UACNUMBER)n);
   lua_Number check = lua_str2number(buff, NULL);  /* read it back */
   if (check != n) {  /* not enough precision? */
     /* convert again with more precision */
-    len = l_sprintf(buff, MAXNUMBER2STR, LUA_NUMBER_FMT_N,
+    len = l_sprintf(buff, LUA_N2SBUFFSZ, LUA_NUMBER_FMT_N,
                           (LUAI_UACNUMBER)n);
   }
   /* looks like an integer? */
@@ -442,14 +444,14 @@ static int tostringbuffFloat (lua_Number n, char *buff) {
 /*
 ** Convert a number object to a string, adding it to a buffer.
 */
-static unsigned tostringbuff (TValue *obj, char *buff) {
+unsigned luaO_tostringbuff (const TValue *obj, char *buff) {
   int len;
   lua_assert(ttisnumber(obj));
   if (ttisinteger(obj))
-    len = lua_integer2str(buff, MAXNUMBER2STR, ivalue(obj));
+    len = lua_integer2str(buff, LUA_N2SBUFFSZ, ivalue(obj));
   else
     len = tostringbuffFloat(fltvalue(obj), buff);
-  lua_assert(len < MAXNUMBER2STR);
+  lua_assert(len < LUA_N2SBUFFSZ);
   return cast_uint(len);
 }
 
@@ -458,8 +460,8 @@ static unsigned tostringbuff (TValue *obj, char *buff) {
 ** Convert a number object to a Lua string, replacing the value at 'obj'
 */
 void luaO_tostring (lua_State *L, TValue *obj) {
-  char buff[MAXNUMBER2STR];
-  unsigned len = tostringbuff(obj, buff);
+  char buff[LUA_N2SBUFFSZ];
+  unsigned len = luaO_tostringbuff(obj, buff);
   setsvalue(L, obj, luaS_newlstr(L, buff, len));
 }
 
@@ -474,10 +476,10 @@ void luaO_tostring (lua_State *L, TValue *obj) {
 
 /*
 ** Size for buffer space used by 'luaO_pushvfstring'. It should be
-** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
+** (LUA_IDSIZE + LUA_N2SBUFFSZ) + a minimal space for basic messages,
 ** so that 'luaG_addinfo' can work directly on the static buffer.
 */
-#define BUFVFS		cast_uint(LUA_IDSIZE + MAXNUMBER2STR + 95)
+#define BUFVFS		cast_uint(LUA_IDSIZE + LUA_N2SBUFFSZ + 95)
 
 /*
 ** Buffer used by 'luaO_pushvfstring'. 'err' signals an error while
@@ -579,8 +581,8 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
 ** Add a numeral to the buffer.
 */
 static void addnum2buff (BuffFS *buff, TValue *num) {
-  char numbuff[MAXNUMBER2STR];
-  unsigned len = tostringbuff(num, numbuff);  /* format number into 'numbuff' */
+  char numbuff[LUA_N2SBUFFSZ];
+  unsigned len = luaO_tostringbuff(num, numbuff);
   addstr2buff(buff, numbuff, len);
 }
 
@@ -626,9 +628,9 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
         break;
       }
       case 'p': {  /* a pointer */
-        char bf[MAXNUMBER2STR];  /* enough space for '%p' */
+        char bf[LUA_N2SBUFFSZ];  /* enough space for '%p' */
         void *p = va_arg(argp, void *);
-        int len = lua_pointer2str(bf, MAXNUMBER2STR, p);
+        int len = lua_pointer2str(bf, LUA_N2SBUFFSZ, p);
         addstr2buff(&buff, bf, cast_uint(len));
         break;
       }

+ 1 - 0
lobject.h

@@ -845,6 +845,7 @@ LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,
 LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1,
                            const TValue *p2, StkId res);
 LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o);
+LUAI_FUNC unsigned luaO_tostringbuff (const TValue *obj, char *buff);
 LUAI_FUNC lu_byte luaO_hexavalue (int c);
 LUAI_FUNC void luaO_tostring (lua_State *L, TValue *obj);
 LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,

+ 3 - 1
lua.h

@@ -371,7 +371,9 @@ LUA_API int   (lua_next) (lua_State *L, int idx);
 LUA_API void  (lua_concat) (lua_State *L, int n);
 LUA_API void  (lua_len)    (lua_State *L, int idx);
 
-LUA_API size_t   (lua_stringtonumber) (lua_State *L, const char *s);
+#define LUA_N2SBUFFSZ	64
+LUA_API unsigned  (lua_numbertostrbuff) (lua_State *L, int idx, char *buff);
+LUA_API size_t  (lua_stringtonumber) (lua_State *L, const char *s);
 
 LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
 LUA_API void      (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);

+ 16 - 1
manual/manual.of

@@ -675,7 +675,7 @@ approximately @M{n} bytes between steps.
 The garbage-collector step multiplier
 controls how much work each incremental step does.
 A value of @M{n} means the interpreter will execute
-@M{n%} @emphx{units of work} for each byte allocated.
+@M{n%} @emphx{units of work} for each word allocated.
 A unit of work corresponds roughly to traversing one slot
 or sweeping one object.
 Larger values make the collector more aggressive.
@@ -3829,11 +3829,26 @@ This macro may evaluate its arguments more than once.
 
 }
 
+@APIEntry{unsigned (lua_numbertostrbuff) (lua_State *L, int idx,
+                                          char *buff);|
+@apii{0,0,-}
+
+Converts the number at acceptable index @id{idx} to a string
+and puts the result in @id{buff}.
+The buffer must have a size of at least @Lid{LUA_N2SBUFFSZ} bytes.
+The conversion follows a non-specified format @see{coercion}.
+The function returns the number of bytes written to the buffer
+(including the final zero),
+or zero if the value at @id{idx} is not a number.
+
+}
+
 @APIEntry{int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);|
 @apii{nargs + 1,nresults|1,-}
 
 Calls a function (or a callable object) in protected mode.
 
+
 Both @id{nargs} and @id{nresults} have the same meaning as
 in @Lid{lua_call}.
 If there are no errors during the call,