Print all whole numbers from A to B, inclusive -- to stdout, each followed by a newline. Then exit. */
| 459 | /* Print all whole numbers from A to B, inclusive -- to stdout, each |
| 460 | followed by a newline. Then exit. */ |
| 461 | static void |
| 462 | seq_fast (char const *a, char const *b, uintmax_t step) |
| 463 | { |
| 464 | /* Skip past any redundant leading '0's. Without this, our naive cmp |
| 465 | function would declare 000 to be larger than 99. */ |
| 466 | a = trim_leading_zeros (a); |
| 467 | b = trim_leading_zeros (b); |
| 468 | |
| 469 | idx_t p_len = strlen (a); |
| 470 | idx_t b_len = strlen (b); |
| 471 | bool inf = b_len == 3 && memeq (b, "inf", 4); |
| 472 | |
| 473 | /* Allow for at least 31 digits without realloc. |
| 474 | 1 more than p_len is needed for the inf case. */ |
| 475 | enum { INITIAL_ALLOC_DIGITS = 31 }; |
| 476 | idx_t inc_size = MAX (MAX (p_len + 1, b_len), INITIAL_ALLOC_DIGITS); |
| 477 | /* Ensure we only increase by at most 1 digit at buffer boundaries. */ |
| 478 | static_assert (SEQ_FAST_STEP_LIMIT_DIGITS < INITIAL_ALLOC_DIGITS - 1); |
| 479 | |
| 480 | /* Copy A (sans NUL) to end of new buffer. */ |
| 481 | char *p0 = xmalloc (inc_size); |
| 482 | char *endp = p0 + inc_size; |
| 483 | char *p = memcpy (endp - p_len, a, p_len); |
| 484 | |
| 485 | /* Reduce number of write calls which is seen to |
| 486 | give a speed-up of more than 2x over naive stdio code |
| 487 | when printing the first 10^9 integers. */ |
| 488 | char buf[BUFSIZ]; |
| 489 | char *buf_end = buf + sizeof buf; |
| 490 | char *bufp = buf; |
| 491 | |
| 492 | while (inf || cmp (p, endp - p, b, b_len) <= 0) |
| 493 | { |
| 494 | /* Append number, flushing output buffer while the number's |
| 495 | digits do not fit with room for a separator or terminator. */ |
| 496 | char *pp = p; |
| 497 | while (buf_end - bufp <= endp - pp) |
| 498 | { |
| 499 | memcpy (bufp, pp, buf_end - bufp); |
| 500 | pp += buf_end - bufp; |
| 501 | if (full_write (STDOUT_FILENO, buf, sizeof buf) != sizeof buf) |
| 502 | write_error (); |
| 503 | bufp = buf; |
| 504 | } |
| 505 | |
| 506 | /* The rest of the number, followed by a separator or terminator, |
| 507 | will fit. Tentatively append a separator. */ |
| 508 | bufp = mempcpy (bufp, pp, endp - pp); |
| 509 | *bufp++ = *separator; |
| 510 | |
| 511 | /* Grow number buffer if needed for the inf case. */ |
| 512 | if (p == p0) |
| 513 | { |
| 514 | char *new_p0 = xpalloc (NULL, &inc_size, 1, -1, 1); |
| 515 | idx_t saved_p_len = endp - p; |
| 516 | endp = new_p0 + inc_size; |
| 517 | p = memcpy (endp - saved_p_len, p0, saved_p_len); |
| 518 | free (p0); |
no test coverage detected