stringzillas-cuda 4.2.2__tar.gz → 4.3.0__tar.gz

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 (51) hide show
  1. {stringzillas_cuda-4.2.2/stringzillas_cuda.egg-info → stringzillas_cuda-4.3.0}/PKG-INFO +13 -6
  2. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/README.md +11 -4
  3. stringzillas_cuda-4.3.0/VERSION +1 -0
  4. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/c/stringzilla.c +84 -11
  5. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/compare.h +2 -2
  6. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/find.h +70 -37
  7. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/hash.h +241 -191
  8. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/intersect.h +2 -2
  9. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/memory.h +7 -6
  10. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/stringzilla.h +4 -2
  11. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/stringzilla.hpp +839 -200
  12. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/types.h +93 -32
  13. stringzillas_cuda-4.3.0/include/stringzilla/utf8.h +1554 -0
  14. stringzillas_cuda-4.3.0/include/stringzilla/utf8_unpack.h +1079 -0
  15. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/python/stringzilla.c +590 -0
  16. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/scripts/test_stringzilla.py +345 -0
  17. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0/stringzillas_cuda.egg-info}/PKG-INFO +13 -6
  18. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/stringzillas_cuda.egg-info/SOURCES.txt +2 -0
  19. stringzillas_cuda-4.3.0/stringzillas_cuda.egg-info/requires.txt +1 -0
  20. stringzillas_cuda-4.2.2/VERSION +0 -1
  21. stringzillas_cuda-4.2.2/stringzillas_cuda.egg-info/requires.txt +0 -1
  22. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/LICENSE +0 -0
  23. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/MANIFEST.in +0 -0
  24. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/SZ_TARGET.env +0 -0
  25. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/build_backend.py +0 -0
  26. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/c/stringzillas.cpp +0 -0
  27. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/c/stringzillas.cu +0 -0
  28. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/c/stringzillas.cuh +0 -0
  29. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/cli/__init__.py +0 -0
  30. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/cli/split.py +0 -0
  31. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/cli/wc.py +0 -0
  32. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/fork_union/include/fork_union.h +0 -0
  33. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/fork_union/include/fork_union.hpp +0 -0
  34. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/module.modulemap +0 -0
  35. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/small_string.h +0 -0
  36. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/sort.h +0 -0
  37. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzilla/types.hpp +0 -0
  38. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzillas/fingerprints.cuh +0 -0
  39. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzillas/fingerprints.hpp +0 -0
  40. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzillas/similarities.cuh +0 -0
  41. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzillas/similarities.hpp +0 -0
  42. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzillas/stringzillas.h +0 -0
  43. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzillas/types.cuh +0 -0
  44. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/include/stringzillas/types.hpp +0 -0
  45. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/pyproject.toml +0 -0
  46. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/python/stringzillas.c +0 -0
  47. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/scripts/test_stringzillas.py +0 -0
  48. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/setup.cfg +0 -0
  49. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/setup.py +0 -0
  50. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/stringzillas_cuda.egg-info/dependency_links.txt +0 -0
  51. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.3.0}/stringzillas_cuda.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stringzillas-cuda
3
- Version: 4.2.2
3
+ Version: 4.3.0
4
4
  Summary: Search, hash, sort, fingerprint, and fuzzy-match strings faster via SWAR, SIMD, and CUDA on Nvidia GPUs
5
5
  Home-page: https://github.com/ashvardanian/StringZilla
6
6
  Author: Ash Vardanian
@@ -30,7 +30,7 @@ Classifier: Topic :: Text Processing :: Indexing
30
30
  Requires-Python: >=3.8
31
31
  Description-Content-Type: text/markdown
32
32
  License-File: LICENSE
33
- Requires-Dist: stringzilla==4.2.2
33
+ Requires-Dist: stringzilla==4.3.0
34
34
  Dynamic: author
35
35
  Dynamic: author-email
36
36
  Dynamic: classifier
@@ -1134,10 +1134,10 @@ Similar to GCC, StringZilla is 32 bytes in size, and similar to Clang it can fit
1134
1134
  Our layout might be preferential, if you want to avoid branches.
1135
1135
  If you use a different compiler, you may want to check its SSO buffer size with a [simple Gist](https://gist.github.com/ashvardanian/c197f15732d9855c4e070797adf17b21).
1136
1136
 
1137
- | | `libstdc++` in GCC 13 | `libc++` in Clang 17 | StringZilla |
1138
- | :-------------------- | ---------------------: | -------------------: | ----------: |
1139
- | `sizeof(std::string)` | 32 | 24 | 32 |
1140
- | Small String Capacity | 15 | __22__ | __22__ |
1137
+ | | `libstdc++` in GCC 13 | `libc++` in Clang 17 | StringZilla |
1138
+ | :-------------- | ---------------------: | -------------------: | ----------: |
1139
+ | String `sizeof` | 32 | 24 | 32 |
1140
+ | Inner Capacity | 15 | __22__ | __22__ |
1141
1141
 
1142
1142
  This design has been since ported to many high-level programming languages.
1143
1143
  Swift, for example, [can store 15 bytes](https://developer.apple.com/documentation/swift/substring/withutf8(_:)#discussion) in the `String` instance itself.
@@ -1530,6 +1530,13 @@ __`SZ_USE_CUDA`, `SZ_USE_KEPLER`, `SZ_USE_HOPPER`__:
1530
1530
  > One can explicitly disable certain families of PTX instructions for compatibility purposes.
1531
1531
  > Default values are inferred at compile time depending on compiler support (for dynamic dispatch) and the target architecture (for static dispatch).
1532
1532
 
1533
+ __`SZ_ENFORCE_SVE_OVER_NEON`__:
1534
+
1535
+ > SVE and SVE2 are expected to supersede NEON on ARM architectures.
1536
+ > Still, oftentimes the equivalent SVE kernels are slower due to equally small register files and higher complexity of the instructions.
1537
+ > By default, when both SVE and NEON are available, SVE is used selectively only for the algorithms that benefit from it.
1538
+ > If you want to enforce SVE usage everywhere, define this flag.
1539
+
1533
1540
  __`SZ_DYNAMIC_DISPATCH`__:
1534
1541
 
1535
1542
  > By default, StringZilla is a header-only library.
@@ -1089,10 +1089,10 @@ Similar to GCC, StringZilla is 32 bytes in size, and similar to Clang it can fit
1089
1089
  Our layout might be preferential, if you want to avoid branches.
1090
1090
  If you use a different compiler, you may want to check its SSO buffer size with a [simple Gist](https://gist.github.com/ashvardanian/c197f15732d9855c4e070797adf17b21).
1091
1091
 
1092
- | | `libstdc++` in GCC 13 | `libc++` in Clang 17 | StringZilla |
1093
- | :-------------------- | ---------------------: | -------------------: | ----------: |
1094
- | `sizeof(std::string)` | 32 | 24 | 32 |
1095
- | Small String Capacity | 15 | __22__ | __22__ |
1092
+ | | `libstdc++` in GCC 13 | `libc++` in Clang 17 | StringZilla |
1093
+ | :-------------- | ---------------------: | -------------------: | ----------: |
1094
+ | String `sizeof` | 32 | 24 | 32 |
1095
+ | Inner Capacity | 15 | __22__ | __22__ |
1096
1096
 
1097
1097
  This design has been since ported to many high-level programming languages.
1098
1098
  Swift, for example, [can store 15 bytes](https://developer.apple.com/documentation/swift/substring/withutf8(_:)#discussion) in the `String` instance itself.
@@ -1485,6 +1485,13 @@ __`SZ_USE_CUDA`, `SZ_USE_KEPLER`, `SZ_USE_HOPPER`__:
1485
1485
  > One can explicitly disable certain families of PTX instructions for compatibility purposes.
1486
1486
  > Default values are inferred at compile time depending on compiler support (for dynamic dispatch) and the target architecture (for static dispatch).
1487
1487
 
1488
+ __`SZ_ENFORCE_SVE_OVER_NEON`__:
1489
+
1490
+ > SVE and SVE2 are expected to supersede NEON on ARM architectures.
1491
+ > Still, oftentimes the equivalent SVE kernels are slower due to equally small register files and higher complexity of the instructions.
1492
+ > By default, when both SVE and NEON are available, SVE is used selectively only for the algorithms that benefit from it.
1493
+ > If you want to enforce SVE usage everywhere, define this flag.
1494
+
1488
1495
  __`SZ_DYNAMIC_DISPATCH`__:
1489
1496
 
1490
1497
  > By default, StringZilla is a header-only library.
@@ -0,0 +1 @@
1
+ 4.3.0
@@ -58,6 +58,13 @@ typedef struct sz_implementations_t {
58
58
  sz_find_byteset_t find_byteset;
59
59
  sz_find_byteset_t rfind_byteset;
60
60
 
61
+ sz_utf8_count_t utf8_count;
62
+ sz_utf8_find_nth_t utf8_find_nth;
63
+ sz_utf8_unpack_chunk_t utf8_unpack_chunk;
64
+ sz_utf8_find_boundary_t utf8_find_newline;
65
+ sz_utf8_find_boundary_t utf8_find_whitespace;
66
+ sz_utf8_case_fold_t utf8_case_fold;
67
+
61
68
  sz_sequence_argsort_t sequence_argsort;
62
69
  sz_sequence_intersect_t sequence_intersect;
63
70
  sz_pgrams_sort_t pgrams_sort;
@@ -99,6 +106,13 @@ static void sz_dispatch_table_update_implementation_(sz_capability_t caps) {
99
106
  impl->find_byteset = sz_find_byteset_serial;
100
107
  impl->rfind_byteset = sz_rfind_byteset_serial;
101
108
 
109
+ impl->utf8_count = sz_utf8_count_serial;
110
+ impl->utf8_find_nth = sz_utf8_find_nth_serial;
111
+ impl->utf8_unpack_chunk = sz_utf8_unpack_chunk_serial;
112
+ impl->utf8_find_newline = sz_utf8_find_newline_serial;
113
+ impl->utf8_find_whitespace = sz_utf8_find_whitespace_serial;
114
+ impl->utf8_case_fold = sz_utf8_case_fold_serial;
115
+
102
116
  impl->sequence_argsort = sz_sequence_argsort_serial;
103
117
  impl->sequence_intersect = sz_sequence_intersect_serial;
104
118
  impl->pgrams_sort = sz_pgrams_sort_serial;
@@ -147,6 +161,13 @@ static void sz_dispatch_table_update_implementation_(sz_capability_t caps) {
147
161
  impl->rfind = sz_rfind_haswell;
148
162
  impl->find_byteset = sz_find_byteset_haswell;
149
163
  impl->rfind_byteset = sz_rfind_byteset_haswell;
164
+
165
+ impl->utf8_count = sz_utf8_count_haswell;
166
+ impl->utf8_find_nth = sz_utf8_find_nth_haswell;
167
+ impl->utf8_unpack_chunk = sz_utf8_unpack_chunk_haswell;
168
+ impl->utf8_find_newline = sz_utf8_find_newline_haswell;
169
+ impl->utf8_find_whitespace = sz_utf8_find_whitespace_haswell;
170
+ impl->utf8_case_fold = sz_utf8_case_fold_haswell;
150
171
  }
151
172
  #endif
152
173
 
@@ -181,6 +202,13 @@ static void sz_dispatch_table_update_implementation_(sz_capability_t caps) {
181
202
  impl->find_byteset = sz_find_byteset_ice;
182
203
  impl->rfind_byteset = sz_rfind_byteset_ice;
183
204
 
205
+ impl->utf8_count = sz_utf8_count_ice;
206
+ impl->utf8_find_nth = sz_utf8_find_nth_ice;
207
+ impl->utf8_unpack_chunk = sz_utf8_unpack_chunk_ice;
208
+ impl->utf8_find_newline = sz_utf8_find_newline_ice;
209
+ impl->utf8_find_whitespace = sz_utf8_find_whitespace_ice;
210
+ impl->utf8_case_fold = sz_utf8_case_fold_ice;
211
+
184
212
  impl->lookup = sz_lookup_ice;
185
213
 
186
214
  impl->bytesum = sz_bytesum_ice;
@@ -215,6 +243,13 @@ static void sz_dispatch_table_update_implementation_(sz_capability_t caps) {
215
243
  impl->rfind_byte = sz_rfind_byte_neon;
216
244
  impl->find_byteset = sz_find_byteset_neon;
217
245
  impl->rfind_byteset = sz_rfind_byteset_neon;
246
+
247
+ impl->utf8_count = sz_utf8_count_neon;
248
+ impl->utf8_find_nth = sz_utf8_find_nth_neon;
249
+ impl->utf8_unpack_chunk = sz_utf8_unpack_chunk_neon;
250
+ impl->utf8_find_newline = sz_utf8_find_newline_neon;
251
+ impl->utf8_find_whitespace = sz_utf8_find_whitespace_neon;
252
+ impl->utf8_case_fold = sz_utf8_case_fold_neon;
218
253
  }
219
254
  #endif
220
255
 
@@ -238,16 +273,19 @@ static void sz_dispatch_table_update_implementation_(sz_capability_t caps) {
238
273
 
239
274
  #if SZ_USE_SVE
240
275
  if (caps & sz_cap_sve_k) {
241
- impl->equal = sz_equal_sve;
242
- impl->order = sz_order_sve;
243
-
244
- impl->copy = sz_copy_sve;
245
- impl->move = sz_move_sve;
246
- impl->fill = sz_fill_sve;
247
- impl->lookup = sz_lookup_sve;
248
-
249
- impl->find = sz_find_sve;
250
- // TODO: impl->rfind = sz_rfind_sve;
276
+ if (SZ_ENFORCE_SVE_OVER_NEON) {
277
+ impl->equal = sz_equal_sve;
278
+ impl->order = sz_order_sve;
279
+
280
+ impl->copy = sz_copy_sve;
281
+ impl->move = sz_move_sve;
282
+ impl->fill = sz_fill_sve;
283
+ impl->lookup = sz_lookup_sve;
284
+
285
+ impl->find = sz_find_sve;
286
+ // TODO: impl->rfind = sz_rfind_sve;
287
+ }
288
+
251
289
  impl->find_byte = sz_find_byte_sve;
252
290
  impl->rfind_byte = sz_rfind_byte_sve;
253
291
 
@@ -260,7 +298,17 @@ static void sz_dispatch_table_update_implementation_(sz_capability_t caps) {
260
298
  #endif
261
299
 
262
300
  #if SZ_USE_SVE2
263
- if (caps & sz_cap_sve2_k) { impl->bytesum = sz_bytesum_sve2; }
301
+ if (caps & sz_cap_sve2_k) {
302
+ impl->bytesum = sz_bytesum_sve2;
303
+
304
+ impl->utf8_count = sz_utf8_count_sve2;
305
+ impl->utf8_find_nth = sz_utf8_find_nth_sve2;
306
+
307
+ if (SZ_ENFORCE_SVE_OVER_NEON) {
308
+ impl->utf8_find_newline = sz_utf8_find_newline_sve2;
309
+ impl->utf8_find_whitespace = sz_utf8_find_whitespace_sve2;
310
+ }
311
+ }
264
312
  #endif
265
313
 
266
314
  #if SZ_USE_SVE2_AES
@@ -434,6 +482,31 @@ SZ_DYNAMIC sz_status_t sz_sequence_intersect(sz_sequence_t const *first_array, s
434
482
  first_positions, second_positions);
435
483
  }
436
484
 
485
+ SZ_DYNAMIC sz_size_t sz_utf8_count(sz_cptr_t text, sz_size_t length) {
486
+ return sz_dispatch_table.utf8_count(text, length);
487
+ }
488
+
489
+ SZ_DYNAMIC sz_cptr_t sz_utf8_find_nth(sz_cptr_t text, sz_size_t length, sz_size_t n) {
490
+ return sz_dispatch_table.utf8_find_nth(text, length, n);
491
+ }
492
+
493
+ SZ_DYNAMIC sz_cptr_t sz_utf8_unpack_chunk(sz_cptr_t text, sz_size_t length, sz_rune_t *runes, sz_size_t runes_capacity,
494
+ sz_size_t *runes_unpacked) {
495
+ return sz_dispatch_table.utf8_unpack_chunk(text, length, runes, runes_capacity, runes_unpacked);
496
+ }
497
+
498
+ SZ_DYNAMIC sz_cptr_t sz_utf8_find_newline(sz_cptr_t text, sz_size_t length, sz_size_t *matched_length) {
499
+ return sz_dispatch_table.utf8_find_newline(text, length, matched_length);
500
+ }
501
+
502
+ SZ_DYNAMIC sz_cptr_t sz_utf8_find_whitespace(sz_cptr_t text, sz_size_t length, sz_size_t *matched_length) {
503
+ return sz_dispatch_table.utf8_find_whitespace(text, length, matched_length);
504
+ }
505
+
506
+ SZ_DYNAMIC sz_size_t sz_utf8_case_fold(sz_cptr_t source, sz_size_t source_length, sz_ptr_t destination) {
507
+ return sz_dispatch_table.utf8_case_fold(source, source_length, destination);
508
+ }
509
+
437
510
  // Provide overrides for the libc mem* functions
438
511
  #if SZ_OVERRIDE_LIBC && !defined(__CYGWIN__)
439
512
 
@@ -526,7 +526,7 @@ SZ_DYNAMIC sz_bool_t sz_equal(sz_cptr_t a, sz_cptr_t b, sz_size_t length) {
526
526
  return sz_equal_skylake(a, b, length);
527
527
  #elif SZ_USE_HASWELL
528
528
  return sz_equal_haswell(a, b, length);
529
- #elif SZ_USE_SVE
529
+ #elif SZ_USE_SVE && SZ_ENFORCE_SVE_OVER_NEON
530
530
  return sz_equal_sve(a, b, length);
531
531
  #elif SZ_USE_NEON
532
532
  return sz_equal_neon(a, b, length);
@@ -540,7 +540,7 @@ SZ_DYNAMIC sz_ordering_t sz_order(sz_cptr_t a, sz_size_t a_length, sz_cptr_t b,
540
540
  return sz_order_skylake(a, a_length, b, b_length);
541
541
  #elif SZ_USE_HASWELL
542
542
  return sz_order_haswell(a, a_length, b, b_length);
543
- #elif SZ_USE_SVE
543
+ #elif SZ_USE_SVE && SZ_ENFORCE_SVE_OVER_NEON
544
544
  return sz_order_sve(a, a_length, b, b_length);
545
545
  #elif SZ_USE_NEON
546
546
  return sz_order_neon(a, a_length, b, b_length);
@@ -205,6 +205,41 @@ SZ_PUBLIC sz_cptr_t sz_find_byteset_neon(sz_cptr_t haystack, sz_size_t length, s
205
205
  SZ_PUBLIC sz_cptr_t sz_rfind_byteset_neon(sz_cptr_t haystack, sz_size_t length, sz_byteset_t const *set);
206
206
  #endif
207
207
 
208
+ /**
209
+ * @brief Finds the first occurence of a UTF-8 whitespace or punctuation character in a string.
210
+ *
211
+ * Delimiters include all of the above, plus common "punctuation" characters, "symbols", and "separators",
212
+ * as defined by the "Unicode UAX #29" word segmentation standard and implemented in the ICU.
213
+ * - around 30 ASCII characters
214
+ * - around 130 2-byte characters
215
+ * - around 4.3k 3-byte characters
216
+ * - around 4.1k 4-byte characters
217
+ *
218
+ * @param[in] text String to be scanned.
219
+ * @param[in] length Number of bytes in the string.
220
+ * @param[out] matched_length Number of bytes in the matched newline delimiter.
221
+ * @return Pointer to the first matching newline character from @p text.
222
+ */
223
+ SZ_DYNAMIC sz_cptr_t sz_find_delimiter_utf8(sz_cptr_t text, sz_size_t length, sz_size_t *matched_length);
224
+
225
+ /** @copydoc sz_find_delimiters_utf8 */
226
+ SZ_PUBLIC sz_cptr_t sz_find_delimiters_utf8_serial(sz_cptr_t text, sz_size_t length, sz_size_t *matched_length);
227
+
228
+ #if SZ_USE_HASWELL
229
+ /** @copydoc sz_find_delimiters_utf8 */
230
+ SZ_PUBLIC sz_cptr_t sz_find_delimiters_utf8_haswell(sz_cptr_t text, sz_size_t length, sz_size_t *matched_length);
231
+ #endif
232
+
233
+ #if SZ_USE_ICE
234
+ /** @copydoc sz_find_delimiters_utf8 */
235
+ SZ_PUBLIC sz_cptr_t sz_find_delimiters_utf8_ice(sz_cptr_t text, sz_size_t length, sz_size_t *matched_length);
236
+ #endif
237
+
238
+ #if SZ_USE_NEON
239
+ /** @copydoc sz_find_delimiters_utf8 */
240
+ SZ_PUBLIC sz_cptr_t sz_find_delimiters_utf8_neon(sz_cptr_t text, sz_size_t length, sz_size_t *matched_length);
241
+ #endif
242
+
208
243
  #pragma endregion // Core API
209
244
 
210
245
  #pragma region Helper Shortcuts
@@ -905,7 +940,7 @@ SZ_PUBLIC sz_cptr_t sz_find_westmere(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
905
940
  sz_locate_needle_anomalies_(n, n_length, &offset_first, &offset_mid, &offset_last);
906
941
 
907
942
  // Broadcast those characters into XMM registers.
908
- int matches;
943
+ sz_u32_vec_t matches_vec;
909
944
  sz_u128_vec_t h_first_vec, h_mid_vec, h_last_vec, n_first_vec, n_mid_vec, n_last_vec;
910
945
  n_first_vec.xmm = _mm_set1_epi8(n[offset_first]);
911
946
  n_mid_vec.xmm = _mm_set1_epi8(n[offset_mid]);
@@ -916,14 +951,14 @@ SZ_PUBLIC sz_cptr_t sz_find_westmere(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
916
951
  h_first_vec.xmm = _mm_lddqu_si128((__m128i const *)(h + offset_first));
917
952
  h_mid_vec.xmm = _mm_lddqu_si128((__m128i const *)(h + offset_mid));
918
953
  h_last_vec.xmm = _mm_lddqu_si128((__m128i const *)(h + offset_last));
919
- matches = //
954
+ matches_vec.i32 = //
920
955
  _mm_movemask_epi8(_mm_cmpeq_epi8(h_first_vec.xmm, n_first_vec.xmm)) &
921
956
  _mm_movemask_epi8(_mm_cmpeq_epi8(h_mid_vec.xmm, n_mid_vec.xmm)) &
922
957
  _mm_movemask_epi8(_mm_cmpeq_epi8(h_last_vec.xmm, n_last_vec.xmm));
923
- while (matches) {
924
- int potential_offset = sz_u32_ctz(matches);
958
+ while (matches_vec.u32) {
959
+ int potential_offset = sz_u32_ctz(matches_vec.u32);
925
960
  if (sz_equal_westmere(h + potential_offset, n, n_length)) return h + potential_offset;
926
- matches &= matches - 1;
961
+ matches_vec.u32 &= matches_vec.u32 - 1;
927
962
  }
928
963
  }
929
964
 
@@ -940,7 +975,7 @@ SZ_PUBLIC sz_cptr_t sz_rfind_westmere(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
940
975
  sz_locate_needle_anomalies_(n, n_length, &offset_first, &offset_mid, &offset_last);
941
976
 
942
977
  // Broadcast those characters into XMM registers.
943
- int matches;
978
+ sz_u32_vec_t matches_vec;
944
979
  sz_u128_vec_t h_first_vec, h_mid_vec, h_last_vec, n_first_vec, n_mid_vec, n_last_vec;
945
980
  n_first_vec.xmm = _mm_set1_epi8(n[offset_first]);
946
981
  n_mid_vec.xmm = _mm_set1_epi8(n[offset_mid]);
@@ -953,15 +988,15 @@ SZ_PUBLIC sz_cptr_t sz_rfind_westmere(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
953
988
  h_first_vec.xmm = _mm_lddqu_si128((__m128i const *)(h_reversed + offset_first));
954
989
  h_mid_vec.xmm = _mm_lddqu_si128((__m128i const *)(h_reversed + offset_mid));
955
990
  h_last_vec.xmm = _mm_lddqu_si128((__m128i const *)(h_reversed + offset_last));
956
- matches = //
991
+ matches_vec.i32 = //
957
992
  _mm_movemask_epi8(_mm_cmpeq_epi8(h_first_vec.xmm, n_first_vec.xmm)) &
958
993
  _mm_movemask_epi8(_mm_cmpeq_epi8(h_mid_vec.xmm, n_mid_vec.xmm)) &
959
994
  _mm_movemask_epi8(_mm_cmpeq_epi8(h_last_vec.xmm, n_last_vec.xmm));
960
- while (matches) {
961
- int potential_offset = sz_u32_clz(matches) - 16;
995
+ while (matches_vec.u32) {
996
+ int potential_offset = sz_u32_clz(matches_vec.u32) - 16;
962
997
  if (sz_equal_westmere(h + h_length - n_length - potential_offset, n, n_length))
963
998
  return h + h_length - n_length - potential_offset;
964
- matches &= ~(1 << (15 - potential_offset));
999
+ matches_vec.u32 &= ~(1u << (15 - potential_offset));
965
1000
  }
966
1001
  }
967
1002
 
@@ -1029,7 +1064,7 @@ SZ_PUBLIC sz_cptr_t sz_find_haswell(sz_cptr_t h, sz_size_t h_length, sz_cptr_t n
1029
1064
  sz_locate_needle_anomalies_(n, n_length, &offset_first, &offset_mid, &offset_last);
1030
1065
 
1031
1066
  // Broadcast those characters into YMM registers.
1032
- int matches;
1067
+ sz_u32_vec_t matches_vec;
1033
1068
  sz_u256_vec_t h_first_vec, h_mid_vec, h_last_vec, n_first_vec, n_mid_vec, n_last_vec;
1034
1069
  n_first_vec.ymm = _mm256_set1_epi8(n[offset_first]);
1035
1070
  n_mid_vec.ymm = _mm256_set1_epi8(n[offset_mid]);
@@ -1040,14 +1075,14 @@ SZ_PUBLIC sz_cptr_t sz_find_haswell(sz_cptr_t h, sz_size_t h_length, sz_cptr_t n
1040
1075
  h_first_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h + offset_first));
1041
1076
  h_mid_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h + offset_mid));
1042
1077
  h_last_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h + offset_last));
1043
- matches = //
1078
+ matches_vec.i32 = //
1044
1079
  _mm256_movemask_epi8(_mm256_cmpeq_epi8(h_first_vec.ymm, n_first_vec.ymm)) &
1045
1080
  _mm256_movemask_epi8(_mm256_cmpeq_epi8(h_mid_vec.ymm, n_mid_vec.ymm)) &
1046
1081
  _mm256_movemask_epi8(_mm256_cmpeq_epi8(h_last_vec.ymm, n_last_vec.ymm));
1047
- while (matches) {
1048
- int potential_offset = sz_u32_ctz(matches);
1082
+ while (matches_vec.u32) {
1083
+ int potential_offset = sz_u32_ctz(matches_vec.u32);
1049
1084
  if (sz_equal_haswell(h + potential_offset, n, n_length)) return h + potential_offset;
1050
- matches &= matches - 1;
1085
+ matches_vec.u32 &= matches_vec.u32 - 1;
1051
1086
  }
1052
1087
  }
1053
1088
 
@@ -1065,7 +1100,7 @@ SZ_PUBLIC sz_cptr_t sz_rfind_haswell(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
1065
1100
  sz_locate_needle_anomalies_(n, n_length, &offset_first, &offset_mid, &offset_last);
1066
1101
 
1067
1102
  // Broadcast those characters into YMM registers.
1068
- int matches;
1103
+ sz_u32_vec_t matches_vec;
1069
1104
  sz_u256_vec_t h_first_vec, h_mid_vec, h_last_vec, n_first_vec, n_mid_vec, n_last_vec;
1070
1105
  n_first_vec.ymm = _mm256_set1_epi8(n[offset_first]);
1071
1106
  n_mid_vec.ymm = _mm256_set1_epi8(n[offset_mid]);
@@ -1078,15 +1113,15 @@ SZ_PUBLIC sz_cptr_t sz_rfind_haswell(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
1078
1113
  h_first_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h_reversed + offset_first));
1079
1114
  h_mid_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h_reversed + offset_mid));
1080
1115
  h_last_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h_reversed + offset_last));
1081
- matches = //
1116
+ matches_vec.i32 = //
1082
1117
  _mm256_movemask_epi8(_mm256_cmpeq_epi8(h_first_vec.ymm, n_first_vec.ymm)) &
1083
1118
  _mm256_movemask_epi8(_mm256_cmpeq_epi8(h_mid_vec.ymm, n_mid_vec.ymm)) &
1084
1119
  _mm256_movemask_epi8(_mm256_cmpeq_epi8(h_last_vec.ymm, n_last_vec.ymm));
1085
- while (matches) {
1086
- int potential_offset = sz_u32_clz(matches);
1120
+ while (matches_vec.u32) {
1121
+ int potential_offset = sz_u32_clz(matches_vec.u32);
1087
1122
  if (sz_equal_haswell(h + h_length - n_length - potential_offset, n, n_length))
1088
1123
  return h + h_length - n_length - potential_offset;
1089
- matches &= ~(1 << (31 - potential_offset));
1124
+ matches_vec.u32 &= ~(1u << (31 - potential_offset));
1090
1125
  }
1091
1126
  }
1092
1127
 
@@ -1388,9 +1423,8 @@ SZ_PUBLIC sz_cptr_t sz_rfind_skylake(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
1388
1423
  int potential_offset = sz_u64_clz(matches);
1389
1424
  if (n_length <= 3 || sz_equal_skylake(h + h_length - n_length - potential_offset, n, n_length))
1390
1425
  return h + h_length - n_length - potential_offset;
1391
- sz_assert_((matches & ((sz_u64_t)1 << (63 - potential_offset))) != 0 &&
1392
- "The bit must be set before we squash it");
1393
- matches &= ~((sz_u64_t)1 << (63 - potential_offset));
1426
+ sz_assert_((matches & (1ull << (63 - potential_offset))) != 0 && "The bit must be set before we squash it");
1427
+ matches &= ~(1ull << (63 - potential_offset));
1394
1428
  }
1395
1429
  }
1396
1430
 
@@ -1409,9 +1443,8 @@ SZ_PUBLIC sz_cptr_t sz_rfind_skylake(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
1409
1443
  int potential_offset = sz_u64_clz(matches);
1410
1444
  if (n_length <= 3 || sz_equal_skylake(h + 64 - potential_offset - 1, n, n_length))
1411
1445
  return h + 64 - potential_offset - 1;
1412
- sz_assert_((matches & ((sz_u64_t)1 << (63 - potential_offset))) != 0 &&
1413
- "The bit must be set before we squash it");
1414
- matches &= ~((sz_u64_t)1 << (63 - potential_offset));
1446
+ sz_assert_((matches & (1ull << (63 - potential_offset))) != 0 && "The bit must be set before we squash it");
1447
+ matches &= ~(1ull << (63 - potential_offset));
1415
1448
  }
1416
1449
  }
1417
1450
 
@@ -1584,7 +1617,7 @@ SZ_PUBLIC sz_cptr_t sz_rfind_byteset_ice(sz_cptr_t text, sz_size_t length, sz_by
1584
1617
  #pragma GCC target("+simd")
1585
1618
  #endif
1586
1619
 
1587
- SZ_INTERNAL sz_u64_t sz_vreinterpretq_u8_u4_(uint8x16_t vec) {
1620
+ SZ_INTERNAL sz_u64_t sz_find_vreinterpretq_u8_u4_(uint8x16_t vec) {
1588
1621
  // Use `vshrn` to produce a bitmask, similar to `movemask` in SSE.
1589
1622
  // https://community.arm.com/arm-community-blogs/b/infrastructure-solutions-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon
1590
1623
  return vget_lane_u64(vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(vec), 4)), 0) & 0x8888888888888888ull;
@@ -1601,7 +1634,7 @@ SZ_PUBLIC sz_cptr_t sz_find_byte_neon(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
1601
1634
  // In Arm NEON we don't have a `movemask` to combine it with `ctz` and get the offset of the match.
1602
1635
  // But assuming the `vmaxvq` is cheap, we can use it to find the first match, by blending (bitwise selecting)
1603
1636
  // the vector with a relative offsets array.
1604
- matches = sz_vreinterpretq_u8_u4_(matches_vec.u8x16);
1637
+ matches = sz_find_vreinterpretq_u8_u4_(matches_vec.u8x16);
1605
1638
  if (matches) return h + sz_u64_ctz(matches) / 4;
1606
1639
 
1607
1640
  h += 16, h_length -= 16;
@@ -1618,7 +1651,7 @@ SZ_PUBLIC sz_cptr_t sz_rfind_byte_neon(sz_cptr_t h, sz_size_t h_length, sz_cptr_
1618
1651
  while (h_length >= 16) {
1619
1652
  h_vec.u8x16 = vld1q_u8((sz_u8_t const *)h + h_length - 16);
1620
1653
  matches_vec.u8x16 = vceqq_u8(h_vec.u8x16, n_vec.u8x16);
1621
- matches = sz_vreinterpretq_u8_u4_(matches_vec.u8x16);
1654
+ matches = sz_find_vreinterpretq_u8_u4_(matches_vec.u8x16);
1622
1655
  if (matches) return h + h_length - 1 - sz_u64_clz(matches) / 4;
1623
1656
  h_length -= 16;
1624
1657
  }
@@ -1643,7 +1676,7 @@ SZ_PUBLIC sz_u64_t sz_find_byteset_neon_register_( //
1643
1676
  uint8x16_t matches_vec = vorrq_u8(matches_top_vec, matches_bottom_vec);
1644
1677
  // Istead of pure `vandq_u8`, we can immediately broadcast a match presence across each 8-bit word.
1645
1678
  matches_vec = vtstq_u8(matches_vec, byte_mask_vec);
1646
- return sz_vreinterpretq_u8_u4_(matches_vec);
1679
+ return sz_find_vreinterpretq_u8_u4_(matches_vec);
1647
1680
  }
1648
1681
 
1649
1682
  SZ_PUBLIC sz_cptr_t sz_find_neon(sz_cptr_t h, sz_size_t h_length, sz_cptr_t n, sz_size_t n_length) {
@@ -1668,7 +1701,7 @@ SZ_PUBLIC sz_cptr_t sz_find_neon(sz_cptr_t h, sz_size_t h_length, sz_cptr_t n, s
1668
1701
  h_last_vec.u8x16 = vld1q_u8((sz_u8_t const *)(h + 1));
1669
1702
  matches_vec.u8x16 =
1670
1703
  vandq_u8(vceqq_u8(h_first_vec.u8x16, n_first_vec.u8x16), vceqq_u8(h_last_vec.u8x16, n_last_vec.u8x16));
1671
- matches = sz_vreinterpretq_u8_u4_(matches_vec.u8x16);
1704
+ matches = sz_find_vreinterpretq_u8_u4_(matches_vec.u8x16);
1672
1705
  if (matches) return h + sz_u64_ctz(matches) / 4;
1673
1706
  }
1674
1707
  }
@@ -1690,7 +1723,7 @@ SZ_PUBLIC sz_cptr_t sz_find_neon(sz_cptr_t h, sz_size_t h_length, sz_cptr_t n, s
1690
1723
  vceqq_u8(h_first_vec.u8x16, n_first_vec.u8x16), //
1691
1724
  vceqq_u8(h_mid_vec.u8x16, n_mid_vec.u8x16)),
1692
1725
  vceqq_u8(h_last_vec.u8x16, n_last_vec.u8x16));
1693
- matches = sz_vreinterpretq_u8_u4_(matches_vec.u8x16);
1726
+ matches = sz_find_vreinterpretq_u8_u4_(matches_vec.u8x16);
1694
1727
  if (matches) return h + sz_u64_ctz(matches) / 4;
1695
1728
  }
1696
1729
  }
@@ -1714,7 +1747,7 @@ SZ_PUBLIC sz_cptr_t sz_find_neon(sz_cptr_t h, sz_size_t h_length, sz_cptr_t n, s
1714
1747
  vceqq_u8(h_first_vec.u8x16, n_first_vec.u8x16), //
1715
1748
  vceqq_u8(h_mid_vec.u8x16, n_mid_vec.u8x16)),
1716
1749
  vceqq_u8(h_last_vec.u8x16, n_last_vec.u8x16));
1717
- matches = sz_vreinterpretq_u8_u4_(matches_vec.u8x16);
1750
+ matches = sz_find_vreinterpretq_u8_u4_(matches_vec.u8x16);
1718
1751
  while (matches) {
1719
1752
  int potential_offset = sz_u64_ctz(matches) / 4;
1720
1753
  if (sz_equal_neon(h + potential_offset, n, n_length)) return h + potential_offset;
@@ -1754,7 +1787,7 @@ SZ_PUBLIC sz_cptr_t sz_rfind_neon(sz_cptr_t h, sz_size_t h_length, sz_cptr_t n,
1754
1787
  vceqq_u8(h_first_vec.u8x16, n_first_vec.u8x16), //
1755
1788
  vceqq_u8(h_mid_vec.u8x16, n_mid_vec.u8x16)),
1756
1789
  vceqq_u8(h_last_vec.u8x16, n_last_vec.u8x16));
1757
- matches = sz_vreinterpretq_u8_u4_(matches_vec.u8x16);
1790
+ matches = sz_find_vreinterpretq_u8_u4_(matches_vec.u8x16);
1758
1791
  while (matches) {
1759
1792
  int potential_offset = sz_u64_clz(matches) / 4;
1760
1793
  if (sz_equal_neon(h + h_length - n_length - potential_offset, n, n_length))
@@ -1966,7 +1999,7 @@ SZ_DYNAMIC sz_cptr_t sz_find_byte(sz_cptr_t haystack, sz_size_t h_length, sz_cpt
1966
1999
  return sz_find_byte_haswell(haystack, h_length, needle);
1967
2000
  #elif SZ_USE_WESTMERE
1968
2001
  return sz_find_byte_westmere(haystack, h_length, needle);
1969
- #elif SZ_USE_SVE
2002
+ #elif SZ_USE_SVE // ? actually faster than NEON on most machines
1970
2003
  return sz_find_byte_sve(haystack, h_length, needle);
1971
2004
  #elif SZ_USE_NEON
1972
2005
  return sz_find_byte_neon(haystack, h_length, needle);
@@ -1982,7 +2015,7 @@ SZ_DYNAMIC sz_cptr_t sz_rfind_byte(sz_cptr_t haystack, sz_size_t h_length, sz_cp
1982
2015
  return sz_rfind_byte_haswell(haystack, h_length, needle);
1983
2016
  #elif SZ_USE_WESTMERE
1984
2017
  return sz_rfind_byte_westmere(haystack, h_length, needle);
1985
- #elif SZ_USE_SVE
2018
+ #elif SZ_USE_SVE // ? actually faster than NEON on most machines
1986
2019
  return sz_rfind_byte_sve(haystack, h_length, needle);
1987
2020
  #elif SZ_USE_NEON
1988
2021
  return sz_rfind_byte_neon(haystack, h_length, needle);
@@ -1998,7 +2031,7 @@ SZ_DYNAMIC sz_cptr_t sz_find(sz_cptr_t haystack, sz_size_t h_length, sz_cptr_t n
1998
2031
  return sz_find_haswell(haystack, h_length, needle, n_length);
1999
2032
  #elif SZ_USE_WESTMERE
2000
2033
  return sz_find_westmere(haystack, h_length, needle, n_length);
2001
- #elif SZ_USE_SVE
2034
+ #elif SZ_USE_SVE && SZ_ENFORCE_SVE_OVER_NEON
2002
2035
  return sz_find_sve(haystack, h_length, needle, n_length);
2003
2036
  #elif SZ_USE_NEON
2004
2037
  return sz_find_neon(haystack, h_length, needle, n_length);