summaryrefslogtreecommitdiff
path: root/src/factor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/factor.c')
-rw-r--r--src/factor.c122
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;
}