usearch 2.9.2 → 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.
- package/README.md +39 -38
- package/javascript/{types → dist/cjs}/usearch.d.ts +90 -115
- package/javascript/dist/cjs/usearch.js +531 -0
- package/javascript/dist/esm/usearch.d.ts +212 -0
- package/javascript/{usearch.js → dist/esm/usearch.js} +199 -153
- package/package.json +25 -23
- package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
- package/prebuilds/linux-arm64/usearch.node +0 -0
- package/prebuilds/linux-x64/usearch.node +0 -0
- package/prebuilds/win32-ia32/usearch.node +0 -0
- package/prebuilds/win32-x64/usearch.node +0 -0
- package/.clang-format +0 -10
- package/.clang-tidy +0 -60
- package/.cmake-format.py +0 -19
- package/.dockerignore +0 -93
- package/.gitattributes +0 -9
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -90
- package/.github/ISSUE_TEMPLATE/config.yml +0 -5
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -64
- package/.github/workflows/Dockerfile.libs +0 -36
- package/.github/workflows/prerelease.yml +0 -331
- package/.github/workflows/release.yml +0 -722
- package/.github/workflows/update_version.sh +0 -15
- package/.gitmodules +0 -9
- package/.releaserc +0 -90
- package/CITATION.cff +0 -11
- package/CMakeLists.txt +0 -324
- package/CODE_OF_CONDUCT.md +0 -128
- package/CONTRIBUTING.md +0 -361
- package/Cargo.toml +0 -19
- package/Dockerfile +0 -16
- package/VERSION +0 -1
- package/assets/unum.png +0 -0
- package/assets/usearch-approaches-transparent.png +0 -0
- package/assets/usearch-approaches-white.png +0 -0
- package/assets/usearch-neighbor-types.png +0 -0
- package/binding.gyp +0 -87
- package/build.gradle +0 -204
- package/build.rs +0 -18
- package/c/CMakeLists.txt +0 -25
- package/c/README.md +0 -34
- package/c/lib.cpp +0 -358
- package/c/test.c +0 -382
- package/c/usearch.h +0 -311
- package/cmake/clipp.cmake +0 -7
- package/cmake/config.cmake.in +0 -15
- package/cmake/emscripten.cmake +0 -8
- package/cmake/jemalloc.cmake +0 -62
- package/cmake/pkg-config.pc.in +0 -4
- package/cmake/usearchConfigVersion.cmake.in +0 -20
- package/conanfile.py +0 -26
- package/cpp/CMakeLists.txt +0 -14
- package/cpp/README.md +0 -161
- package/cpp/bench.cpp +0 -618
- package/cpp/test.cpp +0 -323
- package/fp16/CMakeLists.txt +0 -176
- package/fp16/LICENSE +0 -11
- package/fp16/README.md +0 -20
- package/fp16/bench/alt-element.cc +0 -89
- package/fp16/bench/from-alt-array.cc +0 -175
- package/fp16/bench/from-ieee-array.cc +0 -399
- package/fp16/bench/ieee-element.cc +0 -272
- package/fp16/bench/to-alt-array.cc +0 -91
- package/fp16/bench/to-ieee-array.cc +0 -303
- package/fp16/cmake/DownloadGoogleBenchmark.cmake +0 -15
- package/fp16/cmake/DownloadGoogleTest.cmake +0 -15
- package/fp16/cmake/DownloadPSimd.cmake +0 -15
- package/fp16/configure.py +0 -65
- package/fp16/confu.yaml +0 -8
- package/fp16/include/fp16/__init__.py +0 -0
- package/fp16/include/fp16/avx.py +0 -50
- package/fp16/include/fp16/avx2.py +0 -53
- package/fp16/include/fp16/bitcasts.h +0 -92
- package/fp16/include/fp16/fp16.h +0 -451
- package/fp16/include/fp16/psimd.h +0 -131
- package/fp16/include/fp16.h +0 -11
- package/fp16/jni/Android.mk +0 -6
- package/fp16/jni/Application.mk +0 -4
- package/fp16/test/alt-from-fp32-value.cc +0 -498
- package/fp16/test/alt-to-fp32-bits.cc +0 -263
- package/fp16/test/alt-to-fp32-psimd.cc +0 -145
- package/fp16/test/alt-to-fp32-value.cc +0 -348
- package/fp16/test/alt-to-fp32x2-psimd.cc +0 -245
- package/fp16/test/bitcasts.cc +0 -56
- package/fp16/test/ieee-from-fp32-value.cc +0 -523
- package/fp16/test/ieee-to-fp32-bits.cc +0 -333
- package/fp16/test/ieee-to-fp32-psimd.cc +0 -312
- package/fp16/test/ieee-to-fp32-value.cc +0 -420
- package/fp16/test/ieee-to-fp32x2-psimd.cc +0 -541
- package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +0 -96
- package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +0 -96
- package/fp16/test/peachpy/stubs.py +0 -38
- package/fp16/test/tables.cc +0 -530
- package/fp16/test/tables.h +0 -13
- package/fp16/third-party/THHalf.h +0 -92
- package/fp16/third-party/eigen-half.h +0 -170
- package/fp16/third-party/float16-compressor.h +0 -80
- package/fp16/third-party/half.hpp +0 -2916
- package/fp16/third-party/npy-halffloat.h +0 -328
- package/include/usearch/index.hpp +0 -3836
- package/include/usearch/index_dense.hpp +0 -2004
- package/include/usearch/index_plugins.hpp +0 -2213
- package/javascript/lib.cpp +0 -341
- package/javascript/types/usearch.d.ts.map +0 -1
- package/javascript/usearch.test.js +0 -74
- package/package-ci.json +0 -10
- package/pyproject.toml +0 -51
- package/setup.py +0 -201
- package/simsimd/.releaserc +0 -86
- package/simsimd/CONTRIBUTING.md +0 -88
- package/simsimd/Cargo.lock +0 -709
- package/simsimd/Cargo.toml +0 -44
- package/simsimd/LICENSE +0 -201
- package/simsimd/README.md +0 -317
- package/simsimd/binding.gyp +0 -36
- package/simsimd/build.rs +0 -20
- package/simsimd/include/simsimd/binary.h +0 -245
- package/simsimd/include/simsimd/complex.h +0 -174
- package/simsimd/include/simsimd/probability.h +0 -548
- package/simsimd/include/simsimd/simsimd.h +0 -465
- package/simsimd/include/simsimd/spatial.h +0 -1267
- package/simsimd/include/simsimd/types.h +0 -208
- package/simsimd/javascript/bench.js +0 -127
- package/simsimd/javascript/fallback.ts +0 -193
- package/simsimd/javascript/lib.c +0 -102
- package/simsimd/javascript/node-gyp-build.d.ts +0 -1
- package/simsimd/javascript/simsimd.ts +0 -124
- package/simsimd/javascript/test.mjs +0 -153
- package/simsimd/javascript/tsconfig-base.json +0 -25
- package/simsimd/javascript/tsconfig-cjs.json +0 -8
- package/simsimd/javascript/tsconfig-esm.json +0 -8
- package/simsimd/package-lock.json +0 -1688
- package/simsimd/package.json +0 -61
- package/simsimd/rust/benches/cosine.rs +0 -27
- package/simsimd/rust/benches/native.rs +0 -30
- package/simsimd/rust/benches/sqeuclidean.rs +0 -27
- package/simsimd/rust/lib.c +0 -45
- package/simsimd/rust/lib.rs +0 -550
- package/sqlite/README.md +0 -178
- package/sqlite/lib.cpp +0 -325
- package/stringzilla/CONTRIBUTING.md +0 -446
- package/stringzilla/Cargo.lock +0 -25
- package/stringzilla/Cargo.toml +0 -26
- package/stringzilla/LICENSE +0 -201
- package/stringzilla/README.md +0 -1422
- package/stringzilla/VERSION +0 -1
- package/stringzilla/assets/cover-strinzilla.jpeg +0 -0
- package/stringzilla/assets/meme-stringzilla-v2.jpeg +0 -0
- package/stringzilla/assets/meme-stringzilla-v3.jpeg +0 -0
- package/stringzilla/binding.gyp +0 -16
- package/stringzilla/build.rs +0 -87
- package/stringzilla/c/lib.c +0 -337
- package/stringzilla/cli/README.md +0 -65
- package/stringzilla/cli/__init__.py +0 -0
- package/stringzilla/cli/split.py +0 -105
- package/stringzilla/cli/wc.py +0 -117
- package/stringzilla/include/stringzilla/experimental.h +0 -845
- package/stringzilla/include/stringzilla/module.modulemap +0 -9
- package/stringzilla/include/stringzilla/stringzilla.h +0 -5370
- package/stringzilla/include/stringzilla/stringzilla.hpp +0 -3838
- package/stringzilla/javascript/lib.c +0 -125
- package/stringzilla/javascript/stringzilla.js +0 -22
- package/stringzilla/package-ci.json +0 -10
- package/stringzilla/package.json +0 -32
- package/stringzilla/rust/lib.rs +0 -873
- package/stringzilla/swift/StringProtocol+StringZilla.swift +0 -280
- package/stringzilla/swift/Test.swift +0 -60
- package/tsconfig.json +0 -21
- package/wasmer.toml +0 -12
- package/winlibinstaller.bat +0 -42
- /package/{simsimd/javascript/dist-package-cjs.json → javascript/dist/cjs/package.json} +0 -0
- /package/{simsimd/javascript/dist-package-esm.json → javascript/dist/esm/package.json} +0 -0
package/stringzilla/rust/lib.rs
DELETED
|
@@ -1,873 +0,0 @@
|
|
|
1
|
-
#![cfg_attr(not(test), no_std)]
|
|
2
|
-
|
|
3
|
-
/// The `sz` module provides a collection of string searching and manipulation functionality,
|
|
4
|
-
/// designed for high efficiency and compatibility with no_std environments. This module offers
|
|
5
|
-
/// various utilities for byte string manipulation, including search, reverse search, and
|
|
6
|
-
/// edit-distance calculations, suitable for a wide range of applications from basic string
|
|
7
|
-
/// processing to complex text analysis tasks.
|
|
8
|
-
|
|
9
|
-
pub mod sz {
|
|
10
|
-
|
|
11
|
-
use core::ffi::c_void;
|
|
12
|
-
|
|
13
|
-
// Import the functions from the StringZilla C library.
|
|
14
|
-
extern "C" {
|
|
15
|
-
fn sz_find(
|
|
16
|
-
haystack: *const c_void,
|
|
17
|
-
haystack_length: usize,
|
|
18
|
-
needle: *const c_void,
|
|
19
|
-
needle_length: usize,
|
|
20
|
-
) -> *const c_void;
|
|
21
|
-
|
|
22
|
-
fn sz_rfind(
|
|
23
|
-
haystack: *const c_void,
|
|
24
|
-
haystack_length: usize,
|
|
25
|
-
needle: *const c_void,
|
|
26
|
-
needle_length: usize,
|
|
27
|
-
) -> *const c_void;
|
|
28
|
-
|
|
29
|
-
fn sz_find_char_from(
|
|
30
|
-
haystack: *const c_void,
|
|
31
|
-
haystack_length: usize,
|
|
32
|
-
needle: *const c_void,
|
|
33
|
-
needle_length: usize,
|
|
34
|
-
) -> *const c_void;
|
|
35
|
-
|
|
36
|
-
fn sz_rfind_char_from(
|
|
37
|
-
haystack: *const c_void,
|
|
38
|
-
haystack_length: usize,
|
|
39
|
-
needle: *const c_void,
|
|
40
|
-
needle_length: usize,
|
|
41
|
-
) -> *const c_void;
|
|
42
|
-
|
|
43
|
-
fn sz_find_char_not_from(
|
|
44
|
-
haystack: *const c_void,
|
|
45
|
-
haystack_length: usize,
|
|
46
|
-
needle: *const c_void,
|
|
47
|
-
needle_length: usize,
|
|
48
|
-
) -> *const c_void;
|
|
49
|
-
|
|
50
|
-
fn sz_rfind_char_not_from(
|
|
51
|
-
haystack: *const c_void,
|
|
52
|
-
haystack_length: usize,
|
|
53
|
-
needle: *const c_void,
|
|
54
|
-
needle_length: usize,
|
|
55
|
-
) -> *const c_void;
|
|
56
|
-
|
|
57
|
-
fn sz_edit_distance(
|
|
58
|
-
haystack1: *const c_void,
|
|
59
|
-
haystack1_length: usize,
|
|
60
|
-
haystack2: *const c_void,
|
|
61
|
-
haystack2_length: usize,
|
|
62
|
-
bound: usize,
|
|
63
|
-
allocator: *const c_void,
|
|
64
|
-
) -> usize;
|
|
65
|
-
|
|
66
|
-
fn sz_edit_distance_utf8(
|
|
67
|
-
haystack1: *const c_void,
|
|
68
|
-
haystack1_length: usize,
|
|
69
|
-
haystack2: *const c_void,
|
|
70
|
-
haystack2_length: usize,
|
|
71
|
-
bound: usize,
|
|
72
|
-
allocator: *const c_void,
|
|
73
|
-
) -> usize;
|
|
74
|
-
|
|
75
|
-
fn sz_hamming_distance(
|
|
76
|
-
haystack1: *const c_void,
|
|
77
|
-
haystack1_length: usize,
|
|
78
|
-
haystack2: *const c_void,
|
|
79
|
-
haystack2_length: usize,
|
|
80
|
-
bound: usize,
|
|
81
|
-
) -> usize;
|
|
82
|
-
|
|
83
|
-
fn sz_hamming_distance_utf8(
|
|
84
|
-
haystack1: *const c_void,
|
|
85
|
-
haystack1_length: usize,
|
|
86
|
-
haystack2: *const c_void,
|
|
87
|
-
haystack2_length: usize,
|
|
88
|
-
bound: usize,
|
|
89
|
-
) -> usize;
|
|
90
|
-
|
|
91
|
-
fn sz_alignment_score(
|
|
92
|
-
haystack1: *const c_void,
|
|
93
|
-
haystack1_length: usize,
|
|
94
|
-
haystack2: *const c_void,
|
|
95
|
-
haystack2_length: usize,
|
|
96
|
-
matrix: *const c_void,
|
|
97
|
-
gap: i8,
|
|
98
|
-
allocator: *const c_void,
|
|
99
|
-
) -> isize;
|
|
100
|
-
|
|
101
|
-
// type RandomGeneratorT = fn(*mut c_void) -> u64;
|
|
102
|
-
|
|
103
|
-
fn sz_generate(
|
|
104
|
-
alphabet: *const c_void,
|
|
105
|
-
alphabet_size: usize,
|
|
106
|
-
text: *mut c_void,
|
|
107
|
-
length: usize,
|
|
108
|
-
generate: *const c_void,
|
|
109
|
-
generator: *mut c_void,
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/// Locates the first matching substring within `haystack` that equals `needle`.
|
|
114
|
-
/// This function is similar to the `memmem()` function in LibC, but, unlike `strstr()`,
|
|
115
|
-
/// it requires the length of both haystack and needle to be known beforehand.
|
|
116
|
-
///
|
|
117
|
-
/// # Arguments
|
|
118
|
-
///
|
|
119
|
-
/// * `haystack`: The byte slice to search.
|
|
120
|
-
/// * `needle`: The byte slice to find within the haystack.
|
|
121
|
-
///
|
|
122
|
-
/// # Returns
|
|
123
|
-
///
|
|
124
|
-
/// An `Option<usize>` representing the starting index of the first occurrence of `needle`
|
|
125
|
-
/// within `haystack` if found, otherwise `None`.
|
|
126
|
-
pub fn find<H, N>(haystack: H, needle: N) -> Option<usize>
|
|
127
|
-
where
|
|
128
|
-
H: AsRef<[u8]>,
|
|
129
|
-
N: AsRef<[u8]>,
|
|
130
|
-
{
|
|
131
|
-
let haystack_ref = haystack.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_find(
|
|
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
|
-
/// Locates the last matching substring within `haystack` that equals `needle`.
|
|
154
|
-
/// This function is useful for finding the most recent or last occurrence of a pattern
|
|
155
|
-
/// within a byte slice.
|
|
156
|
-
///
|
|
157
|
-
/// # Arguments
|
|
158
|
-
///
|
|
159
|
-
/// * `haystack`: The byte slice to search.
|
|
160
|
-
/// * `needle`: The byte slice to find within the haystack.
|
|
161
|
-
///
|
|
162
|
-
/// # Returns
|
|
163
|
-
///
|
|
164
|
-
/// An `Option<usize>` representing the starting index of the last occurrence of `needle`
|
|
165
|
-
/// within `haystack` if found, otherwise `None`.
|
|
166
|
-
pub fn rfind<H, N>(haystack: H, needle: N) -> Option<usize>
|
|
167
|
-
where
|
|
168
|
-
H: AsRef<[u8]>,
|
|
169
|
-
N: AsRef<[u8]>,
|
|
170
|
-
{
|
|
171
|
-
let haystack_ref = haystack.as_ref();
|
|
172
|
-
let needle_ref = needle.as_ref();
|
|
173
|
-
let haystack_pointer = haystack_ref.as_ptr() as _;
|
|
174
|
-
let haystack_length = haystack_ref.len();
|
|
175
|
-
let needle_pointer = needle_ref.as_ptr() as _;
|
|
176
|
-
let needle_length = needle_ref.len();
|
|
177
|
-
let result = unsafe {
|
|
178
|
-
sz_rfind(
|
|
179
|
-
haystack_pointer,
|
|
180
|
-
haystack_length,
|
|
181
|
-
needle_pointer,
|
|
182
|
-
needle_length,
|
|
183
|
-
)
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
if result.is_null() {
|
|
187
|
-
None
|
|
188
|
-
} else {
|
|
189
|
-
Some(unsafe { result.offset_from(haystack_pointer) } as usize)
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/// Finds the index of the first character in `haystack` that is also present in `needles`.
|
|
194
|
-
/// This function is particularly useful for parsing and tokenization tasks where a set of
|
|
195
|
-
/// delimiter characters is used.
|
|
196
|
-
///
|
|
197
|
-
/// # Arguments
|
|
198
|
-
///
|
|
199
|
-
/// * `haystack`: The byte slice to search.
|
|
200
|
-
/// * `needles`: The set of bytes to search for within the haystack.
|
|
201
|
-
///
|
|
202
|
-
/// # Returns
|
|
203
|
-
///
|
|
204
|
-
/// An `Option<usize>` representing the index of the first occurrence of any byte from
|
|
205
|
-
/// `needles` within `haystack`, if found, otherwise `None`.
|
|
206
|
-
pub fn find_char_from<H, N>(haystack: H, needles: N) -> Option<usize>
|
|
207
|
-
where
|
|
208
|
-
H: AsRef<[u8]>,
|
|
209
|
-
N: AsRef<[u8]>,
|
|
210
|
-
{
|
|
211
|
-
let haystack_ref = haystack.as_ref();
|
|
212
|
-
let needles_ref = needles.as_ref();
|
|
213
|
-
let haystack_pointer = haystack_ref.as_ptr() as _;
|
|
214
|
-
let haystack_length = haystack_ref.len();
|
|
215
|
-
let needles_pointer = needles_ref.as_ptr() as _;
|
|
216
|
-
let needles_length = needles_ref.len();
|
|
217
|
-
let result = unsafe {
|
|
218
|
-
sz_find_char_from(
|
|
219
|
-
haystack_pointer,
|
|
220
|
-
haystack_length,
|
|
221
|
-
needles_pointer,
|
|
222
|
-
needles_length,
|
|
223
|
-
)
|
|
224
|
-
};
|
|
225
|
-
if result.is_null() {
|
|
226
|
-
None
|
|
227
|
-
} else {
|
|
228
|
-
Some(unsafe { result.offset_from(haystack_pointer) } as usize)
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/// Finds the index of the last character in `haystack` that is also present in `needles`.
|
|
233
|
-
/// This can be used to find the last occurrence of any character from a specified set,
|
|
234
|
-
/// useful in parsing scenarios such as finding the last delimiter in a string.
|
|
235
|
-
///
|
|
236
|
-
/// # Arguments
|
|
237
|
-
///
|
|
238
|
-
/// * `haystack`: The byte slice to search.
|
|
239
|
-
/// * `needles`: The set of bytes to search for within the haystack.
|
|
240
|
-
///
|
|
241
|
-
/// # Returns
|
|
242
|
-
///
|
|
243
|
-
/// An `Option<usize>` representing the index of the last occurrence of any byte from
|
|
244
|
-
/// `needles` within `haystack`, if found, otherwise `None`.
|
|
245
|
-
pub fn rfind_char_from<H, N>(haystack: H, needles: N) -> Option<usize>
|
|
246
|
-
where
|
|
247
|
-
H: AsRef<[u8]>,
|
|
248
|
-
N: AsRef<[u8]>,
|
|
249
|
-
{
|
|
250
|
-
let haystack_ref = haystack.as_ref();
|
|
251
|
-
let needles_ref = needles.as_ref();
|
|
252
|
-
let haystack_pointer = haystack_ref.as_ptr() as _;
|
|
253
|
-
let haystack_length = haystack_ref.len();
|
|
254
|
-
let needles_pointer = needles_ref.as_ptr() as _;
|
|
255
|
-
let needles_length = needles_ref.len();
|
|
256
|
-
let result = unsafe {
|
|
257
|
-
sz_rfind_char_from(
|
|
258
|
-
haystack_pointer,
|
|
259
|
-
haystack_length,
|
|
260
|
-
needles_pointer,
|
|
261
|
-
needles_length,
|
|
262
|
-
)
|
|
263
|
-
};
|
|
264
|
-
if result.is_null() {
|
|
265
|
-
None
|
|
266
|
-
} else {
|
|
267
|
-
Some(unsafe { result.offset_from(haystack_pointer) } as usize)
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/// Finds the index of the first character in `haystack` that is not present in `needles`.
|
|
272
|
-
/// This function is useful for skipping over a known set of characters and finding the
|
|
273
|
-
/// first character that does not belong to that set.
|
|
274
|
-
///
|
|
275
|
-
/// # Arguments
|
|
276
|
-
///
|
|
277
|
-
/// * `haystack`: The byte slice to search.
|
|
278
|
-
/// * `needles`: The set of bytes that should not be matched within the haystack.
|
|
279
|
-
///
|
|
280
|
-
/// # Returns
|
|
281
|
-
///
|
|
282
|
-
/// An `Option<usize>` representing the index of the first occurrence of any byte not in
|
|
283
|
-
/// `needles` within `haystack`, if found, otherwise `None`.
|
|
284
|
-
pub fn find_char_not_from<H, N>(haystack: H, needles: N) -> Option<usize>
|
|
285
|
-
where
|
|
286
|
-
H: AsRef<[u8]>,
|
|
287
|
-
N: AsRef<[u8]>,
|
|
288
|
-
{
|
|
289
|
-
let haystack_ref = haystack.as_ref();
|
|
290
|
-
let needles_ref = needles.as_ref();
|
|
291
|
-
let haystack_pointer = haystack_ref.as_ptr() as _;
|
|
292
|
-
let haystack_length = haystack_ref.len();
|
|
293
|
-
let needles_pointer = needles_ref.as_ptr() as _;
|
|
294
|
-
let needles_length = needles_ref.len();
|
|
295
|
-
let result = unsafe {
|
|
296
|
-
sz_find_char_not_from(
|
|
297
|
-
haystack_pointer,
|
|
298
|
-
haystack_length,
|
|
299
|
-
needles_pointer,
|
|
300
|
-
needles_length,
|
|
301
|
-
)
|
|
302
|
-
};
|
|
303
|
-
if result.is_null() {
|
|
304
|
-
None
|
|
305
|
-
} else {
|
|
306
|
-
Some(unsafe { result.offset_from(haystack_pointer) } as usize)
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/// Finds the index of the last character in `haystack` that is not present in `needles`.
|
|
311
|
-
/// Useful for text processing tasks such as trimming trailing characters that belong to
|
|
312
|
-
/// a specified set.
|
|
313
|
-
///
|
|
314
|
-
/// # Arguments
|
|
315
|
-
///
|
|
316
|
-
/// * `haystack`: The byte slice to search.
|
|
317
|
-
/// * `needles`: The set of bytes that should not be matched within the haystack.
|
|
318
|
-
///
|
|
319
|
-
/// # Returns
|
|
320
|
-
///
|
|
321
|
-
/// An `Option<usize>` representing the index of the last occurrence of any byte not in
|
|
322
|
-
/// `needles` within `haystack`, if found, otherwise `None`.
|
|
323
|
-
pub fn rfind_char_not_from<H, N>(haystack: H, needles: N) -> Option<usize>
|
|
324
|
-
where
|
|
325
|
-
H: AsRef<[u8]>,
|
|
326
|
-
N: AsRef<[u8]>,
|
|
327
|
-
{
|
|
328
|
-
let haystack_ref = haystack.as_ref();
|
|
329
|
-
let needles_ref = needles.as_ref();
|
|
330
|
-
let haystack_pointer = haystack_ref.as_ptr() as _;
|
|
331
|
-
let haystack_length = haystack_ref.len();
|
|
332
|
-
let needles_pointer = needles_ref.as_ptr() as _;
|
|
333
|
-
let needles_length = needles_ref.len();
|
|
334
|
-
let result = unsafe {
|
|
335
|
-
sz_rfind_char_not_from(
|
|
336
|
-
haystack_pointer,
|
|
337
|
-
haystack_length,
|
|
338
|
-
needles_pointer,
|
|
339
|
-
needles_length,
|
|
340
|
-
)
|
|
341
|
-
};
|
|
342
|
-
if result.is_null() {
|
|
343
|
-
None
|
|
344
|
-
} else {
|
|
345
|
-
Some(unsafe { result.offset_from(haystack_pointer) } as usize)
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/// Computes the Levenshtein edit distance between two strings, using the Wagner-Fisher
|
|
350
|
-
/// algorithm. This measure is widely used in applications like spell-checking, DNA sequence
|
|
351
|
-
/// analysis.
|
|
352
|
-
///
|
|
353
|
-
/// # Arguments
|
|
354
|
-
///
|
|
355
|
-
/// * `first`: The first byte slice.
|
|
356
|
-
/// * `second`: The second byte slice.
|
|
357
|
-
/// * `bound`: The maximum distance to compute, allowing for early exit.
|
|
358
|
-
///
|
|
359
|
-
/// # Returns
|
|
360
|
-
///
|
|
361
|
-
/// A `usize` representing the minimum number of single-character edits (insertions,
|
|
362
|
-
/// deletions, or substitutions) required to change `first` into `second`.
|
|
363
|
-
pub fn edit_distance_bounded<F, S>(first: F, second: S, bound: usize) -> usize
|
|
364
|
-
where
|
|
365
|
-
F: AsRef<[u8]>,
|
|
366
|
-
S: AsRef<[u8]>,
|
|
367
|
-
{
|
|
368
|
-
let first_ref = first.as_ref();
|
|
369
|
-
let second_ref = second.as_ref();
|
|
370
|
-
let first_length = first_ref.len();
|
|
371
|
-
let second_length = second_ref.len();
|
|
372
|
-
let first_pointer = first_ref.as_ptr() as _;
|
|
373
|
-
let second_pointer = second_ref.as_ptr() as _;
|
|
374
|
-
unsafe {
|
|
375
|
-
sz_edit_distance(
|
|
376
|
-
first_pointer,
|
|
377
|
-
first_length,
|
|
378
|
-
second_pointer,
|
|
379
|
-
second_length,
|
|
380
|
-
// Upper bound on the distance, that allows us to exit early. If zero is
|
|
381
|
-
// passed, the maximum possible distance will be equal to the length of
|
|
382
|
-
// the longer input.
|
|
383
|
-
bound,
|
|
384
|
-
// Uses the default allocator
|
|
385
|
-
core::ptr::null(),
|
|
386
|
-
)
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/// Computes the Levenshtein edit distance between two UTF8 strings, using the Wagner-Fisher
|
|
391
|
-
/// algorithm. This measure is widely used in applications like spell-checking.
|
|
392
|
-
///
|
|
393
|
-
/// # Arguments
|
|
394
|
-
///
|
|
395
|
-
/// * `first`: The first byte slice.
|
|
396
|
-
/// * `second`: The second byte slice.
|
|
397
|
-
/// * `bound`: The maximum distance to compute, allowing for early exit.
|
|
398
|
-
///
|
|
399
|
-
/// # Returns
|
|
400
|
-
///
|
|
401
|
-
/// A `usize` representing the minimum number of single-character edits (insertions,
|
|
402
|
-
/// deletions, or substitutions) required to change `first` into `second`.
|
|
403
|
-
pub fn edit_distance_utf8_bounded<F, S>(first: F, second: S, bound: usize) -> usize
|
|
404
|
-
where
|
|
405
|
-
F: AsRef<[u8]>,
|
|
406
|
-
S: AsRef<[u8]>,
|
|
407
|
-
{
|
|
408
|
-
let first_ref = first.as_ref();
|
|
409
|
-
let second_ref = second.as_ref();
|
|
410
|
-
let first_length = first_ref.len();
|
|
411
|
-
let second_length = second_ref.len();
|
|
412
|
-
let first_pointer = first_ref.as_ptr() as _;
|
|
413
|
-
let second_pointer = second_ref.as_ptr() as _;
|
|
414
|
-
unsafe {
|
|
415
|
-
sz_edit_distance_utf8(
|
|
416
|
-
first_pointer,
|
|
417
|
-
first_length,
|
|
418
|
-
second_pointer,
|
|
419
|
-
second_length,
|
|
420
|
-
// Upper bound on the distance, that allows us to exit early. If zero is
|
|
421
|
-
// passed, the maximum possible distance will be equal to the length of
|
|
422
|
-
// the longer input.
|
|
423
|
-
bound,
|
|
424
|
-
// Uses the default allocator
|
|
425
|
-
core::ptr::null(),
|
|
426
|
-
)
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/// Computes the Levenshtein edit distance between two strings, using the Wagner-Fisher
|
|
431
|
-
/// algorithm. This measure is widely used in applications like spell-checking, DNA sequence
|
|
432
|
-
/// analysis.
|
|
433
|
-
///
|
|
434
|
-
/// # Arguments
|
|
435
|
-
///
|
|
436
|
-
/// * `first`: The first byte slice.
|
|
437
|
-
/// * `second`: The second byte slice.
|
|
438
|
-
///
|
|
439
|
-
/// # Returns
|
|
440
|
-
///
|
|
441
|
-
/// A `usize` representing the minimum number of single-character edits (insertions,
|
|
442
|
-
/// deletions, or substitutions) required to change `first` into `second`.
|
|
443
|
-
pub fn edit_distance<F, S>(first: F, second: S) -> usize
|
|
444
|
-
where
|
|
445
|
-
F: AsRef<[u8]>,
|
|
446
|
-
S: AsRef<[u8]>,
|
|
447
|
-
{
|
|
448
|
-
edit_distance_bounded(first, second, 0)
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
/// Computes the Levenshtein edit distance between two UTF8 strings, using the Wagner-Fisher
|
|
452
|
-
/// algorithm. This measure is widely used in applications like spell-checking.
|
|
453
|
-
///
|
|
454
|
-
/// # Arguments
|
|
455
|
-
///
|
|
456
|
-
/// * `first`: The first byte slice.
|
|
457
|
-
/// * `second`: The second byte slice.
|
|
458
|
-
///
|
|
459
|
-
/// # Returns
|
|
460
|
-
///
|
|
461
|
-
/// A `usize` representing the minimum number of single-character edits (insertions,
|
|
462
|
-
/// deletions, or substitutions) required to change `first` into `second`.
|
|
463
|
-
pub fn edit_distance_utf8<F, S>(first: F, second: S) -> usize
|
|
464
|
-
where
|
|
465
|
-
F: AsRef<[u8]>,
|
|
466
|
-
S: AsRef<[u8]>,
|
|
467
|
-
{
|
|
468
|
-
edit_distance_utf8_bounded(first, second, 0)
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/// Computes the Hamming edit distance between two strings, counting the number of substituted characters.
|
|
472
|
-
/// Difference in length is added to the result as well.
|
|
473
|
-
///
|
|
474
|
-
/// # Arguments
|
|
475
|
-
///
|
|
476
|
-
/// * `first`: The first byte slice.
|
|
477
|
-
/// * `second`: The second byte slice.
|
|
478
|
-
/// * `bound`: The maximum distance to compute, allowing for early exit.
|
|
479
|
-
///
|
|
480
|
-
/// # Returns
|
|
481
|
-
///
|
|
482
|
-
/// A `usize` representing the minimum number of single-character edits (substitutions) required to
|
|
483
|
-
/// change `first` into `second`.
|
|
484
|
-
pub fn hamming_distance_bounded<F, S>(first: F, second: S, bound: usize) -> usize
|
|
485
|
-
where
|
|
486
|
-
F: AsRef<[u8]>,
|
|
487
|
-
S: AsRef<[u8]>,
|
|
488
|
-
{
|
|
489
|
-
let first_ref = first.as_ref();
|
|
490
|
-
let second_ref = second.as_ref();
|
|
491
|
-
let first_length = first_ref.len();
|
|
492
|
-
let second_length = second_ref.len();
|
|
493
|
-
let first_pointer = first_ref.as_ptr() as _;
|
|
494
|
-
let second_pointer = second_ref.as_ptr() as _;
|
|
495
|
-
unsafe {
|
|
496
|
-
sz_hamming_distance(
|
|
497
|
-
first_pointer,
|
|
498
|
-
first_length,
|
|
499
|
-
second_pointer,
|
|
500
|
-
second_length,
|
|
501
|
-
// Upper bound on the distance, that allows us to exit early. If zero is
|
|
502
|
-
// passed, the maximum possible distance will be equal to the length of
|
|
503
|
-
// the longer input.
|
|
504
|
-
bound,
|
|
505
|
-
)
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
/// Computes the Hamming edit distance between two UTF8 strings, counting the number of substituted
|
|
510
|
-
/// variable-length characters. Difference in length is added to the result as well.
|
|
511
|
-
///
|
|
512
|
-
/// # Arguments
|
|
513
|
-
///
|
|
514
|
-
/// * `first`: The first byte slice.
|
|
515
|
-
/// * `second`: The second byte slice.
|
|
516
|
-
/// * `bound`: The maximum distance to compute, allowing for early exit.
|
|
517
|
-
///
|
|
518
|
-
/// # Returns
|
|
519
|
-
///
|
|
520
|
-
/// A `usize` representing the minimum number of single-character edits (substitutions) required to
|
|
521
|
-
/// change `first` into `second`.
|
|
522
|
-
pub fn hamming_distance_utf8_bounded<F, S>(first: F, second: S, bound: usize) -> usize
|
|
523
|
-
where
|
|
524
|
-
F: AsRef<[u8]>,
|
|
525
|
-
S: AsRef<[u8]>,
|
|
526
|
-
{
|
|
527
|
-
let first_ref = first.as_ref();
|
|
528
|
-
let second_ref = second.as_ref();
|
|
529
|
-
let first_length = first_ref.len();
|
|
530
|
-
let second_length = second_ref.len();
|
|
531
|
-
let first_pointer = first_ref.as_ptr() as _;
|
|
532
|
-
let second_pointer = second_ref.as_ptr() as _;
|
|
533
|
-
unsafe {
|
|
534
|
-
sz_hamming_distance_utf8(
|
|
535
|
-
first_pointer,
|
|
536
|
-
first_length,
|
|
537
|
-
second_pointer,
|
|
538
|
-
second_length,
|
|
539
|
-
// Upper bound on the distance, that allows us to exit early. If zero is
|
|
540
|
-
// passed, the maximum possible distance will be equal to the length of
|
|
541
|
-
// the longer input.
|
|
542
|
-
bound,
|
|
543
|
-
)
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
/// Computes the Hamming edit distance between two strings, counting the number of substituted characters.
|
|
548
|
-
/// Difference in length is added to the result as well.
|
|
549
|
-
///
|
|
550
|
-
/// # Arguments
|
|
551
|
-
///
|
|
552
|
-
/// * `first`: The first byte slice.
|
|
553
|
-
/// * `second`: The second byte slice.
|
|
554
|
-
///
|
|
555
|
-
/// # Returns
|
|
556
|
-
///
|
|
557
|
-
/// A `usize` representing the minimum number of single-character edits (substitutions) required to
|
|
558
|
-
/// change `first` into `second`.
|
|
559
|
-
pub fn hamming_distance<F, S>(first: F, second: S) -> usize
|
|
560
|
-
where
|
|
561
|
-
F: AsRef<[u8]>,
|
|
562
|
-
S: AsRef<[u8]>,
|
|
563
|
-
{
|
|
564
|
-
hamming_distance_bounded(first, second, 0)
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
/// Computes the Hamming edit distance between two UTF8 strings, counting the number of substituted
|
|
568
|
-
/// variable-length characters. Difference in length is added to the result as well.
|
|
569
|
-
///
|
|
570
|
-
/// # Arguments
|
|
571
|
-
///
|
|
572
|
-
/// * `first`: The first byte slice.
|
|
573
|
-
/// * `second`: The second byte slice.
|
|
574
|
-
///
|
|
575
|
-
/// # Returns
|
|
576
|
-
///
|
|
577
|
-
/// A `usize` representing the minimum number of single-character edits (substitutions) required to
|
|
578
|
-
/// change `first` into `second`.
|
|
579
|
-
pub fn hamming_distance_utf8<F, S>(first: F, second: S) -> usize
|
|
580
|
-
where
|
|
581
|
-
F: AsRef<[u8]>,
|
|
582
|
-
S: AsRef<[u8]>,
|
|
583
|
-
{
|
|
584
|
-
hamming_distance_utf8_bounded(first, second, 0)
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
/// Computes the Needleman-Wunsch alignment score for two strings. This function is
|
|
588
|
-
/// particularly used in bioinformatics for sequence alignment but is also applicable in
|
|
589
|
-
/// other domains requiring detailed comparison between two strings, including gap and
|
|
590
|
-
/// substitution penalties.
|
|
591
|
-
///
|
|
592
|
-
/// # Arguments
|
|
593
|
-
///
|
|
594
|
-
/// * `first`: The first byte slice to align.
|
|
595
|
-
/// * `second`: The second byte slice to align.
|
|
596
|
-
/// * `matrix`: The substitution matrix used for scoring.
|
|
597
|
-
/// * `gap`: The penalty for each gap introduced during alignment.
|
|
598
|
-
///
|
|
599
|
-
/// # Returns
|
|
600
|
-
///
|
|
601
|
-
/// An `isize` representing the total alignment score, where higher scores indicate better
|
|
602
|
-
/// alignment between the two strings, considering the specified gap penalties and
|
|
603
|
-
/// substitution matrix.
|
|
604
|
-
pub fn alignment_score<F, S>(first: F, second: S, matrix: [[i8; 256]; 256], gap: i8) -> isize
|
|
605
|
-
where
|
|
606
|
-
F: AsRef<[u8]>,
|
|
607
|
-
S: AsRef<[u8]>,
|
|
608
|
-
{
|
|
609
|
-
let first_ref = first.as_ref();
|
|
610
|
-
let second_ref = second.as_ref();
|
|
611
|
-
let first_length = first_ref.len();
|
|
612
|
-
let second_length = second_ref.len();
|
|
613
|
-
let first_pointer = first_ref.as_ptr() as _;
|
|
614
|
-
let second_pointer = second_ref.as_ptr() as _;
|
|
615
|
-
unsafe {
|
|
616
|
-
sz_alignment_score(
|
|
617
|
-
first_pointer,
|
|
618
|
-
first_length,
|
|
619
|
-
second_pointer,
|
|
620
|
-
second_length,
|
|
621
|
-
matrix.as_ptr() as _,
|
|
622
|
-
gap,
|
|
623
|
-
core::ptr::null(),
|
|
624
|
-
)
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
/// Generates a default substitution matrix for use with the Needleman-Wunsch
|
|
629
|
-
/// alignment algorithm. This matrix is initialized such that diagonal entries
|
|
630
|
-
/// (representing matching characters) are zero, and off-diagonal entries
|
|
631
|
-
/// (representing mismatches) are -1. This setup effectively produces distances
|
|
632
|
-
/// equal to the negative Levenshtein edit distance, suitable for basic sequence
|
|
633
|
-
/// alignment tasks where all mismatches are penalized equally and there are no
|
|
634
|
-
/// rewards for matches.
|
|
635
|
-
///
|
|
636
|
-
/// # Returns
|
|
637
|
-
///
|
|
638
|
-
/// A 256x256 array of `i8`, where each element represents the substitution cost
|
|
639
|
-
/// between two characters (byte values). Matching characters are assigned a cost
|
|
640
|
-
/// of 0, and non-matching characters are assigned a cost of -1.
|
|
641
|
-
pub fn unary_substitution_costs() -> [[i8; 256]; 256] {
|
|
642
|
-
let mut result = [[0; 256]; 256];
|
|
643
|
-
|
|
644
|
-
for i in 0..256 {
|
|
645
|
-
for j in 0..256 {
|
|
646
|
-
result[i][j] = if i == j { 0 } else { -1 };
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
result
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
/// Randomizes the contents of a given byte slice `text` using characters from
|
|
654
|
-
/// a specified `alphabet`. This function mutates `text` in place, replacing each
|
|
655
|
-
/// byte with a random one from `alphabet`. It is designed for situations where
|
|
656
|
-
/// you need to generate random strings or data sequences based on a specific set
|
|
657
|
-
/// of characters, such as generating random DNA sequences or testing inputs.
|
|
658
|
-
///
|
|
659
|
-
/// # Type Parameters
|
|
660
|
-
///
|
|
661
|
-
/// * `T`: The type of the text to be randomized. Must be mutable and convertible to a byte slice.
|
|
662
|
-
/// * `A`: The type of the alphabet. Must be convertible to a byte slice.
|
|
663
|
-
///
|
|
664
|
-
/// # Arguments
|
|
665
|
-
///
|
|
666
|
-
/// * `text`: A mutable reference to the data to randomize. This data will be mutated in place.
|
|
667
|
-
/// * `alphabet`: A reference to the byte slice representing the alphabet to use for randomization.
|
|
668
|
-
///
|
|
669
|
-
/// # Examples
|
|
670
|
-
///
|
|
671
|
-
/// ```
|
|
672
|
-
/// use stringzilla::sz;
|
|
673
|
-
/// let mut my_text = vec![0; 10]; // A buffer to randomize
|
|
674
|
-
/// let alphabet = b"ACTG"; // Using a DNA alphabet
|
|
675
|
-
/// sz::randomize(&mut my_text, &alphabet);
|
|
676
|
-
/// ```
|
|
677
|
-
///
|
|
678
|
-
/// After than, `my_text` is filled with random 'A', 'C', 'T', or 'G' values.
|
|
679
|
-
pub fn randomize<T, A>(text: &mut T, alphabet: &A)
|
|
680
|
-
where
|
|
681
|
-
T: AsMut<[u8]> + ?Sized, // Allows for mutable references to dynamically sized types.
|
|
682
|
-
A: AsRef<[u8]> + ?Sized, // Allows for references to dynamically sized types.
|
|
683
|
-
{
|
|
684
|
-
let text_slice = text.as_mut();
|
|
685
|
-
let alphabet_slice = alphabet.as_ref();
|
|
686
|
-
unsafe {
|
|
687
|
-
sz_generate(
|
|
688
|
-
alphabet_slice.as_ptr() as *const c_void,
|
|
689
|
-
alphabet_slice.len(),
|
|
690
|
-
text_slice.as_mut_ptr() as *mut c_void,
|
|
691
|
-
text_slice.len(),
|
|
692
|
-
core::ptr::null(),
|
|
693
|
-
core::ptr::null_mut(),
|
|
694
|
-
);
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
/// The [StringZilla] trait provides a collection of string searching and manipulation functionalities.
|
|
700
|
-
pub trait StringZilla<N>
|
|
701
|
-
where
|
|
702
|
-
N: AsRef<[u8]>,
|
|
703
|
-
{
|
|
704
|
-
fn sz_find(&self, needle: N) -> Option<usize>;
|
|
705
|
-
fn sz_rfind(&self, needle: N) -> Option<usize>;
|
|
706
|
-
fn sz_find_char_from(&self, needles: N) -> Option<usize>;
|
|
707
|
-
fn sz_rfind_char_from(&self, needles: N) -> Option<usize>;
|
|
708
|
-
fn sz_find_char_not_from(&self, needles: N) -> Option<usize>;
|
|
709
|
-
fn sz_rfind_char_not_from(&self, needles: N) -> Option<usize>;
|
|
710
|
-
fn sz_edit_distance(&self, other: N) -> usize;
|
|
711
|
-
fn sz_alignment_score(&self, other: N, matrix: [[i8; 256]; 256], gap: i8) -> isize;
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
impl<T, N> StringZilla<N> for T
|
|
715
|
-
where
|
|
716
|
-
T: AsRef<[u8]>,
|
|
717
|
-
N: AsRef<[u8]>,
|
|
718
|
-
{
|
|
719
|
-
fn sz_find(&self, needle: N) -> Option<usize> {
|
|
720
|
-
sz::find(self, needle)
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
fn sz_rfind(&self, needle: N) -> Option<usize> {
|
|
724
|
-
sz::rfind(self, needle)
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
fn sz_find_char_from(&self, needles: N) -> Option<usize> {
|
|
728
|
-
sz::find_char_from(self, needles)
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
fn sz_rfind_char_from(&self, needles: N) -> Option<usize> {
|
|
732
|
-
sz::rfind_char_from(self, needles)
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
fn sz_find_char_not_from(&self, needles: N) -> Option<usize> {
|
|
736
|
-
sz::find_char_not_from(self, needles)
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
fn sz_rfind_char_not_from(&self, needles: N) -> Option<usize> {
|
|
740
|
-
sz::rfind_char_not_from(self, needles)
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
fn sz_edit_distance(&self, other: N) -> usize {
|
|
744
|
-
sz::edit_distance(self, other)
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
fn sz_alignment_score(&self, other: N, matrix: [[i8; 256]; 256], gap: i8) -> isize {
|
|
748
|
-
sz::alignment_score(self, other, matrix, gap)
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
/// The [MutableStringZilla] trait provides tools for updating strings.
|
|
753
|
-
trait MutableStringZilla<A>
|
|
754
|
-
where
|
|
755
|
-
A: AsRef<[u8]>,
|
|
756
|
-
{
|
|
757
|
-
/// Generates a random string for a given alphabet.
|
|
758
|
-
/// Replaces the buffer with a random string of the same length.
|
|
759
|
-
fn sz_randomize(&mut self, alphabet: A);
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
impl<T, A> MutableStringZilla<A> for T
|
|
763
|
-
where
|
|
764
|
-
T: AsMut<[u8]>,
|
|
765
|
-
A: AsRef<[u8]>,
|
|
766
|
-
{
|
|
767
|
-
fn sz_randomize(&mut self, alphabet: A) {
|
|
768
|
-
let self_mut = self.as_mut();
|
|
769
|
-
let alphabet_ref = alphabet.as_ref();
|
|
770
|
-
sz::randomize(self_mut, alphabet_ref);
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
#[cfg(test)]
|
|
775
|
-
mod tests {
|
|
776
|
-
use std::borrow::Cow;
|
|
777
|
-
|
|
778
|
-
use crate::sz;
|
|
779
|
-
use crate::MutableStringZilla;
|
|
780
|
-
use crate::StringZilla;
|
|
781
|
-
|
|
782
|
-
#[test]
|
|
783
|
-
fn hamming() {
|
|
784
|
-
assert_eq!(sz::hamming_distance("hello", "hello"), 0);
|
|
785
|
-
assert_eq!(sz::hamming_distance("hello", "hell"), 1);
|
|
786
|
-
assert_eq!(sz::hamming_distance("abc", "adc"), 1);
|
|
787
|
-
|
|
788
|
-
assert_eq!(sz::hamming_distance_bounded("abcdefgh", "ABCDEFGH", 2), 2);
|
|
789
|
-
assert_eq!(sz::hamming_distance_utf8("αβγδ", "αγγδ"), 1);
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
#[test]
|
|
793
|
-
fn levenshtein() {
|
|
794
|
-
assert_eq!(sz::edit_distance("hello", "hell"), 1);
|
|
795
|
-
assert_eq!(sz::edit_distance("hello", "hell"), 1);
|
|
796
|
-
assert_eq!(sz::edit_distance("abc", ""), 3);
|
|
797
|
-
assert_eq!(sz::edit_distance("abc", "ac"), 1);
|
|
798
|
-
assert_eq!(sz::edit_distance("abc", "a_bc"), 1);
|
|
799
|
-
assert_eq!(sz::edit_distance("abc", "adc"), 1);
|
|
800
|
-
assert_eq!(sz::edit_distance("fitting", "kitty"), 4);
|
|
801
|
-
assert_eq!(sz::edit_distance("smitten", "mitten"), 1);
|
|
802
|
-
assert_eq!(sz::edit_distance("ggbuzgjux{}l", "gbuzgjux{}l"), 1);
|
|
803
|
-
assert_eq!(sz::edit_distance("abcdefgABCDEFG", "ABCDEFGabcdefg"), 14);
|
|
804
|
-
|
|
805
|
-
assert_eq!(sz::edit_distance_bounded("fitting", "kitty", 2), 2);
|
|
806
|
-
assert_eq!(sz::edit_distance_utf8("façade", "facade"), 1);
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
#[test]
|
|
810
|
-
fn needleman() {
|
|
811
|
-
let costs_vector = sz::unary_substitution_costs();
|
|
812
|
-
assert_eq!(
|
|
813
|
-
sz::alignment_score("listen", "silent", costs_vector, -1),
|
|
814
|
-
-4
|
|
815
|
-
);
|
|
816
|
-
assert_eq!(
|
|
817
|
-
sz::alignment_score("abcdefgABCDEFG", "ABCDEFGabcdefg", costs_vector, -1),
|
|
818
|
-
-14
|
|
819
|
-
);
|
|
820
|
-
assert_eq!(sz::alignment_score("hello", "hello", costs_vector, -1), 0);
|
|
821
|
-
assert_eq!(sz::alignment_score("hello", "hell", costs_vector, -1), -1);
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
#[test]
|
|
825
|
-
fn search() {
|
|
826
|
-
let my_string: String = String::from("Hello, world!");
|
|
827
|
-
let my_str: &str = my_string.as_str();
|
|
828
|
-
let my_cow_str: Cow<'_, str> = Cow::from(&my_string);
|
|
829
|
-
|
|
830
|
-
// Identical to `memchr::memmem::find` and `memchr::memmem::rfind` functions
|
|
831
|
-
assert_eq!(sz::find("Hello, world!", "world"), Some(7));
|
|
832
|
-
assert_eq!(sz::rfind("Hello, world!", "world"), Some(7));
|
|
833
|
-
|
|
834
|
-
// Use the generic function with a String
|
|
835
|
-
assert_eq!(my_string.sz_find("world"), Some(7));
|
|
836
|
-
assert_eq!(my_string.sz_rfind("world"), Some(7));
|
|
837
|
-
assert_eq!(my_string.sz_find_char_from("world"), Some(2));
|
|
838
|
-
assert_eq!(my_string.sz_rfind_char_from("world"), Some(11));
|
|
839
|
-
assert_eq!(my_string.sz_find_char_not_from("world"), Some(0));
|
|
840
|
-
assert_eq!(my_string.sz_rfind_char_not_from("world"), Some(12));
|
|
841
|
-
|
|
842
|
-
// Use the generic function with a &str
|
|
843
|
-
assert_eq!(my_str.sz_find("world"), Some(7));
|
|
844
|
-
assert_eq!(my_str.sz_find("world"), Some(7));
|
|
845
|
-
assert_eq!(my_str.sz_find_char_from("world"), Some(2));
|
|
846
|
-
assert_eq!(my_str.sz_rfind_char_from("world"), Some(11));
|
|
847
|
-
assert_eq!(my_str.sz_find_char_not_from("world"), Some(0));
|
|
848
|
-
assert_eq!(my_str.sz_rfind_char_not_from("world"), Some(12));
|
|
849
|
-
|
|
850
|
-
// Use the generic function with a Cow<'_, str>
|
|
851
|
-
assert_eq!(my_cow_str.as_ref().sz_find("world"), Some(7));
|
|
852
|
-
assert_eq!(my_cow_str.as_ref().sz_find("world"), Some(7));
|
|
853
|
-
assert_eq!(my_cow_str.as_ref().sz_find_char_from("world"), Some(2));
|
|
854
|
-
assert_eq!(my_cow_str.as_ref().sz_rfind_char_from("world"), Some(11));
|
|
855
|
-
assert_eq!(my_cow_str.as_ref().sz_find_char_not_from("world"), Some(0));
|
|
856
|
-
assert_eq!(
|
|
857
|
-
my_cow_str.as_ref().sz_rfind_char_not_from("world"),
|
|
858
|
-
Some(12)
|
|
859
|
-
);
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
#[test]
|
|
863
|
-
fn randomize() {
|
|
864
|
-
let mut text: Vec<u8> = vec![0; 10]; // A buffer of ten zeros
|
|
865
|
-
let alphabet: &[u8] = b"abcd"; // A byte slice alphabet
|
|
866
|
-
text.sz_randomize(alphabet);
|
|
867
|
-
|
|
868
|
-
// Iterate throught text and check that it only contains letters from the alphabet
|
|
869
|
-
assert!(text
|
|
870
|
-
.iter()
|
|
871
|
-
.all(|&b| b == b'd' || b == b'c' || b == b'b' || b == b'a'));
|
|
872
|
-
}
|
|
873
|
-
}
|