stringzillas-cuda 4.2.2__tar.gz → 4.2.3__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 (49) hide show
  1. {stringzillas_cuda-4.2.2/stringzillas_cuda.egg-info → stringzillas_cuda-4.2.3}/PKG-INFO +6 -6
  2. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/README.md +4 -4
  3. stringzillas_cuda-4.2.3/VERSION +1 -0
  4. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/find.h +24 -26
  5. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/intersect.h +2 -2
  6. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/memory.h +2 -3
  7. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/stringzilla.h +1 -1
  8. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/stringzilla.hpp +222 -150
  9. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/types.h +3 -2
  10. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3/stringzillas_cuda.egg-info}/PKG-INFO +6 -6
  11. stringzillas_cuda-4.2.3/stringzillas_cuda.egg-info/requires.txt +1 -0
  12. stringzillas_cuda-4.2.2/VERSION +0 -1
  13. stringzillas_cuda-4.2.2/stringzillas_cuda.egg-info/requires.txt +0 -1
  14. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/LICENSE +0 -0
  15. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/MANIFEST.in +0 -0
  16. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/SZ_TARGET.env +0 -0
  17. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/build_backend.py +0 -0
  18. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/c/stringzilla.c +0 -0
  19. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/c/stringzillas.cpp +0 -0
  20. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/c/stringzillas.cu +0 -0
  21. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/c/stringzillas.cuh +0 -0
  22. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/cli/__init__.py +0 -0
  23. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/cli/split.py +0 -0
  24. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/cli/wc.py +0 -0
  25. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/fork_union/include/fork_union.h +0 -0
  26. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/fork_union/include/fork_union.hpp +0 -0
  27. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/compare.h +0 -0
  28. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/hash.h +0 -0
  29. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/module.modulemap +0 -0
  30. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/small_string.h +0 -0
  31. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/sort.h +0 -0
  32. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzilla/types.hpp +0 -0
  33. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzillas/fingerprints.cuh +0 -0
  34. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzillas/fingerprints.hpp +0 -0
  35. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzillas/similarities.cuh +0 -0
  36. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzillas/similarities.hpp +0 -0
  37. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzillas/stringzillas.h +0 -0
  38. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzillas/types.cuh +0 -0
  39. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/include/stringzillas/types.hpp +0 -0
  40. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/pyproject.toml +0 -0
  41. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/python/stringzilla.c +0 -0
  42. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/python/stringzillas.c +0 -0
  43. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/scripts/test_stringzilla.py +0 -0
  44. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/scripts/test_stringzillas.py +0 -0
  45. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/setup.cfg +0 -0
  46. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/setup.py +0 -0
  47. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/stringzillas_cuda.egg-info/SOURCES.txt +0 -0
  48. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/stringzillas_cuda.egg-info/dependency_links.txt +0 -0
  49. {stringzillas_cuda-4.2.2 → stringzillas_cuda-4.2.3}/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.2.3
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.2.3
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.
@@ -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.
@@ -0,0 +1 @@
1
+ 4.2.3
@@ -905,7 +905,7 @@ SZ_PUBLIC sz_cptr_t sz_find_westmere(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
905
905
  sz_locate_needle_anomalies_(n, n_length, &offset_first, &offset_mid, &offset_last);
906
906
 
907
907
  // Broadcast those characters into XMM registers.
908
- int matches;
908
+ sz_u32_vec_t matches_vec;
909
909
  sz_u128_vec_t h_first_vec, h_mid_vec, h_last_vec, n_first_vec, n_mid_vec, n_last_vec;
910
910
  n_first_vec.xmm = _mm_set1_epi8(n[offset_first]);
911
911
  n_mid_vec.xmm = _mm_set1_epi8(n[offset_mid]);
@@ -916,14 +916,14 @@ SZ_PUBLIC sz_cptr_t sz_find_westmere(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
916
916
  h_first_vec.xmm = _mm_lddqu_si128((__m128i const *)(h + offset_first));
917
917
  h_mid_vec.xmm = _mm_lddqu_si128((__m128i const *)(h + offset_mid));
918
918
  h_last_vec.xmm = _mm_lddqu_si128((__m128i const *)(h + offset_last));
919
- matches = //
919
+ matches_vec.i32 = //
920
920
  _mm_movemask_epi8(_mm_cmpeq_epi8(h_first_vec.xmm, n_first_vec.xmm)) &
921
921
  _mm_movemask_epi8(_mm_cmpeq_epi8(h_mid_vec.xmm, n_mid_vec.xmm)) &
922
922
  _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);
923
+ while (matches_vec.u32) {
924
+ int potential_offset = sz_u32_ctz(matches_vec.u32);
925
925
  if (sz_equal_westmere(h + potential_offset, n, n_length)) return h + potential_offset;
926
- matches &= matches - 1;
926
+ matches_vec.u32 &= matches_vec.u32 - 1;
927
927
  }
928
928
  }
929
929
 
@@ -940,7 +940,7 @@ SZ_PUBLIC sz_cptr_t sz_rfind_westmere(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
940
940
  sz_locate_needle_anomalies_(n, n_length, &offset_first, &offset_mid, &offset_last);
941
941
 
942
942
  // Broadcast those characters into XMM registers.
943
- int matches;
943
+ sz_u32_vec_t matches_vec;
944
944
  sz_u128_vec_t h_first_vec, h_mid_vec, h_last_vec, n_first_vec, n_mid_vec, n_last_vec;
945
945
  n_first_vec.xmm = _mm_set1_epi8(n[offset_first]);
946
946
  n_mid_vec.xmm = _mm_set1_epi8(n[offset_mid]);
@@ -953,15 +953,15 @@ SZ_PUBLIC sz_cptr_t sz_rfind_westmere(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
953
953
  h_first_vec.xmm = _mm_lddqu_si128((__m128i const *)(h_reversed + offset_first));
954
954
  h_mid_vec.xmm = _mm_lddqu_si128((__m128i const *)(h_reversed + offset_mid));
955
955
  h_last_vec.xmm = _mm_lddqu_si128((__m128i const *)(h_reversed + offset_last));
956
- matches = //
956
+ matches_vec.i32 = //
957
957
  _mm_movemask_epi8(_mm_cmpeq_epi8(h_first_vec.xmm, n_first_vec.xmm)) &
958
958
  _mm_movemask_epi8(_mm_cmpeq_epi8(h_mid_vec.xmm, n_mid_vec.xmm)) &
959
959
  _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;
960
+ while (matches_vec.u32) {
961
+ int potential_offset = sz_u32_clz(matches_vec.u32) - 16;
962
962
  if (sz_equal_westmere(h + h_length - n_length - potential_offset, n, n_length))
963
963
  return h + h_length - n_length - potential_offset;
964
- matches &= ~(1 << (15 - potential_offset));
964
+ matches_vec.u32 &= ~(1u << (15 - potential_offset));
965
965
  }
966
966
  }
967
967
 
@@ -1029,7 +1029,7 @@ SZ_PUBLIC sz_cptr_t sz_find_haswell(sz_cptr_t h, sz_size_t h_length, sz_cptr_t n
1029
1029
  sz_locate_needle_anomalies_(n, n_length, &offset_first, &offset_mid, &offset_last);
1030
1030
 
1031
1031
  // Broadcast those characters into YMM registers.
1032
- int matches;
1032
+ sz_u32_vec_t matches_vec;
1033
1033
  sz_u256_vec_t h_first_vec, h_mid_vec, h_last_vec, n_first_vec, n_mid_vec, n_last_vec;
1034
1034
  n_first_vec.ymm = _mm256_set1_epi8(n[offset_first]);
1035
1035
  n_mid_vec.ymm = _mm256_set1_epi8(n[offset_mid]);
@@ -1040,14 +1040,14 @@ SZ_PUBLIC sz_cptr_t sz_find_haswell(sz_cptr_t h, sz_size_t h_length, sz_cptr_t n
1040
1040
  h_first_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h + offset_first));
1041
1041
  h_mid_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h + offset_mid));
1042
1042
  h_last_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h + offset_last));
1043
- matches = //
1043
+ matches_vec.i32 = //
1044
1044
  _mm256_movemask_epi8(_mm256_cmpeq_epi8(h_first_vec.ymm, n_first_vec.ymm)) &
1045
1045
  _mm256_movemask_epi8(_mm256_cmpeq_epi8(h_mid_vec.ymm, n_mid_vec.ymm)) &
1046
1046
  _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);
1047
+ while (matches_vec.u32) {
1048
+ int potential_offset = sz_u32_ctz(matches_vec.u32);
1049
1049
  if (sz_equal_haswell(h + potential_offset, n, n_length)) return h + potential_offset;
1050
- matches &= matches - 1;
1050
+ matches_vec.u32 &= matches_vec.u32 - 1;
1051
1051
  }
1052
1052
  }
1053
1053
 
@@ -1065,7 +1065,7 @@ SZ_PUBLIC sz_cptr_t sz_rfind_haswell(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
1065
1065
  sz_locate_needle_anomalies_(n, n_length, &offset_first, &offset_mid, &offset_last);
1066
1066
 
1067
1067
  // Broadcast those characters into YMM registers.
1068
- int matches;
1068
+ sz_u32_vec_t matches_vec;
1069
1069
  sz_u256_vec_t h_first_vec, h_mid_vec, h_last_vec, n_first_vec, n_mid_vec, n_last_vec;
1070
1070
  n_first_vec.ymm = _mm256_set1_epi8(n[offset_first]);
1071
1071
  n_mid_vec.ymm = _mm256_set1_epi8(n[offset_mid]);
@@ -1078,15 +1078,15 @@ SZ_PUBLIC sz_cptr_t sz_rfind_haswell(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
1078
1078
  h_first_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h_reversed + offset_first));
1079
1079
  h_mid_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h_reversed + offset_mid));
1080
1080
  h_last_vec.ymm = _mm256_lddqu_si256((__m256i const *)(h_reversed + offset_last));
1081
- matches = //
1081
+ matches_vec.i32 = //
1082
1082
  _mm256_movemask_epi8(_mm256_cmpeq_epi8(h_first_vec.ymm, n_first_vec.ymm)) &
1083
1083
  _mm256_movemask_epi8(_mm256_cmpeq_epi8(h_mid_vec.ymm, n_mid_vec.ymm)) &
1084
1084
  _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);
1085
+ while (matches_vec.u32) {
1086
+ int potential_offset = sz_u32_clz(matches_vec.u32);
1087
1087
  if (sz_equal_haswell(h + h_length - n_length - potential_offset, n, n_length))
1088
1088
  return h + h_length - n_length - potential_offset;
1089
- matches &= ~(1 << (31 - potential_offset));
1089
+ matches_vec.u32 &= ~(1u << (31 - potential_offset));
1090
1090
  }
1091
1091
  }
1092
1092
 
@@ -1388,9 +1388,8 @@ SZ_PUBLIC sz_cptr_t sz_rfind_skylake(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
1388
1388
  int potential_offset = sz_u64_clz(matches);
1389
1389
  if (n_length <= 3 || sz_equal_skylake(h + h_length - n_length - potential_offset, n, n_length))
1390
1390
  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));
1391
+ sz_assert_((matches & (1ull << (63 - potential_offset))) != 0 && "The bit must be set before we squash it");
1392
+ matches &= ~(1ull << (63 - potential_offset));
1394
1393
  }
1395
1394
  }
1396
1395
 
@@ -1409,9 +1408,8 @@ SZ_PUBLIC sz_cptr_t sz_rfind_skylake(sz_cptr_t h, sz_size_t h_length, sz_cptr_t
1409
1408
  int potential_offset = sz_u64_clz(matches);
1410
1409
  if (n_length <= 3 || sz_equal_skylake(h + 64 - potential_offset - 1, n, n_length))
1411
1410
  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));
1411
+ sz_assert_((matches & (1ull << (63 - potential_offset))) != 0 && "The bit must be set before we squash it");
1412
+ matches &= ~(1ull << (63 - potential_offset));
1415
1413
  }
1416
1414
  }
1417
1415
 
@@ -288,7 +288,7 @@ SZ_PUBLIC sz_status_t sz_sequence_intersect_serial(
288
288
  // Allocate memory for the hash table and initialize it with 0xFF.
289
289
  // The higher is the `hash_table_slots` multiple - the more memory we will use,
290
290
  // but the less likely the collisions will be.
291
- sz_size_t const hash_table_slots = sz_size_bit_ceil(small_sequence->count) * (1 << SZ_SEQUENCE_INTERSECT_BUDGET);
291
+ sz_size_t const hash_table_slots = sz_size_bit_ceil(small_sequence->count) * (1u << SZ_SEQUENCE_INTERSECT_BUDGET);
292
292
  sz_size_t const bytes_per_entry = sizeof(sz_size_t) + sizeof(sz_u64_t);
293
293
  sz_size_t *const table_positions = (sz_size_t *)alloc->allocate(hash_table_slots * bytes_per_entry, alloc);
294
294
  if (!table_positions) return sz_bad_alloc_k;
@@ -414,7 +414,7 @@ SZ_PUBLIC sz_status_t sz_sequence_intersect_ice(
414
414
  // Allocate memory for the hash table and initialize it with 0xFF.
415
415
  // The higher is the `hash_table_slots` multiple - the more memory we will use,
416
416
  // but the less likely the collisions will be.
417
- sz_size_t const hash_table_slots = sz_size_bit_ceil(small_sequence->count) * (1 << SZ_SEQUENCE_INTERSECT_BUDGET);
417
+ sz_size_t const hash_table_slots = sz_size_bit_ceil(small_sequence->count) * (1u << SZ_SEQUENCE_INTERSECT_BUDGET);
418
418
  sz_size_t const bytes_per_entry = sizeof(sz_size_t) + sizeof(sz_u64_t);
419
419
  sz_size_t *table_positions = (sz_size_t *)alloc->allocate(hash_table_slots * bytes_per_entry, alloc);
420
420
  if (!table_positions) return sz_bad_alloc_k;
@@ -1194,6 +1194,7 @@ SZ_PUBLIC void sz_lookup_neon(sz_ptr_t target, sz_size_t length, sz_cptr_t sourc
1194
1194
 
1195
1195
  sz_size_t head_length = (16 - ((sz_size_t)target % 16)) % 16; // 15 or less.
1196
1196
  sz_size_t tail_length = (sz_size_t)(target + length) % 16; // 15 or less.
1197
+ sz_size_t body_length = length - head_length - tail_length;
1197
1198
 
1198
1199
  // We need to pull the lookup table into 16x NEON registers. We have a total of 32 such registers.
1199
1200
  // According to the Neoverse V2 manual, the 4-table lookup has a latency of 6 cycles, and 4x throughput.
@@ -1216,9 +1217,7 @@ SZ_PUBLIC void sz_lookup_neon(sz_ptr_t target, sz_size_t length, sz_cptr_t sourc
1216
1217
  // to perform a 4-table lookup in a single instruction. The XORs are used to adjust the lookup position
1217
1218
  // within each 64-byte range of the table.
1218
1219
  // Details on the 4-table lookup: https://lemire.me/blog/2019/07/23/arbitrary-byte-to-byte-maps-using-arm-neon/
1219
- length -= head_length;
1220
- length -= tail_length;
1221
- for (; length >= 16; source += 16, target += 16, length -= 16) {
1220
+ for (; body_length >= 16; source += 16, target += 16, body_length -= 16) {
1222
1221
  source_vec.u8x16 = vld1q_u8((sz_u8_t const *)source);
1223
1222
  lookup_0_to_63_vec.u8x16 = vqtbl4q_u8(lut_0_to_63_vec, source_vec.u8x16);
1224
1223
  lookup_64_to_127_vec.u8x16 = vqtbl4q_u8(lut_64_to_127_vec, veorq_u8(source_vec.u8x16, vdupq_n_u8(0x40)));
@@ -67,7 +67,7 @@
67
67
 
68
68
  #define STRINGZILLA_H_VERSION_MAJOR 4
69
69
  #define STRINGZILLA_H_VERSION_MINOR 2
70
- #define STRINGZILLA_H_VERSION_PATCH 2
70
+ #define STRINGZILLA_H_VERSION_PATCH 3
71
71
 
72
72
  #include "types.h" // `sz_size_t`, `sz_bool_t`, `sz_ordering_t`
73
73
  #include "compare.h" // `sz_equal`, `sz_order`
@@ -401,7 +401,7 @@ inline static constexpr exclude_overlaps_type exclude_overlaps;
401
401
  * @brief Zero-cost wrapper around the `.find` member function of string-like classes.
402
402
  * @see https://en.cppreference.com/w/cpp/string/basic_string/find
403
403
  */
404
- template <typename string_type_, typename overlaps_type = include_overlaps_type>
404
+ template <typename string_type_, typename overlaps_type_ = include_overlaps_type>
405
405
  struct matcher_find {
406
406
  using size_type = typename string_type_::size_type;
407
407
  string_type_ needle_;
@@ -411,7 +411,7 @@ struct matcher_find {
411
411
  size_type operator()(string_type_ haystack) const noexcept { return haystack.find(needle_); }
412
412
  size_type skip_length() const noexcept {
413
413
  // TODO: Apply Galil rule to match repetitive patterns in strictly linear time.
414
- return is_same_type<overlaps_type, include_overlaps_type>::value ? 1 : needle_.length();
414
+ return is_same_type<overlaps_type_, include_overlaps_type>::value ? 1 : needle_.length();
415
415
  }
416
416
  };
417
417
 
@@ -419,7 +419,7 @@ struct matcher_find {
419
419
  * @brief Zero-cost wrapper around the `.rfind` member function of string-like classes.
420
420
  * @see https://en.cppreference.com/w/cpp/string/basic_string/rfind
421
421
  */
422
- template <typename string_type_, typename overlaps_type = include_overlaps_type>
422
+ template <typename string_type_, typename overlaps_type_ = include_overlaps_type>
423
423
  struct matcher_rfind {
424
424
  using size_type = typename string_type_::size_type;
425
425
  string_type_ needle_;
@@ -429,7 +429,7 @@ struct matcher_rfind {
429
429
  size_type operator()(string_type_ haystack) const noexcept { return haystack.rfind(needle_); }
430
430
  size_type skip_length() const noexcept {
431
431
  // TODO: Apply Galil rule to match repetitive patterns in strictly linear time.
432
- return is_same_type<overlaps_type, include_overlaps_type>::value ? 1 : needle_.length();
432
+ return is_same_type<overlaps_type_, include_overlaps_type>::value ? 1 : needle_.length();
433
433
  }
434
434
  };
435
435
 
@@ -437,56 +437,97 @@ struct matcher_rfind {
437
437
  * @brief Zero-cost wrapper around the `.find_first_of` member function of string-like classes.
438
438
  * @see https://en.cppreference.com/w/cpp/string/basic_string/find_first_of
439
439
  */
440
- template <typename haystack_type, typename needles_type = haystack_type>
440
+ template <typename haystack_type_, typename needles_type_ = haystack_type_>
441
441
  struct matcher_find_first_of {
442
- using size_type = typename haystack_type::size_type;
443
- needles_type needles_;
442
+ using size_type = typename haystack_type_::size_type;
443
+ needles_type_ needles_;
444
444
  constexpr size_type needle_length() const noexcept { return 1; }
445
445
  constexpr size_type skip_length() const noexcept { return 1; }
446
- size_type operator()(haystack_type haystack) const noexcept { return haystack.find_first_of(needles_); }
446
+ size_type operator()(haystack_type_ haystack) const noexcept { return haystack.find_first_of(needles_); }
447
447
  };
448
448
 
449
449
  /**
450
450
  * @brief Zero-cost wrapper around the `.find_last_of` member function of string-like classes.
451
451
  * @see https://en.cppreference.com/w/cpp/string/basic_string/find_last_of
452
452
  */
453
- template <typename haystack_type, typename needles_type = haystack_type>
453
+ template <typename haystack_type_, typename needles_type_ = haystack_type_>
454
454
  struct matcher_find_last_of {
455
- using size_type = typename haystack_type::size_type;
456
- needles_type needles_;
455
+ using size_type = typename haystack_type_::size_type;
456
+ needles_type_ needles_;
457
457
  constexpr size_type needle_length() const noexcept { return 1; }
458
458
  constexpr size_type skip_length() const noexcept { return 1; }
459
- size_type operator()(haystack_type haystack) const noexcept { return haystack.find_last_of(needles_); }
459
+ size_type operator()(haystack_type_ haystack) const noexcept { return haystack.find_last_of(needles_); }
460
460
  };
461
461
 
462
462
  /**
463
463
  * @brief Zero-cost wrapper around the `.find_first_not_of` member function of string-like classes.
464
464
  * @see https://en.cppreference.com/w/cpp/string/basic_string/find_first_not_of
465
465
  */
466
- template <typename haystack_type, typename needles_type = haystack_type>
466
+ template <typename haystack_type_, typename needles_type_ = haystack_type_>
467
467
  struct matcher_find_first_not_of {
468
- using size_type = typename haystack_type::size_type;
469
- needles_type needles_;
468
+ using size_type = typename haystack_type_::size_type;
469
+ needles_type_ needles_;
470
470
  constexpr size_type needle_length() const noexcept { return 1; }
471
471
  constexpr size_type skip_length() const noexcept { return 1; }
472
- size_type operator()(haystack_type haystack) const noexcept { return haystack.find_first_not_of(needles_); }
472
+ size_type operator()(haystack_type_ haystack) const noexcept { return haystack.find_first_not_of(needles_); }
473
473
  };
474
474
 
475
475
  /**
476
476
  * @brief Zero-cost wrapper around the `.find_last_not_of` member function of string-like classes.
477
477
  * @see https://en.cppreference.com/w/cpp/string/basic_string/find_last_not_of
478
478
  */
479
- template <typename haystack_type, typename needles_type = haystack_type>
479
+ template <typename haystack_type_, typename needles_type_ = haystack_type_>
480
480
  struct matcher_find_last_not_of {
481
- using size_type = typename haystack_type::size_type;
482
- needles_type needles_;
481
+ using size_type = typename haystack_type_::size_type;
482
+ needles_type_ needles_;
483
483
  constexpr size_type needle_length() const noexcept { return 1; }
484
484
  constexpr size_type skip_length() const noexcept { return 1; }
485
- size_type operator()(haystack_type haystack) const noexcept { return haystack.find_last_not_of(needles_); }
485
+ size_type operator()(haystack_type_ haystack) const noexcept { return haystack.find_last_not_of(needles_); }
486
+ };
487
+
488
+ /**
489
+ * @brief Helper to detect if a type has a nested `::string_view` typedef.
490
+ * Uses SFINAE with no STL dependencies for `std::enabled_if` or `std::void_t`.
491
+ */
492
+ template <typename type_>
493
+ struct has_string_view_member_ {
494
+ private:
495
+ template <typename candidate_>
496
+ static char test_(typename candidate_::string_view *);
497
+ template <typename candidate_>
498
+ static int test_(...);
499
+
500
+ public:
501
+ static constexpr bool value = sizeof(test_<type_>(0)) == sizeof(char);
502
+ };
503
+
504
+ /**
505
+ * @brief Helper to extract the appropriate view type for a string-like type.
506
+ * For StringZilla types, uses the nested ::string_view typedef.
507
+ * For STL types (like std::string_view), uses the type itself.
508
+ */
509
+ template <typename string_type_, bool has_nested_view_ = has_string_view_member_<string_type_>::value>
510
+ struct string_view_for {
511
+ // Default: use the type itself (for STL types)
512
+ using type = string_type_;
513
+ };
514
+
515
+ // Specialization for types with nested ::string_view
516
+ template <typename string_type_>
517
+ struct string_view_for<string_type_, true> {
518
+ // For StringZilla types with nested ::string_view
519
+ using type = typename string_type_::string_view;
486
520
  };
487
521
 
488
522
  /**
489
523
  * @brief A range of string slices representing the matches of a substring search.
524
+ *
525
+ * @note Lifetime semantics: Stores forwarded objects (including owning strings) to maintain lifetime.
526
+ * Iterators receive lightweight views only, ensuring safe iteration without ownership concerns.
527
+ * @note For-loop optimized: Iterators are lightweight views with minimal register pressure, ideal for
528
+ * high-performance applications where cache efficiency and register allocation matter.
529
+ * @note Sentinel support: Supports sentinel-based iteration via `operator==(end_sentinel_type)` for
530
+ * efficient termination without constructing full end iterators.
490
531
  * @note Compatible with C++23 ranges, C++11 string views, and of course, StringZilla.
491
532
  * @see Similar to a pair of `boost::algorithm::find_iterator`.
492
533
  */
@@ -495,6 +536,7 @@ class range_matches {
495
536
  public:
496
537
  using string_type = string_type_;
497
538
  using matcher_type = matcher_type_;
539
+ using string_view_type = typename string_view_for<string_type>::type;
498
540
 
499
541
  private:
500
542
  matcher_type matcher_;
@@ -503,24 +545,24 @@ class range_matches {
503
545
  public:
504
546
  using size_type = std::size_t;
505
547
  using difference_type = std::ptrdiff_t;
506
- using value_type = string_type;
507
- using pointer = string_type; // Needed for compatibility with STL container constructors.
508
- using reference = string_type; // Needed for compatibility with STL container constructors.
548
+ using value_type = string_view_type;
549
+ using pointer = string_view_type; // Needed for compatibility with STL container constructors.
550
+ using reference = string_view_type; // Needed for compatibility with STL container constructors.
509
551
 
510
552
  range_matches(string_type haystack, matcher_type needle) noexcept : matcher_(needle), haystack_(haystack) {}
511
553
 
512
554
  class iterator {
513
555
  matcher_type matcher_;
514
- string_type remaining_;
556
+ string_view_type remaining_;
515
557
 
516
558
  public:
517
559
  using iterator_category = std::forward_iterator_tag;
518
560
  using difference_type = std::ptrdiff_t;
519
- using value_type = string_type;
520
- using pointer = string_type; // Needed for compatibility with STL container constructors.
521
- using reference = string_type; // Needed for compatibility with STL container constructors.
561
+ using value_type = string_view_type;
562
+ using pointer = string_view_type; // Needed for compatibility with STL container constructors.
563
+ using reference = string_view_type; // Needed for compatibility with STL container constructors.
522
564
 
523
- iterator(string_type haystack, matcher_type matcher) noexcept : matcher_(matcher), remaining_(haystack) {
565
+ iterator(string_view_type haystack, matcher_type matcher) noexcept : matcher_(matcher), remaining_(haystack) {
524
566
  auto position = matcher_(remaining_);
525
567
  remaining_.remove_prefix(position != string_type::npos ? position : remaining_.size());
526
568
  }
@@ -548,8 +590,8 @@ class range_matches {
548
590
  bool operator==(end_sentinel_type) const noexcept { return remaining_.empty(); }
549
591
  };
550
592
 
551
- iterator begin() const noexcept { return {haystack_, matcher_}; }
552
- iterator end() const noexcept { return {string_type {haystack_.data() + haystack_.size(), 0ull}, matcher_}; }
593
+ iterator begin() const noexcept { return {string_view_type(haystack_), matcher_}; }
594
+ iterator end() const noexcept { return {string_view_type(haystack_.data() + haystack_.size(), 0ull), matcher_}; }
553
595
  size_type size() const noexcept { return static_cast<size_type>(ssize()); }
554
596
  difference_type ssize() const noexcept { return std::distance(begin(), end()); }
555
597
  bool empty() const noexcept { return begin() == end_sentinel_type {}; }
@@ -570,6 +612,13 @@ class range_matches {
570
612
 
571
613
  /**
572
614
  * @brief A range of string slices representing the matches of a @b reverse-order substring search.
615
+ *
616
+ * @note Lifetime semantics: Stores forwarded objects (including owning strings) to maintain lifetime.
617
+ * Iterators receive lightweight views only, ensuring safe iteration without ownership concerns.
618
+ * @note For-loop optimized: Iterators are lightweight views with minimal register pressure, ideal for
619
+ * high-performance applications where cache efficiency and register allocation matter.
620
+ * @note Sentinel support: Supports sentinel-based iteration via `operator==(end_sentinel_type)` for
621
+ * efficient termination without constructing full end iterators.
573
622
  * @note Compatible with C++23 ranges, C++11 string views, and of course, StringZilla.
574
623
  * @see Similar to a pair of `boost::algorithm::find_iterator`.
575
624
  */
@@ -578,12 +627,13 @@ class range_rmatches {
578
627
  public:
579
628
  using string_type = string_type_;
580
629
  using matcher_type = matcher_type_;
630
+ using string_view_type = typename string_view_for<string_type>::type;
581
631
 
582
632
  using size_type = std::size_t;
583
633
  using difference_type = std::ptrdiff_t;
584
- using value_type = string_type;
585
- using pointer = string_type; // Needed for compatibility with STL container constructors.
586
- using reference = string_type; // Needed for compatibility with STL container constructors.
634
+ using value_type = string_view_type;
635
+ using pointer = string_view_type; // Needed for compatibility with STL container constructors.
636
+ using reference = string_view_type; // Needed for compatibility with STL container constructors.
587
637
 
588
638
  private:
589
639
  matcher_type matcher_;
@@ -594,16 +644,16 @@ class range_rmatches {
594
644
 
595
645
  class iterator {
596
646
  matcher_type matcher_;
597
- string_type remaining_;
647
+ string_view_type remaining_;
598
648
 
599
649
  public:
600
650
  using iterator_category = std::forward_iterator_tag;
601
651
  using difference_type = std::ptrdiff_t;
602
- using value_type = string_type;
603
- using pointer = string_type; // Needed for compatibility with STL container constructors.
604
- using reference = string_type; // Needed for compatibility with STL container constructors.
652
+ using value_type = string_view_type;
653
+ using pointer = string_view_type; // Needed for compatibility with STL container constructors.
654
+ using reference = string_view_type; // Needed for compatibility with STL container constructors.
605
655
 
606
- iterator(string_type haystack, matcher_type matcher) noexcept : matcher_(matcher), remaining_(haystack) {
656
+ iterator(string_view_type haystack, matcher_type matcher) noexcept : matcher_(matcher), remaining_(haystack) {
607
657
  auto position = matcher_(remaining_);
608
658
  remaining_.remove_suffix( //
609
659
  position != string_type::npos //
@@ -644,8 +694,8 @@ class range_rmatches {
644
694
  bool operator==(end_sentinel_type) const noexcept { return remaining_.empty(); }
645
695
  };
646
696
 
647
- iterator begin() const noexcept { return {haystack_, matcher_}; }
648
- iterator end() const noexcept { return {string_type {haystack_.data(), 0ull}, matcher_}; }
697
+ iterator begin() const noexcept { return {string_view_type(haystack_), matcher_}; }
698
+ iterator end() const noexcept { return {string_view_type(haystack_.data(), 0ull), matcher_}; }
649
699
  size_type size() const noexcept { return static_cast<size_type>(ssize()); }
650
700
  difference_type ssize() const noexcept { return std::distance(begin(), end()); }
651
701
  bool empty() const noexcept { return begin() == end_sentinel_type {}; }
@@ -666,6 +716,13 @@ class range_rmatches {
666
716
 
667
717
  /**
668
718
  * @brief A range of string slices for different splits of the data.
719
+ *
720
+ * @note Lifetime semantics: Stores forwarded objects (including owning strings) to maintain lifetime.
721
+ * Iterators receive lightweight views only, ensuring safe iteration without ownership concerns.
722
+ * @note For-loop optimized: Iterators are lightweight views with minimal register pressure, ideal for
723
+ * high-performance applications where cache efficiency and register allocation matter.
724
+ * @note Sentinel support: Supports sentinel-based iteration via `operator==(end_sentinel_type)` for
725
+ * efficient termination without constructing full end iterators.
669
726
  * @note Compatible with C++23 ranges, C++11 string views, and of course, StringZilla.
670
727
  * @see Similar to a pair of `boost::algorithm::split_iterator`.
671
728
  *
@@ -678,12 +735,13 @@ class range_splits {
678
735
  public:
679
736
  using string_type = string_type_;
680
737
  using matcher_type = matcher_type_;
738
+ using string_view_type = typename string_view_for<string_type>::type;
681
739
 
682
740
  using size_type = std::size_t;
683
741
  using difference_type = std::ptrdiff_t;
684
- using value_type = string_type;
685
- using pointer = string_type; // Needed for compatibility with STL container constructors.
686
- using reference = string_type; // Needed for compatibility with STL container constructors.
742
+ using value_type = string_view_type;
743
+ using pointer = string_view_type; // Needed for compatibility with STL container constructors.
744
+ using reference = string_view_type; // Needed for compatibility with STL container constructors.
687
745
 
688
746
  private:
689
747
  matcher_type matcher_;
@@ -694,24 +752,24 @@ class range_splits {
694
752
 
695
753
  class iterator {
696
754
  matcher_type matcher_;
697
- string_type remaining_;
755
+ string_view_type remaining_;
698
756
  std::size_t length_within_remaining_;
699
757
  bool reached_tail_;
700
758
 
701
759
  public:
702
760
  using iterator_category = std::forward_iterator_tag;
703
761
  using difference_type = std::ptrdiff_t;
704
- using value_type = string_type;
705
- using pointer = string_type; // Needed for compatibility with STL container constructors.
706
- using reference = string_type; // Needed for compatibility with STL container constructors.
762
+ using value_type = string_view_type;
763
+ using pointer = string_view_type; // Needed for compatibility with STL container constructors.
764
+ using reference = string_view_type; // Needed for compatibility with STL container constructors.
707
765
 
708
- iterator(string_type haystack, matcher_type matcher) noexcept : matcher_(matcher), remaining_(haystack) {
766
+ iterator(string_view_type haystack, matcher_type matcher) noexcept : matcher_(matcher), remaining_(haystack) {
709
767
  auto position = matcher_(remaining_);
710
768
  length_within_remaining_ = position != string_type::npos ? position : remaining_.size();
711
769
  reached_tail_ = false;
712
770
  }
713
771
 
714
- iterator(string_type haystack, matcher_type matcher, end_sentinel_type) noexcept
772
+ iterator(string_view_type haystack, matcher_type matcher, end_sentinel_type) noexcept
715
773
  : matcher_(matcher), remaining_(haystack), length_within_remaining_(0), reached_tail_(true) {}
716
774
 
717
775
  pointer operator->() const noexcept = delete;
@@ -743,8 +801,8 @@ class range_splits {
743
801
  bool is_last() const noexcept { return remaining_.size() == length_within_remaining_; }
744
802
  };
745
803
 
746
- iterator begin() const noexcept { return {haystack_, matcher_}; }
747
- iterator end() const noexcept { return {string_type {haystack_.end(), 0}, matcher_, end_sentinel_type {}}; }
804
+ iterator begin() const noexcept { return {string_view_type(haystack_), matcher_}; }
805
+ iterator end() const noexcept { return {string_view_type(haystack_.end(), 0), matcher_, end_sentinel_type {}}; }
748
806
  size_type size() const noexcept { return static_cast<size_type>(ssize()); }
749
807
  difference_type ssize() const noexcept { return std::distance(begin(), end()); }
750
808
  constexpr bool empty() const noexcept { return false; }
@@ -765,6 +823,13 @@ class range_splits {
765
823
 
766
824
  /**
767
825
  * @brief A range of string slices for different splits of the data in @b reverse-order.
826
+ *
827
+ * @note Lifetime semantics: Stores forwarded objects (including owning strings) to maintain lifetime.
828
+ * Iterators receive lightweight views only, ensuring safe iteration without ownership concerns.
829
+ * @note For-loop optimized: Iterators are lightweight views with minimal register pressure, ideal for
830
+ * high-performance applications where cache efficiency and register allocation matter.
831
+ * @note Sentinel support: Supports sentinel-based iteration via `operator==(end_sentinel_type)` for
832
+ * efficient termination without constructing full end iterators.
768
833
  * @note Compatible with C++23 ranges, C++11 string views, and of course, StringZilla.
769
834
  * @see Similar to a pair of `boost::algorithm::split_iterator`.
770
835
  *
@@ -777,12 +842,13 @@ class range_rsplits {
777
842
  public:
778
843
  using string_type = string_type_;
779
844
  using matcher_type = matcher_type_;
845
+ using string_view_type = typename string_view_for<string_type>::type;
780
846
 
781
847
  using size_type = std::size_t;
782
848
  using difference_type = std::ptrdiff_t;
783
- using value_type = string_type;
784
- using pointer = string_type; // Needed for compatibility with STL container constructors.
785
- using reference = string_type; // Needed for compatibility with STL container constructors.
849
+ using value_type = string_view_type;
850
+ using pointer = string_view_type; // Needed for compatibility with STL container constructors.
851
+ using reference = string_view_type; // Needed for compatibility with STL container constructors.
786
852
 
787
853
  private:
788
854
  matcher_type matcher_;
@@ -793,18 +859,18 @@ class range_rsplits {
793
859
 
794
860
  class iterator {
795
861
  matcher_type matcher_;
796
- string_type remaining_;
862
+ string_view_type remaining_;
797
863
  std::size_t length_within_remaining_;
798
864
  bool reached_tail_;
799
865
 
800
866
  public:
801
867
  using iterator_category = std::forward_iterator_tag;
802
868
  using difference_type = std::ptrdiff_t;
803
- using value_type = string_type;
804
- using pointer = string_type; // Needed for compatibility with STL container constructors.
805
- using reference = string_type; // Needed for compatibility with STL container constructors.
869
+ using value_type = string_view_type;
870
+ using pointer = string_view_type; // Needed for compatibility with STL container constructors.
871
+ using reference = string_view_type; // Needed for compatibility with STL container constructors.
806
872
 
807
- iterator(string_type haystack, matcher_type matcher) noexcept : matcher_(matcher), remaining_(haystack) {
873
+ iterator(string_view_type haystack, matcher_type matcher) noexcept : matcher_(matcher), remaining_(haystack) {
808
874
  auto position = matcher_(remaining_);
809
875
  length_within_remaining_ = position != string_type::npos
810
876
  ? remaining_.size() - position - matcher_.needle_length()
@@ -812,7 +878,7 @@ class range_rsplits {
812
878
  reached_tail_ = false;
813
879
  }
814
880
 
815
- iterator(string_type haystack, matcher_type matcher, end_sentinel_type) noexcept
881
+ iterator(string_view_type haystack, matcher_type matcher, end_sentinel_type) noexcept
816
882
  : matcher_(matcher), remaining_(haystack), length_within_remaining_(0), reached_tail_(true) {}
817
883
 
818
884
  pointer operator->() const noexcept = delete;
@@ -848,8 +914,8 @@ class range_rsplits {
848
914
  bool is_last() const noexcept { return remaining_.size() == length_within_remaining_; }
849
915
  };
850
916
 
851
- iterator begin() const noexcept { return {haystack_, matcher_}; }
852
- iterator end() const noexcept { return {{haystack_.data(), 0ull}, matcher_, end_sentinel_type {}}; }
917
+ iterator begin() const noexcept { return {string_view_type(haystack_), matcher_}; }
918
+ iterator end() const noexcept { return {string_view_type(haystack_.data(), 0ull), matcher_, end_sentinel_type {}}; }
853
919
  size_type size() const noexcept { return static_cast<size_type>(ssize()); }
854
920
  difference_type ssize() const noexcept { return std::distance(begin(), end()); }
855
921
  constexpr bool empty() const noexcept { return false; }
@@ -870,135 +936,141 @@ class range_rsplits {
870
936
 
871
937
  /**
872
938
  * @brief Find all potentially @b overlapping inclusions of a needle substring.
873
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
939
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
874
940
  */
875
- template <typename string>
876
- range_matches<string, matcher_find<string, include_overlaps_type>> find_all(string const &h, string const &n,
877
- include_overlaps_type = {}) noexcept {
941
+ template <typename string_type_>
942
+ range_matches<string_type_, matcher_find<string_type_, include_overlaps_type>> find_all(
943
+ string_type_ const &h, string_type_ const &n, include_overlaps_type = {}) noexcept {
878
944
  return {h, n};
879
945
  }
880
946
 
881
947
  /**
882
948
  * @brief Find all potentially @b overlapping inclusions of a needle substring in @b reverse order.
883
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
949
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
884
950
  */
885
- template <typename string>
886
- range_rmatches<string, matcher_rfind<string, include_overlaps_type>> rfind_all(string const &h, string const &n,
887
- include_overlaps_type = {}) noexcept {
951
+ template <typename string_type_>
952
+ range_rmatches<string_type_, matcher_rfind<string_type_, include_overlaps_type>> rfind_all(
953
+ string_type_ const &h, string_type_ const &n, include_overlaps_type = {}) noexcept {
888
954
  return {h, n};
889
955
  }
890
956
 
891
957
  /**
892
958
  * @brief Find all @b non-overlapping inclusions of a needle substring.
893
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
959
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
894
960
  */
895
- template <typename string>
896
- range_matches<string, matcher_find<string, exclude_overlaps_type>> find_all(string const &h, string const &n,
897
- exclude_overlaps_type) noexcept {
961
+ template <typename string_type_>
962
+ range_matches<string_type_, matcher_find<string_type_, exclude_overlaps_type>> find_all(
963
+ string_type_ const &h, string_type_ const &n, exclude_overlaps_type) noexcept {
898
964
  return {h, n};
899
965
  }
900
966
 
901
967
  /**
902
968
  * @brief Find all @b non-overlapping inclusions of a needle substring in @b reverse order.
903
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
969
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
904
970
  */
905
- template <typename string>
906
- range_rmatches<string, matcher_rfind<string, exclude_overlaps_type>> rfind_all(string const &h, string const &n,
907
- exclude_overlaps_type) noexcept {
971
+ template <typename string_type_>
972
+ range_rmatches<string_type_, matcher_rfind<string_type_, exclude_overlaps_type>> rfind_all(
973
+ string_type_ const &h, string_type_ const &n, exclude_overlaps_type) noexcept {
908
974
  return {h, n};
909
975
  }
910
976
 
911
977
  /**
912
978
  * @brief Find all inclusions of characters from the second string.
913
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
979
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
914
980
  */
915
- template <typename string>
916
- range_matches<string, matcher_find_first_of<string>> find_all_characters(string const &h, string const &n) noexcept {
981
+ template <typename string_type_>
982
+ range_matches<string_type_, matcher_find_first_of<string_type_>> find_all_characters(string_type_ const &h,
983
+ string_type_ const &n) noexcept {
917
984
  return {h, n};
918
985
  }
919
986
 
920
987
  /**
921
988
  * @brief Find all inclusions of characters from the second string in @b reverse order.
922
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
989
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
923
990
  */
924
- template <typename string>
925
- range_rmatches<string, matcher_find_last_of<string>> rfind_all_characters(string const &h, string const &n) noexcept {
991
+ template <typename string_type_>
992
+ range_rmatches<string_type_, matcher_find_last_of<string_type_>> rfind_all_characters(string_type_ const &h,
993
+ string_type_ const &n) noexcept {
926
994
  return {h, n};
927
995
  }
928
996
 
929
997
  /**
930
998
  * @brief Find all characters except the ones in the second string.
931
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
999
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
932
1000
  */
933
- template <typename string>
934
- range_matches<string, matcher_find_first_not_of<string>> find_all_other_characters(string const &h,
935
- string const &n) noexcept {
1001
+ template <typename string_type_>
1002
+ range_matches<string_type_, matcher_find_first_not_of<string_type_>> find_all_other_characters(
1003
+ string_type_ const &h, string_type_ const &n) noexcept {
936
1004
  return {h, n};
937
1005
  }
938
1006
 
939
1007
  /**
940
1008
  * @brief Find all characters except the ones in the second string in @b reverse order.
941
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
1009
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
942
1010
  */
943
- template <typename string>
944
- range_rmatches<string, matcher_find_last_not_of<string>> rfind_all_other_characters(string const &h,
945
- string const &n) noexcept {
1011
+ template <typename string_type_>
1012
+ range_rmatches<string_type_, matcher_find_last_not_of<string_type_>> rfind_all_other_characters(
1013
+ string_type_ const &h, string_type_ const &n) noexcept {
946
1014
  return {h, n};
947
1015
  }
948
1016
 
949
1017
  /**
950
1018
  * @brief Splits a string around every @b non-overlapping inclusion of the second string.
951
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
1019
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
952
1020
  */
953
- template <typename string>
954
- range_splits<string, matcher_find<string, exclude_overlaps_type>> split(string const &h, string const &n) noexcept {
1021
+ template <typename string_type_>
1022
+ range_splits<string_type_, matcher_find<string_type_, exclude_overlaps_type>> split(string_type_ const &h,
1023
+ string_type_ const &n) noexcept {
955
1024
  return {h, n};
956
1025
  }
957
1026
 
958
1027
  /**
959
1028
  * @brief Splits a string around every @b non-overlapping inclusion of the second string in @b reverse order.
960
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
1029
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
961
1030
  */
962
- template <typename string>
963
- range_rsplits<string, matcher_rfind<string, exclude_overlaps_type>> rsplit(string const &h, string const &n) noexcept {
1031
+ template <typename string_type_>
1032
+ range_rsplits<string_type_, matcher_rfind<string_type_, exclude_overlaps_type>> rsplit(string_type_ const &h,
1033
+ string_type_ const &n) noexcept {
964
1034
  return {h, n};
965
1035
  }
966
1036
 
967
1037
  /**
968
1038
  * @brief Splits a string around every character from the second string.
969
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
1039
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
970
1040
  */
971
- template <typename string>
972
- range_splits<string, matcher_find_first_of<string>> split_characters(string const &h, string const &n) noexcept {
1041
+ template <typename string_type_>
1042
+ range_splits<string_type_, matcher_find_first_of<string_type_>> split_characters(string_type_ const &h,
1043
+ string_type_ const &n) noexcept {
973
1044
  return {h, n};
974
1045
  }
975
1046
 
976
1047
  /**
977
1048
  * @brief Splits a string around every character from the second string in @b reverse order.
978
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
1049
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
979
1050
  */
980
- template <typename string>
981
- range_rsplits<string, matcher_find_last_of<string>> rsplit_characters(string const &h, string const &n) noexcept {
1051
+ template <typename string_type_>
1052
+ range_rsplits<string_type_, matcher_find_last_of<string_type_>> rsplit_characters(string_type_ const &h,
1053
+ string_type_ const &n) noexcept {
982
1054
  return {h, n};
983
1055
  }
984
1056
 
985
1057
  /**
986
1058
  * @brief Splits a string around every character except the ones from the second string.
987
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
1059
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
988
1060
  */
989
- template <typename string>
990
- range_splits<string, matcher_find_first_not_of<string>> split_other_characters(string const &h,
991
- string const &n) noexcept {
1061
+ template <typename string_type_>
1062
+ range_splits<string_type_, matcher_find_first_not_of<string_type_>> split_other_characters(
1063
+ string_type_ const &h, string_type_ const &n) noexcept {
992
1064
  return {h, n};
993
1065
  }
994
1066
 
995
1067
  /**
996
1068
  * @brief Splits a string around every character except the ones from the second string in @b reverse order.
997
- * @tparam string A string-like type, ideally a view, like StringZilla or STL `string_view`.
1069
+ * @tparam string_type_ A string-like type, ideally a view, like StringZilla or STL `string_view`.
998
1070
  */
999
- template <typename string>
1000
- range_rsplits<string, matcher_find_last_not_of<string>> rsplit_other_characters(string const &h,
1001
- string const &n) noexcept {
1071
+ template <typename string_type_>
1072
+ range_rsplits<string_type_, matcher_find_last_not_of<string_type_>> rsplit_other_characters(
1073
+ string_type_ const &h, string_type_ const &n) noexcept {
1002
1074
  return {h, n};
1003
1075
  }
1004
1076
 
@@ -1138,17 +1210,17 @@ class reversed_iterator_for {
1138
1210
  * @see https://en.wikipedia.org/wiki/Expression_templates
1139
1211
  * @sa `concatenate` function for usage examples.
1140
1212
  */
1141
- template <typename first_type, typename second_type>
1213
+ template <typename first_type_, typename second_type_>
1142
1214
  struct concatenation {
1143
1215
 
1144
- using value_type = typename first_type::value_type;
1216
+ using value_type = typename first_type_::value_type;
1145
1217
  using pointer = value_type *;
1146
1218
  using const_pointer = value_type const *;
1147
- using size_type = typename first_type::size_type;
1148
- using difference_type = typename first_type::difference_type;
1219
+ using size_type = typename first_type_::size_type;
1220
+ using difference_type = typename first_type_::difference_type;
1149
1221
 
1150
- first_type first;
1151
- second_type second;
1222
+ first_type_ first;
1223
+ second_type_ second;
1152
1224
 
1153
1225
  std::size_t size() const noexcept { return first.size() + second.size(); }
1154
1226
  std::size_t length() const noexcept { return first.size() + second.size(); }
@@ -1168,7 +1240,7 @@ struct concatenation {
1168
1240
  }
1169
1241
 
1170
1242
  template <typename last_type>
1171
- concatenation<concatenation<first_type, second_type>, last_type> operator|(last_type &&last) const {
1243
+ concatenation<concatenation<first_type_, second_type_>, last_type> operator|(last_type &&last) const {
1172
1244
  return {*this, last};
1173
1245
  }
1174
1246
  };
@@ -1268,9 +1340,9 @@ class basic_string_slice {
1268
1340
  * @brief Formatted output function for compatibility with STL's `std::basic_ostream`.
1269
1341
  * @throw `std::ios_base::failure` if an exception occurred during output.
1270
1342
  */
1271
- template <typename stream_traits>
1272
- friend std::basic_ostream<value_type, stream_traits> &operator<<(std::basic_ostream<value_type, stream_traits> &os,
1273
- string_slice const &str) noexcept(false) {
1343
+ template <typename stream_traits_>
1344
+ friend std::basic_ostream<value_type, stream_traits_> &operator<<(
1345
+ std::basic_ostream<value_type, stream_traits_> &os, string_slice const &str) noexcept(false) {
1274
1346
  return os.write(str.data(), str.size());
1275
1347
  }
1276
1348
 
@@ -2016,8 +2088,8 @@ class basic_string {
2016
2088
  */
2017
2089
  static_assert(std::is_empty<allocator_type_>::value, "We currently only support stateless allocators");
2018
2090
 
2019
- template <typename allocator_callback>
2020
- static status_t _with_alloc(allocator_callback &&callback) noexcept {
2091
+ template <typename allocator_callback_>
2092
+ static status_t _with_alloc(allocator_callback_ &&callback) noexcept {
2021
2093
  return ashvardanian::stringzilla::_with_alloc<allocator_type_>(callback);
2022
2094
  }
2023
2095
 
@@ -2185,9 +2257,9 @@ class basic_string {
2185
2257
  * @brief Formatted output function for compatibility with STL's `std::basic_ostream`.
2186
2258
  * @throw `std::ios_base::failure` if an exception occurred during output.
2187
2259
  */
2188
- template <typename stream_traits>
2189
- friend std::basic_ostream<value_type, stream_traits> &operator<<(std::basic_ostream<value_type, stream_traits> &os,
2190
- basic_string const &str) noexcept(false) {
2260
+ template <typename stream_traits_>
2261
+ friend std::basic_ostream<value_type, stream_traits_> &operator<<(
2262
+ std::basic_ostream<value_type, stream_traits_> &os, basic_string const &str) noexcept(false) {
2191
2263
  return os.write(str.data(), str.size());
2192
2264
  }
2193
2265
 
@@ -2199,8 +2271,8 @@ class basic_string {
2199
2271
 
2200
2272
  #endif
2201
2273
 
2202
- template <typename first_type, typename second_type>
2203
- explicit basic_string(concatenation<first_type, second_type> const &expression) noexcept(false) {
2274
+ template <typename first_type_, typename second_type_>
2275
+ explicit basic_string(concatenation<first_type_, second_type_> const &expression) noexcept(false) {
2204
2276
  raise(_with_alloc([&](sz_alloc_type &alloc) {
2205
2277
  sz_ptr_t ptr = sz_string_init_length(&string_, expression.length(), &alloc);
2206
2278
  if (!ptr) return sz_bad_alloc_k;
@@ -2209,8 +2281,8 @@ class basic_string {
2209
2281
  }));
2210
2282
  }
2211
2283
 
2212
- template <typename first_type, typename second_type>
2213
- basic_string &operator=(concatenation<first_type, second_type> const &expression) noexcept(false) {
2284
+ template <typename first_type_, typename second_type_>
2285
+ basic_string &operator=(concatenation<first_type_, second_type_> const &expression) noexcept(false) {
2214
2286
  if (!try_assign(expression)) throw std::bad_alloc();
2215
2287
  return *this;
2216
2288
  }
@@ -2772,8 +2844,8 @@ class basic_string {
2772
2844
  * @param[in] other The concatenation object representing the sequence to assign.
2773
2845
  * @return `true` if the assignment was successful, `false` otherwise.
2774
2846
  */
2775
- template <typename first_type, typename second_type>
2776
- bool try_assign(concatenation<first_type, second_type> const &other) noexcept;
2847
+ template <typename first_type_, typename second_type_>
2848
+ bool try_assign(concatenation<first_type_, second_type_> const &other) noexcept;
2777
2849
 
2778
2850
  /**
2779
2851
  * @brief Attempts to add a single character to the end of the string.
@@ -3722,8 +3794,8 @@ bool basic_string<char_type_, allocator_>::try_replace_all_(pattern_type pattern
3722
3794
  }
3723
3795
 
3724
3796
  template <typename char_type_, typename allocator_>
3725
- template <typename first_type, typename second_type>
3726
- bool basic_string<char_type_, allocator_>::try_assign(concatenation<first_type, second_type> const &other) noexcept {
3797
+ template <typename first_type_, typename second_type_>
3798
+ bool basic_string<char_type_, allocator_>::try_assign(concatenation<first_type_, second_type_> const &other) noexcept {
3727
3799
  // We can't just assign the other string state, as its start address may be somewhere else on the stack.
3728
3800
  sz_ptr_t string_start;
3729
3801
  sz_size_t string_length;
@@ -3809,25 +3881,25 @@ struct hash {
3809
3881
  };
3810
3882
 
3811
3883
  /** @brief SFINAE-type used to infer the resulting type of concatenating multiple string together. */
3812
- template <typename... args_types>
3884
+ template <typename... args_types_>
3813
3885
  struct concatenation_result {};
3814
3886
 
3815
- template <typename first_type, typename second_type>
3816
- struct concatenation_result<first_type, second_type> {
3817
- using type = concatenation<first_type, second_type>;
3887
+ template <typename first_type_, typename second_type_>
3888
+ struct concatenation_result<first_type_, second_type_> {
3889
+ using type = concatenation<first_type_, second_type_>;
3818
3890
  };
3819
3891
 
3820
- template <typename first_type, typename... following_types>
3821
- struct concatenation_result<first_type, following_types...> {
3822
- using type = concatenation<first_type, typename concatenation_result<following_types...>::type>;
3892
+ template <typename first_type_, typename... following_types_>
3893
+ struct concatenation_result<first_type_, following_types_...> {
3894
+ using type = concatenation<first_type_, typename concatenation_result<following_types_...>::type>;
3823
3895
  };
3824
3896
 
3825
3897
  /**
3826
3898
  * @brief Concatenates two strings into a template expression.
3827
3899
  * @sa `concatenation` class for more details.
3828
3900
  */
3829
- template <typename first_type, typename second_type>
3830
- concatenation<first_type, second_type> concatenate(first_type &&first, second_type &&second) noexcept(false) {
3901
+ template <typename first_type_, typename second_type_>
3902
+ concatenation<first_type_, second_type_> concatenate(first_type_ &&first, second_type_ &&second) noexcept(false) {
3831
3903
  return {first, second};
3832
3904
  }
3833
3905
 
@@ -3835,9 +3907,9 @@ concatenation<first_type, second_type> concatenate(first_type &&first, second_ty
3835
3907
  * @brief Concatenates two or more strings into a template expression.
3836
3908
  * @sa `concatenation` class for more details.
3837
3909
  */
3838
- template <typename first_type, typename second_type, typename... following_types>
3839
- typename concatenation_result<first_type, second_type, following_types...>::type concatenate(
3840
- first_type &&first, second_type &&second, following_types &&...following) noexcept(false) {
3910
+ template <typename first_type_, typename second_type_, typename... following_types_>
3911
+ typename concatenation_result<first_type_, second_type_, following_types_...>::type concatenate(
3912
+ first_type_ &&first, second_type_ &&second, following_types_ &&...following) noexcept(false) {
3841
3913
  // Fold expression like the one below would result in faster compile times,
3842
3914
  // but would incur the penalty of additional `if`-statements in every `append` call.
3843
3915
  // Moreover, those are only supported in C++17 and later.
@@ -3846,10 +3918,10 @@ typename concatenation_result<first_type, second_type, following_types...>::type
3846
3918
  // result.reserve(total_size);
3847
3919
  // (result.append(strings), ...);
3848
3920
  return ashvardanian::stringzilla::concatenate( //
3849
- std::forward<first_type>(first),
3921
+ std::forward<first_type_>(first),
3850
3922
  ashvardanian::stringzilla::concatenate( //
3851
- std::forward<second_type>(second), //
3852
- std::forward<following_types>(following)...));
3923
+ std::forward<second_type_>(second), //
3924
+ std::forward<following_types_>(following)...));
3853
3925
  }
3854
3926
 
3855
3927
  /**
@@ -541,8 +541,7 @@ typedef enum sz_status_t {
541
541
  sz_invalid_utf8_k = -12,
542
542
  /** For algorithms that take collections of unique elements, this status indicates presence of duplicates. */
543
543
  sz_contains_duplicates_k = -13,
544
- /** For algorithms dealing with large inputs, this error reports the need to upcast the logic to larger types.
545
- */
544
+ /** For algorithms dealing with large inputs, this error reports the need to upcast the logic to larger types. */
546
545
  sz_overflow_risk_k = -14,
547
546
  /** For algorithms with multi-stage pipelines indicates input/output size mismatch. */
548
547
  sz_unexpected_dimensions_k = -15,
@@ -841,6 +840,7 @@ typedef union sz_u16_vec_t {
841
840
  */
842
841
  typedef union sz_u32_vec_t {
843
842
  sz_u32_t u32;
843
+ sz_i32_t i32;
844
844
  sz_u16_t u16s[2];
845
845
  sz_i16_t i16s[2];
846
846
  sz_u8_t u8s[4];
@@ -853,6 +853,7 @@ typedef union sz_u32_vec_t {
853
853
  */
854
854
  typedef union sz_u64_vec_t {
855
855
  sz_u64_t u64;
856
+ sz_i64_t i64;
856
857
  sz_u32_t u32s[2];
857
858
  sz_i32_t i32s[2];
858
859
  sz_u16_t u16s[4];
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stringzillas-cuda
3
- Version: 4.2.2
3
+ Version: 4.2.3
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.2.3
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.
@@ -0,0 +1 @@
1
+ stringzilla==4.2.3
@@ -1 +0,0 @@
1
- 4.2.2
@@ -1 +0,0 @@
1
- stringzilla==4.2.2