usearch 2.10.2 → 2.10.5

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 (112) hide show
  1. package/README.md +1 -1
  2. package/binding.gyp +101 -0
  3. package/c/CMakeLists.txt +27 -0
  4. package/c/README.md +34 -0
  5. package/c/lib.cpp +362 -0
  6. package/c/test.c +382 -0
  7. package/c/usearch.h +356 -0
  8. package/cmake/clipp.cmake +7 -0
  9. package/cmake/config.cmake.in +15 -0
  10. package/cmake/emscripten.cmake +8 -0
  11. package/cmake/jemalloc.cmake +62 -0
  12. package/cmake/pkg-config.pc.in +4 -0
  13. package/cmake/usearchConfigVersion.cmake.in +20 -0
  14. package/cpp/CMakeLists.txt +14 -0
  15. package/cpp/README.md +161 -0
  16. package/cpp/bench.cpp +616 -0
  17. package/cpp/test.cpp +324 -0
  18. package/fp16/CMakeLists.txt +176 -0
  19. package/fp16/LICENSE +11 -0
  20. package/fp16/README.md +20 -0
  21. package/fp16/bench/alt-element.cc +89 -0
  22. package/fp16/bench/from-alt-array.cc +175 -0
  23. package/fp16/bench/from-ieee-array.cc +399 -0
  24. package/fp16/bench/ieee-element.cc +272 -0
  25. package/fp16/bench/to-alt-array.cc +91 -0
  26. package/fp16/bench/to-ieee-array.cc +303 -0
  27. package/fp16/cmake/DownloadGoogleBenchmark.cmake +15 -0
  28. package/fp16/cmake/DownloadGoogleTest.cmake +15 -0
  29. package/fp16/cmake/DownloadPSimd.cmake +15 -0
  30. package/fp16/configure.py +65 -0
  31. package/fp16/confu.yaml +8 -0
  32. package/fp16/include/fp16/__init__.py +0 -0
  33. package/fp16/include/fp16/avx.py +50 -0
  34. package/fp16/include/fp16/avx2.py +53 -0
  35. package/fp16/include/fp16/bitcasts.h +92 -0
  36. package/fp16/include/fp16/fp16.h +451 -0
  37. package/fp16/include/fp16/psimd.h +131 -0
  38. package/fp16/include/fp16.h +11 -0
  39. package/fp16/jni/Android.mk +6 -0
  40. package/fp16/jni/Application.mk +4 -0
  41. package/fp16/test/alt-from-fp32-value.cc +498 -0
  42. package/fp16/test/alt-to-fp32-bits.cc +263 -0
  43. package/fp16/test/alt-to-fp32-psimd.cc +145 -0
  44. package/fp16/test/alt-to-fp32-value.cc +348 -0
  45. package/fp16/test/alt-to-fp32x2-psimd.cc +245 -0
  46. package/fp16/test/bitcasts.cc +56 -0
  47. package/fp16/test/ieee-from-fp32-value.cc +523 -0
  48. package/fp16/test/ieee-to-fp32-bits.cc +333 -0
  49. package/fp16/test/ieee-to-fp32-psimd.cc +312 -0
  50. package/fp16/test/ieee-to-fp32-value.cc +420 -0
  51. package/fp16/test/ieee-to-fp32x2-psimd.cc +541 -0
  52. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +96 -0
  53. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +96 -0
  54. package/fp16/test/peachpy/stubs.py +38 -0
  55. package/fp16/test/tables.cc +530 -0
  56. package/fp16/test/tables.h +13 -0
  57. package/fp16/third-party/THHalf.h +92 -0
  58. package/fp16/third-party/eigen-half.h +170 -0
  59. package/fp16/third-party/float16-compressor.h +80 -0
  60. package/fp16/third-party/half.hpp +2916 -0
  61. package/fp16/third-party/npy-halffloat.h +328 -0
  62. package/include/usearch/index.hpp +3838 -0
  63. package/include/usearch/index_dense.hpp +2004 -0
  64. package/include/usearch/index_plugins.hpp +2255 -0
  65. package/javascript/dist-package-cjs.json +3 -0
  66. package/javascript/dist-package-esm.json +3 -0
  67. package/javascript/lib.cpp +350 -0
  68. package/javascript/node-gyp-build.d.ts +1 -0
  69. package/javascript/tsconfig-base.json +25 -0
  70. package/javascript/tsconfig-cjs.json +8 -0
  71. package/javascript/tsconfig-esm.json +8 -0
  72. package/javascript/usearch.test.js +84 -0
  73. package/javascript/usearch.ts +640 -0
  74. package/package.json +10 -3
  75. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  76. package/prebuilds/linux-arm64/usearch.node +0 -0
  77. package/prebuilds/linux-x64/usearch.node +0 -0
  78. package/prebuilds/win32-ia32/usearch.node +0 -0
  79. package/prebuilds/win32-x64/usearch.node +0 -0
  80. package/simsimd/.releaserc +87 -0
  81. package/simsimd/CONTRIBUTING.md +114 -0
  82. package/simsimd/Cargo.lock +709 -0
  83. package/simsimd/Cargo.toml +44 -0
  84. package/simsimd/LICENSE +201 -0
  85. package/simsimd/README.md +708 -0
  86. package/simsimd/binding.gyp +36 -0
  87. package/simsimd/build.rs +51 -0
  88. package/simsimd/c/lib.c +110 -0
  89. package/simsimd/include/simsimd/binary.h +258 -0
  90. package/simsimd/include/simsimd/dot.h +1237 -0
  91. package/simsimd/include/simsimd/geospatial.h +37 -0
  92. package/simsimd/include/simsimd/probability.h +563 -0
  93. package/simsimd/include/simsimd/simsimd.h +1129 -0
  94. package/simsimd/include/simsimd/spatial.h +1019 -0
  95. package/simsimd/include/simsimd/types.h +309 -0
  96. package/simsimd/javascript/bench.js +127 -0
  97. package/simsimd/javascript/dist-package-cjs.json +3 -0
  98. package/simsimd/javascript/dist-package-esm.json +3 -0
  99. package/simsimd/javascript/fallback.ts +203 -0
  100. package/simsimd/javascript/lib.c +107 -0
  101. package/simsimd/javascript/node-gyp-build.d.ts +1 -0
  102. package/simsimd/javascript/simsimd.ts +135 -0
  103. package/simsimd/javascript/test.mjs +179 -0
  104. package/simsimd/javascript/tsconfig-base.json +37 -0
  105. package/simsimd/javascript/tsconfig-cjs.json +8 -0
  106. package/simsimd/javascript/tsconfig-esm.json +8 -0
  107. package/simsimd/package-lock.json +1709 -0
  108. package/simsimd/package.json +61 -0
  109. package/simsimd/rust/benches/cosine.rs +27 -0
  110. package/simsimd/rust/benches/native.rs +30 -0
  111. package/simsimd/rust/benches/sqeuclidean.rs +27 -0
  112. package/simsimd/rust/lib.rs +778 -0
package/README.md CHANGED
@@ -432,7 +432,7 @@ doi = {10.5281/zenodo.7949416},
432
432
  author = {Vardanian, Ash},
433
433
  title = {{USearch by Unum Cloud}},
434
434
  url = {https://github.com/unum-cloud/usearch},
435
- version = {2.10.2},
435
+ version = {2.10.5},
436
436
  year = {2023},
437
437
  month = oct,
438
438
  }
package/binding.gyp ADDED
@@ -0,0 +1,101 @@
1
+ {
2
+ "targets": [
3
+ {
4
+ "target_name": "usearch",
5
+ "sources": ["javascript/lib.cpp"],
6
+ "cflags": [
7
+ "-fexceptions",
8
+ "-Wno-unknown-pragmas",
9
+ "-Wno-maybe-uninitialized",
10
+ ],
11
+ "cflags_cc": [
12
+ "-fexceptions",
13
+ "-Wno-unknown-pragmas",
14
+ "-Wno-maybe-uninitialized",
15
+ "-std=c++17",
16
+ ],
17
+ "include_dirs": [
18
+ "<!@(node -p \"require('node-addon-api').include\")",
19
+ "include",
20
+ "fp16/include",
21
+ "simsimd/include",
22
+ ],
23
+ "dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
24
+ "xcode_settings": {
25
+ "GCC_ENABLE_CPP_EXCEPTIONS": "YES",
26
+ "CLANG_CXX_LIBRARY": "libc++",
27
+ "MACOSX_DEPLOYMENT_TARGET": "11.0",
28
+ "OTHER_CFLAGS": [
29
+ "-arch arm64",
30
+ "-arch x86_64"
31
+ ],
32
+ "OTHER_LDFLAGS": [
33
+ "-arch arm64",
34
+ "-arch x86_64"
35
+ ]
36
+ },
37
+ "msvs_settings": {
38
+ "VCCLCompilerTool": {
39
+ "ExceptionHandling": 1,
40
+ "AdditionalOptions": ["-std:c++17"],
41
+ }
42
+ },
43
+ "conditions": [
44
+ [
45
+ 'OS=="linux"',
46
+ {
47
+ "cflags_cc": [
48
+ '<!(if [ "$USEARCH_USE_OPENMP" = "1" ]; then echo \'-fopenmp\'; fi)',
49
+ ],
50
+ "ldflags": [
51
+ '<!(if [ "$USEARCH_USE_OPENMP" = "1" ]; then echo \'-lgomp\'; fi)'
52
+ ],
53
+ "defines": [
54
+ "USEARCH_USE_OPENMP=<!(echo ${USEARCH_USE_OPENMP:-0})",
55
+ "USEARCH_USE_SIMSIMD=<!(echo ${USEARCH_USE_SIMSIMD:-1})",
56
+ "USEARCH_USE_FP16LIB=<!(echo ${USEARCH_USE_FP16LIB:-1})",
57
+ "SIMSIMD_TARGET_NEON=<!(echo ${SIMSIMD_TARGET_NEON:-1})",
58
+ "SIMSIMD_TARGET_SVE=<!(echo ${SIMSIMD_TARGET_SVE:-1})",
59
+ "SIMSIMD_TARGET_HASWELL=<!(echo ${SIMSIMD_TARGET_HASWELL:-1})",
60
+ "SIMSIMD_TARGET_SKYLAKE=<!(echo ${SIMSIMD_TARGET_SKYLAKE:-1})",
61
+ "SIMSIMD_TARGET_ICE=<!(echo ${SIMSIMD_TARGET_ICE:-1})",
62
+ "SIMSIMD_TARGET_SAPPHIRE=<!(echo ${SIMSIMD_TARGET_SAPPHIRE:-1})",
63
+ ],
64
+ },
65
+ ],
66
+ [
67
+ 'OS=="mac"',
68
+ {
69
+ "defines": [
70
+ "USEARCH_USE_OPENMP=<!(echo ${USEARCH_USE_OPENMP:-0})",
71
+ "USEARCH_USE_SIMSIMD=<!(echo ${USEARCH_USE_SIMSIMD:-0})",
72
+ "USEARCH_USE_FP16LIB=<!(echo ${USEARCH_USE_FP16LIB:-1})",
73
+ "SIMSIMD_TARGET_NEON=<!(echo ${SIMSIMD_TARGET_NEON:-1})",
74
+ "SIMSIMD_TARGET_SVE=<!(echo ${SIMSIMD_TARGET_SVE:-0})",
75
+ "SIMSIMD_TARGET_HASWELL=<!(echo ${SIMSIMD_TARGET_HASWELL:-1})",
76
+ "SIMSIMD_TARGET_SKYLAKE=<!(echo ${SIMSIMD_TARGET_SKYLAKE:-0})",
77
+ "SIMSIMD_TARGET_ICE=<!(echo ${SIMSIMD_TARGET_ICE:-0})",
78
+ "SIMSIMD_TARGET_SAPPHIRE=<!(echo ${SIMSIMD_TARGET_SAPPHIRE:-0})",
79
+ ],
80
+ },
81
+ ],
82
+ [
83
+ 'OS=="win"',
84
+ {
85
+ "defines": [
86
+ "USEARCH_USE_OPENMP=0",
87
+ "USEARCH_USE_SIMSIMD=0",
88
+ "USEARCH_USE_FP16LIB=1",
89
+ "SIMSIMD_TARGET_SKYLAKE=0",
90
+ "SIMSIMD_TARGET_ICE=0",
91
+ "SIMSIMD_TARGET_SAPPHIRE=0",
92
+ "SIMSIMD_TARGET_SVE=0",
93
+ "SIMSIMD_TARGET_HASWELL=0",
94
+ "SIMSIMD_TARGET_NEON=0",
95
+ ],
96
+ },
97
+ ],
98
+ ],
99
+ }
100
+ ]
101
+ }
@@ -0,0 +1,27 @@
1
+ if (USEARCH_BUILD_TEST_C)
2
+ add_executable(test_c test.c lib.cpp)
3
+ setup_target(test_c)
4
+ include(CTest)
5
+ enable_testing()
6
+ add_test(NAME test_c COMMAND test_c)
7
+ endif ()
8
+
9
+ # This article discusses a better way to allow building either static or shared libraries:
10
+ # https://alexreinking.com/blog/building-a-dual-shared-and-static-library-with-cmake.html
11
+ if (USEARCH_BUILD_LIB_C)
12
+ add_library(usearch_c SHARED lib.cpp)
13
+ add_library(usearch_static_c STATIC lib.cpp)
14
+
15
+ # Set the compile options for the static library
16
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
17
+ target_compile_options(usearch_static_c PRIVATE -static-libstdc++)
18
+ target_link_options(usearch_static_c PRIVATE -static-libstdc++)
19
+ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
20
+ target_compile_options(usearch_static_c PRIVATE -static)
21
+ target_link_options(usearch_static_c PRIVATE -static)
22
+ endif ()
23
+
24
+ setup_target(usearch_c)
25
+ setup_target(usearch_static_c)
26
+
27
+ endif ()
package/c/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # USearch for C
2
+
3
+ ## Installation
4
+
5
+ The simplest form to integrate is to copy the contents of `usearch/c/` into your project.
6
+ To build the library `libusearch_static_c` and `libusearch_c`, pass enable the `USEARCH_BUILD_LIB_C` CMake option:
7
+
8
+ ```bash
9
+ cmake -DCMAKE_BUILD_TYPE=Release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_BUILD_TEST_CPP=0 -DUSEARCH_BUILD_BENCH_CPP=0 -B ./build_release
10
+ cmake --build ./build_release --config Release
11
+ ./build_release/test_c
12
+ ```
13
+
14
+ ## Quickstart
15
+
16
+ ```c
17
+ usearch_error_t error = NULL;
18
+ usearch_init_options_t opts = create_options(dimensions);
19
+ usearch_index_t index = usearch_init(&opts, &error);
20
+ usearch_reserve(index, vectors_count, &error);
21
+
22
+ float vector[dimensions] = {...};
23
+ usearch_add(index, 42, &vector[0], usearch_scalar_f32_k, &error);
24
+
25
+ ASSERT(!error, error);
26
+ ASSERT(usearch_size(index, &error) == vectors_count, error);
27
+ ASSERT(usearch_capacity(index, &error) == vectors_count, error);
28
+
29
+ usearch_key_t found_keys[10];
30
+ float found_distances[10];
31
+ size_t found_count = usearch_search(index, &vector[0], usearch_scalar_f32_k, 10, &found_keys[0], &found_distances[0], &error);
32
+
33
+ usearch_free(index, &error);
34
+ ```
package/c/lib.cpp ADDED
@@ -0,0 +1,362 @@
1
+ #include <cassert>
2
+
3
+ #include <usearch/index_dense.hpp>
4
+
5
+ extern "C" {
6
+ #include "usearch.h"
7
+ }
8
+
9
+ using namespace unum::usearch;
10
+ using namespace unum;
11
+
12
+ using add_result_t = typename index_dense_t::add_result_t;
13
+ using search_result_t = typename index_dense_t::search_result_t;
14
+ using labeling_result_t = typename index_dense_t::labeling_result_t;
15
+
16
+ static_assert(std::is_same<usearch_key_t, index_dense_t::vector_key_t>::value, "Type mismatch between C and C++");
17
+ static_assert(std::is_same<usearch_distance_t, index_dense_t::distance_t>::value, "Type mismatch between C and C++");
18
+
19
+ metric_kind_t metric_kind_to_cpp(usearch_metric_kind_t kind) {
20
+ switch (kind) {
21
+ case usearch_metric_ip_k: return metric_kind_t::ip_k;
22
+ case usearch_metric_l2sq_k: return metric_kind_t::l2sq_k;
23
+ case usearch_metric_cos_k: return metric_kind_t::cos_k;
24
+ case usearch_metric_haversine_k: return metric_kind_t::haversine_k;
25
+ case usearch_metric_divergence_k: return metric_kind_t::divergence_k;
26
+ case usearch_metric_pearson_k: return metric_kind_t::pearson_k;
27
+ case usearch_metric_jaccard_k: return metric_kind_t::jaccard_k;
28
+ case usearch_metric_hamming_k: return metric_kind_t::hamming_k;
29
+ case usearch_metric_tanimoto_k: return metric_kind_t::tanimoto_k;
30
+ case usearch_metric_sorensen_k: return metric_kind_t::sorensen_k;
31
+ default: return metric_kind_t::unknown_k;
32
+ }
33
+ }
34
+
35
+ usearch_metric_kind_t metric_kind_to_c(metric_kind_t kind) {
36
+ switch (kind) {
37
+ case metric_kind_t::ip_k: return usearch_metric_ip_k;
38
+ case metric_kind_t::l2sq_k: return usearch_metric_l2sq_k;
39
+ case metric_kind_t::cos_k: return usearch_metric_cos_k;
40
+ case metric_kind_t::haversine_k: return usearch_metric_haversine_k;
41
+ case metric_kind_t::divergence_k: return usearch_metric_divergence_k;
42
+ case metric_kind_t::pearson_k: return usearch_metric_pearson_k;
43
+ case metric_kind_t::jaccard_k: return usearch_metric_jaccard_k;
44
+ case metric_kind_t::hamming_k: return usearch_metric_hamming_k;
45
+ case metric_kind_t::tanimoto_k: return usearch_metric_tanimoto_k;
46
+ case metric_kind_t::sorensen_k: return usearch_metric_sorensen_k;
47
+ default: return usearch_metric_unknown_k;
48
+ }
49
+ }
50
+ scalar_kind_t scalar_kind_to_cpp(usearch_scalar_kind_t kind) {
51
+ switch (kind) {
52
+ case usearch_scalar_f32_k: return scalar_kind_t::f32_k;
53
+ case usearch_scalar_f64_k: return scalar_kind_t::f64_k;
54
+ case usearch_scalar_f16_k: return scalar_kind_t::f16_k;
55
+ case usearch_scalar_i8_k: return scalar_kind_t::i8_k;
56
+ case usearch_scalar_b1_k: return scalar_kind_t::b1x8_k;
57
+ default: return scalar_kind_t::unknown_k;
58
+ }
59
+ }
60
+
61
+ usearch_scalar_kind_t scalar_kind_to_c(scalar_kind_t kind) {
62
+ switch (kind) {
63
+ case scalar_kind_t::f32_k: return usearch_scalar_f32_k;
64
+ case scalar_kind_t::f64_k: return usearch_scalar_f64_k;
65
+ case scalar_kind_t::f16_k: return usearch_scalar_f16_k;
66
+ case scalar_kind_t::i8_k: return usearch_scalar_i8_k;
67
+ case scalar_kind_t::b1x8_k: return usearch_scalar_b1_k;
68
+ default: return usearch_scalar_unknown_k;
69
+ }
70
+ }
71
+
72
+ add_result_t add_(index_dense_t* index, usearch_key_t key, void const* vector, scalar_kind_t kind) {
73
+ switch (kind) {
74
+ case scalar_kind_t::f32_k: return index->add(key, (f32_t const*)vector);
75
+ case scalar_kind_t::f64_k: return index->add(key, (f64_t const*)vector);
76
+ case scalar_kind_t::f16_k: return index->add(key, (f16_t const*)vector);
77
+ case scalar_kind_t::i8_k: return index->add(key, (i8_t const*)vector);
78
+ case scalar_kind_t::b1x8_k: return index->add(key, (b1x8_t const*)vector);
79
+ default: return add_result_t{}.failed("Unknown scalar kind!");
80
+ }
81
+ }
82
+
83
+ std::size_t get_(index_dense_t* index, usearch_key_t key, size_t count, void* vector, scalar_kind_t kind) {
84
+ switch (kind) {
85
+ case scalar_kind_t::f32_k: return index->get(key, (f32_t*)vector, count);
86
+ case scalar_kind_t::f64_k: return index->get(key, (f64_t*)vector, count);
87
+ case scalar_kind_t::f16_k: return index->get(key, (f16_t*)vector, count);
88
+ case scalar_kind_t::i8_k: return index->get(key, (i8_t*)vector, count);
89
+ case scalar_kind_t::b1x8_k: return index->get(key, (b1x8_t*)vector, count);
90
+ default: return search_result_t().failed("Unknown scalar kind!");
91
+ }
92
+ }
93
+
94
+ search_result_t search_(index_dense_t* index, void const* vector, scalar_kind_t kind, size_t n) {
95
+ switch (kind) {
96
+ case scalar_kind_t::f32_k: return index->search((f32_t const*)vector, n);
97
+ case scalar_kind_t::f64_k: return index->search((f64_t const*)vector, n);
98
+ case scalar_kind_t::f16_k: return index->search((f16_t const*)vector, n);
99
+ case scalar_kind_t::i8_k: return index->search((i8_t const*)vector, n);
100
+ case scalar_kind_t::b1x8_k: return index->search((b1x8_t const*)vector, n);
101
+ default: return search_result_t().failed("Unknown scalar kind!");
102
+ }
103
+ }
104
+
105
+ extern "C" {
106
+
107
+ USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, usearch_error_t* error) {
108
+
109
+ assert(options && error && "Missing arguments");
110
+
111
+ index_dense_config_t config(options->connectivity, options->expansion_add, options->expansion_search);
112
+ config.multi = options->multi;
113
+ metric_kind_t metric_kind = metric_kind_to_cpp(options->metric_kind);
114
+ scalar_kind_t scalar_kind = scalar_kind_to_cpp(options->quantization);
115
+
116
+ metric_punned_t metric = //
117
+ !options->metric ? metric_punned_t(options->dimensions, metric_kind, scalar_kind)
118
+ : metric_punned_t(options->dimensions, //
119
+ reinterpret_cast<std::uintptr_t>(options->metric), //
120
+ metric_punned_signature_t::array_array_k, //
121
+ metric_kind, scalar_kind);
122
+ if (metric.missing()) {
123
+ *error = "Unknown metric kind!";
124
+ return NULL;
125
+ }
126
+
127
+ index_dense_t index = index_dense_t::make(metric, config);
128
+ index_dense_t* result_ptr = new index_dense_t(std::move(index));
129
+ if (!result_ptr || !*result_ptr)
130
+ *error = "Out of memory!";
131
+ return result_ptr;
132
+ }
133
+
134
+ USEARCH_EXPORT void usearch_free(usearch_index_t index, usearch_error_t*) {
135
+ delete reinterpret_cast<index_dense_t*>(index);
136
+ }
137
+
138
+ USEARCH_EXPORT size_t usearch_serialized_length(usearch_index_t index, usearch_error_t*) {
139
+ assert(index && "Missing arguments");
140
+ return reinterpret_cast<index_dense_t*>(index)->serialized_length();
141
+ }
142
+
143
+ USEARCH_EXPORT void usearch_save(usearch_index_t index, char const* path, usearch_error_t* error) {
144
+
145
+ assert(index && path && error && "Missing arguments");
146
+ serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->save(path);
147
+ if (!result)
148
+ *error = result.error.release();
149
+ }
150
+
151
+ USEARCH_EXPORT void usearch_load(usearch_index_t index, char const* path, usearch_error_t* error) {
152
+
153
+ assert(index && path && error && "Missing arguments");
154
+ serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->load(path);
155
+ if (!result)
156
+ *error = result.error.release();
157
+ }
158
+
159
+ USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearch_error_t* error) {
160
+
161
+ assert(index && path && error && "Missing arguments");
162
+ serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->view(path);
163
+ if (!result)
164
+ *error = result.error.release();
165
+ }
166
+
167
+ USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* options, usearch_error_t* error) {
168
+
169
+ assert(path && options && error && "Missing arguments");
170
+ index_dense_metadata_result_t result = index_dense_metadata_from_path(path);
171
+ if (!result)
172
+ *error = result.error.release();
173
+
174
+ options->metric_kind = metric_kind_to_c(result.head.kind_metric);
175
+ options->quantization = scalar_kind_to_c(result.head.kind_scalar);
176
+ options->dimensions = result.head.dimensions;
177
+ options->multi = result.head.multi;
178
+
179
+ options->connectivity = 0;
180
+ options->expansion_add = 0;
181
+ options->expansion_search = 0;
182
+ options->metric = NULL;
183
+ }
184
+
185
+ USEARCH_EXPORT void usearch_save_buffer(usearch_index_t index, void* buffer, size_t length, usearch_error_t* error) {
186
+
187
+ assert(index && buffer && length && error && "Missing arguments");
188
+ memory_mapped_file_t memory_map((byte_t*)buffer, length);
189
+ serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->save(std::move(memory_map));
190
+ if (!result)
191
+ *error = result.error.release();
192
+ }
193
+
194
+ USEARCH_EXPORT void usearch_load_buffer(usearch_index_t index, void const* buffer, size_t length,
195
+ usearch_error_t* error) {
196
+
197
+ assert(index && buffer && length && error && "Missing arguments");
198
+ memory_mapped_file_t memory_map((byte_t*)buffer, length);
199
+ serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->load(std::move(memory_map));
200
+ if (!result)
201
+ *error = result.error.release();
202
+ }
203
+
204
+ USEARCH_EXPORT void usearch_view_buffer(usearch_index_t index, void const* buffer, size_t length,
205
+ usearch_error_t* error) {
206
+
207
+ assert(index && buffer && length && error && "Missing arguments");
208
+ memory_mapped_file_t memory_map((byte_t*)buffer, length);
209
+ serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->view(std::move(memory_map));
210
+ if (!result)
211
+ *error = result.error.release();
212
+ }
213
+
214
+ USEARCH_EXPORT void usearch_metadata_buffer(void const* buffer, size_t length, usearch_init_options_t* options,
215
+ usearch_error_t* error) {
216
+
217
+ assert(buffer && length && options && error && "Missing arguments");
218
+ index_dense_metadata_result_t result =
219
+ index_dense_metadata_from_buffer(memory_mapped_file_t((byte_t*)(buffer), length));
220
+ if (!result)
221
+ *error = result.error.release();
222
+
223
+ options->metric_kind = metric_kind_to_c(result.head.kind_metric);
224
+ options->quantization = scalar_kind_to_c(result.head.kind_scalar);
225
+ options->dimensions = result.head.dimensions;
226
+ options->multi = result.head.multi;
227
+
228
+ options->connectivity = 0;
229
+ options->expansion_add = 0;
230
+ options->expansion_search = 0;
231
+ options->metric = NULL;
232
+ }
233
+
234
+ USEARCH_EXPORT size_t usearch_size(usearch_index_t index, usearch_error_t*) { //
235
+ return reinterpret_cast<index_dense_t*>(index)->size();
236
+ }
237
+
238
+ USEARCH_EXPORT size_t usearch_capacity(usearch_index_t index, usearch_error_t*) {
239
+ return reinterpret_cast<index_dense_t*>(index)->capacity();
240
+ }
241
+
242
+ USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t index, usearch_error_t*) {
243
+ return reinterpret_cast<index_dense_t*>(index)->dimensions();
244
+ }
245
+
246
+ USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t index, usearch_error_t*) {
247
+ return reinterpret_cast<index_dense_t*>(index)->connectivity();
248
+ }
249
+
250
+ USEARCH_EXPORT void usearch_reserve(usearch_index_t index, size_t capacity, usearch_error_t* error) {
251
+ assert(index && error && "Missing arguments");
252
+ if (!reinterpret_cast<index_dense_t*>(index)->reserve(capacity))
253
+ *error = "Out of memory!";
254
+ }
255
+
256
+ USEARCH_EXPORT void usearch_add( //
257
+ usearch_index_t index, usearch_key_t key, void const* vector, usearch_scalar_kind_t kind, //
258
+ usearch_error_t* error) {
259
+
260
+ assert(index && vector && error && "Missing arguments");
261
+ add_result_t result = add_(reinterpret_cast<index_dense_t*>(index), key, vector, scalar_kind_to_cpp(kind));
262
+ if (!result)
263
+ *error = result.error.release();
264
+ }
265
+
266
+ USEARCH_EXPORT bool usearch_contains(usearch_index_t index, usearch_key_t key, usearch_error_t*) {
267
+ assert(index && "Missing arguments");
268
+ return reinterpret_cast<index_dense_t*>(index)->contains(key);
269
+ }
270
+
271
+ USEARCH_EXPORT size_t usearch_count(usearch_index_t index, usearch_key_t key, usearch_error_t*) {
272
+ assert(index && "Missing arguments");
273
+ return reinterpret_cast<index_dense_t*>(index)->count(key);
274
+ }
275
+
276
+ USEARCH_EXPORT size_t usearch_search( //
277
+ usearch_index_t index, void const* vector, usearch_scalar_kind_t kind, size_t results_limit, //
278
+ usearch_key_t* found_keys, usearch_distance_t* found_distances, usearch_error_t* error) {
279
+
280
+ assert(index && vector && error && "Missing arguments");
281
+ search_result_t result =
282
+ search_(reinterpret_cast<index_dense_t*>(index), vector, scalar_kind_to_cpp(kind), results_limit);
283
+ if (!result) {
284
+ *error = result.error.release();
285
+ return 0;
286
+ }
287
+
288
+ return result.dump_to(found_keys, found_distances);
289
+ }
290
+
291
+ USEARCH_EXPORT size_t usearch_get( //
292
+ usearch_index_t index, usearch_key_t key, size_t count, //
293
+ void* vectors, usearch_scalar_kind_t kind, usearch_error_t*) {
294
+
295
+ assert(index && vectors);
296
+ return get_(reinterpret_cast<index_dense_t*>(index), key, count, vectors, scalar_kind_to_cpp(kind));
297
+ }
298
+
299
+ USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, usearch_error_t* error) {
300
+
301
+ assert(index && error && "Missing arguments");
302
+ labeling_result_t result = reinterpret_cast<index_dense_t*>(index)->remove(key);
303
+ if (!result)
304
+ *error = result.error.release();
305
+ return result.completed;
306
+ }
307
+
308
+ USEARCH_EXPORT size_t usearch_rename( //
309
+ usearch_index_t index, usearch_key_t from, usearch_key_t to, usearch_error_t* error) {
310
+
311
+ assert(index && error && "Missing arguments");
312
+ labeling_result_t result = reinterpret_cast<index_dense_t*>(index)->rename(from, to);
313
+ if (!result)
314
+ *error = result.error.release();
315
+ return result.completed;
316
+ }
317
+
318
+ USEARCH_EXPORT usearch_distance_t usearch_distance( //
319
+ void const* vector_first, void const* vector_second, //
320
+ usearch_scalar_kind_t scalar_kind, size_t dimensions, //
321
+ usearch_metric_kind_t metric_kind, usearch_error_t* error) {
322
+
323
+ (void)error;
324
+ metric_punned_t metric(dimensions, metric_kind_to_cpp(metric_kind), scalar_kind_to_cpp(scalar_kind));
325
+ return metric((byte_t const*)vector_first, (byte_t const*)vector_second);
326
+ }
327
+
328
+ USEARCH_EXPORT void usearch_exact_search( //
329
+ void const* dataset, size_t dataset_count, size_t dataset_stride, //
330
+ void const* queries, size_t queries_count, size_t queries_stride, //
331
+ usearch_scalar_kind_t scalar_kind, size_t dimensions, //
332
+ usearch_metric_kind_t metric_kind, size_t count, size_t threads, //
333
+ usearch_key_t* keys, size_t keys_stride, //
334
+ usearch_distance_t* distances, size_t distances_stride, //
335
+ usearch_error_t* error) {
336
+
337
+ assert(dataset && queries && keys && distances && error && "Missing arguments");
338
+
339
+ metric_punned_t metric(dimensions, metric_kind_to_cpp(metric_kind), scalar_kind_to_cpp(scalar_kind));
340
+ executor_default_t executor(threads);
341
+ static exact_search_t search;
342
+ exact_search_results_t result = search( //
343
+ (byte_t const*)dataset, dataset_count, dataset_stride, //
344
+ (byte_t const*)queries, queries_count, queries_stride, //
345
+ count, metric);
346
+
347
+ if (!result) {
348
+ *error = "Out of memory, allocating a temporary buffer for batch results";
349
+ return;
350
+ }
351
+
352
+ // Export results into the output buffer
353
+ for (std::size_t query_idx = 0; query_idx != queries_count; ++query_idx) {
354
+ auto query_result = result.at(query_idx);
355
+ auto query_keys = (usearch_key_t*)((byte_t*)keys + query_idx * keys_stride);
356
+ auto query_distances = (usearch_distance_t*)((byte_t*)distances + query_idx * distances_stride);
357
+ for (std::size_t i = 0; i != count; ++i)
358
+ query_keys[i] = static_cast<usearch_key_t>(query_result[i].offset),
359
+ query_distances[i] = static_cast<usearch_distance_t>(query_result[i].distance);
360
+ }
361
+ }
362
+ }