usearch 2.9.1 → 2.10.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 (169) hide show
  1. package/README.md +50 -52
  2. package/javascript/{types → dist/cjs}/usearch.d.ts +90 -115
  3. package/javascript/dist/cjs/usearch.js +531 -0
  4. package/javascript/dist/esm/usearch.d.ts +212 -0
  5. package/javascript/{usearch.js → dist/esm/usearch.js} +202 -153
  6. package/package.json +25 -23
  7. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  8. package/prebuilds/linux-arm64/usearch.node +0 -0
  9. package/prebuilds/linux-x64/usearch.node +0 -0
  10. package/prebuilds/win32-ia32/usearch.node +0 -0
  11. package/prebuilds/win32-x64/usearch.node +0 -0
  12. package/.clang-format +0 -10
  13. package/.clang-tidy +0 -60
  14. package/.cmake-format.py +0 -19
  15. package/.dockerignore +0 -93
  16. package/.gitattributes +0 -9
  17. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -90
  18. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  19. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -64
  20. package/.github/workflows/Dockerfile.libs +0 -36
  21. package/.github/workflows/prerelease.yml +0 -331
  22. package/.github/workflows/release.yml +0 -722
  23. package/.github/workflows/update_version.sh +0 -15
  24. package/.gitmodules +0 -9
  25. package/.releaserc +0 -90
  26. package/CITATION.cff +0 -11
  27. package/CMakeLists.txt +0 -324
  28. package/CODE_OF_CONDUCT.md +0 -128
  29. package/CONTRIBUTING.md +0 -353
  30. package/Cargo.toml +0 -19
  31. package/Dockerfile +0 -16
  32. package/VERSION +0 -1
  33. package/assets/unum.png +0 -0
  34. package/assets/usearch-approaches-transparent.png +0 -0
  35. package/assets/usearch-approaches-white.png +0 -0
  36. package/assets/usearch-neighbor-types.png +0 -0
  37. package/binding.gyp +0 -87
  38. package/build.gradle +0 -204
  39. package/build.rs +0 -18
  40. package/c/CMakeLists.txt +0 -25
  41. package/c/README.md +0 -34
  42. package/c/lib.cpp +0 -358
  43. package/c/test.c +0 -374
  44. package/c/usearch.h +0 -311
  45. package/cmake/clipp.cmake +0 -7
  46. package/cmake/config.cmake.in +0 -15
  47. package/cmake/emscripten.cmake +0 -8
  48. package/cmake/jemalloc.cmake +0 -62
  49. package/cmake/pkg-config.pc.in +0 -4
  50. package/cmake/usearchConfigVersion.cmake.in +0 -20
  51. package/conanfile.py +0 -26
  52. package/cpp/CMakeLists.txt +0 -14
  53. package/cpp/README.md +0 -161
  54. package/cpp/bench.cpp +0 -618
  55. package/cpp/test.cpp +0 -323
  56. package/fp16/CMakeLists.txt +0 -176
  57. package/fp16/LICENSE +0 -11
  58. package/fp16/README.md +0 -20
  59. package/fp16/bench/alt-element.cc +0 -89
  60. package/fp16/bench/from-alt-array.cc +0 -175
  61. package/fp16/bench/from-ieee-array.cc +0 -399
  62. package/fp16/bench/ieee-element.cc +0 -272
  63. package/fp16/bench/to-alt-array.cc +0 -91
  64. package/fp16/bench/to-ieee-array.cc +0 -303
  65. package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
  66. package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
  67. package/fp16/cmake/DownloadPSimd.cmake +0 -15
  68. package/fp16/configure.py +0 -65
  69. package/fp16/confu.yaml +0 -8
  70. package/fp16/include/fp16/__init__.py +0 -0
  71. package/fp16/include/fp16/avx.py +0 -50
  72. package/fp16/include/fp16/avx2.py +0 -53
  73. package/fp16/include/fp16/bitcasts.h +0 -92
  74. package/fp16/include/fp16/fp16.h +0 -451
  75. package/fp16/include/fp16/psimd.h +0 -131
  76. package/fp16/include/fp16.h +0 -11
  77. package/fp16/jni/Android.mk +0 -6
  78. package/fp16/jni/Application.mk +0 -4
  79. package/fp16/test/alt-from-fp32-value.cc +0 -498
  80. package/fp16/test/alt-to-fp32-bits.cc +0 -263
  81. package/fp16/test/alt-to-fp32-psimd.cc +0 -145
  82. package/fp16/test/alt-to-fp32-value.cc +0 -348
  83. package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
  84. package/fp16/test/bitcasts.cc +0 -56
  85. package/fp16/test/ieee-from-fp32-value.cc +0 -523
  86. package/fp16/test/ieee-to-fp32-bits.cc +0 -333
  87. package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
  88. package/fp16/test/ieee-to-fp32-value.cc +0 -420
  89. package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
  90. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
  91. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
  92. package/fp16/test/peachpy/stubs.py +0 -38
  93. package/fp16/test/tables.cc +0 -530
  94. package/fp16/test/tables.h +0 -13
  95. package/fp16/third-party/THHalf.h +0 -92
  96. package/fp16/third-party/eigen-half.h +0 -170
  97. package/fp16/third-party/float16-compressor.h +0 -80
  98. package/fp16/third-party/half.hpp +0 -2916
  99. package/fp16/third-party/npy-halffloat.h +0 -328
  100. package/include/usearch/index.hpp +0 -3836
  101. package/include/usearch/index_dense.hpp +0 -2004
  102. package/include/usearch/index_plugins.hpp +0 -2203
  103. package/javascript/lib.cpp +0 -341
  104. package/javascript/types/usearch.d.ts.map +0 -1
  105. package/javascript/usearch.test.js +0 -74
  106. package/package-ci.json +0 -10
  107. package/pyproject.toml +0 -51
  108. package/setup.py +0 -201
  109. package/simsimd/.releaserc +0 -86
  110. package/simsimd/Cargo.lock +0 -708
  111. package/simsimd/Cargo.toml +0 -36
  112. package/simsimd/LICENSE +0 -201
  113. package/simsimd/README.md +0 -275
  114. package/simsimd/binding.gyp +0 -36
  115. package/simsimd/build.rs +0 -20
  116. package/simsimd/include/simsimd/binary.h +0 -201
  117. package/simsimd/include/simsimd/probability.h +0 -548
  118. package/simsimd/include/simsimd/simsimd.h +0 -456
  119. package/simsimd/include/simsimd/spatial.h +0 -1175
  120. package/simsimd/include/simsimd/types.h +0 -207
  121. package/simsimd/javascript/bench.js +0 -127
  122. package/simsimd/javascript/fallback.ts +0 -193
  123. package/simsimd/javascript/lib.c +0 -102
  124. package/simsimd/javascript/node-gyp-build.d.ts +0 -1
  125. package/simsimd/javascript/simsimd.ts +0 -124
  126. package/simsimd/javascript/test.mjs +0 -153
  127. package/simsimd/javascript/tsconfig-base.json +0 -25
  128. package/simsimd/javascript/tsconfig-cjs.json +0 -8
  129. package/simsimd/javascript/tsconfig-esm.json +0 -8
  130. package/simsimd/package-lock.json +0 -1688
  131. package/simsimd/package.json +0 -61
  132. package/simsimd/rust/benches/cosine.rs +0 -27
  133. package/simsimd/rust/benches/native.rs +0 -27
  134. package/simsimd/rust/benches/sqeuclidean.rs +0 -27
  135. package/simsimd/rust/lib.c +0 -68
  136. package/simsimd/rust/lib.rs +0 -232
  137. package/sqlite/README.md +0 -178
  138. package/sqlite/lib.cpp +0 -325
  139. package/stringzilla/CONTRIBUTING.md +0 -429
  140. package/stringzilla/Cargo.lock +0 -25
  141. package/stringzilla/Cargo.toml +0 -26
  142. package/stringzilla/LICENSE +0 -201
  143. package/stringzilla/README.md +0 -1281
  144. package/stringzilla/VERSION +0 -1
  145. package/stringzilla/assets/cover-strinzilla.jpeg +0 -0
  146. package/stringzilla/assets/meme-stringzilla-v2.jpeg +0 -0
  147. package/stringzilla/assets/meme-stringzilla-v3.jpeg +0 -0
  148. package/stringzilla/binding.gyp +0 -16
  149. package/stringzilla/build.rs +0 -14
  150. package/stringzilla/c/lib.c +0 -304
  151. package/stringzilla/cli/README.md +0 -48
  152. package/stringzilla/cli/split.py +0 -72
  153. package/stringzilla/cli/wc.py +0 -37
  154. package/stringzilla/include/stringzilla/experimental.h +0 -724
  155. package/stringzilla/include/stringzilla/module.modulemap +0 -9
  156. package/stringzilla/include/stringzilla/stringzilla.h +0 -5240
  157. package/stringzilla/include/stringzilla/stringzilla.hpp +0 -3830
  158. package/stringzilla/javascript/lib.c +0 -125
  159. package/stringzilla/javascript/stringzilla.js +0 -22
  160. package/stringzilla/package-ci.json +0 -10
  161. package/stringzilla/package.json +0 -32
  162. package/stringzilla/rust/lib.rs +0 -362
  163. package/stringzilla/swift/StringProtocol+StringZilla.swift +0 -280
  164. package/stringzilla/swift/Test.swift +0 -60
  165. package/tsconfig.json +0 -21
  166. package/wasmer.toml +0 -12
  167. package/winlibinstaller.bat +0 -42
  168. /package/{simsimd/javascript/dist-package-cjs.json → javascript/dist/cjs/package.json} +0 -0
  169. /package/{simsimd/javascript/dist-package-esm.json → javascript/dist/esm/package.json} +0 -0
@@ -1,125 +0,0 @@
1
- /**
2
- * @file lib.c
3
- * @brief JavaScript bindings for StringZilla.
4
- * @author Ash Vardanian
5
- * @date September 18, 2023
6
- *
7
- * @copyright Copyright (c) 2023
8
- * @see NodeJS docs: https://nodejs.org/api/n-api.html
9
- */
10
- #include <stdio.h> // `printf` for debug builds
11
- #include <stdlib.h> // `malloc` to export strings into UTF-8
12
-
13
- #include <node_api.h> // `napi_*` functions
14
-
15
- #include <stringzilla/stringzilla.h> // `sz_*` functions
16
-
17
- napi_value indexOfAPI(napi_env env, napi_callback_info info) {
18
- size_t argc = 2;
19
- napi_value args[2];
20
- napi_get_cb_info(env, info, &argc, args, NULL, NULL);
21
-
22
- // Extract the C string from the JavaScript string for haystack and needle
23
- sz_string_view_t haystack = {NULL, 0};
24
- sz_string_view_t needle = {NULL, 0};
25
-
26
- // For haystack
27
- napi_get_value_string_utf8(env, args[0], NULL, 0, (size_t *)&haystack.length);
28
- haystack.start = malloc(haystack.length + 1);
29
- napi_get_value_string_utf8(env, args[0], (char *)haystack.start, haystack.length + 1, (size_t *)&haystack.length);
30
-
31
- // For needle
32
- napi_get_value_string_utf8(env, args[1], NULL, 0, (size_t *)&needle.length);
33
- needle.start = malloc(needle.length + 1);
34
- napi_get_value_string_utf8(env, args[1], (char *)needle.start, needle.length + 1, (size_t *)&needle.length);
35
-
36
- // Convert the result to JavaScript BigInt and return
37
- napi_value js_result;
38
- if (needle.length == 0) { napi_create_bigint_int64(env, 0, &js_result); }
39
- else {
40
- sz_cptr_t result = sz_find(haystack.start, haystack.length, needle.start, needle.length);
41
-
42
- // In JavaScript, if `indexOf` is unable to indexOf the specified value, then it should return -1
43
- if (result == NULL) { napi_create_bigint_int64(env, -1, &js_result); }
44
- else { napi_create_bigint_uint64(env, result - haystack.start, &js_result); }
45
- }
46
-
47
- // Cleanup
48
- free((void *)haystack.start);
49
- free((void *)needle.start);
50
- return js_result;
51
- }
52
-
53
- napi_value countAPI(napi_env env, napi_callback_info info) {
54
- size_t argc = 3;
55
- napi_value args[3];
56
- napi_get_cb_info(env, info, &argc, args, NULL, NULL);
57
-
58
- // Extract the C string from the JavaScript string for haystack and needle
59
- sz_string_view_t haystack = {NULL, 0};
60
- sz_string_view_t needle = {NULL, 0};
61
-
62
- // For haystack
63
- napi_get_value_string_utf8(env, args[0], NULL, 0, (size_t *)&haystack.length);
64
- haystack.start = malloc(haystack.length + 1);
65
- napi_get_value_string_utf8(env, args[0], (char *)haystack.start, haystack.length + 1, (size_t *)&haystack.length);
66
-
67
- // For needle
68
- napi_get_value_string_utf8(env, args[1], NULL, 0, (size_t *)&needle.length);
69
- needle.start = malloc(needle.length + 1);
70
- napi_get_value_string_utf8(env, args[1], (char *)needle.start, needle.length + 1, (size_t *)&needle.length);
71
-
72
- bool overlap = false;
73
- if (argc > 2) { napi_get_value_bool(env, args[2], &overlap); }
74
-
75
- void const *haystack_start = haystack.start, *needle_start = needle.start;
76
-
77
- size_t count = 0;
78
- if (needle.length == 0 || haystack.length == 0 || haystack.length < needle.length) { count = 0; }
79
- else if (overlap) {
80
- while (haystack.length) {
81
- sz_cptr_t ptr = sz_find(haystack.start, haystack.length, needle.start, needle.length);
82
- sz_bool_t found = ptr != NULL;
83
- sz_size_t offset = found ? (sz_size_t)(ptr - haystack.start) : haystack.length;
84
- count += found;
85
- haystack.start += offset + found;
86
- haystack.length -= offset + found;
87
- }
88
- }
89
- else {
90
- while (haystack.length) {
91
- sz_cptr_t ptr = sz_find(haystack.start, haystack.length, needle.start, needle.length);
92
- sz_bool_t found = ptr != NULL;
93
- sz_size_t offset = found ? (sz_size_t)(ptr - haystack.start) : haystack.length;
94
- count += found;
95
- haystack.start += offset + needle.length;
96
- haystack.length -= offset + needle.length * found;
97
- }
98
- }
99
-
100
- // Cleanup
101
- free((void *)haystack_start);
102
- free((void *)needle_start);
103
-
104
- // Convert the `count` to JavaScript `BigInt` and return
105
- napi_value js_count;
106
- napi_create_bigint_uint64(env, count, &js_count);
107
-
108
- return js_count;
109
- }
110
-
111
- napi_value Init(napi_env env, napi_value exports) {
112
-
113
- // Define an array of property descriptors
114
- napi_property_descriptor findDesc = {"indexOf", 0, indexOfAPI, 0, 0, 0, napi_default, 0};
115
- napi_property_descriptor countDesc = {"count", 0, countAPI, 0, 0, 0, napi_default, 0};
116
- napi_property_descriptor properties[] = {findDesc, countDesc};
117
-
118
- // Define the properties on the `exports` object
119
- size_t propertyCount = sizeof(properties) / sizeof(properties[0]);
120
- napi_define_properties(env, exports, propertyCount, properties);
121
-
122
- return exports;
123
- }
124
-
125
- NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
@@ -1,22 +0,0 @@
1
- const compiled = require('bindings')('stringzilla');
2
-
3
- module.exports = {
4
- /**
5
- * Searches for a short string in a long one.
6
- *
7
- * @param {string} haystack
8
- * @param {string} needle
9
- * @returns {bigint}
10
- */
11
- find: compiled.find,
12
-
13
- /**
14
- * Searches for a substring in a larger string.
15
- *
16
- * @param {string} haystack
17
- * @param {string} needle
18
- * @param {boolean} overlap
19
- * @returns {bigint}
20
- */
21
- count: compiled.count
22
- };
@@ -1,10 +0,0 @@
1
- {
2
- "name": "stringzilla-ci",
3
- "version": "1.0.0",
4
- "devDependencies": {
5
- "@semantic-release/exec": "^6.0.3",
6
- "@semantic-release/git": "^10.0.1",
7
- "conventional-changelog-eslint": "^3.0.9",
8
- "semantic-release": "^21.1.2"
9
- }
10
- }
@@ -1,32 +0,0 @@
1
- {
2
- "name": "stringzilla",
3
- "version": "3.2.0",
4
- "description": "SIMD-accelerated string search, sort, hashes, fingerprints, & edit distances",
5
- "author": "Ash Vardanian",
6
- "license": "Apache 2.0",
7
- "main": "javascript/stringzilla.js",
8
- "type": "module",
9
- "repository": {
10
- "type": "git",
11
- "url": "https://github.com/ashvardanian/stringzilla.git"
12
- },
13
- "gypfile": true,
14
- "engines": {
15
- "node": "~10 >=10.20 || >=12.17"
16
- },
17
- "dependencies": {
18
- "@types/node": "^20.4.5",
19
- "bindings": "~1.2.1",
20
- "node-addon-api": "^3.0.0"
21
- },
22
- "scripts": {
23
- "test": "node --test ./scripts/test.js"
24
- },
25
- "devDependencies": {
26
- "@semantic-release/exec": "^6.0.3",
27
- "@semantic-release/git": "^10.0.1",
28
- "conventional-changelog-eslint": "^3.0.9",
29
- "semantic-release": "^21.1.2",
30
- "typescript": "^5.1.6"
31
- }
32
- }
@@ -1,362 +0,0 @@
1
- #![cfg_attr(not(test), no_std)]
2
-
3
- use core::ffi::c_void;
4
-
5
- // Import the functions from the StringZilla C library.
6
- extern "C" {
7
- fn sz_find(
8
- haystack: *const c_void,
9
- haystack_length: usize,
10
- needle: *const c_void,
11
- needle_length: usize,
12
- ) -> *const c_void;
13
-
14
- fn sz_rfind(
15
- haystack: *const c_void,
16
- haystack_length: usize,
17
- needle: *const c_void,
18
- needle_length: usize,
19
- ) -> *const c_void;
20
-
21
- fn sz_find_char_from(
22
- haystack: *const c_void,
23
- haystack_length: usize,
24
- needle: *const c_void,
25
- needle_length: usize,
26
- ) -> *const c_void;
27
-
28
- fn sz_rfind_char_from(
29
- haystack: *const c_void,
30
- haystack_length: usize,
31
- needle: *const c_void,
32
- needle_length: usize,
33
- ) -> *const c_void;
34
-
35
- fn sz_find_char_not_from(
36
- haystack: *const c_void,
37
- haystack_length: usize,
38
- needle: *const c_void,
39
- needle_length: usize,
40
- ) -> *const c_void;
41
-
42
- fn sz_rfind_char_not_from(
43
- haystack: *const c_void,
44
- haystack_length: usize,
45
- needle: *const c_void,
46
- needle_length: usize,
47
- ) -> *const c_void;
48
-
49
- fn sz_edit_distance(
50
- haystack1: *const c_void,
51
- haystack1_length: usize,
52
- haystack2: *const c_void,
53
- haystack2_length: usize,
54
- bound: usize,
55
- allocator: *const c_void,
56
- ) -> usize;
57
-
58
- fn sz_alignment_score(
59
- haystack1: *const c_void,
60
- haystack1_length: usize,
61
- haystack2: *const c_void,
62
- haystack2_length: usize,
63
- matrix: *const c_void,
64
- gap: i8,
65
- allocator: *const c_void,
66
- ) -> isize;
67
- }
68
-
69
- /// The [StringZilla] trait provides a collection of string searching and manipulation functionalities.
70
- pub trait StringZilla<N>
71
- where
72
- N: AsRef<[u8]>,
73
- {
74
- /// Locates first matching substring. Equivalent to `memmem(haystack, h_length, needle, n_length)` in LibC. Similar
75
- /// to `strstr(haystack, needle)` in LibC, but requires known length.
76
- fn sz_find(&self, needle: N) -> Option<usize>;
77
-
78
- /// Locates the last matching substring.
79
- fn sz_rfind(&self, needle: N) -> Option<usize>;
80
-
81
- /// Finds the first character in the haystack, that is present in the needle.
82
- fn sz_find_char_from(&self, needles: N) -> Option<usize>;
83
-
84
- /// Finds the last character in the haystack, that is present in the needle.
85
- fn sz_rfind_char_from(&self, needles: N) -> Option<usize>;
86
-
87
- /// Finds the first character in the haystack, that is __not__ present in the needle.
88
- fn sz_find_char_not_from(&self, needles: N) -> Option<usize>;
89
-
90
- /// Finds the last character in the haystack, that is __not__ present in the needle.
91
- fn sz_rfind_char_not_from(&self, needles: N) -> Option<usize>;
92
-
93
- /// Computes the Levenshtein edit-distance between two strings using the Wagner-Fisher algorithm.
94
- /// Similar to the Needleman-Wunsch alignment algorithm. Often used in fuzzy string matching.
95
- fn sz_edit_distance(&self, needle: N) -> usize;
96
-
97
- /// Computes Needleman–Wunsch alignment score for two strings. Often used in bioinformatics and cheminformatics.
98
- /// Similar to the Levenshtein edit-distance, parameterized for gap and substitution penalties.
99
- fn sz_alignment_score(&self, needle: N, matrix: [[i8; 256]; 256], gap: i8) -> isize;
100
- }
101
-
102
- impl<T, N> StringZilla<N> for T
103
- where
104
- T: AsRef<[u8]>,
105
- N: AsRef<[u8]>,
106
- {
107
- fn sz_find(&self, needle: N) -> Option<usize> {
108
- let haystack_ref = self.as_ref();
109
- let needle_ref = needle.as_ref();
110
- let haystack_pointer = haystack_ref.as_ptr() as _;
111
- let haystack_length = haystack_ref.len();
112
- let needle_pointer = needle_ref.as_ptr() as _;
113
- let needle_length = needle_ref.len();
114
- let result = unsafe {
115
- sz_find(
116
- haystack_pointer,
117
- haystack_length,
118
- needle_pointer,
119
- needle_length,
120
- )
121
- };
122
-
123
- if result.is_null() {
124
- None
125
- } else {
126
- Some(unsafe { result.offset_from(haystack_pointer) } as usize)
127
- }
128
- }
129
-
130
- fn sz_rfind(&self, needle: N) -> Option<usize> {
131
- let haystack_ref = self.as_ref();
132
- let needle_ref = needle.as_ref();
133
- let haystack_pointer = haystack_ref.as_ptr() as _;
134
- let haystack_length = haystack_ref.len();
135
- let needle_pointer = needle_ref.as_ptr() as _;
136
- let needle_length = needle_ref.len();
137
- let result = unsafe {
138
- sz_rfind(
139
- haystack_pointer,
140
- haystack_length,
141
- needle_pointer,
142
- needle_length,
143
- )
144
- };
145
-
146
- if result.is_null() {
147
- None
148
- } else {
149
- Some(unsafe { result.offset_from(haystack_pointer) } as usize)
150
- }
151
- }
152
-
153
- fn sz_find_char_from(&self, needles: N) -> Option<usize> {
154
- let haystack_ref = self.as_ref();
155
- let needles_ref = needles.as_ref();
156
- let haystack_pointer = haystack_ref.as_ptr() as _;
157
- let haystack_length = haystack_ref.len();
158
- let needles_pointer = needles_ref.as_ptr() as _;
159
- let needles_length = needles_ref.len();
160
- let result = unsafe {
161
- sz_find_char_from(
162
- haystack_pointer,
163
- haystack_length,
164
- needles_pointer,
165
- needles_length,
166
- )
167
- };
168
- if result.is_null() {
169
- None
170
- } else {
171
- Some(unsafe { result.offset_from(haystack_pointer) } as usize)
172
- }
173
- }
174
-
175
- fn sz_rfind_char_from(&self, needles: N) -> Option<usize> {
176
- let haystack_ref = self.as_ref();
177
- let needles_ref = needles.as_ref();
178
- let haystack_pointer = haystack_ref.as_ptr() as _;
179
- let haystack_length = haystack_ref.len();
180
- let needles_pointer = needles_ref.as_ptr() as _;
181
- let needles_length = needles_ref.len();
182
- let result = unsafe {
183
- sz_rfind_char_from(
184
- haystack_pointer,
185
- haystack_length,
186
- needles_pointer,
187
- needles_length,
188
- )
189
- };
190
- if result.is_null() {
191
- None
192
- } else {
193
- Some(unsafe { result.offset_from(haystack_pointer) } as usize)
194
- }
195
- }
196
-
197
- fn sz_find_char_not_from(&self, needles: N) -> Option<usize> {
198
- let haystack_ref = self.as_ref();
199
- let needles_ref = needles.as_ref();
200
- let haystack_pointer = haystack_ref.as_ptr() as _;
201
- let haystack_length = haystack_ref.len();
202
- let needles_pointer = needles_ref.as_ptr() as _;
203
- let needles_length = needles_ref.len();
204
- let result = unsafe {
205
- sz_find_char_not_from(
206
- haystack_pointer,
207
- haystack_length,
208
- needles_pointer,
209
- needles_length,
210
- )
211
- };
212
- if result.is_null() {
213
- None
214
- } else {
215
- Some(unsafe { result.offset_from(haystack_pointer) } as usize)
216
- }
217
- }
218
-
219
- fn sz_rfind_char_not_from(&self, needles: N) -> Option<usize> {
220
- let haystack_ref = self.as_ref();
221
- let needles_ref = needles.as_ref();
222
- let haystack_pointer = haystack_ref.as_ptr() as _;
223
- let haystack_length = haystack_ref.len();
224
- let needles_pointer = needles_ref.as_ptr() as _;
225
- let needles_length = needles_ref.len();
226
- let result = unsafe {
227
- sz_rfind_char_not_from(
228
- haystack_pointer,
229
- haystack_length,
230
- needles_pointer,
231
- needles_length,
232
- )
233
- };
234
- if result.is_null() {
235
- None
236
- } else {
237
- Some(unsafe { result.offset_from(haystack_pointer) } as usize)
238
- }
239
- }
240
-
241
- fn sz_edit_distance(&self, needle: N) -> usize {
242
- let haystack_ref = self.as_ref();
243
- let needle_ref = needle.as_ref();
244
- let haystack_length = haystack_ref.len();
245
- let needle_length = needle_ref.len();
246
- let haystack_pointer = haystack_ref.as_ptr() as _;
247
- let needle_pointer = needle_ref.as_ptr() as _;
248
- unsafe {
249
- sz_edit_distance(
250
- haystack_pointer,
251
- haystack_length,
252
- needle_pointer,
253
- needle_length,
254
- // Upper bound on the distance, that allows us to exit early. If zero is
255
- // passed, the maximum possible distance will be equal to the length of
256
- // the longer input.
257
- 0,
258
- // Uses the default allocator
259
- core::ptr::null(),
260
- )
261
- }
262
- }
263
-
264
- fn sz_alignment_score(&self, needle: N, matrix: [[i8; 256]; 256], gap: i8) -> isize {
265
- let haystack_ref = self.as_ref();
266
- let needle_ref = needle.as_ref();
267
- let haystack_length = haystack_ref.len();
268
- let needle_length = needle_ref.len();
269
- let haystack_pointer = haystack_ref.as_ptr() as _;
270
- let needle_pointer = needle_ref.as_ptr() as _;
271
- unsafe {
272
- sz_alignment_score(
273
- haystack_pointer,
274
- haystack_length,
275
- needle_pointer,
276
- needle_length,
277
- matrix.as_ptr() as _,
278
- gap,
279
- core::ptr::null(),
280
- )
281
- }
282
- }
283
- }
284
-
285
- #[cfg(test)]
286
- mod tests {
287
- use std::borrow::Cow;
288
-
289
- use crate::StringZilla;
290
-
291
- fn unary_substitution_costs() -> [[i8; 256]; 256] {
292
- let mut result = [[0; 256]; 256];
293
-
294
- for i in 0..256 {
295
- for j in 0..256 {
296
- result[i][j] = if i == j { 0 } else { -1 };
297
- }
298
- }
299
-
300
- result
301
- }
302
-
303
- #[test]
304
- fn levenshtein() {
305
- assert_eq!("hello".sz_edit_distance("hell"), 1);
306
- assert_eq!("hello".sz_edit_distance("hell"), 1);
307
- assert_eq!("abc".sz_edit_distance(""), 3);
308
- assert_eq!("abc".sz_edit_distance("ac"), 1);
309
- assert_eq!("abc".sz_edit_distance("a_bc"), 1);
310
- assert_eq!("abc".sz_edit_distance("adc"), 1);
311
- assert_eq!("ggbuzgjux{}l".sz_edit_distance("gbuzgjux{}l"), 1);
312
- assert_eq!("abcdefgABCDEFG".sz_edit_distance("ABCDEFGabcdefg"), 14);
313
- assert_eq!("fitting".sz_edit_distance("kitty"), 4);
314
- assert_eq!("smitten".sz_edit_distance("mitten"), 1);
315
- }
316
-
317
- #[test]
318
- fn needleman() {
319
- let costs_vector = unary_substitution_costs();
320
- assert_eq!("listen".sz_alignment_score("silent", costs_vector, -1), -4);
321
- assert_eq!(
322
- "abcdefgABCDEFG".sz_alignment_score("ABCDEFGabcdefg", costs_vector, -1),
323
- -14
324
- );
325
- assert_eq!("hello".sz_alignment_score("hello", costs_vector, -1), 0);
326
- assert_eq!("hello".sz_alignment_score("hell", costs_vector, -1), -1);
327
- }
328
-
329
- #[test]
330
- fn basics() {
331
- let my_string: String = String::from("Hello, world!");
332
- let my_str: &str = my_string.as_str();
333
- let my_cow_str: Cow<'_, str> = Cow::from(&my_string);
334
-
335
- // Use the generic function with a String
336
- assert_eq!(my_string.sz_find("world"), Some(7));
337
- assert_eq!(my_string.sz_rfind("world"), Some(7));
338
- assert_eq!(my_string.sz_find_char_from("world"), Some(2));
339
- assert_eq!(my_string.sz_rfind_char_from("world"), Some(11));
340
- assert_eq!(my_string.sz_find_char_not_from("world"), Some(0));
341
- assert_eq!(my_string.sz_rfind_char_not_from("world"), Some(12));
342
-
343
- // Use the generic function with a &str
344
- assert_eq!(my_str.sz_find("world"), Some(7));
345
- assert_eq!(my_str.sz_find("world"), Some(7));
346
- assert_eq!(my_str.sz_find_char_from("world"), Some(2));
347
- assert_eq!(my_str.sz_rfind_char_from("world"), Some(11));
348
- assert_eq!(my_str.sz_find_char_not_from("world"), Some(0));
349
- assert_eq!(my_str.sz_rfind_char_not_from("world"), Some(12));
350
-
351
- // Use the generic function with a Cow<'_, str>
352
- assert_eq!(my_cow_str.as_ref().sz_find("world"), Some(7));
353
- assert_eq!(my_cow_str.as_ref().sz_find("world"), Some(7));
354
- assert_eq!(my_cow_str.as_ref().sz_find_char_from("world"), Some(2));
355
- assert_eq!(my_cow_str.as_ref().sz_rfind_char_from("world"), Some(11));
356
- assert_eq!(my_cow_str.as_ref().sz_find_char_not_from("world"), Some(0));
357
- assert_eq!(
358
- my_cow_str.as_ref().sz_rfind_char_not_from("world"),
359
- Some(12)
360
- );
361
- }
362
- }