usearch 2.8.15 → 2.9.0

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 (76) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.yml +1 -1
  2. package/.github/workflows/prerelease.yml +37 -11
  3. package/.github/workflows/release.yml +30 -28
  4. package/.gitmodules +4 -1
  5. package/CITATION.cff +1 -1
  6. package/CMakeLists.txt +6 -8
  7. package/CONTRIBUTING.md +20 -1
  8. package/Cargo.toml +1 -1
  9. package/README.md +8 -7
  10. package/VERSION +1 -1
  11. package/conanfile.py +1 -1
  12. package/cpp/test.cpp +9 -2
  13. package/include/usearch/index.hpp +11 -11
  14. package/include/usearch/index_plugins.hpp +4 -2
  15. package/javascript/usearch.js +1 -1
  16. package/package.json +1 -1
  17. package/pyproject.toml +2 -2
  18. package/setup.py +10 -4
  19. package/simsimd/.releaserc +3 -2
  20. package/simsimd/Cargo.lock +708 -0
  21. package/simsimd/Cargo.toml +36 -0
  22. package/simsimd/README.md +91 -25
  23. package/simsimd/binding.gyp +18 -0
  24. package/simsimd/build.rs +20 -0
  25. package/simsimd/include/simsimd/probability.h +5 -5
  26. package/simsimd/include/simsimd/simsimd.h +9 -5
  27. package/simsimd/include/simsimd/spatial.h +20 -21
  28. package/simsimd/include/simsimd/types.h +5 -1
  29. package/simsimd/javascript/bench.js +20 -10
  30. package/simsimd/javascript/dist-package-cjs.json +3 -0
  31. package/simsimd/javascript/dist-package-esm.json +3 -0
  32. package/simsimd/javascript/fallback.ts +193 -0
  33. package/simsimd/javascript/node-gyp-build.d.ts +1 -0
  34. package/simsimd/javascript/simsimd.ts +124 -0
  35. package/simsimd/javascript/test.mjs +153 -0
  36. package/simsimd/javascript/tsconfig-base.json +25 -0
  37. package/simsimd/javascript/tsconfig-cjs.json +8 -0
  38. package/simsimd/javascript/tsconfig-esm.json +8 -0
  39. package/simsimd/package-lock.json +1688 -0
  40. package/simsimd/package.json +26 -11
  41. package/simsimd/rust/benches/cosine.rs +27 -0
  42. package/simsimd/rust/benches/native.rs +27 -0
  43. package/simsimd/rust/benches/sqeuclidean.rs +27 -0
  44. package/simsimd/rust/lib.c +68 -0
  45. package/simsimd/rust/lib.rs +232 -0
  46. package/sqlite/README.md +178 -0
  47. package/sqlite/lib.cpp +325 -0
  48. package/stringzilla/CONTRIBUTING.md +429 -0
  49. package/stringzilla/Cargo.lock +25 -0
  50. package/stringzilla/Cargo.toml +26 -0
  51. package/stringzilla/LICENSE +201 -0
  52. package/stringzilla/README.md +1281 -0
  53. package/stringzilla/VERSION +1 -0
  54. package/stringzilla/assets/cover-strinzilla.jpeg +0 -0
  55. package/stringzilla/assets/meme-stringzilla-v2.jpeg +0 -0
  56. package/stringzilla/assets/meme-stringzilla-v3.jpeg +0 -0
  57. package/stringzilla/binding.gyp +16 -0
  58. package/stringzilla/build.rs +14 -0
  59. package/stringzilla/c/lib.c +304 -0
  60. package/stringzilla/cli/README.md +48 -0
  61. package/stringzilla/cli/split.py +72 -0
  62. package/stringzilla/cli/wc.py +37 -0
  63. package/stringzilla/include/stringzilla/experimental.h +724 -0
  64. package/stringzilla/include/stringzilla/module.modulemap +9 -0
  65. package/stringzilla/include/stringzilla/stringzilla.h +5240 -0
  66. package/stringzilla/include/stringzilla/stringzilla.hpp +3830 -0
  67. package/stringzilla/javascript/lib.c +125 -0
  68. package/stringzilla/javascript/stringzilla.js +22 -0
  69. package/stringzilla/package-ci.json +10 -0
  70. package/stringzilla/package.json +32 -0
  71. package/stringzilla/rust/lib.rs +362 -0
  72. package/stringzilla/swift/StringProtocol+StringZilla.swift +280 -0
  73. package/stringzilla/swift/Test.swift +60 -0
  74. package/wasmer.toml +1 -1
  75. package/simsimd/javascript/simsimd.js +0 -45
  76. package/simsimd/javascript/test/simsimd.test.js +0 -47
@@ -1,7 +1,7 @@
1
1
  name: Report a bug
2
2
  description: Something doesn't work as expected?
3
3
  title: "Bug: "
4
- labels: ["bug", "invalid"]
4
+ labels: ["bug"]
5
5
  assignees:
6
6
  - octocat
7
7
  body:
@@ -59,11 +59,11 @@ jobs:
59
59
  - name: Set up Node.js
60
60
  uses: actions/setup-node@v3
61
61
  with:
62
- node-version: 18
62
+ node-version: 20
63
63
  - name: Build JavaScript
64
- run: npm install
64
+ run: npm ci
65
65
  - name: Test JavaScript
66
- run: npm ci && npm test
66
+ run: npm test
67
67
 
68
68
  # Rust
69
69
  - name: Test Rust
@@ -151,10 +151,9 @@ jobs:
151
151
  - name: Set up Node.js
152
152
  uses: actions/setup-node@v3
153
153
  with:
154
- node-version: 18
154
+ node-version: 20
155
155
  - name: Build and test JavaScript
156
156
  run: |
157
- npm install
158
157
  npm ci
159
158
  npm test
160
159
 
@@ -210,11 +209,11 @@ jobs:
210
209
  - name: Set up Node.js
211
210
  uses: actions/setup-node@v3
212
211
  with:
213
- node-version: 18
212
+ node-version: 20
214
213
  - name: Build JavaScript
215
- run: npm install
214
+ run: npm ci
216
215
  - name: Test JavaScript
217
- run: npm ci && npm test
216
+ run: npm test
218
217
 
219
218
  # ObjC/Swift
220
219
  - name: Build ObjC/Swift
@@ -272,11 +271,11 @@ jobs:
272
271
  - name: Set up Node.js
273
272
  uses: actions/setup-node@v3
274
273
  with:
275
- node-version: 18
274
+ node-version: 20
276
275
  - name: Build JavaScript
277
- run: npm install
276
+ run: npm ci
278
277
  - name: Test JavaScript
279
- run: npm ci && npm test
278
+ run: npm test
280
279
 
281
280
  # C#
282
281
  - name: Setup .NET ${{ env.DOTNET_VERSION }}
@@ -303,3 +302,30 @@ jobs:
303
302
  context: .
304
303
  load: true
305
304
  push: false
305
+
306
+
307
+ build_wheels:
308
+ name: Build Python ${{ matrix.python-version }} for ${{ matrix.os }}
309
+ runs-on: ${{ matrix.os }}
310
+ needs: [test_ubuntu_gcc, test_ubuntu_clang, test_macos, test_windows]
311
+ strategy:
312
+ matrix:
313
+ os: [ubuntu-latest, macos-latest, windows-latest]
314
+ python-version: ["37", "38", "39", "310", "311", "312"]
315
+ steps:
316
+ - uses: actions/checkout@v4
317
+ - name: Set up Python
318
+ uses: actions/setup-python@v5
319
+ with:
320
+ python-version: 3.x
321
+
322
+ # We only need QEMU for Linux builds
323
+ - name: Setup QEMU
324
+ if: matrix.os == 'ubuntu-latest'
325
+ uses: docker/setup-qemu-action@v3
326
+ - name: Install cibuildwheel
327
+ run: python -m pip install cibuildwheel
328
+ - name: Build wheels
329
+ run: cibuildwheel --output-dir wheelhouse
330
+ env:
331
+ CIBW_BUILD: cp${{ matrix.python-version }}-*
@@ -24,7 +24,10 @@ jobs:
24
24
  - uses: actions/checkout@v3
25
25
  with:
26
26
  persist-credentials: false
27
- - uses: actions/setup-node@v3
27
+ - name: Set up Node.js
28
+ uses: actions/setup-node@v3
29
+ with:
30
+ node-version: 20
28
31
  - run: npm install --save-dev --prefix ./package-ci @semantic-release/exec @semantic-release/git conventional-changelog-eslint semantic-release && npx --prefix ./package-ci semantic-release
29
32
 
30
33
  rebase:
@@ -346,39 +349,36 @@ jobs:
346
349
  * ${{ steps.hashes.outputs.asset_name_15 }} : `${{ steps.hashes.outputs.asset_hash_15 }}`
347
350
 
348
351
  build_wheels:
349
- name: Build Python
350
- needs: versioning
352
+ name: Build Python ${{ matrix.python-version }} for ${{ matrix.os }}
351
353
  runs-on: ${{ matrix.os }}
354
+ needs: versioning
352
355
  strategy:
353
- fail-fast: false
354
356
  matrix:
355
- os: [ubuntu-22.04, macOS-11, windows-2022]
356
-
357
+ os: [ubuntu-latest, macos-latest, windows-latest]
358
+ python-version: ["37", "38", "39", "310", "311", "312"]
357
359
  steps:
358
- - uses: actions/checkout@v3
360
+ - uses: actions/checkout@v4
359
361
  with:
360
362
  ref: "main"
361
- - uses: actions/setup-python@v3
362
-
363
- - name: Setup Docker
364
- if: matrix.os == 'ubuntu-22.04'
365
- uses: crazy-max/ghaction-setup-docker@v1.0.0
363
+ - name: Set up Python
364
+ uses: actions/setup-python@v5
366
365
  with:
367
- version: 23.0.1
368
-
366
+ python-version: 3.x
369
367
  - name: Setup QEMU
370
- if: matrix.os == 'ubuntu-22.04'
371
- uses: docker/setup-qemu-action@v2.1.0
372
-
373
- - name: Install CIBuildWheel
368
+ if: matrix.os == 'ubuntu-latest' # We only need QEMU for Linux builds
369
+ uses: docker/setup-qemu-action@v3
370
+ - name: Install cibuildwheel
374
371
  run: python -m pip install cibuildwheel
375
-
376
372
  - name: Build wheels
377
- run: python -m cibuildwheel
378
-
379
- - uses: actions/upload-artifact@v3
373
+ run: cibuildwheel --output-dir wheelhouse
374
+ env:
375
+ CIBW_BUILD: cp${{ matrix.python-version }}-*
376
+ - name: Upload wheels
377
+ uses: actions/upload-artifact@v4
380
378
  with:
379
+ name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
381
380
  path: ./wheelhouse/*.whl
381
+ overwrite: true
382
382
 
383
383
  publish_python:
384
384
  name: Publish Python
@@ -392,17 +392,20 @@ jobs:
392
392
 
393
393
  steps:
394
394
  - name: Download artifacts
395
- uses: actions/download-artifact@v3.0.2
395
+ uses: actions/download-artifact@v4
396
396
  with:
397
- path: ./dist/
397
+ # unpacks all CIBW artifacts into dist/
398
+ pattern: cibw-*
399
+ path: dist
400
+ merge-multiple: true
398
401
 
399
402
  - name: Publish to PyPi
400
403
  uses: pypa/gh-action-pypi-publish@release/v1
401
404
  with:
402
- packages-dir: ./dist/artifact
405
+ packages-dir: dist
403
406
  verbose: true
404
407
  print-hash: true
405
-
408
+
406
409
  publish_javascript:
407
410
  name: Publish JavaScript
408
411
  needs: versioning
@@ -425,11 +428,10 @@ jobs:
425
428
  - name: Set up Node.js
426
429
  uses: actions/setup-node@v3
427
430
  with:
428
- node-version: 18
431
+ node-version: 20
429
432
 
430
433
  - name: Build and Test
431
434
  run: |
432
- npm install
433
435
  npm ci
434
436
  npm test
435
437
  npm run typegen
package/.gitmodules CHANGED
@@ -3,4 +3,7 @@
3
3
  url = https://github.com/ashvardanian/simsimd
4
4
  [submodule "fp16"]
5
5
  path = fp16
6
- url = https://github.com/maratyszcza/fp16
6
+ url = https://github.com/maratyszcza/fp16
7
+ [submodule "stringzilla"]
8
+ path = stringzilla
9
+ url = https://github.com/ashvardanian/stringzilla
package/CITATION.cff CHANGED
@@ -5,7 +5,7 @@ authors:
5
5
  given-names: "Ash"
6
6
  orcid: "https://orcid.org/0000-0002-4882-1815"
7
7
  title: "USearch by Unum Cloud"
8
- version: 2.8.15
8
+ version: 2.9.0
9
9
  doi: 10.5281/zenodo.7949416
10
10
  date-released: 2023-10-22
11
11
  url: "https://github.com/unum-cloud/usearch"
package/CMakeLists.txt CHANGED
@@ -13,6 +13,11 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
13
13
  set(USEARCH_IS_MAIN_PROJECT ON)
14
14
  endif ()
15
15
 
16
+ # Allow CMake 3.13+ to override options when using FetchContent / add_subdirectory
17
+ if (POLICY CMP0077)
18
+ cmake_policy(SET CMP0077 NEW)
19
+ endif ()
20
+
16
21
  # Options
17
22
  option(USEARCH_INSTALL "Install CMake targets" OFF)
18
23
 
@@ -31,11 +36,6 @@ option(USEARCH_BUILD_WOLFRAM "Compile Wolfram Language bindings" OFF)
31
36
  set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
32
37
  include(ExternalProject)
33
38
 
34
- # Allow CMake 3.13+ to override options when using FetchContent / add_subdirectory
35
- if (POLICY CMP0077)
36
- cmake_policy(SET CMP0077 NEW)
37
- endif ()
38
-
39
39
  # Configuration
40
40
  include(GNUInstallDirs)
41
41
  set(USEARCH_TARGET_NAME ${PROJECT_NAME})
@@ -186,9 +186,7 @@ function (setup_target TARGET_NAME)
186
186
  target_link_libraries(${TARGET_NAME} PRIVATE OpenMP::OpenMP_CXX)
187
187
  endif ()
188
188
 
189
- if (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
190
- target_link_libraries(${TARGET_NAME} PRIVATE Threads::Threads)
191
- endif ()
189
+ target_link_libraries(${TARGET_NAME} PRIVATE Threads::Threads)
192
190
 
193
191
  elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
194
192
  target_compile_options(
package/CONTRIBUTING.md CHANGED
@@ -130,7 +130,26 @@ Still, if you have Docker running on any desktop OS, you can use it to build and
130
130
 
131
131
  ```sh
132
132
  pip install cibuildwheel
133
- cibuildwheel --platform linux
133
+ cibuildwheel
134
+ cibuildwheel --platform linux # works on any OS and builds all Linux backends
135
+ cibuildwheel --platform linux --archs x86_64 # 64-bit x86, the most common on desktop and servers
136
+ cibuildwheel --platform linux --archs aarch64 # 64-bit Arm for mobile devices, Apple M-series, and AWS Graviton
137
+ cibuildwheel --platform linux --archs i686 # 32-bit Linux
138
+ cibuildwheel --platform linux --archs s390x # emulating big-endian IBM Z
139
+ cibuildwheel --platform macos # works only on MacOS
140
+ cibuildwheel --platform windows # works only on Windows
141
+ ```
142
+
143
+ You may need root previligies for multi-architecture builds:
144
+
145
+ ```sh
146
+ sudo $(which cibuildwheel) --platform linux
147
+ ```
148
+
149
+ On Windows and MacOS, to avoid frequent path resolution issues, you may want to use:
150
+
151
+ ```sh
152
+ python -m cibuildwheel --platform windows
134
153
  ```
135
154
 
136
155
  ## JavaScript
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "2.8.15"
3
+ version = "2.9.0"
4
4
  authors = ["Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
5
5
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
6
6
  edition = "2021"
package/README.md CHANGED
@@ -30,13 +30,14 @@ Spatial • Binary • Probabilistic • User-Defined Metrics
30
30
  <a href="https://unum-cloud.github.io/usearch/swift">Swift</a> •
31
31
  <a href="https://unum-cloud.github.io/usearch/csharp">C#</a> •
32
32
  <a href="https://unum-cloud.github.io/usearch/golang">GoLang</a> •
33
- <a href="https://unum-cloud.github.io/usearch/wolfram">Wolfram</a>
33
+ <a href="https://unum-cloud.github.io/usearch/wolfram">Wolfram</a> •
34
+ <a href="https://unum-cloud.github.io/usearch/sqlite">SQLite3</a>
34
35
  <br/>
35
36
  Linux • MacOS • Windows • iOS • WebAssembly
36
37
  </p>
37
38
 
38
39
  <div align="center">
39
- <a href="https://pepy.tech/project/usearch"> <img alt="PyPI" src="https://static.pepy.tech/personalized-badge/usearch?period=month&units=abbreviation&left_color=black&right_color=blue&left_text=Python%20monthly%20installs"> </a>
40
+ <a href="https://pepy.tech/project/usearch"> <img alt="PyPI" src="https://static.pepy.tech/personalized-badge/usearch?period=total&units=abbreviation&left_color=black&right_color=blue&left_text=USearch%20Python%20installs"> </a>
40
41
  <a href="https://www.npmjs.com/package/usearch"> <img alt="NPM" src="https://img.shields.io/npm/dy/usearch?label=NPM%20installs"> </a>
41
42
  <a href="https://crates.io/crates/usearch"> <img alt="Crate" src="https://img.shields.io/crates/d/usearch?label=Crate%20installs"> </a>
42
43
  <a href="https://www.nuget.org/packages/Cloud.Unum.USearch"> <img alt="NuGet" src="https://img.shields.io/nuget/dt/Cloud.Unum.USearch?label=NuGet%20installs"> </a>
@@ -47,10 +48,10 @@ Linux • MacOS • Windows • iOS • WebAssembly
47
48
 
48
49
  ---
49
50
 
50
- - ✅ [10x faster][faster-than-faiss] [HNSW][hnsw-algorithm] implementation than [FAISS][faiss].
51
- - ✅ Simple and extensible [single C++11 header][usearch-header] implementation.
51
+ - ✅ __[10x faster][faster-than-faiss]__ [HNSW][hnsw-algorithm] implementation than [FAISS][faiss].
52
+ - ✅ Simple and extensible [single C++11 header][usearch-header] __library__.
52
53
  - ✅ Compatible with a dozen programming languages out of the box.
53
- - ✅ [Trusted](#integrations) by some of the most loved Datalakes and Databases, like [ClickHouse][clickhouse-docs].
54
+ - ✅ [Trusted](#integrations) by giants like Google and databases like [ClickHouse][clickhouse-docs].
54
55
  - ✅ [SIMD][simd]-optimized and [user-defined metrics](#user-defined-functions) with JIT compilation.
55
56
  - ✅ Hardware-agnostic `f16` & `i8` - [half-precision & quarter-precision support](#memory-efficiency-downcasting-and-quantization).
56
57
  - ✅ [View large indexes from disk](#serving-index-from-disk) without loading into RAM.
@@ -60,7 +61,7 @@ Linux • MacOS • Windows • iOS • WebAssembly
60
61
  - ✅ Space-efficient point-clouds with `uint40_t`, accommodating 4B+ size.
61
62
  - ✅ Compatible with OpenMP and custom "executors" for fine-grained control over CPU utilization.
62
63
  - ✅ Near-real-time [clustering and sub-clustering](#clustering) for Tens or Millions of clusters.
63
- - ✅ [Semantic Search](#usearch--ai--multi-modal-semantic-search) and [Joins](#joins).
64
+ - ✅ [Semantic Search](#usearch--ai--multi-modal-semantic-search) and [Joins](#joins-one-to-one-one-to-many-and-many-to-many-mappings).
64
65
 
65
66
  [faiss]: https://github.com/facebookresearch/faiss
66
67
  [usearch-header]: https://github.com/unum-cloud/usearch/blob/main/include/usearch/index.hpp
@@ -433,7 +434,7 @@ doi = {10.5281/zenodo.7949416},
433
434
  author = {Vardanian, Ash},
434
435
  title = {{USearch by Unum Cloud}},
435
436
  url = {https://github.com/unum-cloud/usearch},
436
- version = {2.8.15},
437
+ version = {2.9.0},
437
438
  year = {2023},
438
439
  month = oct,
439
440
  }
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.8.15
1
+ 2.9.0
package/conanfile.py CHANGED
@@ -7,7 +7,7 @@ required_conan_version = ">=1.53.0"
7
7
  class USearchConan(ConanFile):
8
8
 
9
9
  name = "usearch"
10
- version = '2.8.15'
10
+ version = '2.9.0'
11
11
  license = "Apache-2.0"
12
12
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
13
13
  homepage = "https://github.com/unum-cloud/usearch"
package/cpp/test.cpp CHANGED
@@ -209,7 +209,14 @@ void test_cosine(std::size_t collection_size, std::size_t dimensions) {
209
209
  metric_punned_t metric(dimensions, metric_kind_t::cos_k, scalar_kind<scalar_at>());
210
210
  index_dense_config_t config(connectivity);
211
211
  config.multi = multi;
212
- index_t index = index_t::make(metric, config);
212
+ index_t index;
213
+ {
214
+ index_t index_tmp1 = index_t::make(metric, config);
215
+ // move construction
216
+ index_t index_tmp2 = std::move(index_tmp1);
217
+ // move assignment
218
+ index = std::move(index_tmp2);
219
+ }
213
220
  test_cosine<true>(index, matrix);
214
221
  }
215
222
  }
@@ -313,4 +320,4 @@ int main(int, char**) {
313
320
  test_tanimoto<std::int64_t, std::uint32_t>(dimensions, connectivity);
314
321
 
315
322
  return 0;
316
- }
323
+ }
@@ -10,8 +10,8 @@
10
10
  #define UNUM_USEARCH_HPP
11
11
 
12
12
  #define USEARCH_VERSION_MAJOR 2
13
- #define USEARCH_VERSION_MINOR 8
14
- #define USEARCH_VERSION_PATCH 15
13
+ #define USEARCH_VERSION_MINOR 9
14
+ #define USEARCH_VERSION_PATCH 0
15
15
 
16
16
  // Inferring C++ version
17
17
  // https://stackoverflow.com/a/61552074
@@ -1362,7 +1362,7 @@ class output_file_t {
1362
1362
  serialization_result_t write(void const* begin, std::size_t length) noexcept {
1363
1363
  serialization_result_t result;
1364
1364
  std::size_t written = std::fwrite(begin, length, 1, file_);
1365
- if (!written)
1365
+ if (length && !written)
1366
1366
  return result.failed(std::strerror(errno));
1367
1367
  return result;
1368
1368
  }
@@ -1404,7 +1404,7 @@ class input_file_t {
1404
1404
  serialization_result_t read(void* begin, std::size_t length) noexcept {
1405
1405
  serialization_result_t result;
1406
1406
  std::size_t read = std::fread(begin, length, 1, file_);
1407
- if (!read)
1407
+ if (length && !read)
1408
1408
  return result.failed(std::feof(file_) ? "End of file reached!" : std::strerror(errno));
1409
1409
  return result;
1410
1410
  }
@@ -1942,7 +1942,7 @@ class index_gt {
1942
1942
  std::size_t connectivity() const noexcept { return config_.connectivity; }
1943
1943
  std::size_t capacity() const noexcept { return nodes_capacity_; }
1944
1944
  std::size_t size() const noexcept { return nodes_count_; }
1945
- std::size_t max_level() const noexcept { return static_cast<std::size_t>(max_level_); }
1945
+ std::size_t max_level() const noexcept { return nodes_count_ ? static_cast<std::size_t>(max_level_) : 0; }
1946
1946
  index_config_t const& config() const noexcept { return config_; }
1947
1947
  index_limits_t const& limits() const noexcept { return limits_; }
1948
1948
  bool is_immutable() const noexcept { return bool(viewed_file_); }
@@ -3362,7 +3362,7 @@ class index_gt {
3362
3362
  visits.clear();
3363
3363
 
3364
3364
  // Optional prefetching
3365
- if (!std::is_same<typename std::decay<prefetch_at>::type, dummy_prefetch_t>::value)
3365
+ if (!is_dummy<prefetch_at>())
3366
3366
  prefetch(citerator_at(closest_slot), citerator_at(closest_slot + 1));
3367
3367
 
3368
3368
  distance_t closest_dist = context.measure(query, citerator_at(closest_slot), metric);
@@ -3374,7 +3374,7 @@ class index_gt {
3374
3374
  neighbors_ref_t closest_neighbors = neighbors_non_base_(node_at_(closest_slot), level);
3375
3375
 
3376
3376
  // Optional prefetching
3377
- if (!std::is_same<typename std::decay<prefetch_at>::type, dummy_prefetch_t>::value) {
3377
+ if (!is_dummy<prefetch_at>()) {
3378
3378
  candidates_range_t missing_candidates{*this, closest_neighbors, visits};
3379
3379
  prefetch(missing_candidates.begin(), missing_candidates.end());
3380
3380
  }
@@ -3416,7 +3416,7 @@ class index_gt {
3416
3416
  return false;
3417
3417
 
3418
3418
  // Optional prefetching
3419
- if (!std::is_same<typename std::decay<prefetch_at>::type, dummy_prefetch_t>::value)
3419
+ if (!is_dummy<prefetch_at>())
3420
3420
  prefetch(citerator_at(start_slot), citerator_at(start_slot + 1));
3421
3421
 
3422
3422
  distance_t radius = context.measure(query, citerator_at(start_slot), metric);
@@ -3441,7 +3441,7 @@ class index_gt {
3441
3441
  neighbors_ref_t candidate_neighbors = neighbors_(candidate_ref, level);
3442
3442
 
3443
3443
  // Optional prefetching
3444
- if (!std::is_same<typename std::decay<prefetch_at>::type, dummy_prefetch_t>::value) {
3444
+ if (!is_dummy<prefetch_at>()) {
3445
3445
  candidates_range_t missing_candidates{*this, candidate_neighbors, visits};
3446
3446
  prefetch(missing_candidates.begin(), missing_candidates.end());
3447
3447
  }
@@ -3490,7 +3490,7 @@ class index_gt {
3490
3490
  return false;
3491
3491
 
3492
3492
  // Optional prefetching
3493
- if (!std::is_same<typename std::decay<prefetch_at>::type, dummy_prefetch_t>::value)
3493
+ if (!is_dummy<prefetch_at>())
3494
3494
  prefetch(citerator_at(start_slot), citerator_at(start_slot + 1));
3495
3495
 
3496
3496
  distance_t radius = context.measure(query, citerator_at(start_slot), metric);
@@ -3510,7 +3510,7 @@ class index_gt {
3510
3510
  neighbors_ref_t candidate_neighbors = neighbors_base_(node_at_(candidate.slot));
3511
3511
 
3512
3512
  // Optional prefetching
3513
- if (!std::is_same<typename std::decay<prefetch_at>::type, dummy_prefetch_t>::value) {
3513
+ if (!is_dummy<prefetch_at>()) {
3514
3514
  candidates_range_t missing_candidates{*this, candidate_neighbors, visits};
3515
3515
  prefetch(missing_candidates.begin(), missing_candidates.end());
3516
3516
  }
@@ -1345,8 +1345,9 @@ class metric_punned_t {
1345
1345
  #if USEARCH_USE_SIMSIMD
1346
1346
  if (!configure_with_simsimd())
1347
1347
  configure_with_auto_vectorized();
1348
- #endif
1348
+ #else
1349
1349
  configure_with_auto_vectorized();
1350
+ #endif
1350
1351
 
1351
1352
  if (scalar_kind == scalar_kind_t::b1x8_k)
1352
1353
  raw_arg3_ = raw_arg4_ = divide_round_up<CHAR_BIT>(dimensions_);
@@ -1819,7 +1820,8 @@ class flat_hash_multi_set_gt {
1819
1820
  }
1820
1821
 
1821
1822
  // Reset populated slots count
1822
- std::memset(data_, 0, buckets_ * bytes_per_bucket());
1823
+ if (data_)
1824
+ std::memset(data_, 0, buckets_ * bytes_per_bucket());
1823
1825
  populated_slots_ = 0;
1824
1826
  }
1825
1827
 
@@ -303,7 +303,7 @@ class Index {
303
303
  */
304
304
  remove(keys) {
305
305
  let normalizedKeys = normalizeKeys(keys);
306
- normalizedResults = this._compiledIndex.remove(normalizedKeys);
306
+ let normalizedResults = this._compiledIndex.remove(normalizedKeys);
307
307
  if (isOneKey(keys))
308
308
  return normalizedResults[0];
309
309
  else
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "2.8.15",
3
+ "version": "2.9.0",
4
4
  "description": "Smaller & Faster Single-File Vector Search Engine from Unum",
5
5
  "author": "Ash Vardanian (https://ashvardanian.com/)",
6
6
  "license": "Apache 2.0",
package/pyproject.toml CHANGED
@@ -16,7 +16,7 @@ filterwarnings = ["error"]
16
16
  test-requires = []
17
17
  test-command = ""
18
18
  build-verbosity = 0
19
- skip = ["*musllinux*", "*i686*", "pp*", "cp36-*", "cp312-*"]
19
+ skip = ["*musllinux*", "*i686*", "pp*", "cp36-*"]
20
20
 
21
21
  [tool.cibuildwheel.linux]
22
22
  before-build = [
@@ -48,4 +48,4 @@ before-build = [
48
48
  "git submodule update --init --recursive",
49
49
  ]
50
50
  archs = ["x86", "AMD64"]
51
- skip = ["*win32*", "pp*", "cp36-*", "cp312-*"]
51
+ skip = ["*win32*", "pp*", "cp36-*"]
package/setup.py CHANGED
@@ -5,6 +5,7 @@ from setuptools import setup
5
5
 
6
6
  from pybind11.setup_helpers import Pybind11Extension
7
7
 
8
+ sources = ["python/lib.cpp"]
8
9
  compile_args = []
9
10
  link_args = []
10
11
  macros_args = []
@@ -127,12 +128,14 @@ if is_windows:
127
128
  ]
128
129
  )
129
130
 
130
- print("macros_args", macros_args)
131
+ if is_linux or is_macos:
132
+ sources.append("sqlite/lib.cpp")
133
+ link_args.append("-lsqlite3")
131
134
 
132
135
  ext_modules = [
133
136
  Pybind11Extension(
134
137
  "usearch.compiled",
135
- ["python/lib.cpp"],
138
+ sources,
136
139
  extra_compile_args=compile_args,
137
140
  extra_link_args=link_args,
138
141
  define_macros=macros_args,
@@ -147,7 +150,11 @@ with open(os.path.join(this_directory, "README.md")) as f:
147
150
  long_description = f.read()
148
151
 
149
152
  # Depending on the macros, adjust the include directories
150
- include_dirs = ["include"]
153
+ include_dirs = [
154
+ "include",
155
+ "python",
156
+ "stringzilla/include",
157
+ ]
151
158
  if use_simsimd:
152
159
  include_dirs.append("simsimd/include")
153
160
  if use_fp16lib:
@@ -190,6 +197,5 @@ setup(
190
197
  install_requires=[
191
198
  "numpy",
192
199
  "tqdm",
193
- 'ucall; python_version >= "3.9"',
194
200
  ],
195
201
  )
@@ -74,9 +74,10 @@
74
74
  {
75
75
  "assets": [
76
76
  "VERSION",
77
- "conanfile.py",
78
77
  "package.json",
79
- "Cargo.toml"
78
+ "Cargo.toml",
79
+ "CMakeLists.txt",
80
+ "include/simsimd/simsimd.h"
80
81
  ],
81
82
  "message": "Build: Released ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
82
83
  }