mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-22 21:32:31 +00:00
Make stderr go faster
This change makes _IONBF (unbuffered) stdio handles go 20x faster for certain kinds of formatting directives by being smarter about buffers
This commit is contained in:
parent
2cbd09b4d4
commit
8fc778162e
6 changed files with 70 additions and 38 deletions
|
@ -244,15 +244,15 @@ static int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
|||
unsigned len, count, digit;
|
||||
char buf[BUFFER_SIZE];
|
||||
len = 0;
|
||||
/* we check for log2base != 3 because otherwise we'll print nothing for a
|
||||
* value of 0 with precision 0 when # mandates that one be printed */
|
||||
// we check for log2base!=3, since otherwise we'll print nothing for
|
||||
// a value of 0 with precision 0 when # mandates that one be printed
|
||||
if (!value && log2base != 3) flags &= ~FLAGS_HASH;
|
||||
if (value || !(flags & FLAGS_PRECISION)) {
|
||||
count = 0;
|
||||
do {
|
||||
if (!log2base) {
|
||||
if (value <= UINT64_MAX) {
|
||||
value = DivMod10(value, &digit);
|
||||
value = __divmod10(value, &digit);
|
||||
} else {
|
||||
value = __udivmodti4(value, 10, &remainder);
|
||||
digit = remainder;
|
||||
|
|
|
@ -18,28 +18,35 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/stdckdint.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
struct buf {
|
||||
int n;
|
||||
char p[512];
|
||||
};
|
||||
|
||||
struct state {
|
||||
FILE *f;
|
||||
int n;
|
||||
struct buf b;
|
||||
};
|
||||
|
||||
static int vfprintfputchar(const char *s, struct state *t, size_t n) {
|
||||
static int __vfprintf_flbuf(const char *s, struct state *t, size_t n) {
|
||||
int rc;
|
||||
if (n) {
|
||||
if (n == 1 && *s != '\n' && t->f->beg < t->f->size &&
|
||||
t->f->bufmode != _IONBF) {
|
||||
if (n == 1 && *s != '\n' && t->f->beg < t->f->size) {
|
||||
t->f->buf[t->f->beg++] = *s;
|
||||
t->n += n;
|
||||
rc = 0;
|
||||
} else if (!fwrite_unlocked(s, 1, n, t->f)) {
|
||||
rc = -1;
|
||||
} else {
|
||||
t->n += n;
|
||||
} else if (fwrite_unlocked(s, 1, n, t->f)) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
if (ckd_add(&t->n, t->n, n)) {
|
||||
rc = eoverflow();
|
||||
}
|
||||
} else {
|
||||
rc = 0;
|
||||
|
@ -47,15 +54,49 @@ static int vfprintfputchar(const char *s, struct state *t, size_t n) {
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int __vfprintf_nbuf(const char *s, struct state *t, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
t->b.p[t->b.n++] = s[i];
|
||||
if (t->b.n == sizeof(t->b.p)) {
|
||||
if (!fwrite_unlocked(s, 1, t->b.n, t->f)) {
|
||||
return -1;
|
||||
}
|
||||
t->b.n = 0;
|
||||
}
|
||||
if (ckd_add(&t->n, t->n, 1)) {
|
||||
return eoverflow();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats and writes text to stream.
|
||||
* @see printf() for further documentation
|
||||
*/
|
||||
int vfprintf_unlocked(FILE *f, const char *fmt, va_list va) {
|
||||
int rc;
|
||||
struct state st[1] = {{f, 0}};
|
||||
if ((rc = __fmt(vfprintfputchar, st, fmt, va)) != -1) {
|
||||
rc = st->n;
|
||||
struct state st;
|
||||
int (*out)(const char *, struct state *, size_t);
|
||||
if (f->bufmode != _IONBF) {
|
||||
out = __vfprintf_flbuf;
|
||||
} else {
|
||||
out = __vfprintf_nbuf;
|
||||
}
|
||||
st.f = f;
|
||||
st.n = 0;
|
||||
st.b.n = 0;
|
||||
if ((rc = __fmt(out, &st, fmt, va)) != -1) {
|
||||
if (!st.b.n) {
|
||||
rc = st.n;
|
||||
} else if (fwrite_unlocked(st.b.p, 1, st.b.n, st.f)) {
|
||||
if (ckd_add(&rc, st.n, st.b.n)) {
|
||||
rc = eoverflow();
|
||||
}
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue