Files
fastwc/CONTRIBUTING.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

140 lines
5.1 KiB
Markdown

# Contributing to fastwc
We're building the word counter GNU wc is still trying to be after forty
years. If that sounds like your kind of project, keep reading.
## The rules
These aren't guidelines. They're the deal.
### 1. The benchmark is the contract
`./benchmarks/test-all.sh` must pass. Not "mostly pass." Not "pass on
your machine." Pass. Every suite — words, lines (monsters included),
and stdin — races fastwc against GNU wc.
The moment fastwc is slower than GNU wc — or disagrees with it on a
single count — your change does not ship. We did not spend this much
effort being faster than a forty-year-old dependency museum just so you
could add a `strlen()` in the hot loop.
The old standing exception — the 1M-line case, where GNU's hand-tuned
AVX-512 assembly squeaked out a one-millisecond win — is closed. We
beat them there too now (see docs/PERFORMANCE.md). There are no
exceptions left, and there is no excuse to be slower anywhere else.
### 2. C99, or don't bother
We compile with `-Wall -Wextra` and zero warnings. Zero. If the compiler
is complaining, the compiler is right and you are wrong. We target C99
with POSIX extensions, not whatever your compiler vendor's imagination
happens to ship this quarter.
### 3. No new dependencies. Ever.
The C standard library is the only thing we trust. No gettext. No gnulib.
No `libutf8pro` with its own translation team. GNU wc needs a build
system the size of a small country to count newlines. We need `cc`.
If your feature needs a library, the feature is too big. Make the
feature smaller.
### 4. The hot path is sacred
`count_stream()`, `count_newlines()`, `count_words()`, and the SIMD
kernels in `src/main.c` are the entire point of this project. You may
touch them only if `./benchmarks/test-all.sh` still passes afterward.
Rules for the counting loops:
- fixed stride, no per-token function calls
- no allocation, no locking, no syscalls — the read is the only syscall
- branchless where it costs nothing; lookup tables are the foundation,
not a hack
- if you make it "clearer" but 2x slower, it's not clearer, it's worse
### 5. Never suppress the truth
No casts to silence warnings. No `-Wno-*` flags to make the noise go
away. No `void*` where a real type exists. If the type system is
fighting you, you're fighting the design. Fix the design.
### 6. The codebase is one file. Keep it that way.
`src/main.c` is one file and it will stay one file. GNU wc needs
forty-two translation units and a build system with its own mailing
list. We have one file and we can read all of it in one sitting. If your
feature needs a new file, your feature is over-engineered.
### 7. Tests are the benchmarks
There is no separate test suite, because the benchmark *is* the test
suite — it checks correctness against GNU wc (the only oracle around,
and it's wrong often enough to keep us humble) and speed in the same
breath. Add a flag? It gets benchmarked. Change the counting? It gets
benchmarked. The fail-fast scripts in `benchmarks/` are your tests, and
all of them must pass before you open a PR.
### 8. No AI slop
If it looks like ChatGPT wrote it, it gets rejected. We can tell. Write
code like a human who's been doing this for a decade and is tired of
GNU's excuses.
## How to contribute
### Pick something
Good first issues:
- Benchmark case coverage for `-m` and multiple files
- Move the 1B-line monster behind a flag so quick CI runs stay quick
Ambitious issues:
- A word counter that doesn't just beat GNU — it embarrasses it
- Wider strides, less patience, and a 10B-line monster
### Send a PR
1. Fork the repo
2. Create a branch: `feat/my-thing` or `fix/my-bug`
3. Write code that follows the rules above
4. Run `./benchmarks/test-all.sh` — everything must pass
5. Open a PR against `main`
### PR requirements
- Build must pass with zero warnings: `make && make release`
- Benchmarks must pass: `./benchmarks/test-all.sh`
- Follow [STYLEGUIDE.md](STYLEGUIDE.md). The style is the law.
- No commented-out code. No dead code. No TODO without a date.
- Commit messages in imperative: `Count newlines in 8-byte strides` not
`Added newline counting optimization`
## What we won't merge
- **Anything slower than GNU wc.** We didn't come this far to tie.
- **Dependencies.** If it needs a library, it needs to not need a library.
- **GNU-style bloat.** Long options with help strings in fourteen
languages. Translation infrastructure. "Enterprise" anything. This is
a word counter, not a CRM.
- **Abstract nonsense.** Three layers of indirection to add a feature
means the feature is too complicated. GNU wc is what happens when you
let abstractions win.
- **AI slop.** See rule 8.
## Communication
We don't have a Discord. We don't have a forum. We don't have a mailing
list with a code of conduct and a weekly digest. Open an issue. Write a
clear title, a reproduction case, and what you expected. We'll respond
when we respond.
If you want to propose a major feature, open an issue first. Surprise
PRs that rewrite the counting loops get closed without review — the
benchmark is the referee, and it doesn't know you.
---
fastwc is 0.1.0. Everything is subject to change except the rules above.