Files
fastwc/STYLEGUIDE.md
T
huntedbytheirs 6aa461f053 bench: rub it in — monsters, stdin wins, busybox retired
Suites split into benchmarks/files/{lines,words} and
benchmarks/stdin/piping, with the monsters bolted onto the lines suite:
100M lines raced against coreutils (~2x win), 1B lines solo (~6-8s,
11 GB in one pass). Stdin redirects from regular files are now mmap'd
in count_stream, so the stdin suite wins too — up to 12.00x on words.

The ratio column now reports how many times faster fastwc is, not how
much of GNU's time it used. busybox was removed from the suite: it
stopped being a challenge and started being a participation trophy.
GNU wc's lone win — 1M lines by one millisecond on hand-tuned AVX-512
assembly — is now a historical footnote, and the README says so.
2026-08-29 15:52:24 -04:00

98 lines
4.1 KiB
Markdown

# fastwc Style Guide
The style is the law. GNU wc can afford to look like a committee
designed it — it was. We're one file, one purpose, one opinion.
## The language
- **C99 with POSIX.** `_POSIX_C_SOURCE 200809L`. We target the
standard, not a compiler vendor's mood.
- **Zero warnings** with `-Wall -Wextra`. A warning is a bug you
haven't fixed yet. Fix it.
- **No compiler-specific extensions** unless they're guarded and the
benchmark gets faster because of it. `__builtin_popcountll` is the
one exception — it's the price of admission on every compiler that
matters, and the benchmark proves it.
## Format
- **4 spaces.** Not tabs, not 8 spaces. GNU uses tabs because GNU was
written in 1985 by people who had strong opinions about typewriters.
- **80 columns.** If your line is longer, your idea is longer than it
needs to be.
- **Braces on the next line** (Allman). Everywhere. Functions, blocks,
switch cases. Consistency is the only religion here, and we're devout.
- **Snake case for everything.** `count_stream`, `ws_tab`, `nread`.
No CamelCase — that's for languages that need help knowing what a
word is.
## Structure
- **One file: `src/main.c`.** See CONTRIBUTING.md rule 6. This is not a
suggestion.
- **Everything is `static`.** The binary exports nothing. We're not a
library, we're a verdict.
- **Types end in `_t`.** `counts_t`, and not much else. GNU has a type
for everything and a committee to name it. We have counts, and we
count.
- **No globals except what's truly process-wide.** `flags` and `ws_tab`
live at file scope because they're the program's identity. Everything
else gets passed around like it's hot.
## The hot path
`count_stream()`, `count_newlines()`, `count_words()`, and the SIMD
kernels (`count_lw_avx512`, `count_lw_avx2`, `count_lw_sse2`) are the
product. The rest of the file is just the packaging.
- **Fixed stride.** No per-token function calls. No `isspace()` in a
loop — that's what the lookup table is for.
- **No allocation, no locks, no syscalls in the counting loop.** The
kernels are pure; parallel slices need no locks. The `fread` (or the
single `mmap`) is the only syscall, and it's not yours to add to.
- **Branchless where it costs nothing.** A predictable branch is fine;
a mispredicted one is a lie you told the CPU.
- **Regular files are mapped, not streamed.** The kernel hands us the
pages; we count them, split across cores for anything past 8 MiB.
This includes stdin redirects from regular files. Real pipes, ttys,
and the `-m` path fall back to the `static`, 128 KiB buffer that
never grows.
## Counts
- **`long long` for everything that counts.** Files can be bigger than
your opinions. Signed, because overflow should scream, not wrap.
- **Lines are `'\n'`s.** Not "lines of text," not "records." A file
without a trailing newline has fewer newlines than it has lines, and
that's correct. GNU agrees with us on this one, so it must be right.
- **Words are whitespace-delimited runs.** The lookup table decides
what whitespace is; the popcount decides how many words; you don't
get an opinion.
## Errors
- **`fastwc: <file>: <message>` on stderr**, and keep going. GNU wc
fails gracefully across multiple files, and we'll credit them that
one thing. Then we'll be faster at it.
- **Exit 1 if anything failed**, 0 otherwise. No drama, no
`EXIT_FAILURE` poetry.
## Comments
- **Only when the code can't speak for itself.** The SWAR newline
counter in `count_newlines()` gets a comment because
`(x ^ nl) & cl` is a sentence in a language you don't speak yet.
`i++` does not get a comment.
- **No commented-out code.** The dead don't get to live in the file.
- **No TODO without a date.** A TODO without a date is a promise you
plan to break.
## What the style is not
- It is not GNU's style. GNU's style was written by a committee,
ratified by a foundation, and translated into fourteen languages.
- It is not "whatever your editor defaults to." Your editor has
opinions. So do we. Ours are right.
- It is not negotiable in review. If a PR violates the style, the PR
is a rewrite request with extra steps.