Optimize and refactor printing of numbers to buffers.

This commit is contained in:
Mike Pall 2013-03-25 16:41:13 +01:00
parent 3b0b3afbb1
commit 59329cfbbf
5 changed files with 70 additions and 63 deletions

View File

@ -881,14 +881,10 @@ LJLIB_CF(string_format)
tv.n = lj_lib_checknum(L, arg); tv.n = lj_lib_checknum(L, arg);
if (LJ_UNLIKELY((tv.u32.hi << 1) >= 0xffe00000)) { if (LJ_UNLIKELY((tv.u32.hi << 1) >= 0xffe00000)) {
/* Canonicalize output of non-finite values. */ /* Canonicalize output of non-finite values. */
char *p, nbuf[LJ_STR_NUMBUF]; char nbuf[LJ_STR_NUMBUF];
MSize n = lj_str_bufnum(nbuf, &tv); char *p = lj_str_bufnum(nbuf, &tv);
if (fmt[-1] < 'a') { if (fmt[-1] < 'a') { *(p-3) -= 0x20; *(p-2) -= 0x20; *(p-1) -= 0x20; }
nbuf[n-3] = nbuf[n-3] - 0x20; *p = '\0';
nbuf[n-2] = nbuf[n-2] - 0x20;
nbuf[n-1] = nbuf[n-1] - 0x20;
}
nbuf[n] = '\0';
for (p = spec; *p < 'A' && *p != '.'; p++) ; for (p = spec; *p < 'A' && *p != '.'; p++) ;
*p++ = 's'; *p = '\0'; *p++ = 's'; *p = '\0';
len = (MSize)sprintf(buf, spec, nbuf); len = (MSize)sprintf(buf, spec, nbuf);
@ -901,8 +897,9 @@ LJLIB_CF(string_format)
string_fmt_quoted(sb, lj_lib_checkstr(L, arg)); string_fmt_quoted(sb, lj_lib_checkstr(L, arg));
continue; continue;
case 'p': case 'p':
len = lj_str_bufptr(buf, lua_topointer(L, arg)); setsbufP(sb, lj_str_bufptr(lj_buf_more(sb, LJ_STR_PTRBUF),
break; lua_topointer(L, arg)));
continue;
case 's': { case 's': {
GCstr *str = string_fmt_tostring(L, arg); GCstr *str = string_fmt_tostring(L, arg);
if (!strchr(spec, '.') && str->len >= 100) { /* Format overflow? */ if (!strchr(spec, '.') && str->len >= 100) { /* Format overflow? */

View File

@ -568,19 +568,19 @@ GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned)
/* Convert complex to string with 'i' or 'I' suffix. */ /* Convert complex to string with 'i' or 'I' suffix. */
GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size) GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size)
{ {
char buf[2*LJ_STR_NUMBUF+2+1]; char buf[2*LJ_STR_NUMBUF+2+1], *p = buf;
TValue re, im; TValue re, im;
MSize len;
if (size == 2*sizeof(double)) { if (size == 2*sizeof(double)) {
re.n = *(double *)sp; im.n = ((double *)sp)[1]; re.n = *(double *)sp; im.n = ((double *)sp)[1];
} else { } else {
re.n = (double)*(float *)sp; im.n = (double)((float *)sp)[1]; re.n = (double)*(float *)sp; im.n = (double)((float *)sp)[1];
} }
len = lj_str_bufnum(buf, &re); p = lj_str_bufnum(p, &re);
if (!(im.u32.hi & 0x80000000u) || im.n != im.n) buf[len++] = '+'; if (!(im.u32.hi & 0x80000000u) || im.n != im.n) *p++ = '+';
len += lj_str_bufnum(buf+len, &im); p = lj_str_bufnum(p, &im);
buf[len] = buf[len-1] >= 'a' ? 'I' : 'i'; *p = *(p-1) >= 'a' ? 'I' : 'i';
return lj_str_new(L, buf, len+1); p++;
return lj_str_new(L, buf, p-buf);
} }
/* -- C type state -------------------------------------------------------- */ /* -- C type state -------------------------------------------------------- */

View File

@ -79,10 +79,7 @@ static GCstr *argv2str(jit_State *J, TValue *o)
GCstr *s; GCstr *s;
if (!tvisnumber(o)) if (!tvisnumber(o))
lj_trace_err(J, LJ_TRERR_BADTYPE); lj_trace_err(J, LJ_TRERR_BADTYPE);
if (tvisint(o)) s = lj_str_fromnumber(J->L, o);
s = lj_str_fromint(J->L, intV(o));
else
s = lj_str_fromnum(J->L, &o->n);
setstrV(J->L, o, s); setstrV(J->L, o, s);
return s; return s;
} }

View File

@ -168,41 +168,62 @@ void LJ_FASTCALL lj_str_free(global_State *g, GCstr *s)
/* -- Type conversions ---------------------------------------------------- */ /* -- Type conversions ---------------------------------------------------- */
/* Print number to buffer. Canonicalizes non-finite values. */ /* Print number to buffer. Canonicalizes non-finite values. */
MSize LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o) char * LJ_FASTCALL lj_str_bufnum(char *p, cTValue *o)
{ {
if (LJ_LIKELY((o->u32.hi << 1) < 0xffe00000)) { /* Finite? */ if (LJ_LIKELY((o->u32.hi << 1) < 0xffe00000)) { /* Finite? */
lua_Number n = o->n;
#if __BIONIC__ #if __BIONIC__
if (tvismzero(o)) { s[0] = '-'; s[1] = '0'; return 2; } if (tvismzero(o)) { *p++ = '-'; *p++ = '0'; return p; }
#endif #endif
return (MSize)lua_number2str(s, n); return p + lua_number2str(p, o->n);
} else if (((o->u32.hi & 0x000fffff) | o->u32.lo) != 0) { } else if (((o->u32.hi & 0x000fffff) | o->u32.lo) != 0) {
s[0] = 'n'; s[1] = 'a'; s[2] = 'n'; return 3; *p++ = 'n'; *p++ = 'a'; *p++ = 'n';
} else if ((o->u32.hi & 0x80000000) == 0) { } else if ((o->u32.hi & 0x80000000) == 0) {
s[0] = 'i'; s[1] = 'n'; s[2] = 'f'; return 3; *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
} else { } else {
s[0] = '-'; s[1] = 'i'; s[2] = 'n'; s[3] = 'f'; return 4; *p++ = '-'; *p++ = 'i'; *p++ = 'n'; *p++ = 'f';
} }
return p;
} }
/* Print integer to buffer. Returns pointer to start (!= buffer start). */ #define STR_BUFINT_R(x, sh, sc) \
static char *str_bufint(char *p, int32_t k) { uint32_t d = (x*(((1<<sh)+sc-1)/sc))>>sh; x -= d*sc; *p++ = (char)('0'+d); }
/* Print integer to buffer. */
char * LJ_FASTCALL lj_str_bufint(char *p, int32_t k)
{ {
uint32_t u = (uint32_t)(k < 0 ? -k : k); uint32_t u = (uint32_t)k;
p += LJ_STR_INTBUF; if (k < 0) { u = (uint32_t)-k; *p++ = '-'; }
do { *--p = (char)('0' + u % 10); } while (u /= 10); if (u < 10000) {
if (k < 0) *--p = '-'; if (u < 10) goto dig1; if (u < 100) goto dig2; if (u < 1000) goto dig3;
} else {
uint32_t v = u / 10000; u -= v * 10000;
if (v < 10000) {
if (v < 10) goto dig5; if (v < 100) goto dig6; if (v < 1000) goto dig7;
} else {
uint32_t w = v / 10000; v -= w * 10000;
if (w >= 10) STR_BUFINT_R(w, 10, 10)
*p++ = (char)('0'+w);
}
STR_BUFINT_R(v, 23, 1000)
dig7: STR_BUFINT_R(v, 12, 100)
dig6: STR_BUFINT_R(v, 10, 10)
dig5: *p++ = (char)('0'+v);
}
STR_BUFINT_R(u, 23, 1000)
dig3: STR_BUFINT_R(u, 12, 100)
dig2: STR_BUFINT_R(u, 10, 10)
dig1: *p++ = (char)('0'+u);
return p; return p;
} }
/* Print pointer to buffer. */ /* Print pointer to buffer. */
MSize LJ_FASTCALL lj_str_bufptr(char *p, const void *v) char * LJ_FASTCALL lj_str_bufptr(char *p, const void *v)
{ {
ptrdiff_t x = (ptrdiff_t)v; ptrdiff_t x = (ptrdiff_t)v;
MSize i, n = LJ_STR_PTRBUF; MSize i, n = LJ_STR_PTRBUF;
if (x == 0) { if (x == 0) {
p[0] = 'N'; p[1] = 'U'; p[2] = 'L'; p[3] = 'L'; *p++ = 'N'; *p++ = 'U'; *p++ = 'L'; *p++ = 'L';
return 4; return p;
} }
#if LJ_64 #if LJ_64
/* Shorten output for 64 bit pointers. */ /* Shorten output for 64 bit pointers. */
@ -212,7 +233,7 @@ MSize LJ_FASTCALL lj_str_bufptr(char *p, const void *v)
p[1] = 'x'; p[1] = 'x';
for (i = n-1; i >= 2; i--, x >>= 4) for (i = n-1; i >= 2; i--, x >>= 4)
p[i] = "0123456789abcdef"[(x & 15)]; p[i] = "0123456789abcdef"[(x & 15)];
return n; return p+n;
} }
/* Print TValue to buffer (only for numbers) and return pointer to start. */ /* Print TValue to buffer (only for numbers) and return pointer to start. */
@ -222,11 +243,10 @@ const char *lj_str_buftv(char *buf, cTValue *o, MSize *lenp)
*lenp = strV(o)->len; *lenp = strV(o)->len;
return strVdata(o); return strVdata(o);
} else if (tvisint(o)) { } else if (tvisint(o)) {
char *p = str_bufint(buf, intV(o)); *lenp = (MSize)(lj_str_bufint(buf, intV(o)) - buf);
*lenp = (MSize)(buf+LJ_STR_INTBUF-p); return buf;
return p;
} else if (tvisnum(o)) { } else if (tvisnum(o)) {
*lenp = lj_str_bufnum(buf, o); *lenp = (MSize)(lj_str_bufnum(buf, o) - buf);
return buf; return buf;
} else { } else {
return NULL; return NULL;
@ -237,7 +257,7 @@ const char *lj_str_buftv(char *buf, cTValue *o, MSize *lenp)
GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np) GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np)
{ {
char buf[LJ_STR_NUMBUF]; char buf[LJ_STR_NUMBUF];
MSize len = lj_str_bufnum(buf, (TValue *)np); MSize len = (MSize)(lj_str_bufnum(buf, (TValue *)np) - buf);
return lj_str_new(L, buf, len); return lj_str_new(L, buf, len);
} }
@ -245,8 +265,8 @@ GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np)
GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k) GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k)
{ {
char buf[LJ_STR_INTBUF]; char buf[LJ_STR_INTBUF];
char *p = str_bufint(buf, k); MSize len = (MSize)(lj_str_bufint(buf, k) - buf);
return lj_str_new(L, p, (size_t)(buf+sizeof(buf)-p)); return lj_str_new(L, buf, len);
} }
GCstr * LJ_FASTCALL lj_str_fromnumber(lua_State *L, cTValue *o) GCstr * LJ_FASTCALL lj_str_fromnumber(lua_State *L, cTValue *o)
@ -278,28 +298,20 @@ const char *lj_str_pushvf(lua_State *L, const char *fmt, va_list argp)
case 'c': case 'c':
lj_buf_putb(sb, va_arg(argp, int)); lj_buf_putb(sb, va_arg(argp, int));
break; break;
case 'd': { case 'd':
char buf[LJ_STR_INTBUF]; setsbufP(sb, lj_str_bufint(lj_buf_more(sb, LJ_STR_INTBUF),
char *p = str_bufint(buf, va_arg(argp, int32_t)); va_arg(argp, int32_t)));
lj_buf_putmem(sb, p, (MSize)(buf+LJ_STR_INTBUF-p));
break; break;
}
case 'f': { case 'f': {
char buf[LJ_STR_NUMBUF];
TValue tv; TValue tv;
MSize len; tv.n = va_arg(argp, lua_Number);
tv.n = (lua_Number)(va_arg(argp, LUAI_UACNUMBER)); setsbufP(sb, lj_str_bufnum(lj_buf_more(sb, LJ_STR_NUMBUF), &tv));
len = (MSize)lj_str_bufnum(buf, &tv);
lj_buf_putmem(sb, buf, len);
break; break;
} }
case 'p': { case 'p':
#define FMTP_CHARS (2*sizeof(ptrdiff_t)) setsbufP(sb, lj_str_bufptr(lj_buf_more(sb, LJ_STR_PTRBUF),
char buf[LJ_STR_PTRBUF]; va_arg(argp, void *)));
MSize len = lj_str_bufptr(buf, va_arg(argp, void *));
lj_buf_putmem(sb, buf, len);
break; break;
}
case '%': case '%':
lj_buf_putb(sb, '%'); lj_buf_putb(sb, '%');
break; break;

View File

@ -20,8 +20,9 @@ LJ_FUNC void LJ_FASTCALL lj_str_free(global_State *g, GCstr *s);
#define lj_str_newlit(L, s) (lj_str_new(L, "" s, sizeof(s)-1)) #define lj_str_newlit(L, s) (lj_str_new(L, "" s, sizeof(s)-1))
/* Type conversions. */ /* Type conversions. */
LJ_FUNC MSize LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o); LJ_FUNC char * LJ_FASTCALL lj_str_bufint(char *buf, int32_t k);
LJ_FUNC MSize LJ_FASTCALL lj_str_bufptr(char *p, const void *v); LJ_FUNC char * LJ_FASTCALL lj_str_bufnum(char *p, cTValue *o);
LJ_FUNC char * LJ_FASTCALL lj_str_bufptr(char *p, const void *v);
LJ_FUNC const char *lj_str_buftv(char *buf, cTValue *o, MSize *lenp); LJ_FUNC const char *lj_str_buftv(char *buf, cTValue *o, MSize *lenp);
LJ_FUNCA GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np); LJ_FUNCA GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np);
LJ_FUNC GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k); LJ_FUNC GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k);