wavelet-matrix 2.2.1__tar.gz → 2.2.2__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.
Files changed (46) hide show
  1. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/.github/workflows/CI.yml +2 -2
  2. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/Cargo.lock +122 -20
  3. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/Cargo.toml +4 -2
  4. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/PKG-INFO +1 -7
  5. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/README.md +0 -6
  6. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/disk_wavelet_matrix/disk_bit_vector.rs +82 -25
  7. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/disk_wavelet_matrix/disk_wavelet_matrix.rs +133 -41
  8. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/lib.rs +1 -1
  9. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/python/wavelet_matrix.rs +65 -69
  10. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/wavelet_matrix/wavelet_matrix.rs +11 -12
  11. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/.gitignore +0 -0
  12. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/LICENSE +0 -0
  13. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/benchmarks/__init__.py +0 -0
  14. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/benchmarks/bench_disk_wavelet_matrix.py +0 -0
  15. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/benchmarks/bench_dynamic_wavelet_matrix.py +0 -0
  16. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/benchmarks/bench_wavelet_matrix.py +0 -0
  17. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/docs/index.html +0 -0
  18. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/docs/wavelet_matrix.html +0 -0
  19. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/pdoc_templates/error.html.jinja2 +0 -0
  20. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/pdoc_templates/frame.html.jinja2 +0 -0
  21. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/pdoc_templates/index.html.jinja2 +0 -0
  22. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/pdoc_templates/module.html.jinja2 +0 -0
  23. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/pyproject.toml +0 -0
  24. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/disk_wavelet_matrix/mod.rs +0 -0
  25. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/dynamic_wavelet_matrix/dynamic_bit_vector.rs +0 -0
  26. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/dynamic_wavelet_matrix/dynamic_wavelet_matrix.rs +0 -0
  27. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/dynamic_wavelet_matrix/mod.rs +0 -0
  28. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/python/dynamic_wavelet_matrix.rs +0 -0
  29. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/python/mod.rs +0 -0
  30. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/traits/bit_vector/bit_vector.rs +0 -0
  31. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/traits/bit_vector/dynamic_bit_vector.rs +0 -0
  32. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/traits/bit_vector/mod.rs +0 -0
  33. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/traits/mod.rs +0 -0
  34. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/traits/utils/bit_select.rs +0 -0
  35. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/traits/utils/bit_width.rs +0 -0
  36. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/traits/utils/mod.rs +0 -0
  37. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/traits/wavelet_matrix/dynamic_wavelet_matrix.rs +0 -0
  38. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/traits/wavelet_matrix/mod.rs +0 -0
  39. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/traits/wavelet_matrix/wavelet_matrix.rs +0 -0
  40. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/wavelet_matrix/bit_vector.rs +0 -0
  41. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/src/wavelet_matrix/mod.rs +0 -0
  42. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/tests/__init__.py +0 -0
  43. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/tests/test_disk_wavelet_matrix.py +0 -0
  44. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/tests/test_dynamic_wavelet_matrix.py +0 -0
  45. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/tests/test_wavelet_matrix.py +0 -0
  46. {wavelet_matrix-2.2.1 → wavelet_matrix-2.2.2}/wavelet_matrix.pyi +0 -0
@@ -206,7 +206,7 @@ jobs:
206
206
  - name: Install packages
207
207
  run: python -m pip install -e .[test,dev]
208
208
  - name: Run tests
209
- run: pytest --benchmark-skip
209
+ run: python -m pytest --benchmark-skip
210
210
  - name: Docs check
211
211
  run: |
212
212
  pdoc wavelet_matrix \
@@ -245,7 +245,7 @@ jobs:
245
245
  python -m pip install --upgrade pip
246
246
  python -m pip install -e .[test]
247
247
  - name: Run benchmarks
248
- run: pytest --benchmark-only --db .pymon
248
+ run: python -m pytest --benchmark-only --db .pymon
249
249
  - name: Display benchmark results
250
250
  run: |
251
251
  sqlite3 -header -column .pymon '
@@ -8,17 +8,29 @@ version = "1.5.1"
8
8
  source = "registry+https://github.com/rust-lang/crates.io-index"
9
9
  checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
10
10
 
11
+ [[package]]
12
+ name = "bitflags"
13
+ version = "2.13.0"
14
+ source = "registry+https://github.com/rust-lang/crates.io-index"
15
+ checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
16
+
11
17
  [[package]]
12
18
  name = "bytemuck"
13
19
  version = "1.25.0"
14
20
  source = "registry+https://github.com/rust-lang/crates.io-index"
15
21
  checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
16
22
 
23
+ [[package]]
24
+ name = "cfg-if"
25
+ version = "1.0.4"
26
+ source = "registry+https://github.com/rust-lang/crates.io-index"
27
+ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
28
+
17
29
  [[package]]
18
30
  name = "crossbeam-deque"
19
- version = "0.8.6"
31
+ version = "0.8.7"
20
32
  source = "registry+https://github.com/rust-lang/crates.io-index"
21
- checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
33
+ checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb"
22
34
  dependencies = [
23
35
  "crossbeam-epoch",
24
36
  "crossbeam-utils",
@@ -26,18 +38,18 @@ dependencies = [
26
38
 
27
39
  [[package]]
28
40
  name = "crossbeam-epoch"
29
- version = "0.9.18"
41
+ version = "0.9.20"
30
42
  source = "registry+https://github.com/rust-lang/crates.io-index"
31
- checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
43
+ checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
32
44
  dependencies = [
33
45
  "crossbeam-utils",
34
46
  ]
35
47
 
36
48
  [[package]]
37
49
  name = "crossbeam-utils"
38
- version = "0.8.21"
50
+ version = "0.8.22"
39
51
  source = "registry+https://github.com/rust-lang/crates.io-index"
40
- checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
52
+ checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
41
53
 
42
54
  [[package]]
43
55
  name = "either"
@@ -45,18 +57,60 @@ version = "1.16.0"
45
57
  source = "registry+https://github.com/rust-lang/crates.io-index"
46
58
  checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
47
59
 
60
+ [[package]]
61
+ name = "errno"
62
+ version = "0.3.14"
63
+ source = "registry+https://github.com/rust-lang/crates.io-index"
64
+ checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
65
+ dependencies = [
66
+ "libc",
67
+ "windows-sys",
68
+ ]
69
+
70
+ [[package]]
71
+ name = "fastrand"
72
+ version = "2.4.1"
73
+ source = "registry+https://github.com/rust-lang/crates.io-index"
74
+ checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
75
+
76
+ [[package]]
77
+ name = "getrandom"
78
+ version = "0.4.3"
79
+ source = "registry+https://github.com/rust-lang/crates.io-index"
80
+ checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
81
+ dependencies = [
82
+ "cfg-if",
83
+ "libc",
84
+ "r-efi",
85
+ ]
86
+
48
87
  [[package]]
49
88
  name = "heck"
50
89
  version = "0.5.0"
51
90
  source = "registry+https://github.com/rust-lang/crates.io-index"
52
91
  checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
53
92
 
93
+ [[package]]
94
+ name = "itertools"
95
+ version = "0.15.0"
96
+ source = "registry+https://github.com/rust-lang/crates.io-index"
97
+ checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc"
98
+ dependencies = [
99
+ "either",
100
+ ]
101
+
54
102
  [[package]]
55
103
  name = "libc"
56
104
  version = "0.2.186"
57
105
  source = "registry+https://github.com/rust-lang/crates.io-index"
58
106
  checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
59
107
 
108
+ [[package]]
109
+ name = "linux-raw-sys"
110
+ version = "0.12.1"
111
+ source = "registry+https://github.com/rust-lang/crates.io-index"
112
+ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
113
+
60
114
  [[package]]
61
115
  name = "memmap2"
62
116
  version = "0.9.11"
@@ -68,9 +122,9 @@ dependencies = [
68
122
 
69
123
  [[package]]
70
124
  name = "num-bigint"
71
- version = "0.4.6"
125
+ version = "0.4.8"
72
126
  source = "registry+https://github.com/rust-lang/crates.io-index"
73
- checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
127
+ checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367"
74
128
  dependencies = [
75
129
  "num-integer",
76
130
  "num-traits",
@@ -117,9 +171,9 @@ dependencies = [
117
171
 
118
172
  [[package]]
119
173
  name = "pyo3"
120
- version = "0.28.3"
174
+ version = "0.29.0"
121
175
  source = "registry+https://github.com/rust-lang/crates.io-index"
122
- checksum = "91fd8e38a3b50ed1167fb981cd6fd60147e091784c427b8f7183a7ee32c31c12"
176
+ checksum = "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c"
123
177
  dependencies = [
124
178
  "libc",
125
179
  "num-bigint",
@@ -133,18 +187,18 @@ dependencies = [
133
187
 
134
188
  [[package]]
135
189
  name = "pyo3-build-config"
136
- version = "0.28.3"
190
+ version = "0.29.0"
137
191
  source = "registry+https://github.com/rust-lang/crates.io-index"
138
- checksum = "e368e7ddfdeb98c9bca7f8383be1648fd84ab466bf2bc015e94008db6d35611e"
192
+ checksum = "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078"
139
193
  dependencies = [
140
194
  "target-lexicon",
141
195
  ]
142
196
 
143
197
  [[package]]
144
198
  name = "pyo3-ffi"
145
- version = "0.28.3"
199
+ version = "0.29.0"
146
200
  source = "registry+https://github.com/rust-lang/crates.io-index"
147
- checksum = "7f29e10af80b1f7ccaf7f69eace800a03ecd13e883acfacc1e5d0988605f651e"
201
+ checksum = "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b"
148
202
  dependencies = [
149
203
  "libc",
150
204
  "pyo3-build-config",
@@ -152,9 +206,9 @@ dependencies = [
152
206
 
153
207
  [[package]]
154
208
  name = "pyo3-macros"
155
- version = "0.28.3"
209
+ version = "0.29.0"
156
210
  source = "registry+https://github.com/rust-lang/crates.io-index"
157
- checksum = "df6e520eff47c45997d2fc7dd8214b25dd1310918bbb2642156ef66a67f29813"
211
+ checksum = "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771"
158
212
  dependencies = [
159
213
  "proc-macro2",
160
214
  "pyo3-macros-backend",
@@ -164,13 +218,12 @@ dependencies = [
164
218
 
165
219
  [[package]]
166
220
  name = "pyo3-macros-backend"
167
- version = "0.28.3"
221
+ version = "0.29.0"
168
222
  source = "registry+https://github.com/rust-lang/crates.io-index"
169
- checksum = "c4cdc218d835738f81c2338f822078af45b4afdf8b2e33cbb5916f108b813acb"
223
+ checksum = "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362"
170
224
  dependencies = [
171
225
  "heck",
172
226
  "proc-macro2",
173
- "pyo3-build-config",
174
227
  "quote",
175
228
  "syn",
176
229
  ]
@@ -184,6 +237,12 @@ dependencies = [
184
237
  "proc-macro2",
185
238
  ]
186
239
 
240
+ [[package]]
241
+ name = "r-efi"
242
+ version = "6.0.0"
243
+ source = "registry+https://github.com/rust-lang/crates.io-index"
244
+ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
245
+
187
246
  [[package]]
188
247
  name = "rayon"
189
248
  version = "1.12.0"
@@ -204,6 +263,19 @@ dependencies = [
204
263
  "crossbeam-utils",
205
264
  ]
206
265
 
266
+ [[package]]
267
+ name = "rustix"
268
+ version = "1.1.4"
269
+ source = "registry+https://github.com/rust-lang/crates.io-index"
270
+ checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
271
+ dependencies = [
272
+ "bitflags",
273
+ "errno",
274
+ "libc",
275
+ "linux-raw-sys",
276
+ "windows-sys",
277
+ ]
278
+
207
279
  [[package]]
208
280
  name = "syn"
209
281
  version = "2.0.118"
@@ -221,6 +293,19 @@ version = "0.13.5"
221
293
  source = "registry+https://github.com/rust-lang/crates.io-index"
222
294
  checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
223
295
 
296
+ [[package]]
297
+ name = "tempfile"
298
+ version = "3.27.0"
299
+ source = "registry+https://github.com/rust-lang/crates.io-index"
300
+ checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
301
+ dependencies = [
302
+ "fastrand",
303
+ "getrandom",
304
+ "once_cell",
305
+ "rustix",
306
+ "windows-sys",
307
+ ]
308
+
224
309
  [[package]]
225
310
  name = "unicode-ident"
226
311
  version = "1.0.24"
@@ -229,13 +314,30 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
229
314
 
230
315
  [[package]]
231
316
  name = "wavelet-matrix"
232
- version = "2.2.1"
317
+ version = "2.2.2"
233
318
  dependencies = [
234
319
  "bytemuck",
320
+ "itertools",
235
321
  "memmap2",
236
322
  "num-bigint",
237
323
  "num-integer",
238
324
  "num-traits",
239
325
  "pyo3",
240
326
  "rayon",
327
+ "tempfile",
328
+ ]
329
+
330
+ [[package]]
331
+ name = "windows-link"
332
+ version = "0.2.1"
333
+ source = "registry+https://github.com/rust-lang/crates.io-index"
334
+ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
335
+
336
+ [[package]]
337
+ name = "windows-sys"
338
+ version = "0.61.2"
339
+ source = "registry+https://github.com/rust-lang/crates.io-index"
340
+ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
341
+ dependencies = [
342
+ "windows-link",
241
343
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "wavelet-matrix"
3
- version = "2.2.1"
3
+ version = "2.2.2"
4
4
  edition = "2024"
5
5
  readme = "README.md"
6
6
 
@@ -11,9 +11,11 @@ crate-type = ["cdylib"]
11
11
 
12
12
  [dependencies]
13
13
  bytemuck = "1.25.0"
14
+ itertools = "0.15.0"
14
15
  memmap2 = "0.9.10"
15
16
  num-bigint = "0.4.6"
16
17
  num-integer = "0.1.46"
17
18
  num-traits = "0.2.19"
18
- pyo3 = { version = "0.28.3", features = ["num-bigint"] }
19
+ pyo3 = { version = "0.29.0", features = ["num-bigint"] }
19
20
  rayon = "1.12.0"
21
+ tempfile = "3.27.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wavelet-matrix
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Classifier: Intended Audience :: Developers
5
5
  Classifier: Intended Audience :: Science/Research
6
6
  Classifier: Intended Audience :: Information Technology
@@ -47,7 +47,6 @@ Project-URL: repository, https://github.com/math-hiyoko/wavelet-matrix
47
47
  [![PyPI Downloads](https://static.pepy.tech/personalized-badge/wavelet-matrix?period=total&units=INTERNATIONAL_SYSTEM&left_color=GRAY&right_color=GREEN&left_text=PyPI%20downloads)](https://pepy.tech/projects/wavelet-matrix)
48
48
  ![PyPI - Format](https://img.shields.io/pypi/format/wavelet-matrix)
49
49
  ![Rust](https://img.shields.io/badge/powered%20by-Rust-orange)
50
- ![Unsafe](https://img.shields.io/badge/unsafe-0-success)
51
50
  ![GitHub Repo stars](https://img.shields.io/github/stars/math-hiyoko/wavelet-matrix)
52
51
 
53
52
 
@@ -63,7 +62,6 @@ supporting fast rank / select / range queries over indexed sequences
63
62
  - Rich range queries (freq / sum / top-k / min / max)
64
63
  - Optional disk-backed storage for static WaveletMatrix (`on_disk=True`)
65
64
  - Optional dynamic updates (insert / remove / update)
66
- - Safe Rust (no unsafe)
67
65
 
68
66
  ## Installation
69
67
  ```bash
@@ -177,10 +175,6 @@ dwm.update(index=4, value=5)
177
175
  # or dwm[4] = 5
178
176
  ```
179
177
 
180
- ## Safety
181
- - Powered by safe Rust
182
- - Memory-safe by design
183
-
184
178
  ## Development
185
179
 
186
180
  ### Running Tests
@@ -10,7 +10,6 @@
10
10
  [![PyPI Downloads](https://static.pepy.tech/personalized-badge/wavelet-matrix?period=total&units=INTERNATIONAL_SYSTEM&left_color=GRAY&right_color=GREEN&left_text=PyPI%20downloads)](https://pepy.tech/projects/wavelet-matrix)
11
11
  ![PyPI - Format](https://img.shields.io/pypi/format/wavelet-matrix)
12
12
  ![Rust](https://img.shields.io/badge/powered%20by-Rust-orange)
13
- ![Unsafe](https://img.shields.io/badge/unsafe-0-success)
14
13
  ![GitHub Repo stars](https://img.shields.io/github/stars/math-hiyoko/wavelet-matrix)
15
14
 
16
15
 
@@ -26,7 +25,6 @@ supporting fast rank / select / range queries over indexed sequences
26
25
  - Rich range queries (freq / sum / top-k / min / max)
27
26
  - Optional disk-backed storage for static WaveletMatrix (`on_disk=True`)
28
27
  - Optional dynamic updates (insert / remove / update)
29
- - Safe Rust (no unsafe)
30
28
 
31
29
  ## Installation
32
30
  ```bash
@@ -140,10 +138,6 @@ dwm.update(index=4, value=5)
140
138
  # or dwm[4] = 5
141
139
  ```
142
140
 
143
- ## Safety
144
- - Powered by safe Rust
145
- - Memory-safe by design
146
-
147
141
  ## Development
148
142
 
149
143
  ### Running Tests
@@ -1,4 +1,4 @@
1
- use std::{iter, mem};
1
+ use std::{fs, iter, mem};
2
2
 
3
3
  use bytemuck::{cast_slice, cast_slice_mut};
4
4
  use memmap2::{Mmap, MmapMut};
@@ -8,6 +8,7 @@ use pyo3::{
8
8
  PyResult,
9
9
  exceptions::{PyIndexError, PyRuntimeError, PyValueError},
10
10
  };
11
+ use tempfile::tempfile;
11
12
 
12
13
  use crate::traits::{
13
14
  bit_vector::bit_vector::{BitVectorTrait, BlockType},
@@ -19,19 +20,25 @@ const SELECT_INDEX_INTERVAL: usize = 512;
19
20
  pub(crate) struct DiskBitVector {
20
21
  len: usize,
21
22
  ranks: Mmap,
23
+ ranks_file: fs::File,
22
24
  blocks: Mmap,
25
+ blocks_file: fs::File,
23
26
  select_index: [Mmap; 2],
27
+ select_index_file: [fs::File; 2],
24
28
  }
25
29
 
26
30
  impl DiskBitVector {
27
- pub(super) fn new(blocks: Mmap, len: usize) -> PyResult<Self> {
31
+ pub(super) fn new(blocks: Mmap, blocks_file: fs::File, len: usize) -> PyResult<Self> {
28
32
  assert!(blocks.len().is_multiple_of(mem::size_of::<BlockType>()));
29
33
  let blocks_data: &[BlockType] = cast_slice(&blocks[..]);
30
34
 
31
35
  // Build the rank index structure.
32
- let mut ranks = MmapMut::map_anon((blocks_data.len() + 1) * mem::size_of::<usize>())
36
+ let ranks_file = tempfile().map_err(PyRuntimeError::new_err)?;
37
+ ranks_file
38
+ .set_len((blocks_data.len() + 1) as u64 * mem::size_of::<usize>() as u64)
33
39
  .map_err(PyRuntimeError::new_err)?;
34
- assert!(ranks.len().is_multiple_of(mem::size_of::<usize>()));
40
+ #[allow(unsafe_code)]
41
+ let mut ranks = unsafe { MmapMut::map_mut(&ranks_file).map_err(PyRuntimeError::new_err)? };
35
42
  let ranks_data: &mut [usize] = cast_slice_mut(&mut ranks[..]);
36
43
  iter::once(0usize)
37
44
  .chain(blocks_data.iter().scan(0usize, |acc, block| {
@@ -41,16 +48,32 @@ impl DiskBitVector {
41
48
  .enumerate()
42
49
  .for_each(|(index, rank)| ranks_data[index] = rank);
43
50
 
44
- let mut select_index_0 = MmapMut::map_anon(
45
- ((len - ranks_data.last().unwrap()) / SELECT_INDEX_INTERVAL + 2)
46
- * mem::size_of::<usize>(),
47
- )
48
- .map_err(PyRuntimeError::new_err)?;
49
- let mut select_index_1 = MmapMut::map_anon(
50
- (ranks_data.last().unwrap() / SELECT_INDEX_INTERVAL + 2) * mem::size_of::<usize>(),
51
- )
52
- .map_err(PyRuntimeError::new_err)?;
53
-
51
+ let select_index_file = [
52
+ {
53
+ let file = tempfile().map_err(PyRuntimeError::new_err)?;
54
+ file.set_len(
55
+ (((len - ranks_data.last().unwrap()) / SELECT_INDEX_INTERVAL + 2)
56
+ * mem::size_of::<usize>()) as u64,
57
+ )
58
+ .map_err(PyRuntimeError::new_err)?;
59
+ file
60
+ },
61
+ {
62
+ let file = tempfile().map_err(PyRuntimeError::new_err)?;
63
+ file.set_len(
64
+ ((ranks_data.last().unwrap() / SELECT_INDEX_INTERVAL + 2)
65
+ * mem::size_of::<usize>()) as u64,
66
+ )
67
+ .map_err(PyRuntimeError::new_err)?;
68
+ file
69
+ },
70
+ ];
71
+ #[allow(unsafe_code)]
72
+ let mut select_index_0 =
73
+ unsafe { MmapMut::map_mut(&select_index_file[0]).map_err(PyRuntimeError::new_err)? };
74
+ #[allow(unsafe_code)]
75
+ let mut select_index_1 =
76
+ unsafe { MmapMut::map_mut(&select_index_file[1]).map_err(PyRuntimeError::new_err)? };
54
77
  let select_index_data: [&mut [usize]; 2] = [
55
78
  cast_slice_mut(&mut select_index_0[..]),
56
79
  cast_slice_mut(&mut select_index_1[..]),
@@ -79,7 +102,9 @@ impl DiskBitVector {
79
102
  Ok(Self {
80
103
  len,
81
104
  ranks: ranks.make_read_only().map_err(PyRuntimeError::new_err)?,
105
+ ranks_file,
82
106
  blocks,
107
+ blocks_file,
83
108
  select_index: [
84
109
  select_index_0
85
110
  .make_read_only()
@@ -88,20 +113,47 @@ impl DiskBitVector {
88
113
  .make_read_only()
89
114
  .map_err(PyRuntimeError::new_err)?,
90
115
  ],
116
+ select_index_file,
91
117
  })
92
118
  }
93
119
  }
94
120
 
95
121
  impl Clone for DiskBitVector {
96
122
  fn clone(&self) -> Self {
97
- let mut ranks = MmapMut::map_anon(self.ranks.len()).unwrap();
98
- let mut blocks = MmapMut::map_anon(self.blocks.len()).unwrap();
99
- let mut select_index = [
100
- MmapMut::map_anon(self.select_index[0].len()).unwrap(),
101
- MmapMut::map_anon(self.select_index[1].len()).unwrap(),
102
- ];
123
+ let ranks_file = tempfile().unwrap();
124
+ ranks_file.set_len(self.ranks.len() as u64).unwrap();
125
+ #[allow(unsafe_code)]
126
+ let mut ranks = unsafe { MmapMut::map_mut(&ranks_file).unwrap() };
103
127
  ranks.copy_from_slice(&self.ranks[..]);
128
+
129
+ let blocks_file = tempfile().unwrap();
130
+ blocks_file.set_len(self.blocks.len() as u64).unwrap();
131
+ #[allow(unsafe_code)]
132
+ let mut blocks = unsafe { MmapMut::map_mut(&blocks_file).unwrap() };
104
133
  blocks.copy_from_slice(&self.blocks[..]);
134
+
135
+ let select_index_file = [
136
+ {
137
+ let file = tempfile().unwrap();
138
+ file.set_len(self.select_index[0].len() as u64).unwrap();
139
+ file
140
+ },
141
+ {
142
+ let file = tempfile().unwrap();
143
+ file.set_len(self.select_index[1].len() as u64).unwrap();
144
+ file
145
+ },
146
+ ];
147
+ let mut select_index = [
148
+ #[allow(unsafe_code)]
149
+ unsafe {
150
+ MmapMut::map_mut(&select_index_file[0]).unwrap()
151
+ },
152
+ #[allow(unsafe_code)]
153
+ unsafe {
154
+ MmapMut::map_mut(&select_index_file[1]).unwrap()
155
+ },
156
+ ];
105
157
  select_index[0].copy_from_slice(&self.select_index[0][..]);
106
158
  select_index[1].copy_from_slice(&self.select_index[1][..]);
107
159
 
@@ -110,11 +162,14 @@ impl Clone for DiskBitVector {
110
162
  Self {
111
163
  len: self.len,
112
164
  ranks: ranks.make_read_only().unwrap(),
165
+ ranks_file,
113
166
  blocks: blocks.make_read_only().unwrap(),
167
+ blocks_file,
114
168
  select_index: [
115
169
  select_index_0.make_read_only().unwrap(),
116
170
  select_index_1.make_read_only().unwrap(),
117
171
  ],
172
+ select_index_file,
118
173
  }
119
174
  }
120
175
  }
@@ -217,10 +272,12 @@ mod tests {
217
272
 
218
273
  fn create_disk_bit_vector(bits: Vec<bool>) -> DiskBitVector {
219
274
  let len = bits.len();
220
- let mut blocks =
221
- MmapMut::map_anon(len.div_ceil(BlockType::BITS as usize) * mem::size_of::<BlockType>())
222
- .map_err(PyRuntimeError::new_err)
223
- .unwrap();
275
+ let blocks_file = tempfile().unwrap();
276
+ blocks_file
277
+ .set_len((len.div_ceil(BlockType::BITS as usize) * mem::size_of::<BlockType>()) as u64)
278
+ .unwrap();
279
+ #[allow(unsafe_code)]
280
+ let mut blocks = unsafe { MmapMut::map_mut(&blocks_file).unwrap() };
224
281
  let blocks_data: &mut [BlockType] = cast_slice_mut(&mut blocks[..]);
225
282
  bits.chunks(BlockType::BITS as usize)
226
283
  .enumerate()
@@ -238,7 +295,7 @@ mod tests {
238
295
  })
239
296
  });
240
297
 
241
- DiskBitVector::new(blocks.make_read_only().unwrap(), len).unwrap()
298
+ DiskBitVector::new(blocks.make_read_only().unwrap(), blocks_file, len).unwrap()
242
299
  }
243
300
 
244
301
  fn create_dummy() -> DiskBitVector {
@@ -1,11 +1,12 @@
1
- use std::{iter, marker, mem, ops};
1
+ use std::{fs, iter, marker, mem, ops};
2
2
 
3
3
  use bytemuck::{Pod, cast_slice, cast_slice_mut};
4
- use memmap2::{Mmap, MmapMut};
4
+ use memmap2::MmapMut;
5
5
  use num_bigint::ToBigUint;
6
6
  use num_traits::{One, PrimInt, Unsigned};
7
7
  use pyo3::{PyResult, exceptions::PyRuntimeError};
8
8
  use rayon::prelude::*;
9
+ use tempfile::tempfile;
9
10
 
10
11
  use super::disk_bit_vector::DiskBitVector;
11
12
  use crate::traits::{
@@ -27,11 +28,12 @@ where
27
28
  NumberType: BitWidth + One + PrimInt + Unsigned + Pod + Send + Sync,
28
29
  for<'a> &'a NumberType: ops::Shr<usize, Output = NumberType>,
29
30
  {
30
- pub(crate) fn new(data: Mmap) -> PyResult<Self> {
31
+ pub(crate) fn new(data: MmapMut, data_file: fs::File) -> PyResult<Self> {
31
32
  assert!(data.len().is_multiple_of(mem::size_of::<NumberType>()));
32
33
  let len = data.len() / mem::size_of::<NumberType>();
33
34
 
34
35
  let mut values = data;
36
+ let mut _values_file = data_file;
35
37
  let values_data: &[NumberType] = cast_slice(&values[..]);
36
38
  let height = values_data
37
39
  .par_iter()
@@ -41,10 +43,16 @@ where
41
43
  let mut zeros_count_per_layer = Vec::with_capacity(height);
42
44
  let mut layer_blocks_vec = Vec::with_capacity(height);
43
45
  for i in 0..height {
44
- let mut current_layer_bits = MmapMut::map_anon(
45
- len.div_ceil(BlockType::BITS as usize) * mem::size_of::<BlockType>(),
46
- )
47
- .map_err(PyRuntimeError::new_err)?;
46
+ let current_layer_bits_file = tempfile().map_err(PyRuntimeError::new_err)?;
47
+ current_layer_bits_file
48
+ .set_len(
49
+ (len.div_ceil(BlockType::BITS as usize) * mem::size_of::<BlockType>()) as u64,
50
+ )
51
+ .map_err(PyRuntimeError::new_err)?;
52
+ #[allow(unsafe_code)]
53
+ let mut current_layer_bits = unsafe {
54
+ MmapMut::map_mut(&current_layer_bits_file).map_err(PyRuntimeError::new_err)?
55
+ };
48
56
  assert!(
49
57
  current_layer_bits
50
58
  .len()
@@ -53,32 +61,39 @@ where
53
61
  let current_layer_bits_data: &mut [BlockType] =
54
62
  cast_slice_mut(&mut current_layer_bits[..]);
55
63
  let values_data: &[NumberType] = cast_slice(&values[..]);
56
- values_data
57
- .par_iter()
58
- .map(|value| (value >> (height - i - 1) & NumberType::one()).is_one())
59
- .chunks(BlockType::BITS as usize)
60
- .zip(current_layer_bits_data.par_iter_mut())
61
- .for_each(|(bits_chunk, block)| {
62
- bits_chunk.iter().enumerate().for_each(|(j, &bit)| {
63
- if bit {
64
+ current_layer_bits_data
65
+ .iter_mut()
66
+ .enumerate()
67
+ .for_each(|(block_index, block)| {
68
+ let start = block_index * BlockType::BITS as usize;
69
+ let end = (start + BlockType::BITS as usize).min(len);
70
+ for (j, value) in values_data[start..end].iter().enumerate() {
71
+ if ((value >> (height - i - 1)) & NumberType::one()).is_one() {
64
72
  *block |= BlockType::one() << j;
65
73
  }
66
- });
74
+ }
67
75
  });
76
+
68
77
  let zeros_count = len
69
78
  - current_layer_bits_data
70
79
  .par_iter()
71
80
  .map(|&block| block.count_ones() as usize)
72
81
  .sum::<usize>();
73
82
 
74
- let mut next_values = MmapMut::map_anon(len * mem::size_of::<NumberType>())
83
+ let next_values_file = tempfile().map_err(PyRuntimeError::new_err)?;
84
+ next_values_file
85
+ .set_len((len * mem::size_of::<NumberType>()) as u64)
75
86
  .map_err(PyRuntimeError::new_err)?;
87
+ #[allow(unsafe_code)]
88
+ let mut next_values =
89
+ unsafe { MmapMut::map_mut(&next_values_file).map_err(PyRuntimeError::new_err)? };
76
90
  assert!(
77
91
  next_values
78
92
  .len()
79
93
  .is_multiple_of(mem::size_of::<NumberType>())
80
94
  );
81
95
  let next_values_data: &mut [NumberType] = cast_slice_mut(&mut next_values[..]);
96
+
82
97
  let mut zero_index = 0usize;
83
98
  let mut one_index = zeros_count;
84
99
  for (bit, value) in iter::zip(
@@ -101,19 +116,19 @@ where
101
116
  }
102
117
 
103
118
  zeros_count_per_layer.push(zeros_count);
104
- layer_blocks_vec.push(
119
+ layer_blocks_vec.push((
105
120
  current_layer_bits
106
121
  .make_read_only()
107
122
  .map_err(PyRuntimeError::new_err)?,
108
- );
109
- values = next_values
110
- .make_read_only()
111
- .map_err(PyRuntimeError::new_err)?;
123
+ current_layer_bits_file,
124
+ ));
125
+ values = next_values;
126
+ _values_file = next_values_file;
112
127
  }
113
128
 
114
129
  let layers = layer_blocks_vec
115
130
  .into_par_iter()
116
- .map(|blocks| DiskBitVector::new(blocks, len))
131
+ .map(|(blocks, blocks_file)| DiskBitVector::new(blocks, blocks_file, len))
117
132
  .collect::<PyResult<Vec<_>>>()?;
118
133
 
119
134
  Ok(Self {
@@ -164,32 +179,55 @@ where
164
179
 
165
180
  #[cfg(test)]
166
181
  mod tests {
182
+ use num_bigint::BigUint;
167
183
  use pyo3::Python;
168
184
 
169
185
  use super::*;
170
186
 
171
187
  fn create_u8() -> DiskWaveletMatrix<u8> {
172
188
  let elements: Vec<u8> = vec![5, 4, 5, 5, 2, 1, 5, 6, 1, 3, 5, 0];
173
- let mut mmap = MmapMut::map_anon(elements.len() * mem::size_of::<u8>()).unwrap();
189
+ let file = tempfile().map_err(PyRuntimeError::new_err).unwrap();
190
+ file.set_len((elements.len() * mem::size_of::<u8>()) as u64)
191
+ .unwrap();
192
+ #[allow(unsafe_code)]
193
+ let mut mmap = unsafe {
194
+ MmapMut::map_mut(&file)
195
+ .map_err(PyRuntimeError::new_err)
196
+ .unwrap()
197
+ };
174
198
  let mmap_data: &mut [u8] = cast_slice_mut(&mut mmap[..]);
175
199
  mmap_data.copy_from_slice(&elements);
176
- DiskWaveletMatrix::new(mmap.make_read_only().unwrap()).unwrap()
200
+ DiskWaveletMatrix::new(mmap, file).unwrap()
177
201
  }
178
202
 
179
203
  fn create_u128() -> DiskWaveletMatrix<u128> {
180
204
  let elements: Vec<u128> = vec![5u128, 4, 5, 5, 2, 1, 5, 6, 1, 3, 5, 0];
181
- let mut mmap = MmapMut::map_anon(elements.len() * mem::size_of::<u128>()).unwrap();
205
+ let file = tempfile().map_err(PyRuntimeError::new_err).unwrap();
206
+ file.set_len((elements.len() * mem::size_of::<u128>()) as u64)
207
+ .unwrap();
208
+ #[allow(unsafe_code)]
209
+ let mut mmap = unsafe {
210
+ MmapMut::map_mut(&file)
211
+ .map_err(PyRuntimeError::new_err)
212
+ .unwrap()
213
+ };
182
214
  let mmap_data: &mut [u128] = cast_slice_mut(&mut mmap[..]);
183
215
  mmap_data.copy_from_slice(&elements);
184
- DiskWaveletMatrix::new(mmap.make_read_only().unwrap()).unwrap()
216
+ DiskWaveletMatrix::new(mmap, file).unwrap()
185
217
  }
186
218
 
187
219
  #[test]
188
220
  fn test_empty() {
189
221
  Python::initialize();
190
222
 
191
- let mmap_empty = MmapMut::map_anon(0).unwrap();
192
- let wv_u8 = DiskWaveletMatrix::<u8>::new(mmap_empty.make_read_only().unwrap()).unwrap();
223
+ let file = tempfile().map_err(PyRuntimeError::new_err).unwrap();
224
+ #[allow(unsafe_code)]
225
+ let mmap_empty = unsafe {
226
+ MmapMut::map_mut(&file)
227
+ .map_err(PyRuntimeError::new_err)
228
+ .unwrap()
229
+ };
230
+ let wv_u8 = DiskWaveletMatrix::<u8>::new(mmap_empty, file).unwrap();
193
231
  assert_eq!(wv_u8.len(), 0);
194
232
  assert_eq!(wv_u8.height(), 0);
195
233
  assert_eq!(wv_u8.values().unwrap(), Vec::<u8>::new());
@@ -246,9 +284,15 @@ mod tests {
246
284
  "ValueError: start must be less than end"
247
285
  );
248
286
 
249
- let mmap_empty = MmapMut::map_anon(0).unwrap();
250
- let wv_u128 = DiskWaveletMatrix::<u128>::new(mmap_empty.make_read_only().unwrap()).unwrap();
251
- assert_eq!(wv_u128.len(), 0);
287
+ let file = tempfile().map_err(PyRuntimeError::new_err).unwrap();
288
+ file.set_len(0).unwrap();
289
+ #[allow(unsafe_code)]
290
+ let mmap_empty = unsafe {
291
+ MmapMut::map_mut(&file)
292
+ .map_err(PyRuntimeError::new_err)
293
+ .unwrap()
294
+ };
295
+ let wv_u128 = DiskWaveletMatrix::<u128>::new(mmap_empty, file).unwrap();
252
296
  assert_eq!(wv_u128.height(), 0);
253
297
  assert_eq!(wv_u128.values().unwrap(), Vec::<u128>::new());
254
298
  assert_eq!(
@@ -315,9 +359,15 @@ mod tests {
315
359
  fn test_all_zero() {
316
360
  Python::initialize();
317
361
 
318
- let mmap_u8_all_zero = MmapMut::map_anon(64 * mem::size_of::<u8>()).unwrap();
319
- let wv_u8 =
320
- DiskWaveletMatrix::<u8>::new(mmap_u8_all_zero.make_read_only().unwrap()).unwrap();
362
+ let file = tempfile().map_err(PyRuntimeError::new_err).unwrap();
363
+ file.set_len((64 * mem::size_of::<u8>()) as u64).unwrap();
364
+ #[allow(unsafe_code)]
365
+ let mmap_u8_all_zero = unsafe {
366
+ MmapMut::map_mut(&file)
367
+ .map_err(PyRuntimeError::new_err)
368
+ .unwrap()
369
+ };
370
+ let wv_u8 = DiskWaveletMatrix::<u8>::new(mmap_u8_all_zero, file).unwrap();
321
371
  assert_eq!(wv_u8.len(), 64);
322
372
  assert_eq!(wv_u8.height(), 0);
323
373
  assert_eq!(wv_u8.values().unwrap(), vec![0u8; 64]);
@@ -334,9 +384,15 @@ mod tests {
334
384
  assert_eq!(wv_u8.prev_value(0, 64, None).unwrap(), Some(0u8));
335
385
  assert_eq!(wv_u8.next_value(0, 64, None).unwrap(), Some(0u8));
336
386
 
337
- let mmap_u128_all_zero = MmapMut::map_anon(64 * mem::size_of::<u128>()).unwrap();
338
- let wv_u128 =
339
- DiskWaveletMatrix::<u128>::new(mmap_u128_all_zero.make_read_only().unwrap()).unwrap();
387
+ let file = tempfile().map_err(PyRuntimeError::new_err).unwrap();
388
+ file.set_len((64 * mem::size_of::<u128>()) as u64).unwrap();
389
+ #[allow(unsafe_code)]
390
+ let mmap_u128_all_zero = unsafe {
391
+ MmapMut::map_mut(&file)
392
+ .map_err(PyRuntimeError::new_err)
393
+ .unwrap()
394
+ };
395
+ let wv_u128 = DiskWaveletMatrix::<u128>::new(mmap_u128_all_zero, file).unwrap();
340
396
  assert_eq!(wv_u128.len(), 64);
341
397
  assert_eq!(wv_u128.height(), 0);
342
398
  assert_eq!(wv_u128.values().unwrap(), vec![0u128; 64]);
@@ -358,11 +414,17 @@ mod tests {
358
414
  fn test_max_value() {
359
415
  Python::initialize();
360
416
 
361
- let mut mmap_u8_max_value = MmapMut::map_anon(64 * mem::size_of::<u8>()).unwrap();
417
+ let file = tempfile().map_err(PyRuntimeError::new_err).unwrap();
418
+ file.set_len((64 * mem::size_of::<u8>()) as u64).unwrap();
419
+ #[allow(unsafe_code)]
420
+ let mut mmap_u8_max_value = unsafe {
421
+ MmapMut::map_mut(&file)
422
+ .map_err(PyRuntimeError::new_err)
423
+ .unwrap()
424
+ };
362
425
  let mmap_u8_data: &mut [u8] = cast_slice_mut(&mut mmap_u8_max_value[..]);
363
426
  mmap_u8_data.fill(u8::MAX);
364
- let wv_u8 =
365
- DiskWaveletMatrix::<u8>::new(mmap_u8_max_value.make_read_only().unwrap()).unwrap();
427
+ let wv_u8 = DiskWaveletMatrix::<u8>::new(mmap_u8_max_value, file).unwrap();
366
428
  assert_eq!(wv_u8.len(), 64);
367
429
  assert_eq!(wv_u8.height(), 8);
368
430
  assert_eq!(wv_u8.values().unwrap(), vec![u8::MAX; 64]);
@@ -381,6 +443,36 @@ mod tests {
381
443
  assert_eq!(wv_u8.range_mink(0, 64, None).unwrap().len(), 1);
382
444
  assert_eq!(wv_u8.prev_value(0, 64, None).unwrap(), Some(u8::MAX));
383
445
  assert_eq!(wv_u8.next_value(0, 64, None).unwrap(), Some(u8::MAX));
446
+
447
+ let file = tempfile().map_err(PyRuntimeError::new_err).unwrap();
448
+ file.set_len((64 * mem::size_of::<u128>()) as u64).unwrap();
449
+ #[allow(unsafe_code)]
450
+ let mut mmap_u128_max_value = unsafe {
451
+ MmapMut::map_mut(&file)
452
+ .map_err(PyRuntimeError::new_err)
453
+ .unwrap()
454
+ };
455
+ let mmap_u128_data: &mut [u128] = cast_slice_mut(&mut mmap_u128_max_value[..]);
456
+ mmap_u128_data.fill(u128::MAX);
457
+ let wv_u128 = DiskWaveletMatrix::<u128>::new(mmap_u128_max_value, file).unwrap();
458
+ assert_eq!(wv_u128.len(), 64);
459
+ assert_eq!(wv_u128.height(), 128);
460
+ assert_eq!(wv_u128.values().unwrap(), vec![u128::MAX; 64]);
461
+ assert_eq!(wv_u128.access(1).unwrap(), u128::MAX);
462
+ assert_eq!(wv_u128.rank(&u128::MAX, 1).unwrap(), 1);
463
+ assert_eq!(wv_u128.select(&u128::MAX, 1).unwrap(), Some(0));
464
+ assert_eq!(wv_u128.quantile(0, 64, 1).unwrap(), u128::MAX);
465
+ assert_eq!(wv_u128.topk(0, 64, None).unwrap().len(), 1);
466
+ assert_eq!(
467
+ wv_u128.range_sum(0, 64).unwrap(),
468
+ BigUint::from(u128::MAX) * 64u128,
469
+ );
470
+ assert_eq!(wv_u128.range_freq(0, 64, None, None).unwrap(), 64usize);
471
+ assert_eq!(wv_u128.range_list(0, 64, None, None).unwrap().len(), 1);
472
+ assert_eq!(wv_u128.range_maxk(0, 64, None).unwrap().len(), 1);
473
+ assert_eq!(wv_u128.range_mink(0, 64, None).unwrap().len(), 1);
474
+ assert_eq!(wv_u128.prev_value(0, 64, None).unwrap(), Some(u128::MAX));
475
+ assert_eq!(wv_u128.next_value(0, 64, None).unwrap(), Some(u128::MAX));
384
476
  }
385
477
 
386
478
  #[test]
@@ -1,4 +1,4 @@
1
- #![forbid(unsafe_code)]
1
+ #![deny(unsafe_code)]
2
2
  mod disk_wavelet_matrix;
3
3
  mod dynamic_wavelet_matrix;
4
4
  mod python;
@@ -7,8 +7,9 @@ use num_traits::Zero;
7
7
  use pyo3::{
8
8
  exceptions::{PyIndexError, PyRuntimeError, PyTypeError, PyValueError},
9
9
  prelude::*,
10
- types::{PyDict, PyInt, PyList, PySequence, PySlice, PySliceIndices},
10
+ types::{PyAny, PyDict, PyInt, PyList, PySlice, PySliceIndices},
11
11
  };
12
+ use tempfile::tempfile;
12
13
 
13
14
  use crate::{
14
15
  disk_wavelet_matrix::disk_wavelet_matrix::DiskWaveletMatrix,
@@ -66,7 +67,7 @@ impl PyWaveletMatrix {
66
67
  /// Creates a new Wavelet Matrix from the given list or tuple of integers.
67
68
  #[new]
68
69
  #[pyo3(signature = (data, on_disk=false))]
69
- fn new(data: &Bound<'_, PySequence>, on_disk: bool) -> PyResult<Self> {
70
+ fn new(data: &Bound<'_, PyAny>, on_disk: bool) -> PyResult<Self> {
70
71
  let (len, max_value) =
71
72
  data.try_iter()?
72
73
  .try_fold((0usize, BigUint::zero()), |(len, max_value), item| {
@@ -121,74 +122,69 @@ impl PyWaveletMatrix {
121
122
  WaveletMatrixEnum::BigUint(WaveletMatrix::<BigUint>::new(values))
122
123
  }
123
124
  (true, 0..=8) => {
124
- let mut values = MmapMut::map_anon(len * mem::size_of::<u8>())
125
+ let file = tempfile().map_err(PyRuntimeError::new_err)?;
126
+ file.set_len((len * mem::size_of::<u8>()) as u64)
125
127
  .map_err(PyRuntimeError::new_err)?;
128
+ #[allow(unsafe_code)]
129
+ let mut values =
130
+ unsafe { MmapMut::map_mut(&file).map_err(PyRuntimeError::new_err)? };
126
131
  let values_data: &mut [u8] = cast_slice_mut(&mut values[..]);
127
- data.try_iter()?
128
- .zip(values_data.iter_mut())
129
- .try_for_each(|(item, value)| {
130
- *value = item?.extract::<u8>().map_err(PyValueError::new_err)?;
131
- Ok::<_, PyErr>(())
132
- })?;
133
- WaveletMatrixEnum::DiskU8(DiskWaveletMatrix::<u8>::new(
134
- values.make_read_only().unwrap(),
135
- )?)
132
+ for (i, item) in data.try_iter()?.enumerate() {
133
+ values_data[i] = item?.extract::<u8>().map_err(PyValueError::new_err)?;
134
+ }
135
+ WaveletMatrixEnum::DiskU8(DiskWaveletMatrix::<u8>::new(values, file)?)
136
136
  }
137
137
  (true, 9..=16) => {
138
- let mut values = MmapMut::map_anon(len * mem::size_of::<u16>())
138
+ let file = tempfile().map_err(PyRuntimeError::new_err)?;
139
+ file.set_len((len * mem::size_of::<u16>()) as u64)
139
140
  .map_err(PyRuntimeError::new_err)?;
141
+ #[allow(unsafe_code)]
142
+ let mut values =
143
+ unsafe { MmapMut::map_mut(&file).map_err(PyRuntimeError::new_err)? };
140
144
  let values_data: &mut [u16] = cast_slice_mut(&mut values[..]);
141
- data.try_iter()?
142
- .zip(values_data.iter_mut())
143
- .try_for_each(|(item, value)| {
144
- *value = item?.extract::<u16>().map_err(PyValueError::new_err)?;
145
- Ok::<_, PyErr>(())
146
- })?;
147
- WaveletMatrixEnum::DiskU16(DiskWaveletMatrix::<u16>::new(
148
- values.make_read_only().unwrap(),
149
- )?)
145
+ for (i, item) in data.try_iter()?.enumerate() {
146
+ values_data[i] = item?.extract::<u16>().map_err(PyValueError::new_err)?;
147
+ }
148
+ WaveletMatrixEnum::DiskU16(DiskWaveletMatrix::<u16>::new(values, file)?)
150
149
  }
151
150
  (true, 17..=32) => {
152
- let mut values = MmapMut::map_anon(len * mem::size_of::<u32>())
151
+ let file = tempfile().map_err(PyRuntimeError::new_err)?;
152
+ file.set_len((len * mem::size_of::<u32>()) as u64)
153
153
  .map_err(PyRuntimeError::new_err)?;
154
+ #[allow(unsafe_code)]
155
+ let mut values =
156
+ unsafe { MmapMut::map_mut(&file).map_err(PyRuntimeError::new_err)? };
154
157
  let values_data: &mut [u32] = cast_slice_mut(&mut values[..]);
155
- data.try_iter()?
156
- .zip(values_data.iter_mut())
157
- .try_for_each(|(item, value)| {
158
- *value = item?.extract::<u32>().map_err(PyValueError::new_err)?;
159
- Ok::<_, PyErr>(())
160
- })?;
161
- WaveletMatrixEnum::DiskU32(DiskWaveletMatrix::<u32>::new(
162
- values.make_read_only().unwrap(),
163
- )?)
158
+ for (i, item) in data.try_iter()?.enumerate() {
159
+ values_data[i] = item?.extract::<u32>().map_err(PyValueError::new_err)?;
160
+ }
161
+ WaveletMatrixEnum::DiskU32(DiskWaveletMatrix::<u32>::new(values, file)?)
164
162
  }
165
163
  (true, 33..=64) => {
166
- let mut values = MmapMut::map_anon(len * mem::size_of::<u64>())
164
+ let file = tempfile().map_err(PyRuntimeError::new_err)?;
165
+ file.set_len((len * mem::size_of::<u64>()) as u64)
167
166
  .map_err(PyRuntimeError::new_err)?;
167
+ #[allow(unsafe_code)]
168
+ let mut values =
169
+ unsafe { MmapMut::map_mut(&file).map_err(PyRuntimeError::new_err)? };
168
170
  let values_data: &mut [u64] = cast_slice_mut(&mut values[..]);
169
- data.try_iter()?
170
- .zip(values_data.iter_mut())
171
- .try_for_each(|(item, value)| {
172
- *value = item?.extract::<u64>().map_err(PyValueError::new_err)?;
173
- Ok::<_, PyErr>(())
174
- })?;
175
- WaveletMatrixEnum::DiskU64(DiskWaveletMatrix::<u64>::new(
176
- values.make_read_only().unwrap(),
177
- )?)
171
+ for (i, item) in data.try_iter()?.enumerate() {
172
+ values_data[i] = item?.extract::<u64>().map_err(PyValueError::new_err)?;
173
+ }
174
+ WaveletMatrixEnum::DiskU64(DiskWaveletMatrix::<u64>::new(values, file)?)
178
175
  }
179
176
  (true, 65..=128) => {
180
- let mut values = MmapMut::map_anon(len * mem::size_of::<u128>())
177
+ let file = tempfile().map_err(PyRuntimeError::new_err)?;
178
+ file.set_len((len * mem::size_of::<u128>()) as u64)
181
179
  .map_err(PyRuntimeError::new_err)?;
180
+ #[allow(unsafe_code)]
181
+ let mut values =
182
+ unsafe { MmapMut::map_mut(&file).map_err(PyRuntimeError::new_err)? };
182
183
  let values_data: &mut [u128] = cast_slice_mut(&mut values[..]);
183
- data.try_iter()?
184
- .zip(values_data.iter_mut())
185
- .try_for_each(|(item, value)| {
186
- *value = item?.extract::<u128>().map_err(PyValueError::new_err)?;
187
- Ok::<_, PyErr>(())
188
- })?;
189
- WaveletMatrixEnum::DiskU128(DiskWaveletMatrix::<u128>::new(
190
- values.make_read_only().unwrap(),
191
- )?)
184
+ for (i, item) in data.try_iter()?.enumerate() {
185
+ values_data[i] = item?.extract::<u128>().map_err(PyValueError::new_err)?;
186
+ }
187
+ WaveletMatrixEnum::DiskU128(DiskWaveletMatrix::<u128>::new(values, file)?)
192
188
  }
193
189
  (true, _) => {
194
190
  return Err(PyValueError::new_err(
@@ -1150,9 +1146,9 @@ mod tests {
1150
1146
  Python::attach(|py| {
1151
1147
  let elements = vec![5, 4, 5, 5, 2, 1, 5, 6, 1, 3, 5, 0];
1152
1148
  let pylist = PyList::new(py, &elements).unwrap();
1153
- let pysequence = pylist.cast::<PySequence>().unwrap();
1154
- let wm = PyWaveletMatrix::new(pysequence, false).unwrap();
1155
- let disk_wm = PyWaveletMatrix::new(pysequence, true).unwrap();
1149
+ let pyany = pylist.cast::<PyAny>().unwrap();
1150
+ let wm = PyWaveletMatrix::new(pyany, false).unwrap();
1151
+ let disk_wm = PyWaveletMatrix::new(pyany, true).unwrap();
1156
1152
 
1157
1153
  assert_eq!(wm.__len__(py).unwrap(), elements.len());
1158
1154
  assert_eq!(disk_wm.__len__(py).unwrap(), elements.len());
@@ -1534,9 +1530,9 @@ mod tests {
1534
1530
  0 << 8,
1535
1531
  ];
1536
1532
  let pylist = PyList::new(py, &elements).unwrap();
1537
- let pysequence = pylist.cast::<PySequence>().unwrap();
1538
- let wm = PyWaveletMatrix::new(pysequence, false).unwrap();
1539
- let disk_wm = PyWaveletMatrix::new(pysequence, true).unwrap();
1533
+ let pyany = pylist.cast::<PyAny>().unwrap();
1534
+ let wm = PyWaveletMatrix::new(pyany, false).unwrap();
1535
+ let disk_wm = PyWaveletMatrix::new(pyany, true).unwrap();
1540
1536
 
1541
1537
  assert_eq!(wm.__len__(py).unwrap(), elements.len());
1542
1538
  assert_eq!(disk_wm.__len__(py).unwrap(), elements.len());
@@ -1918,9 +1914,9 @@ mod tests {
1918
1914
  0 << 16,
1919
1915
  ];
1920
1916
  let pylist = PyList::new(py, &elements).unwrap();
1921
- let pysequence = pylist.cast::<PySequence>().unwrap();
1922
- let wm = PyWaveletMatrix::new(pysequence, false).unwrap();
1923
- let disk_wm = PyWaveletMatrix::new(pysequence, true).unwrap();
1917
+ let pyany = pylist.cast::<PyAny>().unwrap();
1918
+ let wm = PyWaveletMatrix::new(pyany, false).unwrap();
1919
+ let disk_wm = PyWaveletMatrix::new(pyany, true).unwrap();
1924
1920
 
1925
1921
  assert_eq!(wm.__len__(py).unwrap(), elements.len());
1926
1922
  assert_eq!(disk_wm.__len__(py).unwrap(), elements.len());
@@ -2302,9 +2298,9 @@ mod tests {
2302
2298
  0 << 32,
2303
2299
  ];
2304
2300
  let pylist = PyList::new(py, &elements).unwrap();
2305
- let pysequence = pylist.cast::<PySequence>().unwrap();
2306
- let wm = PyWaveletMatrix::new(pysequence, false).unwrap();
2307
- let disk_wm = PyWaveletMatrix::new(pysequence, true).unwrap();
2301
+ let pyany = pylist.cast::<PyAny>().unwrap();
2302
+ let wm = PyWaveletMatrix::new(pyany, false).unwrap();
2303
+ let disk_wm = PyWaveletMatrix::new(pyany, true).unwrap();
2308
2304
 
2309
2305
  assert_eq!(wm.__len__(py).unwrap(), elements.len());
2310
2306
  assert_eq!(disk_wm.__len__(py).unwrap(), elements.len());
@@ -2686,9 +2682,9 @@ mod tests {
2686
2682
  0 << 64,
2687
2683
  ];
2688
2684
  let pylist = PyList::new(py, &elements).unwrap();
2689
- let pysequence = pylist.cast::<PySequence>().unwrap();
2690
- let wm = PyWaveletMatrix::new(pysequence, false).unwrap();
2691
- let disk_wm = PyWaveletMatrix::new(pysequence, true).unwrap();
2685
+ let pyany = pylist.cast::<PyAny>().unwrap();
2686
+ let wm = PyWaveletMatrix::new(pyany, false).unwrap();
2687
+ let disk_wm = PyWaveletMatrix::new(pyany, true).unwrap();
2692
2688
 
2693
2689
  assert_eq!(wm.__len__(py).unwrap(), elements.len());
2694
2690
  assert_eq!(disk_wm.__len__(py).unwrap(), elements.len());
@@ -3074,8 +3070,8 @@ mod tests {
3074
3070
  BigUint::from(0u32) << 128,
3075
3071
  ];
3076
3072
  let pylist = elements.clone().into_pyobject(py).unwrap();
3077
- let pysequence = pylist.cast::<PySequence>().unwrap();
3078
- let wm = PyWaveletMatrix::new(pysequence, false).unwrap();
3073
+ let pyany = pylist.cast::<PyAny>().unwrap();
3074
+ let wm = PyWaveletMatrix::new(pyany, false).unwrap();
3079
3075
 
3080
3076
  assert_eq!(wm.__len__(py).unwrap(), elements.len());
3081
3077
  assert_eq!(
@@ -1,5 +1,6 @@
1
1
  use std::{collections, hash, iter, ops};
2
2
 
3
+ use itertools::Itertools;
3
4
  use num_bigint::ToBigUint;
4
5
  use num_traits::{One, Zero};
5
6
  use rayon::prelude::*;
@@ -46,8 +47,8 @@ where
46
47
  .par_iter()
47
48
  .map(|value| (value >> (height - i - 1) & NumberType::one()).is_one())
48
49
  .collect::<Vec<bool>>();
49
- let zeros_count = current_layer_bits.par_iter().filter(|&&b| !b).count();
50
50
 
51
+ let zeros_count = current_layer_bits.par_iter().filter(|&&b| !b).count();
51
52
  let mut next_values = vec![NumberType::one(); len];
52
53
  let mut zero_index = 0usize;
53
54
  let mut one_index = zeros_count;
@@ -62,19 +63,17 @@ where
62
63
  }
63
64
 
64
65
  let current_layer_blocks = current_layer_bits
65
- .into_par_iter()
66
+ .into_iter()
66
67
  .chunks(BlockType::BITS as usize)
68
+ .into_iter()
67
69
  .map(|chunk| {
68
- chunk
69
- .iter()
70
- .enumerate()
71
- .fold(BlockType::zero(), |acc, (j, &b)| {
72
- if b {
73
- acc | (BlockType::one() << j)
74
- } else {
75
- acc
76
- }
77
- })
70
+ chunk.enumerate().fold(BlockType::zero(), |acc, (j, b)| {
71
+ if b {
72
+ acc | (BlockType::one() << j)
73
+ } else {
74
+ acc
75
+ }
76
+ })
78
77
  })
79
78
  .collect::<Vec<_>>();
80
79
 
File without changes