mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-05 02:38:31 +00:00
Improve performance of printf functions
This commit is contained in:
parent
b107d2709f
commit
dc6d11a031
39 changed files with 577 additions and 650 deletions
|
@ -23,6 +23,7 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
|
@ -31,11 +32,12 @@
|
|||
#include "libc/sysv/errfuns.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
||||
#define PUT(C) \
|
||||
do { \
|
||||
if (out(C, arg) == -1) { \
|
||||
return -1; \
|
||||
} \
|
||||
#define PUT(C) \
|
||||
do { \
|
||||
char Buf[1] = {C}; \
|
||||
if (out(Buf, arg, 1) == -1) { \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
||||
|
@ -121,14 +123,18 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
uint32_t u[2];
|
||||
uint64_t q;
|
||||
} pun;
|
||||
long ld;
|
||||
void *p;
|
||||
unsigned u;
|
||||
char ibuf[21];
|
||||
bool longdouble;
|
||||
long double ldbl;
|
||||
unsigned long lu;
|
||||
wchar_t charbuf[1];
|
||||
const char *alphabet;
|
||||
int (*out)(long, void *);
|
||||
int (*out)(const char *, void *, size_t);
|
||||
unsigned char signbit, log2base;
|
||||
int c, d, k, w, i1, ui, bw, bex;
|
||||
int c, d, k, w, n, i1, ui, bw, bex;
|
||||
char *s, *q, *se, qchar, special[8];
|
||||
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
|
||||
|
||||
|
@ -136,18 +142,64 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
out = fn ? fn : (void *)missingno;
|
||||
|
||||
while (*format) {
|
||||
/* %[flags][width][.prec][length] */
|
||||
if (*format != '%') {
|
||||
/* no */
|
||||
PUT(*format);
|
||||
format++;
|
||||
for (n = 1; format[n]; ++n) {
|
||||
if (format[n] == '%') break;
|
||||
}
|
||||
if (out(format, arg, n) == -1) return -1;
|
||||
format += n;
|
||||
continue;
|
||||
} else {
|
||||
/* yes, evaluate it */
|
||||
format++;
|
||||
}
|
||||
|
||||
/* evaluate flags */
|
||||
if (!IsTiny()) {
|
||||
if (format[1] == 's') { /* FAST PATH: PLAIN STRING */
|
||||
s = va_arg(va, char *);
|
||||
if (!s) s = "(null)";
|
||||
if (out(s, arg, strlen(s)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'd') { /* FAST PATH: PLAIN INTEGER */
|
||||
d = va_arg(va, int);
|
||||
if (out(ibuf, arg, int64toarray_radix10(d, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'u') { /* FAST PATH: PLAIN UNSIGNED */
|
||||
u = va_arg(va, unsigned);
|
||||
if (out(ibuf, arg, uint64toarray_radix10(u, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'x') { /* FAST PATH: PLAIN HEX */
|
||||
u = va_arg(va, unsigned);
|
||||
if (out(ibuf, arg, uint64toarray_radix16(u, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'x') {
|
||||
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN LONG HEX */
|
||||
if (out(ibuf, arg, uint64toarray_radix16(lu, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'd') {
|
||||
ld = va_arg(va, long); /* FAST PATH: PLAIN LONG */
|
||||
if (out(ibuf, arg, int64toarray_radix10(ld, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'u') {
|
||||
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN UNSIGNED LONG */
|
||||
if (out(ibuf, arg, int64toarray_radix10(lu, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == '.' && format[2] == '*' && format[3] == 's') {
|
||||
n = va_arg(va, unsigned); /* FAST PATH: PRECISION STRING */
|
||||
s = va_arg(va, const char *);
|
||||
if (!s) s = "(null)", n = MIN(6, n);
|
||||
if (out(s, arg, n) == -1) return -1;
|
||||
format += 4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* GENERAL PATH */
|
||||
format++;
|
||||
sign = 0;
|
||||
flags = 0;
|
||||
getflag:
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int __fmt_pad(int (*)(long, void *), void *, unsigned long) hidden;
|
||||
int __fmt_stoa(int (*)(long, void *), void *, void *, unsigned long,
|
||||
unsigned long, unsigned long, unsigned char,
|
||||
unsigned char) hidden;
|
||||
int __fmt_ntoa(int (*)(long, void *), void *, va_list, unsigned char,
|
||||
int __fmt_pad(int (*)(const char *, void *, size_t), void *,
|
||||
unsigned long) hidden;
|
||||
int __fmt_stoa(int (*)(const char *, void *, size_t), void *, void *,
|
||||
unsigned long, unsigned long, unsigned long, unsigned char,
|
||||
const char *) hidden;
|
||||
unsigned char) hidden;
|
||||
int __fmt_ntoa(int (*)(const char *, void *, size_t), void *, va_list,
|
||||
unsigned char, unsigned long, unsigned long, unsigned long,
|
||||
unsigned char, const char *) hidden;
|
||||
char *__fmt_dtoa(double, int, int, int *, int *, char **) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/reverse.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
|
@ -25,12 +26,11 @@
|
|||
|
||||
uintmax_t __udivmodti4(uintmax_t, uintmax_t, uintmax_t *);
|
||||
|
||||
static int __fmt_ntoa_format(int out(long, void *), void *arg, char *buf,
|
||||
unsigned len, bool negative, unsigned log2base,
|
||||
unsigned prec, unsigned width,
|
||||
static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
||||
char *buf, unsigned len, bool negative,
|
||||
unsigned log2base, unsigned prec, unsigned width,
|
||||
unsigned char flags) {
|
||||
unsigned i, idx;
|
||||
idx = 0;
|
||||
unsigned i;
|
||||
|
||||
/* pad leading zeros */
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
|
@ -82,24 +82,21 @@ static int __fmt_ntoa_format(int out(long, void *), void *arg, char *buf,
|
|||
}
|
||||
}
|
||||
|
||||
/* reverse string */
|
||||
for (i = 0U; i < len; i++) {
|
||||
if (out(buf[len - i - 1], arg) == -1) return -1;
|
||||
idx++;
|
||||
}
|
||||
reverse(buf, len);
|
||||
if (out(buf, arg, len) == -1) return -1;
|
||||
|
||||
/* append pad spaces up to given width */
|
||||
if (flags & FLAGS_LEFT) {
|
||||
if (idx < width) {
|
||||
if (__fmt_pad(out, arg, width - idx) == -1) return -1;
|
||||
if (len < width) {
|
||||
if (__fmt_pad(out, arg, width - len) == -1) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __fmt_ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
||||
unsigned log2base, unsigned prec, unsigned width,
|
||||
unsigned flags, const char *alphabet) {
|
||||
int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
||||
uintmax_t value, bool neg, unsigned log2base, unsigned prec,
|
||||
unsigned width, unsigned flags, const char *alphabet) {
|
||||
uintmax_t remainder;
|
||||
unsigned len, count, digit;
|
||||
char buf[BUFFER_SIZE];
|
||||
|
@ -130,7 +127,7 @@ int __fmt_ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
|||
flags);
|
||||
}
|
||||
|
||||
int __fmt_ntoa(int out(long, void *), void *arg, va_list va,
|
||||
int __fmt_ntoa(int out(const char *, void *, size_t), void *arg, va_list va,
|
||||
unsigned char signbit, unsigned long log2base,
|
||||
unsigned long prec, unsigned long width, unsigned char flags,
|
||||
const char *lang) {
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmts.h"
|
||||
|
||||
int __fmt_pad(int out(long, void *), void *arg, unsigned long n) {
|
||||
int __fmt_pad(int out(const char *, void *, size_t), void *arg,
|
||||
unsigned long n) {
|
||||
int i, rc;
|
||||
for (rc = i = 0; i < n; ++i) rc |= out(' ', arg);
|
||||
for (rc = i = 0; i < n; ++i) rc |= out(" ", arg, 1);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nexgen32e/tinystrlen.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
|
@ -26,56 +29,50 @@
|
|||
#include "libc/str/utf16.h"
|
||||
#include "libc/unicode/unicode.h"
|
||||
|
||||
typedef int (*emit_f)(int (*)(long, void *), void *, wint_t);
|
||||
typedef int (*out_f)(const char *, void *, size_t);
|
||||
typedef int (*emit_f)(out_f, void *, uint64_t);
|
||||
|
||||
static noinstrument int __fmt_stoa_byte(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
return f(c, a);
|
||||
static int __fmt_stoa_byte(out_f out, void *a, uint64_t c) {
|
||||
char buf[1] = {c};
|
||||
return out(buf, a, 1);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_word(int f(long, void *), void *a,
|
||||
uint64_t w) {
|
||||
do {
|
||||
if (f(w & 0xff, a) == -1) {
|
||||
return -1;
|
||||
static int __fmt_stoa_wide(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
if (!isascii(w)) w = tpenc(w);
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static int __fmt_stoa_bing(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
w = tpenc((*weaken(kCp437))[w & 0xFF]);
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static int __fmt_stoa_quoted(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
if (w <= 0x7F) {
|
||||
if (w < 0x20 || w == 0x7F) {
|
||||
w = cescapec(w);
|
||||
}
|
||||
} while ((w >>= 8));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_wide(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
if (isascii(c)) {
|
||||
return f(c, a);
|
||||
} else {
|
||||
return __fmt_stoa_word(f, a, tpenc(c));
|
||||
w = tpenc(w);
|
||||
}
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_bing(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
return __fmt_stoa_wide(f, a, (*weaken(kCp437))[c]);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_quoted(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
if (isascii(c)) {
|
||||
return __fmt_stoa_word(f, a, cescapec(c));
|
||||
} else {
|
||||
return __fmt_stoa_word(f, a, tpenc(c));
|
||||
}
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_quote(int out(long, void *), void *arg,
|
||||
unsigned flags, char ch,
|
||||
unsigned char signbit) {
|
||||
static int __fmt_stoa_quote(out_f out, void *arg, unsigned flags, char ch,
|
||||
unsigned char signbit) {
|
||||
if (flags & FLAGS_REPR) {
|
||||
if (signbit == 63) {
|
||||
if (out('L', arg) == -1) return -1;
|
||||
if (out("L", arg, 1) == -1) return -1;
|
||||
} else if (signbit == 15) {
|
||||
if (out('u', arg) == -1) return -1;
|
||||
if (out("u", arg, 1) == -1) return -1;
|
||||
}
|
||||
if (out(ch, arg) == -1) return -1;
|
||||
if (out(&ch, arg, 1) == -1) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -89,23 +86,25 @@ static noinstrument int __fmt_stoa_quote(int out(long, void *), void *arg,
|
|||
*
|
||||
* @see __fmt()
|
||||
*/
|
||||
int __fmt_stoa(int out(long, void *), void *arg, void *data,
|
||||
int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
|
||||
unsigned long flags, unsigned long precision,
|
||||
unsigned long width, unsigned char signbit,
|
||||
unsigned char qchar) {
|
||||
char *p;
|
||||
wint_t wc;
|
||||
unsigned n;
|
||||
emit_f emit;
|
||||
char *p, buf[1];
|
||||
unsigned w, c, pad;
|
||||
bool justdobytes, ignorenul;
|
||||
|
||||
p = data;
|
||||
if (!p) {
|
||||
p = ((flags & FLAGS_REPR) ? "NULL" : "(null)");
|
||||
flags &= ~FLAGS_PRECISION;
|
||||
flags |= FLAGS_NOQUOTE;
|
||||
signbit = 0;
|
||||
flags |= FLAGS_NOQUOTE;
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
precision = min(strlen(p), precision);
|
||||
}
|
||||
} else {
|
||||
if (__fmt_stoa_quote(out, arg, flags, qchar, signbit) == -1) return -1;
|
||||
}
|
||||
|
@ -215,7 +214,8 @@ int __fmt_stoa(int out(long, void *), void *arg, void *data,
|
|||
}
|
||||
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
if (out(qchar, arg) == -1) return -1;
|
||||
buf[0] = qchar;
|
||||
if (out(buf, arg, 1) == -1) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
struct SprintfStr {
|
||||
|
@ -28,10 +28,13 @@ struct SprintfStr {
|
|||
size_t n;
|
||||
};
|
||||
|
||||
static noinstrument int vsnprintfputchar(unsigned char c,
|
||||
struct SprintfStr *str) {
|
||||
if (str->i < str->n) str->p[str->i] = c;
|
||||
str->i++;
|
||||
static int vsnprintfputchar(const char *s, struct SprintfStr *t, size_t n) {
|
||||
if (t->i + n <= t->n) {
|
||||
memcpy(t->p + t->i, s, n);
|
||||
} else if (t->i < t->n) {
|
||||
memcpy(t->p + t->i, s, t->n - t->i);
|
||||
}
|
||||
t->i += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -51,6 +54,6 @@ static noinstrument int vsnprintfputchar(unsigned char c,
|
|||
int(vsnprintf)(char *buf, size_t size, const char *fmt, va_list va) {
|
||||
struct SprintfStr str = {buf, 0, size};
|
||||
__fmt(vsnprintfputchar, &str, fmt, va);
|
||||
if (str.n) str.p[min(str.i, str.n - 1)] = '\0';
|
||||
if (str.n) str.p[MIN(str.i, str.n - 1)] = '\0';
|
||||
return str.i;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue