diff options
| author | Mike Pall <mike> | 2016-02-26 17:59:43 +0100 |
|---|---|---|
| committer | Mike Pall <mike> | 2016-02-26 18:03:08 +0100 |
| commit | 18f6aa97fd93df8e9964c2d22f20f16e6b71b72b (patch) | |
| tree | fad1176f6c01dc1aaf36bafa0b73f22b8e1c37e4 | |
| parent | 339a1fd69611e2fd084127ee11a36e57035639d1 (diff) | |
| download | luajit-18f6aa97fd93df8e9964c2d22f20f16e6b71b72b.tar.gz luajit-18f6aa97fd93df8e9964c2d22f20f16e6b71b72b.tar.bz2 luajit-18f6aa97fd93df8e9964c2d22f20f16e6b71b72b.zip | |
Use internal implementation for converting FP numbers to strings.
Contributed by Peter Cawley.
| -rw-r--r-- | src/Makefile | 2 | ||||
| -rw-r--r-- | src/Makefile.dep | 4 | ||||
| -rw-r--r-- | src/lib_base.c | 3 | ||||
| -rw-r--r-- | src/lib_io.c | 3 | ||||
| -rw-r--r-- | src/lj_buf.c | 2 | ||||
| -rw-r--r-- | src/lj_ctype.c | 14 | ||||
| -rw-r--r-- | src/lj_meta.c | 14 | ||||
| -rw-r--r-- | src/lj_strfmt.c | 108 | ||||
| -rw-r--r-- | src/lj_strfmt.h | 6 | ||||
| -rw-r--r-- | src/lj_strfmt_num.c | 591 | ||||
| -rw-r--r-- | src/ljamalg.c | 1 |
11 files changed, 627 insertions, 121 deletions
diff --git a/src/Makefile b/src/Makefile index 1df39dc1..5d66f6eb 100644 --- a/src/Makefile +++ b/src/Makefile | |||
| @@ -478,7 +478,7 @@ LJLIB_C= $(LJLIB_O:.o=.c) | |||
| 478 | LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \ | 478 | LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \ |
| 479 | lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \ | 479 | lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \ |
| 480 | lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_strscan.o \ | 480 | lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_strscan.o \ |
| 481 | lj_strfmt.o lj_api.o lj_profile.o \ | 481 | lj_strfmt.o lj_strfmt_num.o lj_api.o lj_profile.o \ |
| 482 | lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \ | 482 | lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \ |
| 483 | lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \ | 483 | lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \ |
| 484 | lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \ | 484 | lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \ |
diff --git a/src/Makefile.dep b/src/Makefile.dep index 9aefb236..2c329f55 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep | |||
| @@ -94,7 +94,7 @@ lj_crecord.o: lj_crecord.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | |||
| 94 | lj_crecord.h lj_strfmt.h | 94 | lj_crecord.h lj_strfmt.h |
| 95 | lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 95 | lj_ctype.o: lj_ctype.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
| 96 | lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_strfmt.h lj_ctype.h \ | 96 | lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_strfmt.h lj_ctype.h \ |
| 97 | lj_ccallback.h | 97 | lj_ccallback.h lj_buf.h |
| 98 | lj_debug.o: lj_debug.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 98 | lj_debug.o: lj_debug.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
| 99 | lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \ | 99 | lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \ |
| 100 | lj_state.h lj_frame.h lj_bc.h lj_strfmt.h lj_jit.h lj_ir.h | 100 | lj_state.h lj_frame.h lj_bc.h lj_strfmt.h lj_jit.h lj_ir.h |
| @@ -188,6 +188,8 @@ lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ | |||
| 188 | lj_err.h lj_errmsg.h lj_str.h lj_char.h | 188 | lj_err.h lj_errmsg.h lj_str.h lj_char.h |
| 189 | lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 189 | lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
| 190 | lj_buf.h lj_gc.h lj_str.h lj_state.h lj_char.h lj_strfmt.h | 190 | lj_buf.h lj_gc.h lj_str.h lj_state.h lj_char.h lj_strfmt.h |
| 191 | lj_strfmt_num.o: lj_strfmt_num.c lj_obj.h lua.h luaconf.h lj_def.h \ | ||
| 192 | lj_arch.h lj_buf.h lj_gc.h lj_str.h lj_strfmt.h | ||
| 191 | lj_strscan.o: lj_strscan.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 193 | lj_strscan.o: lj_strscan.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
| 192 | lj_char.h lj_strscan.h | 194 | lj_char.h lj_strscan.h |
| 193 | lj_tab.o: lj_tab.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ | 195 | lj_tab.o: lj_tab.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ |
diff --git a/src/lib_base.c b/src/lib_base.c index ca268b1d..3c973265 100644 --- a/src/lib_base.c +++ b/src/lib_base.c | |||
| @@ -495,11 +495,10 @@ LJLIB_CF(print) | |||
| 495 | shortcut = (tvisfunc(tv) && funcV(tv)->c.ffid == FF_tostring); | 495 | shortcut = (tvisfunc(tv) && funcV(tv)->c.ffid == FF_tostring); |
| 496 | for (i = 0; i < nargs; i++) { | 496 | for (i = 0; i < nargs; i++) { |
| 497 | cTValue *o = &L->base[i]; | 497 | cTValue *o = &L->base[i]; |
| 498 | char buf[STRFMT_MAXBUF_NUM]; | ||
| 499 | const char *str; | 498 | const char *str; |
| 500 | size_t size; | 499 | size_t size; |
| 501 | MSize len; | 500 | MSize len; |
| 502 | if (shortcut && (str = lj_strfmt_wstrnum(buf, o, &len)) != NULL) { | 501 | if (shortcut && (str = lj_strfmt_wstrnum(L, o, &len)) != NULL) { |
| 503 | size = len; | 502 | size = len; |
| 504 | } else { | 503 | } else { |
| 505 | copyTV(L, L->top+1, o); | 504 | copyTV(L, L->top+1, o); |
diff --git a/src/lib_io.c b/src/lib_io.c index 2aa83474..501de568 100644 --- a/src/lib_io.c +++ b/src/lib_io.c | |||
| @@ -232,9 +232,8 @@ static int io_file_write(lua_State *L, FILE *fp, int start) | |||
| 232 | cTValue *tv; | 232 | cTValue *tv; |
| 233 | int status = 1; | 233 | int status = 1; |
| 234 | for (tv = L->base+start; tv < L->top; tv++) { | 234 | for (tv = L->base+start; tv < L->top; tv++) { |
| 235 | char buf[STRFMT_MAXBUF_NUM]; | ||
| 236 | MSize len; | 235 | MSize len; |
| 237 | const char *p = lj_strfmt_wstrnum(buf, tv, &len); | 236 | const char *p = lj_strfmt_wstrnum(L, tv, &len); |
| 238 | if (!p) | 237 | if (!p) |
| 239 | lj_err_argt(L, (int)(tv - L->base) + 1, LUA_TSTRING); | 238 | lj_err_argt(L, (int)(tv - L->base) + 1, LUA_TSTRING); |
| 240 | status = status && (fwrite(p, 1, len, fp) == len); | 239 | status = status && (fwrite(p, 1, len, fp) == len); |
diff --git a/src/lj_buf.c b/src/lj_buf.c index 023bb9aa..7b6c2188 100644 --- a/src/lj_buf.c +++ b/src/lj_buf.c | |||
| @@ -186,7 +186,7 @@ SBuf *lj_buf_puttab(SBuf *sb, GCtab *t, GCstr *sep, int32_t i, int32_t e) | |||
| 186 | } else if (tvisint(o)) { | 186 | } else if (tvisint(o)) { |
| 187 | p = lj_strfmt_wint(lj_buf_more(sb, STRFMT_MAXBUF_INT+seplen), intV(o)); | 187 | p = lj_strfmt_wint(lj_buf_more(sb, STRFMT_MAXBUF_INT+seplen), intV(o)); |
| 188 | } else if (tvisnum(o)) { | 188 | } else if (tvisnum(o)) { |
| 189 | p = lj_strfmt_wnum(lj_buf_more(sb, STRFMT_MAXBUF_NUM+seplen), o); | 189 | p = lj_buf_more(lj_strfmt_putfnum(sb, STRFMT_G14, numV(o)), seplen); |
| 190 | } else { | 190 | } else { |
| 191 | goto badtype; | 191 | goto badtype; |
| 192 | } | 192 | } |
diff --git a/src/lj_ctype.c b/src/lj_ctype.c index eda070ce..94159462 100644 --- a/src/lj_ctype.c +++ b/src/lj_ctype.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "lj_strfmt.h" | 14 | #include "lj_strfmt.h" |
| 15 | #include "lj_ctype.h" | 15 | #include "lj_ctype.h" |
| 16 | #include "lj_ccallback.h" | 16 | #include "lj_ccallback.h" |
| 17 | #include "lj_buf.h" | ||
| 17 | 18 | ||
| 18 | /* -- C type definitions -------------------------------------------------- */ | 19 | /* -- C type definitions -------------------------------------------------- */ |
| 19 | 20 | ||
| @@ -571,19 +572,18 @@ GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned) | |||
| 571 | /* Convert complex to string with 'i' or 'I' suffix. */ | 572 | /* Convert complex to string with 'i' or 'I' suffix. */ |
| 572 | GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size) | 573 | GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size) |
| 573 | { | 574 | { |
| 574 | char buf[2*STRFMT_MAXBUF_NUM+2+1], *p = buf; | 575 | SBuf *sb = lj_buf_tmp_(L); |
| 575 | TValue re, im; | 576 | TValue re, im; |
| 576 | if (size == 2*sizeof(double)) { | 577 | if (size == 2*sizeof(double)) { |
| 577 | re.n = *(double *)sp; im.n = ((double *)sp)[1]; | 578 | re.n = *(double *)sp; im.n = ((double *)sp)[1]; |
| 578 | } else { | 579 | } else { |
| 579 | re.n = (double)*(float *)sp; im.n = (double)((float *)sp)[1]; | 580 | re.n = (double)*(float *)sp; im.n = (double)((float *)sp)[1]; |
| 580 | } | 581 | } |
| 581 | p = lj_strfmt_wnum(p, &re); | 582 | lj_strfmt_putfnum(sb, STRFMT_G14, re.n); |
| 582 | if (!(im.u32.hi & 0x80000000u) || im.n != im.n) *p++ = '+'; | 583 | if (!(im.u32.hi & 0x80000000u) || im.n != im.n) lj_buf_putchar(sb, '+'); |
| 583 | p = lj_strfmt_wnum(p, &im); | 584 | lj_strfmt_putfnum(sb, STRFMT_G14, im.n); |
| 584 | *p = *(p-1) >= 'a' ? 'I' : 'i'; | 585 | lj_buf_putchar(sb, sbufP(sb)[-1] >= 'a' ? 'I' : 'i'); |
| 585 | p++; | 586 | return lj_buf_str(L, sb); |
| 586 | return lj_str_new(L, buf, p-buf); | ||
| 587 | } | 587 | } |
| 588 | 588 | ||
| 589 | /* -- C type state -------------------------------------------------------- */ | 589 | /* -- C type state -------------------------------------------------------- */ |
diff --git a/src/lj_meta.c b/src/lj_meta.c index 104ecf07..de229571 100644 --- a/src/lj_meta.c +++ b/src/lj_meta.c | |||
| @@ -278,25 +278,25 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left) | |||
| 278 | */ | 278 | */ |
| 279 | TValue *e, *o = top; | 279 | TValue *e, *o = top; |
| 280 | uint64_t tlen = tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM; | 280 | uint64_t tlen = tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM; |
| 281 | char *p, *buf; | 281 | SBuf *sb; |
| 282 | do { | 282 | do { |
| 283 | o--; tlen += tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM; | 283 | o--; tlen += tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM; |
| 284 | } while (--left > 0 && (tvisstr(o-1) || tvisnumber(o-1))); | 284 | } while (--left > 0 && (tvisstr(o-1) || tvisnumber(o-1))); |
| 285 | if (tlen >= LJ_MAX_STR) lj_err_msg(L, LJ_ERR_STROV); | 285 | if (tlen >= LJ_MAX_STR) lj_err_msg(L, LJ_ERR_STROV); |
| 286 | p = buf = lj_buf_tmp(L, (MSize)tlen); | 286 | sb = lj_buf_tmp_(L); |
| 287 | lj_buf_more(sb, (MSize)tlen); | ||
| 287 | for (e = top, top = o; o <= e; o++) { | 288 | for (e = top, top = o; o <= e; o++) { |
| 288 | if (tvisstr(o)) { | 289 | if (tvisstr(o)) { |
| 289 | GCstr *s = strV(o); | 290 | GCstr *s = strV(o); |
| 290 | MSize len = s->len; | 291 | MSize len = s->len; |
| 291 | p = lj_buf_wmem(p, strdata(s), len); | 292 | lj_buf_putmem(sb, strdata(s), len); |
| 292 | } else if (tvisint(o)) { | 293 | } else if (tvisint(o)) { |
| 293 | p = lj_strfmt_wint(p, intV(o)); | 294 | lj_strfmt_putint(sb, intV(o)); |
| 294 | } else { | 295 | } else { |
| 295 | lua_assert(tvisnum(o)); | 296 | lj_strfmt_putfnum(sb, STRFMT_G14, numV(o)); |
| 296 | p = lj_strfmt_wnum(p, o); | ||
| 297 | } | 297 | } |
| 298 | } | 298 | } |
| 299 | setstrV(L, top, lj_str_new(L, buf, (size_t)(p-buf))); | 299 | setstrV(L, top, lj_buf_str(L, sb)); |
| 300 | } | 300 | } |
| 301 | } while (left >= 1); | 301 | } while (left >= 1); |
| 302 | if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) { | 302 | if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) { |
diff --git a/src/lj_strfmt.c b/src/lj_strfmt.c index d54e796a..ba9e1ff8 100644 --- a/src/lj_strfmt.c +++ b/src/lj_strfmt.c | |||
| @@ -18,7 +18,7 @@ | |||
| 18 | /* -- Format parser ------------------------------------------------------- */ | 18 | /* -- Format parser ------------------------------------------------------- */ |
| 19 | 19 | ||
| 20 | static const uint8_t strfmt_map[('x'-'A')+1] = { | 20 | static const uint8_t strfmt_map[('x'-'A')+1] = { |
| 21 | STRFMT_A,0,0,0,STRFMT_E,0,STRFMT_G,0,0,0,0,0,0, | 21 | STRFMT_A,0,0,0,STRFMT_E,STRFMT_F,STRFMT_G,0,0,0,0,0,0, |
| 22 | 0,0,0,0,0,0,0,0,0,0,STRFMT_X,0,0, | 22 | 0,0,0,0,0,0,0,0,0,0,STRFMT_X,0,0, |
| 23 | 0,0,0,0,0,0, | 23 | 0,0,0,0,0,0, |
| 24 | STRFMT_A,0,STRFMT_C,STRFMT_D,STRFMT_E,STRFMT_F,STRFMT_G,0,STRFMT_I,0,0,0,0, | 24 | STRFMT_A,0,STRFMT_C,STRFMT_D,STRFMT_E,STRFMT_F,STRFMT_G,0,STRFMT_I,0,0,0,0, |
| @@ -89,24 +89,6 @@ retlit: | |||
| 89 | 89 | ||
| 90 | /* -- Raw conversions ----------------------------------------------------- */ | 90 | /* -- Raw conversions ----------------------------------------------------- */ |
| 91 | 91 | ||
| 92 | /* Write number to bufer. */ | ||
| 93 | char * LJ_FASTCALL lj_strfmt_wnum(char *p, cTValue *o) | ||
| 94 | { | ||
| 95 | if (LJ_LIKELY((o->u32.hi << 1) < 0xffe00000)) { /* Finite? */ | ||
| 96 | #if __BIONIC__ | ||
| 97 | if (tvismzero(o)) { *p++ = '-'; *p++ = '0'; return p; } | ||
| 98 | #endif | ||
| 99 | return p + lua_number2str(p, o->n); | ||
| 100 | } else if (((o->u32.hi & 0x000fffff) | o->u32.lo) != 0) { | ||
| 101 | *p++ = 'n'; *p++ = 'a'; *p++ = 'n'; | ||
| 102 | } else if ((o->u32.hi & 0x80000000) == 0) { | ||
| 103 | *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; | ||
| 104 | } else { | ||
| 105 | *p++ = '-'; *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; | ||
| 106 | } | ||
| 107 | return p; | ||
| 108 | } | ||
| 109 | |||
| 110 | #define WINT_R(x, sh, sc) \ | 92 | #define WINT_R(x, sh, sc) \ |
| 111 | { uint32_t d = (x*(((1<<sh)+sc-1)/sc))>>sh; x -= d*sc; *p++ = (char)('0'+d); } | 93 | { uint32_t d = (x*(((1<<sh)+sc-1)/sc))>>sh; x -= d*sc; *p++ = (char)('0'+d); } |
| 112 | 94 | ||
| @@ -168,21 +150,22 @@ char * LJ_FASTCALL lj_strfmt_wuleb128(char *p, uint32_t v) | |||
| 168 | return p; | 150 | return p; |
| 169 | } | 151 | } |
| 170 | 152 | ||
| 171 | /* Return string or write number to buffer and return pointer to start. */ | 153 | /* Return string or write number to tmp buffer and return pointer to start. */ |
| 172 | const char *lj_strfmt_wstrnum(char *buf, cTValue *o, MSize *lenp) | 154 | const char *lj_strfmt_wstrnum(lua_State *L, cTValue *o, MSize *lenp) |
| 173 | { | 155 | { |
| 156 | SBuf *sb; | ||
| 174 | if (tvisstr(o)) { | 157 | if (tvisstr(o)) { |
| 175 | *lenp = strV(o)->len; | 158 | *lenp = strV(o)->len; |
| 176 | return strVdata(o); | 159 | return strVdata(o); |
| 177 | } else if (tvisint(o)) { | 160 | } else if (tvisint(o)) { |
| 178 | *lenp = (MSize)(lj_strfmt_wint(buf, intV(o)) - buf); | 161 | sb = lj_strfmt_putint(lj_buf_tmp_(L), intV(o)); |
| 179 | return buf; | ||
| 180 | } else if (tvisnum(o)) { | 162 | } else if (tvisnum(o)) { |
| 181 | *lenp = (MSize)(lj_strfmt_wnum(buf, o) - buf); | 163 | sb = lj_strfmt_putfnum(lj_buf_tmp_(L), STRFMT_G14, o->n); |
| 182 | return buf; | ||
| 183 | } else { | 164 | } else { |
| 184 | return NULL; | 165 | return NULL; |
| 185 | } | 166 | } |
| 167 | *lenp = sbuflen(sb); | ||
| 168 | return sbufB(sb); | ||
| 186 | } | 169 | } |
| 187 | 170 | ||
| 188 | /* -- Unformatted conversions to buffer ----------------------------------- */ | 171 | /* -- Unformatted conversions to buffer ----------------------------------- */ |
| @@ -198,8 +181,7 @@ SBuf * LJ_FASTCALL lj_strfmt_putint(SBuf *sb, int32_t k) | |||
| 198 | /* Add number to buffer. */ | 181 | /* Add number to buffer. */ |
| 199 | SBuf * LJ_FASTCALL lj_strfmt_putnum(SBuf *sb, cTValue *o) | 182 | SBuf * LJ_FASTCALL lj_strfmt_putnum(SBuf *sb, cTValue *o) |
| 200 | { | 183 | { |
| 201 | setsbufP(sb, lj_strfmt_wnum(lj_buf_more(sb, STRFMT_MAXBUF_NUM), o)); | 184 | return lj_strfmt_putfnum(sb, STRFMT_G14, o->n); |
| 202 | return sb; | ||
| 203 | } | 185 | } |
| 204 | #endif | 186 | #endif |
| 205 | 187 | ||
| @@ -360,63 +342,6 @@ SBuf *lj_strfmt_putfnum_uint(SBuf *sb, SFormat sf, lua_Number n) | |||
| 360 | return lj_strfmt_putfxint(sb, sf, (uint64_t)k); | 342 | return lj_strfmt_putfxint(sb, sf, (uint64_t)k); |
| 361 | } | 343 | } |
| 362 | 344 | ||
| 363 | /* Max. sprintf buffer size needed. At least #string.format("%.99f", -1e308). */ | ||
| 364 | #define STRFMT_FMTNUMBUF 512 | ||
| 365 | |||
| 366 | /* Add formatted floating-point number to buffer. */ | ||
| 367 | SBuf *lj_strfmt_putfnum(SBuf *sb, SFormat sf, lua_Number n) | ||
| 368 | { | ||
| 369 | TValue tv; | ||
| 370 | tv.n = n; | ||
| 371 | if (LJ_UNLIKELY((tv.u32.hi << 1) >= 0xffe00000)) { | ||
| 372 | /* Canonicalize output of non-finite values. */ | ||
| 373 | MSize width = STRFMT_WIDTH(sf), len = 3; | ||
| 374 | int prefix = 0, ch = (sf & STRFMT_F_UPPER) ? 0x202020 : 0; | ||
| 375 | char *p; | ||
| 376 | if (((tv.u32.hi & 0x000fffff) | tv.u32.lo) != 0) { | ||
| 377 | ch ^= ('n' << 16) | ('a' << 8) | 'n'; | ||
| 378 | if ((sf & STRFMT_F_SPACE)) prefix = ' '; | ||
| 379 | } else { | ||
| 380 | ch ^= ('i' << 16) | ('n' << 8) | 'f'; | ||
| 381 | if ((tv.u32.hi & 0x80000000)) prefix = '-'; | ||
| 382 | else if ((sf & STRFMT_F_PLUS)) prefix = '+'; | ||
| 383 | else if ((sf & STRFMT_F_SPACE)) prefix = ' '; | ||
| 384 | } | ||
| 385 | if (prefix) len = 4; | ||
| 386 | p = lj_buf_more(sb, width > len ? width : len); | ||
| 387 | if (!(sf & STRFMT_F_LEFT)) while (width-- > len) *p++ = ' '; | ||
| 388 | if (prefix) *p++ = prefix; | ||
| 389 | *p++ = (char)(ch >> 16); *p++ = (char)(ch >> 8); *p++ = (char)ch; | ||
| 390 | if ((sf & STRFMT_F_LEFT)) while (width-- > len) *p++ = ' '; | ||
| 391 | setsbufP(sb, p); | ||
| 392 | } else { /* Delegate to sprintf() for now. */ | ||
| 393 | uint8_t width = (uint8_t)STRFMT_WIDTH(sf), prec = (uint8_t)STRFMT_PREC(sf); | ||
| 394 | char fmt[1+5+2+3+1+1], *p = fmt; | ||
| 395 | *p++ = '%'; | ||
| 396 | if ((sf & STRFMT_F_LEFT)) *p++ = '-'; | ||
| 397 | if ((sf & STRFMT_F_PLUS)) *p++ = '+'; | ||
| 398 | if ((sf & STRFMT_F_ZERO)) *p++ = '0'; | ||
| 399 | if ((sf & STRFMT_F_SPACE)) *p++ = ' '; | ||
| 400 | if ((sf & STRFMT_F_ALT)) *p++ = '#'; | ||
| 401 | if (width) { | ||
| 402 | uint8_t x = width / 10, y = width % 10; | ||
| 403 | if (x) *p++ = '0' + x; | ||
| 404 | *p++ = '0' + y; | ||
| 405 | } | ||
| 406 | if (prec != 255) { | ||
| 407 | uint8_t x = prec / 10, y = prec % 10; | ||
| 408 | *p++ = '.'; | ||
| 409 | if (x) *p++ = '0' + x; | ||
| 410 | *p++ = '0' + y; | ||
| 411 | } | ||
| 412 | *p++ = (0x67666561 >> (STRFMT_FP(sf)<<3)) ^ ((sf & STRFMT_F_UPPER)?0x20:0); | ||
| 413 | *p = '\0'; | ||
| 414 | p = lj_buf_more(sb, STRFMT_FMTNUMBUF); | ||
| 415 | setsbufP(sb, p + sprintf(p, fmt, n)); | ||
| 416 | } | ||
| 417 | return sb; | ||
| 418 | } | ||
| 419 | |||
| 420 | /* -- Conversions to strings ---------------------------------------------- */ | 345 | /* -- Conversions to strings ---------------------------------------------- */ |
| 421 | 346 | ||
| 422 | /* Convert integer to string. */ | 347 | /* Convert integer to string. */ |
| @@ -427,14 +352,6 @@ GCstr * LJ_FASTCALL lj_strfmt_int(lua_State *L, int32_t k) | |||
| 427 | return lj_str_new(L, buf, len); | 352 | return lj_str_new(L, buf, len); |
| 428 | } | 353 | } |
| 429 | 354 | ||
| 430 | /* Convert number to string. */ | ||
| 431 | GCstr * LJ_FASTCALL lj_strfmt_num(lua_State *L, cTValue *o) | ||
| 432 | { | ||
| 433 | char buf[STRFMT_MAXBUF_NUM]; | ||
| 434 | MSize len = (MSize)(lj_strfmt_wnum(buf, o) - buf); | ||
| 435 | return lj_str_new(L, buf, len); | ||
| 436 | } | ||
| 437 | |||
| 438 | /* Convert integer or number to string. */ | 355 | /* Convert integer or number to string. */ |
| 439 | GCstr * LJ_FASTCALL lj_strfmt_number(lua_State *L, cTValue *o) | 356 | GCstr * LJ_FASTCALL lj_strfmt_number(lua_State *L, cTValue *o) |
| 440 | { | 357 | { |
| @@ -510,12 +427,9 @@ const char *lj_strfmt_pushvf(lua_State *L, const char *fmt, va_list argp) | |||
| 510 | case STRFMT_UINT: | 427 | case STRFMT_UINT: |
| 511 | lj_strfmt_putfxint(sb, sf, va_arg(argp, uint32_t)); | 428 | lj_strfmt_putfxint(sb, sf, va_arg(argp, uint32_t)); |
| 512 | break; | 429 | break; |
| 513 | case STRFMT_NUM: { | 430 | case STRFMT_NUM: |
| 514 | TValue tv; | 431 | lj_strfmt_putfnum(sb, STRFMT_G14, va_arg(argp, lua_Number)); |
| 515 | tv.n = va_arg(argp, lua_Number); | ||
| 516 | setsbufP(sb, lj_strfmt_wnum(lj_buf_more(sb, STRFMT_MAXBUF_NUM), &tv)); | ||
| 517 | break; | 432 | break; |
| 518 | } | ||
| 519 | case STRFMT_STR: { | 433 | case STRFMT_STR: { |
| 520 | const char *s = va_arg(argp, char *); | 434 | const char *s = va_arg(argp, char *); |
| 521 | if (s == NULL) s = "(null)"; | 435 | if (s == NULL) s = "(null)"; |
diff --git a/src/lj_strfmt.h b/src/lj_strfmt.h index dcfaf2e3..f229f25c 100644 --- a/src/lj_strfmt.h +++ b/src/lj_strfmt.h | |||
| @@ -64,11 +64,12 @@ typedef enum FormatType { | |||
| 64 | #define STRFMT_S (STRFMT_STR) | 64 | #define STRFMT_S (STRFMT_STR) |
| 65 | #define STRFMT_U (STRFMT_UINT) | 65 | #define STRFMT_U (STRFMT_UINT) |
| 66 | #define STRFMT_X (STRFMT_UINT|STRFMT_T_HEX) | 66 | #define STRFMT_X (STRFMT_UINT|STRFMT_T_HEX) |
| 67 | #define STRFMT_G14 (STRFMT_G | ((14+1) << STRFMT_SH_PREC)) | ||
| 67 | 68 | ||
| 68 | /* Maximum buffer sizes for conversions. */ | 69 | /* Maximum buffer sizes for conversions. */ |
| 69 | #define STRFMT_MAXBUF_XINT (1+22) /* '0' prefix + uint64_t in octal. */ | 70 | #define STRFMT_MAXBUF_XINT (1+22) /* '0' prefix + uint64_t in octal. */ |
| 70 | #define STRFMT_MAXBUF_INT (1+10) /* Sign + int32_t in decimal. */ | 71 | #define STRFMT_MAXBUF_INT (1+10) /* Sign + int32_t in decimal. */ |
| 71 | #define STRFMT_MAXBUF_NUM LUAI_MAXNUMBER2STR | 72 | #define STRFMT_MAXBUF_NUM 32 /* Must correspond with STRFMT_G14. */ |
| 72 | #define STRFMT_MAXBUF_PTR (2+2*sizeof(ptrdiff_t)) /* "0x" + hex ptr. */ | 73 | #define STRFMT_MAXBUF_PTR (2+2*sizeof(ptrdiff_t)) /* "0x" + hex ptr. */ |
| 73 | 74 | ||
| 74 | /* Format parser. */ | 75 | /* Format parser. */ |
| @@ -83,10 +84,9 @@ static LJ_AINLINE void lj_strfmt_init(FormatState *fs, const char *p, MSize len) | |||
| 83 | 84 | ||
| 84 | /* Raw conversions. */ | 85 | /* Raw conversions. */ |
| 85 | LJ_FUNC char * LJ_FASTCALL lj_strfmt_wint(char *p, int32_t k); | 86 | LJ_FUNC char * LJ_FASTCALL lj_strfmt_wint(char *p, int32_t k); |
| 86 | LJ_FUNC char * LJ_FASTCALL lj_strfmt_wnum(char *p, cTValue *o); | ||
| 87 | LJ_FUNC char * LJ_FASTCALL lj_strfmt_wptr(char *p, const void *v); | 87 | LJ_FUNC char * LJ_FASTCALL lj_strfmt_wptr(char *p, const void *v); |
| 88 | LJ_FUNC char * LJ_FASTCALL lj_strfmt_wuleb128(char *p, uint32_t v); | 88 | LJ_FUNC char * LJ_FASTCALL lj_strfmt_wuleb128(char *p, uint32_t v); |
| 89 | LJ_FUNC const char *lj_strfmt_wstrnum(char *buf, cTValue *o, MSize *lenp); | 89 | LJ_FUNC const char *lj_strfmt_wstrnum(lua_State *L, cTValue *o, MSize *lenp); |
| 90 | 90 | ||
| 91 | /* Unformatted conversions to buffer. */ | 91 | /* Unformatted conversions to buffer. */ |
| 92 | LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putint(SBuf *sb, int32_t k); | 92 | LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putint(SBuf *sb, int32_t k); |
diff --git a/src/lj_strfmt_num.c b/src/lj_strfmt_num.c new file mode 100644 index 00000000..577795e0 --- /dev/null +++ b/src/lj_strfmt_num.c | |||
| @@ -0,0 +1,591 @@ | |||
| 1 | /* | ||
| 2 | ** String formatting for floating-point numbers. | ||
| 3 | ** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h | ||
| 4 | ** Contributed by Peter Cawley. | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <stdio.h> | ||
| 8 | |||
| 9 | #define lj_strfmt_num_c | ||
| 10 | #define LUA_CORE | ||
| 11 | |||
| 12 | #include "lj_obj.h" | ||
| 13 | #include "lj_buf.h" | ||
| 14 | #include "lj_str.h" | ||
| 15 | #include "lj_strfmt.h" | ||
| 16 | |||
| 17 | /* -- Precomputed tables -------------------------------------------------- */ | ||
| 18 | |||
| 19 | /* Rescale factors to push the exponent of a number towards zero. */ | ||
| 20 | #define RESCALE_EXPONENTS(P, N) \ | ||
| 21 | P(308), P(289), P(270), P(250), P(231), P(212), P(193), P(173), P(154), \ | ||
| 22 | P(135), P(115), P(96), P(77), P(58), P(38), P(0), P(0), P(0), N(39), N(58), \ | ||
| 23 | N(77), N(96), N(116), N(135), N(154), N(174), N(193), N(212), N(231), \ | ||
| 24 | N(251), N(270), N(289) | ||
| 25 | |||
| 26 | #define ONE_E_P(X) 1e+0 ## X | ||
| 27 | #define ONE_E_N(X) 1e-0 ## X | ||
| 28 | static const int16_t rescale_e[] = { RESCALE_EXPONENTS(-, +) }; | ||
| 29 | static const double rescale_n[] = { RESCALE_EXPONENTS(ONE_E_P, ONE_E_N) }; | ||
| 30 | #undef ONE_E_N | ||
| 31 | #undef ONE_E_P | ||
| 32 | |||
| 33 | /* | ||
| 34 | ** For p in range -70 through 57, this table encodes pairs (m, e) such that | ||
| 35 | ** 4*2^p <= (uint8_t)m*10^e, and is the smallest value for which this holds. | ||
| 36 | */ | ||
| 37 | static const int8_t four_ulp_m_e[] = { | ||
| 38 | 34, -21, 68, -21, 14, -20, 28, -20, 55, -20, 2, -19, 3, -19, 5, -19, 9, -19, | ||
| 39 | -82, -18, 35, -18, 7, -17, -117, -17, 28, -17, 56, -17, 112, -16, -33, -16, | ||
| 40 | 45, -16, 89, -16, -78, -15, 36, -15, 72, -15, -113, -14, 29, -14, 57, -14, | ||
| 41 | 114, -13, -28, -13, 46, -13, 91, -12, -74, -12, 37, -12, 73, -12, 15, -11, 3, | ||
| 42 | -11, 59, -11, 2, -10, 3, -10, 5, -10, 1, -9, -69, -9, 38, -9, 75, -9, 15, -7, | ||
| 43 | 3, -7, 6, -7, 12, -6, -17, -7, 48, -7, 96, -7, -65, -6, 39, -6, 77, -6, -103, | ||
| 44 | -5, 31, -5, 62, -5, 123, -4, -11, -4, 49, -4, 98, -4, -60, -3, 4, -2, 79, -3, | ||
| 45 | 16, -2, 32, -2, 63, -2, 2, -1, 25, 0, 5, 1, 1, 2, 2, 2, 4, 2, 8, 2, 16, 2, | ||
| 46 | 32, 2, 64, 2, -128, 2, 26, 2, 52, 2, 103, 3, -51, 3, 41, 4, 82, 4, -92, 4, | ||
| 47 | 33, 4, 66, 4, -124, 5, 27, 5, 53, 5, 105, 6, 21, 6, 42, 6, 84, 6, 17, 7, 34, | ||
| 48 | 7, 68, 7, 2, 8, 3, 8, 6, 8, 108, 9, -41, 9, 43, 10, 86, 9, -84, 10, 35, 10, | ||
| 49 | 69, 10, -118, 11, 28, 11, 55, 12, 11, 13, 22, 13, 44, 13, 88, 13, -80, 13, | ||
| 50 | 36, 13, 71, 13, -115, 14, 29, 14, 57, 14, 113, 15, -30, 15, 46, 15, 91, 15, | ||
| 51 | 19, 16, 37, 16, 73, 16, 2, 17, 3, 17, 6, 17 | ||
| 52 | }; | ||
| 53 | |||
| 54 | /* min(2^32-1, 10^e-1) for e in range 0 through 10 */ | ||
| 55 | static uint32_t ndigits_dec_threshold[] = { | ||
| 56 | 0, 9U, 99U, 999U, 9999U, 99999U, 999999U, | ||
| 57 | 9999999U, 99999999U, 999999999U, 0xffffffffU | ||
| 58 | }; | ||
| 59 | |||
| 60 | /* -- Helper functions ---------------------------------------------------- */ | ||
| 61 | |||
| 62 | /* Compute the number of digits in the decimal representation of x. */ | ||
| 63 | static MSize ndigits_dec(uint32_t x) | ||
| 64 | { | ||
| 65 | MSize t = ((lj_fls(x | 1) * 77) >> 8) + 1; /* 2^8/77 is roughly log2(10) */ | ||
| 66 | return t + (x > ndigits_dec_threshold[t]); | ||
| 67 | } | ||
| 68 | |||
| 69 | #define WINT_R(x, sh, sc) \ | ||
| 70 | { uint32_t d = (x*(((1<<sh)+sc-1)/sc))>>sh; x -= d*sc; *p++ = (char)('0'+d); } | ||
| 71 | |||
| 72 | /* Write 9-digit unsigned integer to buffer. */ | ||
| 73 | static char *lj_strfmt_wuint9(char *p, uint32_t u) | ||
| 74 | { | ||
| 75 | uint32_t v = u / 10000, w; | ||
| 76 | u -= v * 10000; | ||
| 77 | w = v / 10000; | ||
| 78 | v -= w * 10000; | ||
| 79 | *p++ = (char)('0'+w); | ||
| 80 | WINT_R(v, 23, 1000) | ||
| 81 | WINT_R(v, 12, 100) | ||
| 82 | WINT_R(v, 10, 10) | ||
| 83 | *p++ = (char)('0'+v); | ||
| 84 | WINT_R(u, 23, 1000) | ||
| 85 | WINT_R(u, 12, 100) | ||
| 86 | WINT_R(u, 10, 10) | ||
| 87 | *p++ = (char)('0'+u); | ||
| 88 | return p; | ||
| 89 | } | ||
| 90 | #undef WINT_R | ||
| 91 | |||
| 92 | /* -- Extended precision arithmetic --------------------------------------- */ | ||
| 93 | |||
| 94 | /* | ||
| 95 | ** The "nd" format is a fixed-precision decimal representation for numbers. It | ||
| 96 | ** consists of up to 64 uint32_t values, with each uint32_t storing a value | ||
| 97 | ** in the range [0, 1e9). A number in "nd" format consists of three variables: | ||
| 98 | ** | ||
| 99 | ** uint32_t nd[64]; | ||
| 100 | ** uint32_t ndlo; | ||
| 101 | ** uint32_t ndhi; | ||
| 102 | ** | ||
| 103 | ** The integral part of the number is stored in nd[0 ... ndhi], the value of | ||
| 104 | ** which is sum{i in [0, ndhi] | nd[i] * 10^(9*i)}. If the fractional part of | ||
| 105 | ** the number is zero, ndlo is zero. Otherwise, the fractional part is stored | ||
| 106 | ** in nd[ndlo ... 63], the value of which is taken to be | ||
| 107 | ** sum{i in [ndlo, 63] | nd[i] * 10^(9*(i-64))}. | ||
| 108 | ** | ||
| 109 | ** If the array part had 128 elements rather than 64, then every double would | ||
| 110 | ** have an exact representation in "nd" format. With 64 elements, all integral | ||
| 111 | ** doubles have an exact representation, and all non-integral doubles have | ||
| 112 | ** enough digits to make both %.99e and %.99f do the right thing. | ||
| 113 | */ | ||
| 114 | |||
| 115 | #if LJ_64 | ||
| 116 | #define ND_MUL2K_MAX_SHIFT 29 | ||
| 117 | #define ND_MUL2K_DIV1E9(val) ((uint32_t)((val) / 1000000000)) | ||
| 118 | #else | ||
| 119 | #define ND_MUL2K_MAX_SHIFT 11 | ||
| 120 | #define ND_MUL2K_DIV1E9(val) ((uint32_t)((val) >> 9) / 1953125) | ||
| 121 | #endif | ||
| 122 | |||
| 123 | /* Multiply nd by 2^k and add carry_in (ndlo is assumed to be zero). */ | ||
| 124 | static uint32_t nd_mul2k(uint32_t* nd, uint32_t ndhi, uint32_t k, | ||
| 125 | uint32_t carry_in, SFormat sf) | ||
| 126 | { | ||
| 127 | uint32_t i, ndlo = 0, start = 1; | ||
| 128 | /* Performance hacks. */ | ||
| 129 | if (k > ND_MUL2K_MAX_SHIFT*2 && STRFMT_FP(sf) != STRFMT_FP(STRFMT_T_FP_F)) { | ||
| 130 | start = ndhi - (STRFMT_PREC(sf) + 17) / 8; | ||
| 131 | } | ||
| 132 | /* Real logic. */ | ||
| 133 | while (k >= ND_MUL2K_MAX_SHIFT) { | ||
| 134 | for (i = ndlo; i <= ndhi; i++) { | ||
| 135 | uint64_t val = ((uint64_t)nd[i] << ND_MUL2K_MAX_SHIFT) | carry_in; | ||
| 136 | carry_in = ND_MUL2K_DIV1E9(val); | ||
| 137 | nd[i] = (uint32_t)val - carry_in * 1000000000; | ||
| 138 | } | ||
| 139 | if (carry_in) { | ||
| 140 | nd[++ndhi] = carry_in; carry_in = 0; | ||
| 141 | if(start++ == ndlo) ++ndlo; | ||
| 142 | } | ||
| 143 | k -= ND_MUL2K_MAX_SHIFT; | ||
| 144 | } | ||
| 145 | if (k) { | ||
| 146 | for (i = ndlo; i <= ndhi; i++) { | ||
| 147 | uint64_t val = ((uint64_t)nd[i] << k) | carry_in; | ||
| 148 | carry_in = ND_MUL2K_DIV1E9(val); | ||
| 149 | nd[i] = (uint32_t)val - carry_in * 1000000000; | ||
| 150 | } | ||
| 151 | if (carry_in) nd[++ndhi] = carry_in; | ||
| 152 | } | ||
| 153 | return ndhi; | ||
| 154 | } | ||
| 155 | |||
| 156 | /* Divide nd by 2^k (ndlo is assumed to be zero). */ | ||
| 157 | static uint32_t nd_div2k(uint32_t* nd, uint32_t ndhi, uint32_t k, SFormat sf) | ||
| 158 | { | ||
| 159 | uint32_t ndlo = 0, stop1 = ~0, stop2 = ~0; | ||
| 160 | /* Performance hacks. */ | ||
| 161 | if (!ndhi) { | ||
| 162 | if (!nd[0]) { | ||
| 163 | return 0; | ||
| 164 | } else { | ||
| 165 | uint32_t s = lj_ffs(nd[0]); | ||
| 166 | if (s >= k) { nd[0] >>= k; return 0; } | ||
| 167 | nd[0] >>= s; k -= s; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | if (k > 18) { | ||
| 171 | if (STRFMT_FP(sf) == STRFMT_FP(STRFMT_T_FP_F)) { | ||
| 172 | stop1 = 63 - (int32_t)STRFMT_PREC(sf) / 9; | ||
| 173 | } else { | ||
| 174 | int32_t floorlog2 = ndhi * 29 + lj_fls(nd[ndhi]) - k; | ||
| 175 | int32_t floorlog10 = (int32_t)(floorlog2 * 0.30102999566398114); | ||
| 176 | stop1 = 62 + (floorlog10 - (int32_t)STRFMT_PREC(sf)) / 9; | ||
| 177 | stop2 = 61 + ndhi - (int32_t)STRFMT_PREC(sf) / 8; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | /* Real logic. */ | ||
| 181 | while (k >= 9) { | ||
| 182 | uint32_t i = ndhi, carry = 0; | ||
| 183 | for (;;) { | ||
| 184 | uint32_t val = nd[i]; | ||
| 185 | nd[i] = (val >> 9) + carry; | ||
| 186 | carry = (val & 0x1ff) * 1953125; | ||
| 187 | if (i == ndlo) break; | ||
| 188 | i = (i - 1) & 0x3f; | ||
| 189 | } | ||
| 190 | if (ndlo != stop1 && ndlo != stop2) { | ||
| 191 | if (carry) { ndlo = (ndlo - 1) & 0x3f; nd[ndlo] = carry; } | ||
| 192 | if (!nd[ndhi]) { ndhi = (ndhi - 1) & 0x3f; stop2--; } | ||
| 193 | } else if (!nd[ndhi]) { | ||
| 194 | if (ndhi != ndlo) { ndhi = (ndhi - 1) & 0x3f; stop2--; } | ||
| 195 | else return ndlo; | ||
| 196 | } | ||
| 197 | k -= 9; | ||
| 198 | } | ||
| 199 | if (k) { | ||
| 200 | uint32_t mask = (1U << k) - 1, mul = 1000000000 >> k, i = ndhi, carry = 0; | ||
| 201 | for (;;) { | ||
| 202 | uint32_t val = nd[i]; | ||
| 203 | nd[i] = (val >> k) + carry; | ||
| 204 | carry = (val & mask) * mul; | ||
| 205 | if (i == ndlo) break; | ||
| 206 | i = (i - 1) & 0x3f; | ||
| 207 | } | ||
| 208 | if (carry) { ndlo = (ndlo - 1) & 0x3f; nd[ndlo] = carry; } | ||
| 209 | } | ||
| 210 | return ndlo; | ||
| 211 | } | ||
| 212 | |||
| 213 | /* Add m*10^e to nd (assumes ndlo <= e/9 <= ndhi and 0 <= m <= 9). */ | ||
| 214 | static uint32_t nd_add_m10e(uint32_t* nd, uint32_t ndhi, uint8_t m, int32_t e) | ||
| 215 | { | ||
| 216 | uint32_t i, carry; | ||
| 217 | if (e >= 0) { | ||
| 218 | i = (uint32_t)e/9; | ||
| 219 | carry = m * (ndigits_dec_threshold[e - (int32_t)i*9] + 1); | ||
| 220 | } else { | ||
| 221 | int32_t f = (e-8)/9; | ||
| 222 | i = (uint32_t)(64 + f); | ||
| 223 | carry = m * (ndigits_dec_threshold[e - f*9] + 1); | ||
| 224 | } | ||
| 225 | for (;;) { | ||
| 226 | uint32_t val = nd[i] + carry; | ||
| 227 | if (LJ_UNLIKELY(val >= 1000000000)) { | ||
| 228 | val -= 1000000000; | ||
| 229 | nd[i] = val; | ||
| 230 | if (LJ_UNLIKELY(i == ndhi)) { | ||
| 231 | ndhi = (ndhi + 1) & 0x3f; | ||
| 232 | nd[ndhi] = 1; | ||
| 233 | break; | ||
| 234 | } | ||
| 235 | carry = 1; | ||
| 236 | i = (i + 1) & 0x3f; | ||
| 237 | } else { | ||
| 238 | nd[i] = val; | ||
| 239 | break; | ||
| 240 | } | ||
| 241 | } | ||
| 242 | return ndhi; | ||
| 243 | } | ||
| 244 | |||
| 245 | /* Test whether two "nd" values are equal in their most significant digits. */ | ||
| 246 | static int nd_similar(uint32_t* nd, uint32_t ndhi, uint32_t* ref, MSize hilen, | ||
| 247 | MSize prec) | ||
| 248 | { | ||
| 249 | char nd9[9], ref9[9]; | ||
| 250 | if (hilen <= prec) { | ||
| 251 | if (LJ_UNLIKELY(nd[ndhi] != *ref)) return 0; | ||
| 252 | prec -= hilen; ref--; ndhi = (ndhi - 1) & 0x3f; | ||
| 253 | if (prec >= 9) { | ||
| 254 | if (LJ_UNLIKELY(nd[ndhi] != *ref)) return 0; | ||
| 255 | prec -= 9; ref--; ndhi = (ndhi - 1) & 0x3f; | ||
| 256 | } | ||
| 257 | } else { | ||
| 258 | prec -= hilen - 9; | ||
| 259 | } | ||
| 260 | lua_assert(prec < 9); | ||
| 261 | lj_strfmt_wuint9(nd9, nd[ndhi]); | ||
| 262 | lj_strfmt_wuint9(ref9, *ref); | ||
| 263 | return !memcmp(nd9, ref9, prec) && (nd9[prec] < '5') == (ref9[prec] < '5'); | ||
| 264 | } | ||
| 265 | |||
| 266 | /* -- Formatted conversions to buffer ------------------------------------- */ | ||
| 267 | |||
| 268 | /* Write formatted floating-point number to either sb or p. */ | ||
| 269 | static char *lj_strfmt_wfnum(SBuf *sb, SFormat sf, lua_Number n, char *p) | ||
| 270 | { | ||
| 271 | MSize width = STRFMT_WIDTH(sf), prec = STRFMT_PREC(sf), len; | ||
| 272 | TValue t; | ||
| 273 | t.n = n; | ||
| 274 | if (LJ_UNLIKELY((t.u32.hi << 1) >= 0xffe00000)) { | ||
| 275 | /* Handle non-finite values uniformly for %a, %e, %f, %g. */ | ||
| 276 | int prefix = 0, ch = (sf & STRFMT_F_UPPER) ? 0x202020 : 0; | ||
| 277 | if (((t.u32.hi & 0x000fffff) | t.u32.lo) != 0) { | ||
| 278 | ch ^= ('n' << 16) | ('a' << 8) | 'n'; | ||
| 279 | if ((sf & STRFMT_F_SPACE)) prefix = ' '; | ||
| 280 | } else { | ||
| 281 | ch ^= ('i' << 16) | ('n' << 8) | 'f'; | ||
| 282 | if ((t.u32.hi & 0x80000000)) prefix = '-'; | ||
| 283 | else if ((sf & STRFMT_F_PLUS)) prefix = '+'; | ||
| 284 | else if ((sf & STRFMT_F_SPACE)) prefix = ' '; | ||
| 285 | } | ||
| 286 | len = 3 + (prefix != 0); | ||
| 287 | if (!p) p = lj_buf_more(sb, width > len ? width : len); | ||
| 288 | if (!(sf & STRFMT_F_LEFT)) while (width-- > len) *p++ = ' '; | ||
| 289 | if (prefix) *p++ = prefix; | ||
| 290 | *p++ = (char)(ch >> 16); *p++ = (char)(ch >> 8); *p++ = (char)ch; | ||
| 291 | } else if (STRFMT_FP(sf) == STRFMT_FP(STRFMT_T_FP_A)) { | ||
| 292 | /* %a */ | ||
| 293 | const char *hexdig = (sf & STRFMT_F_UPPER) ? "0123456789ABCDEFPX" | ||
| 294 | : "0123456789abcdefpx"; | ||
| 295 | int32_t e = (t.u32.hi >> 20) & 0x7ff; | ||
| 296 | char prefix = 0, eprefix = '+'; | ||
| 297 | if (t.u32.hi & 0x80000000) prefix = '-'; | ||
| 298 | else if ((sf & STRFMT_F_PLUS)) prefix = '+'; | ||
| 299 | else if ((sf & STRFMT_F_SPACE)) prefix = ' '; | ||
| 300 | t.u32.hi &= 0xfffff; | ||
| 301 | if (e) { | ||
| 302 | t.u32.hi |= 0x100000; | ||
| 303 | e -= 1023; | ||
| 304 | } else if (t.u32.lo | t.u32.hi) { | ||
| 305 | /* Non-zero denormal - normalise it. */ | ||
| 306 | uint32_t shift = t.u32.hi ? 20-lj_fls(t.u32.hi) : 52-lj_fls(t.u32.lo); | ||
| 307 | e = -1022 - shift; | ||
| 308 | t.u64 <<= shift; | ||
| 309 | } | ||
| 310 | /* abs(n) == t.u64 * 2^(e - 52) */ | ||
| 311 | /* If n != 0, bit 52 of t.u64 is set, and is the highest set bit. */ | ||
| 312 | if ((int32_t)prec < 0) { | ||
| 313 | /* Default precision: use smallest precision giving exact result. */ | ||
| 314 | prec = t.u32.lo ? 13-lj_ffs(t.u32.lo)/4 : 5-lj_ffs(t.u32.hi|0x100000)/4; | ||
| 315 | } else if (prec < 13) { | ||
| 316 | /* Precision is sufficiently low as to maybe require rounding. */ | ||
| 317 | t.u64 += (((uint64_t)1) << (51 - prec*4)); | ||
| 318 | } | ||
| 319 | if (e < 0) { | ||
| 320 | eprefix = '-'; | ||
| 321 | e = -e; | ||
| 322 | } | ||
| 323 | len = 5 + ndigits_dec((uint32_t)e) + prec + (prefix != 0) | ||
| 324 | + ((prec | (sf & STRFMT_F_ALT)) != 0); | ||
| 325 | if (!p) p = lj_buf_more(sb, width > len ? width : len); | ||
| 326 | if (!(sf & (STRFMT_F_LEFT | STRFMT_F_ZERO))) { | ||
| 327 | while (width-- > len) *p++ = ' '; | ||
| 328 | } | ||
| 329 | if (prefix) *p++ = prefix; | ||
| 330 | *p++ = '0'; | ||
| 331 | *p++ = hexdig[17]; /* x or X */ | ||
| 332 | if ((sf & (STRFMT_F_LEFT | STRFMT_F_ZERO)) == STRFMT_F_ZERO) { | ||
| 333 | while (width-- > len) *p++ = '0'; | ||
| 334 | } | ||
| 335 | *p++ = '0' + (t.u32.hi >> 20); /* Usually '1', sometimes '0' or '2'. */ | ||
| 336 | if ((prec | (sf & STRFMT_F_ALT))) { | ||
| 337 | /* Emit fractional part. */ | ||
| 338 | char *q = p + 1 + prec; | ||
| 339 | *p = '.'; | ||
| 340 | if (prec < 13) t.u64 >>= (52 - prec*4); | ||
| 341 | else while (prec > 13) p[prec--] = '0'; | ||
| 342 | while (prec) { p[prec--] = hexdig[t.u64 & 15]; t.u64 >>= 4; } | ||
| 343 | p = q; | ||
| 344 | } | ||
| 345 | *p++ = hexdig[16]; /* p or P */ | ||
| 346 | *p++ = eprefix; /* + or - */ | ||
| 347 | p = lj_strfmt_wint(p, e); | ||
| 348 | } else { | ||
| 349 | /* %e or %f or %g - begin by converting n to "nd" format. */ | ||
| 350 | uint32_t nd[64]; | ||
| 351 | uint32_t ndhi = 0, ndlo, i; | ||
| 352 | int32_t e = (t.u32.hi >> 20) & 0x7ff, ndebias = 0; | ||
| 353 | char prefix = 0, *q; | ||
| 354 | if (t.u32.hi & 0x80000000) prefix = '-'; | ||
| 355 | else if ((sf & STRFMT_F_PLUS)) prefix = '+'; | ||
| 356 | else if ((sf & STRFMT_F_SPACE)) prefix = ' '; | ||
| 357 | prec += ((int32_t)prec >> 31) & 7; /* Default precision is 6. */ | ||
| 358 | if (STRFMT_FP(sf) == STRFMT_FP(STRFMT_T_FP_G)) { | ||
| 359 | /* %g - decrement precision if non-zero (to make it like %e). */ | ||
| 360 | prec--; | ||
| 361 | prec ^= (uint32_t)((int32_t)prec >> 31); | ||
| 362 | } | ||
| 363 | if ((sf & STRFMT_T_FP_E) && prec < 14 && n != 0) { | ||
| 364 | /* Precision is sufficiently low that rescaling will probably work. */ | ||
| 365 | if ((ndebias = rescale_e[e >> 6])) { | ||
| 366 | t.n = n * rescale_n[e >> 6]; | ||
| 367 | t.u64 -= 2; /* Convert 2ulp below (later we convert 2ulp above). */ | ||
| 368 | nd[0] = 0x100000 | (t.u32.hi & 0xfffff); | ||
| 369 | e = ((t.u32.hi >> 20) & 0x7ff) - 1075 - (ND_MUL2K_MAX_SHIFT < 29); | ||
| 370 | goto load_t_lo; rescale_failed: | ||
| 371 | t.n = n; | ||
| 372 | e = (t.u32.hi >> 20) & 0x7ff; | ||
| 373 | ndebias = ndhi = 0; | ||
| 374 | } | ||
| 375 | } | ||
| 376 | nd[0] = t.u32.hi & 0xfffff; | ||
| 377 | if (e == 0) e++; else nd[0] |= 0x100000; | ||
| 378 | e -= 1043; | ||
| 379 | if (t.u32.lo) { | ||
| 380 | e -= 32 + (ND_MUL2K_MAX_SHIFT < 29); load_t_lo: | ||
| 381 | #if ND_MUL2K_MAX_SHIFT >= 29 | ||
| 382 | nd[0] = (nd[0] << 3) | (t.u32.lo >> 29); | ||
| 383 | ndhi = nd_mul2k(nd, ndhi, 29, t.u32.lo & 0x1fffffff, sf); | ||
| 384 | #elif ND_MUL2K_MAX_SHIFT >= 11 | ||
| 385 | ndhi = nd_mul2k(nd, ndhi, 11, t.u32.lo >> 21, sf); | ||
| 386 | ndhi = nd_mul2k(nd, ndhi, 11, (t.u32.lo >> 10) & 0x7ff, sf); | ||
| 387 | ndhi = nd_mul2k(nd, ndhi, 11, (t.u32.lo << 1) & 0x7ff, sf); | ||
| 388 | #else | ||
| 389 | #error "ND_MUL2K_MAX_SHIFT too small" | ||
| 390 | #endif | ||
| 391 | } | ||
| 392 | if (e >= 0) { | ||
| 393 | ndhi = nd_mul2k(nd, ndhi, (uint32_t)e, 0, sf); | ||
| 394 | ndlo = 0; | ||
| 395 | } else { | ||
| 396 | ndlo = nd_div2k(nd, ndhi, (uint32_t)-e, sf); | ||
| 397 | if (ndhi && !nd[ndhi]) ndhi--; | ||
| 398 | } | ||
| 399 | /* abs(n) == nd * 10^ndebias (for slightly loose interpretation of ==) */ | ||
| 400 | if ((sf & STRFMT_T_FP_E)) { | ||
| 401 | /* %e or %g - assume %e and start by calculating nd's exponent (nde). */ | ||
| 402 | char eprefix = '+'; | ||
| 403 | int32_t nde = -1; | ||
| 404 | MSize hilen; | ||
| 405 | if (ndlo && !nd[ndhi]) { | ||
| 406 | ndhi = 64; do {} while (!nd[--ndhi]); | ||
| 407 | nde -= 64 * 9; | ||
| 408 | } | ||
| 409 | hilen = ndigits_dec(nd[ndhi]); | ||
| 410 | nde += ndhi * 9 + hilen; | ||
| 411 | if (ndebias) { | ||
| 412 | /* | ||
| 413 | ** Rescaling was performed, but this introduced some error, and might | ||
| 414 | ** have pushed us across a rounding boundary. We check whether this | ||
| 415 | ** error affected the result by introducing even more error (2ulp in | ||
| 416 | ** either direction), and seeing whether a roundary boundary was | ||
| 417 | ** crossed. Having already converted the -2ulp case, we save off its | ||
| 418 | ** most significant digits, convert the +2ulp case, and compare them. | ||
| 419 | */ | ||
| 420 | int32_t eidx = e + 70 + (ND_MUL2K_MAX_SHIFT < 29) | ||
| 421 | + (t.u32.lo >= 0xfffffffe && !(~t.u32.hi << 12)); | ||
| 422 | const int8_t *m_e = four_ulp_m_e + eidx * 2; | ||
| 423 | lua_assert(0 <= eidx && eidx < 128); | ||
| 424 | nd[33] = nd[ndhi]; | ||
| 425 | nd[32] = nd[(ndhi - 1) & 0x3f]; | ||
| 426 | nd[31] = nd[(ndhi - 2) & 0x3f]; | ||
| 427 | nd_add_m10e(nd, ndhi, (uint8_t)*m_e, m_e[1]); | ||
| 428 | if (LJ_UNLIKELY(!nd_similar(nd, ndhi, nd + 33, hilen, prec + 1))) { | ||
| 429 | goto rescale_failed; | ||
| 430 | } | ||
| 431 | } | ||
| 432 | if ((int32_t)(prec - nde) < (0x3f & -(int32_t)ndlo) * 9) { | ||
| 433 | /* Precision is sufficiently low as to maybe require rounding. */ | ||
| 434 | ndhi = nd_add_m10e(nd, ndhi, 5, nde - prec - 1); | ||
| 435 | nde += (hilen != ndigits_dec(nd[ndhi])); | ||
| 436 | } | ||
| 437 | nde += ndebias; | ||
| 438 | if ((sf & STRFMT_T_FP_F)) { | ||
| 439 | /* %g */ | ||
| 440 | if ((int32_t)prec >= nde && nde >= -4) { | ||
| 441 | if (nde < 0) ndhi = 0; | ||
| 442 | prec -= nde; | ||
| 443 | goto g_format_like_f; | ||
| 444 | } else if (!(sf & STRFMT_F_ALT) && prec && width > 5) { | ||
| 445 | /* Decrease precision in order to strip trailing zeroes. */ | ||
| 446 | char tail[9]; | ||
| 447 | uint32_t maxprec = hilen - 1 + ((ndhi - ndlo) & 0x3f) * 9; | ||
| 448 | if (prec >= maxprec) prec = maxprec; | ||
| 449 | else ndlo = (ndhi - (((int32_t)(prec - hilen) + 9) / 9)) & 0x3f; | ||
| 450 | i = prec - hilen - (((ndhi - ndlo) & 0x3f) * 9) + 10; | ||
| 451 | lj_strfmt_wuint9(tail, nd[ndlo]); | ||
| 452 | while (prec && tail[--i] == '0') { | ||
| 453 | prec--; | ||
| 454 | if (!i) { | ||
| 455 | if (ndlo == ndhi) { prec = 0; break; } | ||
| 456 | lj_strfmt_wuint9(tail, nd[++ndlo]); | ||
| 457 | i = 9; | ||
| 458 | } | ||
| 459 | } | ||
| 460 | } | ||
| 461 | } | ||
| 462 | if (nde < 0) { | ||
| 463 | /* Make nde non-negative. */ | ||
| 464 | eprefix = '-'; | ||
| 465 | nde = -nde; | ||
| 466 | } | ||
| 467 | len = 3 + prec + (prefix != 0) + ndigits_dec((uint32_t)nde) + (nde < 10) | ||
| 468 | + ((prec | (sf & STRFMT_F_ALT)) != 0); | ||
| 469 | if (!p) p = lj_buf_more(sb, (width > len ? width : len) + 5); | ||
| 470 | if (!(sf & (STRFMT_F_LEFT | STRFMT_F_ZERO))) { | ||
| 471 | while (width-- > len) *p++ = ' '; | ||
| 472 | } | ||
| 473 | if (prefix) *p++ = prefix; | ||
| 474 | if ((sf & (STRFMT_F_LEFT | STRFMT_F_ZERO)) == STRFMT_F_ZERO) { | ||
| 475 | while (width-- > len) *p++ = '0'; | ||
| 476 | } | ||
| 477 | q = lj_strfmt_wint(p + 1, nd[ndhi]); | ||
| 478 | p[0] = p[1]; /* Put leading digit in the correct place. */ | ||
| 479 | if ((prec | (sf & STRFMT_F_ALT))) { | ||
| 480 | /* Emit fractional part. */ | ||
| 481 | p[1] = '.'; p += 2; | ||
| 482 | prec -= (q - p); p = q; /* Account for the digits already emitted. */ | ||
| 483 | /* Then emit chunks of 9 digits (this may emit 8 digits too many). */ | ||
| 484 | for (i = ndhi; (int32_t)prec > 0 && i != ndlo; prec -= 9) { | ||
| 485 | i = (i - 1) & 0x3f; | ||
| 486 | p = lj_strfmt_wuint9(p, nd[i]); | ||
| 487 | } | ||
| 488 | if ((sf & STRFMT_T_FP_F) && !(sf & STRFMT_F_ALT)) { | ||
| 489 | /* %g (and not %#g) - strip trailing zeroes. */ | ||
| 490 | p += (int32_t)prec & ((int32_t)prec >> 31); | ||
| 491 | while (p[-1] == '0') p--; | ||
| 492 | if (p[-1] == '.') p--; | ||
| 493 | } else { | ||
| 494 | /* %e (or %#g) - emit trailing zeroes. */ | ||
| 495 | while ((int32_t)prec > 0) { *p++ = '0'; prec--; } | ||
| 496 | p += (int32_t)prec; | ||
| 497 | } | ||
| 498 | } else { | ||
| 499 | p++; | ||
| 500 | } | ||
| 501 | *p++ = (sf & STRFMT_F_UPPER) ? 'E' : 'e'; | ||
| 502 | *p++ = eprefix; /* + or - */ | ||
| 503 | if (nde < 10) *p++ = '0'; /* Always at least two digits of exponent. */ | ||
| 504 | p = lj_strfmt_wint(p, nde); | ||
| 505 | } else { | ||
| 506 | /* %f (or, shortly, %g in %f style) */ | ||
| 507 | if (prec < (MSize)(0x3f & -(int32_t)ndlo) * 9) { | ||
| 508 | /* Precision is sufficiently low as to maybe require rounding. */ | ||
| 509 | ndhi = nd_add_m10e(nd, ndhi, 5, 0 - prec - 1); | ||
| 510 | } | ||
| 511 | g_format_like_f: | ||
| 512 | if ((sf & STRFMT_T_FP_E) && !(sf & STRFMT_F_ALT) && prec && width) { | ||
| 513 | /* Decrease precision in order to strip trailing zeroes. */ | ||
| 514 | if (ndlo) { | ||
| 515 | /* nd has a fractional part; we need to look at its digits. */ | ||
| 516 | char tail[9]; | ||
| 517 | uint32_t maxprec = (64 - ndlo) * 9; | ||
| 518 | if (prec >= maxprec) prec = maxprec; | ||
| 519 | else ndlo = 64 - (prec + 8) / 9; | ||
| 520 | i = prec - ((63 - ndlo) * 9); | ||
| 521 | lj_strfmt_wuint9(tail, nd[ndlo]); | ||
| 522 | while (prec && tail[--i] == '0') { | ||
| 523 | prec--; | ||
| 524 | if (!i) { | ||
| 525 | if (ndlo == 63) { prec = 0; break; } | ||
| 526 | lj_strfmt_wuint9(tail, nd[++ndlo]); | ||
| 527 | i = 9; | ||
| 528 | } | ||
| 529 | } | ||
| 530 | } else { | ||
| 531 | /* nd has no fractional part, so precision goes straight to zero. */ | ||
| 532 | prec = 0; | ||
| 533 | } | ||
| 534 | } | ||
| 535 | len = ndhi * 9 + ndigits_dec(nd[ndhi]) + prec + (prefix != 0) | ||
| 536 | + ((prec | (sf & STRFMT_F_ALT)) != 0); | ||
| 537 | if (!p) p = lj_buf_more(sb, (width > len ? width : len) + 8); | ||
| 538 | if (!(sf & (STRFMT_F_LEFT | STRFMT_F_ZERO))) { | ||
| 539 | while (width-- > len) *p++ = ' '; | ||
| 540 | } | ||
| 541 | if (prefix) *p++ = prefix; | ||
| 542 | if ((sf & (STRFMT_F_LEFT | STRFMT_F_ZERO)) == STRFMT_F_ZERO) { | ||
| 543 | while (width-- > len) *p++ = '0'; | ||
| 544 | } | ||
| 545 | /* Emit integer part. */ | ||
| 546 | p = lj_strfmt_wint(p, nd[ndhi]); | ||
| 547 | i = ndhi; | ||
| 548 | while (i) p = lj_strfmt_wuint9(p, nd[--i]); | ||
| 549 | if ((prec | (sf & STRFMT_F_ALT))) { | ||
| 550 | /* Emit fractional part. */ | ||
| 551 | *p++ = '.'; | ||
| 552 | /* Emit chunks of 9 digits (this may emit 8 digits too many). */ | ||
| 553 | while ((int32_t)prec > 0 && i != ndlo) { | ||
| 554 | i = (i - 1) & 0x3f; | ||
| 555 | p = lj_strfmt_wuint9(p, nd[i]); | ||
| 556 | prec -= 9; | ||
| 557 | } | ||
| 558 | if ((sf & STRFMT_T_FP_E) && !(sf & STRFMT_F_ALT)) { | ||
| 559 | /* %g (and not %#g) - strip trailing zeroes. */ | ||
| 560 | p += (int32_t)prec & ((int32_t)prec >> 31); | ||
| 561 | while (p[-1] == '0') p--; | ||
| 562 | if (p[-1] == '.') p--; | ||
| 563 | } else { | ||
| 564 | /* %f (or %#g) - emit trailing zeroes. */ | ||
| 565 | while ((int32_t)prec > 0) { *p++ = '0'; prec--; } | ||
| 566 | p += (int32_t)prec; | ||
| 567 | } | ||
| 568 | } | ||
| 569 | } | ||
| 570 | } | ||
| 571 | if ((sf & STRFMT_F_LEFT)) while (width-- > len) *p++ = ' '; | ||
| 572 | return p; | ||
| 573 | } | ||
| 574 | |||
| 575 | /* Add formatted floating-point number to buffer. */ | ||
| 576 | SBuf *lj_strfmt_putfnum(SBuf *sb, SFormat sf, lua_Number n) | ||
| 577 | { | ||
| 578 | setsbufP(sb, lj_strfmt_wfnum(sb, sf, n, NULL)); | ||
| 579 | return sb; | ||
| 580 | } | ||
| 581 | |||
| 582 | /* -- Conversions to strings ---------------------------------------------- */ | ||
| 583 | |||
| 584 | /* Convert number to string. */ | ||
| 585 | GCstr * LJ_FASTCALL lj_strfmt_num(lua_State *L, cTValue *o) | ||
| 586 | { | ||
| 587 | char buf[STRFMT_MAXBUF_NUM]; | ||
| 588 | MSize len = (MSize)(lj_strfmt_wfnum(NULL, STRFMT_G14, o->n, buf) - buf); | ||
| 589 | return lj_str_new(L, buf, len); | ||
| 590 | } | ||
| 591 | |||
diff --git a/src/ljamalg.c b/src/ljamalg.c index be0c52d7..93b81f2a 100644 --- a/src/ljamalg.c +++ b/src/ljamalg.c | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #include "lj_vmmath.c" | 46 | #include "lj_vmmath.c" |
| 47 | #include "lj_strscan.c" | 47 | #include "lj_strscan.c" |
| 48 | #include "lj_strfmt.c" | 48 | #include "lj_strfmt.c" |
| 49 | #include "lj_strfmt_num.c" | ||
| 49 | #include "lj_api.c" | 50 | #include "lj_api.c" |
| 50 | #include "lj_profile.c" | 51 | #include "lj_profile.c" |
| 51 | #include "lj_lex.c" | 52 | #include "lj_lex.c" |
