An optimized wc implementation in Zig, 5-20x faster than GNU and BSD wc. zwc achieves this by using a finite-state machine to process UTF-8 text branchlessly, and by implementing data parallelism to distribute the work across multiple CPU cores.
This is not intended as a complete replacement for the GNU or BSD wc programs. It's missing some of the features, like the --max-line-length flag. Additionally, it only supports ASCII and UTF-8 encodings.
This program is based heavily on Robert Graham's wc2 program.
Here is what the core loop looks like:
const table: [State.STATE_MAX][256]u8 = gen_table(); var counts = [_]usize{0} ** State.STATE_MAX; var state: usize = State.WASSPACE; // initial state while (true) { const b = file.takeByte() catch break; state = table[state][b]; counts[state] += 1; }
Development
For the simple version of the state machine, see simple.zig.
For the UTF-8 version of the state machine, see dfa.zig.
For the parallel version, see parallel.zig.
Building
This project currently only compiles with the 0.15.2 version of Zig.
# Build the binary into ./zig-out/bin/zwc zig build -Doptimize=ReleaseFast # Alternatively, you can use `just`: just build-exe ~/.local/bin/zwc # build into local path
Benchmarks
Here are some benchmarks from the english and chinese wikipedia title dumps, which are 165MB text files with lots of words and lines. Programs (in order): zwc, BSD wc, GNU wc, Rust uutils/coreutils wc.
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
./zwc enwiki-20260301-all-titles |
40.8 ± 1.2 | 39.6 | 46.8 | 1.00 |
wc enwiki-20260301-all-titles |
233.5 ± 10.8 | 227.5 | 266.8 | 5.73 ± 0.31 |
gwc enwiki-20260301-all-titles |
274.5 ± 5.9 | 271.7 | 291.1 | 6.74 ± 0.24 |
uutils-wc enwiki-20260301-all-titles |
260.7 ± 11.6 | 232.9 | 268.8 | 6.40 ± 0.34 |
Same-size file with mostly chinese characters. The -lwm flags tell the programs to count lines, words, and multibyte characters.
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
./zwc -lwm zhwiki-latest-all-titles |
40.3 ± 1.1 | 39.3 | 46.4 | 1.00 |
wc -lwm zhwiki-latest-all-titles |
832.5 ± 1.4 | 829.1 | 834.0 | 20.64 ± 0.55 |
gwc -lwm zhwiki-latest-all-titles |
702.0 ± 1.6 | 699.2 | 704.5 | 17.41 ± 0.47 |
uutils-wc -lwm zhwiki-latest-all-titles |
285.5 ± 9.1 | 275.1 | 295.6 | 7.08 ± 0.29 |
See justfile bench_all and bench_all_multibyte.