usearch 2.6.1 → 2.7.1

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 (54) hide show
  1. package/. npmignore +14 -0
  2. package/.cmake-format.py +19 -0
  3. package/.github/workflows/Dockerfile.libs +3 -3
  4. package/.github/workflows/prerelease.yml +85 -64
  5. package/.github/workflows/release.yml +18 -16
  6. package/.gitignore +1 -1
  7. package/.vscode/launch.json +47 -14
  8. package/.vscode/settings.json +7 -0
  9. package/.vscode/tasks.json +44 -8
  10. package/CITATION.cff +1 -1
  11. package/CMakeLists.txt +218 -67
  12. package/Cargo.toml +1 -1
  13. package/README.md +1 -1
  14. package/binding.gyp +3 -2
  15. package/build.gradle +19 -10
  16. package/c/CMakeLists.txt +21 -48
  17. package/c/README.md +5 -5
  18. package/c/lib.cpp +52 -7
  19. package/c/test.c +137 -94
  20. package/c/usearch.h +42 -0
  21. package/cmake/clipp.cmake +0 -1
  22. package/cmake/jemalloc.cmake +21 -37
  23. package/conanfile.py +1 -1
  24. package/cpp/CMakeLists.txt +14 -123
  25. package/cpp/bench.cpp +0 -12
  26. package/cpp/test.cpp +29 -1
  27. package/csharp/nuget/nuget-package.props +1 -1
  28. package/docs/compilation.md +23 -16
  29. package/docs/conf.py +1 -1
  30. package/golang/README.md +52 -51
  31. package/golang/lib.go +1 -1
  32. package/golang/lib_test.go +4 -1
  33. package/include/usearch/index.hpp +2 -2
  34. package/include/usearch/index_plugins.hpp +345 -160
  35. package/javascript/lib.cpp +204 -250
  36. package/javascript/usearch.js +440 -2
  37. package/javascript/usearch.test.js +37 -0
  38. package/package.json +10 -5
  39. package/python/lib.cpp +96 -225
  40. package/python/scripts/bench_exact.py +2 -2
  41. package/python/scripts/test_jit.py +2 -13
  42. package/python/scripts/test_sparse.py +1 -1
  43. package/python/scripts/test_tooling.py +26 -5
  44. package/rust/lib.cpp +12 -4
  45. package/rust/lib.hpp +7 -0
  46. package/rust/lib.rs +170 -10
  47. package/setup.py +14 -4
  48. package/wasm/CMakeLists.txt +4 -12
  49. package/wasm/lib.cpp +1 -1
  50. package/wasmer.toml +1 -1
  51. package/javascript/docs.js +0 -111
  52. package/javascript/test.js +0 -32
  53. package/javascript/usearch.d.ts +0 -110
  54. package/tsconfig.json +0 -8
package/CMakeLists.txt CHANGED
@@ -1,21 +1,31 @@
1
1
  # This CMake file is heavily inspired by following `usearch` CMake:
2
2
  # https://github.com/nlohmann/json/blob/develop/CMakeLists.txt
3
3
  cmake_minimum_required(VERSION 3.1)
4
- project(usearch VERSION 0.6.0 LANGUAGES C CXX)
4
+ project(
5
+ usearch
6
+ VERSION 0.6.0
7
+ LANGUAGES C CXX
8
+ )
5
9
 
6
10
  # Determine if USearch is built as a subproject (using `add_subdirectory`) or if it is the main project
7
11
  set(USEARCH_IS_MAIN_PROJECT OFF)
8
12
  if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
9
13
  set(USEARCH_IS_MAIN_PROJECT ON)
10
- endif()
14
+ endif ()
11
15
 
12
16
  # Options
13
17
  option(USEARCH_INSTALL "Install CMake targets" OFF)
14
- option(USEARCH_BUILD_TEST "Compile a native unit test in C++" ${USEARCH_IS_MAIN_PROJECT})
15
- option(USEARCH_BUILD_BENCHMARK "Compile a native benchmark in C++" ${USEARCH_IS_MAIN_PROJECT})
18
+
19
+ option(USEARCH_USE_OPENMP "Use OpenMP for a thread pool" OFF)
20
+ option(USEARCH_USE_SIMSIMD "Use SimSIMD hardware-accelerated metrics" OFF)
21
+ option(USEARCH_USE_JEMALLOC "Use JeMalloc for faster memory allocations" OFF)
22
+ option(USEARCH_USE_NATIVE_F16 "Use native half-precision types" OFF)
23
+
24
+ option(USEARCH_BUILD_TEST_CPP "Compile a native unit test in C++" ${USEARCH_IS_MAIN_PROJECT})
25
+ option(USEARCH_BUILD_BENCH_CPP "Compile a native benchmark in C++" ${USEARCH_IS_MAIN_PROJECT})
26
+ option(USEARCH_BUILD_LIB_C "Compile a native library for the C 99 interface" OFF)
27
+ option(USEARCH_BUILD_TEST_C "Compile a test for the C 99 interface" OFF)
16
28
  option(USEARCH_BUILD_WOLFRAM "Compile Wolfram Language bindings" OFF)
17
- option(USEARCH_BUILD_CLIB "Compile a native library for the C 99 interface" OFF)
18
- option(USEARCH_BUILD_CTEST "Compile a test for the C 99 interface" OFF)
19
29
 
20
30
  # Includes
21
31
  set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
@@ -28,17 +38,19 @@ endif ()
28
38
 
29
39
  # Configuration
30
40
  include(GNUInstallDirs)
31
- set(USEARCH_TARGET_NAME ${PROJECT_NAME})
32
- set(USEARCH_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}" CACHE INTERNAL "")
33
- set(USEARCH_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}")
34
- set(USEARCH_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
35
- set(USEARCH_CMAKE_CONFIG_TEMPLATE "cmake/config.cmake.in")
36
- set(USEARCH_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}")
41
+ set(USEARCH_TARGET_NAME ${PROJECT_NAME})
42
+ set(USEARCH_CONFIG_INSTALL_DIR
43
+ "${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}"
44
+ CACHE INTERNAL ""
45
+ )
46
+ set(USEARCH_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}")
47
+ set(USEARCH_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
48
+ set(USEARCH_CMAKE_CONFIG_TEMPLATE "cmake/config.cmake.in")
49
+ set(USEARCH_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}")
37
50
  set(USEARCH_CMAKE_VERSION_CONFIG_FILE "${USEARCH_CMAKE_CONFIG_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
38
51
  set(USEARCH_CMAKE_PROJECT_CONFIG_FILE "${USEARCH_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Config.cmake")
39
52
  set(USEARCH_CMAKE_PROJECT_TARGETS_FILE "${USEARCH_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Targets.cmake")
40
- set(USEARCH_PKGCONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/pkgconfig")
41
-
53
+ set(USEARCH_PKGCONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/pkgconfig")
42
54
 
43
55
  # Define our header-only library
44
56
  add_library(${USEARCH_TARGET_NAME} INTERFACE)
@@ -46,66 +58,42 @@ add_library(${PROJECT_NAME}::${USEARCH_TARGET_NAME} ALIAS ${USEARCH_TARGET_NAME}
46
58
  set(USEARCH_INCLUDE_BUILD_DIR "${PROJECT_SOURCE_DIR}/include/")
47
59
  if (${CMAKE_VERSION} VERSION_LESS "3.8.0")
48
60
  target_compile_features(${USEARCH_TARGET_NAME} INTERFACE cxx_range_for)
49
- else()
61
+ else ()
50
62
  target_compile_features(${USEARCH_TARGET_NAME} INTERFACE cxx_std_11)
51
- endif()
63
+ endif ()
52
64
 
53
65
  # Core compilation settings affecting "index.hpp"
54
66
  target_compile_definitions(
55
- ${USEARCH_TARGET_NAME}
56
- INTERFACE
57
- $<$<NOT:$<BOOL:${JSON_GlobalUDLs}>>:USEARCH_USE_OPENMP=0>
67
+ ${USEARCH_TARGET_NAME} INTERFACE $<$<NOT:$<BOOL:${USEARCH_USE_OPENMP}>>:USEARCH_USE_OPENMP=0>
58
68
  )
59
69
 
60
70
  # Supplementary compilation settings affecting "index_plugins.hpp"
61
71
  target_compile_definitions(
62
- ${USEARCH_TARGET_NAME}
63
- INTERFACE
64
- $<$<NOT:$<BOOL:${JSON_GlobalUDLs}>>:USEARCH_USE_NATIVE_F16=0>
72
+ ${USEARCH_TARGET_NAME} INTERFACE $<$<NOT:$<BOOL:${USEARCH_USE_NATIVE_F16}>>:USEARCH_USE_NATIVE_F16=0>
65
73
  )
66
74
 
67
75
  target_compile_definitions(
68
- ${USEARCH_TARGET_NAME}
69
- INTERFACE
70
- $<$<NOT:$<BOOL:${JSON_GlobalUDLs}>>:USEARCH_USE_SIMSIMD=0>
76
+ ${USEARCH_TARGET_NAME} INTERFACE $<$<NOT:$<BOOL:${USEARCH_USE_SIMSIMD}>>:USEARCH_USE_SIMSIMD=0>
71
77
  )
72
78
 
73
79
  target_include_directories(
74
- ${USEARCH_TARGET_NAME}
75
- ${USEARCH_SYSTEM_INCLUDE} INTERFACE
76
- $<BUILD_INTERFACE:${USEARCH_INCLUDE_BUILD_DIR}>
77
- $<INSTALL_INTERFACE:include>
80
+ ${USEARCH_TARGET_NAME} ${USEARCH_SYSTEM_INCLUDE} INTERFACE $<BUILD_INTERFACE:${USEARCH_INCLUDE_BUILD_DIR}>
81
+ $<INSTALL_INTERFACE:include>
78
82
  )
79
83
 
80
84
  # Install a pkg-config file, so other tools can find this
81
- configure_file(
82
- "${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in"
83
- "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
84
- )
85
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc")
85
86
 
86
- # Install a custom package version config file instead of
87
- # write_basic_package_version_file to ensure that it's architecture-independent
88
- # https://github.com/nlohmann/json/issues/1697
87
+ # Install a custom package version config file instead of write_basic_package_version_file to ensure that it's
88
+ # architecture-independent https://github.com/nlohmann/json/issues/1697
89
89
  include(CMakePackageConfigHelpers)
90
- configure_file(
91
- "cmake/usearchConfigVersion.cmake.in"
92
- ${USEARCH_CMAKE_VERSION_CONFIG_FILE}
93
- @ONLY
94
- )
95
- configure_file(
96
- ${USEARCH_CMAKE_CONFIG_TEMPLATE}
97
- ${USEARCH_CMAKE_PROJECT_CONFIG_FILE}
98
- @ONLY
99
- )
90
+ configure_file("cmake/usearchConfigVersion.cmake.in" ${USEARCH_CMAKE_VERSION_CONFIG_FILE} @ONLY)
91
+ configure_file(${USEARCH_CMAKE_CONFIG_TEMPLATE} ${USEARCH_CMAKE_PROJECT_CONFIG_FILE} @ONLY)
100
92
 
101
- if(USEARCH_INSTALL)
102
- install(
103
- DIRECTORY ${USEARCH_INCLUDE_BUILD_DIR}
104
- DESTINATION ${USEARCH_INCLUDE_INSTALL_DIR}
105
- )
106
- install(
107
- FILES ${USEARCH_CMAKE_PROJECT_CONFIG_FILE} ${USEARCH_CMAKE_VERSION_CONFIG_FILE}
108
- DESTINATION ${USEARCH_CONFIG_INSTALL_DIR}
93
+ if (USEARCH_INSTALL)
94
+ install(DIRECTORY ${USEARCH_INCLUDE_BUILD_DIR} DESTINATION ${USEARCH_INCLUDE_INSTALL_DIR})
95
+ install(FILES ${USEARCH_CMAKE_PROJECT_CONFIG_FILE} ${USEARCH_CMAKE_VERSION_CONFIG_FILE}
96
+ DESTINATION ${USEARCH_CONFIG_INSTALL_DIR}
109
97
  )
110
98
  export(
111
99
  TARGETS ${USEARCH_TARGET_NAME}
@@ -115,31 +103,194 @@ if(USEARCH_INSTALL)
115
103
  install(
116
104
  TARGETS ${USEARCH_TARGET_NAME}
117
105
  EXPORT ${USEARCH_TARGETS_EXPORT_NAME}
118
- INCLUDES DESTINATION ${USEARCH_INCLUDE_INSTALL_DIR}
106
+ INCLUDES
107
+ DESTINATION ${USEARCH_INCLUDE_INSTALL_DIR}
119
108
  )
120
109
  install(
121
110
  EXPORT ${USEARCH_TARGETS_EXPORT_NAME}
122
111
  NAMESPACE ${PROJECT_NAME}::
123
112
  DESTINATION ${USEARCH_CONFIG_INSTALL_DIR}
124
113
  )
125
- install(
126
- FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
127
- DESTINATION ${USEARCH_PKGCONFIG_INSTALL_DIR}
114
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" DESTINATION ${USEARCH_PKGCONFIG_INSTALL_DIR})
115
+ endif ()
116
+
117
+ # Find required packages
118
+ if (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
119
+ set(CMAKE_THREAD_LIBS_INIT "-lpthread")
120
+ set(CMAKE_HAVE_THREADS_LIBRARY 1)
121
+ set(CMAKE_USE_WIN32_THREADS_INIT 0)
122
+ set(CMAKE_USE_PTHREADS_INIT 1)
123
+ set(THREADS_PREFER_PTHREAD_FLAG ON)
124
+ endif ()
125
+ find_package(Threads REQUIRED)
126
+
127
+ if (USEARCH_USE_OPENMP)
128
+ find_package(OpenMP REQUIRED)
129
+ endif ()
130
+
131
+ if (USEARCH_USE_JEMALLOC)
132
+ include(jemalloc)
133
+ endif ()
134
+
135
+ # Set default build type to Release
136
+ if (NOT CMAKE_BUILD_TYPE)
137
+ set(CMAKE_BUILD_TYPE RelWithDebInfo)
138
+ endif ()
139
+
140
+ # Include directories
141
+ set(USEARCH_HEADER_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/fp16/include"
142
+ "${CMAKE_CURRENT_SOURCE_DIR}/simsimd/include"
143
+ )
144
+
145
+ # Function to setup target
146
+ function (setup_target TARGET_NAME)
147
+ # Compiler-specific options List of all possible compiler IDs:
148
+ # https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html
149
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
150
+ target_compile_options(
151
+ ${TARGET_NAME}
152
+ PRIVATE $<$<CONFIG:RELEASE>:-O3>
153
+ $<$<CONFIG:RELWITHDEBINFO>:-O3
154
+ -g>
155
+ $<$<CONFIG:DEBUG>:-g
156
+ -fsanitize=address
157
+ -fsanitize=leak
158
+ -fsanitize=alignment
159
+ -fsanitize=undefined
160
+ >
161
+ -ffast-math
162
+ -fPIC
163
+ -Wall
164
+ -Wextra
165
+ -Wno-conversion
166
+ -Wno-unknown-pragmas
167
+ -march=native
168
+ -fmax-errors=1
169
+ -pedantic
170
+ -fdiagnostics-color=always
171
+ -ftime-report
172
+ )
173
+ target_link_options(
174
+ ${TARGET_NAME}
175
+ PRIVATE
176
+ $<$<CONFIG:DEBUG>:-g
177
+ -fsanitize=address
178
+ -fsanitize=leak
179
+ -fsanitize=alignment
180
+ -fsanitize=undefined
181
+ >
182
+ -fPIC
183
+ )
184
+
185
+ if (USEARCH_USE_OPENMP)
186
+ target_link_libraries(${TARGET_NAME} PRIVATE OpenMP::OpenMP_CXX)
187
+ endif ()
188
+
189
+ if (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
190
+ target_link_libraries(${TARGET_NAME} PRIVATE Threads::Threads)
191
+ endif ()
192
+
193
+ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
194
+ target_compile_options(
195
+ ${TARGET_NAME}
196
+ PRIVATE $<$<CONFIG:RELEASE>:-O3>
197
+ $<$<CONFIG:RELWITHDEBINFO>:-O3
198
+ -g>
199
+ $<$<CONFIG:DEBUG>:-g
200
+ -fsanitize=address
201
+ -fsanitize=alignment
202
+ -fsanitize=undefined
203
+ >
204
+ -ffast-math
205
+ -fPIC
206
+ -pedantic
207
+ -Wfatal-errors
208
+ # Don't complain if the for-loops were not vectorzied
209
+ -Wpass-failed=transform-warning
210
+ -fcolor-diagnostics
211
+ -ftime-trace
212
+ )
213
+ target_link_options(
214
+ ${TARGET_NAME}
215
+ PRIVATE
216
+ $<$<CONFIG:DEBUG>:-g
217
+ -fsanitize=address
218
+ -fsanitize=alignment
219
+ -fsanitize=undefined
220
+ >
221
+ -fPIC
222
+ )
223
+
224
+ # Check if the compiler is AppleClang, and if not, add the leak sanitizer
225
+ if (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
226
+ # It's likely AppleClang Adjust options as needed for AppleClang
227
+ else ()
228
+ # It's likely LLVM Clang
229
+ target_compile_options(${TARGET_NAME} PRIVATE $<$<CONFIG:DEBUG>:-fsanitize=leak>)
230
+ target_link_options(${TARGET_NAME} PRIVATE $<$<CONFIG:DEBUG>:-fsanitize=leak>)
231
+ endif ()
232
+
233
+ if (USEARCH_USE_OPENMP)
234
+ target_link_libraries(${TARGET_NAME} PRIVATE OpenMP::OpenMP_CXX)
235
+ endif ()
236
+
237
+ if (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
238
+ target_link_libraries(
239
+ ${TARGET_NAME} PRIVATE "-framework CoreFoundation" "-framework Security" Threads::Threads
240
+ )
241
+ else ()
242
+ target_link_libraries(${TARGET_NAME} PRIVATE Threads::Threads)
243
+ endif ()
244
+
245
+ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "NVIDIA" OR CMAKE_CXX_COMPILER_ID STREQUAL "NVHPC")
246
+ target_compile_options(${TARGET_NAME} PRIVATE $<$<CONFIG:RELEASE>:-O3>)
247
+ target_compile_definitions(${TARGET_NAME} PRIVATE --expt-relaxed-constexpr --extended-lambda)
248
+ set_property(SOURCE bench.cpp PROPERTY LANGUAGE CUDA)
249
+ set_target_properties(${TARGET_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
250
+ set_target_properties(${TARGET_NAME} PROPERTIES CUDA_ARCHITECTURES "86")
251
+
252
+ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
253
+ target_compile_options(${TARGET_NAME} PRIVATE -w -ferror-limit=1)
254
+
255
+ elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
256
+ target_compile_options(
257
+ ${TARGET_NAME} PRIVATE $<$<CONFIG:DEBUG>:/DEBUG> $<$<CONFIG:RELEASE>:/O2> $<$<CONFIG:RELWITHDEBINFO>:/O2
258
+ /DEBUG>
259
+ )
260
+ endif ()
261
+
262
+ target_include_directories(${TARGET_NAME} PRIVATE ${USEARCH_HEADER_INCLUDES})
263
+ set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
264
+ set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
265
+ set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
266
+ set_target_properties(${TARGET_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
267
+ set_target_properties(${TARGET_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
268
+ set_target_properties(${TARGET_NAME} PROPERTIES CXX_STANDARD 17)
269
+
270
+ # Core compilation settings affecting "index.hpp"
271
+ target_compile_definitions(${TARGET_NAME} PRIVATE $<$<NOT:$<BOOL:${USEARCH_USE_OPENMP}>>:USEARCH_USE_OPENMP=0>)
272
+
273
+ # Supplementary compilation settings affecting "index_plugins.hpp"
274
+ target_compile_definitions(
275
+ ${TARGET_NAME} PRIVATE $<$<NOT:$<BOOL:${USEARCH_USE_NATIVE_F16}>>:USEARCH_USE_NATIVE_F16=0>
128
276
  )
129
- endif()
130
277
 
131
- if(${USEARCH_BUILD_TEST} OR ${USEARCH_BUILD_BENCHMARK})
278
+ target_compile_definitions(${TARGET_NAME} PRIVATE $<$<NOT:$<BOOL:${USEARCH_USE_SIMSIMD}>>:USEARCH_USE_SIMSIMD=0>)
279
+
280
+ endfunction ()
281
+
282
+ if (${USEARCH_BUILD_TEST_CPP} OR ${USEARCH_BUILD_BENCH_CPP})
132
283
  add_subdirectory(cpp)
133
- endif()
284
+ endif ()
134
285
 
135
- if(${USEARCH_BUILD_WOLFRAM})
286
+ if (${USEARCH_BUILD_WOLFRAM})
136
287
  add_subdirectory(wolfram)
137
- endif()
288
+ endif ()
138
289
 
139
- if(${USEARCH_BUILD_WASM})
290
+ if (${USEARCH_BUILD_WASM})
140
291
  add_subdirectory(wasm)
141
- endif()
292
+ endif ()
142
293
 
143
- if (${USEARCH_BUILD_CLIB} OR ${USEARCH_BUILD_CTEST})
294
+ if (${USEARCH_BUILD_LIB_C} OR ${USEARCH_BUILD_TEST_C})
144
295
  add_subdirectory(c)
145
- endif()
296
+ endif ()
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "2.6.1"
3
+ version = "2.7.1"
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
@@ -392,7 +392,7 @@ doi = {10.5281/zenodo.7949416},
392
392
  author = {Vardanian, Ash},
393
393
  title = {{USearch by Unum Cloud}},
394
394
  url = {https://github.com/unum-cloud/usearch},
395
- version = {2.6.1},
395
+ version = {2.7.1},
396
396
  year = {2022},
397
397
  month = jun,
398
398
  }
package/binding.gyp CHANGED
@@ -10,6 +10,7 @@
10
10
  "simsimd/include",
11
11
  ],
12
12
  "dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
13
+ "defines": ["USEARCH_USE_SIMSIMD=1"],
13
14
  "cflags": [
14
15
  "-fexceptions",
15
16
  "-Wno-unknown-pragmas",
@@ -19,7 +20,7 @@
19
20
  "-fexceptions",
20
21
  "-Wno-unknown-pragmas",
21
22
  "-Wno-maybe-uninitialized",
22
- "-std=c++11",
23
+ "-std=c++17",
23
24
  ],
24
25
  "xcode_settings": {
25
26
  "GCC_ENABLE_CPP_EXCEPTIONS": "YES",
@@ -29,7 +30,7 @@
29
30
  "msvs_settings": {
30
31
  "VCCLCompilerTool": {
31
32
  "ExceptionHandling": 1,
32
- "AdditionalOptions": ["-std:c++11"],
33
+ "AdditionalOptions": ["-std:c++17"],
33
34
  }
34
35
  },
35
36
  }
package/build.gradle CHANGED
@@ -96,27 +96,36 @@ publishing {
96
96
  name = "USearch"
97
97
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
98
98
  url = "https://github.com/unum-cloud/usearch"
99
+
99
100
  licenses {
100
101
  license {
101
102
  name = 'The Apache License, Version 2.0'
102
103
  url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
103
104
  }
104
105
  }
106
+
107
+ scm {
108
+ connection = 'scm:git:git://github.com/unum-cloud/usearch.git'
109
+ developerConnection = 'scm:git:ssh://github.com/unum-cloud/usearch.git'
110
+ url = 'https://github.com/unum-cloud/usearch'
111
+ }
112
+
105
113
  }
106
114
  }
107
115
  }
108
116
 
117
+
109
118
  // Publishing to GitHub is much easier ;)
110
- // repositories {
111
- // maven {
112
- // name = "OSSRH"
113
- // url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
114
- // credentials {
115
- // username = System.getenv("MAVEN_USERNAME")
116
- // password = System.getenv("MAVEN_PASSWORD")
117
- // }
118
- // }
119
- // }
119
+ repositories {
120
+ maven {
121
+ name = "OSSRH"
122
+ url = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
123
+ credentials {
124
+ username = System.getenv("MAVEN_USERNAME")
125
+ password = System.getenv("MAVEN_PASSWORD")
126
+ }
127
+ }
128
+ }
120
129
 
121
130
  repositories {
122
131
  maven {
package/c/CMakeLists.txt CHANGED
@@ -1,52 +1,25 @@
1
-
2
-
3
- set(USEARCH_PUNNED_INCLUDE_DIRS
4
- "${CMAKE_CURRENT_SOURCE_DIR}/../include"
5
- "${CMAKE_CURRENT_SOURCE_DIR}/../fp16/include"
6
- "${CMAKE_CURRENT_SOURCE_DIR}/../simsimd/include"
7
- "${CMAKE_CURRENT_SOURCE_DIR}/"
8
- )
9
-
10
- # This article discusses a better way to allow building either static or shared libraries
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:
11
10
  # https://alexreinking.com/blog/building-a-dual-shared-and-static-library-with-cmake.html
12
- if (${USEARCH_BUILD_STATIC})
13
- if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
14
- set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -static-libstdc++")
15
- elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
16
- set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -static")
17
- endif()
18
-
19
- add_library(usearch_c STATIC "${CMAKE_CURRENT_SOURCE_DIR}/lib.cpp")
20
- else()
21
- add_library(usearch_c SHARED "${CMAKE_CURRENT_SOURCE_DIR}/lib.cpp")
22
- endif()
23
-
24
- set_target_properties(usearch_c PROPERTIES POSITION_INDEPENDENT_CODE ON)
25
- set_target_properties(usearch_c PROPERTIES CXX_STANDARD 11)
26
- set_target_properties(usearch_c PROPERTIES C_STANDARD 99)
27
-
28
- target_include_directories(usearch_c PRIVATE ${USEARCH_PUNNED_INCLUDE_DIRS})
29
- set_target_properties(usearch_c PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
30
- set_target_properties(usearch_c PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
31
- set_target_properties(usearch_c PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
32
-
33
-
34
- target_include_directories(usearch_c PRIVATE ${USEARCH_PUNNED_INCLUDE_DIRS})
11
+ if (USEARCH_BUILD_LIB_C)
12
+ add_library(usearch_c SHARED lib.cpp)
13
+ add_library(usearch_static_c STATIC lib.cpp)
35
14
 
36
- if(${USEARCH_DEBUG_BUILD_ASAN})
37
- # For ASAN in debug builds
38
- target_link_libraries(usearch_c PRIVATE gcov)
39
- endif()
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
+ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
19
+ target_compile_options(usearch_static_c PRIVATE -static)
20
+ endif ()
40
21
 
41
- if(${USEARCH_USE_SIMSIMD})
42
- target_compile_definitions(usearch_c PRIVATE USEARCH_USE_SIMSIMD=1)
43
- endif()
44
- if (${USEARCH_LOOKUP_LABEL})
45
- target_compile_definitions(usearch_c PRIVATE USEARCH_LOOKUP_LABEL=1)
46
- endif()
22
+ setup_target(usearch_c)
23
+ setup_target(usearch_static_c)
47
24
 
48
- if(${USEARCH_BUILD_CTEST})
49
- add_executable(test_c "${CMAKE_CURRENT_SOURCE_DIR}/test.c")
50
- target_link_libraries(test_c usearch_c)
51
- set_target_properties(test_c PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
52
- endif()
25
+ endif ()
package/c/README.md CHANGED
@@ -3,13 +3,13 @@
3
3
  ## Installation
4
4
 
5
5
  The simplest form to integrate is to copy the contents of `usearch/c/` into your project.
6
- To build the library `libusearch_c`, pass enable the `USEARCH_BUILD_CLIB` CMake option:
6
+ To build the library `libusearch_static_c` and `libusearch_c`, pass enable the `USEARCH_BUILD_LIB_C` CMake option:
7
7
 
8
8
  ```bash
9
- cmake -DUSEARCH_BUILD_CLIB=1 -DUSEARCH_BUILD_CTEST=1 -DUSEARCH_BUILD_STATIC=0 -DUSEARCH_BUILD_TEST=0 -DUSEARCH_BUILD_BENCHMARK=0 ..
10
- ```
11
-
12
- You can choose between a static and dynamic library by setting `USEARCH_BUILD_STATIC`.
9
+ cmake -B ./build -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_BUILD_TEST_CPP=0 -DUSEARCH_BUILD_BENCH_CPP=0
10
+ make -C ./build
11
+ ./build/test_c
12
+ ```
13
13
 
14
14
  ## Quickstart
15
15
 
package/c/lib.cpp CHANGED
@@ -87,15 +87,17 @@ USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, use
87
87
  metric_kind_t metric_kind = to_native_metric(options->metric_kind);
88
88
  scalar_kind_t scalar_kind = to_native_scalar(options->quantization);
89
89
 
90
- auto metric_lambda = [options](byte_t const* a, byte_t const* b) -> usearch_distance_t {
91
- return options->metric((void const*)a, (void const*)b);
92
- };
93
90
  metric_punned_t metric = //
94
- options->metric ? metric_punned_t(metric_lambda, options->dimensions, metric_kind, scalar_kind)
95
- : metric_punned_t(options->dimensions, metric_kind, scalar_kind);
91
+ !options->metric ? metric_punned_t(options->dimensions, metric_kind, scalar_kind)
92
+ : metric_punned_t(options->dimensions, //
93
+ reinterpret_cast<std::uintptr_t>(options->metric), //
94
+ metric_punned_signature_t::array_array_k, //
95
+ metric_kind, scalar_kind);
96
96
 
97
97
  index_dense_t index = index_dense_t::make(metric, config);
98
98
  index_dense_t* result_ptr = new index_dense_t(std::move(index));
99
+ if (!result_ptr || !*result_ptr)
100
+ *error = "Out of memory!";
99
101
  return result_ptr;
100
102
  }
101
103
 
@@ -235,8 +237,8 @@ USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, u
235
237
  return result.completed;
236
238
  }
237
239
 
238
- USEARCH_EXPORT size_t usearch_rename(usearch_index_t index, usearch_key_t from, usearch_key_t to,
239
- usearch_error_t* error) {
240
+ USEARCH_EXPORT size_t usearch_rename( //
241
+ usearch_index_t index, usearch_key_t from, usearch_key_t to, usearch_error_t* error) {
240
242
 
241
243
  assert(index && error);
242
244
  labeling_result_t result = reinterpret_cast<index_dense_t*>(index)->rename(from, to);
@@ -244,4 +246,47 @@ USEARCH_EXPORT size_t usearch_rename(usearch_index_t index, usearch_key_t from,
244
246
  *error = result.error.release();
245
247
  return result.completed;
246
248
  }
249
+
250
+ USEARCH_EXPORT usearch_distance_t usearch_distance( //
251
+ void const* vector_first, void const* vector_second, //
252
+ usearch_scalar_kind_t scalar_kind, size_t dimensions, //
253
+ usearch_metric_kind_t metric_kind, usearch_error_t* error) {
254
+
255
+ (void)error;
256
+ metric_punned_t metric(dimensions, to_native_metric(metric_kind), to_native_scalar(scalar_kind));
257
+ return metric((byte_t const*)vector_first, (byte_t const*)vector_second);
258
+ }
259
+
260
+ USEARCH_EXPORT void usearch_exact_search( //
261
+ void const* dataset, size_t dataset_count, size_t dataset_stride, //
262
+ void const* queries, size_t queries_count, size_t queries_stride, //
263
+ usearch_scalar_kind_t scalar_kind, size_t dimensions, //
264
+ usearch_metric_kind_t metric_kind, size_t count, size_t threads, //
265
+ usearch_key_t* keys, size_t keys_stride, //
266
+ usearch_distance_t* distances, size_t distances_stride, //
267
+ usearch_error_t* error) {
268
+
269
+ metric_punned_t metric(dimensions, to_native_metric(metric_kind), to_native_scalar(scalar_kind));
270
+ executor_default_t executor(threads);
271
+ static exact_search_t search;
272
+ exact_search_results_t result = search( //
273
+ (byte_t const*)dataset, dataset_count, dataset_stride, //
274
+ (byte_t const*)queries, queries_count, queries_stride, //
275
+ count, metric);
276
+
277
+ if (!result) {
278
+ *error = "Out of memory, allocating a temporary buffer for batch results";
279
+ return;
280
+ }
281
+
282
+ // Export results into the output buffer
283
+ for (std::size_t query_idx = 0; query_idx != queries_count; ++query_idx) {
284
+ auto query_result = result.at(query_idx);
285
+ auto query_keys = (usearch_key_t*)((byte_t*)keys + query_idx * keys_stride);
286
+ auto query_distances = (usearch_distance_t*)((byte_t*)distances + query_idx * distances_stride);
287
+ for (std::size_t i = 0; i != count; ++i)
288
+ query_keys[i] = static_cast<usearch_key_t>(query_result[i].offset),
289
+ query_distances[i] = static_cast<usearch_distance_t>(query_result[i].distance);
290
+ }
291
+ }
247
292
  }