hashcodecs 1.2.1__tar.gz → 1.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/.gitignore +3 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/BENCHMARK.md +81 -6
- hashcodecs-1.4.0/CHANGELOG.md +209 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/CITATION.cff +2 -2
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/Cargo.lock +16 -5
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/Cargo.toml +8 -19
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/PKG-INFO +44 -24
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/README.md +43 -23
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/SAFETY.md +9 -0
- hashcodecs-1.4.0/benches/Cargo.toml +37 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/benches/base64.rs +18 -12
- hashcodecs-1.4.0/benches/crossover.rs +90 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/benches/murmur3.rs +1 -5
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/benches/support/mod.rs +2 -0
- hashcodecs-1.4.0/benches/xxhash.rs +246 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/build.rs +1 -0
- hashcodecs-1.4.0/docs/ARCHITECTURE.md +218 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/docs/api/base64.md +2 -2
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/docs/api/murmur3.md +1 -1
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/docs/api/xxh3.md +1 -1
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/docs/performance.md +4 -4
- hashcodecs-1.4.0/docs/requirements.txt +2 -0
- hashcodecs-1.4.0/generated/rust/binding_schema.rs +1759 -0
- hashcodecs-1.4.0/generated/rust/murmur3_classes.rs +34 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/hashcodecs/__init__.py +2 -2
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/hashcodecs/__init__.pyi +1 -1
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/hashcodecs/_hashcodecs.pyi +126 -102
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/hashcodecs/base64.py +2 -2
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/hashcodecs/base64.pyi +1 -1
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/hashcodecs/murmur3.py +2 -2
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/hashcodecs/murmur3.pyi +1 -1
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/hashcodecs/xxhash.py +2 -2
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/hashcodecs/xxhash.pyi +1 -1
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/hatch_build.py +58 -6
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/pyproject.toml +21 -9
- hashcodecs-1.4.0/src/backend.rs +178 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/base64/alphabet.rs +14 -8
- hashcodecs-1.4.0/src/base64/backend.rs +103 -0
- hashcodecs-1.4.0/src/base64/decode/aarch64.rs +354 -0
- hashcodecs-1.4.0/src/base64/decode/avx2.rs +338 -0
- hashcodecs-1.4.0/src/base64/decode/avx512.rs +355 -0
- hashcodecs-1.4.0/src/base64/decode/sse41.rs +129 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/base64/decode/ssse3.rs +117 -38
- hashcodecs-1.4.0/src/base64/decode/tables.rs +58 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/base64/decode/x86_contracts.rs +37 -4
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/base64/decode.rs +259 -79
- hashcodecs-1.4.0/src/base64/encode/aarch64.rs +274 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/base64/encode/avx2.rs +335 -128
- hashcodecs-1.4.0/src/base64/encode/avx512.rs +309 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/base64/encode/cache.rs +6 -0
- hashcodecs-1.4.0/src/base64/encode/ssse3.rs +165 -0
- hashcodecs-1.4.0/src/base64/encode.rs +627 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/base64/miri_tests.rs +2 -0
- hashcodecs-1.4.0/src/base64/output_buffer.rs +21 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/base64/proofs.rs +2 -0
- hashcodecs-1.4.0/src/base64/runtime_dispatch.rs +918 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/base64/tests/aarch64.rs +45 -7
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/base64/tests.rs +711 -66
- hashcodecs-1.4.0/src/base64.rs +59 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/bindings/arguments.rs +6 -73
- hashcodecs-1.4.0/src/bindings/base64/api.rs +308 -0
- hashcodecs-1.4.0/src/bindings/base64/batch.rs +450 -0
- hashcodecs-1.4.0/src/bindings/base64/configured.rs +800 -0
- hashcodecs-1.4.0/src/bindings/base64/configured_tests.rs +911 -0
- hashcodecs-1.4.0/src/bindings/base64/decode.rs +648 -0
- hashcodecs-1.4.0/src/bindings/base64/encode.rs +679 -0
- hashcodecs-1.4.0/src/bindings/base64/lenient.rs +549 -0
- hashcodecs-1.4.0/src/bindings/base64/policy.rs +463 -0
- hashcodecs-1.4.0/src/bindings/base64/scan/aarch64.rs +112 -0
- hashcodecs-1.4.0/src/bindings/base64/scan/scalar.rs +60 -0
- hashcodecs-1.4.0/src/bindings/base64/scan/x86.rs +296 -0
- hashcodecs-1.4.0/src/bindings/base64/scan.rs +182 -0
- hashcodecs-1.4.0/src/bindings/base64/staging.rs +380 -0
- hashcodecs-1.4.0/src/bindings/base64/strict.rs +274 -0
- hashcodecs-1.4.0/src/bindings/base64.rs +14 -0
- hashcodecs-1.4.0/src/bindings/buffer.rs +750 -0
- hashcodecs-1.4.0/src/bindings/compatibility.rs +113 -0
- hashcodecs-1.4.0/src/bindings/murmur3/callbacks.rs +85 -0
- hashcodecs-1.4.0/src/bindings/murmur3/digest.rs +37 -0
- hashcodecs-1.4.0/src/bindings/murmur3/incremental.rs +123 -0
- hashcodecs-1.4.0/src/bindings/murmur3/methods.rs +20 -0
- hashcodecs-1.2.1/src/bindings/murmur3/mod.rs → hashcodecs-1.4.0/src/bindings/murmur3.rs +1 -1
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/bindings/objects.rs +54 -35
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/bindings/runtime.rs +3 -1
- hashcodecs-1.4.0/src/bindings/schema.rs +234 -0
- hashcodecs-1.4.0/src/bindings/xxhash/batch.rs +472 -0
- hashcodecs-1.4.0/src/bindings/xxhash/callbacks.rs +122 -0
- hashcodecs-1.4.0/src/bindings/xxhash/methods.rs +20 -0
- hashcodecs-1.4.0/src/bindings/xxhash.rs +5 -0
- hashcodecs-1.2.1/src/bindings/mod.rs → hashcodecs-1.4.0/src/bindings.rs +2 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/lib.rs +4 -5
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3/block_buffer.rs +7 -3
- hashcodecs-1.4.0/src/murmur3/dispatch.rs +53 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3/primitives.rs +2 -3
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3/tests.rs +93 -63
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3/x64_128/x86.rs +29 -30
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3/x64_128.rs +53 -48
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3/x86_128/x86.rs +44 -36
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3/x86_128.rs +41 -41
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3/x86_32/x86.rs +25 -27
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3/x86_32.rs +43 -43
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3.rs +2 -3
- hashcodecs-1.4.0/src/xxhash/batch.rs +543 -0
- {hashcodecs-1.2.1/src/xxhash/long → hashcodecs-1.4.0/src/xxhash/long_inputs}/aarch64.rs +49 -16
- hashcodecs-1.4.0/src/xxhash/long_inputs/scalar.rs +75 -0
- {hashcodecs-1.2.1/src/xxhash/long → hashcodecs-1.4.0/src/xxhash/long_inputs}/x86/avx2.rs +42 -20
- {hashcodecs-1.2.1/src/xxhash/long → hashcodecs-1.4.0/src/xxhash/long_inputs}/x86/avx2_batch.rs +21 -15
- {hashcodecs-1.2.1/src/xxhash/long → hashcodecs-1.4.0/src/xxhash/long_inputs}/x86/avx512.rs +20 -8
- {hashcodecs-1.2.1/src/xxhash/long → hashcodecs-1.4.0/src/xxhash/long_inputs}/x86/ssse3.rs +21 -8
- hashcodecs-1.2.1/src/xxhash/long.rs → hashcodecs-1.4.0/src/xxhash/long_inputs.rs +166 -138
- hashcodecs-1.4.0/src/xxhash/one_shot.rs +76 -0
- hashcodecs-1.4.0/src/xxhash/prepared.rs +136 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/xxhash/primitives.rs +47 -12
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/xxhash/proofs.rs +13 -7
- hashcodecs-1.4.0/src/xxhash/short_inputs.rs +279 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/xxhash/tests.rs +182 -44
- hashcodecs-1.4.0/src/xxhash.rs +25 -0
- hashcodecs-1.4.0/tools/generate_api_metadata.py +412 -0
- hashcodecs-1.4.0/tools/install_local_wheel.py +30 -0
- hashcodecs-1.4.0/tools/verify_sdist.py +127 -0
- hashcodecs-1.2.1/CHANGELOG.md +0 -141
- hashcodecs-1.2.1/benches/xxhash.rs +0 -141
- hashcodecs-1.2.1/docs/ARCHITECTURE.md +0 -198
- hashcodecs-1.2.1/docs/benchmarks/base64-python-batch-large.svg +0 -85
- hashcodecs-1.2.1/docs/benchmarks/base64-python-batch-reusable.svg +0 -106
- hashcodecs-1.2.1/docs/benchmarks/base64-python-batch.svg +0 -313
- hashcodecs-1.2.1/docs/benchmarks/base64-python-lenient.svg +0 -127
- hashcodecs-1.2.1/docs/benchmarks/base64-python-memoryview.svg +0 -159
- hashcodecs-1.2.1/docs/benchmarks/base64-python-mutable.svg +0 -83
- hashcodecs-1.2.1/docs/benchmarks/base64-python-reusable.svg +0 -115
- hashcodecs-1.2.1/docs/benchmarks/base64-python.svg +0 -203
- hashcodecs-1.2.1/docs/benchmarks/base64-rust.svg +0 -203
- hashcodecs-1.2.1/docs/benchmarks/murmur3-python-mutable.svg +0 -169
- hashcodecs-1.2.1/docs/benchmarks/murmur3-python.svg +0 -235
- hashcodecs-1.2.1/docs/benchmarks/murmur3-rust.svg +0 -193
- hashcodecs-1.2.1/docs/benchmarks/performance-at-a-glance.svg +0 -37
- hashcodecs-1.2.1/docs/benchmarks/results.csv +0 -527
- hashcodecs-1.2.1/docs/benchmarks/xxh3-python.svg +0 -181
- hashcodecs-1.2.1/docs/benchmarks/xxh3-rust-batch-remainders.svg +0 -139
- hashcodecs-1.2.1/docs/benchmarks/xxh3-rust.svg +0 -169
- hashcodecs-1.2.1/docs/requirements.txt +0 -2
- hashcodecs-1.2.1/src/backend.rs +0 -241
- hashcodecs-1.2.1/src/base64/backend.rs +0 -94
- hashcodecs-1.2.1/src/base64/decode/aarch64.rs +0 -225
- hashcodecs-1.2.1/src/base64/decode/avx2.rs +0 -182
- hashcodecs-1.2.1/src/base64/decode/avx512.rs +0 -117
- hashcodecs-1.2.1/src/base64/decode/sse41.rs +0 -51
- hashcodecs-1.2.1/src/base64/dispatch.rs +0 -346
- hashcodecs-1.2.1/src/base64/encode/aarch64.rs +0 -113
- hashcodecs-1.2.1/src/base64/encode/avx512.rs +0 -132
- hashcodecs-1.2.1/src/base64/encode/ssse3.rs +0 -86
- hashcodecs-1.2.1/src/base64/encode.rs +0 -321
- hashcodecs-1.2.1/src/base64/output.rs +0 -17
- hashcodecs-1.2.1/src/base64.rs +0 -55
- hashcodecs-1.2.1/src/bindings/base64/callbacks.rs +0 -755
- hashcodecs-1.2.1/src/bindings/base64/decode/plan.rs +0 -176
- hashcodecs-1.2.1/src/bindings/base64/decode.rs +0 -1686
- hashcodecs-1.2.1/src/bindings/base64/encode.rs +0 -221
- hashcodecs-1.2.1/src/bindings/base64/methods.rs +0 -678
- hashcodecs-1.2.1/src/bindings/base64/mod.rs +0 -499
- hashcodecs-1.2.1/src/bindings/buffer.rs +0 -400
- hashcodecs-1.2.1/src/bindings/murmur3/digest.rs +0 -25
- hashcodecs-1.2.1/src/bindings/murmur3/incremental.rs +0 -383
- hashcodecs-1.2.1/src/bindings/murmur3/methods.rs +0 -103
- hashcodecs-1.2.1/src/bindings/murmur3/one_shot.rs +0 -86
- hashcodecs-1.2.1/src/bindings/xxhash/batch.rs +0 -270
- hashcodecs-1.2.1/src/bindings/xxhash/methods.rs +0 -201
- hashcodecs-1.2.1/src/bindings/xxhash/mod.rs +0 -195
- hashcodecs-1.2.1/src/murmur3/dispatch.rs +0 -51
- hashcodecs-1.2.1/src/xxhash/batch.rs +0 -282
- hashcodecs-1.2.1/src/xxhash/hash.rs +0 -71
- hashcodecs-1.2.1/src/xxhash/long/scalar.rs +0 -53
- hashcodecs-1.2.1/src/xxhash/short.rs +0 -177
- hashcodecs-1.2.1/src/xxhash.rs +0 -28
- hashcodecs-1.2.1/tools/generate_api_metadata.py +0 -235
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/LICENSE +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/LICENSE-MIT +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/SECURITY.md +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/docs/base64.md +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/docs/compatibility.md +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/docs/index.md +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/docs/murmur3.md +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/docs/xxh3.md +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/hashcodecs/py.typed +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/base64/error.rs +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3/miri_tests.rs +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/murmur3/proofs.rs +0 -0
- /hashcodecs-1.2.1/src/xxhash/long/x86/mod.rs → /hashcodecs-1.4.0/src/xxhash/long_inputs/x86.rs +0 -0
- {hashcodecs-1.2.1 → hashcodecs-1.4.0}/src/xxhash/miri_tests.rs +0 -0
|
@@ -6,9 +6,13 @@ Pin one logical CPU. Run each case in one thread. Collect 50 Rust samples and 15
|
|
|
6
6
|
baseline with AVX2, the backend that hashcodecs selects on this host. Higher throughput wins.
|
|
7
7
|
|
|
8
8
|
Build the Python wheel with CPython 3.12 and the full C API. Keep competitor values from the latest comparison run.
|
|
9
|
-
Use `uv run python benchmarks/render_charts.py` to render the charts. Read exact values in
|
|
9
|
+
Use `uv run --python 3.12 --no-project python benchmarks/render_charts.py` to render the charts. Read exact values in
|
|
10
10
|
[docs/benchmarks/results.csv](docs/benchmarks/results.csv).
|
|
11
11
|
|
|
12
|
+
The standard and URL-safe Python decode panels report CPython 3.12.10 measurements from 2026-09-09; the lenient
|
|
13
|
+
decode chart retains its 2026-09-05 measurements. Each value is the median of 15 samples lasting at least 0.2
|
|
14
|
+
seconds each, with one logical CPU pinned.
|
|
15
|
+
|
|
12
16
|
## Timing Controls
|
|
13
17
|
|
|
14
18
|
Every Python benchmark accepts `--samples` (default: 15) and `--minimum-sample-seconds` (default: 0.2). Their
|
|
@@ -16,12 +20,16 @@ sampling time per case is at least their product, plus calibration; use lower va
|
|
|
16
20
|
hashcodecs-only pass, use `--hashcodecs-only --samples 3 --minimum-sample-seconds 0.05` with each Python benchmark
|
|
17
21
|
script.
|
|
18
22
|
|
|
23
|
+
Each Rust Criterion harness collects 50 samples per case. Pass Criterion's `--sample-size` option for an exploratory
|
|
24
|
+
run with a different count.
|
|
25
|
+
|
|
19
26
|
## Python Call Costs
|
|
20
27
|
|
|
21
28
|
Run `python benchmarks/python_calls.py` to measure positional calls from 0 through 256 bytes in nanoseconds per
|
|
22
29
|
call. Use `--keywords` for positional and keyword calls at 64 bytes, or `--thresholds` for latency around the
|
|
23
30
|
GIL-detachment cutoffs. The `--thread-scaling` mode measures aggregate throughput with one, two, and four threads;
|
|
24
|
-
it does not pin the process to one logical CPU.
|
|
31
|
+
it does not pin the process to one logical CPU. Use `--buffer-inputs` to compare 64-byte and 4 KiB XXH3-64 calls
|
|
32
|
+
across bytes, full and sliced memoryviews, writable and non-contiguous views, and `array('B')`.
|
|
25
33
|
|
|
26
34
|
## XXH3
|
|
27
35
|
|
|
@@ -30,10 +38,38 @@ For Python, run the upstream `xxhash` extension beside hashcodecs. Pass 32 equal
|
|
|
30
38
|
The Rust remainder cases pass two or three equal-size long inputs. Run Python remainder cases with
|
|
31
39
|
`python benchmarks/python_xxhash.py --batch-counts 2 3`.
|
|
32
40
|
|
|
41
|
+
To measure a branch against its parent, build both extensions with the same Python and Rust toolchains, then run:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
uv run --frozen --no-sync python benchmarks/compare_xxh3_batches.py path/to/parent/_hashcodecs.pyd path/to/branch/_hashcodecs.pyd
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Use the corresponding `.so` paths on Linux or macOS. The comparison loads both builds into one interpreter, pins
|
|
48
|
+
one CPU, and alternates their timing order across 15 samples. It checks matching digests and covers bytes,
|
|
49
|
+
bytearrays, and writable memoryviews. Use `--batch-counts 2 9 32 33 --sizes 64` to inspect small batches and the
|
|
50
|
+
32-result stack boundary. Positive `change_percent` values mean higher branch throughput.
|
|
51
|
+
|
|
52
|
+
The [32-item parent comparison](docs/benchmarks/xxh3-batch-parent-comparison.csv) records CPython 3.12.10 results
|
|
53
|
+
against parent commit `f17ab86`, measured on 2026-09-05. These paired measurements also cover the 256 KiB
|
|
54
|
+
GIL-detachment threshold and 1 MiB items. The Python XXH3 chart uses the candidate's allocating-batch measurements;
|
|
55
|
+
packed-output and upstream values retain their prior measurements.
|
|
56
|
+
|
|
57
|
+
Across the 30 paired 32-item cases, branch throughput ranges from 2.59% lower to 2.70% higher than the parent.
|
|
58
|
+
The [stack-boundary comparison](docs/benchmarks/xxh3-batch-boundary-comparison.csv) covers counts 2 and 33 with
|
|
59
|
+
64-byte items: two-item bytearray batches lose 5.40–6.05%, and 33-item bytes batches lose 6.06–7.05%. These
|
|
60
|
+
measurements show residual overhead for some small-input batches; they do not establish zero regression.
|
|
61
|
+
|
|
62
|
+
The Rust mixed benchmarks use `[1024, 1024, 4096, 4096]`, `[257, 258, 259, 260]`, `[240, 240, 241, 241]`, and the
|
|
63
|
+
reverse boundary order. The 1024/4096 case measures adjacent two-item long runs. The 257–260 case measures a
|
|
64
|
+
four-item run with one shared stripe count and distinct final stripes. The 240/241 cases measure both orders across
|
|
65
|
+
the short/long dispatch boundary.
|
|
66
|
+
|
|
33
67
|
Use the focused one-shot run to cover the AVX2 four-chain boundaries:
|
|
34
68
|
|
|
35
69
|
```sh
|
|
36
|
-
cargo bench --bench xxhash --
|
|
70
|
+
cargo bench --manifest-path benches/Cargo.toml --bench xxhash -- "xxh3_(64|128)/(240|241|512|768|1024|1536|2048|4096)/hashcodecs"
|
|
71
|
+
cargo bench --manifest-path benches/Cargo.toml --bench xxhash -- "xxh3_batch/mixed/.*/hashcodecs_(64|128)"
|
|
72
|
+
cargo bench --manifest-path benches/Cargo.toml --bench xxhash -- "xxh3_prepared"
|
|
37
73
|
```
|
|
38
74
|
|
|
39
75
|
[](docs/benchmarks/xxh3-rust.svg)
|
|
@@ -55,11 +91,17 @@ noisy cases insert `!` at the same boundaries. Both cases measure returned bytes
|
|
|
55
91
|
|
|
56
92
|
[](docs/benchmarks/base64-python-lenient.svg)
|
|
57
93
|
|
|
94
|
+
## Wrapped Python Base64
|
|
95
|
+
|
|
96
|
+
Run `python benchmarks/python_base64.py --wrapped` with CPython 3.15 or newer. The benchmark inserts newlines after
|
|
97
|
+
76 output characters and measures returned bytes and a reusable `bytearray`.
|
|
98
|
+
|
|
58
99
|
## Python Memoryview Inputs
|
|
59
100
|
|
|
60
|
-
Use `--memoryview-input` for full immutable views and `--sliced-memoryview-input` for equal-length views
|
|
61
|
-
nonzero starting offset.
|
|
62
|
-
|
|
101
|
+
Use `--memoryview-input` for full immutable views and `--sliced-memoryview-input` for equal-length contiguous views
|
|
102
|
+
with a nonzero starting offset. Full views can recover their exact immutable owner at detachment sizes; slices cover
|
|
103
|
+
offset-buffer handling, which borrows under the GIL and stabilizes the input in free-threaded builds. The encoded data
|
|
104
|
+
remains identical.
|
|
63
105
|
|
|
64
106
|
[](docs/benchmarks/base64-python-memoryview.svg)
|
|
65
107
|
|
|
@@ -76,6 +118,15 @@ into a decode investigation:
|
|
|
76
118
|
python benchmarks/python_base64_batch.py --item-sizes 4096 --batch-sizes 512 768 1024 1280 2048 --decode-only
|
|
77
119
|
```
|
|
78
120
|
|
|
121
|
+
Add `--memoryview-input` to wrap every matrix input in an exact memoryview. This mode compares independent views
|
|
122
|
+
against the matching one-item loops and reusable-output paths.
|
|
123
|
+
|
|
124
|
+
[](docs/benchmarks/base64-python-batch-memoryview.svg)
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
python benchmarks/python_base64_batch.py --item-sizes 1048576 --batch-sizes 8 --memoryview-input --decode-only
|
|
128
|
+
```
|
|
129
|
+
|
|
79
130
|
Use a single operation when recording a sampling profile, or compare traced allocations without a sampler:
|
|
80
131
|
|
|
81
132
|
```sh
|
|
@@ -118,3 +169,27 @@ Pass `bytearray` inputs to the Base64 API.
|
|
|
118
169
|
Pass `bytearray` inputs to the MurmurHash3 API.
|
|
119
170
|
|
|
120
171
|
[](docs/benchmarks/murmur3-python-mutable.svg)
|
|
172
|
+
|
|
173
|
+
## Reproduction
|
|
174
|
+
|
|
175
|
+
Run the benchmark
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
uv sync --python 3.12 --frozen --group benchmark --no-install-project
|
|
179
|
+
|
|
180
|
+
uv run --python 3.12 --refresh-package hashcodecs --no-project --with . --with mmh3==5.2.1 --with pybase64==1.4.3 --with xxhash==3.8.1 python benchmarks/python_base64.py --hashcodecs-only
|
|
181
|
+
|
|
182
|
+
uv run --python 3.12 --refresh-package hashcodecs --no-project --with . --with mmh3==5.2.1 --with pybase64==1.4.3 --with xxhash==3.8.1 python benchmarks/python_base64_batch.py --hashcodecs-only
|
|
183
|
+
|
|
184
|
+
uv run --python 3.12 --refresh-package hashcodecs --no-project --with . --with mmh3==5.2.1 --with pybase64==1.4.3 --with xxhash==3.8.1 python benchmarks/python_murmur3.py --hashcodecs-only
|
|
185
|
+
|
|
186
|
+
uv run --python 3.12 --refresh-package hashcodecs --no-project --with . --with mmh3==5.2.1 --with pybase64==1.4.3 --with xxhash==3.8.1 python benchmarks/python_murmur3.py --hashcodecs-only --incremental
|
|
187
|
+
|
|
188
|
+
uv run --python 3.12 --refresh-package hashcodecs --no-project --with . --with mmh3==5.2.1 --with pybase64==1.4.3 --with xxhash==3.8.1 python benchmarks/python_xxhash.py --hashcodecs-only
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Update the documentation
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
uv run --python 3.12 --no-project python benchmarks/render_charts.py
|
|
195
|
+
```
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
This file records notable user-facing changes to `hashcodecs`. Version 1.0.0 starts the stable Python API policy.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [1.4.0] - 2026-09-10
|
|
8
|
+
|
|
9
|
+
### What's Changed
|
|
10
|
+
* refactor: flatten internal module layout by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/91
|
|
11
|
+
* refactor: prepare Base64 decoder policies once by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/92
|
|
12
|
+
* refactor: consolidate binding and dispatch cleanup by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/93
|
|
13
|
+
* refactor: simplify project module layout by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/94
|
|
14
|
+
* refactor: prepare codec policies and unify bindings by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/95
|
|
15
|
+
* refactor: accelerate Base64 codec hot paths by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/96
|
|
16
|
+
* fix: protect XXH3 batches from GC reentrancy by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/97
|
|
17
|
+
* refactor: unify Base64 decode execution by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/98
|
|
18
|
+
* refactor: flatten Base64 binding ownership by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/99
|
|
19
|
+
* refactor: improve XXH3 loads and internal naming by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/100
|
|
20
|
+
* refactor: reduce Base64 decoder setup and retry costs by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/101
|
|
21
|
+
* fix: preserve Base64 decode boundaries and restore ARM coverage by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/102
|
|
22
|
+
* refactor: keep XXH3 AVX2 tail chains in registers by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/103
|
|
23
|
+
* refactor: store AVX2 Base64 vectors in smaller groups by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/104
|
|
24
|
+
* fix: reduce Python overhead and align canonical decoding by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/106
|
|
25
|
+
* refactor: reduce cached AVX2 encoder setup by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/107
|
|
26
|
+
* feat: optimize XXH3 seeded and batch hashing by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/108
|
|
27
|
+
* Optimize AVX2 Base64 decoding by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/109
|
|
28
|
+
* refactor: optimize Python batch orchestration by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/110
|
|
29
|
+
* feat: optimize XXH3 batches and wrapped Base64 by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/111
|
|
30
|
+
* Fuse Base64 SIMD lookup paths and Murmur3 hex output by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/112
|
|
31
|
+
* fix: preserve custom alphabets and batch typing by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/113
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
**Full Changelog**: https://github.com/kozistr/hashcodecs-rs/compare/v1.3.0...v1.4.0
|
|
35
|
+
|
|
36
|
+
## [1.3.0] - 2026-09-04
|
|
37
|
+
|
|
38
|
+
### What's Changed
|
|
39
|
+
* chore: expand XXH3 benchmark coverage by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/61
|
|
40
|
+
* refactor: split Base64 decoder bindings by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/62
|
|
41
|
+
* refactor: declare Base64 binding schema by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/63
|
|
42
|
+
* perf: inspect exact CPython memoryviews directly by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/64
|
|
43
|
+
* refactor: avoid copying Base64 fallback inputs by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/65
|
|
44
|
+
* chore: strengthen runtime coverage and benchmarks by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/66
|
|
45
|
+
* fix: avoid unnecessary batch snapshots and scalar grouping by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/67
|
|
46
|
+
* refactor: generate Base64 binding metadata by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/68
|
|
47
|
+
* perf: remove advanced decode and batch allocations by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/69
|
|
48
|
+
* refactor: finish native codec cleanup by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/70
|
|
49
|
+
* chore: verify source distributions in CI by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/71
|
|
50
|
+
* fix: stabilize aliased Base64 decode inputs by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/72
|
|
51
|
+
* perf: remove Python batch input copies by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/73
|
|
52
|
+
* fix: use strict fast paths for decode-into by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/74
|
|
53
|
+
* refactor: streamline native bindings and benchmarks by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/75
|
|
54
|
+
* fix: restore XXH fast paths and wheel compatibility by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/76
|
|
55
|
+
* refactor: use four-lane AArch64 XXH3 accumulation by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/77
|
|
56
|
+
* refactor: clarify internal names and technical prose by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/78
|
|
57
|
+
* fix: restore Base64 batch encode throughput by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/79
|
|
58
|
+
* refactor: clarify internal naming by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/80
|
|
59
|
+
* refactor: simplify internal decode and dispatch paths by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/81
|
|
60
|
+
* fix: harden hashers and optimize codec paths by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/82
|
|
61
|
+
* refactor: centralize Python Base64 decode routing by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/83
|
|
62
|
+
* refactor: standardize Rust callback and input names by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/84
|
|
63
|
+
* refactor: clarify codec routing and CPU capabilities by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/85
|
|
64
|
+
* refactor: consolidate base64 batch ownership by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/86
|
|
65
|
+
* refactor: reduce XXH3 dispatch overhead by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/87
|
|
66
|
+
* Fix Base64 batch alias stabilization and AVX2 streaming stores by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/88
|
|
67
|
+
* fix: restore Base64 encode fast paths by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/89
|
|
68
|
+
* fix: restore Base64 memoryview batch throughput by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/90
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
**Full Changelog**: https://github.com/kozistr/hashcodecs-rs/compare/v1.2.1...v1.3.0
|
|
72
|
+
|
|
73
|
+
## [1.2.1] - 2026-08-26
|
|
74
|
+
|
|
75
|
+
### What's Changed
|
|
76
|
+
* fix: harden buffer and lenient decode paths by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/58
|
|
77
|
+
* Refactor Murmur SIMD and centralize XXH3 long dispatch by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/59
|
|
78
|
+
* Repair sdist verification and roll back unpublished 1.2.1 by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/60
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
**Full Changelog**: https://github.com/kozistr/hashcodecs-rs/compare/v1.2.0...v1.2.1
|
|
82
|
+
|
|
83
|
+
## [1.2.0] - 2026-08-25
|
|
84
|
+
|
|
85
|
+
### What's Changed
|
|
86
|
+
* fix: harden free-threaded bindings and API correctness by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/47
|
|
87
|
+
* feat: accelerate Python batch outputs by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/48
|
|
88
|
+
* feat: add native lenient Base64 decoding by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/49
|
|
89
|
+
* update: tune Python detach thresholds by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/50
|
|
90
|
+
* fix: harden Base64 binding edge cases by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/51
|
|
91
|
+
* fix: stabilize Base64 GIL release test by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/52
|
|
92
|
+
* feat: accelerate XXH3 batch remainders by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/53
|
|
93
|
+
* perf: refresh Base64 batch benchmarks by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/54
|
|
94
|
+
* perf: accelerate XXH3 long inputs by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/55
|
|
95
|
+
* perf: profile Base64 batch allocations by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/56
|
|
96
|
+
* refactor: organize Python binding infrastructure by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/57
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
**Full Changelog**: https://github.com/kozistr/hashcodecs-rs/compare/v1.1.0...v1.2.0
|
|
100
|
+
|
|
101
|
+
## [1.1.0] - 2026-08-23
|
|
102
|
+
|
|
103
|
+
### What's Changed
|
|
104
|
+
* chore: use trusted publishing for crates.io by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/44
|
|
105
|
+
* refactor: establish clean architecture boundaries by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/45
|
|
106
|
+
* feat: borrow contiguous Python buffers by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/46
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
**Full Changelog**: https://github.com/kozistr/hashcodecs-rs/compare/v1.0.0...v1.1.0
|
|
110
|
+
|
|
111
|
+
## [1.0.0] - 2026-08-22
|
|
112
|
+
|
|
113
|
+
### What's Changed
|
|
114
|
+
* Expand Python and Rust API documentation by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/36
|
|
115
|
+
* feat: move base64 batch aliases into Rust by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/37
|
|
116
|
+
* feat: support free-threaded Python wheels by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/38
|
|
117
|
+
* Update benchmark and Python support docs by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/39
|
|
118
|
+
* chore: reduce CI runner usage and latency by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/40
|
|
119
|
+
* build: prepare 1.0 release by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/41
|
|
120
|
+
* build: publish Rust crate from release workflow by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/42
|
|
121
|
+
* feat: expose namespaced Rust API by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/43
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
**Full Changelog**: https://github.com/kozistr/hashcodecs-rs/compare/v0.6.1...v1.0.0
|
|
125
|
+
|
|
126
|
+
## [0.6.1] - 2026-08-22
|
|
127
|
+
|
|
128
|
+
### Added
|
|
129
|
+
|
|
130
|
+
- Reusable output buffers for XXH3 batch operations.
|
|
131
|
+
- A Read the Docs site with Python and Rust API documentation.
|
|
132
|
+
|
|
133
|
+
## [0.6.0] - 2026-08-21
|
|
134
|
+
|
|
135
|
+
### Added
|
|
136
|
+
|
|
137
|
+
- SIMD-accelerated XXH3-64 and XXH3-128 APIs.
|
|
138
|
+
- Native one-shot and batch bindings built on the full CPython API.
|
|
139
|
+
|
|
140
|
+
### Changed
|
|
141
|
+
|
|
142
|
+
- Faster Base64 and XXH3 hot paths, including small XXH3 inputs and large AVX2 Base64 inputs.
|
|
143
|
+
- One runtime dispatch layer now selects SIMD backends for each codec and hash implementation.
|
|
144
|
+
|
|
145
|
+
## [0.5.0] - 2026-08-12
|
|
146
|
+
|
|
147
|
+
### Added
|
|
148
|
+
|
|
149
|
+
- Batch Base64 APIs that write into caller-provided buffers.
|
|
150
|
+
|
|
151
|
+
### Changed
|
|
152
|
+
|
|
153
|
+
- Faster unpadded Base64 and Python decoding paths with fewer aligned-input copies.
|
|
154
|
+
- Release validation now runs before packaging and publication.
|
|
155
|
+
|
|
156
|
+
## [0.4.0] - 2026-08-10
|
|
157
|
+
|
|
158
|
+
### Added
|
|
159
|
+
|
|
160
|
+
- CPython 3.15 support.
|
|
161
|
+
- Native Base64 batch APIs.
|
|
162
|
+
|
|
163
|
+
### Changed
|
|
164
|
+
|
|
165
|
+
- Faster SIMD Base64 codecs and mutable Python buffer handling.
|
|
166
|
+
- Simpler URL-safe Base64 wrappers.
|
|
167
|
+
|
|
168
|
+
## [0.3.0] - 2026-08-09
|
|
169
|
+
|
|
170
|
+
### Added
|
|
171
|
+
|
|
172
|
+
- Reusable Python output buffers for allocation-sensitive Base64 operations.
|
|
173
|
+
|
|
174
|
+
### Changed
|
|
175
|
+
|
|
176
|
+
- Faster AVX2 Base64 decoding and SIMD encoding paths.
|
|
177
|
+
|
|
178
|
+
## [0.2.0] - 2026-08-09
|
|
179
|
+
|
|
180
|
+
### Added
|
|
181
|
+
|
|
182
|
+
- Incremental MurmurHash3 hashers.
|
|
183
|
+
- SIMD implementations for each MurmurHash3 variant and additional codec backends.
|
|
184
|
+
|
|
185
|
+
### Fixed
|
|
186
|
+
|
|
187
|
+
- Short NEON Base64 blocks and scalar backend detection on non-x86 systems.
|
|
188
|
+
|
|
189
|
+
## [0.1.0] - 2026-08-09
|
|
190
|
+
|
|
191
|
+
### Added
|
|
192
|
+
|
|
193
|
+
- Initial Python and Rust APIs for Base64 and MurmurHash3.
|
|
194
|
+
- Runtime SIMD dispatch and platform-specific CPython wheels.
|
|
195
|
+
|
|
196
|
+
[Unreleased]: https://github.com/kozistr/hashcodecs-rs/compare/v1.4.0...HEAD
|
|
197
|
+
[1.4.0]: https://github.com/kozistr/hashcodecs-rs/compare/v1.3.0...v1.4.0
|
|
198
|
+
[1.3.0]: https://github.com/kozistr/hashcodecs-rs/compare/v1.2.1...v1.3.0
|
|
199
|
+
[1.2.1]: https://github.com/kozistr/hashcodecs-rs/compare/v1.2.0...v1.2.1
|
|
200
|
+
[1.2.0]: https://github.com/kozistr/hashcodecs-rs/compare/v1.1.0...v1.2.0
|
|
201
|
+
[1.1.0]: https://github.com/kozistr/hashcodecs-rs/compare/v1.0.0...v1.1.0
|
|
202
|
+
[1.0.0]: https://github.com/kozistr/hashcodecs-rs/compare/v0.6.1...v1.0.0
|
|
203
|
+
[0.6.1]: https://github.com/kozistr/hashcodecs-rs/compare/v0.6.0...v0.6.1
|
|
204
|
+
[0.6.0]: https://github.com/kozistr/hashcodecs-rs/compare/v0.5.0...v0.6.0
|
|
205
|
+
[0.5.0]: https://github.com/kozistr/hashcodecs-rs/compare/v0.4.0...v0.5.0
|
|
206
|
+
[0.4.0]: https://github.com/kozistr/hashcodecs-rs/compare/v0.3.0...v0.4.0
|
|
207
|
+
[0.3.0]: https://github.com/kozistr/hashcodecs-rs/compare/v0.2.0...v0.3.0
|
|
208
|
+
[0.2.0]: https://github.com/kozistr/hashcodecs-rs/compare/v0.1.0...v0.2.0
|
|
209
|
+
[0.1.0]: https://github.com/kozistr/hashcodecs-rs/tree/v0.1.0
|
|
@@ -5,8 +5,8 @@ authors:
|
|
|
5
5
|
given-names: Hyeongchan
|
|
6
6
|
orcid: https://orcid.org/0000-0002-1729-0580
|
|
7
7
|
title: "hashcodecs: SIMD-accelerated Base64, MurmurHash3, and XXH3 for Python and Rust"
|
|
8
|
-
version: 1.
|
|
9
|
-
date-released: 2026-
|
|
8
|
+
version: 1.4.0
|
|
9
|
+
date-released: 2026-09-10
|
|
10
10
|
license: "MIT OR Apache-2.0"
|
|
11
11
|
repository-code: "https://github.com/kozistr/hashcodecs-rs"
|
|
12
12
|
url: "https://github.com/kozistr/hashcodecs-rs"
|
|
@@ -194,21 +194,32 @@ dependencies = [
|
|
|
194
194
|
|
|
195
195
|
[[package]]
|
|
196
196
|
name = "hashcodecs"
|
|
197
|
-
version = "1.
|
|
197
|
+
version = "1.4.0"
|
|
198
|
+
dependencies = [
|
|
199
|
+
"base64",
|
|
200
|
+
"memchr",
|
|
201
|
+
"mimalloc",
|
|
202
|
+
"murmur3",
|
|
203
|
+
"pyo3",
|
|
204
|
+
"pyo3-build-config",
|
|
205
|
+
"xxhash-c-sys",
|
|
206
|
+
"xxhash-rust",
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
[[package]]
|
|
210
|
+
name = "hashcodecs-benchmarks"
|
|
211
|
+
version = "0.0.0"
|
|
198
212
|
dependencies = [
|
|
199
213
|
"base64",
|
|
200
214
|
"base64-turbo",
|
|
201
215
|
"criterion",
|
|
202
216
|
"fastmurmur3",
|
|
203
|
-
"
|
|
217
|
+
"hashcodecs",
|
|
204
218
|
"mimalloc",
|
|
205
219
|
"mm3h",
|
|
206
220
|
"murmur3",
|
|
207
221
|
"murmurs",
|
|
208
|
-
"pyo3",
|
|
209
|
-
"pyo3-build-config",
|
|
210
222
|
"xxhash-c-sys",
|
|
211
|
-
"xxhash-rust",
|
|
212
223
|
]
|
|
213
224
|
|
|
214
225
|
[[package]]
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "hashcodecs"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.4.0"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
rust-version = "1.89"
|
|
6
|
+
autobenches = false
|
|
6
7
|
description = "SIMD-accelerated Base64 codecs and fast MurmurHash3 and xxHash implementations"
|
|
7
8
|
license = "MIT OR Apache-2.0"
|
|
8
9
|
repository = "https://github.com/kozistr/hashcodecs-rs"
|
|
@@ -10,6 +11,7 @@ keywords = ["base64", "simd", "murmur3", "xxhash", "python"]
|
|
|
10
11
|
categories = ["encoding", "algorithms"]
|
|
11
12
|
readme = "README.md"
|
|
12
13
|
include = [
|
|
14
|
+
"/generated/**",
|
|
13
15
|
"/src/**",
|
|
14
16
|
"/benches/**",
|
|
15
17
|
"/tests/sanitizers.rs",
|
|
@@ -19,6 +21,11 @@ include = [
|
|
|
19
21
|
"/LICENSE-MIT",
|
|
20
22
|
]
|
|
21
23
|
|
|
24
|
+
[workspace]
|
|
25
|
+
members = [".", "benches"]
|
|
26
|
+
default-members = ["."]
|
|
27
|
+
resolver = "3"
|
|
28
|
+
|
|
22
29
|
[lib]
|
|
23
30
|
name = "hashcodecs"
|
|
24
31
|
crate-type = ["rlib", "cdylib"]
|
|
@@ -37,28 +44,10 @@ pyo3-build-config = { version = "0.29.2", optional = true }
|
|
|
37
44
|
|
|
38
45
|
[dev-dependencies]
|
|
39
46
|
base64 = "=0.23.1"
|
|
40
|
-
base64-turbo = "=0.3.0"
|
|
41
|
-
criterion = { version = "=0.8.2", default-features = false, features = ["cargo_bench_support"] }
|
|
42
|
-
fastmurmur3 = "=0.2.0"
|
|
43
|
-
mimalloc = "=0.1.52"
|
|
44
|
-
mm3h = "=0.1.3"
|
|
45
47
|
murmur3 = "=0.5.2"
|
|
46
|
-
murmurs = "=1.0.5"
|
|
47
48
|
xxhash-c-sys = "=0.8.7"
|
|
48
49
|
xxhash-rust = { version = "=0.8.18", features = ["xxh3"] }
|
|
49
50
|
|
|
50
|
-
[[bench]]
|
|
51
|
-
name = "base64"
|
|
52
|
-
harness = false
|
|
53
|
-
|
|
54
|
-
[[bench]]
|
|
55
|
-
name = "murmur3"
|
|
56
|
-
harness = false
|
|
57
|
-
|
|
58
|
-
[[bench]]
|
|
59
|
-
name = "xxhash"
|
|
60
|
-
harness = false
|
|
61
|
-
|
|
62
51
|
[[test]]
|
|
63
52
|
name = "sanitizers"
|
|
64
53
|
path = "tests/sanitizers.rs"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hashcodecs
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: SIMD-accelerated Base64, MurmurHash3, and xxHash codecs
|
|
5
5
|
Project-URL: Documentation, https://hashcodecs-rs.readthedocs.io/
|
|
6
6
|
Project-URL: Repository, https://github.com/kozistr/hashcodecs-rs
|
|
@@ -43,20 +43,20 @@ Description-Content-Type: text/markdown
|
|
|
43
43
|
|
|
44
44
|
<p align="center">
|
|
45
45
|
<a href="BENCHMARK.md">
|
|
46
|
-
<img src="docs/benchmarks/performance-at-a-glance.svg" alt="CPython 3.12
|
|
46
|
+
<img src="docs/benchmarks/performance-at-a-glance.svg" alt="CPython 3.12 standard Base64 encoding and decoding benchmark">
|
|
47
47
|
</a>
|
|
48
48
|
</p>
|
|
49
49
|
|
|
50
50
|
SIMD-accelerated Base64, MurmurHash3, and XXH3 for Python and Rust.
|
|
51
51
|
|
|
52
52
|
Move byte-heavy work into Rust without changing your Python inputs. `hashcodecs` accepts `bytes`, `bytearray`, and
|
|
53
|
-
`memoryview`, selects the
|
|
53
|
+
`memoryview`, selects the highest-priority supported SIMD backend, and exposes batch and reusable-buffer APIs.
|
|
54
54
|
|
|
55
55
|
## Features
|
|
56
56
|
|
|
57
57
|
- Base64 encode and decode with standard, URL-safe, padded, unpadded, wrapped, and canonical modes.
|
|
58
58
|
- MurmurHash3 x86-32, x86-128, and x64-128 with one-shot and incremental APIs.
|
|
59
|
-
- Bit-for-bit compatible XXH3-64 and XXH3-128 with
|
|
59
|
+
- Bit-for-bit compatible XXH3-64 and XXH3-128 with prepared seeds and allocating and allocation-free native batch APIs.
|
|
60
60
|
- Caller-managed `*_into` outputs for allocation-sensitive workloads.
|
|
61
61
|
- Runtime dispatch across AVX-512, AVX2, SSE4.1, SSSE3, NEON, and scalar implementations where applicable.
|
|
62
62
|
- Direct CPython buffer handling for `bytes`, `bytearray`, and `memoryview` inputs.
|
|
@@ -146,17 +146,36 @@ assert_eq!(
|
|
|
146
146
|
hashcodecs::xxhash::xxh3_64(b"", 0),
|
|
147
147
|
0x2d06_8005_38d3_94c2
|
|
148
148
|
);
|
|
149
|
+
|
|
150
|
+
let seeded_input = vec![7; 1024];
|
|
151
|
+
let prepared = hashcodecs::xxhash::PreparedXxh3::new(42);
|
|
152
|
+
assert_eq!(
|
|
153
|
+
prepared.hash_64(&seeded_input),
|
|
154
|
+
hashcodecs::xxhash::xxh3_64(&seeded_input, 42)
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
let inputs: &[&[u8]] = &[b"hello", b"world"];
|
|
158
|
+
assert_eq!(
|
|
159
|
+
prepared.hash_64_batch(inputs),
|
|
160
|
+
hashcodecs::xxhash::xxh3_64_batch(inputs, 42)
|
|
161
|
+
);
|
|
162
|
+
let mut hashes = [0_u64; 2];
|
|
163
|
+
let mut index = 0;
|
|
164
|
+
hashcodecs::xxhash::xxh3_64_batch_for_each(inputs, 0, |hash| {
|
|
165
|
+
hashes[index] = hash;
|
|
166
|
+
index += 1;
|
|
167
|
+
});
|
|
168
|
+
assert_eq!(index, inputs.len());
|
|
149
169
|
```
|
|
150
170
|
|
|
151
171
|
## Architecture
|
|
152
172
|
|
|
153
|
-
The Rust core owns algorithm behavior and SIMD dispatch.
|
|
154
|
-
|
|
155
|
-
adding per-call wrappers.
|
|
173
|
+
The Rust core owns algorithm behavior and SIMD dispatch. The CPython layer handles argument parsing, buffers,
|
|
174
|
+
reusable outputs, and GIL decisions. Root-level Python modules provide typed exports without per-call wrappers.
|
|
156
175
|
|
|
157
|
-
Each Rust algorithm exposes a small public
|
|
176
|
+
Each Rust algorithm exposes a small public module. Base64 groups internals by encode and decode operation and
|
|
158
177
|
places ISA kernels such as `encode/avx2.rs` and `decode/ssse3.rs` under their operation. MurmurHash3 groups code by
|
|
159
|
-
canonical variant. XXH3 uses processing-stage modules
|
|
178
|
+
canonical variant. XXH3 uses processing-stage modules. Long-input ISA kernels are under `xxhash/long_inputs/`.
|
|
160
179
|
|
|
161
180
|
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the module layout, dispatch model, algorithm data flows,
|
|
162
181
|
CPython boundary, and safety invariants.
|
|
@@ -206,9 +225,10 @@ Read the focused cases, commands, and values in [BENCHMARK.md](BENCHMARK.md). Re
|
|
|
206
225
|
Comparison crates and Python packages are development-only dependencies and are not included in consumer builds.
|
|
207
226
|
|
|
208
227
|
```sh
|
|
209
|
-
cargo bench --bench base64
|
|
210
|
-
cargo bench --bench murmur3
|
|
211
|
-
cargo bench --bench xxhash
|
|
228
|
+
cargo bench --manifest-path benches/Cargo.toml --bench base64
|
|
229
|
+
cargo bench --manifest-path benches/Cargo.toml --bench murmur3
|
|
230
|
+
cargo bench --manifest-path benches/Cargo.toml --bench xxhash
|
|
231
|
+
cargo bench --manifest-path benches/Cargo.toml --bench crossover
|
|
212
232
|
|
|
213
233
|
uv sync --group benchmark --no-install-project
|
|
214
234
|
uv run --no-project --with . python benchmarks/python_base64.py
|
|
@@ -219,22 +239,24 @@ uv run --no-project --with . python benchmarks/python_xxhash.py
|
|
|
219
239
|
```
|
|
220
240
|
|
|
221
241
|
The Python benchmarks expose focused modes such as `--into`, `--lenient`, `--bytearray-input`, `--memoryview-input`,
|
|
222
|
-
`--sliced-memoryview-input`, `--incremental`, `--large`, and `--hashcodecs-only`. All scripts also
|
|
223
|
-
`--minimum-sample-seconds`; use `--help` on a benchmark script for its supported modes and
|
|
242
|
+
`--sliced-memoryview-input`, `--buffer-inputs`, `--incremental`, `--large`, and `--hashcodecs-only`. All scripts also
|
|
243
|
+
accept `--samples` and `--minimum-sample-seconds`; use `--help` on a benchmark script for its supported modes and
|
|
244
|
+
defaults.
|
|
224
245
|
|
|
225
246
|
For the same-ISA Windows XXH3 comparison shown above, rebuild the C baseline with:
|
|
226
247
|
|
|
227
248
|
```powershell
|
|
228
249
|
$env:CFLAGS='/O2 /arch:AVX2'
|
|
229
250
|
cargo clean -p xxhash-c-sys
|
|
230
|
-
cargo bench --bench xxhash
|
|
251
|
+
cargo bench --manifest-path benches/Cargo.toml --bench xxhash
|
|
231
252
|
```
|
|
232
253
|
|
|
233
254
|
## Performance snapshot
|
|
234
255
|
|
|
235
|
-
In the
|
|
236
|
-
|
|
237
|
-
decode.
|
|
256
|
+
In the focused 2026-09-09 hashcodecs-only run on the benchmark host, `hashcodecs.xxh3_64` processes a 1 MiB input
|
|
257
|
+
at 91.27 GiB/s. In the full 2026-09-02 run, the Base64 batch API reaches 11.84 GiB/s for encode and 6.23 GiB/s for
|
|
258
|
+
decode with 256 B items in batches of 64. Each run pins one logical CPU and uses 15 samples with a 0.2-second
|
|
259
|
+
minimum per sample. Read the
|
|
238
260
|
[benchmark details](BENCHMARK.md) and [raw comparison results](docs/benchmarks/results.csv).
|
|
239
261
|
|
|
240
262
|
## Development
|
|
@@ -248,14 +270,12 @@ uv build
|
|
|
248
270
|
Run the primary local checks:
|
|
249
271
|
|
|
250
272
|
```sh
|
|
251
|
-
|
|
252
|
-
cargo clippy --all-targets --features python -- -D warnings
|
|
253
|
-
cargo test --features python
|
|
254
|
-
uv run --frozen --no-sync ruff check . --no-cache
|
|
255
|
-
uv run --frozen --no-sync ruff format --check .
|
|
256
|
-
uv run --frozen --no-sync pytest tests --cov=hashcodecs --cov-branch --cov-fail-under=100
|
|
273
|
+
just check
|
|
257
274
|
```
|
|
258
275
|
|
|
276
|
+
`just check` builds and reinstalls the current wheel before running Python tests. Run `just full-check` before
|
|
277
|
+
committing to also check release builds, Rust core coverage, and the extracted source distribution.
|
|
278
|
+
|
|
259
279
|
Optimized paths are also checked with differential fuzzing, Kani, strict-provenance Miri, AddressSanitizer, and
|
|
260
280
|
MemorySanitizer in CI.
|
|
261
281
|
|