diff options
Diffstat (limited to 'src/factor.c')
-rw-r--r-- | src/factor.c | 122 |
1 files changed, 107 insertions, 15 deletions
diff --git a/src/factor.c b/src/factor.c index 63924d54..1d7d7c8d 100644 --- a/src/factor.c +++ b/src/factor.c @@ -1,5 +1,5 @@ /* factor -- print prime factors of n. - Copyright (C) 1986-2014 Free Software Foundation, Inc. + Copyright (C) 1986-2015 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -98,6 +98,7 @@ #include "system.h" #include "error.h" +#include "full-write.h" #include "quote.h" #include "readtokens.h" #include "xstrtol.h" @@ -1811,9 +1812,9 @@ isqrt2 (uintmax_t nh, uintmax_t nl) } /* MAGIC[N] has a bit i set iff i is a quadratic residue mod N. */ -#define MAGIC64 ((uint64_t) 0x0202021202030213ULL) -#define MAGIC63 ((uint64_t) 0x0402483012450293ULL) -#define MAGIC65 ((uint64_t) 0x218a019866014613ULL) +#define MAGIC64 0x0202021202030213ULL +#define MAGIC63 0x0402483012450293ULL +#define MAGIC65 0x218a019866014613ULL #define MAGIC11 0x23b /* Return the square root if the input is a square, otherwise 0. */ @@ -2055,8 +2056,9 @@ factor_using_squfof (uintmax_t n1, uintmax_t n0, struct factors *factors) div_smallq (q, rem, S+P, Q); P1 = S - rem; /* P1 = q*Q - P */ + IF_LINT (assert (q > 0 && Q > 0)); + #if STAT_SQUFOF - assert (q > 0); q_freq[0]++; q_freq[MIN (q, Q_FREQ_SIZE)]++; #endif @@ -2322,13 +2324,100 @@ strto2uintmax (uintmax_t *hip, uintmax_t *lop, const char *s) return err; } +/* Structure and routines for buffering and outputting full lines, + to support parallel operation efficiently. */ +static struct lbuf_ +{ + char *buf; + char *end; +} lbuf; + +/* 512 is chosen to give good performance, + and also is the max guaranteed size that + consumers can read atomically through pipes. + Also it's big enough to cater for max line length + even with 128 bit uintmax_t. */ +#define FACTOR_PIPE_BUF 512 + +static void +lbuf_alloc (void) +{ + if (lbuf.buf) + return; + + /* Double to ensure enough space for + previous numbers + next number. */ + lbuf.buf = xmalloc (FACTOR_PIPE_BUF * 2); + lbuf.end = lbuf.buf; +} + +/* Write complete LBUF to standard output. */ +static void +lbuf_flush (void) +{ + size_t size = lbuf.end - lbuf.buf; + if (full_write (STDOUT_FILENO, lbuf.buf, size) != size) + error (EXIT_FAILURE, errno, "%s", _("write error")); + lbuf.end = lbuf.buf; +} + +/* Add a character C to LBUF and if it's a newline + and enough bytes are already buffered, + then write atomically to standard output. */ +static void +lbuf_putc (char c) +{ + *lbuf.end++ = c; + + if (c == '\n') + { + size_t buffered = lbuf.end - lbuf.buf; + + if (buffered >= FACTOR_PIPE_BUF) + { + /* Write output in <= PIPE_BUF chunks + so consumers can read atomically. */ + char const *tend = lbuf.end; + + /* Since a umaxint_t's factors must fit in 512 + we're guaranteed to find a newline here. */ + char *tlend = lbuf.buf + FACTOR_PIPE_BUF; + while (*--tlend != '\n'); + tlend++; + + lbuf.end = tlend; + lbuf_flush (); + + /* Buffer the remainder. */ + memcpy (lbuf.buf, tlend, tend - tlend); + lbuf.end = lbuf.buf + (tend - tlend); + } + } +} + +/* Buffer an int to the internal LBUF. */ +static void +lbuf_putint (uintmax_t i, size_t min_width) +{ + char buf[INT_BUFSIZE_BOUND (uintmax_t)]; + char const *umaxstr = umaxtostr (i, buf); + size_t width = sizeof (buf) - (umaxstr - buf) - 1; + size_t z = width; + + for (; z < min_width; z++) + *lbuf.end++ = '0'; + + memcpy (lbuf.end, umaxstr, width); + lbuf.end += width; +} + static void print_uintmaxes (uintmax_t t1, uintmax_t t0) { uintmax_t q, r; if (t1 == 0) - printf ("%"PRIuMAX, t0); + lbuf_putint (t0, 0); else { /* Use very plain code here since it seems hard to write fast code @@ -2337,7 +2426,7 @@ print_uintmaxes (uintmax_t t1, uintmax_t t0) r = t1 % 1000000000; udiv_qrnnd (t0, r, r, t0, 1000000000); print_uintmaxes (q, t0); - printf ("%09u", (int) r); + lbuf_putint (r, 9); } } @@ -2348,24 +2437,24 @@ print_factors_single (uintmax_t t1, uintmax_t t0) struct factors factors; print_uintmaxes (t1, t0); - putchar (':'); + lbuf_putc (':'); factor (t1, t0, &factors); for (unsigned int j = 0; j < factors.nfactors; j++) for (unsigned int k = 0; k < factors.e[j]; k++) { - char buf[INT_BUFSIZE_BOUND (uintmax_t)]; - putchar (' '); - fputs (umaxtostr (factors.p[j], buf), stdout); + lbuf_putc (' '); + print_uintmaxes (0, factors.p[j]); } if (factors.plarge[1]) { - putchar (' '); + lbuf_putc (' '); print_uintmaxes (factors.plarge[1], factors.plarge[0]); } - putchar ('\n'); + + lbuf_putc ('\n'); } /* Emit the factors of the indicated number. If we have the option of using @@ -2421,6 +2510,7 @@ print_factors (const char *input) mp_factor_clear (&factors); mpz_clear (t); putchar ('\n'); + fflush (stdout); return true; #else error (0, 0, _("%s is too large"), quote (input)); @@ -2447,7 +2537,7 @@ are specified on the command line, read them from standard input.\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); - emit_ancillary_info (); + emit_ancillary_info (PROGRAM_NAME); } exit (status); } @@ -2482,7 +2572,9 @@ main (int argc, char **argv) bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); + lbuf_alloc (); atexit (close_stdout); + atexit (lbuf_flush); alg = ALG_POLLARD_RHO; /* Default to Pollard rho */ @@ -2543,5 +2635,5 @@ main (int argc, char **argv) } #endif - exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); + return ok ? EXIT_SUCCESS : EXIT_FAILURE; } |