hashcodecs 0.3.0__tar.gz → 0.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-0.4.0/BENCHMARK.md +71 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/Cargo.lock +1 -1
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/Cargo.toml +1 -1
- hashcodecs-0.4.0/PKG-INFO +190 -0
- hashcodecs-0.4.0/README.md +170 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/pyproject.toml +8 -1
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/python/hashcodecs/__init__.py +12 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/python/hashcodecs/_hashcodecs.pyi +31 -4
- hashcodecs-0.4.0/python/hashcodecs/base64.py +89 -0
- hashcodecs-0.4.0/python/hashcodecs/base64.pyi +54 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/src/base64/aarch64.rs +44 -45
- hashcodecs-0.4.0/src/base64/x86.rs +822 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/src/base64/x86_avx512.rs +14 -39
- hashcodecs-0.4.0/src/python/base64/encode.rs +163 -0
- hashcodecs-0.4.0/src/python/base64.rs +792 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/src/python/buffer.rs +37 -12
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/src/python/murmur3.rs +28 -49
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/src/python.rs +5 -1
- hashcodecs-0.3.0/PKG-INFO +0 -202
- hashcodecs-0.3.0/README.md +0 -188
- hashcodecs-0.3.0/python/hashcodecs/base64.py +0 -59
- hashcodecs-0.3.0/python/hashcodecs/base64.pyi +0 -23
- hashcodecs-0.3.0/src/base64/x86.rs +0 -651
- hashcodecs-0.3.0/src/python/base64.rs +0 -335
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/.gitignore +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/LICENSE +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/LICENSE-MIT +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/benches/base64.rs +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/benches/murmur3.rs +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/benches/support/mod.rs +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/build.rs +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/hatch_build.py +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/python/hashcodecs/murmur3.py +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/python/hashcodecs/py.typed +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/src/base64/dispatch.rs +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/src/base64.rs +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/src/lib.rs +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/src/murmur3/dispatch.rs +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/src/murmur3/x86.rs +0 -0
- {hashcodecs-0.3.0 → hashcodecs-0.4.0}/src/murmur3.rs +0 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Benchmark Details
|
|
2
|
+
|
|
3
|
+
Environment: Windows 10 x64 and Intel Core Ultra 7 265K.
|
|
4
|
+
|
|
5
|
+
Conditions: clean builds, one pinned logical CPU, single-threaded execution, and 15 Python samples. Higher is better.
|
|
6
|
+
|
|
7
|
+
## Reusable Python Buffers
|
|
8
|
+
|
|
9
|
+
| Alphabet | Input | Operation | hashcodecs |
|
|
10
|
+
| --- | --- | --- | ---: |
|
|
11
|
+
| Standard | 4 KiB | encode | **15.09 GiB/s** |
|
|
12
|
+
| | 4 KiB | decode | **18.43 GiB/s** |
|
|
13
|
+
| | 1 MiB | encode | **39.66 GiB/s** |
|
|
14
|
+
| | 1 MiB | decode | **29.03 GiB/s** |
|
|
15
|
+
| | 32 MiB | encode | **10.89 GiB/s** |
|
|
16
|
+
| | 32 MiB | decode | **10.36 GiB/s** |
|
|
17
|
+
| URL-safe | 4 KiB | encode | **14.83 GiB/s** |
|
|
18
|
+
| | 4 KiB | decode | **12.26 GiB/s** |
|
|
19
|
+
| | 1 MiB | encode | **39.71 GiB/s** |
|
|
20
|
+
| | 1 MiB | decode | **20.72 GiB/s** |
|
|
21
|
+
| | 32 MiB | encode | **10.84 GiB/s** |
|
|
22
|
+
| | 32 MiB | decode | **10.44 GiB/s** |
|
|
23
|
+
|
|
24
|
+
## Python Base64 Batches
|
|
25
|
+
|
|
26
|
+
Each value is total input throughput; the parenthesized figure is items per second. Higher is better.
|
|
27
|
+
|
|
28
|
+
| Item | Batch | Operation | hashcodecs | hashcodecs loop | pybase64 loop | CPython loop |
|
|
29
|
+
| ---: | ---: | --- | ---: | ---: | ---: | ---: |
|
|
30
|
+
| 16 B | 8 | encode | **0.41 GiB/s (27.42M)** | 0.27 GiB/s (18.11M) | 0.13 GiB/s (8.45M) | 0.18 GiB/s (12.37M) |
|
|
31
|
+
| | | decode | **0.36 GiB/s (24.24M)** | 0.21 GiB/s (14.13M) | 0.08 GiB/s (5.44M) | 0.12 GiB/s (7.85M) |
|
|
32
|
+
| 16 B | 64 | encode | **0.55 GiB/s (36.69M)** | 0.31 GiB/s (20.81M) | 0.14 GiB/s (9.17M) | 0.21 GiB/s (13.81M) |
|
|
33
|
+
| | | decode | **0.49 GiB/s (32.86M)** | 0.24 GiB/s (16.13M) | 0.09 GiB/s (5.87M) | 0.13 GiB/s (8.63M) |
|
|
34
|
+
| 16 B | 1,024 | encode | **0.56 GiB/s (37.26M)** | 0.31 GiB/s (20.64M) | 0.14 GiB/s (9.07M) | 0.20 GiB/s (13.73M) |
|
|
35
|
+
| | | decode | **0.49 GiB/s (32.70M)** | 0.25 GiB/s (16.60M) | 0.09 GiB/s (5.95M) | 0.13 GiB/s (8.71M) |
|
|
36
|
+
| 256 B | 8 | encode | 1.77 GiB/s (7.43M) | 1.52 GiB/s (6.38M) | **1.93 GiB/s (8.08M)** | 0.40 GiB/s (1.67M) |
|
|
37
|
+
| | | decode | **5.03 GiB/s (21.12M)** | 3.02 GiB/s (12.66M) | 1.22 GiB/s (5.12M) | 0.76 GiB/s (3.19M) |
|
|
38
|
+
| 256 B | 64 | encode | 1.92 GiB/s (8.05M) | 1.62 GiB/s (6.82M) | **2.02 GiB/s (8.48M)** | 0.41 GiB/s (1.71M) |
|
|
39
|
+
| | | decode | **6.09 GiB/s (25.56M)** | 3.36 GiB/s (14.07M) | 1.29 GiB/s (5.40M) | 0.76 GiB/s (3.18M) |
|
|
40
|
+
| 256 B | 1,024 | encode | 1.92 GiB/s (8.05M) | 1.63 GiB/s (6.82M) | **1.99 GiB/s (8.35M)** | 0.40 GiB/s (1.69M) |
|
|
41
|
+
| | | decode | **5.87 GiB/s (24.61M)** | 3.30 GiB/s (13.83M) | 1.29 GiB/s (5.43M) | 0.76 GiB/s (3.17M) |
|
|
42
|
+
| 4 KiB | 8 | encode | **15.12 GiB/s (3.96M)** | 13.72 GiB/s (3.60M) | 12.69 GiB/s (3.33M) | 0.48 GiB/s (0.13M) |
|
|
43
|
+
| | | decode | **19.20 GiB/s (5.03M)** | 16.52 GiB/s (4.33M) | 8.29 GiB/s (2.17M) | 1.13 GiB/s (0.30M) |
|
|
44
|
+
| 4 KiB | 64 | encode | **12.59 GiB/s (3.30M)** | 11.55 GiB/s (3.03M) | 9.54 GiB/s (2.50M) | 0.48 GiB/s (0.12M) |
|
|
45
|
+
| | | decode | **18.95 GiB/s (4.97M)** | 16.12 GiB/s (4.23M) | 8.12 GiB/s (2.13M) | 1.12 GiB/s (0.29M) |
|
|
46
|
+
| 4 KiB | 1,024 | encode | 5.84 GiB/s (1.53M) | **8.81 GiB/s (2.31M)** | 7.83 GiB/s (2.05M) | 0.47 GiB/s (0.12M) |
|
|
47
|
+
| | | decode | 3.52 GiB/s (0.92M) | **3.81 GiB/s (1.00M)** | 2.99 GiB/s (0.79M) | 0.92 GiB/s (0.24M) |
|
|
48
|
+
|
|
49
|
+
## Mutable Python Inputs
|
|
50
|
+
|
|
51
|
+
### Base64
|
|
52
|
+
|
|
53
|
+
| Input | Operation | Returned `bytes` | Reusable `bytearray` |
|
|
54
|
+
| --- | --- | ---: | ---: |
|
|
55
|
+
| 4 KiB | encode | 14.12 GiB/s | **15.16 GiB/s** |
|
|
56
|
+
| | decode | 16.76 GiB/s | **18.27 GiB/s** |
|
|
57
|
+
| 1 MiB | encode | 2.88 GiB/s | **38.96 GiB/s** |
|
|
58
|
+
| | decode | 3.59 GiB/s | **28.99 GiB/s** |
|
|
59
|
+
| 32 MiB | encode | 2.92 GiB/s | **10.83 GiB/s** |
|
|
60
|
+
| | decode | 3.44 GiB/s | **10.35 GiB/s** |
|
|
61
|
+
|
|
62
|
+
### MurmurHash3
|
|
63
|
+
|
|
64
|
+
| Variant | API | 4 KiB | 1 MiB | 32 MiB |
|
|
65
|
+
| --- | --- | ---: | ---: | ---: |
|
|
66
|
+
| x86 32-bit | one-shot | **3.79 GiB/s** | **3.98 GiB/s** | **3.97 GiB/s** |
|
|
67
|
+
| | incremental | **3.58 GiB/s** | **3.96 GiB/s** | **3.92 GiB/s** |
|
|
68
|
+
| x86 128-bit | one-shot | **8.09 GiB/s** | **9.22 GiB/s** | **9.12 GiB/s** |
|
|
69
|
+
| | incremental | **7.02 GiB/s** | **9.17 GiB/s** | **9.01 GiB/s** |
|
|
70
|
+
| x64 128-bit | one-shot | **8.68 GiB/s** | **10.10 GiB/s** | **9.54 GiB/s** |
|
|
71
|
+
| | incremental | **7.70 GiB/s** | **10.01 GiB/s** | **9.41 GiB/s** |
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hashcodecs
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: SIMD-accelerated Base64 and MurmurHash3 codecs
|
|
5
|
+
License-Expression: MIT OR Apache-2.0
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
License-File: LICENSE-MIT
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
16
|
+
Classifier: Programming Language :: Rust
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# hashcodecs
|
|
22
|
+
|
|
23
|
+
[](https://github.com/kozistr/hashcodecs-rs/actions/workflows/ci.yml)
|
|
24
|
+
[](https://pypi.org/project/hashcodecs/)
|
|
25
|
+
[](https://pypi.org/project/hashcodecs/)
|
|
26
|
+
[](https://github.com/kozistr/hashcodecs-rs#license)
|
|
27
|
+
[](https://pypi.org/project/hashcodecs/)
|
|
28
|
+
|
|
29
|
+
`hashcodecs` provides runtime-dispatched SIMD Base64 codecs and fast, reference-compatible MurmurHash3 functions for Rust and Python.
|
|
30
|
+
|
|
31
|
+
## Design
|
|
32
|
+
|
|
33
|
+
- Runtime-dispatched SIMD Base64 with portable scalar fallbacks.
|
|
34
|
+
- Reference-compatible MurmurHash3 with SIMD acceleration.
|
|
35
|
+
- Rust and Python `*_into` APIs for caller-managed output buffers.
|
|
36
|
+
- A familiar Python Base64 API, including native batch encode and decode operations.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
pip3 install hashcodecs
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Usage
|
|
45
|
+
|
|
46
|
+
### Rust
|
|
47
|
+
|
|
48
|
+
```rust
|
|
49
|
+
let encoded = hashcodecs::b64encode(b"hello");
|
|
50
|
+
assert_eq!(encoded, "aGVsbG8=");
|
|
51
|
+
|
|
52
|
+
let mut output = [0_u8; 8];
|
|
53
|
+
let written = hashcodecs::b64encode_into(b"hello", &mut output).unwrap();
|
|
54
|
+
assert_eq!(&output[..written], b"aGVsbG8=");
|
|
55
|
+
assert_eq!(hashcodecs::murmur3_x86_32(b"hello", 0), 0x248b_fa47);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Python
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import hashcodecs.base64 as base64
|
|
62
|
+
from hashcodecs import murmur3_32, murmur3_x64_128
|
|
63
|
+
|
|
64
|
+
assert base64.b64encode(b'hello') == b'aGVsbG8='
|
|
65
|
+
assert base64.b64decode(b'aGVsbG8=') == b'hello'
|
|
66
|
+
assert base64.b64encode_batch([b'hello', b'world']) == [b'aGVsbG8=', b'd29ybGQ=']
|
|
67
|
+
assert base64.b64decode_batch([b'aGVsbG8=', 'd29ybGQ=']) == [b'hello', b'world']
|
|
68
|
+
assert base64.b64encode(b'hello', padded=False) == b'aGVsbG8'
|
|
69
|
+
assert base64.b64decode(b'aGVsbG8', padded=False, canonical=True) == b'hello'
|
|
70
|
+
assert murmur3_32(b'hello') == 0x248BFA47
|
|
71
|
+
|
|
72
|
+
payload = b'hello'
|
|
73
|
+
encoded = bytearray(4 * ((len(payload) + 2) // 3))
|
|
74
|
+
encoded_len = base64.b64encode_into(payload, encoded)
|
|
75
|
+
decoded = bytearray(len(encoded))
|
|
76
|
+
decoded_len = base64.b64decode_into(encoded, decoded, validate=True)
|
|
77
|
+
assert encoded[:encoded_len] == b'aGVsbG8='
|
|
78
|
+
assert decoded[:decoded_len] == payload
|
|
79
|
+
|
|
80
|
+
hasher = murmur3_x64_128(seed=42)
|
|
81
|
+
hasher.update(b'hello')
|
|
82
|
+
assert hasher.hexdigest() == hasher.digest().hex()
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Build an installable wheel and source distribution with:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
uv build
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
# Benchmark
|
|
92
|
+
|
|
93
|
+
Environment: Windows 10 x64 and Intel Core Ultra 7 265K.
|
|
94
|
+
|
|
95
|
+
Conditions: clean builds, one pinned logical CPU, single-threaded execution, 50 Rust samples, and 15 Python samples. Returned-output allocation is included except in the reusable-buffer table. Higher is better.
|
|
96
|
+
|
|
97
|
+
## Run Locally
|
|
98
|
+
|
|
99
|
+
Comparison crates are development-only dependencies and are not included in consumer builds.
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
cargo bench --bench base64
|
|
103
|
+
cargo bench --bench murmur3
|
|
104
|
+
uv sync --group benchmark --no-install-project
|
|
105
|
+
uv run --no-project --with . python benchmarks/python_base64.py
|
|
106
|
+
uv run --no-project --with . python benchmarks/python_base64.py --into
|
|
107
|
+
uv run --no-project --with . python benchmarks/python_base64.py --bytearray-input
|
|
108
|
+
uv run --no-project --with . python benchmarks/python_base64_batch.py
|
|
109
|
+
uv run --no-project --with . python benchmarks/python_murmur3.py
|
|
110
|
+
uv run --no-project --with . python benchmarks/python_murmur3.py --incremental
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Base64: Rust
|
|
114
|
+
|
|
115
|
+
| Alphabet | Input | Operation | hashcodecs | `base64` | `base64-turbo` |
|
|
116
|
+
| --- | --- | --- | ---: | ---: | ---: |
|
|
117
|
+
| Standard | 4 KiB | encode | **20.41 GiB/s** | 5.81 GiB/s | 18.29 GiB/s |
|
|
118
|
+
| | 4 KiB | decode | **27.11 GiB/s** | 4.33 GiB/s | 16.95 GiB/s |
|
|
119
|
+
| | 1 MiB | encode | **42.38 GiB/s** | 5.16 GiB/s | 19.60 GiB/s |
|
|
120
|
+
| | 1 MiB | decode | **31.07 GiB/s** | 4.10 GiB/s | 18.17 GiB/s |
|
|
121
|
+
| | 32 MiB | encode | **11.97 GiB/s** | 3.28 GiB/s | 10.94 GiB/s |
|
|
122
|
+
| | 32 MiB | decode | **11.51 GiB/s** | 3.35 GiB/s | 10.45 GiB/s |
|
|
123
|
+
| URL-safe | 4 KiB | encode | **20.46 GiB/s** | 5.81 GiB/s | 18.31 GiB/s |
|
|
124
|
+
| | 4 KiB | decode | **25.65 GiB/s** | 4.35 GiB/s | 16.96 GiB/s |
|
|
125
|
+
| | 1 MiB | encode | **42.56 GiB/s** | 5.18 GiB/s | 19.66 GiB/s |
|
|
126
|
+
| | 1 MiB | decode | **29.42 GiB/s** | 4.08 GiB/s | 18.16 GiB/s |
|
|
127
|
+
| | 32 MiB | encode | **11.86 GiB/s** | 3.29 GiB/s | 11.09 GiB/s |
|
|
128
|
+
| | 32 MiB | decode | **11.67 GiB/s** | 3.36 GiB/s | 10.62 GiB/s |
|
|
129
|
+
|
|
130
|
+
## MurmurHash3: Rust
|
|
131
|
+
|
|
132
|
+
| Variant | Input | hashcodecs | `murmur3` | `murmurs` | `fastmurmur3` | `mm3h` |
|
|
133
|
+
| --- | --- | ---: | ---: | ---: | ---: | ---: |
|
|
134
|
+
| x86 32-bit | 4 KiB | **4.30 GiB/s** | 2.60 GiB/s | 4.09 GiB/s | n/a | **4.30 GiB/s** |
|
|
135
|
+
| | 1 MiB | **4.26 GiB/s** | 2.59 GiB/s | 4.04 GiB/s | n/a | 4.25 GiB/s |
|
|
136
|
+
| | 32 MiB | **4.21 GiB/s** | 2.54 GiB/s | 3.87 GiB/s | n/a | 4.03 GiB/s |
|
|
137
|
+
| x86 128-bit | 4 KiB | **9.54 GiB/s** | 4.97 GiB/s | 8.64 GiB/s | n/a | n/a |
|
|
138
|
+
| | 1 MiB | **9.84 GiB/s** | 5.06 GiB/s | 8.77 GiB/s | n/a | n/a |
|
|
139
|
+
| | 32 MiB | **9.63 GiB/s** | 4.84 GiB/s | 6.05 GiB/s | n/a | n/a |
|
|
140
|
+
| x64 128-bit | 4 KiB | **10.76 GiB/s** | 6.83 GiB/s | 9.45 GiB/s | 10.06 GiB/s | 9.54 GiB/s |
|
|
141
|
+
| | 1 MiB | **10.84 GiB/s** | 6.89 GiB/s | 9.51 GiB/s | 10.04 GiB/s | 9.51 GiB/s |
|
|
142
|
+
| | 32 MiB | **10.12 GiB/s** | 6.11 GiB/s | 6.64 GiB/s | 7.25 GiB/s | 6.70 GiB/s |
|
|
143
|
+
|
|
144
|
+
## Base64: Python
|
|
145
|
+
|
|
146
|
+
Python decoding uses `validate=True`, and `hashcodecs` passes `bytes` directly into Rust without an input copy.
|
|
147
|
+
|
|
148
|
+
| Alphabet | Input | Operation | hashcodecs | CPython `base64` | `pybase64` |
|
|
149
|
+
| --- | --- | --- | ---: | ---: | ---: |
|
|
150
|
+
| Standard | 4 KiB | encode | 13.57 GiB/s | 0.48 GiB/s | **14.06 GiB/s** |
|
|
151
|
+
| | 4 KiB | decode | **16.70 GiB/s** | 1.13 GiB/s | 8.47 GiB/s |
|
|
152
|
+
| | 1 MiB | encode | **3.28 GiB/s** | 0.44 GiB/s | 3.02 GiB/s |
|
|
153
|
+
| | 1 MiB | decode | **4.02 GiB/s** | 0.95 GiB/s | 3.68 GiB/s |
|
|
154
|
+
| | 32 MiB | encode | **2.92 GiB/s** | 0.43 GiB/s | 2.84 GiB/s |
|
|
155
|
+
| | 32 MiB | decode | 3.40 GiB/s | 0.94 GiB/s | **3.69 GiB/s** |
|
|
156
|
+
| URL-safe | 4 KiB | encode | **12.63 GiB/s** | 0.41 GiB/s | 1.19 GiB/s |
|
|
157
|
+
| | 4 KiB | decode | **11.34 GiB/s** | 0.76 GiB/s | 1.56 GiB/s |
|
|
158
|
+
| | 1 MiB | encode | **3.24 GiB/s** | 0.36 GiB/s | 0.91 GiB/s |
|
|
159
|
+
| | 1 MiB | decode | **4.15 GiB/s** | 0.63 GiB/s | 1.45 GiB/s |
|
|
160
|
+
| | 32 MiB | encode | **3.03 GiB/s** | 0.36 GiB/s | 0.90 GiB/s |
|
|
161
|
+
| | 32 MiB | decode | **3.40 GiB/s** | 0.61 GiB/s | 1.48 GiB/s |
|
|
162
|
+
|
|
163
|
+
## MurmurHash3: Python
|
|
164
|
+
|
|
165
|
+
| Variant | API | Input | hashcodecs | `mmh3` |
|
|
166
|
+
| --- | --- | --- | ---: | ---: |
|
|
167
|
+
| x86 32-bit | one-shot | 4 KiB | **3.79 GiB/s** | 3.71 GiB/s |
|
|
168
|
+
| | | 1 MiB | **3.98 GiB/s** | 3.83 GiB/s |
|
|
169
|
+
| | | 32 MiB | **3.97 GiB/s** | 3.66 GiB/s |
|
|
170
|
+
| | incremental | 4 KiB | **3.58 GiB/s** | **3.58 GiB/s** |
|
|
171
|
+
| | | 1 MiB | **3.96 GiB/s** | 3.81 GiB/s |
|
|
172
|
+
| | | 32 MiB | **3.92 GiB/s** | 3.74 GiB/s |
|
|
173
|
+
| x86 128-bit | one-shot | 4 KiB | 8.09 GiB/s | **8.21 GiB/s** |
|
|
174
|
+
| | | 1 MiB | **9.22 GiB/s** | 8.87 GiB/s |
|
|
175
|
+
| | | 32 MiB | **9.12 GiB/s** | 6.15 GiB/s |
|
|
176
|
+
| | incremental | 4 KiB | **7.02 GiB/s** | 0.77 GiB/s |
|
|
177
|
+
| | | 1 MiB | **9.17 GiB/s** | 0.80 GiB/s |
|
|
178
|
+
| | | 32 MiB | **9.01 GiB/s** | 0.79 GiB/s |
|
|
179
|
+
| x64 128-bit | one-shot | 4 KiB | 8.68 GiB/s | **9.46 GiB/s** |
|
|
180
|
+
| | | 1 MiB | 10.10 GiB/s | **10.24 GiB/s** |
|
|
181
|
+
| | | 32 MiB | **9.54 GiB/s** | 6.61 GiB/s |
|
|
182
|
+
| | incremental | 4 KiB | 7.70 GiB/s | **7.99 GiB/s** |
|
|
183
|
+
| | | 1 MiB | **10.01 GiB/s** | 9.28 GiB/s |
|
|
184
|
+
| | | 32 MiB | **9.41 GiB/s** | 7.34 GiB/s |
|
|
185
|
+
|
|
186
|
+
Reusable-buffer and mutable-input results are available in [BENCHMARK.md](https://github.com/kozistr/hashcodecs-rs/blob/main/BENCHMARK.md).
|
|
187
|
+
|
|
188
|
+
## SIMD References
|
|
189
|
+
|
|
190
|
+
The SIMD implementation follows the approach described in [Faster Base64 Encoding and Decoding using AVX2 Instructions](https://arxiv.org/abs/1704.00605), with AVX-512 VBMI and AArch64 NEON backends selected automatically when available.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# hashcodecs
|
|
2
|
+
|
|
3
|
+
[](https://github.com/kozistr/hashcodecs-rs/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/hashcodecs/)
|
|
5
|
+
[](https://pypi.org/project/hashcodecs/)
|
|
6
|
+
[](https://github.com/kozistr/hashcodecs-rs#license)
|
|
7
|
+
[](https://pypi.org/project/hashcodecs/)
|
|
8
|
+
|
|
9
|
+
`hashcodecs` provides runtime-dispatched SIMD Base64 codecs and fast, reference-compatible MurmurHash3 functions for Rust and Python.
|
|
10
|
+
|
|
11
|
+
## Design
|
|
12
|
+
|
|
13
|
+
- Runtime-dispatched SIMD Base64 with portable scalar fallbacks.
|
|
14
|
+
- Reference-compatible MurmurHash3 with SIMD acceleration.
|
|
15
|
+
- Rust and Python `*_into` APIs for caller-managed output buffers.
|
|
16
|
+
- A familiar Python Base64 API, including native batch encode and decode operations.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
pip3 install hashcodecs
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Rust
|
|
27
|
+
|
|
28
|
+
```rust
|
|
29
|
+
let encoded = hashcodecs::b64encode(b"hello");
|
|
30
|
+
assert_eq!(encoded, "aGVsbG8=");
|
|
31
|
+
|
|
32
|
+
let mut output = [0_u8; 8];
|
|
33
|
+
let written = hashcodecs::b64encode_into(b"hello", &mut output).unwrap();
|
|
34
|
+
assert_eq!(&output[..written], b"aGVsbG8=");
|
|
35
|
+
assert_eq!(hashcodecs::murmur3_x86_32(b"hello", 0), 0x248b_fa47);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Python
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import hashcodecs.base64 as base64
|
|
42
|
+
from hashcodecs import murmur3_32, murmur3_x64_128
|
|
43
|
+
|
|
44
|
+
assert base64.b64encode(b'hello') == b'aGVsbG8='
|
|
45
|
+
assert base64.b64decode(b'aGVsbG8=') == b'hello'
|
|
46
|
+
assert base64.b64encode_batch([b'hello', b'world']) == [b'aGVsbG8=', b'd29ybGQ=']
|
|
47
|
+
assert base64.b64decode_batch([b'aGVsbG8=', 'd29ybGQ=']) == [b'hello', b'world']
|
|
48
|
+
assert base64.b64encode(b'hello', padded=False) == b'aGVsbG8'
|
|
49
|
+
assert base64.b64decode(b'aGVsbG8', padded=False, canonical=True) == b'hello'
|
|
50
|
+
assert murmur3_32(b'hello') == 0x248BFA47
|
|
51
|
+
|
|
52
|
+
payload = b'hello'
|
|
53
|
+
encoded = bytearray(4 * ((len(payload) + 2) // 3))
|
|
54
|
+
encoded_len = base64.b64encode_into(payload, encoded)
|
|
55
|
+
decoded = bytearray(len(encoded))
|
|
56
|
+
decoded_len = base64.b64decode_into(encoded, decoded, validate=True)
|
|
57
|
+
assert encoded[:encoded_len] == b'aGVsbG8='
|
|
58
|
+
assert decoded[:decoded_len] == payload
|
|
59
|
+
|
|
60
|
+
hasher = murmur3_x64_128(seed=42)
|
|
61
|
+
hasher.update(b'hello')
|
|
62
|
+
assert hasher.hexdigest() == hasher.digest().hex()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Build an installable wheel and source distribution with:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
uv build
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
# Benchmark
|
|
72
|
+
|
|
73
|
+
Environment: Windows 10 x64 and Intel Core Ultra 7 265K.
|
|
74
|
+
|
|
75
|
+
Conditions: clean builds, one pinned logical CPU, single-threaded execution, 50 Rust samples, and 15 Python samples. Returned-output allocation is included except in the reusable-buffer table. Higher is better.
|
|
76
|
+
|
|
77
|
+
## Run Locally
|
|
78
|
+
|
|
79
|
+
Comparison crates are development-only dependencies and are not included in consumer builds.
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
cargo bench --bench base64
|
|
83
|
+
cargo bench --bench murmur3
|
|
84
|
+
uv sync --group benchmark --no-install-project
|
|
85
|
+
uv run --no-project --with . python benchmarks/python_base64.py
|
|
86
|
+
uv run --no-project --with . python benchmarks/python_base64.py --into
|
|
87
|
+
uv run --no-project --with . python benchmarks/python_base64.py --bytearray-input
|
|
88
|
+
uv run --no-project --with . python benchmarks/python_base64_batch.py
|
|
89
|
+
uv run --no-project --with . python benchmarks/python_murmur3.py
|
|
90
|
+
uv run --no-project --with . python benchmarks/python_murmur3.py --incremental
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Base64: Rust
|
|
94
|
+
|
|
95
|
+
| Alphabet | Input | Operation | hashcodecs | `base64` | `base64-turbo` |
|
|
96
|
+
| --- | --- | --- | ---: | ---: | ---: |
|
|
97
|
+
| Standard | 4 KiB | encode | **20.41 GiB/s** | 5.81 GiB/s | 18.29 GiB/s |
|
|
98
|
+
| | 4 KiB | decode | **27.11 GiB/s** | 4.33 GiB/s | 16.95 GiB/s |
|
|
99
|
+
| | 1 MiB | encode | **42.38 GiB/s** | 5.16 GiB/s | 19.60 GiB/s |
|
|
100
|
+
| | 1 MiB | decode | **31.07 GiB/s** | 4.10 GiB/s | 18.17 GiB/s |
|
|
101
|
+
| | 32 MiB | encode | **11.97 GiB/s** | 3.28 GiB/s | 10.94 GiB/s |
|
|
102
|
+
| | 32 MiB | decode | **11.51 GiB/s** | 3.35 GiB/s | 10.45 GiB/s |
|
|
103
|
+
| URL-safe | 4 KiB | encode | **20.46 GiB/s** | 5.81 GiB/s | 18.31 GiB/s |
|
|
104
|
+
| | 4 KiB | decode | **25.65 GiB/s** | 4.35 GiB/s | 16.96 GiB/s |
|
|
105
|
+
| | 1 MiB | encode | **42.56 GiB/s** | 5.18 GiB/s | 19.66 GiB/s |
|
|
106
|
+
| | 1 MiB | decode | **29.42 GiB/s** | 4.08 GiB/s | 18.16 GiB/s |
|
|
107
|
+
| | 32 MiB | encode | **11.86 GiB/s** | 3.29 GiB/s | 11.09 GiB/s |
|
|
108
|
+
| | 32 MiB | decode | **11.67 GiB/s** | 3.36 GiB/s | 10.62 GiB/s |
|
|
109
|
+
|
|
110
|
+
## MurmurHash3: Rust
|
|
111
|
+
|
|
112
|
+
| Variant | Input | hashcodecs | `murmur3` | `murmurs` | `fastmurmur3` | `mm3h` |
|
|
113
|
+
| --- | --- | ---: | ---: | ---: | ---: | ---: |
|
|
114
|
+
| x86 32-bit | 4 KiB | **4.30 GiB/s** | 2.60 GiB/s | 4.09 GiB/s | n/a | **4.30 GiB/s** |
|
|
115
|
+
| | 1 MiB | **4.26 GiB/s** | 2.59 GiB/s | 4.04 GiB/s | n/a | 4.25 GiB/s |
|
|
116
|
+
| | 32 MiB | **4.21 GiB/s** | 2.54 GiB/s | 3.87 GiB/s | n/a | 4.03 GiB/s |
|
|
117
|
+
| x86 128-bit | 4 KiB | **9.54 GiB/s** | 4.97 GiB/s | 8.64 GiB/s | n/a | n/a |
|
|
118
|
+
| | 1 MiB | **9.84 GiB/s** | 5.06 GiB/s | 8.77 GiB/s | n/a | n/a |
|
|
119
|
+
| | 32 MiB | **9.63 GiB/s** | 4.84 GiB/s | 6.05 GiB/s | n/a | n/a |
|
|
120
|
+
| x64 128-bit | 4 KiB | **10.76 GiB/s** | 6.83 GiB/s | 9.45 GiB/s | 10.06 GiB/s | 9.54 GiB/s |
|
|
121
|
+
| | 1 MiB | **10.84 GiB/s** | 6.89 GiB/s | 9.51 GiB/s | 10.04 GiB/s | 9.51 GiB/s |
|
|
122
|
+
| | 32 MiB | **10.12 GiB/s** | 6.11 GiB/s | 6.64 GiB/s | 7.25 GiB/s | 6.70 GiB/s |
|
|
123
|
+
|
|
124
|
+
## Base64: Python
|
|
125
|
+
|
|
126
|
+
Python decoding uses `validate=True`, and `hashcodecs` passes `bytes` directly into Rust without an input copy.
|
|
127
|
+
|
|
128
|
+
| Alphabet | Input | Operation | hashcodecs | CPython `base64` | `pybase64` |
|
|
129
|
+
| --- | --- | --- | ---: | ---: | ---: |
|
|
130
|
+
| Standard | 4 KiB | encode | 13.57 GiB/s | 0.48 GiB/s | **14.06 GiB/s** |
|
|
131
|
+
| | 4 KiB | decode | **16.70 GiB/s** | 1.13 GiB/s | 8.47 GiB/s |
|
|
132
|
+
| | 1 MiB | encode | **3.28 GiB/s** | 0.44 GiB/s | 3.02 GiB/s |
|
|
133
|
+
| | 1 MiB | decode | **4.02 GiB/s** | 0.95 GiB/s | 3.68 GiB/s |
|
|
134
|
+
| | 32 MiB | encode | **2.92 GiB/s** | 0.43 GiB/s | 2.84 GiB/s |
|
|
135
|
+
| | 32 MiB | decode | 3.40 GiB/s | 0.94 GiB/s | **3.69 GiB/s** |
|
|
136
|
+
| URL-safe | 4 KiB | encode | **12.63 GiB/s** | 0.41 GiB/s | 1.19 GiB/s |
|
|
137
|
+
| | 4 KiB | decode | **11.34 GiB/s** | 0.76 GiB/s | 1.56 GiB/s |
|
|
138
|
+
| | 1 MiB | encode | **3.24 GiB/s** | 0.36 GiB/s | 0.91 GiB/s |
|
|
139
|
+
| | 1 MiB | decode | **4.15 GiB/s** | 0.63 GiB/s | 1.45 GiB/s |
|
|
140
|
+
| | 32 MiB | encode | **3.03 GiB/s** | 0.36 GiB/s | 0.90 GiB/s |
|
|
141
|
+
| | 32 MiB | decode | **3.40 GiB/s** | 0.61 GiB/s | 1.48 GiB/s |
|
|
142
|
+
|
|
143
|
+
## MurmurHash3: Python
|
|
144
|
+
|
|
145
|
+
| Variant | API | Input | hashcodecs | `mmh3` |
|
|
146
|
+
| --- | --- | --- | ---: | ---: |
|
|
147
|
+
| x86 32-bit | one-shot | 4 KiB | **3.79 GiB/s** | 3.71 GiB/s |
|
|
148
|
+
| | | 1 MiB | **3.98 GiB/s** | 3.83 GiB/s |
|
|
149
|
+
| | | 32 MiB | **3.97 GiB/s** | 3.66 GiB/s |
|
|
150
|
+
| | incremental | 4 KiB | **3.58 GiB/s** | **3.58 GiB/s** |
|
|
151
|
+
| | | 1 MiB | **3.96 GiB/s** | 3.81 GiB/s |
|
|
152
|
+
| | | 32 MiB | **3.92 GiB/s** | 3.74 GiB/s |
|
|
153
|
+
| x86 128-bit | one-shot | 4 KiB | 8.09 GiB/s | **8.21 GiB/s** |
|
|
154
|
+
| | | 1 MiB | **9.22 GiB/s** | 8.87 GiB/s |
|
|
155
|
+
| | | 32 MiB | **9.12 GiB/s** | 6.15 GiB/s |
|
|
156
|
+
| | incremental | 4 KiB | **7.02 GiB/s** | 0.77 GiB/s |
|
|
157
|
+
| | | 1 MiB | **9.17 GiB/s** | 0.80 GiB/s |
|
|
158
|
+
| | | 32 MiB | **9.01 GiB/s** | 0.79 GiB/s |
|
|
159
|
+
| x64 128-bit | one-shot | 4 KiB | 8.68 GiB/s | **9.46 GiB/s** |
|
|
160
|
+
| | | 1 MiB | 10.10 GiB/s | **10.24 GiB/s** |
|
|
161
|
+
| | | 32 MiB | **9.54 GiB/s** | 6.61 GiB/s |
|
|
162
|
+
| | incremental | 4 KiB | 7.70 GiB/s | **7.99 GiB/s** |
|
|
163
|
+
| | | 1 MiB | **10.01 GiB/s** | 9.28 GiB/s |
|
|
164
|
+
| | | 32 MiB | **9.41 GiB/s** | 7.34 GiB/s |
|
|
165
|
+
|
|
166
|
+
Reusable-buffer and mutable-input results are available in [BENCHMARK.md](https://github.com/kozistr/hashcodecs-rs/blob/main/BENCHMARK.md).
|
|
167
|
+
|
|
168
|
+
## SIMD References
|
|
169
|
+
|
|
170
|
+
The SIMD implementation follows the approach described in [Faster Base64 Encoding and Decoding using AVX2 Instructions](https://arxiv.org/abs/1704.00605), with AVX-512 VBMI and AArch64 NEON backends selected automatically when available.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hashcodecs"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "SIMD-accelerated Base64 and MurmurHash3 codecs"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -12,6 +12,12 @@ license = "MIT OR Apache-2.0"
|
|
|
12
12
|
license-files = ["LICENSE", "LICENSE-MIT"]
|
|
13
13
|
classifiers = [
|
|
14
14
|
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.10",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
20
|
+
"Programming Language :: Python :: 3.15",
|
|
15
21
|
"Programming Language :: Rust",
|
|
16
22
|
"Operating System :: OS Independent",
|
|
17
23
|
"Topic :: Software Development :: Libraries",
|
|
@@ -33,6 +39,7 @@ packages = ["python/hashcodecs"]
|
|
|
33
39
|
|
|
34
40
|
[tool.hatch.build.targets.sdist]
|
|
35
41
|
include = [
|
|
42
|
+
"/BENCHMARK.md",
|
|
36
43
|
"/Cargo.lock",
|
|
37
44
|
"/Cargo.toml",
|
|
38
45
|
"/build.rs",
|
|
@@ -2,16 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
from .base64 import (
|
|
4
4
|
b64decode,
|
|
5
|
+
b64decode_batch,
|
|
5
6
|
b64decode_into,
|
|
6
7
|
b64encode,
|
|
8
|
+
b64encode_batch,
|
|
7
9
|
b64encode_into,
|
|
8
10
|
standard_b64decode,
|
|
11
|
+
standard_b64decode_batch,
|
|
9
12
|
standard_b64decode_into,
|
|
10
13
|
standard_b64encode,
|
|
14
|
+
standard_b64encode_batch,
|
|
11
15
|
standard_b64encode_into,
|
|
12
16
|
urlsafe_b64decode,
|
|
17
|
+
urlsafe_b64decode_batch,
|
|
13
18
|
urlsafe_b64decode_into,
|
|
14
19
|
urlsafe_b64encode,
|
|
20
|
+
urlsafe_b64encode_batch,
|
|
15
21
|
urlsafe_b64encode_into,
|
|
16
22
|
)
|
|
17
23
|
from .murmur3 import (
|
|
@@ -25,8 +31,10 @@ from .murmur3 import (
|
|
|
25
31
|
|
|
26
32
|
__all__ = [
|
|
27
33
|
'b64decode',
|
|
34
|
+
'b64decode_batch',
|
|
28
35
|
'b64decode_into',
|
|
29
36
|
'b64encode',
|
|
37
|
+
'b64encode_batch',
|
|
30
38
|
'b64encode_into',
|
|
31
39
|
'murmur3_32',
|
|
32
40
|
'murmur3_x64_128',
|
|
@@ -35,11 +43,15 @@ __all__ = [
|
|
|
35
43
|
'murmur3_x86_128',
|
|
36
44
|
'murmur3_x86_128_digest',
|
|
37
45
|
'standard_b64decode',
|
|
46
|
+
'standard_b64decode_batch',
|
|
38
47
|
'standard_b64decode_into',
|
|
39
48
|
'standard_b64encode',
|
|
49
|
+
'standard_b64encode_batch',
|
|
40
50
|
'standard_b64encode_into',
|
|
41
51
|
'urlsafe_b64decode',
|
|
52
|
+
'urlsafe_b64decode_batch',
|
|
42
53
|
'urlsafe_b64decode_into',
|
|
43
54
|
'urlsafe_b64encode',
|
|
55
|
+
'urlsafe_b64encode_batch',
|
|
44
56
|
'urlsafe_b64encode_into',
|
|
45
57
|
]
|
|
@@ -1,17 +1,44 @@
|
|
|
1
1
|
from _typeshed import ReadableBuffer
|
|
2
2
|
|
|
3
|
-
def b64encode(
|
|
4
|
-
|
|
3
|
+
def b64encode(
|
|
4
|
+
s: ReadableBuffer,
|
|
5
|
+
altchars: ReadableBuffer | None = None,
|
|
6
|
+
*,
|
|
7
|
+
padded: bool = True,
|
|
8
|
+
wrapcol: int = 0,
|
|
9
|
+
) -> bytes: ...
|
|
10
|
+
def b64encode_batch(items: list[ReadableBuffer], altchars: ReadableBuffer | None = None) -> list[bytes]: ...
|
|
11
|
+
def b64encode_into(
|
|
12
|
+
s: ReadableBuffer,
|
|
13
|
+
output: bytearray,
|
|
14
|
+
altchars: ReadableBuffer | None = None,
|
|
15
|
+
*,
|
|
16
|
+
padded: bool = True,
|
|
17
|
+
wrapcol: int = 0,
|
|
18
|
+
) -> int: ...
|
|
5
19
|
def b64decode(
|
|
6
20
|
s: str | ReadableBuffer,
|
|
7
21
|
altchars: str | ReadableBuffer | None = None,
|
|
8
|
-
validate: bool =
|
|
22
|
+
validate: bool = ...,
|
|
23
|
+
*,
|
|
24
|
+
padded: bool = True,
|
|
25
|
+
ignorechars: ReadableBuffer = ...,
|
|
26
|
+
canonical: bool = False,
|
|
9
27
|
) -> bytes: ...
|
|
28
|
+
def b64decode_batch(
|
|
29
|
+
items: list[str | ReadableBuffer],
|
|
30
|
+
altchars: str | ReadableBuffer | None = None,
|
|
31
|
+
validate: bool = False,
|
|
32
|
+
) -> list[bytes]: ...
|
|
10
33
|
def b64decode_into(
|
|
11
34
|
s: str | ReadableBuffer,
|
|
12
35
|
output: bytearray,
|
|
13
36
|
altchars: str | ReadableBuffer | None = None,
|
|
14
|
-
validate: bool =
|
|
37
|
+
validate: bool = ...,
|
|
38
|
+
*,
|
|
39
|
+
padded: bool = True,
|
|
40
|
+
ignorechars: ReadableBuffer = ...,
|
|
41
|
+
canonical: bool = False,
|
|
15
42
|
) -> int: ...
|
|
16
43
|
def murmur3_32(s: ReadableBuffer, seed: int = 0) -> int: ...
|
|
17
44
|
def murmur3_x86_128_digest(s: ReadableBuffer, seed: int = 0) -> bytes: ...
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""A fast, API-compatible subset of Python's :mod:`base64` module."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from ._hashcodecs import b64decode, b64decode_batch, b64decode_into, b64encode, b64encode_batch, b64encode_into
|
|
6
|
+
|
|
7
|
+
_URLSAFE_PADDED_DEFAULT = sys.version_info < (3, 15)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def standard_b64encode(s) -> bytes:
|
|
11
|
+
"""Encode *s* with the standard Base64 alphabet."""
|
|
12
|
+
return b64encode(s)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def standard_b64encode_batch(items) -> list[bytes]:
|
|
16
|
+
"""Encode a list of inputs with the standard Base64 alphabet."""
|
|
17
|
+
return b64encode_batch(items)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def standard_b64encode_into(s, output: bytearray) -> int:
|
|
21
|
+
"""Encode *s* with the standard Base64 alphabet into *output*."""
|
|
22
|
+
return b64encode_into(s, output)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def standard_b64decode(s) -> bytes:
|
|
26
|
+
"""Decode *s* with the standard Base64 alphabet."""
|
|
27
|
+
return b64decode(s)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def standard_b64decode_batch(items) -> list[bytes]:
|
|
31
|
+
"""Decode a list of inputs with the standard Base64 alphabet."""
|
|
32
|
+
return b64decode_batch(items)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def standard_b64decode_into(s, output: bytearray) -> int:
|
|
36
|
+
"""Decode standard Base64 *s* into *output*."""
|
|
37
|
+
return b64decode_into(s, output)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def urlsafe_b64encode(s, *, padded: bool = True) -> bytes:
|
|
41
|
+
"""Encode *s* with the URL-safe Base64 alphabet."""
|
|
42
|
+
return b64encode(s, b'-_', padded=padded)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def urlsafe_b64encode_batch(items) -> list[bytes]:
|
|
46
|
+
"""Encode a list of inputs with the URL-safe Base64 alphabet."""
|
|
47
|
+
return b64encode_batch(items, b'-_')
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def urlsafe_b64encode_into(s, output: bytearray, *, padded: bool = True) -> int:
|
|
51
|
+
"""Encode *s* with the URL-safe Base64 alphabet into *output*."""
|
|
52
|
+
return b64encode_into(s, output, b'-_', padded=padded)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def urlsafe_b64decode(s, *, padded: bool = _URLSAFE_PADDED_DEFAULT) -> bytes:
|
|
56
|
+
"""Decode *s* with the URL-safe Base64 alphabet."""
|
|
57
|
+
return b64decode(s, b'-_', padded=padded)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def urlsafe_b64decode_batch(items) -> list[bytes]:
|
|
61
|
+
"""Decode a list of inputs with the URL-safe Base64 alphabet."""
|
|
62
|
+
return b64decode_batch(items, b'-_')
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def urlsafe_b64decode_into(s, output: bytearray, *, padded: bool = _URLSAFE_PADDED_DEFAULT) -> int:
|
|
66
|
+
"""Decode URL-safe Base64 *s* into *output*."""
|
|
67
|
+
return b64decode_into(s, output, b'-_', padded=padded)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
__all__ = [
|
|
71
|
+
'b64decode',
|
|
72
|
+
'b64decode_batch',
|
|
73
|
+
'b64decode_into',
|
|
74
|
+
'b64encode',
|
|
75
|
+
'b64encode_batch',
|
|
76
|
+
'b64encode_into',
|
|
77
|
+
'standard_b64decode',
|
|
78
|
+
'standard_b64decode_batch',
|
|
79
|
+
'standard_b64decode_into',
|
|
80
|
+
'standard_b64encode',
|
|
81
|
+
'standard_b64encode_batch',
|
|
82
|
+
'standard_b64encode_into',
|
|
83
|
+
'urlsafe_b64decode',
|
|
84
|
+
'urlsafe_b64decode_batch',
|
|
85
|
+
'urlsafe_b64decode_into',
|
|
86
|
+
'urlsafe_b64encode',
|
|
87
|
+
'urlsafe_b64encode_batch',
|
|
88
|
+
'urlsafe_b64encode_into',
|
|
89
|
+
]
|