1use std::mem;
8
9use rayon::prelude::*;
10
11use crate::{run_rayon_with_threads, SyncMutPtr};
12
13pub type SaSint = i32;
14pub type SaUint = u32;
15
16pub const ALPHABET_SIZE: usize = 1usize << 16;
17const SAINT_MAX: SaSint = SaSint::MAX;
18const SAINT_MIN: SaSint = SaSint::MIN;
19const SAINT_BIT: u32 = 32;
20const SUFFIX_GROUP_BIT: u32 = SAINT_BIT - 1;
21const SUFFIX_GROUP_MARKER: SaSint = 1_i32 << (SUFFIX_GROUP_BIT - 1);
22const LIBSAIS_FLAGS_BWT: SaSint = 1;
23const LIBSAIS_FLAGS_GSA: SaSint = 2;
24const LIBSAIS_LOCAL_BUFFER_SIZE: usize = 2000;
25const UNBWT_FASTBITS: usize = 17;
26const PER_THREAD_CACHE_SIZE: usize = 2_097_184;
27
28#[repr(C)]
29#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
30struct ThreadCache {
31 symbol: SaSint,
32 index: SaSint,
33}
34
35#[derive(Clone, Debug, Default, PartialEq, Eq)]
36pub struct ThreadState {
37 position: SaSint,
38 m: SaSint,
39 last_lms_suffix: SaSint,
40 count: SaSint,
41 buckets: Vec<SaSint>,
42 cache: Vec<ThreadCache>,
43 cache_entries: usize,
44}
45
46#[derive(Clone, Debug, Default, PartialEq, Eq)]
47pub struct Context {
48 buckets: Vec<SaSint>,
49 thread_state: Option<Vec<ThreadState>>,
50 threads: SaSint,
51}
52
53#[derive(Clone, Debug, Default, PartialEq, Eq)]
54pub struct UnbwtContext {
55 bucket2: Vec<usize>,
56 fastbits: Vec<u16>,
57 buckets: Option<Vec<usize>>,
58 threads: SaSint,
59}
60
61pub fn create_ctx() -> Option<Context> {
67 create_ctx_main(1)
68}
69
70pub fn create_ctx_omp(threads: SaSint) -> Option<Context> {
78 if threads < 0 {
79 None
80 } else {
81 create_ctx_main(normalize_threads(threads))
82 }
83}
84
85pub fn free_ctx(_ctx: Context) {}
87
88pub fn unbwt_create_ctx() -> Option<UnbwtContext> {
94 unbwt_create_ctx_main(1)
95}
96
97pub fn unbwt_create_ctx_omp(threads: SaSint) -> Option<UnbwtContext> {
105 if threads < 0 {
106 None
107 } else {
108 unbwt_create_ctx_main(normalize_threads(threads))
109 }
110}
111
112pub fn unbwt_free_ctx(_ctx: UnbwtContext) {}
114
115fn normalize_threads(threads: SaSint) -> SaSint {
116 if threads > 0 {
117 threads
118 } else {
119 1
120 }
121}
122
123fn align_up(value: usize, alignment: usize) -> usize {
124 (value + (alignment - 1)) & !(alignment - 1)
125}
126
127fn alloc_thread_state(threads: SaSint) -> Option<Vec<ThreadState>> {
128 let threads = usize::try_from(threads).ok()?;
129 let mut thread_state = Vec::with_capacity(threads);
130 for _ in 0..threads {
131 thread_state.push(ThreadState {
132 position: 0,
133 m: 0,
134 last_lms_suffix: 0,
135 count: 0,
136 buckets: vec![0; 4 * ALPHABET_SIZE],
137 cache: vec![ThreadCache::default(); PER_THREAD_CACHE_SIZE],
138 cache_entries: PER_THREAD_CACHE_SIZE,
139 });
140 }
141 Some(thread_state)
142}
143
144fn create_ctx_main(threads: SaSint) -> Option<Context> {
145 let buckets = vec![0; 8 * ALPHABET_SIZE];
146 let thread_state = if threads > 1 {
147 Some(alloc_thread_state(threads)?)
148 } else {
149 None
150 };
151
152 Some(Context {
153 buckets,
154 thread_state,
155 threads,
156 })
157}
158
159fn unbwt_create_ctx_main(threads: SaSint) -> Option<UnbwtContext> {
160 let bucket2 = vec![0; ALPHABET_SIZE];
161 let fastbits = vec![0; 1 + (1 << UNBWT_FASTBITS)];
162 let buckets = if threads > 1 {
163 Some(vec![0; usize::try_from(threads).ok()? * ALPHABET_SIZE])
164 } else {
165 None
166 };
167
168 Some(UnbwtContext {
169 bucket2,
170 fastbits,
171 buckets,
172 threads,
173 })
174}
175
176fn fill_freq(t: &[u16], freq: Option<&mut [SaSint]>) {
177 if let Some(freq) = freq {
178 freq[..ALPHABET_SIZE].fill(0);
179 for &symbol in t {
180 freq[symbol as usize] += 1;
181 }
182 }
183}
184
185fn buckets_index4(c: usize, s: usize) -> usize {
186 (c << 2) + s
187}
188
189fn buckets_index2(c: usize, s: usize) -> usize {
190 (c << 1) + s
191}
192
193fn place_cached_suffixes(
194 sa: &mut [SaSint],
195 cache: &[ThreadCache],
196 block_start: SaSint,
197 block_size: SaSint,
198) {
199 let start = usize::try_from(block_start).expect("block_start must be non-negative");
200 let len = usize::try_from(block_size).expect("block_size must be non-negative");
201 let entries = if cache.len() >= start + len {
202 &cache[start..start + len]
203 } else {
204 &cache[..len]
205 };
206
207 for entry in entries {
208 sa[entry.symbol as usize] = entry.index;
209 }
210}
211
212fn compact_and_place_cached_suffixes(
213 sa: &mut [SaSint],
214 cache: &mut [ThreadCache],
215 block_start: SaSint,
216 block_size: SaSint,
217) {
218 let start = usize::try_from(block_start).expect("block_start must be non-negative");
219 let len = usize::try_from(block_size).expect("block_size must be non-negative");
220 let read_start = if cache.len() >= start + len { start } else { 0 };
221 let read_end = read_start + len;
222
223 let mut write = read_start;
224 for read in read_start..read_end {
225 let entry = cache[read];
226 if entry.symbol >= 0 {
227 cache[write] = entry;
228 write += 1;
229 }
230 }
231 place_cached_suffixes(sa, cache, block_start, (write - read_start) as SaSint);
232}
233
234fn count_negative_marked_suffixes(
235 sa: &[SaSint],
236 block_start: SaSint,
237 block_size: SaSint,
238) -> SaSint {
239 let start = block_start as usize;
240 let end = start + block_size as usize;
241 sa[start..end].iter().filter(|&&value| value < 0).count() as SaSint
242}
243
244fn count_zero_marked_suffixes(sa: &[SaSint], block_start: SaSint, block_size: SaSint) -> SaSint {
245 let start = block_start as usize;
246 let end = start + block_size as usize;
247 sa[start..end].iter().filter(|&&value| value == 0).count() as SaSint
248}
249
250fn accumulate_counts_s32_n(
251 buckets: &mut [SaSint],
252 bucket00: usize,
253 bucket_size: usize,
254 bucket_stride: usize,
255 num_buckets: usize,
256) {
257 for s in 0..bucket_size {
258 let mut sum = buckets[bucket00 + s];
259 for bucket in 1..num_buckets {
260 sum += buckets[bucket00 - bucket * bucket_stride + s];
261 }
262 buckets[bucket00 + s] = sum;
263 }
264}
265
266fn accumulate_counts_s32_2(
267 buckets: &mut [SaSint],
268 bucket00: usize,
269 bucket_size: usize,
270 bucket_stride: usize,
271) {
272 accumulate_counts_s32_n(buckets, bucket00, bucket_size, bucket_stride, 2);
273}
274
275fn accumulate_counts_s32_3(
276 buckets: &mut [SaSint],
277 bucket00: usize,
278 bucket_size: usize,
279 bucket_stride: usize,
280) {
281 accumulate_counts_s32_n(buckets, bucket00, bucket_size, bucket_stride, 3);
282}
283
284fn accumulate_counts_s32_4(
285 buckets: &mut [SaSint],
286 bucket00: usize,
287 bucket_size: usize,
288 bucket_stride: usize,
289) {
290 accumulate_counts_s32_n(buckets, bucket00, bucket_size, bucket_stride, 4);
291}
292
293fn accumulate_counts_s32_5(
294 buckets: &mut [SaSint],
295 bucket00: usize,
296 bucket_size: usize,
297 bucket_stride: usize,
298) {
299 accumulate_counts_s32_n(buckets, bucket00, bucket_size, bucket_stride, 5);
300}
301
302fn accumulate_counts_s32_6(
303 buckets: &mut [SaSint],
304 bucket00: usize,
305 bucket_size: usize,
306 bucket_stride: usize,
307) {
308 accumulate_counts_s32_n(buckets, bucket00, bucket_size, bucket_stride, 6);
309}
310
311fn accumulate_counts_s32_7(
312 buckets: &mut [SaSint],
313 bucket00: usize,
314 bucket_size: usize,
315 bucket_stride: usize,
316) {
317 accumulate_counts_s32_n(buckets, bucket00, bucket_size, bucket_stride, 7);
318}
319
320fn accumulate_counts_s32_8(
321 buckets: &mut [SaSint],
322 bucket00: usize,
323 bucket_size: usize,
324 bucket_stride: usize,
325) {
326 accumulate_counts_s32_n(buckets, bucket00, bucket_size, bucket_stride, 8);
327}
328
329fn accumulate_counts_s32_9(
330 buckets: &mut [SaSint],
331 bucket00: usize,
332 bucket_size: usize,
333 bucket_stride: usize,
334) {
335 accumulate_counts_s32_n(buckets, bucket00, bucket_size, bucket_stride, 9);
336}
337
338fn accumulate_counts_s32(
339 buckets: &mut [SaSint],
340 bucket00: usize,
341 bucket_size: usize,
342 bucket_stride: usize,
343 mut num_buckets: usize,
344) {
345 while num_buckets >= 9 {
346 accumulate_counts_s32_9(
347 buckets,
348 bucket00 - (num_buckets - 9) * bucket_stride,
349 bucket_size,
350 bucket_stride,
351 );
352 num_buckets -= 8;
353 }
354
355 match num_buckets {
356 2 => accumulate_counts_s32_2(buckets, bucket00, bucket_size, bucket_stride),
357 3 => accumulate_counts_s32_3(buckets, bucket00, bucket_size, bucket_stride),
358 4 => accumulate_counts_s32_4(buckets, bucket00, bucket_size, bucket_stride),
359 5 => accumulate_counts_s32_5(buckets, bucket00, bucket_size, bucket_stride),
360 6 => accumulate_counts_s32_6(buckets, bucket00, bucket_size, bucket_stride),
361 7 => accumulate_counts_s32_7(buckets, bucket00, bucket_size, bucket_stride),
362 8 => accumulate_counts_s32_8(buckets, bucket00, bucket_size, bucket_stride),
363 _ => {}
364 }
365}
366
367fn flip_suffix_markers_omp(sa: &mut [SaSint], l: SaSint, threads: SaSint) {
368 let len = usize::try_from(l).expect("l must be non-negative");
369 let omp_num_threads = if threads > 1 && l >= 65_536 {
370 usize::try_from(threads).expect("threads must be non-negative")
371 } else {
372 1
373 };
374 let omp_block_stride = (len / omp_num_threads) & !15usize;
375 if omp_num_threads > 1 {
376 let chunk_size = omp_block_stride.max(16);
377 run_rayon_with_threads(omp_num_threads, || {
378 sa[..len].par_chunks_mut(chunk_size).for_each(|chunk| {
379 for value in chunk {
380 *value ^= SAINT_MIN;
381 }
382 });
383 });
384 return;
385 }
386 for value in &mut sa[..len] {
388 *value ^= SAINT_MIN;
389 }
390}
391
392fn gather_lms_suffixes_32s(t: &[SaSint], sa: &mut [SaSint], n: SaSint) -> SaSint {
393 let mut i = n - 2;
394 let mut m = n - 1;
395 let mut f0 = 1usize;
396 let mut f1: usize;
397 let mut c0 = t[(n - 1) as usize] as isize;
398 let mut c1: isize;
399
400 while i >= 3 {
401 c1 = t[i as usize] as isize;
402 f1 = usize::from(c1 > c0 - f0 as isize);
403 sa[m as usize] = i + 1;
404 m -= (f1 & !f0) as SaSint;
405
406 c0 = t[(i - 1) as usize] as isize;
407 f0 = usize::from(c0 > c1 - f1 as isize);
408 sa[m as usize] = i;
409 m -= (f0 & !f1) as SaSint;
410
411 c1 = t[(i - 2) as usize] as isize;
412 f1 = usize::from(c1 > c0 - f0 as isize);
413 sa[m as usize] = i - 1;
414 m -= (f1 & !f0) as SaSint;
415
416 c0 = t[(i - 3) as usize] as isize;
417 f0 = usize::from(c0 > c1 - f1 as isize);
418 sa[m as usize] = i - 2;
419 m -= (f0 & !f1) as SaSint;
420
421 i -= 4;
422 }
423
424 while i >= 0 {
425 c1 = c0;
426 c0 = t[i as usize] as isize;
427 f1 = f0;
428 f0 = usize::from(c0 > c1 - f1 as isize);
429 sa[m as usize] = i + 1;
430 m -= (f0 & !f1) as SaSint;
431 i -= 1;
432 }
433
434 n - 1 - m
435}
436
437fn gather_compacted_lms_suffixes_32s(t: &[SaSint], sa: &mut [SaSint], n: SaSint) -> SaSint {
438 let mut i = n - 2;
439 let mut m = n - 1;
440 let mut f0 = 1usize;
441 let mut f1: usize;
442 let mut c0 = t[(n - 1) as usize] as isize;
443 let mut c1: isize;
444
445 while i >= 3 {
446 c1 = t[i as usize] as isize;
447 f1 = usize::from(c1 > c0 - f0 as isize);
448 sa[m as usize] = i + 1;
449 m -= (f1 & !f0 & usize::from(c0 >= 0)) as SaSint;
450
451 c0 = t[(i - 1) as usize] as isize;
452 f0 = usize::from(c0 > c1 - f1 as isize);
453 sa[m as usize] = i;
454 m -= (f0 & !f1 & usize::from(c1 >= 0)) as SaSint;
455
456 c1 = t[(i - 2) as usize] as isize;
457 f1 = usize::from(c1 > c0 - f0 as isize);
458 sa[m as usize] = i - 1;
459 m -= (f1 & !f0 & usize::from(c0 >= 0)) as SaSint;
460
461 c0 = t[(i - 3) as usize] as isize;
462 f0 = usize::from(c0 > c1 - f1 as isize);
463 sa[m as usize] = i - 2;
464 m -= (f0 & !f1 & usize::from(c1 >= 0)) as SaSint;
465
466 i -= 4;
467 }
468
469 while i >= 0 {
470 c1 = c0;
471 c0 = t[i as usize] as isize;
472 f1 = f0;
473 f0 = usize::from(c0 > c1 - f1 as isize);
474 sa[m as usize] = i + 1;
475 m -= (f0 & !f1 & usize::from(c1 >= 0)) as SaSint;
476 i -= 1;
477 }
478
479 n - 1 - m
480}
481
482fn count_lms_suffixes_32s_4k(t: &[SaSint], n: SaSint, k: SaSint, buckets: &mut [SaSint]) {
483 buckets[..4 * k as usize].fill(0);
484 let mut i = n - 2;
485 let mut f0 = 1usize;
486 let mut f1: usize;
487 let mut c0 = t[(n - 1) as usize] as isize;
488 let mut c1: isize;
489
490 while i >= 3 {
491 c1 = t[i as usize] as isize;
492 f1 = usize::from(c1 > c0 - f0 as isize);
493 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
494
495 c0 = t[(i - 1) as usize] as isize;
496 f0 = usize::from(c0 > c1 - f1 as isize);
497 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
498
499 c1 = t[(i - 2) as usize] as isize;
500 f1 = usize::from(c1 > c0 - f0 as isize);
501 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
502
503 c0 = t[(i - 3) as usize] as isize;
504 f0 = usize::from(c0 > c1 - f1 as isize);
505 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
506
507 i -= 4;
508 }
509
510 while i >= 0 {
511 c1 = c0;
512 c0 = t[i as usize] as isize;
513 f1 = f0;
514 f0 = usize::from(c0 > c1 - f1 as isize);
515 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
516 i -= 1;
517 }
518
519 buckets[buckets_index4(c0 as usize, f0 + f0)] += 1;
520}
521
522fn count_lms_suffixes_32s_2k(t: &[SaSint], n: SaSint, k: SaSint, buckets: &mut [SaSint]) {
523 buckets[..2 * k as usize].fill(0);
524 let mut i = n - 2;
525 let mut f0 = 1usize;
526 let mut f1: usize;
527 let mut c0 = t[(n - 1) as usize] as isize;
528 let mut c1: isize;
529
530 while i >= 3 {
531 c1 = t[i as usize] as isize;
532 f1 = usize::from(c1 > c0 - f0 as isize);
533 buckets[buckets_index2(c0 as usize, f1 & !f0)] += 1;
534
535 c0 = t[(i - 1) as usize] as isize;
536 f0 = usize::from(c0 > c1 - f1 as isize);
537 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
538
539 c1 = t[(i - 2) as usize] as isize;
540 f1 = usize::from(c1 > c0 - f0 as isize);
541 buckets[buckets_index2(c0 as usize, f1 & !f0)] += 1;
542
543 c0 = t[(i - 3) as usize] as isize;
544 f0 = usize::from(c0 > c1 - f1 as isize);
545 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
546
547 i -= 4;
548 }
549
550 while i >= 0 {
551 c1 = c0;
552 c0 = t[i as usize] as isize;
553 f1 = f0;
554 f0 = usize::from(c0 > c1 - f1 as isize);
555 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
556 i -= 1;
557 }
558
559 buckets[buckets_index2(c0 as usize, 0)] += 1;
560}
561
562fn count_compacted_lms_suffixes_32s_2k(t: &[SaSint], n: SaSint, k: SaSint, buckets: &mut [SaSint]) {
563 buckets[..2 * k as usize].fill(0);
564 let mut i = n - 2;
565 let mut f0 = 1usize;
566 let mut f1: usize;
567 let mut c0 = t[(n - 1) as usize] as isize;
568 let mut c1: isize;
569
570 while i >= 3 {
571 c1 = t[i as usize] as isize;
572 f1 = usize::from(c1 > c0 - f0 as isize);
573 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, f1 & !f0)] += 1;
574
575 c0 = t[(i - 1) as usize] as isize;
576 f0 = usize::from(c0 > c1 - f1 as isize);
577 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
578
579 c1 = t[(i - 2) as usize] as isize;
580 f1 = usize::from(c1 > c0 - f0 as isize);
581 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, f1 & !f0)] += 1;
582
583 c0 = t[(i - 3) as usize] as isize;
584 f0 = usize::from(c0 > c1 - f1 as isize);
585 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
586
587 i -= 4;
588 }
589
590 while i >= 0 {
591 c1 = c0;
592 c0 = t[i as usize] as isize;
593 f1 = f0;
594 f0 = usize::from(c0 > c1 - f1 as isize);
595 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
596 i -= 1;
597 }
598
599 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, 0)] += 1;
600}
601
602fn get_bucket_stride(free_space: SaSint, bucket_size: SaSint, num_buckets: SaSint) -> SaSint {
603 let bucket_size_1024 = (bucket_size + 1023) & !1023;
604 if free_space / (num_buckets - 1) >= bucket_size_1024 {
605 return bucket_size_1024;
606 }
607 let bucket_size_16 = (bucket_size + 15) & !15;
608 if free_space / (num_buckets - 1) >= bucket_size_16 {
609 return bucket_size_16;
610 }
611 bucket_size
612}
613
614fn count_and_gather_lms_suffixes_32s_4k(
615 t: &[SaSint],
616 sa: &mut [SaSint],
617 n: SaSint,
618 k: SaSint,
619 buckets: &mut [SaSint],
620 omp_block_start: isize,
621 omp_block_size: isize,
622) -> SaSint {
623 buckets[..4 * k as usize].fill(0);
624 let mut m = omp_block_start + omp_block_size - 1;
625
626 if omp_block_size > 0 {
627 let mut j = m + 1;
628 let mut c0 = t[m as usize] as isize;
629 let mut c1 = -1isize;
630 while j < n as isize {
631 c1 = t[j as usize] as isize;
632 if c1 != c0 {
633 break;
634 }
635 j += 1;
636 }
637
638 let mut f0 = usize::from(c0 >= c1);
639 let mut f1: usize;
640 let mut i = m - 1;
641 j = omp_block_start + 64 + 3;
642 while i >= j {
643 c1 = t[i as usize] as isize;
644 f1 = usize::from(c1 > c0 - f0 as isize);
645 sa[m as usize] = (i + 1) as SaSint;
646 m -= (f1 & !f0) as isize;
647 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
648
649 c0 = t[(i - 1) as usize] as isize;
650 f0 = usize::from(c0 > c1 - f1 as isize);
651 sa[m as usize] = i as SaSint;
652 m -= (f0 & !f1) as isize;
653 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
654
655 c1 = t[(i - 2) as usize] as isize;
656 f1 = usize::from(c1 > c0 - f0 as isize);
657 sa[m as usize] = (i - 1) as SaSint;
658 m -= (f1 & !f0) as isize;
659 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
660
661 c0 = t[(i - 3) as usize] as isize;
662 f0 = usize::from(c0 > c1 - f1 as isize);
663 sa[m as usize] = (i - 2) as SaSint;
664 m -= (f0 & !f1) as isize;
665 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
666
667 i -= 4;
668 }
669
670 j -= 64 + 3;
671 while i >= j {
672 c1 = c0;
673 c0 = t[i as usize] as isize;
674 f1 = f0;
675 f0 = usize::from(c0 > c1 - f1 as isize);
676 sa[m as usize] = (i + 1) as SaSint;
677 m -= (f0 & !f1) as isize;
678 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
679 i -= 1;
680 }
681
682 c1 = if i >= 0 { t[i as usize] as isize } else { -1 };
683 f1 = usize::from(c1 > c0 - f0 as isize);
684 sa[m as usize] = (i + 1) as SaSint;
685 m -= (f1 & !f0) as isize;
686 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
687 }
688
689 (omp_block_start + omp_block_size - 1 - m) as SaSint
690}
691
692fn count_and_gather_lms_suffixes_32s_2k(
693 t: &[SaSint],
694 sa: &mut [SaSint],
695 n: SaSint,
696 k: SaSint,
697 buckets: &mut [SaSint],
698 omp_block_start: isize,
699 omp_block_size: isize,
700) -> SaSint {
701 buckets[..2 * k as usize].fill(0);
702 let mut m = omp_block_start + omp_block_size - 1;
703
704 if omp_block_size > 0 {
705 let mut j = m + 1;
706 let mut c0 = t[m as usize] as isize;
707 let mut c1 = -1isize;
708 while j < n as isize {
709 c1 = t[j as usize] as isize;
710 if c1 != c0 {
711 break;
712 }
713 j += 1;
714 }
715
716 let mut f0 = usize::from(c0 >= c1);
717 let mut f1: usize;
718 let mut i = m - 1;
719 j = omp_block_start + 64 + 3;
720 while i >= j {
721 c1 = t[i as usize] as isize;
722 f1 = usize::from(c1 > c0 - f0 as isize);
723 sa[m as usize] = (i + 1) as SaSint;
724 m -= (f1 & !f0) as isize;
725 buckets[buckets_index2(c0 as usize, f1 & !f0)] += 1;
726
727 c0 = t[(i - 1) as usize] as isize;
728 f0 = usize::from(c0 > c1 - f1 as isize);
729 sa[m as usize] = i as SaSint;
730 m -= (f0 & !f1) as isize;
731 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
732
733 c1 = t[(i - 2) as usize] as isize;
734 f1 = usize::from(c1 > c0 - f0 as isize);
735 sa[m as usize] = (i - 1) as SaSint;
736 m -= (f1 & !f0) as isize;
737 buckets[buckets_index2(c0 as usize, f1 & !f0)] += 1;
738
739 c0 = t[(i - 3) as usize] as isize;
740 f0 = usize::from(c0 > c1 - f1 as isize);
741 sa[m as usize] = (i - 2) as SaSint;
742 m -= (f0 & !f1) as isize;
743 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
744
745 i -= 4;
746 }
747
748 j -= 64 + 3;
749 while i >= j {
750 c1 = c0;
751 c0 = t[i as usize] as isize;
752 f1 = f0;
753 f0 = usize::from(c0 > c1 - f1 as isize);
754 sa[m as usize] = (i + 1) as SaSint;
755 m -= (f0 & !f1) as isize;
756 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
757 i -= 1;
758 }
759
760 c1 = if i >= 0 { t[i as usize] as isize } else { -1 };
761 f1 = usize::from(c1 > c0 - f0 as isize);
762 sa[m as usize] = (i + 1) as SaSint;
763 m -= (f1 & !f0) as isize;
764 buckets[buckets_index2(c0 as usize, f1 & !f0)] += 1;
765 }
766
767 (omp_block_start + omp_block_size - 1 - m) as SaSint
768}
769
770fn count_and_gather_compacted_lms_suffixes_32s_2k(
771 t: &[SaSint],
772 sa: &mut [SaSint],
773 n: SaSint,
774 k: SaSint,
775 buckets: &mut [SaSint],
776 omp_block_start: isize,
777 omp_block_size: isize,
778) -> SaSint {
779 buckets[..2 * k as usize].fill(0);
780 let mut m = omp_block_start + omp_block_size - 1;
781
782 if omp_block_size > 0 {
783 let mut j = m + 1;
784 let mut c0 = t[m as usize] as isize;
785 let mut c1 = -1isize;
786 while j < n as isize {
787 c1 = t[j as usize] as isize;
788 if c1 != c0 {
789 break;
790 }
791 j += 1;
792 }
793
794 let mut f0 = usize::from(c0 >= c1);
795 let mut f1: usize;
796 let mut i = m - 1;
797 j = omp_block_start + 64 + 3;
798 while i >= j {
799 c1 = t[i as usize] as isize;
800 f1 = usize::from(c1 > c0 - f0 as isize);
801 sa[m as usize] = (i + 1) as SaSint;
802 m -= (f1 & !f0 & usize::from(c0 >= 0)) as isize;
803 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, f1 & !f0)] += 1;
804
805 c0 = t[(i - 1) as usize] as isize;
806 f0 = usize::from(c0 > c1 - f1 as isize);
807 sa[m as usize] = i as SaSint;
808 m -= (f0 & !f1 & usize::from(c1 >= 0)) as isize;
809 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
810
811 c1 = t[(i - 2) as usize] as isize;
812 f1 = usize::from(c1 > c0 - f0 as isize);
813 sa[m as usize] = (i - 1) as SaSint;
814 m -= (f1 & !f0 & usize::from(c0 >= 0)) as isize;
815 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, f1 & !f0)] += 1;
816
817 c0 = t[(i - 3) as usize] as isize;
818 f0 = usize::from(c0 > c1 - f1 as isize);
819 sa[m as usize] = (i - 2) as SaSint;
820 m -= (f0 & !f1 & usize::from(c1 >= 0)) as isize;
821 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
822
823 i -= 4;
824 }
825
826 j -= 64 + 3;
827 while i >= j {
828 c1 = c0;
829 c0 = t[i as usize] as isize;
830 f1 = f0;
831 f0 = usize::from(c0 > c1 - f1 as isize);
832 sa[m as usize] = (i + 1) as SaSint;
833 m -= (f0 & !f1 & usize::from(c1 >= 0)) as isize;
834 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
835 i -= 1;
836 }
837
838 c1 = if i >= 0 { t[i as usize] as isize } else { -1 };
839 f1 = usize::from(c1 > c0 - f0 as isize);
840 sa[m as usize] = (i + 1) as SaSint;
841 m -= (f1 & !f0 & usize::from(c0 >= 0)) as isize;
842 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, f1 & !f0)] += 1;
843 }
844
845 (omp_block_start + omp_block_size - 1 - m) as SaSint
846}
847
848fn count_and_gather_lms_suffixes_32s_4k_fs_omp(
849 t: &[SaSint],
850 sa: &mut [SaSint],
851 n: SaSint,
852 k: SaSint,
853 buckets: &mut [SaSint],
854 local_buckets: SaSint,
855 threads: SaSint,
856 thread_state: &mut [ThreadState],
857) -> SaSint {
858 if threads == 1 || n < 65_536 {
859 return count_and_gather_lms_suffixes_32s_4k(t, sa, n, k, buckets, 0, n as isize);
860 }
861
862 let thread_count = threads as usize;
863 let n_usize = n as usize;
864 let bucket_size = 4 * k as usize;
865 let block_stride = (n / threads) & !15;
866 let free_space = if local_buckets != 0 {
867 LIBSAIS_LOCAL_BUFFER_SIZE as SaSint
868 } else {
869 buckets.len() as SaSint
870 };
871 let bucket_stride = get_bucket_stride(free_space, 4 * k, threads) as usize;
872 let workspace_len = bucket_size + bucket_stride * thread_count.saturating_sub(1);
873 let mut workspace = vec![0; workspace_len];
874
875 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
876 let block_start = thread as SaSint * block_stride;
877 let block_size = if thread + 1 < thread_count {
878 block_stride
879 } else {
880 n - block_start
881 };
882 let workspace_end = workspace_len - thread * bucket_stride;
883 let workspace_start = workspace_end - bucket_size;
884 state.count = count_and_gather_lms_suffixes_32s_4k(
885 t,
886 sa,
887 n,
888 k,
889 &mut workspace[workspace_start..workspace_end],
890 block_start as isize,
891 block_size as isize,
892 );
893 state.position = block_start + block_size;
894 }
895
896 let mut m = 0usize;
897 for thread in (0..thread_count).rev() {
898 let count =
899 usize::try_from(thread_state[thread].count).expect("count must be non-negative");
900 m += count;
901 if thread + 1 != thread_count && count > 0 {
902 let src_end = usize::try_from(thread_state[thread].position)
903 .expect("position must be non-negative");
904 let src_start = src_end - count;
905 let dst_start = n_usize - m;
906 sa.copy_within(src_start..src_end, dst_start);
907 }
908 }
909
910 let accumulation_threads = thread_count - 1;
911 let block_stride = (bucket_size / accumulation_threads) & !15usize;
912 for thread in 0..accumulation_threads {
913 let block_start = thread * block_stride;
914 let block_size = if thread + 1 < accumulation_threads {
915 block_stride
916 } else {
917 bucket_size - block_start
918 };
919 accumulate_counts_s32(
920 &mut workspace,
921 block_start,
922 block_size,
923 bucket_stride,
924 accumulation_threads + 1,
925 );
926 }
927
928 buckets[..bucket_size].copy_from_slice(&workspace[..bucket_size]);
929 m as SaSint
930}
931
932fn count_and_gather_lms_suffixes_32s_2k_fs_omp(
933 t: &[SaSint],
934 sa: &mut [SaSint],
935 n: SaSint,
936 k: SaSint,
937 buckets: &mut [SaSint],
938 local_buckets: SaSint,
939 threads: SaSint,
940 thread_state: &mut [ThreadState],
941) -> SaSint {
942 if threads == 1 || n < 65_536 {
943 return count_and_gather_lms_suffixes_32s_2k(t, sa, n, k, buckets, 0, n as isize);
944 }
945
946 let thread_count = threads as usize;
947 let n_usize = n as usize;
948 let bucket_size = 2 * k as usize;
949 let block_stride = (n / threads) & !15;
950 let free_space = if local_buckets != 0 {
951 LIBSAIS_LOCAL_BUFFER_SIZE as SaSint
952 } else {
953 buckets.len() as SaSint
954 };
955 let bucket_stride = get_bucket_stride(free_space, 2 * k, threads) as usize;
956 let workspace_len = bucket_size + bucket_stride * thread_count.saturating_sub(1);
957 let mut workspace = vec![0; workspace_len];
958
959 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
960 let block_start = thread as SaSint * block_stride;
961 let block_size = if thread + 1 < thread_count {
962 block_stride
963 } else {
964 n - block_start
965 };
966 let workspace_end = workspace_len - thread * bucket_stride;
967 let workspace_start = workspace_end - bucket_size;
968 state.count = count_and_gather_lms_suffixes_32s_2k(
969 t,
970 sa,
971 n,
972 k,
973 &mut workspace[workspace_start..workspace_end],
974 block_start as isize,
975 block_size as isize,
976 );
977 state.position = block_start + block_size;
978 }
979
980 let mut m = 0usize;
981 for thread in (0..thread_count).rev() {
982 let count =
983 usize::try_from(thread_state[thread].count).expect("count must be non-negative");
984 m += count;
985 if thread + 1 != thread_count && count > 0 {
986 let src_end = usize::try_from(thread_state[thread].position)
987 .expect("position must be non-negative");
988 let src_start = src_end - count;
989 let dst_start = n_usize - m;
990 sa.copy_within(src_start..src_end, dst_start);
991 }
992 }
993
994 let accumulation_threads = thread_count - 1;
995 let block_stride = (bucket_size / accumulation_threads) & !15usize;
996 for thread in 0..accumulation_threads {
997 let block_start = thread * block_stride;
998 let block_size = if thread + 1 < accumulation_threads {
999 block_stride
1000 } else {
1001 bucket_size - block_start
1002 };
1003 accumulate_counts_s32(
1004 &mut workspace,
1005 block_start,
1006 block_size,
1007 bucket_stride,
1008 accumulation_threads + 1,
1009 );
1010 }
1011
1012 buckets[..bucket_size].copy_from_slice(&workspace[..bucket_size]);
1013 m as SaSint
1014}
1015
1016fn count_and_gather_compacted_lms_suffixes_32s_2k_fs_omp(
1017 t: &[SaSint],
1018 sa: &mut [SaSint],
1019 n: SaSint,
1020 k: SaSint,
1021 buckets: &mut [SaSint],
1022 _local_buckets: SaSint,
1023 threads: SaSint,
1024 thread_state: &mut [ThreadState],
1025) {
1026 if threads == 1 || n < 65_536 {
1027 count_and_gather_compacted_lms_suffixes_32s_2k(t, sa, n, k, buckets, 0, n as isize);
1028 return;
1029 }
1030
1031 let thread_count = threads as usize;
1032 let n_usize = n as usize;
1033 let bucket_size = 2 * k as usize;
1034 let block_stride = (n / threads) & !15;
1035 let mut workspaces = vec![vec![0; bucket_size]; thread_count];
1036 let mut gathered_runs = vec![Vec::<SaSint>::new(); thread_count];
1037
1038 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
1039 let block_start = thread as SaSint * block_stride;
1040 let block_size = if thread + 1 < thread_count {
1041 block_stride
1042 } else {
1043 n - block_start
1044 };
1045 let mut temp_sa = vec![0; n_usize + block_size as usize];
1046 state.count = count_and_gather_compacted_lms_suffixes_32s_2k(
1047 t,
1048 &mut temp_sa,
1049 n,
1050 k,
1051 &mut workspaces[thread],
1052 block_start as isize,
1053 block_size as isize,
1054 );
1055 state.position = block_start + block_size;
1056 let count = usize::try_from(state.count).expect("count must be non-negative");
1057 let src_end =
1058 n_usize + usize::try_from(state.position).expect("position must be non-negative");
1059 let src_start = src_end - count;
1060 gathered_runs[thread].extend_from_slice(&temp_sa[src_start..src_end]);
1061 }
1062
1063 let mut suffixes_before = 0usize;
1064 for thread in (0..thread_count).rev() {
1065 let count =
1066 usize::try_from(thread_state[thread].count).expect("count must be non-negative");
1067 suffixes_before += count;
1068 if count > 0 {
1069 let dst_start = n_usize - suffixes_before;
1070 let dst_end = dst_start + count;
1071 sa[dst_start..dst_end].copy_from_slice(&gathered_runs[thread]);
1072 }
1073 }
1074
1075 buckets.fill(0);
1076 for workspace in &workspaces {
1077 for (dst, src) in buckets.iter_mut().zip(workspace.iter()) {
1078 *dst += *src;
1079 }
1080 }
1081}
1082
1083fn count_and_gather_lms_suffixes_32s_4k_nofs_omp(
1084 t: &[SaSint],
1085 sa: &mut [SaSint],
1086 n: SaSint,
1087 k: SaSint,
1088 buckets: &mut [SaSint],
1089 threads: SaSint,
1090) -> SaSint {
1091 if threads > 1 && n >= 65_536 {
1092 count_lms_suffixes_32s_4k(t, n, k, buckets);
1093 gather_lms_suffixes_32s(t, sa, n)
1094 } else {
1095 count_and_gather_lms_suffixes_32s_4k(t, sa, n, k, buckets, 0, n as isize)
1096 }
1097}
1098
1099fn count_and_gather_lms_suffixes_32s_2k_nofs_omp(
1100 t: &[SaSint],
1101 sa: &mut [SaSint],
1102 n: SaSint,
1103 k: SaSint,
1104 buckets: &mut [SaSint],
1105 threads: SaSint,
1106) -> SaSint {
1107 if threads > 1 && n >= 65_536 {
1108 count_lms_suffixes_32s_2k(t, n, k, buckets);
1109 gather_lms_suffixes_32s(t, sa, n)
1110 } else {
1111 count_and_gather_lms_suffixes_32s_2k(t, sa, n, k, buckets, 0, n as isize)
1112 }
1113}
1114
1115fn count_and_gather_compacted_lms_suffixes_32s_2k_nofs_omp(
1116 t: &[SaSint],
1117 sa: &mut [SaSint],
1118 n: SaSint,
1119 k: SaSint,
1120 buckets: &mut [SaSint],
1121 threads: SaSint,
1122) -> SaSint {
1123 if threads > 1 && n >= 65_536 {
1124 count_compacted_lms_suffixes_32s_2k(t, n, k, buckets);
1125 gather_compacted_lms_suffixes_32s(t, sa, n)
1126 } else {
1127 count_and_gather_compacted_lms_suffixes_32s_2k(t, sa, n, k, buckets, 0, n as isize)
1128 }
1129}
1130
1131fn count_and_gather_lms_suffixes_32s_4k_omp(
1132 t: &[SaSint],
1133 sa: &mut [SaSint],
1134 n: SaSint,
1135 k: SaSint,
1136 buckets: &mut [SaSint],
1137 local_buckets: SaSint,
1138 threads: SaSint,
1139 thread_state: &mut [ThreadState],
1140) -> SaSint {
1141 let free_space = if local_buckets != 0 {
1142 LIBSAIS_LOCAL_BUFFER_SIZE as SaSint
1143 } else {
1144 buckets.len() as SaSint
1145 };
1146 let mut max_threads = (free_space / (((4 * k) + 15) & !15)).min(threads);
1147
1148 if max_threads > 1 && n >= 65_536 && n / k >= 2 {
1149 let thread_cap = n / (16 * k);
1150 if max_threads > thread_cap {
1151 max_threads = thread_cap;
1152 }
1153 count_and_gather_lms_suffixes_32s_4k_fs_omp(
1154 t,
1155 sa,
1156 n,
1157 k,
1158 buckets,
1159 local_buckets,
1160 max_threads.max(2),
1161 thread_state,
1162 )
1163 } else if threads > 1 && n >= 65_536 {
1164 count_lms_suffixes_32s_4k(t, n, k, buckets);
1165 gather_lms_suffixes_32s(t, sa, n)
1166 } else {
1167 count_and_gather_lms_suffixes_32s_4k_nofs_omp(t, sa, n, k, buckets, threads)
1168 }
1169}
1170
1171fn count_and_gather_lms_suffixes_32s_2k_omp(
1172 t: &[SaSint],
1173 sa: &mut [SaSint],
1174 n: SaSint,
1175 k: SaSint,
1176 buckets: &mut [SaSint],
1177 local_buckets: SaSint,
1178 threads: SaSint,
1179 thread_state: &mut [ThreadState],
1180) -> SaSint {
1181 let free_space = if local_buckets != 0 {
1182 LIBSAIS_LOCAL_BUFFER_SIZE as SaSint
1183 } else {
1184 buckets.len() as SaSint
1185 };
1186 let mut max_threads = (free_space / (((2 * k) + 15) & !15)).min(threads);
1187
1188 if max_threads > 1 && n >= 65_536 && n / k >= 2 {
1189 let thread_cap = n / (8 * k);
1190 if max_threads > thread_cap {
1191 max_threads = thread_cap;
1192 }
1193 count_and_gather_lms_suffixes_32s_2k_fs_omp(
1194 t,
1195 sa,
1196 n,
1197 k,
1198 buckets,
1199 local_buckets,
1200 max_threads.max(2),
1201 thread_state,
1202 )
1203 } else if threads > 1 && n >= 65_536 {
1204 count_lms_suffixes_32s_2k(t, n, k, buckets);
1205 gather_lms_suffixes_32s(t, sa, n)
1206 } else {
1207 count_and_gather_lms_suffixes_32s_2k_nofs_omp(t, sa, n, k, buckets, threads)
1208 }
1209}
1210
1211fn count_suffixes_32s(t: &[SaSint], n: SaSint, k: SaSint, buckets: &mut [SaSint]) {
1212 buckets[..k as usize].fill(0);
1213
1214 let mut i = 0usize;
1215 let mut j = (n as usize).saturating_sub(7);
1216 while i < j {
1217 buckets[t[i] as usize] += 1;
1218 buckets[t[i + 1] as usize] += 1;
1219 buckets[t[i + 2] as usize] += 1;
1220 buckets[t[i + 3] as usize] += 1;
1221 buckets[t[i + 4] as usize] += 1;
1222 buckets[t[i + 5] as usize] += 1;
1223 buckets[t[i + 6] as usize] += 1;
1224 buckets[t[i + 7] as usize] += 1;
1225 i += 8;
1226 }
1227
1228 j += 7;
1229 while i < j {
1230 buckets[t[i] as usize] += 1;
1231 i += 1;
1232 }
1233}
1234
1235fn initialize_buckets_start_and_end_32s_6k(k: SaSint, buckets: &mut [SaSint]) {
1236 let k = k as usize;
1237 let mut sum = 0;
1238 for j in 0..k {
1239 let i = buckets_index4(j, 0);
1240 buckets[4 * k + j] = sum;
1241 sum += buckets[i] + buckets[i + 1] + buckets[i + 2] + buckets[i + 3];
1242 buckets[5 * k + j] = sum;
1243 }
1244}
1245
1246fn initialize_buckets_start_and_end_32s_4k(k: SaSint, buckets: &mut [SaSint]) {
1247 let k = k as usize;
1248 let mut sum = 0;
1249 for j in 0..k {
1250 let i = buckets_index2(j, 0);
1251 buckets[2 * k + j] = sum;
1252 sum += buckets[i] + buckets[i + 1];
1253 buckets[3 * k + j] = sum;
1254 }
1255}
1256
1257fn initialize_buckets_end_32s_2k(k: SaSint, buckets: &mut [SaSint]) {
1258 let mut sum0 = 0;
1259 for j in 0..k as usize {
1260 let i = buckets_index2(j, 0);
1261 sum0 += buckets[i] + buckets[i + 1];
1262 buckets[i] = sum0;
1263 }
1264}
1265
1266fn initialize_buckets_start_and_end_32s_2k(k: SaSint, buckets: &mut [SaSint]) {
1267 let k = k as usize;
1268 for j in 0..k {
1269 let i = buckets_index2(j, 0);
1270 buckets[j] = buckets[i];
1271 }
1272 buckets[k] = 0;
1273 buckets.copy_within(0..k - 1, k + 1);
1274}
1275
1276fn initialize_buckets_start_32s_1k(k: SaSint, buckets: &mut [SaSint]) {
1277 let mut sum = 0;
1278 for bucket in buckets.iter_mut().take(k as usize) {
1279 let tmp = *bucket;
1280 *bucket = sum;
1281 sum += tmp;
1282 }
1283}
1284
1285fn initialize_buckets_end_32s_1k(k: SaSint, buckets: &mut [SaSint]) {
1286 let mut sum = 0;
1287 for bucket in buckets.iter_mut().take(k as usize) {
1288 sum += *bucket;
1289 *bucket = sum;
1290 }
1291}
1292
1293fn initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(
1294 t: &[SaSint],
1295 k: SaSint,
1296 buckets: &mut [SaSint],
1297 first_lms_suffix: SaSint,
1298) {
1299 buckets[buckets_index2(t[first_lms_suffix as usize] as usize, 0)] += 1;
1300 buckets[buckets_index2(t[first_lms_suffix as usize] as usize, 1)] -= 1;
1301
1302 let mut sum0 = 0;
1303 let mut sum1 = 0;
1304 for j in 0..k as usize {
1305 let i = buckets_index2(j, 0);
1306 sum0 += buckets[i] + buckets[i + 1];
1307 sum1 += buckets[i + 1];
1308 buckets[i] = sum0;
1309 buckets[i + 1] = sum1;
1310 }
1311}
1312
1313fn initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(
1314 t: &[SaSint],
1315 k: SaSint,
1316 buckets: &mut [SaSint],
1317 mut first_lms_suffix: SaSint,
1318) -> SaSint {
1319 let mut f0 = 0usize;
1320 let mut c0 = t[first_lms_suffix as usize] as isize;
1321
1322 loop {
1323 first_lms_suffix -= 1;
1324 if first_lms_suffix < 0 {
1325 break;
1326 }
1327 let c1 = c0;
1328 c0 = t[first_lms_suffix as usize] as isize;
1329 let f1 = f0;
1330 f0 = usize::from(c0 > c1 - f1 as isize);
1331 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] -= 1;
1332 }
1333 buckets[buckets_index4(c0 as usize, f0 + f0)] -= 1;
1334
1335 let mut sum = 0;
1336 for j in 0..k as usize {
1337 let i = buckets_index4(j, 0);
1338 sum += buckets[i + 1] + buckets[i + 3];
1339 buckets[4 * k as usize + j] = sum;
1340 }
1341 sum
1342}
1343
1344fn initialize_buckets_for_partial_sorting_32s_6k(
1345 t: &[SaSint],
1346 k: SaSint,
1347 buckets: &mut [SaSint],
1348 first_lms_suffix: SaSint,
1349 left_suffixes_count: SaSint,
1350) {
1351 let k = k as usize;
1352 let temp_offset = 4 * k;
1353 let first_symbol = t[first_lms_suffix as usize] as usize;
1354 let mut sum0 = left_suffixes_count + 1;
1355 let mut sum1 = 0;
1356 let mut sum2 = 0;
1357
1358 for j in 0..first_symbol {
1359 let i = buckets_index4(j, 0);
1360 let tj = buckets_index2(j, 0);
1361 let ss = buckets[i];
1362 let ls = buckets[i + 1];
1363 let sl = buckets[i + 2];
1364 let ll = buckets[i + 3];
1365
1366 buckets[i] = sum0;
1367 buckets[i + 1] = sum2;
1368 buckets[i + 2] = 0;
1369 buckets[i + 3] = 0;
1370
1371 sum0 += ss + sl;
1372 sum1 += ls;
1373 sum2 += ls + ll;
1374
1375 buckets[temp_offset + tj] = sum0;
1376 buckets[temp_offset + tj + 1] = sum1;
1377 }
1378
1379 sum1 += 1;
1380 for j in first_symbol..k {
1381 let i = buckets_index4(j, 0);
1382 let tj = buckets_index2(j, 0);
1383 let ss = buckets[i];
1384 let ls = buckets[i + 1];
1385 let sl = buckets[i + 2];
1386 let ll = buckets[i + 3];
1387
1388 buckets[i] = sum0;
1389 buckets[i + 1] = sum2;
1390 buckets[i + 2] = 0;
1391 buckets[i + 3] = 0;
1392
1393 sum0 += ss + sl;
1394 sum1 += ls;
1395 sum2 += ls + ll;
1396
1397 buckets[temp_offset + tj] = sum0;
1398 buckets[temp_offset + tj + 1] = sum1;
1399 }
1400}
1401
1402fn initialize_buckets_for_radix_and_partial_sorting_32s_4k(
1403 t: &[SaSint],
1404 k: SaSint,
1405 buckets: &mut [SaSint],
1406 first_lms_suffix: SaSint,
1407) {
1408 let k = k as usize;
1409 buckets[buckets_index2(t[first_lms_suffix as usize] as usize, 0)] += 1;
1410 buckets[buckets_index2(t[first_lms_suffix as usize] as usize, 1)] -= 1;
1411
1412 let mut sum0 = 0;
1413 let mut sum1 = 0;
1414 for j in 0..k {
1415 let i = buckets_index2(j, 0);
1416 buckets[2 * k + j] = sum1;
1417 sum0 += buckets[i + 1];
1418 sum1 += buckets[i] + buckets[i + 1];
1419 buckets[i + 1] = sum0;
1420 buckets[3 * k + j] = sum1;
1421 }
1422}
1423
1424fn count_and_gather_compacted_lms_suffixes_32s_2k_omp(
1425 t: &[SaSint],
1426 sa: &mut [SaSint],
1427 n: SaSint,
1428 k: SaSint,
1429 buckets: &mut [SaSint],
1430 local_buckets: SaSint,
1431 threads: SaSint,
1432 thread_state: &mut [ThreadState],
1433) {
1434 let free_space = if local_buckets != 0 {
1435 LIBSAIS_LOCAL_BUFFER_SIZE as SaSint
1436 } else {
1437 buckets.len() as SaSint
1438 };
1439 let mut max_threads = (free_space / (((2 * k) + 15) & !15)).min(threads);
1440
1441 if local_buckets == 0 && max_threads > 1 && n >= 65_536 && n / k >= 2 {
1442 let thread_cap = n / (8 * k);
1443 if max_threads > thread_cap {
1444 max_threads = thread_cap;
1445 }
1446 count_and_gather_compacted_lms_suffixes_32s_2k_fs_omp(
1447 t,
1448 sa,
1449 n,
1450 k,
1451 buckets,
1452 local_buckets,
1453 max_threads.max(2),
1454 thread_state,
1455 );
1456 } else {
1457 count_and_gather_compacted_lms_suffixes_32s_2k_nofs_omp(t, sa, n, k, buckets, threads);
1458 }
1459}
1460
1461fn gather_lms_suffixes_16u(
1462 t: &[u16],
1463 sa: &mut [SaSint],
1464 n: SaSint,
1465 mut m: SaSint,
1466 omp_block_start: SaSint,
1467 omp_block_size: SaSint,
1468) {
1469 if omp_block_size > 0 {
1470 let n = n as isize;
1471 let mut i: isize;
1472 let mut j = (omp_block_start + omp_block_size) as isize;
1473 let mut c0 = t[(omp_block_start + omp_block_size - 1) as usize] as isize;
1474 let mut c1 = -1isize;
1475
1476 while j < n {
1477 c1 = t[j as usize] as isize;
1478 if c1 != c0 {
1479 break;
1480 }
1481 j += 1;
1482 }
1483
1484 let mut f0 = usize::from(c0 >= c1);
1485 let mut f1: usize;
1486
1487 i = (omp_block_start + omp_block_size - 2) as isize;
1488 j = (omp_block_start + 3) as isize;
1489 while i >= j {
1490 c1 = t[i as usize] as isize;
1491 f1 = usize::from(c1 > c0 - f0 as isize);
1492 sa[m as usize] = (i + 1) as SaSint;
1493 m -= (f1 & (1 - f0)) as SaSint;
1494
1495 c0 = t[(i - 1) as usize] as isize;
1496 f0 = usize::from(c0 > c1 - f1 as isize);
1497 sa[m as usize] = i as SaSint;
1498 m -= (f0 & (1 - f1)) as SaSint;
1499
1500 c1 = t[(i - 2) as usize] as isize;
1501 f1 = usize::from(c1 > c0 - f0 as isize);
1502 sa[m as usize] = (i - 1) as SaSint;
1503 m -= (f1 & (1 - f0)) as SaSint;
1504
1505 c0 = t[(i - 3) as usize] as isize;
1506 f0 = usize::from(c0 > c1 - f1 as isize);
1507 sa[m as usize] = (i - 2) as SaSint;
1508 m -= (f0 & (1 - f1)) as SaSint;
1509
1510 i -= 4;
1511 }
1512
1513 j -= 3;
1514 while i >= j {
1515 c1 = c0;
1516 c0 = t[i as usize] as isize;
1517 f1 = f0;
1518 f0 = usize::from(c0 > c1 - f1 as isize);
1519 sa[m as usize] = (i + 1) as SaSint;
1520 m -= (f0 & (1 - f1)) as SaSint;
1521 i -= 1;
1522 }
1523
1524 sa[m as usize] = (i + 1) as SaSint;
1525 }
1526}
1527
1528fn count_and_gather_lms_suffixes_16u(
1529 t: &[u16],
1530 sa: &mut [SaSint],
1531 n: SaSint,
1532 buckets: &mut [SaSint],
1533 omp_block_start: SaSint,
1534 omp_block_size: SaSint,
1535) -> SaSint {
1536 buckets[..4 * ALPHABET_SIZE].fill(0);
1537
1538 let mut m = (omp_block_start + omp_block_size - 1) as isize;
1539
1540 if omp_block_size > 0 {
1541 let n = n as isize;
1542 let mut i: isize;
1543 let mut j = m + 1;
1544 let mut c0 = t[m as usize] as isize;
1545 let mut c1 = -1isize;
1546
1547 while j < n {
1548 c1 = t[j as usize] as isize;
1549 if c1 != c0 {
1550 break;
1551 }
1552 j += 1;
1553 }
1554
1555 let mut f0 = usize::from(c0 >= c1);
1556 let mut f1: usize;
1557
1558 i = m - 1;
1559 j = (omp_block_start + 3) as isize;
1560 while i >= j {
1561 c1 = t[i as usize] as isize;
1562 f1 = usize::from(c1 > c0 - f0 as isize);
1563 sa[m as usize] = (i + 1) as SaSint;
1564 m -= (f1 & (1 - f0)) as isize;
1565 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
1566
1567 c0 = t[(i - 1) as usize] as isize;
1568 f0 = usize::from(c0 > c1 - f1 as isize);
1569 sa[m as usize] = i as SaSint;
1570 m -= (f0 & (1 - f1)) as isize;
1571 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
1572
1573 c1 = t[(i - 2) as usize] as isize;
1574 f1 = usize::from(c1 > c0 - f0 as isize);
1575 sa[m as usize] = (i - 1) as SaSint;
1576 m -= (f1 & (1 - f0)) as isize;
1577 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
1578
1579 c0 = t[(i - 3) as usize] as isize;
1580 f0 = usize::from(c0 > c1 - f1 as isize);
1581 sa[m as usize] = (i - 2) as SaSint;
1582 m -= (f0 & (1 - f1)) as isize;
1583 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
1584
1585 i -= 4;
1586 }
1587
1588 j -= 3;
1589 while i >= j {
1590 c1 = c0;
1591 c0 = t[i as usize] as isize;
1592 f1 = f0;
1593 f0 = usize::from(c0 > c1 - f1 as isize);
1594 sa[m as usize] = (i + 1) as SaSint;
1595 m -= (f0 & (1 - f1)) as isize;
1596 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
1597 i -= 1;
1598 }
1599
1600 c1 = if i >= 0 { t[i as usize] as isize } else { -1 };
1601 f1 = usize::from(c1 > c0 - f0 as isize);
1602 sa[m as usize] = (i + 1) as SaSint;
1603 m -= (f1 & (1 - f0)) as isize;
1604 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
1605 }
1606
1607 omp_block_start + omp_block_size - 1 - m as SaSint
1608}
1609
1610fn gather_lms_suffixes_16u_omp(
1611 t: &[u16],
1612 sa: &mut [SaSint],
1613 n: SaSint,
1614 threads: SaSint,
1615 thread_state: &mut [ThreadState],
1616) {
1617 if threads == 1 || n < 65_536 || thread_state.is_empty() {
1618 gather_lms_suffixes_16u(t, sa, n, n - 1, 0, n);
1619 return;
1620 }
1621
1622 let thread_count = threads as usize;
1623 let block_stride = (n / threads) & !15;
1624 let mut suffix_counts_after = vec![0; thread_count];
1625 let mut m = 0;
1626 for thread in (0..thread_count).rev() {
1627 suffix_counts_after[thread] = m;
1628 m += thread_state[thread].m;
1629 }
1630
1631 for thread in 0..thread_count {
1632 let block_start = thread as SaSint * block_stride;
1633 let block_size = if thread + 1 < thread_count {
1634 block_stride
1635 } else {
1636 n - block_start
1637 };
1638 gather_lms_suffixes_16u(
1639 t,
1640 sa,
1641 n,
1642 n - 1 - suffix_counts_after[thread],
1643 block_start,
1644 block_size,
1645 );
1646 }
1647
1648 for thread in 0..thread_count {
1649 if thread_state[thread].m > 0 {
1650 sa[(n - 1 - suffix_counts_after[thread]) as usize] =
1651 thread_state[thread].last_lms_suffix;
1652 }
1653 }
1654}
1655
1656fn count_and_gather_lms_suffixes_16u_omp(
1657 t: &[u16],
1658 sa: &mut [SaSint],
1659 n: SaSint,
1660 buckets: &mut [SaSint],
1661 threads: SaSint,
1662 thread_state: &mut [ThreadState],
1663) -> SaSint {
1664 if threads == 1 || n < 65_536 || thread_state.is_empty() {
1665 return count_and_gather_lms_suffixes_16u(t, sa, n, buckets, 0, n);
1666 }
1667
1668 let thread_count = threads as usize;
1669 let block_stride = (n / threads) & !15;
1670
1671 for thread in 0..thread_count {
1672 let block_start = thread as SaSint * block_stride;
1673 let block_size = if thread + 1 < thread_count {
1674 block_stride
1675 } else {
1676 n - block_start
1677 };
1678 let count = count_and_gather_lms_suffixes_16u(
1679 t,
1680 sa,
1681 n,
1682 &mut thread_state[thread].buckets,
1683 block_start,
1684 block_size,
1685 );
1686 thread_state[thread].m = count;
1687 thread_state[thread].position = block_start + block_size;
1688 if count > 0 {
1689 thread_state[thread].last_lms_suffix = sa[(block_start + block_size - 1) as usize];
1690 }
1691 }
1692
1693 buckets[..4 * ALPHABET_SIZE].fill(0);
1694 let mut m = 0;
1695 for thread in (0..thread_count).rev() {
1696 let position = thread_state[thread].position;
1697 let count = thread_state[thread].m;
1698 m += count;
1699 if thread + 1 != thread_count && count > 0 {
1700 let src_end = position as usize;
1701 let src_start = src_end - count as usize;
1702 let dst_start = (n - m) as usize;
1703 sa.copy_within(src_start..src_end, dst_start);
1704 }
1705 for s in 0..4 * ALPHABET_SIZE {
1706 let a = buckets[s];
1707 let b = thread_state[thread].buckets[s];
1708 buckets[s] = a + b;
1709 thread_state[thread].buckets[s] = a;
1710 }
1711 }
1712
1713 m
1714}
1715
1716fn initialize_buckets_start_and_end_16u(
1717 buckets: &mut [SaSint],
1718 freq: Option<&mut [SaSint]>,
1719) -> SaSint {
1720 let (count_buckets, start_end) = buckets.split_at_mut(6 * ALPHABET_SIZE);
1721 let (bucket_start, bucket_end) = start_end.split_at_mut(ALPHABET_SIZE);
1722
1723 let mut k = -1;
1724 let mut sum = 0;
1725
1726 if let Some(freq) = freq {
1727 for j in 0..ALPHABET_SIZE {
1728 let i = buckets_index4(j, 0);
1729 let total = count_buckets[i]
1730 + count_buckets[i + buckets_index4(0, 1)]
1731 + count_buckets[i + buckets_index4(0, 2)]
1732 + count_buckets[i + buckets_index4(0, 3)];
1733
1734 bucket_start[j] = sum;
1735 sum += total;
1736 bucket_end[j] = sum;
1737 if total > 0 {
1738 k = j as SaSint;
1739 }
1740 freq[j] = total;
1741 }
1742 } else {
1743 for j in 0..ALPHABET_SIZE {
1744 let i = buckets_index4(j, 0);
1745 let total = count_buckets[i]
1746 + count_buckets[i + buckets_index4(0, 1)]
1747 + count_buckets[i + buckets_index4(0, 2)]
1748 + count_buckets[i + buckets_index4(0, 3)];
1749
1750 bucket_start[j] = sum;
1751 sum += total;
1752 bucket_end[j] = sum;
1753 if total > 0 {
1754 k = j as SaSint;
1755 }
1756 }
1757 }
1758
1759 k + 1
1760}
1761
1762fn initialize_buckets_for_lms_suffixes_radix_sort_16u(
1763 t: &[u16],
1764 buckets: &mut [SaSint],
1765 mut first_lms_suffix: SaSint,
1766) -> SaSint {
1767 let mut f0 = 0usize;
1768 let mut c0 = t[first_lms_suffix as usize] as isize;
1769
1770 loop {
1771 first_lms_suffix -= 1;
1772 if first_lms_suffix < 0 {
1773 break;
1774 }
1775
1776 let c1 = c0;
1777 c0 = t[first_lms_suffix as usize] as isize;
1778 let f1 = f0;
1779 f0 = usize::from(c0 > c1 - f1 as isize);
1780 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] -= 1;
1781 }
1782
1783 buckets[buckets_index4(c0 as usize, f0 + f0)] -= 1;
1784
1785 let (count_buckets, temp_bucket) = buckets.split_at_mut(4 * ALPHABET_SIZE);
1786 let mut sum = 0;
1787 for c in 0..ALPHABET_SIZE {
1788 let i = buckets_index4(c, 0);
1789 let j = buckets_index2(c, 0);
1790 temp_bucket[j + buckets_index2(0, 1)] = sum;
1791 sum += count_buckets[i + buckets_index4(0, 1)] + count_buckets[i + buckets_index4(0, 3)];
1792 temp_bucket[j] = sum;
1793 }
1794
1795 sum
1796}
1797
1798fn radix_sort_lms_suffixes_16u(
1799 t: &[u16],
1800 sa: &mut [SaSint],
1801 induction_bucket: &mut [SaSint],
1802 omp_block_start: SaSint,
1803 omp_block_size: SaSint,
1804) {
1805 let mut i = omp_block_start + omp_block_size - 1;
1806 let mut j = omp_block_start + 64 + 3;
1807 while i >= j {
1808 let p0 = sa[i as usize];
1809 induction_bucket[buckets_index2(t[p0 as usize] as usize, 0)] -= 1;
1810 sa[induction_bucket[buckets_index2(t[p0 as usize] as usize, 0)] as usize] = p0;
1811
1812 let p1 = sa[(i - 1) as usize];
1813 induction_bucket[buckets_index2(t[p1 as usize] as usize, 0)] -= 1;
1814 sa[induction_bucket[buckets_index2(t[p1 as usize] as usize, 0)] as usize] = p1;
1815
1816 let p2 = sa[(i - 2) as usize];
1817 induction_bucket[buckets_index2(t[p2 as usize] as usize, 0)] -= 1;
1818 sa[induction_bucket[buckets_index2(t[p2 as usize] as usize, 0)] as usize] = p2;
1819
1820 let p3 = sa[(i - 3) as usize];
1821 induction_bucket[buckets_index2(t[p3 as usize] as usize, 0)] -= 1;
1822 sa[induction_bucket[buckets_index2(t[p3 as usize] as usize, 0)] as usize] = p3;
1823
1824 i -= 4;
1825 }
1826
1827 j -= 64 + 3;
1828 while i >= j {
1829 let p = sa[i as usize];
1830 induction_bucket[buckets_index2(t[p as usize] as usize, 0)] -= 1;
1831 sa[induction_bucket[buckets_index2(t[p as usize] as usize, 0)] as usize] = p;
1832 i -= 1;
1833 }
1834}
1835
1836fn radix_sort_lms_suffixes_16u_omp(
1837 t: &[u16],
1838 sa: &mut [SaSint],
1839 n: SaSint,
1840 m: SaSint,
1841 flags: SaSint,
1842 buckets: &mut [SaSint],
1843 threads: SaSint,
1844 thread_state: &mut [ThreadState],
1845) {
1846 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
1847 buckets[4 * ALPHABET_SIZE] -= 1;
1848 }
1849 if threads == 1 || n < 65_536 || m < 65_536 || thread_state.is_empty() {
1850 radix_sort_lms_suffixes_16u(t, sa, &mut buckets[4 * ALPHABET_SIZE..], n - m + 1, m - 1);
1851 return;
1852 }
1853
1854 let thread_count = threads as usize;
1855 for thread in 0..thread_count {
1856 let (src_buckets, state_buckets) = (
1857 &buckets[4 * ALPHABET_SIZE..],
1858 &mut thread_state[thread].buckets,
1859 );
1860 for c in 0..ALPHABET_SIZE {
1861 let i = buckets_index2(c, 0);
1862 let j = buckets_index4(c, 1);
1863 state_buckets[i] = src_buckets[i] - state_buckets[j];
1864 }
1865
1866 let mut block_start = 0;
1867 let mut block_size = thread_state[thread].m;
1868 for idx in (thread..thread_count).rev() {
1869 block_start += thread_state[idx].m;
1870 }
1871
1872 if block_start == m && block_size > 0 {
1873 block_start -= 1;
1874 block_size -= 1;
1875 }
1876
1877 radix_sort_lms_suffixes_16u(
1878 t,
1879 sa,
1880 &mut thread_state[thread].buckets,
1881 n - block_start,
1882 block_size,
1883 );
1884 }
1885}
1886
1887fn radix_sort_lms_suffixes_32s_6k(
1888 t: &[SaSint],
1889 sa: &mut [SaSint],
1890 induction_bucket: &mut [SaSint],
1891 omp_block_start: SaSint,
1892 omp_block_size: SaSint,
1893) {
1894 let mut i = omp_block_start + omp_block_size - 1;
1895 let mut j = omp_block_start + 64 + 3;
1896 while i >= j {
1897 let p0 = sa[i as usize];
1898 induction_bucket[t[p0 as usize] as usize] -= 1;
1899 sa[induction_bucket[t[p0 as usize] as usize] as usize] = p0;
1900 let p1 = sa[(i - 1) as usize];
1901 induction_bucket[t[p1 as usize] as usize] -= 1;
1902 sa[induction_bucket[t[p1 as usize] as usize] as usize] = p1;
1903 let p2 = sa[(i - 2) as usize];
1904 induction_bucket[t[p2 as usize] as usize] -= 1;
1905 sa[induction_bucket[t[p2 as usize] as usize] as usize] = p2;
1906 let p3 = sa[(i - 3) as usize];
1907 induction_bucket[t[p3 as usize] as usize] -= 1;
1908 sa[induction_bucket[t[p3 as usize] as usize] as usize] = p3;
1909 i -= 4;
1910 }
1911
1912 j -= 64 + 3;
1913 while i >= j {
1914 let p = sa[i as usize];
1915 induction_bucket[t[p as usize] as usize] -= 1;
1916 sa[induction_bucket[t[p as usize] as usize] as usize] = p;
1917 i -= 1;
1918 }
1919}
1920
1921fn radix_sort_lms_suffixes_32s_2k(
1922 t: &[SaSint],
1923 sa: &mut [SaSint],
1924 induction_bucket: &mut [SaSint],
1925 omp_block_start: SaSint,
1926 omp_block_size: SaSint,
1927) {
1928 let mut i = omp_block_start + omp_block_size - 1;
1929 let mut j = omp_block_start + 64 + 3;
1930 while i >= j {
1931 let p0 = sa[i as usize];
1932 induction_bucket[buckets_index2(t[p0 as usize] as usize, 0)] -= 1;
1933 sa[induction_bucket[buckets_index2(t[p0 as usize] as usize, 0)] as usize] = p0;
1934 let p1 = sa[(i - 1) as usize];
1935 induction_bucket[buckets_index2(t[p1 as usize] as usize, 0)] -= 1;
1936 sa[induction_bucket[buckets_index2(t[p1 as usize] as usize, 0)] as usize] = p1;
1937 let p2 = sa[(i - 2) as usize];
1938 induction_bucket[buckets_index2(t[p2 as usize] as usize, 0)] -= 1;
1939 sa[induction_bucket[buckets_index2(t[p2 as usize] as usize, 0)] as usize] = p2;
1940 let p3 = sa[(i - 3) as usize];
1941 induction_bucket[buckets_index2(t[p3 as usize] as usize, 0)] -= 1;
1942 sa[induction_bucket[buckets_index2(t[p3 as usize] as usize, 0)] as usize] = p3;
1943 i -= 4;
1944 }
1945
1946 j -= 64 + 3;
1947 while i >= j {
1948 let p = sa[i as usize];
1949 induction_bucket[buckets_index2(t[p as usize] as usize, 0)] -= 1;
1950 sa[induction_bucket[buckets_index2(t[p as usize] as usize, 0)] as usize] = p;
1951 i -= 1;
1952 }
1953}
1954
1955fn radix_sort_lms_suffixes_32s_block_gather(
1956 t: &[SaSint],
1957 sa: &[SaSint],
1958 cache: &mut [ThreadCache],
1959 omp_block_start: SaSint,
1960 omp_block_size: SaSint,
1961) {
1962 if omp_block_size <= 0 {
1963 return;
1964 }
1965
1966 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
1967 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
1968 let cache_base = if cache.len() >= start + size {
1969 0
1970 } else {
1971 start
1972 };
1973 let mut i = start;
1974 let mut j = if size > 67 { start + size - 67 } else { start };
1975
1976 while i < j {
1977 for current in [i, i + 1, i + 2, i + 3] {
1978 let ci = current - cache_base;
1979 let index = sa[current];
1980 cache[ci].index = index;
1981 cache[ci].symbol = t[index as usize];
1982 }
1983 i += 4;
1984 }
1985
1986 j = if size > 67 { j + 67 } else { start + size };
1987 while i < j {
1988 let ci = i - cache_base;
1989 let index = sa[i];
1990 cache[ci].index = index;
1991 cache[ci].symbol = t[index as usize];
1992 i += 1;
1993 }
1994}
1995
1996fn radix_sort_lms_suffixes_32s_6k_block_sort(
1997 induction_bucket: &mut [SaSint],
1998 cache: &mut [ThreadCache],
1999 omp_block_start: SaSint,
2000 omp_block_size: SaSint,
2001) {
2002 if omp_block_size <= 0 {
2003 return;
2004 }
2005
2006 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
2007 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
2008 let cache_base = if cache.len() >= start + size {
2009 0
2010 } else {
2011 start
2012 };
2013 let mut i = start + size - 1;
2014 let mut j = start + 64 + 3;
2015
2016 while i >= j {
2017 for current in [i, i - 1, i - 2, i - 3] {
2018 let ci = current - cache_base;
2019 let v = cache[ci].symbol as usize;
2020 induction_bucket[v] -= 1;
2021 cache[ci].symbol = induction_bucket[v];
2022 }
2023 i -= 4;
2024 }
2025
2026 j -= 64 + 3;
2027 while i >= j {
2028 let ci = i - cache_base;
2029 let v = cache[ci].symbol as usize;
2030 induction_bucket[v] -= 1;
2031 cache[ci].symbol = induction_bucket[v];
2032 if i == 0 {
2033 break;
2034 }
2035 i -= 1;
2036 }
2037}
2038
2039fn radix_sort_lms_suffixes_32s_2k_block_sort(
2040 induction_bucket: &mut [SaSint],
2041 cache: &mut [ThreadCache],
2042 omp_block_start: SaSint,
2043 omp_block_size: SaSint,
2044) {
2045 if omp_block_size <= 0 {
2046 return;
2047 }
2048
2049 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
2050 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
2051 let cache_base = if cache.len() >= start + size {
2052 0
2053 } else {
2054 start
2055 };
2056 let mut i = start + size - 1;
2057 let mut j = start + 64 + 3;
2058
2059 while i >= j {
2060 for current in [i, i - 1, i - 2, i - 3] {
2061 let ci = current - cache_base;
2062 let v = buckets_index2(cache[ci].symbol as usize, 0);
2063 induction_bucket[v] -= 1;
2064 cache[ci].symbol = induction_bucket[v];
2065 }
2066 i -= 4;
2067 }
2068
2069 j -= 64 + 3;
2070 while i >= j {
2071 let ci = i - cache_base;
2072 let v = buckets_index2(cache[ci].symbol as usize, 0);
2073 induction_bucket[v] -= 1;
2074 cache[ci].symbol = induction_bucket[v];
2075 if i == 0 {
2076 break;
2077 }
2078 i -= 1;
2079 }
2080}
2081
2082fn radix_sort_lms_suffixes_32s_6k_block_omp(
2083 t: &[SaSint],
2084 sa: &mut [SaSint],
2085 induction_bucket: &mut [SaSint],
2086 cache: &mut [ThreadCache],
2087 block_start: SaSint,
2088 block_size: SaSint,
2089 threads: SaSint,
2090) {
2091 if threads <= 1 || block_size < 16_384 {
2092 radix_sort_lms_suffixes_32s_6k(t, sa, induction_bucket, block_start, block_size);
2093 return;
2094 }
2095
2096 radix_sort_lms_suffixes_32s_block_gather(t, sa, cache, block_start, block_size);
2097 radix_sort_lms_suffixes_32s_6k_block_sort(induction_bucket, cache, block_start, block_size);
2098 place_cached_suffixes(sa, cache, block_start, block_size);
2099}
2100
2101fn radix_sort_lms_suffixes_32s_2k_block_omp(
2102 t: &[SaSint],
2103 sa: &mut [SaSint],
2104 induction_bucket: &mut [SaSint],
2105 cache: &mut [ThreadCache],
2106 block_start: SaSint,
2107 block_size: SaSint,
2108 threads: SaSint,
2109) {
2110 if threads <= 1 || block_size < 16_384 {
2111 radix_sort_lms_suffixes_32s_2k(t, sa, induction_bucket, block_start, block_size);
2112 return;
2113 }
2114
2115 radix_sort_lms_suffixes_32s_block_gather(t, sa, cache, block_start, block_size);
2116 radix_sort_lms_suffixes_32s_2k_block_sort(induction_bucket, cache, block_start, block_size);
2117 place_cached_suffixes(sa, cache, block_start, block_size);
2118}
2119
2120fn radix_sort_lms_suffixes_32s_6k_omp(
2121 t: &[SaSint],
2122 sa: &mut [SaSint],
2123 n: SaSint,
2124 m: SaSint,
2125 induction_bucket: &mut [SaSint],
2126 threads: SaSint,
2127) {
2128 if threads <= 1 || m < 65_536 {
2129 radix_sort_lms_suffixes_32s_6k(t, sa, induction_bucket, n - m + 1, m - 1);
2130 return;
2131 }
2132
2133 let threads_usize = usize::try_from(threads).expect("threads must be positive");
2134 let mut cache = vec![ThreadCache::default(); threads_usize * PER_THREAD_CACHE_SIZE];
2135 let mut block_start = 0usize;
2136 let m_usize = usize::try_from(m).expect("m must be non-negative");
2137 let n_usize = usize::try_from(n).expect("n must be non-negative");
2138 let last = m_usize - 1;
2139
2140 while block_start < last {
2141 let block_end = (block_start + threads_usize * PER_THREAD_CACHE_SIZE).min(last);
2142 radix_sort_lms_suffixes_32s_6k_block_omp(
2143 t,
2144 sa,
2145 induction_bucket,
2146 &mut cache,
2147 (n_usize - block_end) as SaSint,
2148 (block_end - block_start) as SaSint,
2149 threads,
2150 );
2151 block_start = block_end;
2152 }
2153}
2154
2155fn radix_sort_lms_suffixes_32s_2k_omp(
2156 t: &[SaSint],
2157 sa: &mut [SaSint],
2158 n: SaSint,
2159 m: SaSint,
2160 induction_bucket: &mut [SaSint],
2161 threads: SaSint,
2162) {
2163 if threads <= 1 || m < 65_536 {
2164 radix_sort_lms_suffixes_32s_2k(t, sa, induction_bucket, n - m + 1, m - 1);
2165 return;
2166 }
2167
2168 let threads_usize = usize::try_from(threads).expect("threads must be positive");
2169 let mut cache = vec![ThreadCache::default(); threads_usize * PER_THREAD_CACHE_SIZE];
2170 let mut block_start = 0usize;
2171 let m_usize = usize::try_from(m).expect("m must be non-negative");
2172 let n_usize = usize::try_from(n).expect("n must be non-negative");
2173 let last = m_usize - 1;
2174
2175 while block_start < last {
2176 let block_end = (block_start + threads_usize * PER_THREAD_CACHE_SIZE).min(last);
2177 radix_sort_lms_suffixes_32s_2k_block_omp(
2178 t,
2179 sa,
2180 induction_bucket,
2181 &mut cache,
2182 (n_usize - block_end) as SaSint,
2183 (block_end - block_start) as SaSint,
2184 threads,
2185 );
2186 block_start = block_end;
2187 }
2188}
2189
2190fn radix_sort_lms_suffixes_32s_1k(
2191 t: &[SaSint],
2192 sa: &mut [SaSint],
2193 n: SaSint,
2194 buckets: &mut [SaSint],
2195) -> SaSint {
2196 let mut i = n - 2;
2197 let mut m = 0;
2198 let mut f0 = 1usize;
2199 let mut f1: usize;
2200 let mut c0 = t[(n - 1) as usize] as isize;
2201 let mut c1: isize;
2202 let mut c2 = 0isize;
2203
2204 while i >= 64 + 3 {
2205 c1 = t[i as usize] as isize;
2206 f1 = usize::from(c1 > c0 - f0 as isize);
2207 if (f1 & !f0) != 0 {
2208 c2 = c0;
2209 buckets[c2 as usize] -= 1;
2210 sa[buckets[c2 as usize] as usize] = i + 1;
2211 m += 1;
2212 }
2213 c0 = t[(i - 1) as usize] as isize;
2214 f0 = usize::from(c0 > c1 - f1 as isize);
2215 if (f0 & !f1) != 0 {
2216 c2 = c1;
2217 buckets[c2 as usize] -= 1;
2218 sa[buckets[c2 as usize] as usize] = i;
2219 m += 1;
2220 }
2221 c1 = t[(i - 2) as usize] as isize;
2222 f1 = usize::from(c1 > c0 - f0 as isize);
2223 if (f1 & !f0) != 0 {
2224 c2 = c0;
2225 buckets[c2 as usize] -= 1;
2226 sa[buckets[c2 as usize] as usize] = i - 1;
2227 m += 1;
2228 }
2229 c0 = t[(i - 3) as usize] as isize;
2230 f0 = usize::from(c0 > c1 - f1 as isize);
2231 if (f0 & !f1) != 0 {
2232 c2 = c1;
2233 buckets[c2 as usize] -= 1;
2234 sa[buckets[c2 as usize] as usize] = i - 2;
2235 m += 1;
2236 }
2237 i -= 4;
2238 }
2239
2240 while i >= 0 {
2241 c1 = c0;
2242 c0 = t[i as usize] as isize;
2243 f1 = f0;
2244 f0 = usize::from(c0 > c1 - f1 as isize);
2245 if (f0 & !f1) != 0 {
2246 c2 = c1;
2247 buckets[c2 as usize] -= 1;
2248 sa[buckets[c2 as usize] as usize] = i + 1;
2249 m += 1;
2250 }
2251 i -= 1;
2252 }
2253
2254 if m > 1 {
2255 sa[buckets[c2 as usize] as usize] = 0;
2256 }
2257
2258 m
2259}
2260
2261fn radix_sort_set_markers_32s_6k(
2262 sa: &mut [SaSint],
2263 induction_bucket: &[SaSint],
2264 omp_block_start: SaSint,
2265 omp_block_size: SaSint,
2266) {
2267 let mut i = omp_block_start;
2268 let mut j = omp_block_start + omp_block_size - 64 - 3;
2269
2270 while i < j {
2271 sa[induction_bucket[i as usize] as usize] |= SAINT_MIN;
2272 sa[induction_bucket[(i + 1) as usize] as usize] |= SAINT_MIN;
2273 sa[induction_bucket[(i + 2) as usize] as usize] |= SAINT_MIN;
2274 sa[induction_bucket[(i + 3) as usize] as usize] |= SAINT_MIN;
2275 i += 4;
2276 }
2277
2278 j += 64 + 3;
2279 while i < j {
2280 sa[induction_bucket[i as usize] as usize] |= SAINT_MIN;
2281 i += 1;
2282 }
2283}
2284
2285fn radix_sort_set_markers_32s_4k(
2286 sa: &mut [SaSint],
2287 induction_bucket: &[SaSint],
2288 omp_block_start: SaSint,
2289 omp_block_size: SaSint,
2290) {
2291 let mut i = omp_block_start;
2292 let mut j = omp_block_start + omp_block_size - 64 - 3;
2293
2294 while i < j {
2295 sa[induction_bucket[buckets_index2(i as usize, 0)] as usize] |= SUFFIX_GROUP_MARKER;
2296 sa[induction_bucket[buckets_index2((i + 1) as usize, 0)] as usize] |= SUFFIX_GROUP_MARKER;
2297 sa[induction_bucket[buckets_index2((i + 2) as usize, 0)] as usize] |= SUFFIX_GROUP_MARKER;
2298 sa[induction_bucket[buckets_index2((i + 3) as usize, 0)] as usize] |= SUFFIX_GROUP_MARKER;
2299 i += 4;
2300 }
2301
2302 j += 64 + 3;
2303 while i < j {
2304 sa[induction_bucket[buckets_index2(i as usize, 0)] as usize] |= SUFFIX_GROUP_MARKER;
2305 i += 1;
2306 }
2307}
2308
2309fn radix_sort_set_markers_32s_6k_omp(
2310 sa: &mut [SaSint],
2311 k: SaSint,
2312 induction_bucket: &[SaSint],
2313 threads: SaSint,
2314) {
2315 if k <= 1 {
2316 return;
2317 }
2318
2319 if threads <= 1 || k < 65_536 {
2320 radix_sort_set_markers_32s_6k(sa, induction_bucket, 0, k - 1);
2321 return;
2322 }
2323
2324 let threads_usize = usize::try_from(threads).expect("threads must be positive");
2325 let last = usize::try_from(k - 1).expect("k must be positive");
2326 let stride = (last / threads_usize) & !15usize;
2327
2328 {
2329 let sa_ptr = SyncMutPtr::new(sa);
2330 run_rayon_with_threads(threads_usize, || {
2331 (0..threads_usize).into_par_iter().for_each(|thread| {
2332 let start = thread * stride;
2333 let end = if thread + 1 == threads_usize {
2334 last
2335 } else {
2336 start + stride
2337 };
2338 if end > start {
2339 let sa = unsafe { sa_ptr.as_slice() };
2340 radix_sort_set_markers_32s_6k(
2341 sa,
2342 induction_bucket,
2343 start as SaSint,
2344 (end - start) as SaSint,
2345 );
2346 }
2347 });
2348 });
2349 }
2350}
2351
2352fn radix_sort_set_markers_32s_4k_omp(
2353 sa: &mut [SaSint],
2354 k: SaSint,
2355 induction_bucket: &[SaSint],
2356 threads: SaSint,
2357) {
2358 if k <= 1 {
2359 return;
2360 }
2361
2362 if threads <= 1 || k < 65_536 {
2363 radix_sort_set_markers_32s_4k(sa, induction_bucket, 0, k - 1);
2364 return;
2365 }
2366
2367 let threads_usize = usize::try_from(threads).expect("threads must be positive");
2368 let last = usize::try_from(k - 1).expect("k must be positive");
2369 let stride = (last / threads_usize) & !15usize;
2370
2371 {
2372 let sa_ptr = SyncMutPtr::new(sa);
2373 run_rayon_with_threads(threads_usize, || {
2374 (0..threads_usize).into_par_iter().for_each(|thread| {
2375 let start = thread * stride;
2376 let end = if thread + 1 == threads_usize {
2377 last
2378 } else {
2379 start + stride
2380 };
2381 if end > start {
2382 let sa = unsafe { sa_ptr.as_slice() };
2383 radix_sort_set_markers_32s_4k(
2384 sa,
2385 induction_bucket,
2386 start as SaSint,
2387 (end - start) as SaSint,
2388 );
2389 }
2390 });
2391 });
2392 }
2393}
2394
2395fn initialize_buckets_for_partial_sorting_16u(
2396 t: &[u16],
2397 buckets: &mut [SaSint],
2398 first_lms_suffix: SaSint,
2399 left_suffixes_count: SaSint,
2400) {
2401 buckets[buckets_index4(t[first_lms_suffix as usize] as usize, 1)] += 1;
2402
2403 let (front, temp_bucket) = buckets.split_at_mut(4 * ALPHABET_SIZE);
2404 let mut sum0 = left_suffixes_count + 1;
2405 let mut sum1 = 0;
2406
2407 for c in 0..ALPHABET_SIZE {
2408 let i = buckets_index4(c, 0);
2409 let j = buckets_index2(c, 0);
2410
2411 temp_bucket[j + buckets_index2(0, 0)] = sum0;
2412
2413 sum0 += front[i + buckets_index4(0, 0)] + front[i + buckets_index4(0, 2)];
2414 sum1 += front[i + buckets_index4(0, 1)];
2415
2416 front[j + buckets_index2(0, 0)] = sum0;
2417 front[j + buckets_index2(0, 1)] = sum1;
2418 }
2419}
2420
2421fn partial_sorting_shift_markers_32s_6k_omp(
2422 sa: &mut [SaSint],
2423 k: SaSint,
2424 buckets: &[SaSint],
2425 threads: SaSint,
2426) {
2427 let k_usize = usize::try_from(k).expect("k must be non-negative");
2428 let temp_bucket = &buckets[4 * k_usize..];
2429 let thread_count = if threads > 1 && k >= 65536 {
2430 usize::try_from(threads).expect("threads must be positive")
2431 } else {
2432 1
2433 };
2434 {
2435 let sa_ptr = SyncMutPtr::new(sa);
2436 let buckets_ref: &[SaSint] = buckets;
2437 let temp_bucket_ref: &[SaSint] = temp_bucket;
2438 run_rayon_with_threads(thread_count, || {
2439 (0..thread_count).into_par_iter().for_each(|t| {
2440 let mut c = k_usize as isize - 1 - t as isize;
2441 let sa = unsafe { sa_ptr.as_slice() };
2442 while c >= 1 {
2443 let c_usize = c as usize;
2444 let mut i = buckets_ref[buckets_index4(c_usize, 0)] - 1;
2445 let mut j = temp_bucket_ref[buckets_index2(c_usize - 1, 0)] + 3;
2446 let mut s = SAINT_MIN;
2447
2448 while i >= j {
2449 let p0 = sa[i as usize];
2450 let q0 = (p0 & SAINT_MIN) ^ s;
2451 s ^= q0;
2452 sa[i as usize] = p0 ^ q0;
2453
2454 let p1 = sa[(i - 1) as usize];
2455 let q1 = (p1 & SAINT_MIN) ^ s;
2456 s ^= q1;
2457 sa[(i - 1) as usize] = p1 ^ q1;
2458
2459 let p2 = sa[(i - 2) as usize];
2460 let q2 = (p2 & SAINT_MIN) ^ s;
2461 s ^= q2;
2462 sa[(i - 2) as usize] = p2 ^ q2;
2463
2464 let p3 = sa[(i - 3) as usize];
2465 let q3 = (p3 & SAINT_MIN) ^ s;
2466 s ^= q3;
2467 sa[(i - 3) as usize] = p3 ^ q3;
2468
2469 i -= 4;
2470 }
2471
2472 j -= 3;
2473 while i >= j {
2474 let p = sa[i as usize];
2475 let q = (p & SAINT_MIN) ^ s;
2476 s ^= q;
2477 sa[i as usize] = p ^ q;
2478 i -= 1;
2479 }
2480
2481 c -= thread_count as isize;
2482 }
2483 });
2484 });
2485 }
2486}
2487
2488fn partial_sorting_shift_markers_32s_4k(sa: &mut [SaSint], n: SaSint) {
2489 let mut i = n - 1;
2490 let mut s = SUFFIX_GROUP_MARKER;
2491
2492 while i >= 3 {
2493 let p0 = sa[i as usize];
2494 let q0 =
2495 ((p0 & SUFFIX_GROUP_MARKER) ^ s) & (((p0 > 0) as SaSint) << (SUFFIX_GROUP_BIT - 1));
2496 s ^= q0;
2497 sa[i as usize] = p0 ^ q0;
2498
2499 let p1 = sa[(i - 1) as usize];
2500 let q1 =
2501 ((p1 & SUFFIX_GROUP_MARKER) ^ s) & (((p1 > 0) as SaSint) << (SUFFIX_GROUP_BIT - 1));
2502 s ^= q1;
2503 sa[(i - 1) as usize] = p1 ^ q1;
2504
2505 let p2 = sa[(i - 2) as usize];
2506 let q2 =
2507 ((p2 & SUFFIX_GROUP_MARKER) ^ s) & (((p2 > 0) as SaSint) << (SUFFIX_GROUP_BIT - 1));
2508 s ^= q2;
2509 sa[(i - 2) as usize] = p2 ^ q2;
2510
2511 let p3 = sa[(i - 3) as usize];
2512 let q3 =
2513 ((p3 & SUFFIX_GROUP_MARKER) ^ s) & (((p3 > 0) as SaSint) << (SUFFIX_GROUP_BIT - 1));
2514 s ^= q3;
2515 sa[(i - 3) as usize] = p3 ^ q3;
2516
2517 i -= 4;
2518 }
2519
2520 while i >= 0 {
2521 let p = sa[i as usize];
2522 let q = ((p & SUFFIX_GROUP_MARKER) ^ s) & (((p > 0) as SaSint) << (SUFFIX_GROUP_BIT - 1));
2523 s ^= q;
2524 sa[i as usize] = p ^ q;
2525 i -= 1;
2526 }
2527}
2528
2529fn partial_sorting_shift_buckets_32s_6k(k: SaSint, buckets: &mut [SaSint]) {
2530 let temp_offset = 4 * k as usize;
2531 let mut i = buckets_index2(0, 0);
2532
2533 while i <= buckets_index2(k as usize - 1, 0) {
2534 buckets[2 * i + buckets_index4(0, 0)] = buckets[temp_offset + i + buckets_index2(0, 0)];
2535 buckets[2 * i + buckets_index4(0, 1)] = buckets[temp_offset + i + buckets_index2(0, 1)];
2536 i += buckets_index2(1, 0);
2537 }
2538}
2539
2540fn partial_sorting_scan_left_to_right_16u(
2541 t: &[u16],
2542 sa: &mut [SaSint],
2543 buckets: &mut [SaSint],
2544 mut d: SaSint,
2545 omp_block_start: SaSint,
2546 omp_block_size: SaSint,
2547) -> SaSint {
2548 let mut i = omp_block_start as isize;
2549 let mut j = (omp_block_start + omp_block_size - 64 - 1) as isize;
2550 while i < j {
2551 let mut p0 = sa[i as usize];
2552 d += SaSint::from(p0 < 0);
2553 p0 &= SAINT_MAX;
2554 let v0 = buckets_index2(
2555 t[(p0 - 1) as usize] as usize,
2556 usize::from(t[(p0 - 2) as usize] >= t[(p0 - 1) as usize]),
2557 );
2558 let mark0 = if buckets[2 * ALPHABET_SIZE + v0] != d {
2559 SAINT_MIN
2560 } else {
2561 0
2562 };
2563 let dst0 = buckets[4 * ALPHABET_SIZE + v0] as usize;
2564 sa[dst0] = (p0 - 1) | mark0;
2565 buckets[4 * ALPHABET_SIZE + v0] += 1;
2566 buckets[2 * ALPHABET_SIZE + v0] = d;
2567
2568 let mut p1 = sa[(i + 1) as usize];
2569 d += SaSint::from(p1 < 0);
2570 p1 &= SAINT_MAX;
2571 let v1 = buckets_index2(
2572 t[(p1 - 1) as usize] as usize,
2573 usize::from(t[(p1 - 2) as usize] >= t[(p1 - 1) as usize]),
2574 );
2575 let mark1 = if buckets[2 * ALPHABET_SIZE + v1] != d {
2576 SAINT_MIN
2577 } else {
2578 0
2579 };
2580 let dst1 = buckets[4 * ALPHABET_SIZE + v1] as usize;
2581 sa[dst1] = (p1 - 1) | mark1;
2582 buckets[4 * ALPHABET_SIZE + v1] += 1;
2583 buckets[2 * ALPHABET_SIZE + v1] = d;
2584
2585 i += 2;
2586 }
2587
2588 j += 64 + 1;
2589 while i < j {
2590 let mut p = sa[i as usize];
2591 d += SaSint::from(p < 0);
2592 p &= SAINT_MAX;
2593 let v = buckets_index2(
2594 t[(p - 1) as usize] as usize,
2595 usize::from(t[(p - 2) as usize] >= t[(p - 1) as usize]),
2596 );
2597 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2598 SAINT_MIN
2599 } else {
2600 0
2601 };
2602 let dst = buckets[4 * ALPHABET_SIZE + v] as usize;
2603 sa[dst] = (p - 1) | mark;
2604 buckets[4 * ALPHABET_SIZE + v] += 1;
2605 buckets[2 * ALPHABET_SIZE + v] = d;
2606 i += 1;
2607 }
2608
2609 d
2610}
2611
2612fn partial_sorting_scan_left_to_right_16u_block_prepare(
2613 t: &[u16],
2614 sa: &mut [SaSint],
2615 k: SaSint,
2616 buckets: &mut [SaSint],
2617 cache: &mut [ThreadCache],
2618 omp_block_start: SaSint,
2619 omp_block_size: SaSint,
2620 state: &mut ThreadState,
2621) -> SaSint {
2622 let width = 2 * k as usize;
2623 buckets[..width].fill(0);
2624 buckets[2 * ALPHABET_SIZE..2 * ALPHABET_SIZE + width].fill(0);
2625
2626 let mut count = 0usize;
2627 let mut d = 1;
2628 for i in omp_block_start as usize..(omp_block_start + omp_block_size) as usize {
2629 let mut p = sa[i];
2630 cache[count].index = p;
2631 d += SaSint::from(p < 0);
2632 p &= SAINT_MAX;
2633 let v = buckets_index2(
2634 t[(p - 1) as usize] as usize,
2635 usize::from(t[(p - 2) as usize] >= t[(p - 1) as usize]),
2636 );
2637 cache[count].symbol = v as SaSint;
2638 buckets[v] += 1;
2639 buckets[2 * ALPHABET_SIZE + v] = d;
2640 count += 1;
2641 }
2642 state.cache_entries = count;
2643 d - 1
2644}
2645
2646fn partial_sorting_scan_left_to_right_16u_block_place(
2647 sa: &mut [SaSint],
2648 buckets: &mut [SaSint],
2649 cache: &[ThreadCache],
2650 count: SaSint,
2651 mut d: SaSint,
2652) {
2653 for entry in cache.iter().take(count as usize) {
2654 let mut p = entry.index;
2655 d += SaSint::from(p < 0);
2656 p &= SAINT_MAX;
2657 let v = entry.symbol as usize;
2658 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2659 SAINT_MIN
2660 } else {
2661 0
2662 };
2663 let dst = buckets[v] as usize;
2664 sa[dst] = (p - 1) | mark;
2665 buckets[v] += 1;
2666 buckets[2 * ALPHABET_SIZE + v] = d;
2667 }
2668}
2669
2670fn partial_sorting_scan_left_to_right_16u_block_omp(
2671 t: &[u16],
2672 sa: &mut [SaSint],
2673 k: SaSint,
2674 buckets: &mut [SaSint],
2675 d: SaSint,
2676 block_start: SaSint,
2677 block_size: SaSint,
2678 threads: SaSint,
2679 thread_state: &mut [ThreadState],
2680) -> SaSint {
2681 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
2682 usize::try_from(threads)
2683 .expect("threads must be non-negative")
2684 .min(thread_state.len())
2685 } else {
2686 1
2687 };
2688 if thread_count <= 1 {
2689 return partial_sorting_scan_left_to_right_16u(t, sa, buckets, d, block_start, block_size);
2690 }
2691
2692 let bucket_width = 2 * k as usize;
2693 let block_stride = (block_size / thread_count as SaSint) & !15;
2694
2695 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
2696 let local_start = thread as SaSint * block_stride;
2697 let local_size = if thread + 1 < thread_count {
2698 block_stride
2699 } else {
2700 block_size - local_start
2701 };
2702 let mut local_state = ThreadState::default();
2703 state.position = partial_sorting_scan_left_to_right_16u_block_prepare(
2704 t,
2705 sa,
2706 k,
2707 &mut state.buckets,
2708 &mut state.cache,
2709 block_start + local_start,
2710 local_size,
2711 &mut local_state,
2712 );
2713 state.count = local_state.cache_entries as SaSint;
2714 }
2715
2716 let mut next_d = d;
2717 for state in thread_state.iter_mut().take(thread_count) {
2718 for c in 0..bucket_width {
2719 let a = buckets[4 * ALPHABET_SIZE + c];
2720 let b = state.buckets[c];
2721 buckets[4 * ALPHABET_SIZE + c] = a + b;
2722 state.buckets[c] = a;
2723 }
2724
2725 next_d -= 1;
2726 for c in 0..bucket_width {
2727 let a = buckets[2 * ALPHABET_SIZE + c];
2728 let b = state.buckets[2 * ALPHABET_SIZE + c];
2729 let shifted = b + next_d;
2730 buckets[2 * ALPHABET_SIZE + c] = if b > 0 { shifted } else { a };
2731 state.buckets[2 * ALPHABET_SIZE + c] = a;
2732 }
2733 next_d += 1 + state.position;
2734 state.position = next_d - state.position;
2735 }
2736
2737 for state in thread_state.iter_mut().take(thread_count) {
2738 partial_sorting_scan_left_to_right_16u_block_place(
2739 sa,
2740 &mut state.buckets,
2741 &state.cache,
2742 state.count,
2743 state.position,
2744 );
2745 }
2746
2747 next_d
2748}
2749
2750fn partial_sorting_scan_left_to_right_16u_omp(
2751 t: &[u16],
2752 sa: &mut [SaSint],
2753 n: SaSint,
2754 k: SaSint,
2755 buckets: &mut [SaSint],
2756 left_suffixes_count: SaSint,
2757 mut d: SaSint,
2758 threads: SaSint,
2759) -> SaSint {
2760 let v = buckets_index2(
2761 t[(n - 1) as usize] as usize,
2762 usize::from(t[(n - 2) as usize] >= t[(n - 1) as usize]),
2763 );
2764 let dst = buckets[4 * ALPHABET_SIZE + v] as usize;
2765 buckets[4 * ALPHABET_SIZE + v] += 1;
2766 sa[dst] = (n - 1) | SAINT_MIN;
2767 d += 1;
2768 buckets[2 * ALPHABET_SIZE + v] = d;
2769
2770 if threads == 1 || left_suffixes_count < 65536 {
2771 d = partial_sorting_scan_left_to_right_16u(t, sa, buckets, d, 0, left_suffixes_count);
2772 } else {
2773 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
2774 let mut block_start = 0;
2775 while block_start < left_suffixes_count {
2776 if sa[block_start as usize] == 0 {
2777 block_start += 1;
2778 } else {
2779 let mut block_end =
2780 block_start + threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
2781 if block_end > left_suffixes_count {
2782 block_end = left_suffixes_count;
2783 }
2784 let mut block_scan_end = block_start + 1;
2785 while block_scan_end < block_end && sa[block_scan_end as usize] != 0 {
2786 block_scan_end += 1;
2787 }
2788 let block_size = block_scan_end - block_start;
2789
2790 if block_size < 32 {
2791 while block_start < block_scan_end {
2792 let mut p = sa[block_start as usize];
2793 d += SaSint::from(p < 0);
2794 p &= SAINT_MAX;
2795 let v = buckets_index2(
2796 t[(p - 1) as usize] as usize,
2797 usize::from(t[(p - 2) as usize] >= t[(p - 1) as usize]),
2798 );
2799 let dst = buckets[4 * ALPHABET_SIZE + v] as usize;
2800 buckets[4 * ALPHABET_SIZE + v] += 1;
2801 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2802 SAINT_MIN
2803 } else {
2804 0
2805 };
2806 sa[dst] = (p - 1) | mark;
2807 buckets[2 * ALPHABET_SIZE + v] = d;
2808 block_start += 1;
2809 }
2810 } else {
2811 d = partial_sorting_scan_left_to_right_16u_block_omp(
2812 t,
2813 sa,
2814 k,
2815 buckets,
2816 d,
2817 block_start,
2818 block_size,
2819 threads,
2820 &mut thread_state,
2821 );
2822 block_start = block_scan_end;
2823 }
2824 }
2825 }
2826 }
2827 d
2828}
2829
2830fn partial_sorting_scan_right_to_left_16u(
2831 t: &[u16],
2832 sa: &mut [SaSint],
2833 buckets: &mut [SaSint],
2834 mut d: SaSint,
2835 omp_block_start: SaSint,
2836 omp_block_size: SaSint,
2837) -> SaSint {
2838 let mut i = (omp_block_start + omp_block_size - 1) as isize;
2839 let mut j = (omp_block_start + 64 + 1) as isize;
2840 while i >= j {
2841 let mut p0 = sa[i as usize];
2842 d += SaSint::from(p0 < 0);
2843 p0 &= SAINT_MAX;
2844 let v0 = buckets_index2(
2845 t[(p0 - 1) as usize] as usize,
2846 usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]),
2847 );
2848 let mark0 = if buckets[2 * ALPHABET_SIZE + v0] != d {
2849 SAINT_MIN
2850 } else {
2851 0
2852 };
2853 buckets[v0] -= 1;
2854 sa[buckets[v0] as usize] = (p0 - 1) | mark0;
2855 buckets[2 * ALPHABET_SIZE + v0] = d;
2856
2857 let mut p1 = sa[(i - 1) as usize];
2858 d += SaSint::from(p1 < 0);
2859 p1 &= SAINT_MAX;
2860 let v1 = buckets_index2(
2861 t[(p1 - 1) as usize] as usize,
2862 usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]),
2863 );
2864 let mark1 = if buckets[2 * ALPHABET_SIZE + v1] != d {
2865 SAINT_MIN
2866 } else {
2867 0
2868 };
2869 buckets[v1] -= 1;
2870 sa[buckets[v1] as usize] = (p1 - 1) | mark1;
2871 buckets[2 * ALPHABET_SIZE + v1] = d;
2872
2873 i -= 2;
2874 }
2875
2876 j -= 64 + 1;
2877 while i >= j {
2878 let mut p = sa[i as usize];
2879 d += SaSint::from(p < 0);
2880 p &= SAINT_MAX;
2881 let v = buckets_index2(
2882 t[(p - 1) as usize] as usize,
2883 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
2884 );
2885 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2886 SAINT_MIN
2887 } else {
2888 0
2889 };
2890 buckets[v] -= 1;
2891 sa[buckets[v] as usize] = (p - 1) | mark;
2892 buckets[2 * ALPHABET_SIZE + v] = d;
2893 i -= 1;
2894 }
2895
2896 d
2897}
2898
2899fn partial_sorting_scan_right_to_left_16u_block_prepare(
2900 t: &[u16],
2901 sa: &mut [SaSint],
2902 k: SaSint,
2903 buckets: &mut [SaSint],
2904 cache: &mut [ThreadCache],
2905 omp_block_start: SaSint,
2906 omp_block_size: SaSint,
2907 state: &mut ThreadState,
2908) -> SaSint {
2909 let width = 2 * k as usize;
2910 buckets[..width].fill(0);
2911 buckets[2 * ALPHABET_SIZE..2 * ALPHABET_SIZE + width].fill(0);
2912
2913 let mut count = 0usize;
2914 let mut d = 1;
2915 for i in (omp_block_start as usize..(omp_block_start + omp_block_size) as usize).rev() {
2916 let mut p = sa[i];
2917 cache[count].index = p;
2918 d += SaSint::from(p < 0);
2919 p &= SAINT_MAX;
2920 let v = buckets_index2(
2921 t[(p - 1) as usize] as usize,
2922 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
2923 );
2924 cache[count].symbol = v as SaSint;
2925 buckets[v] += 1;
2926 buckets[2 * ALPHABET_SIZE + v] = d;
2927 count += 1;
2928 }
2929 state.cache_entries = count;
2930 d - 1
2931}
2932
2933fn partial_sorting_scan_right_to_left_16u_block_place(
2934 sa: &mut [SaSint],
2935 buckets: &mut [SaSint],
2936 cache: &[ThreadCache],
2937 count: SaSint,
2938 mut d: SaSint,
2939) {
2940 for entry in cache.iter().take(count as usize) {
2941 let mut p = entry.index;
2942 d += SaSint::from(p < 0);
2943 p &= SAINT_MAX;
2944 let v = entry.symbol as usize;
2945 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2946 SAINT_MIN
2947 } else {
2948 0
2949 };
2950 buckets[v] -= 1;
2951 sa[buckets[v] as usize] = (p - 1) | mark;
2952 buckets[2 * ALPHABET_SIZE + v] = d;
2953 }
2954}
2955
2956fn partial_gsa_scan_right_to_left_16u_block_place(
2957 sa: &mut [SaSint],
2958 buckets: &mut [SaSint],
2959 cache: &[ThreadCache],
2960 count: SaSint,
2961 mut d: SaSint,
2962) {
2963 for entry in cache.iter().take(count as usize) {
2964 let mut p = entry.index;
2965 d += SaSint::from(p < 0);
2966 p &= SAINT_MAX;
2967 let v = entry.symbol as usize;
2968 if v != 1 {
2969 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2970 SAINT_MIN
2971 } else {
2972 0
2973 };
2974 buckets[v] -= 1;
2975 sa[buckets[v] as usize] = (p - 1) | mark;
2976 buckets[2 * ALPHABET_SIZE + v] = d;
2977 }
2978 }
2979}
2980
2981fn partial_sorting_scan_right_to_left_16u_block_omp(
2982 t: &[u16],
2983 sa: &mut [SaSint],
2984 k: SaSint,
2985 buckets: &mut [SaSint],
2986 d: SaSint,
2987 block_start: SaSint,
2988 block_size: SaSint,
2989 threads: SaSint,
2990 thread_state: &mut [ThreadState],
2991) -> SaSint {
2992 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
2993 usize::try_from(threads)
2994 .expect("threads must be non-negative")
2995 .min(thread_state.len())
2996 } else {
2997 1
2998 };
2999 if thread_count <= 1 {
3000 return partial_sorting_scan_right_to_left_16u(t, sa, buckets, d, block_start, block_size);
3001 }
3002
3003 let width = 2 * k as usize;
3004 let distinct_offset = 2 * ALPHABET_SIZE;
3005 let block_stride = (block_size / thread_count as SaSint) & !15;
3006
3007 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
3008 let local_start = thread as SaSint * block_stride;
3009 let local_size = if thread + 1 < thread_count {
3010 block_stride
3011 } else {
3012 block_size - local_start
3013 };
3014 let mut local_state = ThreadState::default();
3015 state.position = partial_sorting_scan_right_to_left_16u_block_prepare(
3016 t,
3017 sa,
3018 k,
3019 &mut state.buckets,
3020 &mut state.cache,
3021 block_start + local_start,
3022 local_size,
3023 &mut local_state,
3024 );
3025 state.count = local_state.cache_entries as SaSint;
3026 }
3027
3028 let mut next_d = d;
3029 for state in thread_state.iter_mut().take(thread_count).rev() {
3030 for c in 0..width {
3031 let a = buckets[c];
3032 let b = state.buckets[c];
3033 buckets[c] = a - b;
3034 state.buckets[c] = a;
3035 }
3036
3037 next_d -= 1;
3038 for c in 0..width {
3039 let offset = distinct_offset + c;
3040 let a = buckets[offset];
3041 let b = state.buckets[offset];
3042 let shifted = b + next_d;
3043 buckets[offset] = if b > 0 { shifted } else { a };
3044 state.buckets[offset] = a;
3045 }
3046 next_d += 1 + state.position;
3047 state.position = next_d - state.position;
3048 }
3049
3050 for state in thread_state.iter_mut().take(thread_count) {
3051 partial_sorting_scan_right_to_left_16u_block_place(
3052 sa,
3053 &mut state.buckets,
3054 &state.cache,
3055 state.count,
3056 state.position,
3057 );
3058 }
3059
3060 next_d
3061}
3062
3063fn partial_sorting_scan_right_to_left_16u_omp(
3064 t: &[u16],
3065 sa: &mut [SaSint],
3066 n: SaSint,
3067 k: SaSint,
3068 buckets: &mut [SaSint],
3069 first_lms_suffix: SaSint,
3070 left_suffixes_count: SaSint,
3071 d: SaSint,
3072 threads: SaSint,
3073) {
3074 let scan_start = left_suffixes_count + 1;
3075 let scan_end = n - first_lms_suffix;
3076
3077 if threads == 1 || scan_end - scan_start < 65536 {
3078 partial_sorting_scan_right_to_left_16u(
3079 t,
3080 sa,
3081 buckets,
3082 d,
3083 scan_start,
3084 scan_end - scan_start,
3085 );
3086 } else {
3087 let mut d = d;
3088 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
3089 let mut block_start = scan_end - 1;
3090 while block_start >= scan_start {
3091 if sa[block_start as usize] == 0 {
3092 block_start -= 1;
3093 } else {
3094 let block_limit = threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
3095 let mut block_max_end = block_start - block_limit;
3096 if block_max_end < scan_start {
3097 block_max_end = scan_start - 1;
3098 }
3099 let mut block_end = block_start - 1;
3100 while block_end > block_max_end && sa[block_end as usize] != 0 {
3101 block_end -= 1;
3102 }
3103 let block_size = block_start - block_end;
3104
3105 if block_size < 32 {
3106 while block_start > block_end {
3107 let mut p = sa[block_start as usize];
3108 d += SaSint::from(p < 0);
3109 p &= SAINT_MAX;
3110 let v = buckets_index2(
3111 t[(p - 1) as usize] as usize,
3112 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
3113 );
3114 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
3115 SAINT_MIN
3116 } else {
3117 0
3118 };
3119 buckets[v] -= 1;
3120 sa[buckets[v] as usize] = (p - 1) | mark;
3121 buckets[2 * ALPHABET_SIZE + v] = d;
3122 block_start -= 1;
3123 }
3124 } else {
3125 d = partial_sorting_scan_right_to_left_16u_block_omp(
3126 t,
3127 sa,
3128 k,
3129 buckets,
3130 d,
3131 block_end + 1,
3132 block_size,
3133 threads,
3134 &mut thread_state,
3135 );
3136 block_start = block_end;
3137 }
3138 }
3139 }
3140 }
3141}
3142
3143fn partial_sorting_scan_left_to_right_32s_6k(
3144 t: &[SaSint],
3145 sa: &mut [SaSint],
3146 buckets: &mut [SaSint],
3147 mut d: SaSint,
3148 omp_block_start: SaSint,
3149 omp_block_size: SaSint,
3150) -> SaSint {
3151 let mut i = omp_block_start;
3152 let mut j = omp_block_start + omp_block_size - 2 * 64 - 1;
3153
3154 while i < j {
3155 let mut p2 = sa[i as usize];
3156 d += SaSint::from(p2 < 0);
3157 p2 &= SAINT_MAX;
3158 let v2 = buckets_index4(
3159 t[(p2 - 1) as usize] as usize,
3160 usize::from(t[(p2 - 2) as usize] >= t[(p2 - 1) as usize]),
3161 );
3162 let pos2 = buckets[v2] as usize;
3163 buckets[v2] += 1;
3164 sa[pos2] = (p2 - 1) | (((buckets[2 + v2] != d) as SaSint) << (SAINT_BIT - 1));
3165 buckets[2 + v2] = d;
3166
3167 let mut p3 = sa[(i + 1) as usize];
3168 d += SaSint::from(p3 < 0);
3169 p3 &= SAINT_MAX;
3170 let v3 = buckets_index4(
3171 t[(p3 - 1) as usize] as usize,
3172 usize::from(t[(p3 - 2) as usize] >= t[(p3 - 1) as usize]),
3173 );
3174 let pos3 = buckets[v3] as usize;
3175 buckets[v3] += 1;
3176 sa[pos3] = (p3 - 1) | (((buckets[2 + v3] != d) as SaSint) << (SAINT_BIT - 1));
3177 buckets[2 + v3] = d;
3178
3179 i += 2;
3180 }
3181
3182 j += 2 * 64 + 1;
3183 while i < j {
3184 let mut p = sa[i as usize];
3185 d += SaSint::from(p < 0);
3186 p &= SAINT_MAX;
3187 let v = buckets_index4(
3188 t[(p - 1) as usize] as usize,
3189 usize::from(t[(p - 2) as usize] >= t[(p - 1) as usize]),
3190 );
3191 let pos = buckets[v] as usize;
3192 buckets[v] += 1;
3193 sa[pos] = (p - 1) | (((buckets[2 + v] != d) as SaSint) << (SAINT_BIT - 1));
3194 buckets[2 + v] = d;
3195 i += 1;
3196 }
3197
3198 d
3199}
3200
3201fn partial_sorting_scan_left_to_right_32s_4k(
3202 t: &[SaSint],
3203 sa: &mut [SaSint],
3204 k: SaSint,
3205 buckets: &mut [SaSint],
3206 mut d: SaSint,
3207 omp_block_start: SaSint,
3208 omp_block_size: SaSint,
3209) -> SaSint {
3210 let k = k as usize;
3211 let mut i = omp_block_start;
3212 let mut j = omp_block_start + omp_block_size - 2 * 64 - 1;
3213
3214 while i < j {
3215 let mut p0 = sa[i as usize];
3216 sa[i as usize] = p0 & SAINT_MAX;
3217 if p0 > 0 {
3218 sa[i as usize] = 0;
3219 d += p0 >> (SUFFIX_GROUP_BIT - 1);
3220 p0 &= !SUFFIX_GROUP_MARKER;
3221 let v0 = buckets_index2(
3222 t[(p0 - 1) as usize] as usize,
3223 usize::from(t[(p0 - 2) as usize] < t[(p0 - 1) as usize]),
3224 );
3225 let c0 = t[(p0 - 1) as usize] as usize;
3226 let pos0 = buckets[2 * k + c0] as usize;
3227 buckets[2 * k + c0] += 1;
3228 sa[pos0] = (p0 - 1)
3229 | ((usize::from(t[(p0 - 2) as usize] < t[(p0 - 1) as usize]) as SaSint)
3230 << (SAINT_BIT - 1))
3231 | (((buckets[v0] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3232 buckets[v0] = d;
3233 }
3234
3235 let mut p1 = sa[(i + 1) as usize];
3236 sa[(i + 1) as usize] = p1 & SAINT_MAX;
3237 if p1 > 0 {
3238 sa[(i + 1) as usize] = 0;
3239 d += p1 >> (SUFFIX_GROUP_BIT - 1);
3240 p1 &= !SUFFIX_GROUP_MARKER;
3241 let v1 = buckets_index2(
3242 t[(p1 - 1) as usize] as usize,
3243 usize::from(t[(p1 - 2) as usize] < t[(p1 - 1) as usize]),
3244 );
3245 let c1 = t[(p1 - 1) as usize] as usize;
3246 let pos1 = buckets[2 * k + c1] as usize;
3247 buckets[2 * k + c1] += 1;
3248 sa[pos1] = (p1 - 1)
3249 | ((usize::from(t[(p1 - 2) as usize] < t[(p1 - 1) as usize]) as SaSint)
3250 << (SAINT_BIT - 1))
3251 | (((buckets[v1] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3252 buckets[v1] = d;
3253 }
3254
3255 i += 2;
3256 }
3257
3258 j += 2 * 64 + 1;
3259 while i < j {
3260 let mut p = sa[i as usize];
3261 sa[i as usize] = p & SAINT_MAX;
3262 if p > 0 {
3263 sa[i as usize] = 0;
3264 d += p >> (SUFFIX_GROUP_BIT - 1);
3265 p &= !SUFFIX_GROUP_MARKER;
3266 let v = buckets_index2(
3267 t[(p - 1) as usize] as usize,
3268 usize::from(t[(p - 2) as usize] < t[(p - 1) as usize]),
3269 );
3270 let c = t[(p - 1) as usize] as usize;
3271 let pos = buckets[2 * k + c] as usize;
3272 buckets[2 * k + c] += 1;
3273 sa[pos] = (p - 1)
3274 | ((usize::from(t[(p - 2) as usize] < t[(p - 1) as usize]) as SaSint)
3275 << (SAINT_BIT - 1))
3276 | (((buckets[v] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3277 buckets[v] = d;
3278 }
3279 i += 1;
3280 }
3281
3282 d
3283}
3284
3285fn partial_sorting_scan_left_to_right_32s_1k(
3286 t: &[SaSint],
3287 sa: &mut [SaSint],
3288 induction_bucket: &mut [SaSint],
3289 omp_block_start: SaSint,
3290 omp_block_size: SaSint,
3291) {
3292 let mut i = omp_block_start;
3293 let mut j = omp_block_start + omp_block_size - 2 * 64 - 1;
3294
3295 while i < j {
3296 let p0 = sa[i as usize];
3297 sa[i as usize] = p0 & SAINT_MAX;
3298 if p0 > 0 {
3299 sa[i as usize] = 0;
3300 let c0 = t[(p0 - 1) as usize] as usize;
3301 let pos0 = induction_bucket[c0] as usize;
3302 induction_bucket[c0] += 1;
3303 sa[pos0] = (p0 - 1)
3304 | ((usize::from(t[(p0 - 2) as usize] < t[(p0 - 1) as usize]) as SaSint)
3305 << (SAINT_BIT - 1));
3306 }
3307
3308 let p1 = sa[(i + 1) as usize];
3309 sa[(i + 1) as usize] = p1 & SAINT_MAX;
3310 if p1 > 0 {
3311 sa[(i + 1) as usize] = 0;
3312 let c1 = t[(p1 - 1) as usize] as usize;
3313 let pos1 = induction_bucket[c1] as usize;
3314 induction_bucket[c1] += 1;
3315 sa[pos1] = (p1 - 1)
3316 | ((usize::from(t[(p1 - 2) as usize] < t[(p1 - 1) as usize]) as SaSint)
3317 << (SAINT_BIT - 1));
3318 }
3319
3320 i += 2;
3321 }
3322
3323 j += 2 * 64 + 1;
3324 while i < j {
3325 let p = sa[i as usize];
3326 sa[i as usize] = p & SAINT_MAX;
3327 if p > 0 {
3328 sa[i as usize] = 0;
3329 let c = t[(p - 1) as usize] as usize;
3330 let pos = induction_bucket[c] as usize;
3331 induction_bucket[c] += 1;
3332 sa[pos] = (p - 1)
3333 | ((usize::from(t[(p - 2) as usize] < t[(p - 1) as usize]) as SaSint)
3334 << (SAINT_BIT - 1));
3335 }
3336 i += 1;
3337 }
3338}
3339
3340fn partial_sorting_scan_left_to_right_32s_6k_omp(
3341 t: &[SaSint],
3342 sa: &mut [SaSint],
3343 n: SaSint,
3344 buckets: &mut [SaSint],
3345 left_suffixes_count: SaSint,
3346 mut d: SaSint,
3347 threads: SaSint,
3348 _thread_state: &mut [ThreadState],
3349) -> SaSint {
3350 let v = buckets_index4(
3351 t[(n - 1) as usize] as usize,
3352 usize::from(t[(n - 2) as usize] >= t[(n - 1) as usize]),
3353 );
3354 let pos = buckets[v] as usize;
3355 buckets[v] += 1;
3356 sa[pos] = (n - 1) | SAINT_MIN;
3357 d += 1;
3358 buckets[2 + v] = d;
3359
3360 if threads == 1 || left_suffixes_count < 65536 {
3361 d = partial_sorting_scan_left_to_right_32s_6k(t, sa, buckets, d, 0, left_suffixes_count);
3362 } else {
3363 let mut cache = vec![ThreadCache::default(); left_suffixes_count as usize];
3364 let mut block_start = 0;
3365 while block_start < left_suffixes_count {
3366 let mut block_end = block_start + threads * PER_THREAD_CACHE_SIZE as SaSint;
3367 if block_end > left_suffixes_count {
3368 block_end = left_suffixes_count;
3369 }
3370 d = partial_sorting_scan_left_to_right_32s_6k_block_omp(
3371 t,
3372 sa,
3373 buckets,
3374 d,
3375 &mut cache,
3376 block_start,
3377 block_end - block_start,
3378 threads,
3379 );
3380 block_start = block_end;
3381 }
3382 }
3383
3384 d
3385}
3386
3387fn partial_sorting_scan_left_to_right_32s_4k_omp(
3388 t: &[SaSint],
3389 sa: &mut [SaSint],
3390 n: SaSint,
3391 k: SaSint,
3392 buckets: &mut [SaSint],
3393 mut d: SaSint,
3394 threads: SaSint,
3395 _thread_state: &mut [ThreadState],
3396) -> SaSint {
3397 let k_usize = k as usize;
3398 let pos = buckets[2 * k_usize + t[(n - 1) as usize] as usize] as usize;
3399 buckets[2 * k_usize + t[(n - 1) as usize] as usize] += 1;
3400 sa[pos] = (n - 1)
3401 | ((usize::from(t[(n - 2) as usize] < t[(n - 1) as usize]) as SaSint) << (SAINT_BIT - 1))
3402 | SUFFIX_GROUP_MARKER;
3403 d += 1;
3404 buckets[buckets_index2(
3405 t[(n - 1) as usize] as usize,
3406 usize::from(t[(n - 2) as usize] < t[(n - 1) as usize]),
3407 )] = d;
3408
3409 if threads == 1 || n < 65536 {
3410 d = partial_sorting_scan_left_to_right_32s_4k(t, sa, k, buckets, d, 0, n);
3411 } else {
3412 let mut cache = vec![ThreadCache::default(); n as usize];
3413 let mut block_start = 0;
3414 while block_start < n {
3415 let mut block_end = block_start + threads * PER_THREAD_CACHE_SIZE as SaSint;
3416 if block_end > n {
3417 block_end = n;
3418 }
3419 d = partial_sorting_scan_left_to_right_32s_4k_block_omp(
3420 t,
3421 sa,
3422 k,
3423 buckets,
3424 d,
3425 &mut cache,
3426 block_start,
3427 block_end - block_start,
3428 threads,
3429 );
3430 block_start = block_end;
3431 }
3432 }
3433
3434 d
3435}
3436
3437fn partial_sorting_scan_left_to_right_32s_1k_omp(
3438 t: &[SaSint],
3439 sa: &mut [SaSint],
3440 n: SaSint,
3441 buckets: &mut [SaSint],
3442 threads: SaSint,
3443 _thread_state: &mut [ThreadState],
3444) {
3445 let pos = buckets[t[(n - 1) as usize] as usize] as usize;
3446 buckets[t[(n - 1) as usize] as usize] += 1;
3447 sa[pos] = (n - 1)
3448 | ((usize::from(t[(n - 2) as usize] < t[(n - 1) as usize]) as SaSint) << (SAINT_BIT - 1));
3449
3450 if threads == 1 || n < 65536 {
3451 partial_sorting_scan_left_to_right_32s_1k(t, sa, buckets, 0, n);
3452 } else {
3453 let mut cache = vec![ThreadCache::default(); n as usize];
3454 let mut block_start = 0;
3455 while block_start < n {
3456 let mut block_end = block_start + threads * PER_THREAD_CACHE_SIZE as SaSint;
3457 if block_end > n {
3458 block_end = n;
3459 }
3460 partial_sorting_scan_left_to_right_32s_1k_block_omp(
3461 t,
3462 sa,
3463 buckets,
3464 &mut cache,
3465 block_start,
3466 block_end - block_start,
3467 threads,
3468 );
3469 block_start = block_end;
3470 }
3471 }
3472}
3473
3474fn partial_sorting_scan_right_to_left_32s_6k(
3475 t: &[SaSint],
3476 sa: &mut [SaSint],
3477 buckets: &mut [SaSint],
3478 mut d: SaSint,
3479 omp_block_start: SaSint,
3480 omp_block_size: SaSint,
3481) -> SaSint {
3482 if omp_block_size <= 0 {
3483 return d;
3484 }
3485
3486 let mut i = omp_block_start + omp_block_size - 1;
3487 let mut j = omp_block_start + 2 * 64 + 1;
3488
3489 while i >= j {
3490 let mut p2 = sa[i as usize];
3491 d += SaSint::from(p2 < 0);
3492 p2 &= SAINT_MAX;
3493 let v2 = buckets_index4(
3494 t[(p2 - 1) as usize] as usize,
3495 usize::from(t[(p2 - 2) as usize] > t[(p2 - 1) as usize]),
3496 );
3497 buckets[v2] -= 1;
3498 sa[buckets[v2] as usize] =
3499 (p2 - 1) | (((buckets[2 + v2] != d) as SaSint) << (SAINT_BIT - 1));
3500 buckets[2 + v2] = d;
3501
3502 let mut p3 = sa[(i - 1) as usize];
3503 d += SaSint::from(p3 < 0);
3504 p3 &= SAINT_MAX;
3505 let v3 = buckets_index4(
3506 t[(p3 - 1) as usize] as usize,
3507 usize::from(t[(p3 - 2) as usize] > t[(p3 - 1) as usize]),
3508 );
3509 buckets[v3] -= 1;
3510 sa[buckets[v3] as usize] =
3511 (p3 - 1) | (((buckets[2 + v3] != d) as SaSint) << (SAINT_BIT - 1));
3512 buckets[2 + v3] = d;
3513
3514 i -= 2;
3515 }
3516
3517 j -= 2 * 64 + 1;
3518 while i >= j {
3519 let mut p = sa[i as usize];
3520 d += SaSint::from(p < 0);
3521 p &= SAINT_MAX;
3522 let v = buckets_index4(
3523 t[(p - 1) as usize] as usize,
3524 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
3525 );
3526 buckets[v] -= 1;
3527 sa[buckets[v] as usize] = (p - 1) | (((buckets[2 + v] != d) as SaSint) << (SAINT_BIT - 1));
3528 buckets[2 + v] = d;
3529 i -= 1;
3530 }
3531
3532 d
3533}
3534
3535fn partial_sorting_scan_right_to_left_32s_4k(
3536 t: &[SaSint],
3537 sa: &mut [SaSint],
3538 k: SaSint,
3539 buckets: &mut [SaSint],
3540 mut d: SaSint,
3541 omp_block_start: SaSint,
3542 omp_block_size: SaSint,
3543) -> SaSint {
3544 if omp_block_size <= 0 {
3545 return d;
3546 }
3547
3548 let k = k as usize;
3549 let mut i = omp_block_start + omp_block_size - 1;
3550 let mut j = omp_block_start + 2 * 64 + 1;
3551
3552 while i >= j {
3553 let mut p0 = sa[i as usize];
3554 if p0 > 0 {
3555 sa[i as usize] = 0;
3556 d += p0 >> (SUFFIX_GROUP_BIT - 1);
3557 p0 &= !SUFFIX_GROUP_MARKER;
3558 let v0 = buckets_index2(
3559 t[(p0 - 1) as usize] as usize,
3560 usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]),
3561 );
3562 let c0 = t[(p0 - 1) as usize] as usize;
3563 buckets[3 * k + c0] -= 1;
3564 sa[buckets[3 * k + c0] as usize] = (p0 - 1)
3565 | ((usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]) as SaSint)
3566 << (SAINT_BIT - 1))
3567 | (((buckets[v0] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3568 buckets[v0] = d;
3569 }
3570
3571 let mut p1 = sa[(i - 1) as usize];
3572 if p1 > 0 {
3573 sa[(i - 1) as usize] = 0;
3574 d += p1 >> (SUFFIX_GROUP_BIT - 1);
3575 p1 &= !SUFFIX_GROUP_MARKER;
3576 let v1 = buckets_index2(
3577 t[(p1 - 1) as usize] as usize,
3578 usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]),
3579 );
3580 let c1 = t[(p1 - 1) as usize] as usize;
3581 buckets[3 * k + c1] -= 1;
3582 sa[buckets[3 * k + c1] as usize] = (p1 - 1)
3583 | ((usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]) as SaSint)
3584 << (SAINT_BIT - 1))
3585 | (((buckets[v1] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3586 buckets[v1] = d;
3587 }
3588
3589 i -= 2;
3590 }
3591
3592 j -= 2 * 64 + 1;
3593 while i >= j {
3594 let mut p = sa[i as usize];
3595 if p > 0 {
3596 sa[i as usize] = 0;
3597 d += p >> (SUFFIX_GROUP_BIT - 1);
3598 p &= !SUFFIX_GROUP_MARKER;
3599 let v = buckets_index2(
3600 t[(p - 1) as usize] as usize,
3601 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
3602 );
3603 let c = t[(p - 1) as usize] as usize;
3604 buckets[3 * k + c] -= 1;
3605 sa[buckets[3 * k + c] as usize] = (p - 1)
3606 | ((usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]) as SaSint)
3607 << (SAINT_BIT - 1))
3608 | (((buckets[v] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3609 buckets[v] = d;
3610 }
3611 i -= 1;
3612 }
3613
3614 d
3615}
3616
3617fn partial_sorting_scan_right_to_left_32s_1k(
3618 t: &[SaSint],
3619 sa: &mut [SaSint],
3620 induction_bucket: &mut [SaSint],
3621 omp_block_start: SaSint,
3622 omp_block_size: SaSint,
3623) {
3624 if omp_block_size <= 0 {
3625 return;
3626 }
3627
3628 let mut i = omp_block_start + omp_block_size - 1;
3629 let mut j = omp_block_start + 2 * 64 + 1;
3630
3631 while i >= j {
3632 let p0 = sa[i as usize];
3633 if p0 > 0 {
3634 sa[i as usize] = 0;
3635 let c0 = t[(p0 - 1) as usize] as usize;
3636 induction_bucket[c0] -= 1;
3637 sa[induction_bucket[c0] as usize] = (p0 - 1)
3638 | ((usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]) as SaSint)
3639 << (SAINT_BIT - 1));
3640 }
3641
3642 let p1 = sa[(i - 1) as usize];
3643 if p1 > 0 {
3644 sa[(i - 1) as usize] = 0;
3645 let c1 = t[(p1 - 1) as usize] as usize;
3646 induction_bucket[c1] -= 1;
3647 sa[induction_bucket[c1] as usize] = (p1 - 1)
3648 | ((usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]) as SaSint)
3649 << (SAINT_BIT - 1));
3650 }
3651
3652 i -= 2;
3653 }
3654
3655 j -= 2 * 64 + 1;
3656 while i >= j {
3657 let p = sa[i as usize];
3658 if p > 0 {
3659 sa[i as usize] = 0;
3660 let c = t[(p - 1) as usize] as usize;
3661 induction_bucket[c] -= 1;
3662 sa[induction_bucket[c] as usize] = (p - 1)
3663 | ((usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]) as SaSint)
3664 << (SAINT_BIT - 1));
3665 }
3666 i -= 1;
3667 }
3668}
3669
3670fn partial_sorting_scan_right_to_left_32s_6k_omp(
3671 t: &[SaSint],
3672 sa: &mut [SaSint],
3673 n: SaSint,
3674 buckets: &mut [SaSint],
3675 first_lms_suffix: SaSint,
3676 left_suffixes_count: SaSint,
3677 mut d: SaSint,
3678 threads: SaSint,
3679 _thread_state: &mut [ThreadState],
3680) -> SaSint {
3681 let scan_start = left_suffixes_count + 1;
3682 let scan_end = n - first_lms_suffix;
3683
3684 if threads == 1 || scan_end - scan_start < 65536 {
3685 d = partial_sorting_scan_right_to_left_32s_6k(
3686 t,
3687 sa,
3688 buckets,
3689 d,
3690 scan_start,
3691 scan_end - scan_start,
3692 );
3693 } else {
3694 let mut cache = vec![ThreadCache::default(); (scan_end - scan_start) as usize];
3695 let mut block_start = scan_end;
3696 while block_start > scan_start {
3697 let block_size =
3698 (block_start - scan_start).min(threads * PER_THREAD_CACHE_SIZE as SaSint);
3699 block_start -= block_size;
3700 d = partial_sorting_scan_right_to_left_32s_6k_block_omp(
3701 t,
3702 sa,
3703 buckets,
3704 d,
3705 &mut cache,
3706 block_start,
3707 block_size,
3708 threads,
3709 );
3710 }
3711 }
3712
3713 d
3714}
3715
3716fn partial_sorting_scan_right_to_left_32s_4k_omp(
3717 t: &[SaSint],
3718 sa: &mut [SaSint],
3719 n: SaSint,
3720 k: SaSint,
3721 buckets: &mut [SaSint],
3722 mut d: SaSint,
3723 threads: SaSint,
3724 _thread_state: &mut [ThreadState],
3725) -> SaSint {
3726 if threads == 1 || n < 65536 {
3727 d = partial_sorting_scan_right_to_left_32s_4k(t, sa, k, buckets, d, 0, n);
3728 } else {
3729 let mut cache = vec![ThreadCache::default(); n as usize];
3730 let mut block_start = n;
3731 while block_start > 0 {
3732 let block_size = block_start.min(threads * PER_THREAD_CACHE_SIZE as SaSint);
3733 block_start -= block_size;
3734 d = partial_sorting_scan_right_to_left_32s_4k_block_omp(
3735 t,
3736 sa,
3737 k,
3738 buckets,
3739 d,
3740 &mut cache,
3741 block_start,
3742 block_size,
3743 threads,
3744 );
3745 }
3746 }
3747
3748 d
3749}
3750
3751fn partial_sorting_scan_right_to_left_32s_1k_omp(
3752 t: &[SaSint],
3753 sa: &mut [SaSint],
3754 n: SaSint,
3755 buckets: &mut [SaSint],
3756 threads: SaSint,
3757 _thread_state: &mut [ThreadState],
3758) {
3759 if threads == 1 || n < 65536 {
3760 partial_sorting_scan_right_to_left_32s_1k(t, sa, buckets, 0, n);
3761 } else {
3762 let mut cache = vec![ThreadCache::default(); n as usize];
3763 let mut block_start = n;
3764 while block_start > 0 {
3765 let block_size = block_start.min(threads * PER_THREAD_CACHE_SIZE as SaSint);
3766 block_start -= block_size;
3767 partial_sorting_scan_right_to_left_32s_1k_block_omp(
3768 t,
3769 sa,
3770 buckets,
3771 &mut cache,
3772 block_start,
3773 block_size,
3774 threads,
3775 );
3776 }
3777 }
3778}
3779
3780fn partial_sorting_scan_left_to_right_32s_6k_block_gather(
3781 t: &[SaSint],
3782 sa: &mut [SaSint],
3783 cache: &mut [ThreadCache],
3784 omp_block_start: SaSint,
3785 omp_block_size: SaSint,
3786) {
3787 let mut i = omp_block_start;
3788 let mut j = omp_block_start + omp_block_size - 64 - 1;
3789
3790 while i < j {
3791 let p0 = sa[i as usize];
3792 cache[i as usize].index = p0;
3793 let p0 = p0 & SAINT_MAX;
3794 cache[i as usize].symbol = if p0 != 0 {
3795 buckets_index4(
3796 t[(p0 - 1) as usize] as usize,
3797 usize::from(t[(p0 - 2) as usize] >= t[(p0 - 1) as usize]),
3798 ) as SaSint
3799 } else {
3800 0
3801 };
3802
3803 let p1 = sa[(i + 1) as usize];
3804 cache[(i + 1) as usize].index = p1;
3805 let p1 = p1 & SAINT_MAX;
3806 cache[(i + 1) as usize].symbol = if p1 != 0 {
3807 buckets_index4(
3808 t[(p1 - 1) as usize] as usize,
3809 usize::from(t[(p1 - 2) as usize] >= t[(p1 - 1) as usize]),
3810 ) as SaSint
3811 } else {
3812 0
3813 };
3814
3815 i += 2;
3816 }
3817
3818 j += 64 + 1;
3819 while i < j {
3820 let p = sa[i as usize];
3821 cache[i as usize].index = p;
3822 let p = p & SAINT_MAX;
3823 cache[i as usize].symbol = if p != 0 {
3824 buckets_index4(
3825 t[(p - 1) as usize] as usize,
3826 usize::from(t[(p - 2) as usize] >= t[(p - 1) as usize]),
3827 ) as SaSint
3828 } else {
3829 0
3830 };
3831 i += 1;
3832 }
3833}
3834
3835fn partial_sorting_scan_left_to_right_32s_4k_block_gather(
3836 t: &[SaSint],
3837 sa: &mut [SaSint],
3838 cache: &mut [ThreadCache],
3839 omp_block_start: SaSint,
3840 omp_block_size: SaSint,
3841) {
3842 let mut i = omp_block_start;
3843 let mut j = omp_block_start + omp_block_size - 64 - 1;
3844
3845 while i < j {
3846 let mut symbol0 = SAINT_MIN;
3847 let mut p0 = sa[i as usize];
3848 if p0 > 0 {
3849 cache[i as usize].index = p0;
3850 p0 &= !SUFFIX_GROUP_MARKER;
3851 symbol0 = buckets_index2(
3852 t[(p0 - 1) as usize] as usize,
3853 usize::from(t[(p0 - 2) as usize] < t[(p0 - 1) as usize]),
3854 ) as SaSint;
3855 p0 = 0;
3856 }
3857 cache[i as usize].symbol = symbol0;
3858 sa[i as usize] = p0 & SAINT_MAX;
3859
3860 let mut symbol1 = SAINT_MIN;
3861 let mut p1 = sa[(i + 1) as usize];
3862 if p1 > 0 {
3863 cache[(i + 1) as usize].index = p1;
3864 p1 &= !SUFFIX_GROUP_MARKER;
3865 symbol1 = buckets_index2(
3866 t[(p1 - 1) as usize] as usize,
3867 usize::from(t[(p1 - 2) as usize] < t[(p1 - 1) as usize]),
3868 ) as SaSint;
3869 p1 = 0;
3870 }
3871 cache[(i + 1) as usize].symbol = symbol1;
3872 sa[(i + 1) as usize] = p1 & SAINT_MAX;
3873
3874 i += 2;
3875 }
3876
3877 j += 64 + 1;
3878 while i < j {
3879 let mut symbol = SAINT_MIN;
3880 let mut p = sa[i as usize];
3881 if p > 0 {
3882 cache[i as usize].index = p;
3883 p &= !SUFFIX_GROUP_MARKER;
3884 symbol = buckets_index2(
3885 t[(p - 1) as usize] as usize,
3886 usize::from(t[(p - 2) as usize] < t[(p - 1) as usize]),
3887 ) as SaSint;
3888 p = 0;
3889 }
3890 cache[i as usize].symbol = symbol;
3891 sa[i as usize] = p & SAINT_MAX;
3892 i += 1;
3893 }
3894}
3895
3896fn partial_sorting_scan_left_to_right_32s_1k_block_gather(
3897 t: &[SaSint],
3898 sa: &mut [SaSint],
3899 cache: &mut [ThreadCache],
3900 omp_block_start: SaSint,
3901 omp_block_size: SaSint,
3902) {
3903 let mut i = omp_block_start;
3904 let mut j = omp_block_start + omp_block_size - 64 - 1;
3905
3906 while i < j {
3907 let mut symbol0 = SAINT_MIN;
3908 let mut p0 = sa[i as usize];
3909 if p0 > 0 {
3910 cache[i as usize].index = (p0 - 1)
3911 | ((usize::from(t[(p0 - 2) as usize] < t[(p0 - 1) as usize]) as SaSint)
3912 << (SAINT_BIT - 1));
3913 symbol0 = t[(p0 - 1) as usize];
3914 p0 = 0;
3915 }
3916 cache[i as usize].symbol = symbol0;
3917 sa[i as usize] = p0 & SAINT_MAX;
3918
3919 let mut symbol1 = SAINT_MIN;
3920 let mut p1 = sa[(i + 1) as usize];
3921 if p1 > 0 {
3922 cache[(i + 1) as usize].index = (p1 - 1)
3923 | ((usize::from(t[(p1 - 2) as usize] < t[(p1 - 1) as usize]) as SaSint)
3924 << (SAINT_BIT - 1));
3925 symbol1 = t[(p1 - 1) as usize];
3926 p1 = 0;
3927 }
3928 cache[(i + 1) as usize].symbol = symbol1;
3929 sa[(i + 1) as usize] = p1 & SAINT_MAX;
3930
3931 i += 2;
3932 }
3933
3934 j += 64 + 1;
3935 while i < j {
3936 let mut symbol = SAINT_MIN;
3937 let mut p = sa[i as usize];
3938 if p > 0 {
3939 cache[i as usize].index = (p - 1)
3940 | ((usize::from(t[(p - 2) as usize] < t[(p - 1) as usize]) as SaSint)
3941 << (SAINT_BIT - 1));
3942 symbol = t[(p - 1) as usize];
3943 p = 0;
3944 }
3945 cache[i as usize].symbol = symbol;
3946 sa[i as usize] = p & SAINT_MAX;
3947 i += 1;
3948 }
3949}
3950
3951fn partial_sorting_scan_right_to_left_32s_6k_block_gather(
3952 t: &[SaSint],
3953 sa: &mut [SaSint],
3954 cache: &mut [ThreadCache],
3955 omp_block_start: SaSint,
3956 omp_block_size: SaSint,
3957) {
3958 let mut i = omp_block_start;
3959 let mut j = omp_block_start + omp_block_size - 64 - 1;
3960
3961 while i < j {
3962 let p0 = sa[i as usize];
3963 cache[i as usize].index = p0;
3964 let p0 = p0 & SAINT_MAX;
3965 cache[i as usize].symbol = if p0 != 0 {
3966 buckets_index4(
3967 t[(p0 - 1) as usize] as usize,
3968 usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]),
3969 ) as SaSint
3970 } else {
3971 0
3972 };
3973
3974 let p1 = sa[(i + 1) as usize];
3975 cache[(i + 1) as usize].index = p1;
3976 let p1 = p1 & SAINT_MAX;
3977 cache[(i + 1) as usize].symbol = if p1 != 0 {
3978 buckets_index4(
3979 t[(p1 - 1) as usize] as usize,
3980 usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]),
3981 ) as SaSint
3982 } else {
3983 0
3984 };
3985
3986 i += 2;
3987 }
3988
3989 j += 64 + 1;
3990 while i < j {
3991 let p = sa[i as usize];
3992 cache[i as usize].index = p;
3993 let p = p & SAINT_MAX;
3994 cache[i as usize].symbol = if p != 0 {
3995 buckets_index4(
3996 t[(p - 1) as usize] as usize,
3997 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
3998 ) as SaSint
3999 } else {
4000 0
4001 };
4002 i += 1;
4003 }
4004}
4005
4006fn partial_sorting_scan_right_to_left_32s_4k_block_gather(
4007 t: &[SaSint],
4008 sa: &mut [SaSint],
4009 cache: &mut [ThreadCache],
4010 omp_block_start: SaSint,
4011 omp_block_size: SaSint,
4012) {
4013 let mut i = omp_block_start;
4014 let mut j = omp_block_start + omp_block_size - 64 - 1;
4015
4016 while i < j {
4017 let mut symbol0 = SAINT_MIN;
4018 let mut p0 = sa[i as usize];
4019 if p0 > 0 {
4020 sa[i as usize] = 0;
4021 cache[i as usize].index = p0;
4022 p0 &= !SUFFIX_GROUP_MARKER;
4023 symbol0 = buckets_index2(
4024 t[(p0 - 1) as usize] as usize,
4025 usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]),
4026 ) as SaSint;
4027 }
4028 cache[i as usize].symbol = symbol0;
4029
4030 let mut symbol1 = SAINT_MIN;
4031 let mut p1 = sa[(i + 1) as usize];
4032 if p1 > 0 {
4033 sa[(i + 1) as usize] = 0;
4034 cache[(i + 1) as usize].index = p1;
4035 p1 &= !SUFFIX_GROUP_MARKER;
4036 symbol1 = buckets_index2(
4037 t[(p1 - 1) as usize] as usize,
4038 usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]),
4039 ) as SaSint;
4040 }
4041 cache[(i + 1) as usize].symbol = symbol1;
4042
4043 i += 2;
4044 }
4045
4046 j += 64 + 1;
4047 while i < j {
4048 let mut symbol = SAINT_MIN;
4049 let mut p = sa[i as usize];
4050 if p > 0 {
4051 sa[i as usize] = 0;
4052 cache[i as usize].index = p;
4053 p &= !SUFFIX_GROUP_MARKER;
4054 symbol = buckets_index2(
4055 t[(p - 1) as usize] as usize,
4056 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
4057 ) as SaSint;
4058 }
4059 cache[i as usize].symbol = symbol;
4060 i += 1;
4061 }
4062}
4063
4064fn partial_sorting_scan_right_to_left_32s_1k_block_gather(
4065 t: &[SaSint],
4066 sa: &mut [SaSint],
4067 cache: &mut [ThreadCache],
4068 omp_block_start: SaSint,
4069 omp_block_size: SaSint,
4070) {
4071 let mut i = omp_block_start;
4072 let mut j = omp_block_start + omp_block_size - 64 - 1;
4073
4074 while i < j {
4075 let mut symbol0 = SAINT_MIN;
4076 let p0 = sa[i as usize];
4077 if p0 > 0 {
4078 sa[i as usize] = 0;
4079 cache[i as usize].index = (p0 - 1)
4080 | ((usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]) as SaSint)
4081 << (SAINT_BIT - 1));
4082 symbol0 = t[(p0 - 1) as usize];
4083 }
4084 cache[i as usize].symbol = symbol0;
4085
4086 let mut symbol1 = SAINT_MIN;
4087 let p1 = sa[(i + 1) as usize];
4088 if p1 > 0 {
4089 sa[(i + 1) as usize] = 0;
4090 cache[(i + 1) as usize].index = (p1 - 1)
4091 | ((usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]) as SaSint)
4092 << (SAINT_BIT - 1));
4093 symbol1 = t[(p1 - 1) as usize];
4094 }
4095 cache[(i + 1) as usize].symbol = symbol1;
4096
4097 i += 2;
4098 }
4099
4100 j += 64 + 1;
4101 while i < j {
4102 let mut symbol = SAINT_MIN;
4103 let p = sa[i as usize];
4104 if p > 0 {
4105 sa[i as usize] = 0;
4106 cache[i as usize].index = (p - 1)
4107 | ((usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]) as SaSint)
4108 << (SAINT_BIT - 1));
4109 symbol = t[(p - 1) as usize];
4110 }
4111 cache[i as usize].symbol = symbol;
4112 i += 1;
4113 }
4114}
4115
4116fn partial_sorting_scan_left_to_right_32s_6k_block_sort(
4117 t: &[SaSint],
4118 buckets: &mut [SaSint],
4119 mut d: SaSint,
4120 cache: &mut [ThreadCache],
4121 omp_block_start: SaSint,
4122 omp_block_size: SaSint,
4123) -> SaSint {
4124 let mut i = omp_block_start;
4125 let omp_block_end = omp_block_start + omp_block_size;
4126 let mut j = omp_block_end - 64 - 1;
4127
4128 while i < j {
4129 let v0 = cache[i as usize].symbol as usize;
4130 let p0 = cache[i as usize].index;
4131 d += SaSint::from(p0 < 0);
4132 cache[i as usize].symbol = buckets[v0];
4133 buckets[v0] += 1;
4134 cache[i as usize].index =
4135 (p0 - 1) | (((buckets[2 + v0] != d) as SaSint) << (SAINT_BIT - 1));
4136 buckets[2 + v0] = d;
4137 if cache[i as usize].symbol < omp_block_end {
4138 let s = cache[i as usize].symbol as usize;
4139 let q = cache[i as usize].index & SAINT_MAX;
4140 cache[s].index = cache[i as usize].index;
4141 cache[s].symbol = buckets_index4(
4142 t[(q - 1) as usize] as usize,
4143 usize::from(t[(q - 2) as usize] >= t[(q - 1) as usize]),
4144 ) as SaSint;
4145 }
4146
4147 let v1 = cache[(i + 1) as usize].symbol as usize;
4148 let p1 = cache[(i + 1) as usize].index;
4149 d += SaSint::from(p1 < 0);
4150 cache[(i + 1) as usize].symbol = buckets[v1];
4151 buckets[v1] += 1;
4152 cache[(i + 1) as usize].index =
4153 (p1 - 1) | (((buckets[2 + v1] != d) as SaSint) << (SAINT_BIT - 1));
4154 buckets[2 + v1] = d;
4155 if cache[(i + 1) as usize].symbol < omp_block_end {
4156 let s = cache[(i + 1) as usize].symbol as usize;
4157 let q = cache[(i + 1) as usize].index & SAINT_MAX;
4158 cache[s].index = cache[(i + 1) as usize].index;
4159 cache[s].symbol = buckets_index4(
4160 t[(q - 1) as usize] as usize,
4161 usize::from(t[(q - 2) as usize] >= t[(q - 1) as usize]),
4162 ) as SaSint;
4163 }
4164
4165 i += 2;
4166 }
4167
4168 j += 64 + 1;
4169 while i < j {
4170 let v = cache[i as usize].symbol as usize;
4171 let p = cache[i as usize].index;
4172 d += SaSint::from(p < 0);
4173 cache[i as usize].symbol = buckets[v];
4174 buckets[v] += 1;
4175 cache[i as usize].index = (p - 1) | (((buckets[2 + v] != d) as SaSint) << (SAINT_BIT - 1));
4176 buckets[2 + v] = d;
4177 if cache[i as usize].symbol < omp_block_end {
4178 let s = cache[i as usize].symbol as usize;
4179 let q = cache[i as usize].index & SAINT_MAX;
4180 cache[s].index = cache[i as usize].index;
4181 cache[s].symbol = buckets_index4(
4182 t[(q - 1) as usize] as usize,
4183 usize::from(t[(q - 2) as usize] >= t[(q - 1) as usize]),
4184 ) as SaSint;
4185 }
4186 i += 1;
4187 }
4188
4189 d
4190}
4191
4192fn partial_sorting_scan_left_to_right_32s_4k_block_sort(
4193 t: &[SaSint],
4194 k: SaSint,
4195 buckets: &mut [SaSint],
4196 mut d: SaSint,
4197 cache: &mut [ThreadCache],
4198 omp_block_start: SaSint,
4199 omp_block_size: SaSint,
4200) -> SaSint {
4201 let k = k as usize;
4202 let mut i = omp_block_start;
4203 let omp_block_end = omp_block_start + omp_block_size;
4204 let mut j = omp_block_end - 64 - 1;
4205
4206 while i < j {
4207 for current in [i, i + 1] {
4208 let v = cache[current as usize].symbol;
4209 if v >= 0 {
4210 let p = cache[current as usize].index;
4211 d += p >> (SUFFIX_GROUP_BIT - 1);
4212 let bucket_index = (v >> 1) as usize;
4213 let v_usize = v as usize;
4214 cache[current as usize].symbol = buckets[2 * k + bucket_index];
4215 buckets[2 * k + bucket_index] += 1;
4216 cache[current as usize].index = (p - 1)
4217 | ((v & 1) << (SAINT_BIT - 1))
4218 | (((buckets[v_usize] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
4219 buckets[v_usize] = d;
4220 if cache[current as usize].symbol < omp_block_end {
4221 let ni = cache[current as usize].symbol as usize;
4222 let mut np = cache[current as usize].index;
4223 if np > 0 {
4224 cache[ni].index = np;
4225 np &= !SUFFIX_GROUP_MARKER;
4226 cache[ni].symbol = buckets_index2(
4227 t[(np - 1) as usize] as usize,
4228 usize::from(t[(np - 2) as usize] < t[(np - 1) as usize]),
4229 ) as SaSint;
4230 np = 0;
4231 }
4232 cache[current as usize].index = np & SAINT_MAX;
4233 }
4234 }
4235 }
4236 i += 2;
4237 }
4238
4239 j += 64 + 1;
4240 while i < j {
4241 let v = cache[i as usize].symbol;
4242 if v >= 0 {
4243 let p = cache[i as usize].index;
4244 d += p >> (SUFFIX_GROUP_BIT - 1);
4245 let bucket_index = (v >> 1) as usize;
4246 let v_usize = v as usize;
4247 cache[i as usize].symbol = buckets[2 * k + bucket_index];
4248 buckets[2 * k + bucket_index] += 1;
4249 cache[i as usize].index = (p - 1)
4250 | ((v & 1) << (SAINT_BIT - 1))
4251 | (((buckets[v_usize] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
4252 buckets[v_usize] = d;
4253 if cache[i as usize].symbol < omp_block_end {
4254 let ni = cache[i as usize].symbol as usize;
4255 let mut np = cache[i as usize].index;
4256 if np > 0 {
4257 cache[ni].index = np;
4258 np &= !SUFFIX_GROUP_MARKER;
4259 cache[ni].symbol = buckets_index2(
4260 t[(np - 1) as usize] as usize,
4261 usize::from(t[(np - 2) as usize] < t[(np - 1) as usize]),
4262 ) as SaSint;
4263 np = 0;
4264 }
4265 cache[i as usize].index = np & SAINT_MAX;
4266 }
4267 }
4268 i += 1;
4269 }
4270
4271 d
4272}
4273
4274fn partial_sorting_scan_left_to_right_32s_1k_block_sort(
4275 t: &[SaSint],
4276 induction_bucket: &mut [SaSint],
4277 cache: &mut [ThreadCache],
4278 omp_block_start: SaSint,
4279 omp_block_size: SaSint,
4280) {
4281 let mut i = omp_block_start;
4282 let omp_block_end = omp_block_start + omp_block_size;
4283 let mut j = omp_block_end - 64 - 1;
4284
4285 while i < j {
4286 for current in [i, i + 1] {
4287 let v = cache[current as usize].symbol;
4288 if v >= 0 {
4289 cache[current as usize].symbol = induction_bucket[v as usize];
4290 induction_bucket[v as usize] += 1;
4291 if cache[current as usize].symbol < omp_block_end {
4292 let ni = cache[current as usize].symbol as usize;
4293 let mut np = cache[current as usize].index;
4294 if np > 0 {
4295 cache[ni].index = (np - 1)
4296 | ((usize::from(t[(np - 2) as usize] < t[(np - 1) as usize])
4297 as SaSint)
4298 << (SAINT_BIT - 1));
4299 cache[ni].symbol = t[(np - 1) as usize];
4300 np = 0;
4301 }
4302 cache[current as usize].index = np & SAINT_MAX;
4303 }
4304 }
4305 }
4306 i += 2;
4307 }
4308
4309 j = omp_block_end;
4310 while i < j {
4311 let v = cache[i as usize].symbol;
4312 if v >= 0 {
4313 cache[i as usize].symbol = induction_bucket[v as usize];
4314 induction_bucket[v as usize] += 1;
4315 if cache[i as usize].symbol < omp_block_end {
4316 let ni = cache[i as usize].symbol as usize;
4317 let mut np = cache[i as usize].index;
4318 if np > 0 {
4319 cache[ni].index = (np - 1)
4320 | ((usize::from(t[(np - 2) as usize] < t[(np - 1) as usize]) as SaSint)
4321 << (SAINT_BIT - 1));
4322 cache[ni].symbol = t[(np - 1) as usize];
4323 np = 0;
4324 }
4325 cache[i as usize].index = np & SAINT_MAX;
4326 }
4327 }
4328 i += 1;
4329 }
4330}
4331
4332fn partial_sorting_scan_right_to_left_32s_6k_block_sort(
4333 t: &[SaSint],
4334 buckets: &mut [SaSint],
4335 mut d: SaSint,
4336 cache: &mut [ThreadCache],
4337 omp_block_start: SaSint,
4338 omp_block_size: SaSint,
4339) -> SaSint {
4340 let mut i = omp_block_start + omp_block_size - 1;
4341 let mut j = omp_block_start + 64 + 1;
4342
4343 while i >= j {
4344 let v0 = cache[i as usize].symbol as usize;
4345 let p0 = cache[i as usize].index;
4346 d += SaSint::from(p0 < 0);
4347 buckets[v0] -= 1;
4348 cache[i as usize].symbol = buckets[v0];
4349 cache[i as usize].index =
4350 (p0 - 1) | (((buckets[2 + v0] != d) as SaSint) << (SAINT_BIT - 1));
4351 buckets[2 + v0] = d;
4352 if cache[i as usize].symbol >= omp_block_start {
4353 let s = cache[i as usize].symbol as usize;
4354 let q = cache[i as usize].index & SAINT_MAX;
4355 cache[s].index = cache[i as usize].index;
4356 cache[s].symbol = buckets_index4(
4357 t[(q - 1) as usize] as usize,
4358 usize::from(t[(q - 2) as usize] > t[(q - 1) as usize]),
4359 ) as SaSint;
4360 }
4361
4362 let v1 = cache[(i - 1) as usize].symbol as usize;
4363 let p1 = cache[(i - 1) as usize].index;
4364 d += SaSint::from(p1 < 0);
4365 buckets[v1] -= 1;
4366 cache[(i - 1) as usize].symbol = buckets[v1];
4367 cache[(i - 1) as usize].index =
4368 (p1 - 1) | (((buckets[2 + v1] != d) as SaSint) << (SAINT_BIT - 1));
4369 buckets[2 + v1] = d;
4370 if cache[(i - 1) as usize].symbol >= omp_block_start {
4371 let s = cache[(i - 1) as usize].symbol as usize;
4372 let q = cache[(i - 1) as usize].index & SAINT_MAX;
4373 cache[s].index = cache[(i - 1) as usize].index;
4374 cache[s].symbol = buckets_index4(
4375 t[(q - 1) as usize] as usize,
4376 usize::from(t[(q - 2) as usize] > t[(q - 1) as usize]),
4377 ) as SaSint;
4378 }
4379
4380 i -= 2;
4381 }
4382
4383 j -= 64 + 1;
4384 while i >= j {
4385 let v = cache[i as usize].symbol as usize;
4386 let p = cache[i as usize].index;
4387 d += SaSint::from(p < 0);
4388 buckets[v] -= 1;
4389 cache[i as usize].symbol = buckets[v];
4390 cache[i as usize].index = (p - 1) | (((buckets[2 + v] != d) as SaSint) << (SAINT_BIT - 1));
4391 buckets[2 + v] = d;
4392 if cache[i as usize].symbol >= omp_block_start {
4393 let s = cache[i as usize].symbol as usize;
4394 let q = cache[i as usize].index & SAINT_MAX;
4395 cache[s].index = cache[i as usize].index;
4396 cache[s].symbol = buckets_index4(
4397 t[(q - 1) as usize] as usize,
4398 usize::from(t[(q - 2) as usize] > t[(q - 1) as usize]),
4399 ) as SaSint;
4400 }
4401 i -= 1;
4402 }
4403
4404 d
4405}
4406
4407fn partial_sorting_scan_right_to_left_32s_4k_block_sort(
4408 t: &[SaSint],
4409 k: SaSint,
4410 buckets: &mut [SaSint],
4411 mut d: SaSint,
4412 cache: &mut [ThreadCache],
4413 omp_block_start: SaSint,
4414 omp_block_size: SaSint,
4415) -> SaSint {
4416 let k = k as usize;
4417 let mut i = omp_block_start + omp_block_size - 1;
4418 let mut j = omp_block_start + 64 + 1;
4419
4420 while i >= j {
4421 for current in [i, i - 1] {
4422 let v = cache[current as usize].symbol;
4423 if v >= 0 {
4424 let p = cache[current as usize].index;
4425 d += p >> (SUFFIX_GROUP_BIT - 1);
4426 let bucket_index = (v >> 1) as usize;
4427 let v_usize = v as usize;
4428 buckets[3 * k + bucket_index] -= 1;
4429 cache[current as usize].symbol = buckets[3 * k + bucket_index];
4430 cache[current as usize].index = (p - 1)
4431 | ((v & 1) << (SAINT_BIT - 1))
4432 | (((buckets[v_usize] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
4433 buckets[v_usize] = d;
4434 if cache[current as usize].symbol >= omp_block_start {
4435 let ni = cache[current as usize].symbol as usize;
4436 let mut np = cache[current as usize].index;
4437 if np > 0 {
4438 cache[current as usize].index = 0;
4439 cache[ni].index = np;
4440 np &= !SUFFIX_GROUP_MARKER;
4441 cache[ni].symbol = buckets_index2(
4442 t[(np - 1) as usize] as usize,
4443 usize::from(t[(np - 2) as usize] > t[(np - 1) as usize]),
4444 ) as SaSint;
4445 }
4446 }
4447 }
4448 }
4449 i -= 2;
4450 }
4451
4452 j -= 64 + 1;
4453 while i >= j {
4454 let v = cache[i as usize].symbol;
4455 if v >= 0 {
4456 let p = cache[i as usize].index;
4457 d += p >> (SUFFIX_GROUP_BIT - 1);
4458 let bucket_index = (v >> 1) as usize;
4459 let v_usize = v as usize;
4460 buckets[3 * k + bucket_index] -= 1;
4461 cache[i as usize].symbol = buckets[3 * k + bucket_index];
4462 cache[i as usize].index = (p - 1)
4463 | ((v & 1) << (SAINT_BIT - 1))
4464 | (((buckets[v_usize] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
4465 buckets[v_usize] = d;
4466 if cache[i as usize].symbol >= omp_block_start {
4467 let ni = cache[i as usize].symbol as usize;
4468 let mut np = cache[i as usize].index;
4469 if np > 0 {
4470 cache[i as usize].index = 0;
4471 cache[ni].index = np;
4472 np &= !SUFFIX_GROUP_MARKER;
4473 cache[ni].symbol = buckets_index2(
4474 t[(np - 1) as usize] as usize,
4475 usize::from(t[(np - 2) as usize] > t[(np - 1) as usize]),
4476 ) as SaSint;
4477 }
4478 }
4479 }
4480 i -= 1;
4481 }
4482
4483 d
4484}
4485
4486fn partial_sorting_scan_right_to_left_32s_1k_block_sort(
4487 t: &[SaSint],
4488 induction_bucket: &mut [SaSint],
4489 cache: &mut [ThreadCache],
4490 omp_block_start: SaSint,
4491 omp_block_size: SaSint,
4492) {
4493 let mut i = omp_block_start + omp_block_size - 1;
4494 let mut j = omp_block_start + 64 + 1;
4495
4496 while i >= j {
4497 for current in [i, i - 1] {
4498 let v = cache[current as usize].symbol;
4499 if v >= 0 {
4500 induction_bucket[v as usize] -= 1;
4501 cache[current as usize].symbol = induction_bucket[v as usize];
4502 if cache[current as usize].symbol >= omp_block_start {
4503 let ni = cache[current as usize].symbol as usize;
4504 let np = cache[current as usize].index;
4505 if np > 0 {
4506 cache[current as usize].index = 0;
4507 cache[ni].index = (np - 1)
4508 | ((usize::from(t[(np - 2) as usize] > t[(np - 1) as usize])
4509 as SaSint)
4510 << (SAINT_BIT - 1));
4511 cache[ni].symbol = t[(np - 1) as usize];
4512 }
4513 }
4514 }
4515 }
4516 i -= 2;
4517 }
4518
4519 j -= 64 + 1;
4520 while i >= j {
4521 let v = cache[i as usize].symbol;
4522 if v >= 0 {
4523 induction_bucket[v as usize] -= 1;
4524 cache[i as usize].symbol = induction_bucket[v as usize];
4525 if cache[i as usize].symbol >= omp_block_start {
4526 let ni = cache[i as usize].symbol as usize;
4527 let np = cache[i as usize].index;
4528 if np > 0 {
4529 cache[i as usize].index = 0;
4530 cache[ni].index = (np - 1)
4531 | ((usize::from(t[(np - 2) as usize] > t[(np - 1) as usize]) as SaSint)
4532 << (SAINT_BIT - 1));
4533 cache[ni].symbol = t[(np - 1) as usize];
4534 }
4535 }
4536 }
4537 i -= 1;
4538 }
4539}
4540
4541fn partial_sorting_scan_left_to_right_32s_6k_block_omp(
4542 t: &[SaSint],
4543 sa: &mut [SaSint],
4544 buckets: &mut [SaSint],
4545 d: SaSint,
4546 cache: &mut [ThreadCache],
4547 block_start: SaSint,
4548 block_size: SaSint,
4549 threads: SaSint,
4550) -> SaSint {
4551 if block_size <= 0 {
4552 return d;
4553 }
4554 if threads == 1 || block_size < 16_384 {
4555 return partial_sorting_scan_left_to_right_32s_6k(
4556 t,
4557 sa,
4558 buckets,
4559 d,
4560 block_start,
4561 block_size,
4562 );
4563 }
4564
4565 let threads_usize = usize::try_from(threads)
4566 .expect("threads must be non-negative")
4567 .max(1);
4568 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4569 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4570 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4571 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4572
4573 {
4574 let sa_ptr = SyncMutPtr::new(sa);
4575 let t_ro: &[SaSint] = t;
4576 let cache_ptr = SyncMutPtr::new(cache);
4577 run_rayon_with_threads(omp_num_threads, || {
4578 (0..omp_num_threads)
4579 .into_par_iter()
4580 .for_each(|omp_thread_num| {
4581 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4582 omp_block_stride
4583 } else {
4584 block_size_usize - omp_thread_num * omp_block_stride
4585 };
4586 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4587 if omp_block_size == 0 {
4588 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4589 }
4590 let cache = unsafe { cache_ptr.as_slice() };
4591 let sa = unsafe { sa_ptr.as_slice() };
4592 partial_sorting_scan_left_to_right_32s_6k_block_gather(
4593 t_ro,
4594 sa,
4595 &mut cache[omp_thread_num * omp_block_stride
4596 ..omp_thread_num * omp_block_stride + omp_block_size],
4597 omp_block_start as SaSint,
4598 omp_block_size as SaSint,
4599 );
4600 });
4601 });
4602 }
4603
4604 let d = partial_sorting_scan_left_to_right_32s_6k_block_sort(
4605 t,
4606 buckets,
4607 d,
4608 &mut cache[..block_size_usize],
4609 block_start,
4610 block_size,
4611 );
4612 place_cached_suffixes(sa, &cache[..block_size_usize], 0, block_size);
4613 d
4614}
4615
4616fn partial_sorting_scan_left_to_right_32s_4k_block_omp(
4617 t: &[SaSint],
4618 sa: &mut [SaSint],
4619 k: SaSint,
4620 buckets: &mut [SaSint],
4621 d: SaSint,
4622 cache: &mut [ThreadCache],
4623 block_start: SaSint,
4624 block_size: SaSint,
4625 threads: SaSint,
4626) -> SaSint {
4627 if block_size <= 0 {
4628 return d;
4629 }
4630 if threads == 1 || block_size < 16_384 {
4631 return partial_sorting_scan_left_to_right_32s_4k(
4632 t,
4633 sa,
4634 k,
4635 buckets,
4636 d,
4637 block_start,
4638 block_size,
4639 );
4640 }
4641
4642 let threads_usize = usize::try_from(threads)
4643 .expect("threads must be non-negative")
4644 .max(1);
4645 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4646 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4647 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4648 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4649
4650 {
4651 let sa_ptr = SyncMutPtr::new(sa);
4652 let t_ro: &[SaSint] = t;
4653 let cache_ptr = SyncMutPtr::new(cache);
4654 run_rayon_with_threads(omp_num_threads, || {
4655 (0..omp_num_threads)
4656 .into_par_iter()
4657 .for_each(|omp_thread_num| {
4658 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4659 omp_block_stride
4660 } else {
4661 block_size_usize - omp_thread_num * omp_block_stride
4662 };
4663 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4664 if omp_block_size == 0 {
4665 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4666 }
4667 let cache = unsafe { cache_ptr.as_slice() };
4668 let sa = unsafe { sa_ptr.as_slice() };
4669 partial_sorting_scan_left_to_right_32s_4k_block_gather(
4670 t_ro,
4671 sa,
4672 &mut cache[omp_thread_num * omp_block_stride
4673 ..omp_thread_num * omp_block_stride + omp_block_size],
4674 omp_block_start as SaSint,
4675 omp_block_size as SaSint,
4676 );
4677 });
4678 });
4679 }
4680
4681 let cache = &mut cache[..block_size_usize];
4682 let d = partial_sorting_scan_left_to_right_32s_4k_block_sort(
4683 t,
4684 k,
4685 buckets,
4686 d,
4687 cache,
4688 block_start,
4689 block_size,
4690 );
4691 for entry in cache.iter() {
4692 if entry.symbol >= 0 {
4693 sa[entry.symbol as usize] = entry.index;
4694 }
4695 }
4696 d
4697}
4698
4699fn partial_sorting_scan_left_to_right_32s_1k_block_omp(
4700 t: &[SaSint],
4701 sa: &mut [SaSint],
4702 buckets: &mut [SaSint],
4703 cache: &mut [ThreadCache],
4704 block_start: SaSint,
4705 block_size: SaSint,
4706 threads: SaSint,
4707) {
4708 if block_size <= 0 {
4709 return;
4710 }
4711 if threads == 1 || block_size < 16_384 {
4712 partial_sorting_scan_left_to_right_32s_1k(t, sa, buckets, block_start, block_size);
4713 return;
4714 }
4715
4716 let threads_usize = usize::try_from(threads)
4717 .expect("threads must be non-negative")
4718 .max(1);
4719 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4720 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4721 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4722 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4723
4724 {
4725 let sa_ptr = SyncMutPtr::new(sa);
4726 let t_ro: &[SaSint] = t;
4727 let cache_ptr = SyncMutPtr::new(cache);
4728 run_rayon_with_threads(omp_num_threads, || {
4729 (0..omp_num_threads)
4730 .into_par_iter()
4731 .for_each(|omp_thread_num| {
4732 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4733 omp_block_stride
4734 } else {
4735 block_size_usize - omp_thread_num * omp_block_stride
4736 };
4737 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4738 if omp_block_size == 0 {
4739 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4740 }
4741 let cache = unsafe { cache_ptr.as_slice() };
4742 let sa = unsafe { sa_ptr.as_slice() };
4743 partial_sorting_scan_left_to_right_32s_1k_block_gather(
4744 t_ro,
4745 sa,
4746 &mut cache[omp_thread_num * omp_block_stride
4747 ..omp_thread_num * omp_block_stride + omp_block_size],
4748 omp_block_start as SaSint,
4749 omp_block_size as SaSint,
4750 );
4751 });
4752 });
4753 }
4754
4755 let cache = &mut cache[..block_size_usize];
4756 partial_sorting_scan_left_to_right_32s_1k_block_sort(
4757 t,
4758 buckets,
4759 cache,
4760 block_start,
4761 block_size,
4762 );
4763 compact_and_place_cached_suffixes(sa, cache, block_start, block_size);
4764}
4765
4766fn partial_sorting_scan_right_to_left_32s_6k_block_omp(
4767 t: &[SaSint],
4768 sa: &mut [SaSint],
4769 buckets: &mut [SaSint],
4770 mut d: SaSint,
4771 cache: &mut [ThreadCache],
4772 block_start: SaSint,
4773 block_size: SaSint,
4774 threads: SaSint,
4775) -> SaSint {
4776 if block_size <= 0 {
4777 return d;
4778 }
4779 if threads == 1 || block_size < 16_384 {
4780 return partial_sorting_scan_right_to_left_32s_6k(
4781 t,
4782 sa,
4783 buckets,
4784 d,
4785 block_start,
4786 block_size,
4787 );
4788 }
4789
4790 let threads_usize = usize::try_from(threads)
4791 .expect("threads must be non-negative")
4792 .max(1);
4793 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4794 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4795 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4796 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4797
4798 {
4799 let sa_ptr = SyncMutPtr::new(sa);
4800 let t_ro: &[SaSint] = t;
4801 let cache_ptr = SyncMutPtr::new(cache);
4802 run_rayon_with_threads(omp_num_threads, || {
4803 (0..omp_num_threads)
4804 .into_par_iter()
4805 .for_each(|omp_thread_num| {
4806 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4807 omp_block_stride
4808 } else {
4809 block_size_usize - omp_thread_num * omp_block_stride
4810 };
4811 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4812 if omp_block_size == 0 {
4813 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4814 }
4815 let cache = unsafe { cache_ptr.as_slice() };
4816 let sa = unsafe { sa_ptr.as_slice() };
4817 partial_sorting_scan_right_to_left_32s_6k_block_gather(
4818 t_ro,
4819 sa,
4820 &mut cache[omp_thread_num * omp_block_stride
4821 ..omp_thread_num * omp_block_stride + omp_block_size],
4822 omp_block_start as SaSint,
4823 omp_block_size as SaSint,
4824 );
4825 });
4826 });
4827 }
4828
4829 d = partial_sorting_scan_right_to_left_32s_6k_block_sort(
4830 t,
4831 buckets,
4832 d,
4833 &mut cache[..block_size_usize],
4834 block_start,
4835 block_size,
4836 );
4837 {
4838 let sa_ptr = SyncMutPtr::new(sa);
4839 let cache_ro: &[ThreadCache] = cache;
4840 run_rayon_with_threads(omp_num_threads, || {
4841 (0..omp_num_threads)
4842 .into_par_iter()
4843 .for_each(|omp_thread_num| {
4844 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4845 omp_block_stride
4846 } else {
4847 block_size_usize - omp_thread_num * omp_block_stride
4848 };
4849 let cache_start = omp_thread_num * omp_block_stride;
4850 if omp_block_size == 0 {
4851 omp_block_size = block_size_usize - cache_start;
4852 }
4853 let sa = unsafe { sa_ptr.as_slice() };
4854 for entry in &cache_ro[cache_start..cache_start + omp_block_size] {
4855 sa[entry.symbol as usize] = entry.index;
4856 }
4857 });
4858 });
4859 }
4860 d
4861}
4862
4863fn partial_sorting_scan_right_to_left_32s_4k_block_omp(
4864 t: &[SaSint],
4865 sa: &mut [SaSint],
4866 k: SaSint,
4867 buckets: &mut [SaSint],
4868 mut d: SaSint,
4869 cache: &mut [ThreadCache],
4870 block_start: SaSint,
4871 block_size: SaSint,
4872 threads: SaSint,
4873) -> SaSint {
4874 if block_size <= 0 {
4875 return d;
4876 }
4877 if threads == 1 || block_size < 16_384 {
4878 return partial_sorting_scan_right_to_left_32s_4k(
4879 t,
4880 sa,
4881 k,
4882 buckets,
4883 d,
4884 block_start,
4885 block_size,
4886 );
4887 }
4888
4889 let threads_usize = usize::try_from(threads)
4890 .expect("threads must be non-negative")
4891 .max(1);
4892 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4893 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4894 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4895 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4896
4897 {
4898 let sa_ptr = SyncMutPtr::new(sa);
4899 let t_ro: &[SaSint] = t;
4900 let cache_ptr = SyncMutPtr::new(cache);
4901 run_rayon_with_threads(omp_num_threads, || {
4902 (0..omp_num_threads)
4903 .into_par_iter()
4904 .for_each(|omp_thread_num| {
4905 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4906 omp_block_stride
4907 } else {
4908 block_size_usize - omp_thread_num * omp_block_stride
4909 };
4910 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4911 if omp_block_size == 0 {
4912 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4913 }
4914 let cache = unsafe { cache_ptr.as_slice() };
4915 let sa = unsafe { sa_ptr.as_slice() };
4916 partial_sorting_scan_right_to_left_32s_4k_block_gather(
4917 t_ro,
4918 sa,
4919 &mut cache[omp_thread_num * omp_block_stride
4920 ..omp_thread_num * omp_block_stride + omp_block_size],
4921 omp_block_start as SaSint,
4922 omp_block_size as SaSint,
4923 );
4924 });
4925 });
4926 }
4927
4928 d = partial_sorting_scan_right_to_left_32s_4k_block_sort(
4929 t,
4930 k,
4931 buckets,
4932 d,
4933 &mut cache[..block_size_usize],
4934 block_start,
4935 block_size,
4936 );
4937 let mut write = 0usize;
4938 for read in 0..block_size_usize {
4939 let entry = cache[read];
4940 if entry.symbol >= 0 {
4941 cache[write] = entry;
4942 write += 1;
4943 }
4944 }
4945 for entry in &cache[..write] {
4946 sa[entry.symbol as usize] = entry.index;
4947 }
4948 d
4949}
4950
4951fn partial_sorting_scan_right_to_left_32s_1k_block_omp(
4952 t: &[SaSint],
4953 sa: &mut [SaSint],
4954 buckets: &mut [SaSint],
4955 cache: &mut [ThreadCache],
4956 block_start: SaSint,
4957 block_size: SaSint,
4958 threads: SaSint,
4959) {
4960 if block_size <= 0 {
4961 return;
4962 }
4963 if threads == 1 || block_size < 16_384 {
4964 partial_sorting_scan_right_to_left_32s_1k(t, sa, buckets, block_start, block_size);
4965 return;
4966 }
4967
4968 let threads_usize = usize::try_from(threads)
4969 .expect("threads must be non-negative")
4970 .max(1);
4971 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4972 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4973 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4974 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4975
4976 {
4977 let sa_ptr = SyncMutPtr::new(sa);
4978 let t_ro: &[SaSint] = t;
4979 let cache_ptr = SyncMutPtr::new(cache);
4980 run_rayon_with_threads(omp_num_threads, || {
4981 (0..omp_num_threads)
4982 .into_par_iter()
4983 .for_each(|omp_thread_num| {
4984 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4985 omp_block_stride
4986 } else {
4987 block_size_usize - omp_thread_num * omp_block_stride
4988 };
4989 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4990 if omp_block_size == 0 {
4991 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4992 }
4993 let cache = unsafe { cache_ptr.as_slice() };
4994 let sa = unsafe { sa_ptr.as_slice() };
4995 partial_sorting_scan_right_to_left_32s_1k_block_gather(
4996 t_ro,
4997 sa,
4998 &mut cache[omp_thread_num * omp_block_stride
4999 ..omp_thread_num * omp_block_stride + omp_block_size],
5000 omp_block_start as SaSint,
5001 omp_block_size as SaSint,
5002 );
5003 });
5004 });
5005 }
5006
5007 let cache = &mut cache[..block_size_usize];
5008 partial_sorting_scan_right_to_left_32s_1k_block_sort(
5009 t,
5010 buckets,
5011 cache,
5012 block_start,
5013 block_size,
5014 );
5015 compact_and_place_cached_suffixes(sa, cache, block_start, block_size);
5016}
5017
5018fn partial_sorting_gather_lms_suffixes_32s_4k(
5019 sa: &mut [SaSint],
5020 omp_block_start: SaSint,
5021 omp_block_size: SaSint,
5022) -> SaSint {
5023 let mut i = omp_block_start;
5024 let mut j = omp_block_start + omp_block_size - 3;
5025 let mut l = omp_block_start;
5026
5027 while i < j {
5028 let s0 = sa[i as usize] as SaUint;
5029 sa[l as usize] = (s0.wrapping_sub(SUFFIX_GROUP_MARKER as SaUint)
5030 & !(SUFFIX_GROUP_MARKER as SaUint)) as SaSint;
5031 l += SaSint::from((s0 as SaSint) < 0);
5032
5033 let s1 = sa[(i + 1) as usize] as SaUint;
5034 sa[l as usize] = (s1.wrapping_sub(SUFFIX_GROUP_MARKER as SaUint)
5035 & !(SUFFIX_GROUP_MARKER as SaUint)) as SaSint;
5036 l += SaSint::from((s1 as SaSint) < 0);
5037
5038 let s2 = sa[(i + 2) as usize] as SaUint;
5039 sa[l as usize] = (s2.wrapping_sub(SUFFIX_GROUP_MARKER as SaUint)
5040 & !(SUFFIX_GROUP_MARKER as SaUint)) as SaSint;
5041 l += SaSint::from((s2 as SaSint) < 0);
5042
5043 let s3 = sa[(i + 3) as usize] as SaUint;
5044 sa[l as usize] = (s3.wrapping_sub(SUFFIX_GROUP_MARKER as SaUint)
5045 & !(SUFFIX_GROUP_MARKER as SaUint)) as SaSint;
5046 l += SaSint::from((s3 as SaSint) < 0);
5047
5048 i += 4;
5049 }
5050
5051 j += 3;
5052 while i < j {
5053 let s = sa[i as usize] as SaUint;
5054 sa[l as usize] = (s.wrapping_sub(SUFFIX_GROUP_MARKER as SaUint)
5055 & !(SUFFIX_GROUP_MARKER as SaUint)) as SaSint;
5056 l += SaSint::from((s as SaSint) < 0);
5057 i += 1;
5058 }
5059
5060 l
5061}
5062
5063fn partial_sorting_gather_lms_suffixes_32s_1k(
5064 sa: &mut [SaSint],
5065 omp_block_start: SaSint,
5066 omp_block_size: SaSint,
5067) -> SaSint {
5068 let mut i = omp_block_start;
5069 let mut j = omp_block_start + omp_block_size - 3;
5070 let mut l = omp_block_start;
5071
5072 while i < j {
5073 let s0 = sa[i as usize];
5074 sa[l as usize] = s0 & SAINT_MAX;
5075 l += SaSint::from(s0 < 0);
5076
5077 let s1 = sa[(i + 1) as usize];
5078 sa[l as usize] = s1 & SAINT_MAX;
5079 l += SaSint::from(s1 < 0);
5080
5081 let s2 = sa[(i + 2) as usize];
5082 sa[l as usize] = s2 & SAINT_MAX;
5083 l += SaSint::from(s2 < 0);
5084
5085 let s3 = sa[(i + 3) as usize];
5086 sa[l as usize] = s3 & SAINT_MAX;
5087 l += SaSint::from(s3 < 0);
5088
5089 i += 4;
5090 }
5091
5092 j += 3;
5093 while i < j {
5094 let s = sa[i as usize];
5095 sa[l as usize] = s & SAINT_MAX;
5096 l += SaSint::from(s < 0);
5097 i += 1;
5098 }
5099
5100 l
5101}
5102
5103fn partial_sorting_gather_lms_suffixes_32s_4k_omp(
5104 sa: &mut [SaSint],
5105 n: SaSint,
5106 threads: SaSint,
5107 thread_state: &mut [ThreadState],
5108) {
5109 let n_usize = usize::try_from(n).expect("n must be non-negative");
5110 let thread_count = if threads > 1 && n >= 65_536 {
5111 usize::try_from(threads)
5112 .expect("threads must be non-negative")
5113 .min(thread_state.len())
5114 .max(1)
5115 } else {
5116 1
5117 };
5118
5119 if thread_count == 1 {
5120 let _ = partial_sorting_gather_lms_suffixes_32s_4k(sa, 0, n);
5121 return;
5122 }
5123
5124 let block_stride = (n_usize / thread_count) & !15usize;
5125 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
5126 let block_start = thread * block_stride;
5127 let block_size = if thread + 1 < thread_count {
5128 block_stride
5129 } else {
5130 n_usize - block_start
5131 };
5132 state.position = block_start as SaSint;
5133 state.count = partial_sorting_gather_lms_suffixes_32s_4k(
5134 sa,
5135 block_start as SaSint,
5136 block_size as SaSint,
5137 ) - block_start as SaSint;
5138 }
5139
5140 let mut position = 0usize;
5141 for (thread, state) in thread_state.iter().take(thread_count).enumerate() {
5142 let count = usize::try_from(state.count).expect("count must be non-negative");
5143 let src = usize::try_from(state.position).expect("position must be non-negative");
5144 if thread > 0 && count > 0 {
5145 sa.copy_within(src..src + count, position);
5146 }
5147 position += count;
5148 }
5149}
5150
5151fn partial_sorting_gather_lms_suffixes_32s_1k_omp(
5152 sa: &mut [SaSint],
5153 n: SaSint,
5154 threads: SaSint,
5155 thread_state: &mut [ThreadState],
5156) {
5157 let n_usize = usize::try_from(n).expect("n must be non-negative");
5158 let thread_count = if threads > 1 && n >= 65_536 {
5159 usize::try_from(threads)
5160 .expect("threads must be non-negative")
5161 .min(thread_state.len())
5162 .max(1)
5163 } else {
5164 1
5165 };
5166
5167 if thread_count == 1 {
5168 let _ = partial_sorting_gather_lms_suffixes_32s_1k(sa, 0, n);
5169 return;
5170 }
5171
5172 let block_stride = (n_usize / thread_count) & !15usize;
5173 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
5174 let block_start = thread * block_stride;
5175 let block_size = if thread + 1 < thread_count {
5176 block_stride
5177 } else {
5178 n_usize - block_start
5179 };
5180 state.position = block_start as SaSint;
5181 state.count = partial_sorting_gather_lms_suffixes_32s_1k(
5182 sa,
5183 block_start as SaSint,
5184 block_size as SaSint,
5185 ) - block_start as SaSint;
5186 }
5187
5188 let mut position = 0usize;
5189 for (thread, state) in thread_state.iter().take(thread_count).enumerate() {
5190 let count = usize::try_from(state.count).expect("count must be non-negative");
5191 let src = usize::try_from(state.position).expect("position must be non-negative");
5192 if thread > 0 && count > 0 {
5193 sa.copy_within(src..src + count, position);
5194 }
5195 position += count;
5196 }
5197}
5198
5199fn partial_gsa_scan_right_to_left_16u(
5200 t: &[u16],
5201 sa: &mut [SaSint],
5202 buckets: &mut [SaSint],
5203 mut d: SaSint,
5204 omp_block_start: SaSint,
5205 omp_block_size: SaSint,
5206) -> SaSint {
5207 let mut i = (omp_block_start + omp_block_size - 1) as isize;
5208 let mut j = (omp_block_start + 64 + 1) as isize;
5209 while i >= j {
5210 let mut p0 = sa[i as usize];
5211 d += SaSint::from(p0 < 0);
5212 p0 &= SAINT_MAX;
5213 let v0 = buckets_index2(
5214 t[(p0 - 1) as usize] as usize,
5215 usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]),
5216 );
5217 if v0 != 1 {
5218 let mark0 = if buckets[2 * ALPHABET_SIZE + v0] != d {
5219 SAINT_MIN
5220 } else {
5221 0
5222 };
5223 buckets[v0] -= 1;
5224 sa[buckets[v0] as usize] = (p0 - 1) | mark0;
5225 buckets[2 * ALPHABET_SIZE + v0] = d;
5226 }
5227
5228 let mut p1 = sa[(i - 1) as usize];
5229 d += SaSint::from(p1 < 0);
5230 p1 &= SAINT_MAX;
5231 let v1 = buckets_index2(
5232 t[(p1 - 1) as usize] as usize,
5233 usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]),
5234 );
5235 if v1 != 1 {
5236 let mark1 = if buckets[2 * ALPHABET_SIZE + v1] != d {
5237 SAINT_MIN
5238 } else {
5239 0
5240 };
5241 buckets[v1] -= 1;
5242 sa[buckets[v1] as usize] = (p1 - 1) | mark1;
5243 buckets[2 * ALPHABET_SIZE + v1] = d;
5244 }
5245
5246 i -= 2;
5247 }
5248
5249 j -= 64 + 1;
5250 while i >= j {
5251 let mut p = sa[i as usize];
5252 d += SaSint::from(p < 0);
5253 p &= SAINT_MAX;
5254 let v = buckets_index2(
5255 t[(p - 1) as usize] as usize,
5256 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
5257 );
5258 if v != 1 {
5259 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
5260 SAINT_MIN
5261 } else {
5262 0
5263 };
5264 buckets[v] -= 1;
5265 sa[buckets[v] as usize] = (p - 1) | mark;
5266 buckets[2 * ALPHABET_SIZE + v] = d;
5267 }
5268 i -= 1;
5269 }
5270
5271 d
5272}
5273
5274fn partial_gsa_scan_right_to_left_16u_block_omp(
5275 t: &[u16],
5276 sa: &mut [SaSint],
5277 k: SaSint,
5278 buckets: &mut [SaSint],
5279 d: SaSint,
5280 block_start: SaSint,
5281 block_size: SaSint,
5282 threads: SaSint,
5283 thread_state: &mut [ThreadState],
5284) -> SaSint {
5285 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
5286 usize::try_from(threads)
5287 .expect("threads must be non-negative")
5288 .min(thread_state.len())
5289 } else {
5290 1
5291 };
5292 if thread_count <= 1 {
5293 return partial_gsa_scan_right_to_left_16u(t, sa, buckets, d, block_start, block_size);
5294 }
5295
5296 let width = 2 * k as usize;
5297 let distinct_offset = 2 * ALPHABET_SIZE;
5298 let block_stride = (block_size / thread_count as SaSint) & !15;
5299
5300 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
5301 let local_start = thread as SaSint * block_stride;
5302 let local_size = if thread + 1 < thread_count {
5303 block_stride
5304 } else {
5305 block_size - local_start
5306 };
5307 let mut local_state = ThreadState::default();
5308 state.position = partial_sorting_scan_right_to_left_16u_block_prepare(
5309 t,
5310 sa,
5311 k,
5312 &mut state.buckets,
5313 &mut state.cache,
5314 block_start + local_start,
5315 local_size,
5316 &mut local_state,
5317 );
5318 state.count = local_state.cache_entries as SaSint;
5319 }
5320
5321 let mut next_d = d;
5322 for state in thread_state.iter_mut().take(thread_count).rev() {
5323 for c in 0..width {
5324 let a = buckets[c];
5325 let b = state.buckets[c];
5326 buckets[c] = a - b;
5327 state.buckets[c] = a;
5328 }
5329
5330 next_d -= 1;
5331 for c in 0..width {
5332 let offset = distinct_offset + c;
5333 let a = buckets[offset];
5334 let b = state.buckets[offset];
5335 let shifted = b + next_d;
5336 buckets[offset] = if b > 0 { shifted } else { a };
5337 state.buckets[offset] = a;
5338 }
5339 next_d += 1 + state.position;
5340 state.position = next_d - state.position;
5341 }
5342
5343 for state in thread_state.iter_mut().take(thread_count) {
5344 partial_gsa_scan_right_to_left_16u_block_place(
5345 sa,
5346 &mut state.buckets,
5347 &state.cache,
5348 state.count,
5349 state.position,
5350 );
5351 }
5352
5353 next_d
5354}
5355
5356fn partial_gsa_scan_right_to_left_16u_omp(
5357 t: &[u16],
5358 sa: &mut [SaSint],
5359 n: SaSint,
5360 k: SaSint,
5361 buckets: &mut [SaSint],
5362 first_lms_suffix: SaSint,
5363 left_suffixes_count: SaSint,
5364 d: SaSint,
5365 threads: SaSint,
5366) {
5367 let scan_start = left_suffixes_count + 1;
5368 let scan_end = n - first_lms_suffix;
5369
5370 if threads == 1 || scan_end - scan_start < 65536 {
5371 partial_gsa_scan_right_to_left_16u(t, sa, buckets, d, scan_start, scan_end - scan_start);
5372 } else {
5373 let mut d = d;
5374 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
5375 let mut block_start = scan_end - 1;
5376 while block_start >= scan_start {
5377 if sa[block_start as usize] == 0 {
5378 block_start -= 1;
5379 } else {
5380 let block_limit = threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
5381 let mut block_max_end = block_start - block_limit;
5382 if block_max_end < scan_start {
5383 block_max_end = scan_start - 1;
5384 }
5385 let mut block_end = block_start - 1;
5386 while block_end > block_max_end && sa[block_end as usize] != 0 {
5387 block_end -= 1;
5388 }
5389 let block_size = block_start - block_end;
5390
5391 if block_size < 32 {
5392 while block_start > block_end {
5393 let mut p = sa[block_start as usize];
5394 d += SaSint::from(p < 0);
5395 p &= SAINT_MAX;
5396 let v = buckets_index2(
5397 t[(p - 1) as usize] as usize,
5398 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
5399 );
5400 if v != 1 {
5401 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
5402 SAINT_MIN
5403 } else {
5404 0
5405 };
5406 buckets[v] -= 1;
5407 sa[buckets[v] as usize] = (p - 1) | mark;
5408 buckets[2 * ALPHABET_SIZE + v] = d;
5409 }
5410 block_start -= 1;
5411 }
5412 } else {
5413 d = partial_gsa_scan_right_to_left_16u_block_omp(
5414 t,
5415 sa,
5416 k,
5417 buckets,
5418 d,
5419 block_end + 1,
5420 block_size,
5421 threads,
5422 &mut thread_state,
5423 );
5424 block_start = block_end;
5425 }
5426 }
5427 }
5428 }
5429}
5430
5431fn partial_sorting_shift_markers_16u_omp(
5432 sa: &mut [SaSint],
5433 n: SaSint,
5434 buckets: &[SaSint],
5435 threads: SaSint,
5436) {
5437 let thread_count = if threads > 1 && n >= 65536 {
5438 usize::try_from(threads).expect("threads must be positive")
5439 } else {
5440 1
5441 };
5442 let c_step = buckets_index2(1, 0) as isize;
5443 let c_min = buckets_index2(1, 0) as isize;
5444 let c_max = buckets_index2(ALPHABET_SIZE - 1, 0) as isize;
5445 let sa_ptr = SyncMutPtr::new(sa);
5446 let buckets_ref: &[SaSint] = buckets;
5447 run_rayon_with_threads(thread_count, || {
5448 (0..thread_count).into_par_iter().for_each(|t| {
5449 let mut c = c_max - (t as isize * c_step);
5450 let sa = unsafe { sa_ptr.as_slice() };
5451 while c >= c_min {
5452 let c_usize = c as usize;
5453 let mut s = SAINT_MIN;
5454 let mut i = buckets_ref[4 * ALPHABET_SIZE + c_usize] as isize - 1;
5455 let mut j = buckets_ref[c_usize - buckets_index2(1, 0)] as isize + 3;
5456 while i >= j {
5457 let p0 = sa[i as usize];
5458 let q0 = (p0 & SAINT_MIN) ^ s;
5459 s ^= q0;
5460 sa[i as usize] = p0 ^ q0;
5461
5462 let p1 = sa[(i - 1) as usize];
5463 let q1 = (p1 & SAINT_MIN) ^ s;
5464 s ^= q1;
5465 sa[(i - 1) as usize] = p1 ^ q1;
5466
5467 let p2 = sa[(i - 2) as usize];
5468 let q2 = (p2 & SAINT_MIN) ^ s;
5469 s ^= q2;
5470 sa[(i - 2) as usize] = p2 ^ q2;
5471
5472 let p3 = sa[(i - 3) as usize];
5473 let q3 = (p3 & SAINT_MIN) ^ s;
5474 s ^= q3;
5475 sa[(i - 3) as usize] = p3 ^ q3;
5476
5477 i -= 4;
5478 }
5479
5480 j -= 3;
5481 while i >= j {
5482 let p = sa[i as usize];
5483 let q = (p & SAINT_MIN) ^ s;
5484 s ^= q;
5485 sa[i as usize] = p ^ q;
5486 i -= 1;
5487 }
5488
5489 c -= c_step * thread_count as isize;
5490 }
5491 });
5492 });
5493}
5494
5495fn induce_partial_order_16u_omp(
5496 t: &[u16],
5497 sa: &mut [SaSint],
5498 n: SaSint,
5499 k: SaSint,
5500 flags: SaSint,
5501 buckets: &mut [SaSint],
5502 first_lms_suffix: SaSint,
5503 left_suffixes_count: SaSint,
5504 threads: SaSint,
5505) {
5506 buckets[2 * ALPHABET_SIZE..4 * ALPHABET_SIZE].fill(0);
5507
5508 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
5509 let marker = 4 * ALPHABET_SIZE + buckets_index2(0, 1);
5510 buckets[marker] = buckets[4 * ALPHABET_SIZE + buckets_index2(1, 1)] - 1;
5511 flip_suffix_markers_omp(sa, buckets[marker], threads);
5512 }
5513
5514 let d = partial_sorting_scan_left_to_right_16u_omp(
5515 t,
5516 sa,
5517 n,
5518 k,
5519 buckets,
5520 left_suffixes_count,
5521 0,
5522 threads,
5523 );
5524 partial_sorting_shift_markers_16u_omp(sa, n, buckets, threads);
5525
5526 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
5527 partial_gsa_scan_right_to_left_16u_omp(
5528 t,
5529 sa,
5530 n,
5531 k,
5532 buckets,
5533 first_lms_suffix,
5534 left_suffixes_count,
5535 d,
5536 threads,
5537 );
5538
5539 if t[first_lms_suffix as usize] == 0 {
5540 let count = (buckets[buckets_index2(1, 1)] - 1) as usize;
5541 sa.copy_within(0..count, 1);
5542 sa[0] = first_lms_suffix | SAINT_MIN;
5543 }
5544
5545 buckets[buckets_index2(0, 1)] = 0;
5546 } else {
5547 partial_sorting_scan_right_to_left_16u_omp(
5548 t,
5549 sa,
5550 n,
5551 k,
5552 buckets,
5553 first_lms_suffix,
5554 left_suffixes_count,
5555 d,
5556 threads,
5557 );
5558 }
5559}
5560
5561fn induce_partial_order_32s_6k_omp(
5562 t: &[SaSint],
5563 sa: &mut [SaSint],
5564 n: SaSint,
5565 k: SaSint,
5566 buckets: &mut [SaSint],
5567 first_lms_suffix: SaSint,
5568 left_suffixes_count: SaSint,
5569 threads: SaSint,
5570 thread_state: &mut [ThreadState],
5571) {
5572 let d = partial_sorting_scan_left_to_right_32s_6k_omp(
5573 t,
5574 sa,
5575 n,
5576 buckets,
5577 left_suffixes_count,
5578 0,
5579 threads,
5580 thread_state,
5581 );
5582 partial_sorting_shift_markers_32s_6k_omp(sa, k, buckets, threads);
5583 partial_sorting_shift_buckets_32s_6k(k, buckets);
5584 partial_sorting_scan_right_to_left_32s_6k_omp(
5585 t,
5586 sa,
5587 n,
5588 buckets,
5589 first_lms_suffix,
5590 left_suffixes_count,
5591 d,
5592 threads,
5593 thread_state,
5594 );
5595}
5596
5597fn induce_partial_order_32s_4k_omp(
5598 t: &[SaSint],
5599 sa: &mut [SaSint],
5600 n: SaSint,
5601 k: SaSint,
5602 buckets: &mut [SaSint],
5603 threads: SaSint,
5604 thread_state: &mut [ThreadState],
5605) {
5606 buckets[..2 * k as usize].fill(0);
5607 let d = partial_sorting_scan_left_to_right_32s_4k_omp(
5608 t,
5609 sa,
5610 n,
5611 k,
5612 buckets,
5613 0,
5614 threads,
5615 thread_state,
5616 );
5617 partial_sorting_shift_markers_32s_4k(sa, n);
5618 partial_sorting_scan_right_to_left_32s_4k_omp(t, sa, n, k, buckets, d, threads, thread_state);
5619 partial_sorting_gather_lms_suffixes_32s_4k_omp(sa, n, threads, thread_state);
5620}
5621
5622fn induce_partial_order_32s_2k_omp(
5623 t: &[SaSint],
5624 sa: &mut [SaSint],
5625 n: SaSint,
5626 k: SaSint,
5627 buckets: &mut [SaSint],
5628 threads: SaSint,
5629 thread_state: &mut [ThreadState],
5630) {
5631 let k = k as usize;
5632 let (left, right) = buckets.split_at_mut(k);
5633 partial_sorting_scan_left_to_right_32s_1k_omp(t, sa, n, right, threads, thread_state);
5634 partial_sorting_scan_right_to_left_32s_1k_omp(t, sa, n, left, threads, thread_state);
5635 partial_sorting_gather_lms_suffixes_32s_1k_omp(sa, n, threads, thread_state);
5636}
5637
5638fn induce_partial_order_32s_1k_omp(
5639 t: &[SaSint],
5640 sa: &mut [SaSint],
5641 n: SaSint,
5642 k: SaSint,
5643 buckets: &mut [SaSint],
5644 threads: SaSint,
5645 thread_state: &mut [ThreadState],
5646) {
5647 count_suffixes_32s(t, n, k, buckets);
5648 initialize_buckets_start_32s_1k(k, buckets);
5649 partial_sorting_scan_left_to_right_32s_1k_omp(t, sa, n, buckets, threads, thread_state);
5650
5651 count_suffixes_32s(t, n, k, buckets);
5652 initialize_buckets_end_32s_1k(k, buckets);
5653 partial_sorting_scan_right_to_left_32s_1k_omp(t, sa, n, buckets, threads, thread_state);
5654
5655 partial_sorting_gather_lms_suffixes_32s_1k_omp(sa, n, threads, thread_state);
5656}
5657
5658fn final_sorting_scan_left_to_right_16u(
5659 t: &[u16],
5660 sa: &mut [SaSint],
5661 induction_bucket: &mut [SaSint],
5662 omp_block_start: SaSint,
5663 omp_block_size: SaSint,
5664) {
5665 let mut i = omp_block_start as isize;
5666 let mut j = (omp_block_start + omp_block_size - 64 - 1) as isize;
5667 while i < j {
5668 final_sorting_ltr_step(t, sa, induction_bucket, i as usize);
5669 final_sorting_ltr_step(t, sa, induction_bucket, (i + 1) as usize);
5670 i += 2;
5671 }
5672 j += 64 + 1;
5673 while i < j {
5674 final_sorting_ltr_step(t, sa, induction_bucket, i as usize);
5675 i += 1;
5676 }
5677}
5678
5679fn final_sorting_scan_right_to_left_16u(
5680 t: &[u16],
5681 sa: &mut [SaSint],
5682 induction_bucket: &mut [SaSint],
5683 omp_block_start: SaSint,
5684 omp_block_size: SaSint,
5685) {
5686 let mut i = (omp_block_start + omp_block_size - 1) as isize;
5687 let mut j = (omp_block_start + 64 + 1) as isize;
5688 while i >= j {
5689 final_sorting_rtl_step(t, sa, induction_bucket, i as usize, false);
5690 final_sorting_rtl_step(t, sa, induction_bucket, (i - 1) as usize, false);
5691 i -= 2;
5692 }
5693 j -= 64 + 1;
5694 while i >= j {
5695 final_sorting_rtl_step(t, sa, induction_bucket, i as usize, false);
5696 i -= 1;
5697 }
5698}
5699
5700fn final_sorting_scan_left_to_right_32s(
5701 t: &[SaSint],
5702 sa: &mut [SaSint],
5703 induction_bucket: &mut [SaSint],
5704 omp_block_start: SaSint,
5705 omp_block_size: SaSint,
5706) {
5707 let mut i = omp_block_start as isize;
5708 let mut j = (omp_block_start + omp_block_size - 2 * 64 - 1) as isize;
5709 while i < j {
5710 for current in [i, i + 1] {
5711 let current = current as usize;
5712 let mut p = sa[current];
5713 sa[current] = p ^ SAINT_MIN;
5714 if p > 0 {
5715 p -= 1;
5716 let p_usize = p as usize;
5717 let bucket = t[p_usize] as usize;
5718 let slot = induction_bucket[bucket] as usize;
5719 sa[slot] = p
5720 | ((usize::from(t[p_usize - usize::from(p > 0)] < t[p_usize]) as SaSint)
5721 << (SAINT_BIT - 1));
5722 induction_bucket[bucket] += 1;
5723 }
5724 }
5725 i += 2;
5726 }
5727
5728 j += 2 * 64 + 1;
5729 while i < j {
5730 let current = i as usize;
5731 let mut p = sa[current];
5732 sa[current] = p ^ SAINT_MIN;
5733 if p > 0 {
5734 p -= 1;
5735 let p_usize = p as usize;
5736 let bucket = t[p_usize] as usize;
5737 let slot = induction_bucket[bucket] as usize;
5738 sa[slot] = p
5739 | ((usize::from(t[p_usize - usize::from(p > 0)] < t[p_usize]) as SaSint)
5740 << (SAINT_BIT - 1));
5741 induction_bucket[bucket] += 1;
5742 }
5743 i += 1;
5744 }
5745}
5746
5747fn final_sorting_scan_left_to_right_32s_block_gather(
5748 t: &[SaSint],
5749 sa: &mut [SaSint],
5750 cache: &mut [ThreadCache],
5751 omp_block_start: SaSint,
5752 omp_block_size: SaSint,
5753) {
5754 if omp_block_size <= 0 {
5755 return;
5756 }
5757
5758 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
5759 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
5760 for offset in 0..size {
5761 let current = start + offset;
5762 let mut symbol = SAINT_MIN;
5763 let mut p = sa[current];
5764 sa[current] = p ^ SAINT_MIN;
5765 if p > 0 {
5766 p -= 1;
5767 let p_usize = p as usize;
5768 cache[offset].index = p
5769 | ((usize::from(t[p_usize - usize::from(p > 0)] < t[p_usize]) as SaSint)
5770 << (SAINT_BIT - 1));
5771 symbol = t[p_usize];
5772 }
5773 cache[offset].symbol = symbol;
5774 }
5775}
5776
5777fn final_sorting_scan_left_to_right_32s_block_sort(
5778 t: &[SaSint],
5779 induction_bucket: &mut [SaSint],
5780 cache: &mut [ThreadCache],
5781 omp_block_start: SaSint,
5782 omp_block_size: SaSint,
5783) {
5784 if omp_block_size <= 0 {
5785 return;
5786 }
5787
5788 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
5789 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
5790 let block_end = start + size;
5791
5792 for offset in 0..size {
5793 let v = cache[offset].symbol;
5794 if v >= 0 {
5795 let bucket_index = v as usize;
5796 let target = induction_bucket[bucket_index];
5797 cache[offset].symbol = target;
5798 induction_bucket[bucket_index] += 1;
5799 if target >= omp_block_start && target < block_end as SaSint {
5800 let ni = usize::try_from(target - omp_block_start)
5801 .expect("cache slot must be non-negative");
5802 let mut np = cache[offset].index;
5803 cache[offset].index = np ^ SAINT_MIN;
5804 if np > 0 {
5805 np -= 1;
5806 let np_usize = np as usize;
5807 cache[ni].index = np
5808 | ((usize::from(t[np_usize - usize::from(np > 0)] < t[np_usize])
5809 as SaSint)
5810 << (SAINT_BIT - 1));
5811 cache[ni].symbol = t[np_usize];
5812 }
5813 }
5814 }
5815 }
5816}
5817
5818fn final_sorting_scan_left_to_right_32s_block_omp(
5819 t: &[SaSint],
5820 sa: &mut [SaSint],
5821 buckets: &mut [SaSint],
5822 cache: &mut [ThreadCache],
5823 block_start: SaSint,
5824 block_size: SaSint,
5825 threads: SaSint,
5826) {
5827 if threads <= 1 || block_size < 16_384 {
5828 final_sorting_scan_left_to_right_32s(t, sa, buckets, block_start, block_size);
5829 return;
5830 }
5831
5832 final_sorting_scan_left_to_right_32s_block_gather(t, sa, cache, block_start, block_size);
5833 final_sorting_scan_left_to_right_32s_block_sort(t, buckets, cache, block_start, block_size);
5834
5835 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
5836 let threads_usize = usize::try_from(threads.max(1)).expect("threads must be positive");
5837 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
5838 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
5839 {
5840 let sa_ptr = SyncMutPtr::new(sa);
5841 let cache_ptr = SyncMutPtr::new(cache);
5842 run_rayon_with_threads(omp_num_threads, || {
5843 (0..omp_num_threads)
5844 .into_par_iter()
5845 .for_each(|omp_thread_num| {
5846 let omp_block_start = omp_thread_num * omp_block_stride;
5847 let omp_block_size = if omp_thread_num + 1 < omp_num_threads {
5848 omp_block_stride
5849 } else {
5850 block_size_usize - omp_block_start
5851 };
5852 let sa = unsafe { sa_ptr.as_slice() };
5853 let cache = unsafe { cache_ptr.as_slice() };
5854 compact_and_place_cached_suffixes(
5855 sa,
5856 cache,
5857 omp_block_start as SaSint,
5858 omp_block_size as SaSint,
5859 );
5860 });
5861 });
5862 }
5863}
5864
5865fn final_sorting_scan_left_to_right_32s_omp(
5866 t: &[SaSint],
5867 sa: &mut [SaSint],
5868 n: SaSint,
5869 induction_bucket: &mut [SaSint],
5870 threads: SaSint,
5871 thread_state: &mut [ThreadState],
5872) {
5873 let last = (n - 1) as usize;
5874 let bucket = t[last] as usize;
5875 let slot = induction_bucket[bucket] as usize;
5876 sa[slot] = (n - 1) | ((usize::from(t[last - 1] < t[last]) as SaSint) << (SAINT_BIT - 1));
5877 induction_bucket[bucket] += 1;
5878
5879 if threads == 1 || n < 65536 || thread_state.is_empty() {
5880 final_sorting_scan_left_to_right_32s(t, sa, induction_bucket, 0, n);
5881 return;
5882 }
5883
5884 let threads_usize = usize::try_from(threads)
5885 .expect("threads must be non-negative")
5886 .max(1);
5887 let block_span = threads_usize * PER_THREAD_CACHE_SIZE;
5888 let mut cache = vec![ThreadCache::default(); block_span];
5889 let mut block_start = 0;
5890 while block_start < n {
5891 let block_end = (block_start + block_span as SaSint).min(n);
5892 final_sorting_scan_left_to_right_32s_block_omp(
5893 t,
5894 sa,
5895 induction_bucket,
5896 &mut cache,
5897 block_start,
5898 block_end - block_start,
5899 threads,
5900 );
5901 block_start = block_end;
5902 }
5903}
5904
5905fn final_sorting_scan_right_to_left_32s(
5906 t: &[SaSint],
5907 sa: &mut [SaSint],
5908 induction_bucket: &mut [SaSint],
5909 omp_block_start: SaSint,
5910 omp_block_size: SaSint,
5911) {
5912 let mut i = (omp_block_start + omp_block_size - 1) as isize;
5913 let mut j = (omp_block_start + 2 * 64 + 1) as isize;
5914 while i >= j {
5915 for current in [i, i - 1] {
5916 let current = current as usize;
5917 let mut p = sa[current];
5918 sa[current] = p & SAINT_MAX;
5919 if p > 0 {
5920 p -= 1;
5921 let p_usize = p as usize;
5922 let bucket = t[p_usize] as usize;
5923 induction_bucket[bucket] -= 1;
5924 let slot = induction_bucket[bucket] as usize;
5925 sa[slot] = p
5926 | ((usize::from(t[p_usize - usize::from(p > 0)] > t[p_usize]) as SaSint)
5927 << (SAINT_BIT - 1));
5928 }
5929 }
5930 i -= 2;
5931 }
5932
5933 j -= 2 * 64 + 1;
5934 while i >= j {
5935 let current = i as usize;
5936 let mut p = sa[current];
5937 sa[current] = p & SAINT_MAX;
5938 if p > 0 {
5939 p -= 1;
5940 let p_usize = p as usize;
5941 let bucket = t[p_usize] as usize;
5942 induction_bucket[bucket] -= 1;
5943 let slot = induction_bucket[bucket] as usize;
5944 sa[slot] = p
5945 | ((usize::from(t[p_usize - usize::from(p > 0)] > t[p_usize]) as SaSint)
5946 << (SAINT_BIT - 1));
5947 }
5948 i -= 1;
5949 }
5950}
5951
5952fn final_sorting_scan_right_to_left_32s_block_gather(
5953 t: &[SaSint],
5954 sa: &mut [SaSint],
5955 cache: &mut [ThreadCache],
5956 omp_block_start: SaSint,
5957 omp_block_size: SaSint,
5958) {
5959 if omp_block_size <= 0 {
5960 return;
5961 }
5962
5963 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
5964 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
5965 for offset in 0..size {
5966 let current = start + offset;
5967 let mut symbol = SAINT_MIN;
5968 let mut p = sa[current];
5969 sa[current] = p & SAINT_MAX;
5970 if p > 0 {
5971 p -= 1;
5972 let p_usize = p as usize;
5973 cache[offset].index = p
5974 | ((usize::from(t[p_usize - usize::from(p > 0)] > t[p_usize]) as SaSint)
5975 << (SAINT_BIT - 1));
5976 symbol = t[p_usize];
5977 }
5978 cache[offset].symbol = symbol;
5979 }
5980}
5981
5982fn final_sorting_scan_right_to_left_32s_block_sort(
5983 t: &[SaSint],
5984 induction_bucket: &mut [SaSint],
5985 cache: &mut [ThreadCache],
5986 omp_block_start: SaSint,
5987 omp_block_size: SaSint,
5988) {
5989 if omp_block_size <= 0 {
5990 return;
5991 }
5992
5993 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
5994 let block_end = omp_block_start + omp_block_size;
5995 let mut offset = size;
5996
5997 while offset > 0 {
5998 offset -= 1;
5999 let v = cache[offset].symbol;
6000 if v >= 0 {
6001 let bucket_index = v as usize;
6002 induction_bucket[bucket_index] -= 1;
6003 let target = induction_bucket[bucket_index];
6004 cache[offset].symbol = target;
6005 if target >= omp_block_start && target < block_end {
6006 let ni = usize::try_from(target - omp_block_start)
6007 .expect("cache slot must be non-negative");
6008 let mut np = cache[offset].index;
6009 cache[offset].index = np & SAINT_MAX;
6010 if np > 0 {
6011 np -= 1;
6012 let np_usize = np as usize;
6013 cache[ni].index = np
6014 | ((usize::from(t[np_usize - usize::from(np > 0)] > t[np_usize])
6015 as SaSint)
6016 << (SAINT_BIT - 1));
6017 cache[ni].symbol = t[np_usize];
6018 }
6019 }
6020 }
6021 }
6022}
6023
6024fn final_sorting_scan_right_to_left_32s_block_omp(
6025 t: &[SaSint],
6026 sa: &mut [SaSint],
6027 buckets: &mut [SaSint],
6028 cache: &mut [ThreadCache],
6029 block_start: SaSint,
6030 block_size: SaSint,
6031 threads: SaSint,
6032) {
6033 if threads <= 1 || block_size < 16_384 {
6034 final_sorting_scan_right_to_left_32s(t, sa, buckets, block_start, block_size);
6035 return;
6036 }
6037
6038 final_sorting_scan_right_to_left_32s_block_gather(t, sa, cache, block_start, block_size);
6039 final_sorting_scan_right_to_left_32s_block_sort(t, buckets, cache, block_start, block_size);
6040
6041 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
6042 let threads_usize = usize::try_from(threads.max(1)).expect("threads must be positive");
6043 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
6044 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
6045 {
6046 let sa_ptr = SyncMutPtr::new(sa);
6047 let cache_ptr = SyncMutPtr::new(cache);
6048 run_rayon_with_threads(omp_num_threads, || {
6049 (0..omp_num_threads)
6050 .into_par_iter()
6051 .for_each(|omp_thread_num| {
6052 let omp_block_start = omp_thread_num * omp_block_stride;
6053 let omp_block_size = if omp_thread_num + 1 < omp_num_threads {
6054 omp_block_stride
6055 } else {
6056 block_size_usize - omp_block_start
6057 };
6058 let sa = unsafe { sa_ptr.as_slice() };
6059 let cache = unsafe { cache_ptr.as_slice() };
6060 compact_and_place_cached_suffixes(
6061 sa,
6062 cache,
6063 omp_block_start as SaSint,
6064 omp_block_size as SaSint,
6065 );
6066 });
6067 });
6068 }
6069}
6070
6071fn final_sorting_scan_right_to_left_32s_omp(
6072 t: &[SaSint],
6073 sa: &mut [SaSint],
6074 n: SaSint,
6075 induction_bucket: &mut [SaSint],
6076 threads: SaSint,
6077 thread_state: &mut [ThreadState],
6078) {
6079 if threads == 1 || n < 65536 || thread_state.is_empty() {
6080 final_sorting_scan_right_to_left_32s(t, sa, induction_bucket, 0, n);
6081 return;
6082 }
6083
6084 let threads_usize = usize::try_from(threads)
6085 .expect("threads must be non-negative")
6086 .max(1);
6087 let block_span = threads_usize * PER_THREAD_CACHE_SIZE;
6088 let mut cache = vec![ThreadCache::default(); block_span];
6089 let mut block_start = n - 1;
6090 while block_start >= 0 {
6091 let block_end = (block_start - block_span as SaSint).max(-1);
6092 final_sorting_scan_right_to_left_32s_block_omp(
6093 t,
6094 sa,
6095 induction_bucket,
6096 &mut cache,
6097 block_end + 1,
6098 block_start - block_end,
6099 threads,
6100 );
6101 block_start = block_end;
6102 }
6103}
6104
6105fn induce_final_order_32s_6k(
6106 t: &[SaSint],
6107 sa: &mut [SaSint],
6108 n: SaSint,
6109 k: SaSint,
6110 buckets: &mut [SaSint],
6111 threads: SaSint,
6112 thread_state: &mut [ThreadState],
6113) {
6114 let k = k as usize;
6115 final_sorting_scan_left_to_right_32s_omp(
6116 t,
6117 sa,
6118 n,
6119 &mut buckets[4 * k..5 * k],
6120 threads,
6121 thread_state,
6122 );
6123 final_sorting_scan_right_to_left_32s_omp(
6124 t,
6125 sa,
6126 n,
6127 &mut buckets[5 * k..6 * k],
6128 threads,
6129 thread_state,
6130 );
6131}
6132
6133fn induce_final_order_32s_4k(
6134 t: &[SaSint],
6135 sa: &mut [SaSint],
6136 n: SaSint,
6137 k: SaSint,
6138 buckets: &mut [SaSint],
6139 threads: SaSint,
6140 thread_state: &mut [ThreadState],
6141) {
6142 let k = k as usize;
6143 final_sorting_scan_left_to_right_32s_omp(
6144 t,
6145 sa,
6146 n,
6147 &mut buckets[2 * k..3 * k],
6148 threads,
6149 thread_state,
6150 );
6151 final_sorting_scan_right_to_left_32s_omp(
6152 t,
6153 sa,
6154 n,
6155 &mut buckets[3 * k..4 * k],
6156 threads,
6157 thread_state,
6158 );
6159}
6160
6161fn induce_final_order_32s_2k(
6162 t: &[SaSint],
6163 sa: &mut [SaSint],
6164 n: SaSint,
6165 k: SaSint,
6166 buckets: &mut [SaSint],
6167 threads: SaSint,
6168 thread_state: &mut [ThreadState],
6169) {
6170 let k = k as usize;
6171 final_sorting_scan_left_to_right_32s_omp(
6172 t,
6173 sa,
6174 n,
6175 &mut buckets[k..2 * k],
6176 threads,
6177 thread_state,
6178 );
6179 final_sorting_scan_right_to_left_32s_omp(t, sa, n, &mut buckets[..k], threads, thread_state);
6180}
6181
6182fn induce_final_order_32s_1k(
6183 t: &[SaSint],
6184 sa: &mut [SaSint],
6185 n: SaSint,
6186 k: SaSint,
6187 buckets: &mut [SaSint],
6188 threads: SaSint,
6189 thread_state: &mut [ThreadState],
6190) {
6191 count_suffixes_32s(t, n, k, buckets);
6192 initialize_buckets_start_32s_1k(k, buckets);
6193 final_sorting_scan_left_to_right_32s_omp(t, sa, n, buckets, threads, thread_state);
6194
6195 count_suffixes_32s(t, n, k, buckets);
6196 initialize_buckets_end_32s_1k(k, buckets);
6197 final_sorting_scan_right_to_left_32s_omp(t, sa, n, buckets, threads, thread_state);
6198}
6199
6200fn clear_lms_suffixes_omp(
6201 sa: &mut [SaSint],
6202 n: SaSint,
6203 k: SaSint,
6204 bucket_start: &[SaSint],
6205 bucket_end: &[SaSint],
6206 threads: SaSint,
6207) {
6208 let k_usize = usize::try_from(k).expect("k must be non-negative");
6209 let thread_count = if threads > 1 && n >= 65536 {
6210 usize::try_from(threads).expect("threads must be positive")
6211 } else {
6212 1
6213 };
6214 {
6215 let sa_ptr = SyncMutPtr::new(sa);
6216 let bucket_start_ref: &[SaSint] = bucket_start;
6217 let bucket_end_ref: &[SaSint] = bucket_end;
6218 run_rayon_with_threads(thread_count, || {
6219 (0..thread_count).into_par_iter().for_each(|t| {
6220 let mut c = t;
6221 let sa = unsafe { sa_ptr.as_slice() };
6222 while c < k_usize {
6223 if bucket_end_ref[c] > bucket_start_ref[c] {
6224 let start = bucket_start_ref[c] as usize;
6225 let end = bucket_end_ref[c] as usize;
6226 sa[start..end].fill(0);
6227 }
6228 c += thread_count;
6229 }
6230 });
6231 });
6232 }
6233}
6234
6235fn final_gsa_scan_right_to_left_16u(
6236 t: &[u16],
6237 sa: &mut [SaSint],
6238 induction_bucket: &mut [SaSint],
6239 omp_block_start: SaSint,
6240 omp_block_size: SaSint,
6241) {
6242 let mut i = (omp_block_start + omp_block_size - 1) as isize;
6243 let mut j = (omp_block_start + 64 + 1) as isize;
6244 while i >= j {
6245 final_sorting_rtl_step(t, sa, induction_bucket, i as usize, true);
6246 final_sorting_rtl_step(t, sa, induction_bucket, (i - 1) as usize, true);
6247 i -= 2;
6248 }
6249 j -= 64 + 1;
6250 while i >= j {
6251 final_sorting_rtl_step(t, sa, induction_bucket, i as usize, true);
6252 i -= 1;
6253 }
6254}
6255
6256fn final_sorting_ltr_step(
6257 t: &[u16],
6258 sa: &mut [SaSint],
6259 induction_bucket: &mut [SaSint],
6260 index: usize,
6261) {
6262 let mut p = sa[index];
6263 sa[index] = p ^ SAINT_MIN;
6264 if p > 0 {
6265 p -= 1;
6266 let c = t[p as usize] as usize;
6267 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
6268 SAINT_MIN
6269 } else {
6270 0
6271 };
6272 let dst = induction_bucket[c] as usize;
6273 sa[dst] = p | mark;
6274 induction_bucket[c] += 1;
6275 }
6276}
6277
6278fn final_sorting_rtl_step(
6279 t: &[u16],
6280 sa: &mut [SaSint],
6281 induction_bucket: &mut [SaSint],
6282 index: usize,
6283 gsa: bool,
6284) {
6285 let mut p = sa[index];
6286 sa[index] = p & SAINT_MAX;
6287 if p > 0 && (!gsa || t[(p - 1) as usize] > 0) {
6288 p -= 1;
6289 let c = t[p as usize] as usize;
6290 let mark = if t[(p - SaSint::from(p > 0)) as usize] > t[p as usize] {
6291 SAINT_MIN
6292 } else {
6293 0
6294 };
6295 induction_bucket[c] -= 1;
6296 sa[induction_bucket[c] as usize] = p | mark;
6297 }
6298}
6299
6300fn final_bwt_scan_left_to_right_16u(
6301 t: &[u16],
6302 sa: &mut [SaSint],
6303 induction_bucket: &mut [SaSint],
6304 omp_block_start: SaSint,
6305 omp_block_size: SaSint,
6306) {
6307 let mut i = omp_block_start as isize;
6308 let mut j = (omp_block_start + omp_block_size - 64 - 1) as isize;
6309 while i < j {
6310 final_bwt_ltr_step(t, sa, induction_bucket, i as usize);
6311 final_bwt_ltr_step(t, sa, induction_bucket, (i + 1) as usize);
6312 i += 2;
6313 }
6314 j += 64 + 1;
6315 while i < j {
6316 final_bwt_ltr_step(t, sa, induction_bucket, i as usize);
6317 i += 1;
6318 }
6319}
6320
6321fn final_bwt_scan_right_to_left_16u(
6322 t: &[u16],
6323 sa: &mut [SaSint],
6324 induction_bucket: &mut [SaSint],
6325 omp_block_start: SaSint,
6326 omp_block_size: SaSint,
6327) -> SaSint {
6328 let mut index = -1;
6329 let mut i = (omp_block_start + omp_block_size - 1) as isize;
6330 let mut j = (omp_block_start + 64 + 1) as isize;
6331 while i >= j {
6332 final_bwt_rtl_step(t, sa, induction_bucket, i as usize, &mut index);
6333 final_bwt_rtl_step(t, sa, induction_bucket, (i - 1) as usize, &mut index);
6334 i -= 2;
6335 }
6336 j -= 64 + 1;
6337 while i >= j {
6338 final_bwt_rtl_step(t, sa, induction_bucket, i as usize, &mut index);
6339 i -= 1;
6340 }
6341 index
6342}
6343
6344fn final_bwt_aux_scan_left_to_right_16u(
6345 t: &[u16],
6346 sa: &mut [SaSint],
6347 rm: SaSint,
6348 i_sample: &mut [SaSint],
6349 induction_bucket: &mut [SaSint],
6350 omp_block_start: SaSint,
6351 omp_block_size: SaSint,
6352) {
6353 let mut i = omp_block_start as isize;
6354 let mut j = (omp_block_start + omp_block_size - 64 - 1) as isize;
6355 while i < j {
6356 final_bwt_aux_ltr_step(t, sa, rm, i_sample, induction_bucket, i as usize);
6357 final_bwt_aux_ltr_step(t, sa, rm, i_sample, induction_bucket, (i + 1) as usize);
6358 i += 2;
6359 }
6360 j += 64 + 1;
6361 while i < j {
6362 final_bwt_aux_ltr_step(t, sa, rm, i_sample, induction_bucket, i as usize);
6363 i += 1;
6364 }
6365}
6366
6367fn final_bwt_aux_scan_right_to_left_16u(
6368 t: &[u16],
6369 sa: &mut [SaSint],
6370 rm: SaSint,
6371 i_sample: &mut [SaSint],
6372 induction_bucket: &mut [SaSint],
6373 omp_block_start: SaSint,
6374 omp_block_size: SaSint,
6375) {
6376 let mut i = (omp_block_start + omp_block_size - 1) as isize;
6377 let mut j = (omp_block_start + 64 + 1) as isize;
6378 while i >= j {
6379 final_bwt_aux_rtl_step(t, sa, rm, i_sample, induction_bucket, i as usize);
6380 final_bwt_aux_rtl_step(t, sa, rm, i_sample, induction_bucket, (i - 1) as usize);
6381 i -= 2;
6382 }
6383 j -= 64 + 1;
6384 while i >= j {
6385 final_bwt_aux_rtl_step(t, sa, rm, i_sample, induction_bucket, i as usize);
6386 i -= 1;
6387 }
6388}
6389
6390fn renumber_lms_suffixes_16u(
6391 sa: &mut [SaSint],
6392 m: SaSint,
6393 mut name: SaSint,
6394 omp_block_start: SaSint,
6395 omp_block_size: SaSint,
6396) -> SaSint {
6397 let mut i = omp_block_start as isize;
6398 let mut j = (omp_block_start + omp_block_size - 64 - 3) as isize;
6399 while i < j {
6400 let p0 = sa[i as usize];
6401 sa[m as usize + ((p0 & SAINT_MAX) >> 1) as usize] = name | SAINT_MIN;
6402 name += SaSint::from(p0 < 0);
6403
6404 let p1 = sa[(i + 1) as usize];
6405 sa[m as usize + ((p1 & SAINT_MAX) >> 1) as usize] = name | SAINT_MIN;
6406 name += SaSint::from(p1 < 0);
6407
6408 let p2 = sa[(i + 2) as usize];
6409 sa[m as usize + ((p2 & SAINT_MAX) >> 1) as usize] = name | SAINT_MIN;
6410 name += SaSint::from(p2 < 0);
6411
6412 let p3 = sa[(i + 3) as usize];
6413 sa[m as usize + ((p3 & SAINT_MAX) >> 1) as usize] = name | SAINT_MIN;
6414 name += SaSint::from(p3 < 0);
6415
6416 i += 4;
6417 }
6418
6419 j += 64 + 3;
6420 while i < j {
6421 let p = sa[i as usize];
6422 sa[m as usize + ((p & SAINT_MAX) >> 1) as usize] = name | SAINT_MIN;
6423 name += SaSint::from(p < 0);
6424 i += 1;
6425 }
6426
6427 name
6428}
6429
6430fn renumber_lms_suffixes_16u_omp(
6431 sa: &mut [SaSint],
6432 m: SaSint,
6433 threads: SaSint,
6434 thread_state: &mut [ThreadState],
6435) -> SaSint {
6436 if threads == 1 || m < 65_536 || thread_state.is_empty() {
6437 return renumber_lms_suffixes_16u(sa, m, 0, 0, m);
6438 }
6439
6440 let thread_count = usize::try_from(threads)
6441 .expect("threads must be non-negative")
6442 .min(thread_state.len());
6443 let block_stride = (m / thread_count as SaSint) & !15;
6444
6445 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
6446 let block_start = thread as SaSint * block_stride;
6447 let block_size = if thread + 1 < thread_count {
6448 block_stride
6449 } else {
6450 m - block_start
6451 };
6452 state.count = count_negative_marked_suffixes(sa, block_start, block_size);
6453 }
6454
6455 let mut name = 0;
6456 for thread in 0..thread_count {
6457 let block_start = thread as SaSint * block_stride;
6458 let block_size = if thread + 1 < thread_count {
6459 block_stride
6460 } else {
6461 m - block_start
6462 };
6463 renumber_lms_suffixes_16u(sa, m, name, block_start, block_size);
6464 name += thread_state[thread].count;
6465 }
6466
6467 name
6468}
6469
6470fn gather_marked_lms_suffixes(
6471 sa: &mut [SaSint],
6472 m: SaSint,
6473 mut l: isize,
6474 omp_block_start: isize,
6475 omp_block_size: isize,
6476) -> isize {
6477 if omp_block_size <= 0 {
6478 return l;
6479 }
6480
6481 l -= 1;
6482 let mut i = m as isize + omp_block_start + omp_block_size - 1;
6483 let mut j = m as isize + omp_block_start + 3;
6484 while i >= j {
6485 let s0 = sa[i as usize];
6486 sa[l as usize] = s0 & SAINT_MAX;
6487 l -= isize::from(s0 < 0);
6488
6489 let s1 = sa[(i - 1) as usize];
6490 sa[l as usize] = s1 & SAINT_MAX;
6491 l -= isize::from(s1 < 0);
6492
6493 let s2 = sa[(i - 2) as usize];
6494 sa[l as usize] = s2 & SAINT_MAX;
6495 l -= isize::from(s2 < 0);
6496
6497 let s3 = sa[(i - 3) as usize];
6498 sa[l as usize] = s3 & SAINT_MAX;
6499 l -= isize::from(s3 < 0);
6500
6501 i -= 4;
6502 }
6503
6504 j -= 3;
6505 while i >= j {
6506 let s = sa[i as usize];
6507 sa[l as usize] = s & SAINT_MAX;
6508 l -= isize::from(s < 0);
6509 i -= 1;
6510 }
6511
6512 l + 1
6513}
6514
6515fn gather_marked_lms_suffixes_omp(
6516 sa: &mut [SaSint],
6517 n: SaSint,
6518 m: SaSint,
6519 fs: SaSint,
6520 threads: SaSint,
6521 thread_state: &mut [ThreadState],
6522) {
6523 let half_n = n >> 1;
6524 if threads == 1 || n < 131_072 || thread_state.is_empty() {
6525 let _ = gather_marked_lms_suffixes(sa, m, (n + fs) as isize, 0, half_n as isize);
6526 return;
6527 }
6528
6529 let thread_count = usize::try_from(threads)
6530 .expect("threads must be non-negative")
6531 .min(thread_state.len());
6532 let block_stride = (half_n / thread_count as SaSint) & !15;
6533
6534 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
6535 let block_start = thread as SaSint * block_stride;
6536 let block_size = if thread + 1 < thread_count {
6537 block_stride
6538 } else {
6539 half_n - block_start
6540 };
6541 let local_end = if thread + 1 < thread_count {
6542 m + block_start + block_size
6543 } else {
6544 n + fs
6545 } as isize;
6546 let gathered_position =
6547 gather_marked_lms_suffixes(sa, m, local_end, block_start as isize, block_size as isize);
6548 state.position = gathered_position as SaSint;
6549 state.count = (local_end - gathered_position) as SaSint;
6550 }
6551
6552 let mut position = (n + fs) as isize;
6553 for thread in (0..thread_count).rev() {
6554 let count =
6555 usize::try_from(thread_state[thread].count).expect("count must be non-negative");
6556 position -= thread_state[thread].count as isize;
6557 if thread + 1 != thread_count && count > 0 {
6558 let src = usize::try_from(thread_state[thread].position)
6559 .expect("position must be non-negative");
6560 let dst = position as usize;
6561 sa.copy_within(src..src + count, dst);
6562 }
6563 }
6564}
6565
6566fn renumber_and_gather_lms_suffixes_omp(
6567 sa: &mut [SaSint],
6568 n: SaSint,
6569 m: SaSint,
6570 fs: SaSint,
6571 threads: SaSint,
6572 thread_state: &mut [ThreadState],
6573) -> SaSint {
6574 let m_usize = m as usize;
6575 let half_n = (n >> 1) as usize;
6576 sa[m_usize..m_usize + half_n].fill(0);
6577
6578 let name = renumber_lms_suffixes_16u_omp(sa, m, threads, thread_state);
6579 if name < m {
6580 gather_marked_lms_suffixes_omp(sa, n, m, fs, threads, thread_state);
6581 } else {
6582 for item in &mut sa[..m_usize] {
6583 *item &= SAINT_MAX;
6584 }
6585 }
6586
6587 name
6588}
6589
6590fn reconstruct_lms_suffixes(
6591 sa: &mut [SaSint],
6592 n: SaSint,
6593 m: SaSint,
6594 omp_block_start: isize,
6595 omp_block_size: isize,
6596) {
6597 if omp_block_size <= 0 {
6598 return;
6599 }
6600
6601 let base = (n - m) as usize;
6602 let mut i = omp_block_start;
6603 let mut j = omp_block_start + omp_block_size - 64 - 3;
6604 while i < j {
6605 let iu = i as usize;
6606 let s0 = sa[iu] as usize;
6607 let s1 = sa[iu + 1] as usize;
6608 let s2 = sa[iu + 2] as usize;
6609 let s3 = sa[iu + 3] as usize;
6610 sa[iu] = sa[base + s0];
6611 sa[iu + 1] = sa[base + s1];
6612 sa[iu + 2] = sa[base + s2];
6613 sa[iu + 3] = sa[base + s3];
6614 i += 4;
6615 }
6616
6617 j += 64 + 3;
6618 while i < j {
6619 let iu = i as usize;
6620 let s = sa[iu] as usize;
6621 sa[iu] = sa[base + s];
6622 i += 1;
6623 }
6624}
6625
6626fn reconstruct_lms_suffixes_omp(sa: &mut [SaSint], n: SaSint, m: SaSint, threads: SaSint) {
6627 if threads == 1 || m < 65_536 {
6628 reconstruct_lms_suffixes(sa, n, m, 0, m as isize);
6629 return;
6630 }
6631
6632 let thread_count = threads as usize;
6633 let block_stride = (m / threads) & !15;
6634 for thread in 0..thread_count {
6635 let block_start = thread as SaSint * block_stride;
6636 let block_size = if thread + 1 < thread_count {
6637 block_stride
6638 } else {
6639 m - block_start
6640 };
6641 reconstruct_lms_suffixes(sa, n, m, block_start as isize, block_size as isize);
6642 }
6643}
6644
6645fn renumber_distinct_lms_suffixes_32s_4k(
6646 sa: &mut [SaSint],
6647 m: SaSint,
6648 mut name: SaSint,
6649 omp_block_start: isize,
6650 omp_block_size: isize,
6651) -> SaSint {
6652 if omp_block_size <= 0 {
6653 return name;
6654 }
6655
6656 let m_usize = m as usize;
6657 let start = omp_block_start as usize;
6658 let size = omp_block_size as usize;
6659 let (sa_head, sam) = sa.split_at_mut(m_usize);
6660 let mut i = start;
6661 let mut j = start + size.saturating_sub(64 + 3);
6662 let mut p3 = 0;
6663
6664 while i < j {
6665 let p0 = sa_head[i];
6666 sa_head[i] = p0 & SAINT_MAX;
6667 sam[(sa_head[i] >> 1) as usize] = name | (p0 & p3 & SAINT_MIN);
6668 name += SaSint::from(p0 < 0);
6669
6670 let p1 = sa_head[i + 1];
6671 sa_head[i + 1] = p1 & SAINT_MAX;
6672 sam[(sa_head[i + 1] >> 1) as usize] = name | (p1 & p0 & SAINT_MIN);
6673 name += SaSint::from(p1 < 0);
6674
6675 let p2 = sa_head[i + 2];
6676 sa_head[i + 2] = p2 & SAINT_MAX;
6677 sam[(sa_head[i + 2] >> 1) as usize] = name | (p2 & p1 & SAINT_MIN);
6678 name += SaSint::from(p2 < 0);
6679
6680 p3 = sa_head[i + 3];
6681 sa_head[i + 3] = p3 & SAINT_MAX;
6682 sam[(sa_head[i + 3] >> 1) as usize] = name | (p3 & p2 & SAINT_MIN);
6683 name += SaSint::from(p3 < 0);
6684
6685 i += 4;
6686 }
6687
6688 j = start + size;
6689 while i < j {
6690 let p2 = p3;
6691 p3 = sa_head[i];
6692 sa_head[i] = p3 & SAINT_MAX;
6693 sam[(sa_head[i] >> 1) as usize] = name | (p3 & p2 & SAINT_MIN);
6694 name += SaSint::from(p3 < 0);
6695 i += 1;
6696 }
6697
6698 name
6699}
6700
6701fn mark_distinct_lms_suffixes_32s(
6702 sa: &mut [SaSint],
6703 m: SaSint,
6704 omp_block_start: isize,
6705 omp_block_size: isize,
6706) {
6707 if omp_block_size <= 0 {
6708 return;
6709 }
6710
6711 let mut i = m as usize + omp_block_start as usize;
6712 let mut j = i + (omp_block_size as usize).saturating_sub(3);
6713 let mut p3 = 0;
6714 while i < j {
6715 let mut p0 = sa[i];
6716 sa[i] = p0 & (p3 | SAINT_MAX);
6717 p0 = if p0 == 0 { p3 } else { p0 };
6718
6719 let mut p1 = sa[i + 1];
6720 sa[i + 1] = p1 & (p0 | SAINT_MAX);
6721 p1 = if p1 == 0 { p0 } else { p1 };
6722
6723 let mut p2 = sa[i + 2];
6724 sa[i + 2] = p2 & (p1 | SAINT_MAX);
6725 p2 = if p2 == 0 { p1 } else { p2 };
6726
6727 p3 = sa[i + 3];
6728 sa[i + 3] = p3 & (p2 | SAINT_MAX);
6729 p3 = if p3 == 0 { p2 } else { p3 };
6730 i += 4;
6731 }
6732
6733 j = m as usize + omp_block_start as usize + omp_block_size as usize;
6734 while i < j {
6735 let p2 = p3;
6736 p3 = sa[i];
6737 sa[i] = p3 & (p2 | SAINT_MAX);
6738 p3 = if p3 == 0 { p2 } else { p3 };
6739 i += 1;
6740 }
6741}
6742
6743fn clamp_lms_suffixes_length_32s(
6744 sa: &mut [SaSint],
6745 m: SaSint,
6746 omp_block_start: isize,
6747 omp_block_size: isize,
6748) {
6749 if omp_block_size <= 0 {
6750 return;
6751 }
6752
6753 let mut i = m as usize + omp_block_start as usize;
6754 let mut j = i + (omp_block_size as usize).saturating_sub(3);
6755 while i < j {
6756 let s0 = sa[i];
6757 sa[i] = if s0 < 0 { s0 } else { 0 } & SAINT_MAX;
6758
6759 let s1 = sa[i + 1];
6760 sa[i + 1] = if s1 < 0 { s1 } else { 0 } & SAINT_MAX;
6761
6762 let s2 = sa[i + 2];
6763 sa[i + 2] = if s2 < 0 { s2 } else { 0 } & SAINT_MAX;
6764
6765 let s3 = sa[i + 3];
6766 sa[i + 3] = if s3 < 0 { s3 } else { 0 } & SAINT_MAX;
6767
6768 i += 4;
6769 }
6770
6771 j = m as usize + omp_block_start as usize + omp_block_size as usize;
6772 while i < j {
6773 let s = sa[i];
6774 sa[i] = if s < 0 { s } else { 0 } & SAINT_MAX;
6775 i += 1;
6776 }
6777}
6778
6779fn renumber_distinct_lms_suffixes_32s_4k_omp(
6780 sa: &mut [SaSint],
6781 m: SaSint,
6782 threads: SaSint,
6783 thread_state: &mut [ThreadState],
6784) -> SaSint {
6785 if threads == 1 || m < 65_536 || thread_state.is_empty() {
6786 return renumber_distinct_lms_suffixes_32s_4k(sa, m, 1, 0, m as isize) - 1;
6787 }
6788
6789 let thread_count = usize::try_from(threads)
6790 .expect("threads must be non-negative")
6791 .min(thread_state.len());
6792 let block_stride = (m / thread_count as SaSint) & !15;
6793
6794 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
6795 let block_start = thread as SaSint * block_stride;
6796 let block_size = if thread + 1 < thread_count {
6797 block_stride
6798 } else {
6799 m - block_start
6800 };
6801 state.count = count_negative_marked_suffixes(sa, block_start, block_size);
6802 }
6803
6804 let mut count = 1;
6805 for thread in 0..thread_count {
6806 let block_start = thread as SaSint * block_stride;
6807 let block_size = if thread + 1 < thread_count {
6808 block_stride
6809 } else {
6810 m - block_start
6811 };
6812 renumber_distinct_lms_suffixes_32s_4k(
6813 sa,
6814 m,
6815 count,
6816 block_start as isize,
6817 block_size as isize,
6818 );
6819 count += thread_state[thread].count;
6820 }
6821
6822 count - 1
6823}
6824
6825fn mark_distinct_lms_suffixes_32s_omp(sa: &mut [SaSint], n: SaSint, m: SaSint, threads: SaSint) {
6826 let half_n = n >> 1;
6827 if threads == 1 || n < 131_072 {
6828 mark_distinct_lms_suffixes_32s(sa, m, 0, half_n as isize);
6829 return;
6830 }
6831
6832 let thread_count = threads as usize;
6833 let block_stride = (half_n / threads) & !15;
6834 for thread in 0..thread_count {
6835 let block_start = thread as SaSint * block_stride;
6836 let block_size = if thread + 1 < thread_count {
6837 block_stride
6838 } else {
6839 half_n - block_start
6840 };
6841 mark_distinct_lms_suffixes_32s(sa, m, block_start as isize, block_size as isize);
6842 }
6843}
6844
6845fn clamp_lms_suffixes_length_32s_omp(sa: &mut [SaSint], n: SaSint, m: SaSint, threads: SaSint) {
6846 let half_n = n >> 1;
6847 if threads == 1 || n < 131_072 {
6848 clamp_lms_suffixes_length_32s(sa, m, 0, half_n as isize);
6849 return;
6850 }
6851
6852 let thread_count = threads as usize;
6853 let block_stride = (half_n / threads) & !15;
6854 for thread in 0..thread_count {
6855 let block_start = thread as SaSint * block_stride;
6856 let block_size = if thread + 1 < thread_count {
6857 block_stride
6858 } else {
6859 half_n - block_start
6860 };
6861 clamp_lms_suffixes_length_32s(sa, m, block_start as isize, block_size as isize);
6862 }
6863}
6864
6865fn renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(
6866 sa: &mut [SaSint],
6867 n: SaSint,
6868 m: SaSint,
6869 threads: SaSint,
6870 thread_state: &mut [ThreadState],
6871) -> SaSint {
6872 let m_usize = m as usize;
6873 let half_n = (n >> 1) as usize;
6874 sa[m_usize..m_usize + half_n].fill(0);
6875
6876 let name = renumber_distinct_lms_suffixes_32s_4k_omp(sa, m, threads, thread_state);
6877 if name < m {
6878 mark_distinct_lms_suffixes_32s_omp(sa, n, m, threads);
6879 }
6880
6881 name
6882}
6883
6884fn renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(
6885 t: &[SaSint],
6886 sa: &mut [SaSint],
6887 n: SaSint,
6888 m: SaSint,
6889 threads: SaSint,
6890) -> SaSint {
6891 let m_usize = m as usize;
6892 let n_usize = n as usize;
6893
6894 gather_lms_suffixes_32s(t, sa, n);
6895 sa[m_usize..n_usize - m_usize].fill(0);
6896
6897 let mut i = n - m;
6898 let mut j = n - 1 - 64 - 3;
6899 while i < j {
6900 let s0 = (sa[i as usize] as SaUint >> 1) as usize;
6901 let s1 = (sa[(i + 1) as usize] as SaUint >> 1) as usize;
6902 let s2 = (sa[(i + 2) as usize] as SaUint >> 1) as usize;
6903 let s3 = (sa[(i + 3) as usize] as SaUint >> 1) as usize;
6904 sa[m_usize + s0] = sa[(i + 1) as usize] - sa[i as usize] + 1 + SAINT_MIN;
6905 sa[m_usize + s1] = sa[(i + 2) as usize] - sa[(i + 1) as usize] + 1 + SAINT_MIN;
6906 sa[m_usize + s2] = sa[(i + 3) as usize] - sa[(i + 2) as usize] + 1 + SAINT_MIN;
6907 sa[m_usize + s3] = sa[(i + 4) as usize] - sa[(i + 3) as usize] + 1 + SAINT_MIN;
6908 i += 4;
6909 }
6910
6911 j += 64 + 3;
6912 while i < j {
6913 let s = (sa[i as usize] as SaUint >> 1) as usize;
6914 sa[m_usize + s] = sa[(i + 1) as usize] - sa[i as usize] + 1 + SAINT_MIN;
6915 i += 1;
6916 }
6917
6918 let tail = (sa[n_usize - 1] as SaUint >> 1) as usize;
6919 sa[m_usize + tail] = 1 + SAINT_MIN;
6920
6921 clamp_lms_suffixes_length_32s_omp(sa, n, m, threads);
6922
6923 let mut name = 1;
6924 if m_usize > 0 {
6925 let mut i = 1usize;
6926 let mut j = m_usize.saturating_sub(64 + 1);
6927 let mut p = sa[0] as usize;
6928 let mut plen = sa[m_usize + (p >> 1)];
6929 let mut pdiff = SAINT_MIN;
6930
6931 while i < j {
6932 let q = sa[i] as usize;
6933 let qlen = sa[m_usize + (q >> 1)];
6934 let mut qdiff = SAINT_MIN;
6935 if plen == qlen {
6936 let mut l = 0;
6937 while l < qlen as usize {
6938 if t[p + l] != t[q + l] {
6939 break;
6940 }
6941 l += 1;
6942 }
6943 qdiff = ((l as SaSint) - qlen) & SAINT_MIN;
6944 }
6945 sa[m_usize + (p >> 1)] = name | (pdiff & qdiff);
6946 name += SaSint::from(qdiff < 0);
6947
6948 p = sa[i + 1] as usize;
6949 plen = sa[m_usize + (p >> 1)];
6950 pdiff = SAINT_MIN;
6951 if qlen == plen {
6952 let mut l = 0;
6953 while l < plen as usize {
6954 if t[q + l] != t[p + l] {
6955 break;
6956 }
6957 l += 1;
6958 }
6959 pdiff = ((l as SaSint) - plen) & SAINT_MIN;
6960 }
6961 sa[m_usize + (q >> 1)] = name | (qdiff & pdiff);
6962 name += SaSint::from(pdiff < 0);
6963 i += 2;
6964 }
6965
6966 j = m_usize;
6967 while i < j {
6968 let q = sa[i] as usize;
6969 let qlen = sa[m_usize + (q >> 1)];
6970 let mut qdiff = SAINT_MIN;
6971 if plen == qlen {
6972 let mut l = 0;
6973 while l < plen as usize {
6974 if t[p + l] != t[q + l] {
6975 break;
6976 }
6977 l += 1;
6978 }
6979 qdiff = ((l as SaSint) - plen) & SAINT_MIN;
6980 }
6981 sa[m_usize + (p >> 1)] = name | (pdiff & qdiff);
6982 name += SaSint::from(qdiff < 0);
6983 p = q;
6984 plen = qlen;
6985 pdiff = qdiff;
6986 i += 1;
6987 }
6988
6989 sa[m_usize + (p >> 1)] = name | pdiff;
6990 name += 1;
6991 }
6992
6993 if name <= m {
6994 mark_distinct_lms_suffixes_32s_omp(sa, n, m, threads);
6995 }
6996
6997 name - 1
6998}
6999
7000fn renumber_unique_and_nonunique_lms_suffixes_32s(
7001 t: &mut [SaSint],
7002 sa: &mut [SaSint],
7003 m: SaSint,
7004 mut f: SaSint,
7005 omp_block_start: isize,
7006 omp_block_size: isize,
7007) -> SaSint {
7008 if omp_block_size <= 0 {
7009 return f;
7010 }
7011
7012 let m_usize = m as usize;
7013 let (sa_head, sam) = sa.split_at_mut(m_usize);
7014 let mut i = omp_block_start;
7015 let mut j = omp_block_start + omp_block_size - 128 - 3;
7016 while i < j {
7017 for offset in 0..4 {
7018 let idx = (i + offset) as usize;
7019 let p = sa_head[idx] as SaUint;
7020 let mut s = sam[(p >> 1) as usize];
7021 if s < 0 {
7022 t[p as usize] |= SAINT_MIN;
7023 f += 1;
7024 s = i as SaSint + offset as SaSint + SAINT_MIN + f;
7025 }
7026 sam[(p >> 1) as usize] = s - f;
7027 }
7028 i += 4;
7029 }
7030
7031 j += 128 + 3;
7032 while i < j {
7033 let p = sa_head[i as usize] as SaUint;
7034 let mut s = sam[(p >> 1) as usize];
7035 if s < 0 {
7036 t[p as usize] |= SAINT_MIN;
7037 f += 1;
7038 s = i as SaSint + SAINT_MIN + f;
7039 }
7040 sam[(p >> 1) as usize] = s - f;
7041 i += 1;
7042 }
7043
7044 f
7045}
7046
7047fn compact_unique_and_nonunique_lms_suffixes_32s(
7048 sa: &mut [SaSint],
7049 m: SaSint,
7050 pl: &mut isize,
7051 pr: &mut isize,
7052 omp_block_start: isize,
7053 omp_block_size: isize,
7054) {
7055 if omp_block_size <= 0 {
7056 return;
7057 }
7058
7059 let m_usize = m as usize;
7060 let source: Vec<SaSint> = sa
7061 [m_usize + omp_block_start as usize..m_usize + (omp_block_start + omp_block_size) as usize]
7062 .to_vec();
7063 let mut l = *pl - 1;
7064 let mut r = *pr - 1;
7065
7066 for &p in source.iter().rev() {
7067 sa[l as usize] = p & SAINT_MAX;
7068 l -= isize::from(p < 0);
7069
7070 sa[r as usize] = p.wrapping_sub(1);
7071 r -= isize::from(p > 0);
7072 }
7073
7074 *pl = l + 1;
7075 *pr = r + 1;
7076}
7077
7078fn count_unique_suffixes(
7079 sa: &[SaSint],
7080 m: SaSint,
7081 omp_block_start: isize,
7082 omp_block_size: isize,
7083) -> SaSint {
7084 let base = m as usize;
7085 let start = omp_block_start as usize;
7086 let end = start + omp_block_size as usize;
7087 let mut count = 0;
7088 for i in start..end {
7089 count += SaSint::from(sa[base + ((sa[i] as SaUint) >> 1) as usize] < 0);
7090 }
7091 count
7092}
7093
7094fn renumber_unique_and_nonunique_lms_suffixes_32s_omp(
7095 t: &mut [SaSint],
7096 sa: &mut [SaSint],
7097 m: SaSint,
7098 threads: SaSint,
7099) -> SaSint {
7100 if threads == 1 || m < 65_536 {
7101 return renumber_unique_and_nonunique_lms_suffixes_32s(t, sa, m, 0, 0, m as isize);
7102 }
7103
7104 let thread_count = threads as usize;
7105 let block_stride = (m / threads) & !15;
7106 let mut counts = vec![0; thread_count];
7107
7108 for thread in 0..thread_count {
7109 let block_start = thread as SaSint * block_stride;
7110 let block_size = if thread + 1 < thread_count {
7111 block_stride
7112 } else {
7113 m - block_start
7114 };
7115 counts[thread] = count_unique_suffixes(sa, m, block_start as isize, block_size as isize);
7116 }
7117
7118 let mut f = 0;
7119 for thread in 0..thread_count {
7120 let block_start = thread as SaSint * block_stride;
7121 let block_size = if thread + 1 < thread_count {
7122 block_stride
7123 } else {
7124 m - block_start
7125 };
7126 renumber_unique_and_nonunique_lms_suffixes_32s(
7127 t,
7128 sa,
7129 m,
7130 f,
7131 block_start as isize,
7132 block_size as isize,
7133 );
7134 f += counts[thread];
7135 }
7136
7137 f
7138}
7139
7140fn compact_unique_and_nonunique_lms_suffixes_32s_omp(
7141 sa: &mut [SaSint],
7142 n: SaSint,
7143 m: SaSint,
7144 fs: SaSint,
7145 f: SaSint,
7146 threads: SaSint,
7147) {
7148 let half_n = n >> 1;
7149 if threads == 1 || n < 131_072 || m >= fs {
7150 let mut l = m as isize;
7151 let mut r = (n + fs) as isize;
7152 compact_unique_and_nonunique_lms_suffixes_32s(sa, m, &mut l, &mut r, 0, half_n as isize);
7153 } else {
7154 let thread_count = threads as usize;
7155 let block_stride = (half_n / threads) & !15;
7156 let mut positions = vec![0isize; thread_count];
7157 let mut counts = vec![0isize; thread_count];
7158
7159 for thread in 0..thread_count {
7160 let block_start = thread as SaSint * block_stride;
7161 let block_size = if thread + 1 < thread_count {
7162 block_stride
7163 } else {
7164 half_n - block_start
7165 };
7166 let mut position = (m + half_n + block_start + block_size) as isize;
7167 let mut count = (m + block_start + block_size) as isize;
7168 compact_unique_and_nonunique_lms_suffixes_32s(
7169 sa,
7170 m,
7171 &mut position,
7172 &mut count,
7173 block_start as isize,
7174 block_size as isize,
7175 );
7176 positions[thread] = position;
7177 counts[thread] = count;
7178 }
7179
7180 let mut position = m as isize;
7181 for thread in (0..thread_count).rev() {
7182 let block_end = if thread + 1 < thread_count {
7183 block_stride * (thread as SaSint + 1)
7184 } else {
7185 half_n
7186 };
7187 let count = (m + half_n + block_end) as isize - positions[thread];
7188 if count > 0 {
7189 position -= count;
7190 let src = positions[thread] as usize;
7191 let dst = position as usize;
7192 sa.copy_within(src..src + count as usize, dst);
7193 }
7194 }
7195
7196 let mut position = (n + fs) as isize;
7197 for thread in (0..thread_count).rev() {
7198 let block_end = if thread + 1 < thread_count {
7199 block_stride * (thread as SaSint + 1)
7200 } else {
7201 half_n
7202 };
7203 let count = (m + block_end) as isize - counts[thread];
7204 if count > 0 {
7205 position -= count;
7206 let src = counts[thread] as usize;
7207 let dst = position as usize;
7208 sa.copy_within(src..src + count as usize, dst);
7209 }
7210 }
7211 }
7212
7213 let dst = (n + fs - m) as usize;
7214 let src = (m - f) as usize;
7215 sa.copy_within(src..src + f as usize, dst);
7216}
7217
7218fn compact_lms_suffixes_32s_omp(
7219 t: &mut [SaSint],
7220 sa: &mut [SaSint],
7221 n: SaSint,
7222 m: SaSint,
7223 fs: SaSint,
7224 threads: SaSint,
7225) -> SaSint {
7226 let f = renumber_unique_and_nonunique_lms_suffixes_32s_omp(t, sa, m, threads);
7227 compact_unique_and_nonunique_lms_suffixes_32s_omp(sa, n, m, fs, f, threads);
7228 f
7229}
7230
7231fn merge_unique_lms_suffixes_32s(
7232 t: &mut [SaSint],
7233 sa: &mut [SaSint],
7234 n: SaSint,
7235 m: SaSint,
7236 l: isize,
7237 omp_block_start: isize,
7238 omp_block_size: isize,
7239) {
7240 let mut src_index = (n as isize - m as isize - 1 + l) as usize;
7241 let mut tmp = sa[src_index] as isize;
7242 src_index += 1;
7243
7244 let mut i = omp_block_start;
7245 let mut j = omp_block_start + omp_block_size - 6;
7246 while i < j {
7247 let iu = i as usize;
7248
7249 let c0 = t[iu];
7250 if c0 < 0 {
7251 t[iu] = c0 & SAINT_MAX;
7252 sa[tmp as usize] = i as SaSint;
7253 i += 1;
7254 tmp = sa[src_index] as isize;
7255 src_index += 1;
7256 }
7257
7258 let c1 = t[(i + 1) as usize];
7259 if c1 < 0 {
7260 t[(i + 1) as usize] = c1 & SAINT_MAX;
7261 sa[tmp as usize] = i as SaSint + 1;
7262 i += 1;
7263 tmp = sa[src_index] as isize;
7264 src_index += 1;
7265 }
7266
7267 let c2 = t[(i + 2) as usize];
7268 if c2 < 0 {
7269 t[(i + 2) as usize] = c2 & SAINT_MAX;
7270 sa[tmp as usize] = i as SaSint + 2;
7271 i += 1;
7272 tmp = sa[src_index] as isize;
7273 src_index += 1;
7274 }
7275
7276 let c3 = t[(i + 3) as usize];
7277 if c3 < 0 {
7278 t[(i + 3) as usize] = c3 & SAINT_MAX;
7279 sa[tmp as usize] = i as SaSint + 3;
7280 i += 1;
7281 tmp = sa[src_index] as isize;
7282 src_index += 1;
7283 }
7284
7285 i += 4;
7286 }
7287
7288 j += 6;
7289 while i < j {
7290 let c = t[i as usize];
7291 if c < 0 {
7292 t[i as usize] = c & SAINT_MAX;
7293 sa[tmp as usize] = i as SaSint;
7294 i += 1;
7295 tmp = sa[src_index] as isize;
7296 src_index += 1;
7297 }
7298 i += 1;
7299 }
7300}
7301
7302fn merge_nonunique_lms_suffixes_32s(
7303 sa: &mut [SaSint],
7304 n: SaSint,
7305 m: SaSint,
7306 l: isize,
7307 omp_block_start: isize,
7308 omp_block_size: isize,
7309) {
7310 let mut src_index = (n as isize - m as isize - 1 + l) as usize;
7311 let mut tmp = sa[src_index];
7312 src_index += 1;
7313
7314 let mut i = omp_block_start;
7315 let mut j = omp_block_start + omp_block_size - 3;
7316 while i < j {
7317 if sa[i as usize] == 0 {
7318 sa[i as usize] = tmp;
7319 tmp = sa[src_index];
7320 src_index += 1;
7321 }
7322 if sa[(i + 1) as usize] == 0 {
7323 sa[(i + 1) as usize] = tmp;
7324 tmp = sa[src_index];
7325 src_index += 1;
7326 }
7327 if sa[(i + 2) as usize] == 0 {
7328 sa[(i + 2) as usize] = tmp;
7329 tmp = sa[src_index];
7330 src_index += 1;
7331 }
7332 if sa[(i + 3) as usize] == 0 {
7333 sa[(i + 3) as usize] = tmp;
7334 tmp = sa[src_index];
7335 src_index += 1;
7336 }
7337 i += 4;
7338 }
7339
7340 j += 3;
7341 while i < j {
7342 if sa[i as usize] == 0 {
7343 sa[i as usize] = tmp;
7344 tmp = sa[src_index];
7345 src_index += 1;
7346 }
7347 i += 1;
7348 }
7349}
7350
7351fn merge_unique_lms_suffixes_32s_omp(
7352 t: &mut [SaSint],
7353 sa: &mut [SaSint],
7354 n: SaSint,
7355 m: SaSint,
7356 threads: SaSint,
7357) {
7358 if threads == 1 || n < 65_536 {
7359 merge_unique_lms_suffixes_32s(t, sa, n, m, 0, 0, n as isize);
7360 return;
7361 }
7362
7363 let thread_count = threads as usize;
7364 let block_stride = (n / threads) & !15;
7365 let mut counts = vec![0; thread_count];
7366
7367 for thread in 0..thread_count {
7368 let block_start = thread as SaSint * block_stride;
7369 let block_size = if thread + 1 < thread_count {
7370 block_stride
7371 } else {
7372 n - block_start
7373 };
7374 counts[thread] = count_negative_marked_suffixes(t, block_start, block_size);
7375 }
7376
7377 let mut count = 0;
7378 for thread in 0..thread_count {
7379 let block_start = thread as SaSint * block_stride;
7380 let block_size = if thread + 1 < thread_count {
7381 block_stride
7382 } else {
7383 n - block_start
7384 };
7385 merge_unique_lms_suffixes_32s(
7386 t,
7387 sa,
7388 n,
7389 m,
7390 count as isize,
7391 block_start as isize,
7392 block_size as isize,
7393 );
7394 count += counts[thread];
7395 }
7396}
7397
7398fn merge_nonunique_lms_suffixes_32s_omp(
7399 sa: &mut [SaSint],
7400 n: SaSint,
7401 m: SaSint,
7402 f: SaSint,
7403 threads: SaSint,
7404) {
7405 if threads == 1 || m < 65_536 {
7406 merge_nonunique_lms_suffixes_32s(sa, n, m, f as isize, 0, m as isize);
7407 return;
7408 }
7409
7410 let thread_count = threads as usize;
7411 let block_stride = (m / threads) & !15;
7412 let mut counts = vec![0; thread_count];
7413
7414 for thread in 0..thread_count {
7415 let block_start = thread as SaSint * block_stride;
7416 let block_size = if thread + 1 < thread_count {
7417 block_stride
7418 } else {
7419 m - block_start
7420 };
7421 counts[thread] = count_zero_marked_suffixes(sa, block_start, block_size);
7422 }
7423
7424 let mut count = f;
7425 for thread in 0..thread_count {
7426 let block_start = thread as SaSint * block_stride;
7427 let block_size = if thread + 1 < thread_count {
7428 block_stride
7429 } else {
7430 m - block_start
7431 };
7432 merge_nonunique_lms_suffixes_32s(
7433 sa,
7434 n,
7435 m,
7436 count as isize,
7437 block_start as isize,
7438 block_size as isize,
7439 );
7440 count += counts[thread];
7441 }
7442}
7443
7444fn merge_compacted_lms_suffixes_32s_omp(
7445 t: &mut [SaSint],
7446 sa: &mut [SaSint],
7447 n: SaSint,
7448 m: SaSint,
7449 f: SaSint,
7450 threads: SaSint,
7451) {
7452 merge_unique_lms_suffixes_32s_omp(t, sa, n, m, threads);
7453 merge_nonunique_lms_suffixes_32s_omp(sa, n, m, f, threads);
7454}
7455
7456fn reconstruct_compacted_lms_suffixes_32s_2k_omp(
7457 t: &mut [SaSint],
7458 sa: &mut [SaSint],
7459 n: SaSint,
7460 k: SaSint,
7461 m: SaSint,
7462 fs: SaSint,
7463 f: SaSint,
7464 buckets: &mut [SaSint],
7465 local_buckets: SaSint,
7466 threads: SaSint,
7467 thread_state: &mut [ThreadState],
7468) {
7469 if f > 0 {
7470 let dst = (n - m - 1) as usize;
7471 let src = (n + fs - m) as usize;
7472 sa.copy_within(src..src + f as usize, dst);
7473
7474 count_and_gather_compacted_lms_suffixes_32s_2k_omp(
7475 t,
7476 sa,
7477 n,
7478 k,
7479 buckets,
7480 local_buckets,
7481 threads,
7482 thread_state,
7483 );
7484 reconstruct_lms_suffixes_omp(sa, n, m - f, threads);
7485
7486 let dst = (n - m - 1 + f) as usize;
7487 sa.copy_within(0..(m - f) as usize, dst);
7488 sa[..m as usize].fill(0);
7489
7490 merge_compacted_lms_suffixes_32s_omp(t, sa, n, m, f, threads);
7491 } else {
7492 count_and_gather_lms_suffixes_32s_2k(t, sa, n, k, buckets, 0, n as isize);
7493 reconstruct_lms_suffixes_omp(sa, n, m, threads);
7494 }
7495}
7496
7497fn reconstruct_compacted_lms_suffixes_32s_1k_omp(
7498 t: &mut [SaSint],
7499 sa: &mut [SaSint],
7500 n: SaSint,
7501 m: SaSint,
7502 fs: SaSint,
7503 f: SaSint,
7504 threads: SaSint,
7505) {
7506 if f > 0 {
7507 let dst = (n - m - 1) as usize;
7508 let src = (n + fs - m) as usize;
7509 sa.copy_within(src..src + f as usize, dst);
7510
7511 gather_compacted_lms_suffixes_32s(t, sa, n);
7512 reconstruct_lms_suffixes_omp(sa, n, m - f, threads);
7513
7514 let dst = (n - m - 1 + f) as usize;
7515 sa.copy_within(0..(m - f) as usize, dst);
7516 sa[..m as usize].fill(0);
7517
7518 merge_compacted_lms_suffixes_32s_omp(t, sa, n, m, f, threads);
7519 } else {
7520 gather_lms_suffixes_32s(t, sa, n);
7521 reconstruct_lms_suffixes_omp(sa, n, m, threads);
7522 }
7523}
7524
7525fn place_lms_suffixes_interval_16u(
7526 sa: &mut [SaSint],
7527 n: SaSint,
7528 mut m: SaSint,
7529 flags: SaSint,
7530 buckets: &mut [SaSint],
7531) {
7532 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
7533 buckets[7 * ALPHABET_SIZE] -= 1;
7534 }
7535
7536 let mut j = n as isize;
7537 let mut c = ALPHABET_SIZE as isize - 2;
7538 while c >= 0 {
7539 let ci = c as usize;
7540 let l =
7541 buckets[buckets_index2(ci, 1) + buckets_index2(1, 0)] - buckets[buckets_index2(ci, 1)];
7542 if l > 0 {
7543 let i = buckets[7 * ALPHABET_SIZE + ci] as isize;
7544 if j - i > 0 {
7545 sa[i as usize..j as usize].fill(0);
7546 }
7547
7548 m -= l;
7549 j = i - l as isize;
7550 let src = m as usize;
7551 let dst = j as usize;
7552 sa.copy_within(src..src + l as usize, dst);
7553 }
7554 c -= 1;
7555 }
7556
7557 sa[..j as usize].fill(0);
7558
7559 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
7560 buckets[7 * ALPHABET_SIZE] += 1;
7561 }
7562}
7563
7564fn place_lms_suffixes_interval_32s_4k(
7565 sa: &mut [SaSint],
7566 n: SaSint,
7567 k: SaSint,
7568 mut m: SaSint,
7569 buckets: &[SaSint],
7570) {
7571 let bucket_end = &buckets[3 * k as usize..4 * k as usize];
7572 let mut j = n as usize;
7573 let mut c = k - 2;
7574 while c >= 0 {
7575 let cu = c as usize;
7576 let l =
7577 buckets[buckets_index2(cu, 1) + buckets_index2(1, 0)] - buckets[buckets_index2(cu, 1)];
7578 if l > 0 {
7579 let i = bucket_end[cu] as usize;
7580 if j > i {
7581 sa[i..j].fill(0);
7582 }
7583
7584 m -= l;
7585 let dst = i - l as usize;
7586 sa.copy_within(m as usize..m as usize + l as usize, dst);
7587 j = dst;
7588 }
7589 c -= 1;
7590 }
7591
7592 sa[..j].fill(0);
7593}
7594
7595fn place_lms_suffixes_interval_32s_2k(
7596 sa: &mut [SaSint],
7597 n: SaSint,
7598 k: SaSint,
7599 mut m: SaSint,
7600 buckets: &[SaSint],
7601) {
7602 let mut j = n as usize;
7603 if k > 1 {
7604 let mut c = buckets_index2(k as usize - 2, 0) as isize;
7605 while c >= buckets_index2(0, 0) as isize {
7606 let cu = c as usize;
7607 let l = buckets[cu + buckets_index2(1, 1)] - buckets[cu + buckets_index2(0, 1)];
7608 if l > 0 {
7609 let i = buckets[cu] as usize;
7610 if j > i {
7611 sa[i..j].fill(0);
7612 }
7613
7614 m -= l;
7615 let dst = i - l as usize;
7616 sa.copy_within(m as usize..m as usize + l as usize, dst);
7617 j = dst;
7618 }
7619 c -= buckets_index2(1, 0) as isize;
7620 }
7621 }
7622
7623 sa[..j].fill(0);
7624}
7625
7626fn place_lms_suffixes_interval_32s_1k(
7627 t: &[SaSint],
7628 sa: &mut [SaSint],
7629 k: SaSint,
7630 m: SaSint,
7631 buckets: &[SaSint],
7632) {
7633 let mut c = k - 1;
7634 let mut l = buckets[c as usize] as usize;
7635
7636 let mut i = m - 1;
7637 while i >= 0 {
7638 let p = sa[i as usize] as usize;
7639 if t[p] != c {
7640 c = t[p];
7641 let bucket_pos = buckets[c as usize] as usize;
7642 if l > bucket_pos {
7643 sa[bucket_pos..l].fill(0);
7644 }
7645 l = bucket_pos;
7646 }
7647 l -= 1;
7648 sa[l] = p as SaSint;
7649 i -= 1;
7650 }
7651
7652 sa[..l].fill(0);
7653}
7654
7655fn place_lms_suffixes_histogram_32s_6k(
7656 sa: &mut [SaSint],
7657 n: SaSint,
7658 k: SaSint,
7659 mut m: SaSint,
7660 buckets: &[SaSint],
7661) {
7662 let bucket_end = &buckets[5 * k as usize..6 * k as usize];
7663 let mut j = n as usize;
7664 let mut c = k - 2;
7665 while c >= 0 {
7666 let l = buckets[buckets_index4(c as usize, 1)] as usize;
7667 if l > 0 {
7668 let i = bucket_end[c as usize] as usize;
7669 if j > i {
7670 sa[i..j].fill(0);
7671 }
7672 let dst = i - l;
7673 m -= l as SaSint;
7674 sa.copy_within(m as usize..m as usize + l, dst);
7675 j = dst;
7676 }
7677 c -= 1;
7678 }
7679 sa[..j].fill(0);
7680}
7681
7682fn place_lms_suffixes_histogram_32s_4k(
7683 sa: &mut [SaSint],
7684 n: SaSint,
7685 k: SaSint,
7686 mut m: SaSint,
7687 buckets: &[SaSint],
7688) {
7689 let bucket_end = &buckets[3 * k as usize..4 * k as usize];
7690 let mut j = n as usize;
7691 let mut c = k - 2;
7692 while c >= 0 {
7693 let l = buckets[buckets_index2(c as usize, 1)] as usize;
7694 if l > 0 {
7695 let i = bucket_end[c as usize] as usize;
7696 if j > i {
7697 sa[i..j].fill(0);
7698 }
7699 let dst = i - l;
7700 m -= l as SaSint;
7701 sa.copy_within(m as usize..m as usize + l, dst);
7702 j = dst;
7703 }
7704 c -= 1;
7705 }
7706 sa[..j].fill(0);
7707}
7708
7709fn place_lms_suffixes_histogram_32s_2k(
7710 sa: &mut [SaSint],
7711 n: SaSint,
7712 k: SaSint,
7713 mut m: SaSint,
7714 buckets: &[SaSint],
7715) {
7716 let mut j = n as usize;
7717 if k > 1 {
7718 let mut c = buckets_index2(k as usize - 2, 0) as isize;
7719 while c >= buckets_index2(0, 0) as isize {
7720 let cu = c as usize;
7721 let l = buckets[cu + buckets_index2(0, 1)] as usize;
7722 if l > 0 {
7723 let i = buckets[cu] as usize;
7724 if j > i {
7725 sa[i..j].fill(0);
7726 }
7727 let dst = i - l;
7728 m -= l as SaSint;
7729 sa.copy_within(m as usize..m as usize + l, dst);
7730 j = dst;
7731 }
7732 c -= buckets_index2(1, 0) as isize;
7733 }
7734 }
7735 sa[..j].fill(0);
7736}
7737
7738fn final_bwt_scan_left_to_right_16u_block_prepare(
7739 t: &[u16],
7740 sa: &mut [SaSint],
7741 k: SaSint,
7742 buckets: &mut [SaSint],
7743 cache: &mut [ThreadCache],
7744 omp_block_start: SaSint,
7745 omp_block_size: SaSint,
7746) -> SaSint {
7747 buckets[..k as usize].fill(0);
7748 let mut count = 0usize;
7749 for i in omp_block_start as usize..(omp_block_start + omp_block_size) as usize {
7750 let mut p = sa[i];
7751 sa[i] = p & SAINT_MAX;
7752 if p > 0 {
7753 p -= 1;
7754 let c = t[p as usize] as usize;
7755 sa[i] = c as SaSint | SAINT_MIN;
7756 buckets[c] += 1;
7757 cache[count].symbol = c as SaSint;
7758 cache[count].index = p
7759 | ((usize::from(t[(p - SaSint::from(p > 0)) as usize] < t[p as usize]) as SaSint)
7760 << (SAINT_BIT - 1));
7761 count += 1;
7762 }
7763 }
7764 count as SaSint
7765}
7766
7767fn final_sorting_scan_left_to_right_16u_block_prepare(
7768 t: &[u16],
7769 sa: &mut [SaSint],
7770 k: SaSint,
7771 buckets: &mut [SaSint],
7772 cache: &mut [ThreadCache],
7773 omp_block_start: SaSint,
7774 omp_block_size: SaSint,
7775) -> SaSint {
7776 buckets[..k as usize].fill(0);
7777 let mut count = 0usize;
7778 for i in omp_block_start as usize..(omp_block_start + omp_block_size) as usize {
7779 let mut p = sa[i];
7780 sa[i] = p ^ SAINT_MIN;
7781 if p > 0 {
7782 p -= 1;
7783 let c = t[p as usize] as usize;
7784 buckets[c] += 1;
7785 cache[count].symbol = c as SaSint;
7786 cache[count].index = p
7787 | ((usize::from(t[(p - SaSint::from(p > 0)) as usize] < t[p as usize]) as SaSint)
7788 << (SAINT_BIT - 1));
7789 count += 1;
7790 }
7791 }
7792 count as SaSint
7793}
7794
7795fn final_order_scan_left_to_right_16u_block_place(
7796 sa: &mut [SaSint],
7797 buckets: &mut [SaSint],
7798 cache: &[ThreadCache],
7799 count: SaSint,
7800) {
7801 for entry in cache.iter().take(count as usize) {
7802 let c = entry.symbol as usize;
7803 let dst = buckets[c] as usize;
7804 sa[dst] = entry.index;
7805 buckets[c] += 1;
7806 }
7807}
7808
7809fn final_bwt_aux_scan_left_to_right_16u_block_place(
7810 sa: &mut [SaSint],
7811 rm: SaSint,
7812 i_sample: &mut [SaSint],
7813 buckets: &mut [SaSint],
7814 cache: &[ThreadCache],
7815 count: SaSint,
7816) {
7817 for entry in cache.iter().take(count as usize) {
7818 let c = entry.symbol as usize;
7819 let dst = buckets[c] as usize;
7820 sa[dst] = entry.index;
7821 buckets[c] += 1;
7822 let p = entry.index & SAINT_MAX;
7823 if (p & rm) == 0 {
7824 i_sample[(p / (rm + 1)) as usize] = buckets[c];
7825 }
7826 }
7827}
7828
7829fn final_bwt_scan_left_to_right_16u_block_omp(
7830 t: &[u16],
7831 sa: &mut [SaSint],
7832 k: SaSint,
7833 induction_bucket: &mut [SaSint],
7834 block_start: SaSint,
7835 block_size: SaSint,
7836 threads: SaSint,
7837 thread_state: &mut [ThreadState],
7838) {
7839 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
7840 usize::try_from(threads)
7841 .expect("threads must be non-negative")
7842 .min(thread_state.len())
7843 } else {
7844 1
7845 };
7846 if thread_count <= 1 {
7847 final_bwt_scan_left_to_right_16u(t, sa, induction_bucket, block_start, block_size);
7848 return;
7849 }
7850
7851 let k_usize = usize::try_from(k).expect("k must be non-negative");
7852 let block_stride = (block_size / thread_count as SaSint) & !15;
7853
7854 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
7855 let local_start = thread as SaSint * block_stride;
7856 let local_size = if thread + 1 < thread_count {
7857 block_stride
7858 } else {
7859 block_size - local_start
7860 };
7861 state.count = final_bwt_scan_left_to_right_16u_block_prepare(
7862 t,
7863 sa,
7864 k,
7865 &mut state.buckets[..k_usize],
7866 &mut state.cache,
7867 block_start + local_start,
7868 local_size,
7869 );
7870 }
7871
7872 for state in thread_state.iter_mut().take(thread_count) {
7873 for c in 0..k_usize {
7874 let a = induction_bucket[c];
7875 let b = state.buckets[c];
7876 induction_bucket[c] = a + b;
7877 state.buckets[c] = a;
7878 }
7879 }
7880
7881 for state in thread_state.iter_mut().take(thread_count) {
7882 final_order_scan_left_to_right_16u_block_place(
7883 sa,
7884 &mut state.buckets[..k_usize],
7885 &state.cache,
7886 state.count,
7887 );
7888 }
7889}
7890
7891fn final_bwt_aux_scan_left_to_right_16u_block_omp(
7892 t: &[u16],
7893 sa: &mut [SaSint],
7894 k: SaSint,
7895 rm: SaSint,
7896 i_sample: &mut [SaSint],
7897 induction_bucket: &mut [SaSint],
7898 block_start: SaSint,
7899 block_size: SaSint,
7900 threads: SaSint,
7901 thread_state: &mut [ThreadState],
7902) {
7903 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
7904 usize::try_from(threads)
7905 .expect("threads must be non-negative")
7906 .min(thread_state.len())
7907 } else {
7908 1
7909 };
7910 if thread_count <= 1 {
7911 final_bwt_aux_scan_left_to_right_16u(
7912 t,
7913 sa,
7914 rm,
7915 i_sample,
7916 induction_bucket,
7917 block_start,
7918 block_size,
7919 );
7920 return;
7921 }
7922
7923 let k_usize = usize::try_from(k).expect("k must be non-negative");
7924 let block_stride = (block_size / thread_count as SaSint) & !15;
7925
7926 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
7927 let local_start = thread as SaSint * block_stride;
7928 let local_size = if thread + 1 < thread_count {
7929 block_stride
7930 } else {
7931 block_size - local_start
7932 };
7933 state.count = final_bwt_scan_left_to_right_16u_block_prepare(
7934 t,
7935 sa,
7936 k,
7937 &mut state.buckets[..k_usize],
7938 &mut state.cache,
7939 block_start + local_start,
7940 local_size,
7941 );
7942 }
7943
7944 for state in thread_state.iter_mut().take(thread_count) {
7945 for c in 0..k_usize {
7946 let a = induction_bucket[c];
7947 let b = state.buckets[c];
7948 induction_bucket[c] = a + b;
7949 state.buckets[c] = a;
7950 }
7951 }
7952
7953 for state in thread_state.iter_mut().take(thread_count) {
7954 final_bwt_aux_scan_left_to_right_16u_block_place(
7955 sa,
7956 rm,
7957 i_sample,
7958 &mut state.buckets[..k_usize],
7959 &state.cache,
7960 state.count,
7961 );
7962 }
7963}
7964
7965fn final_sorting_scan_left_to_right_16u_block_omp(
7966 t: &[u16],
7967 sa: &mut [SaSint],
7968 k: SaSint,
7969 induction_bucket: &mut [SaSint],
7970 block_start: SaSint,
7971 block_size: SaSint,
7972 threads: SaSint,
7973 thread_state: &mut [ThreadState],
7974) {
7975 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
7976 usize::try_from(threads)
7977 .expect("threads must be non-negative")
7978 .min(thread_state.len())
7979 } else {
7980 1
7981 };
7982 if thread_count <= 1 {
7983 final_sorting_scan_left_to_right_16u(t, sa, induction_bucket, block_start, block_size);
7984 return;
7985 }
7986
7987 let k_usize = usize::try_from(k).expect("k must be non-negative");
7988 let block_stride = (block_size / thread_count as SaSint) & !15;
7989
7990 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
7991 let local_start = thread as SaSint * block_stride;
7992 let local_size = if thread + 1 < thread_count {
7993 block_stride
7994 } else {
7995 block_size - local_start
7996 };
7997 state.count = final_sorting_scan_left_to_right_16u_block_prepare(
7998 t,
7999 sa,
8000 k,
8001 &mut state.buckets[..k_usize],
8002 &mut state.cache,
8003 block_start + local_start,
8004 local_size,
8005 );
8006 }
8007
8008 for state in thread_state.iter_mut().take(thread_count) {
8009 for c in 0..k_usize {
8010 let a = induction_bucket[c];
8011 let b = state.buckets[c];
8012 induction_bucket[c] = a + b;
8013 state.buckets[c] = a;
8014 }
8015 }
8016
8017 for state in thread_state.iter_mut().take(thread_count) {
8018 final_order_scan_left_to_right_16u_block_place(
8019 sa,
8020 &mut state.buckets[..k_usize],
8021 &state.cache,
8022 state.count,
8023 );
8024 }
8025}
8026
8027fn final_bwt_scan_left_to_right_16u_omp(
8028 t: &[u16],
8029 sa: &mut [SaSint],
8030 n: SaSint,
8031 k: SaSint,
8032 induction_bucket: &mut [SaSint],
8033 threads: SaSint,
8034) {
8035 let c = t[(n - 1) as usize] as usize;
8036 let dst = induction_bucket[c] as usize;
8037 induction_bucket[c] += 1;
8038 let mark = if t[(n - 2) as usize] < t[(n - 1) as usize] {
8039 SAINT_MIN
8040 } else {
8041 0
8042 };
8043 sa[dst] = (n - 1) | mark;
8044
8045 if threads == 1 || n < 65536 {
8046 final_bwt_scan_left_to_right_16u(t, sa, induction_bucket, 0, n);
8047 } else {
8048 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8049 let mut block_start = 0;
8050 while block_start < n {
8051 if sa[block_start as usize] == 0 {
8052 block_start += 1;
8053 } else {
8054 let mut block_end =
8055 block_start + threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8056 if block_end > n {
8057 block_end = n;
8058 }
8059 let mut block_scan_end = block_start + 1;
8060 while block_scan_end < block_end && sa[block_scan_end as usize] != 0 {
8061 block_scan_end += 1;
8062 }
8063 let block_size = block_scan_end - block_start;
8064 if block_size < 32 {
8065 while block_start < block_scan_end {
8066 let mut p = sa[block_start as usize];
8067 sa[block_start as usize] = p & SAINT_MAX;
8068 if p > 0 {
8069 p -= 1;
8070 let c = t[p as usize] as usize;
8071 sa[block_start as usize] = c as SaSint | SAINT_MIN;
8072 let dst = induction_bucket[c] as usize;
8073 induction_bucket[c] += 1;
8074 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
8075 SAINT_MIN
8076 } else {
8077 0
8078 };
8079 sa[dst] = p | mark;
8080 }
8081 block_start += 1;
8082 }
8083 } else {
8084 final_bwt_scan_left_to_right_16u_block_omp(
8085 t,
8086 sa,
8087 k,
8088 induction_bucket,
8089 block_start,
8090 block_size,
8091 threads,
8092 &mut thread_state,
8093 );
8094 block_start = block_scan_end;
8095 }
8096 }
8097 }
8098 }
8099}
8100
8101fn final_bwt_aux_scan_left_to_right_16u_omp(
8102 t: &[u16],
8103 sa: &mut [SaSint],
8104 n: SaSint,
8105 k: SaSint,
8106 rm: SaSint,
8107 i_sample: &mut [SaSint],
8108 induction_bucket: &mut [SaSint],
8109 threads: SaSint,
8110) {
8111 let c = t[(n - 1) as usize] as usize;
8112 let dst = induction_bucket[c] as usize;
8113 induction_bucket[c] += 1;
8114 let mark = if t[(n - 2) as usize] < t[(n - 1) as usize] {
8115 SAINT_MIN
8116 } else {
8117 0
8118 };
8119 sa[dst] = (n - 1) | mark;
8120
8121 if ((n - 1) & rm) == 0 {
8122 i_sample[((n - 1) / (rm + 1)) as usize] = induction_bucket[c];
8123 }
8124
8125 if threads == 1 || n < 65536 {
8126 final_bwt_aux_scan_left_to_right_16u(t, sa, rm, i_sample, induction_bucket, 0, n);
8127 } else {
8128 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8129 let mut block_start = 0;
8130 while block_start < n {
8131 if sa[block_start as usize] == 0 {
8132 block_start += 1;
8133 } else {
8134 let mut block_end =
8135 block_start + threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8136 if block_end > n {
8137 block_end = n;
8138 }
8139 let mut block_scan_end = block_start + 1;
8140 while block_scan_end < block_end && sa[block_scan_end as usize] != 0 {
8141 block_scan_end += 1;
8142 }
8143 let block_size = block_scan_end - block_start;
8144 if block_size < 32 {
8145 while block_start < block_scan_end {
8146 let mut p = sa[block_start as usize];
8147 sa[block_start as usize] = p & SAINT_MAX;
8148 if p > 0 {
8149 p -= 1;
8150 let c = t[p as usize] as usize;
8151 sa[block_start as usize] = c as SaSint | SAINT_MIN;
8152 let dst = induction_bucket[c] as usize;
8153 induction_bucket[c] += 1;
8154 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
8155 SAINT_MIN
8156 } else {
8157 0
8158 };
8159 sa[dst] = p | mark;
8160 if (p & rm) == 0 {
8161 i_sample[(p / (rm + 1)) as usize] = induction_bucket[c];
8162 }
8163 }
8164 block_start += 1;
8165 }
8166 } else {
8167 final_bwt_aux_scan_left_to_right_16u_block_omp(
8168 t,
8169 sa,
8170 k,
8171 rm,
8172 i_sample,
8173 induction_bucket,
8174 block_start,
8175 block_size,
8176 threads,
8177 &mut thread_state,
8178 );
8179 block_start = block_scan_end;
8180 }
8181 }
8182 }
8183 }
8184}
8185
8186fn final_sorting_scan_left_to_right_16u_omp(
8187 t: &[u16],
8188 sa: &mut [SaSint],
8189 n: SaSint,
8190 k: SaSint,
8191 induction_bucket: &mut [SaSint],
8192 threads: SaSint,
8193) {
8194 let c = t[(n - 1) as usize] as usize;
8195 let dst = induction_bucket[c] as usize;
8196 induction_bucket[c] += 1;
8197 let mark = if t[(n - 2) as usize] < t[(n - 1) as usize] {
8198 SAINT_MIN
8199 } else {
8200 0
8201 };
8202 sa[dst] = (n - 1) | mark;
8203
8204 if threads == 1 || n < 65536 {
8205 final_sorting_scan_left_to_right_16u(t, sa, induction_bucket, 0, n);
8206 } else {
8207 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8208 let mut block_start = 0;
8209 while block_start < n {
8210 if sa[block_start as usize] == 0 {
8211 block_start += 1;
8212 } else {
8213 let mut block_end =
8214 block_start + threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8215 if block_end > n {
8216 block_end = n;
8217 }
8218 let mut block_scan_end = block_start + 1;
8219 while block_scan_end < block_end && sa[block_scan_end as usize] != 0 {
8220 block_scan_end += 1;
8221 }
8222 let block_size = block_scan_end - block_start;
8223 if block_size < 32 {
8224 while block_start < block_scan_end {
8225 let mut p = sa[block_start as usize];
8226 sa[block_start as usize] = p ^ SAINT_MIN;
8227 if p > 0 {
8228 p -= 1;
8229 let c = t[p as usize] as usize;
8230 let dst = induction_bucket[c] as usize;
8231 induction_bucket[c] += 1;
8232 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
8233 SAINT_MIN
8234 } else {
8235 0
8236 };
8237 sa[dst] = p | mark;
8238 }
8239 block_start += 1;
8240 }
8241 } else {
8242 final_sorting_scan_left_to_right_16u_block_omp(
8243 t,
8244 sa,
8245 k,
8246 induction_bucket,
8247 block_start,
8248 block_size,
8249 threads,
8250 &mut thread_state,
8251 );
8252 block_start = block_scan_end;
8253 }
8254 }
8255 }
8256 }
8257}
8258
8259fn final_bwt_scan_right_to_left_16u_block_prepare(
8260 t: &[u16],
8261 sa: &mut [SaSint],
8262 k: SaSint,
8263 buckets: &mut [SaSint],
8264 cache: &mut [ThreadCache],
8265 omp_block_start: SaSint,
8266 omp_block_size: SaSint,
8267) -> SaSint {
8268 buckets[..k as usize].fill(0);
8269 let mut count = 0usize;
8270 for i in (omp_block_start as usize..(omp_block_start + omp_block_size) as usize).rev() {
8271 let mut p = sa[i];
8272 sa[i] = p & SAINT_MAX;
8273 if p > 0 {
8274 p -= 1;
8275 let c0 = t[(p - SaSint::from(p > 0)) as usize];
8276 let c1 = t[p as usize];
8277 sa[i] = c1 as SaSint;
8278 buckets[c1 as usize] += 1;
8279 cache[count].symbol = c1 as SaSint;
8280 cache[count].index = if c0 <= c1 {
8281 p
8282 } else {
8283 c0 as SaSint | SAINT_MIN
8284 };
8285 count += 1;
8286 }
8287 }
8288 count as SaSint
8289}
8290
8291fn final_bwt_aux_scan_right_to_left_16u_block_prepare(
8292 t: &[u16],
8293 sa: &mut [SaSint],
8294 k: SaSint,
8295 buckets: &mut [SaSint],
8296 cache: &mut [ThreadCache],
8297 omp_block_start: SaSint,
8298 omp_block_size: SaSint,
8299) -> SaSint {
8300 buckets[..k as usize].fill(0);
8301 let mut count = 0usize;
8302 for i in (omp_block_start as usize..(omp_block_start + omp_block_size) as usize).rev() {
8303 let mut p = sa[i];
8304 sa[i] = p & SAINT_MAX;
8305 if p > 0 {
8306 p -= 1;
8307 let c0 = t[(p - SaSint::from(p > 0)) as usize];
8308 let c1 = t[p as usize];
8309 sa[i] = c1 as SaSint;
8310 buckets[c1 as usize] += 1;
8311 cache[count].symbol = c1 as SaSint;
8312 cache[count].index = if c0 <= c1 {
8313 p
8314 } else {
8315 c0 as SaSint | SAINT_MIN
8316 };
8317 cache[count + 1].index = p;
8318 count += 2;
8319 }
8320 }
8321 count as SaSint
8322}
8323
8324fn final_sorting_scan_right_to_left_16u_block_prepare(
8325 t: &[u16],
8326 sa: &mut [SaSint],
8327 k: SaSint,
8328 buckets: &mut [SaSint],
8329 cache: &mut [ThreadCache],
8330 omp_block_start: SaSint,
8331 omp_block_size: SaSint,
8332) -> SaSint {
8333 buckets[..k as usize].fill(0);
8334 let mut count = 0usize;
8335 for i in (omp_block_start as usize..(omp_block_start + omp_block_size) as usize).rev() {
8336 let mut p = sa[i];
8337 sa[i] = p & SAINT_MAX;
8338 if p > 0 {
8339 p -= 1;
8340 let c = t[p as usize] as usize;
8341 buckets[c] += 1;
8342 cache[count].symbol = c as SaSint;
8343 cache[count].index = p
8344 | ((usize::from(t[(p - SaSint::from(p > 0)) as usize] > t[p as usize]) as SaSint)
8345 << (SAINT_BIT - 1));
8346 count += 1;
8347 }
8348 }
8349 count as SaSint
8350}
8351
8352fn final_order_scan_right_to_left_16u_block_place(
8353 sa: &mut [SaSint],
8354 buckets: &mut [SaSint],
8355 cache: &[ThreadCache],
8356 count: SaSint,
8357) {
8358 for entry in cache.iter().take(count as usize) {
8359 let c = entry.symbol as usize;
8360 buckets[c] -= 1;
8361 sa[buckets[c] as usize] = entry.index;
8362 }
8363}
8364
8365fn final_gsa_scan_right_to_left_16u_block_place(
8366 sa: &mut [SaSint],
8367 buckets: &mut [SaSint],
8368 cache: &[ThreadCache],
8369 count: SaSint,
8370) {
8371 for entry in cache.iter().take(count as usize) {
8372 let c = entry.symbol as usize;
8373 if c > 0 {
8374 buckets[c] -= 1;
8375 sa[buckets[c] as usize] = entry.index;
8376 }
8377 }
8378}
8379
8380fn final_bwt_aux_scan_right_to_left_16u_block_place(
8381 sa: &mut [SaSint],
8382 rm: SaSint,
8383 i_sample: &mut [SaSint],
8384 buckets: &mut [SaSint],
8385 cache: &[ThreadCache],
8386 count: SaSint,
8387) {
8388 let mut i = 0usize;
8389 while i < count as usize {
8390 let c = cache[i].symbol as usize;
8391 buckets[c] -= 1;
8392 sa[buckets[c] as usize] = cache[i].index;
8393 let p = cache[i + 1].index;
8394 if (p & rm) == 0 {
8395 i_sample[(p / (rm + 1)) as usize] = buckets[c] + 1;
8396 }
8397 i += 2;
8398 }
8399}
8400
8401fn final_bwt_scan_right_to_left_16u_block_omp(
8402 t: &[u16],
8403 sa: &mut [SaSint],
8404 k: SaSint,
8405 induction_bucket: &mut [SaSint],
8406 block_start: SaSint,
8407 block_size: SaSint,
8408 threads: SaSint,
8409 thread_state: &mut [ThreadState],
8410) -> SaSint {
8411 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
8412 usize::try_from(threads)
8413 .expect("threads must be non-negative")
8414 .min(thread_state.len())
8415 } else {
8416 1
8417 };
8418 if thread_count <= 1 {
8419 return final_bwt_scan_right_to_left_16u(t, sa, induction_bucket, block_start, block_size);
8420 }
8421
8422 let k_usize = usize::try_from(k).expect("k must be non-negative");
8423 let block_stride = (block_size / thread_count as SaSint) & !15;
8424
8425 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
8426 let local_start = thread as SaSint * block_stride;
8427 let local_size = if thread + 1 < thread_count {
8428 block_stride
8429 } else {
8430 block_size - local_start
8431 };
8432 state.count = final_bwt_scan_right_to_left_16u_block_prepare(
8433 t,
8434 sa,
8435 k,
8436 &mut state.buckets[..k_usize],
8437 &mut state.cache,
8438 block_start + local_start,
8439 local_size,
8440 );
8441 }
8442
8443 for state in thread_state.iter_mut().take(thread_count).rev() {
8444 for c in 0..k_usize {
8445 let a = induction_bucket[c];
8446 let b = state.buckets[c];
8447 induction_bucket[c] = a - b;
8448 state.buckets[c] = a;
8449 }
8450 }
8451
8452 for state in thread_state.iter_mut().take(thread_count) {
8453 final_order_scan_right_to_left_16u_block_place(
8454 sa,
8455 &mut state.buckets[..k_usize],
8456 &state.cache,
8457 state.count,
8458 );
8459 }
8460
8461 -1
8462}
8463
8464fn final_bwt_aux_scan_right_to_left_16u_block_omp(
8465 t: &[u16],
8466 sa: &mut [SaSint],
8467 k: SaSint,
8468 rm: SaSint,
8469 i_sample: &mut [SaSint],
8470 induction_bucket: &mut [SaSint],
8471 block_start: SaSint,
8472 block_size: SaSint,
8473 threads: SaSint,
8474 thread_state: &mut [ThreadState],
8475) {
8476 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
8477 usize::try_from(threads)
8478 .expect("threads must be non-negative")
8479 .min(thread_state.len())
8480 } else {
8481 1
8482 };
8483 if thread_count <= 1 {
8484 final_bwt_aux_scan_right_to_left_16u(
8485 t,
8486 sa,
8487 rm,
8488 i_sample,
8489 induction_bucket,
8490 block_start,
8491 block_size,
8492 );
8493 return;
8494 }
8495
8496 let k_usize = usize::try_from(k).expect("k must be non-negative");
8497 let block_stride = (block_size / thread_count as SaSint) & !15;
8498
8499 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
8500 let local_start = thread as SaSint * block_stride;
8501 let local_size = if thread + 1 < thread_count {
8502 block_stride
8503 } else {
8504 block_size - local_start
8505 };
8506 state.count = final_bwt_aux_scan_right_to_left_16u_block_prepare(
8507 t,
8508 sa,
8509 k,
8510 &mut state.buckets[..k_usize],
8511 &mut state.cache,
8512 block_start + local_start,
8513 local_size,
8514 );
8515 }
8516
8517 for state in thread_state.iter_mut().take(thread_count).rev() {
8518 for c in 0..k_usize {
8519 let a = induction_bucket[c];
8520 let b = state.buckets[c];
8521 induction_bucket[c] = a - b;
8522 state.buckets[c] = a;
8523 }
8524 }
8525
8526 for state in thread_state.iter_mut().take(thread_count) {
8527 final_bwt_aux_scan_right_to_left_16u_block_place(
8528 sa,
8529 rm,
8530 i_sample,
8531 &mut state.buckets[..k_usize],
8532 &state.cache,
8533 state.count,
8534 );
8535 }
8536}
8537
8538fn final_sorting_scan_right_to_left_16u_block_omp(
8539 t: &[u16],
8540 sa: &mut [SaSint],
8541 k: SaSint,
8542 induction_bucket: &mut [SaSint],
8543 block_start: SaSint,
8544 block_size: SaSint,
8545 threads: SaSint,
8546 thread_state: &mut [ThreadState],
8547) {
8548 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
8549 usize::try_from(threads)
8550 .expect("threads must be non-negative")
8551 .min(thread_state.len())
8552 } else {
8553 1
8554 };
8555 if thread_count <= 1 {
8556 final_sorting_scan_right_to_left_16u(t, sa, induction_bucket, block_start, block_size);
8557 return;
8558 }
8559
8560 let k_usize = usize::try_from(k).expect("k must be non-negative");
8561 let block_stride = (block_size / thread_count as SaSint) & !15;
8562
8563 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
8564 let local_start = thread as SaSint * block_stride;
8565 let local_size = if thread + 1 < thread_count {
8566 block_stride
8567 } else {
8568 block_size - local_start
8569 };
8570 state.count = final_sorting_scan_right_to_left_16u_block_prepare(
8571 t,
8572 sa,
8573 k,
8574 &mut state.buckets[..k_usize],
8575 &mut state.cache,
8576 block_start + local_start,
8577 local_size,
8578 );
8579 }
8580
8581 for state in thread_state.iter_mut().take(thread_count).rev() {
8582 for c in 0..k_usize {
8583 let a = induction_bucket[c];
8584 let b = state.buckets[c];
8585 induction_bucket[c] = a - b;
8586 state.buckets[c] = a;
8587 }
8588 }
8589
8590 for state in thread_state.iter_mut().take(thread_count) {
8591 final_order_scan_right_to_left_16u_block_place(
8592 sa,
8593 &mut state.buckets[..k_usize],
8594 &state.cache,
8595 state.count,
8596 );
8597 }
8598}
8599
8600fn final_gsa_scan_right_to_left_16u_block_omp(
8601 t: &[u16],
8602 sa: &mut [SaSint],
8603 k: SaSint,
8604 induction_bucket: &mut [SaSint],
8605 block_start: SaSint,
8606 block_size: SaSint,
8607 threads: SaSint,
8608 thread_state: &mut [ThreadState],
8609) {
8610 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
8611 usize::try_from(threads)
8612 .expect("threads must be non-negative")
8613 .min(thread_state.len())
8614 } else {
8615 1
8616 };
8617 if thread_count <= 1 {
8618 final_gsa_scan_right_to_left_16u(t, sa, induction_bucket, block_start, block_size);
8619 return;
8620 }
8621
8622 let k_usize = usize::try_from(k).expect("k must be non-negative");
8623 let block_stride = (block_size / thread_count as SaSint) & !15;
8624
8625 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
8626 let local_start = thread as SaSint * block_stride;
8627 let local_size = if thread + 1 < thread_count {
8628 block_stride
8629 } else {
8630 block_size - local_start
8631 };
8632 state.count = final_sorting_scan_right_to_left_16u_block_prepare(
8633 t,
8634 sa,
8635 k,
8636 &mut state.buckets[..k_usize],
8637 &mut state.cache,
8638 block_start + local_start,
8639 local_size,
8640 );
8641 }
8642
8643 for state in thread_state.iter_mut().take(thread_count).rev() {
8644 for c in 0..k_usize {
8645 let a = induction_bucket[c];
8646 let b = state.buckets[c];
8647 induction_bucket[c] = a - b;
8648 state.buckets[c] = a;
8649 }
8650 }
8651
8652 for state in thread_state.iter_mut().take(thread_count) {
8653 final_gsa_scan_right_to_left_16u_block_place(
8654 sa,
8655 &mut state.buckets[..k_usize],
8656 &state.cache,
8657 state.count,
8658 );
8659 }
8660}
8661
8662fn final_bwt_scan_right_to_left_16u_omp(
8663 t: &[u16],
8664 sa: &mut [SaSint],
8665 n: SaSint,
8666 k: SaSint,
8667 induction_bucket: &mut [SaSint],
8668 threads: SaSint,
8669) -> SaSint {
8670 let mut index = -1;
8671
8672 if threads == 1 || n < 65536 {
8673 index = final_bwt_scan_right_to_left_16u(t, sa, induction_bucket, 0, n);
8674 } else {
8675 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8676 let mut block_start = n - 1;
8677 while block_start >= 0 {
8678 if sa[block_start as usize] == 0 {
8679 index = block_start;
8680 block_start -= 1;
8681 } else {
8682 let mut block_max_end =
8683 block_start - threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8684 if block_max_end < 0 {
8685 block_max_end = -1;
8686 }
8687 let mut block_end = block_start - 1;
8688 while block_end > block_max_end && sa[block_end as usize] != 0 {
8689 block_end -= 1;
8690 }
8691 let block_size = block_start - block_end;
8692 if block_size < 32 {
8693 while block_start > block_end {
8694 let mut p = sa[block_start as usize];
8695 sa[block_start as usize] = p & SAINT_MAX;
8696 if p > 0 {
8697 p -= 1;
8698 let c0 = t[(p - SaSint::from(p > 0)) as usize];
8699 let c1 = t[p as usize] as usize;
8700 sa[block_start as usize] = c1 as SaSint;
8701 induction_bucket[c1] -= 1;
8702 sa[induction_bucket[c1] as usize] = if c0 <= c1 as u16 {
8703 p
8704 } else {
8705 c0 as SaSint | SAINT_MIN
8706 };
8707 }
8708 block_start -= 1;
8709 }
8710 } else {
8711 final_bwt_scan_right_to_left_16u_block_omp(
8712 t,
8713 sa,
8714 k,
8715 induction_bucket,
8716 block_end + 1,
8717 block_size,
8718 threads,
8719 &mut thread_state,
8720 );
8721 block_start = block_end;
8722 }
8723 }
8724 }
8725 }
8726 index
8727}
8728
8729fn final_bwt_aux_scan_right_to_left_16u_omp(
8730 t: &[u16],
8731 sa: &mut [SaSint],
8732 n: SaSint,
8733 k: SaSint,
8734 rm: SaSint,
8735 i_sample: &mut [SaSint],
8736 induction_bucket: &mut [SaSint],
8737 threads: SaSint,
8738) {
8739 if threads == 1 || n < 65536 {
8740 final_bwt_aux_scan_right_to_left_16u(t, sa, rm, i_sample, induction_bucket, 0, n);
8741 } else {
8742 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8743 let mut block_start = n - 1;
8744 while block_start >= 0 {
8745 if sa[block_start as usize] == 0 {
8746 block_start -= 1;
8747 } else {
8748 let mut block_max_end =
8749 block_start - threads * ((PER_THREAD_CACHE_SIZE as SaSint - 16 * threads) / 2);
8750 if block_max_end < 0 {
8751 block_max_end = -1;
8752 }
8753 let mut block_end = block_start - 1;
8754 while block_end > block_max_end && sa[block_end as usize] != 0 {
8755 block_end -= 1;
8756 }
8757 let block_size = block_start - block_end;
8758 if block_size < 32 {
8759 while block_start > block_end {
8760 let mut p = sa[block_start as usize];
8761 sa[block_start as usize] = p & SAINT_MAX;
8762 if p > 0 {
8763 p -= 1;
8764 let c0 = t[(p - SaSint::from(p > 0)) as usize];
8765 let c1 = t[p as usize] as usize;
8766 sa[block_start as usize] = c1 as SaSint;
8767 induction_bucket[c1] -= 1;
8768 sa[induction_bucket[c1] as usize] = if c0 <= c1 as u16 {
8769 p
8770 } else {
8771 c0 as SaSint | SAINT_MIN
8772 };
8773 if (p & rm) == 0 {
8774 i_sample[(p / (rm + 1)) as usize] = induction_bucket[c1] + 1;
8775 }
8776 }
8777 block_start -= 1;
8778 }
8779 } else {
8780 final_bwt_aux_scan_right_to_left_16u_block_omp(
8781 t,
8782 sa,
8783 k,
8784 rm,
8785 i_sample,
8786 induction_bucket,
8787 block_end + 1,
8788 block_size,
8789 threads,
8790 &mut thread_state,
8791 );
8792 block_start = block_end;
8793 }
8794 }
8795 }
8796 }
8797}
8798
8799fn final_sorting_scan_right_to_left_16u_omp(
8800 t: &[u16],
8801 sa: &mut [SaSint],
8802 omp_block_start: SaSint,
8803 omp_block_size: SaSint,
8804 k: SaSint,
8805 induction_bucket: &mut [SaSint],
8806 threads: SaSint,
8807) {
8808 if threads == 1 || omp_block_size < 65536 {
8809 final_sorting_scan_right_to_left_16u(
8810 t,
8811 sa,
8812 induction_bucket,
8813 omp_block_start,
8814 omp_block_size,
8815 );
8816 } else {
8817 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8818 let mut block_start = omp_block_start + omp_block_size - 1;
8819 while block_start >= omp_block_start {
8820 if sa[block_start as usize] == 0 {
8821 block_start -= 1;
8822 } else {
8823 let mut block_max_end =
8824 block_start - threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8825 if block_max_end < omp_block_start {
8826 block_max_end = omp_block_start - 1;
8827 }
8828 let mut block_end = block_start - 1;
8829 while block_end > block_max_end && sa[block_end as usize] != 0 {
8830 block_end -= 1;
8831 }
8832 let block_size = block_start - block_end;
8833 if block_size < 32 {
8834 while block_start > block_end {
8835 let mut p = sa[block_start as usize];
8836 sa[block_start as usize] = p & SAINT_MAX;
8837 if p > 0 {
8838 p -= 1;
8839 let c = t[p as usize] as usize;
8840 induction_bucket[c] -= 1;
8841 let mark = if t[(p - SaSint::from(p > 0)) as usize] > t[p as usize] {
8842 SAINT_MIN
8843 } else {
8844 0
8845 };
8846 sa[induction_bucket[c] as usize] = p | mark;
8847 }
8848 block_start -= 1;
8849 }
8850 } else {
8851 final_sorting_scan_right_to_left_16u_block_omp(
8852 t,
8853 sa,
8854 k,
8855 induction_bucket,
8856 block_end + 1,
8857 block_size,
8858 threads,
8859 &mut thread_state,
8860 );
8861 block_start = block_end;
8862 }
8863 }
8864 }
8865 }
8866}
8867
8868fn final_gsa_scan_right_to_left_16u_omp(
8869 t: &[u16],
8870 sa: &mut [SaSint],
8871 omp_block_start: SaSint,
8872 omp_block_size: SaSint,
8873 k: SaSint,
8874 induction_bucket: &mut [SaSint],
8875 threads: SaSint,
8876) {
8877 if threads == 1 || omp_block_size < 65536 {
8878 final_gsa_scan_right_to_left_16u(t, sa, induction_bucket, omp_block_start, omp_block_size);
8879 } else {
8880 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8881 let mut block_start = omp_block_start + omp_block_size - 1;
8882 while block_start >= omp_block_start {
8883 if sa[block_start as usize] == 0 {
8884 block_start -= 1;
8885 } else {
8886 let mut block_max_end =
8887 block_start - threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8888 if block_max_end < omp_block_start {
8889 block_max_end = omp_block_start - 1;
8890 }
8891 let mut block_end = block_start - 1;
8892 while block_end > block_max_end && sa[block_end as usize] != 0 {
8893 block_end -= 1;
8894 }
8895 let block_size = block_start - block_end;
8896 if block_size < 32 {
8897 while block_start > block_end {
8898 let mut p = sa[block_start as usize];
8899 sa[block_start as usize] = p & SAINT_MAX;
8900 if p > 0 && t[(p - 1) as usize] > 0 {
8901 p -= 1;
8902 let c = t[p as usize] as usize;
8903 induction_bucket[c] -= 1;
8904 let mark = if t[(p - SaSint::from(p > 0)) as usize] > t[p as usize] {
8905 SAINT_MIN
8906 } else {
8907 0
8908 };
8909 sa[induction_bucket[c] as usize] = p | mark;
8910 }
8911 block_start -= 1;
8912 }
8913 } else {
8914 final_gsa_scan_right_to_left_16u_block_omp(
8915 t,
8916 sa,
8917 k,
8918 induction_bucket,
8919 block_end + 1,
8920 block_size,
8921 threads,
8922 &mut thread_state,
8923 );
8924 block_start = block_end;
8925 }
8926 }
8927 }
8928 }
8929}
8930
8931fn induce_final_order_16u_omp(
8932 t: &[u16],
8933 sa: &mut [SaSint],
8934 n: SaSint,
8935 k: SaSint,
8936 flags: SaSint,
8937 r: SaSint,
8938 i_out: Option<&mut [SaSint]>,
8939 buckets: &mut [SaSint],
8940 threads: SaSint,
8941 _thread_state: &mut [ThreadState],
8942) -> SaSint {
8943 if (flags & LIBSAIS_FLAGS_BWT) == 0 {
8944 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
8945 buckets[6 * ALPHABET_SIZE] = buckets[7 * ALPHABET_SIZE] - 1;
8946 }
8947
8948 let (left_buckets, right_tail) = buckets.split_at_mut(7 * ALPHABET_SIZE);
8949 let bucket_start = &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE];
8950 let bucket_end = &mut right_tail[..ALPHABET_SIZE];
8951
8952 final_sorting_scan_left_to_right_16u_omp(t, sa, n, k, bucket_start, threads);
8953 if threads > 1 && n >= 65_536 {
8954 clear_lms_suffixes_omp(
8955 sa,
8956 n,
8957 ALPHABET_SIZE as SaSint,
8958 bucket_start,
8959 bucket_end,
8960 threads,
8961 );
8962 }
8963
8964 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
8965 flip_suffix_markers_omp(sa, bucket_end[0], threads);
8966 final_gsa_scan_right_to_left_16u_omp(
8967 t,
8968 sa,
8969 bucket_end[0],
8970 n - bucket_end[0],
8971 k,
8972 bucket_end,
8973 threads,
8974 );
8975 } else {
8976 final_sorting_scan_right_to_left_16u_omp(t, sa, 0, n, k, bucket_end, threads);
8977 }
8978
8979 0
8980 } else if let Some(i_out) = i_out {
8981 let (left_buckets, right_tail) = buckets.split_at_mut(7 * ALPHABET_SIZE);
8982 let bucket_start = &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE];
8983 let bucket_end = &mut right_tail[..ALPHABET_SIZE];
8984
8985 final_bwt_aux_scan_left_to_right_16u_omp(t, sa, n, k, r - 1, i_out, bucket_start, threads);
8986 if threads > 1 && n >= 65_536 {
8987 clear_lms_suffixes_omp(
8988 sa,
8989 n,
8990 ALPHABET_SIZE as SaSint,
8991 bucket_start,
8992 bucket_end,
8993 threads,
8994 );
8995 }
8996 final_bwt_aux_scan_right_to_left_16u_omp(t, sa, n, k, r - 1, i_out, bucket_end, threads);
8997 0
8998 } else {
8999 let (left_buckets, right_tail) = buckets.split_at_mut(7 * ALPHABET_SIZE);
9000 let bucket_start = &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE];
9001 let bucket_end = &mut right_tail[..ALPHABET_SIZE];
9002
9003 final_bwt_scan_left_to_right_16u_omp(t, sa, n, k, bucket_start, threads);
9004 if threads > 1 && n >= 65_536 {
9005 clear_lms_suffixes_omp(
9006 sa,
9007 n,
9008 ALPHABET_SIZE as SaSint,
9009 bucket_start,
9010 bucket_end,
9011 threads,
9012 );
9013 }
9014 final_bwt_scan_right_to_left_16u_omp(t, sa, n, k, bucket_end, threads)
9015 }
9016}
9017
9018fn bwt_copy_16u(u: &mut [u16], a: &[SaSint], n: SaSint) {
9019 let mut i = 0isize;
9020 let mut j = n as isize - 7;
9021 while i < j {
9022 u[i as usize] = a[i as usize] as u16;
9023 u[(i + 1) as usize] = a[(i + 1) as usize] as u16;
9024 u[(i + 2) as usize] = a[(i + 2) as usize] as u16;
9025 u[(i + 3) as usize] = a[(i + 3) as usize] as u16;
9026 u[(i + 4) as usize] = a[(i + 4) as usize] as u16;
9027 u[(i + 5) as usize] = a[(i + 5) as usize] as u16;
9028 u[(i + 6) as usize] = a[(i + 6) as usize] as u16;
9029 u[(i + 7) as usize] = a[(i + 7) as usize] as u16;
9030 i += 8;
9031 }
9032
9033 j += 7;
9034 while i < j {
9035 u[i as usize] = a[i as usize] as u16;
9036 i += 1;
9037 }
9038}
9039
9040#[allow(dead_code)]
9041fn bwt_copy_16u_omp(u: &mut [u16], a: &[SaSint], n: SaSint, threads: SaSint) {
9042 if threads == 1 || n < 65_536 {
9043 bwt_copy_16u(u, a, n);
9044 return;
9045 }
9046
9047 let block_stride = (n / threads) & !15;
9048 for thread in 0..threads {
9049 let block_start = thread * block_stride;
9050 let block_size = if thread < threads - 1 {
9051 block_stride
9052 } else {
9053 n - block_start
9054 };
9055 let start = block_start as usize;
9056 bwt_copy_16u(&mut u[start..], &a[start..], block_size);
9057 }
9058}
9059
9060fn final_bwt_ltr_step(t: &[u16], sa: &mut [SaSint], induction_bucket: &mut [SaSint], index: usize) {
9061 let mut p = sa[index];
9062 sa[index] = p & SAINT_MAX;
9063 if p > 0 {
9064 p -= 1;
9065 let c = t[p as usize] as usize;
9066 sa[index] = t[p as usize] as SaSint | SAINT_MIN;
9067 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
9068 SAINT_MIN
9069 } else {
9070 0
9071 };
9072 let dst = induction_bucket[c] as usize;
9073 sa[dst] = p | mark;
9074 induction_bucket[c] += 1;
9075 }
9076}
9077
9078fn final_bwt_rtl_step(
9079 t: &[u16],
9080 sa: &mut [SaSint],
9081 induction_bucket: &mut [SaSint],
9082 index: usize,
9083 primary_index: &mut SaSint,
9084) {
9085 let mut p = sa[index];
9086 if p == 0 {
9087 *primary_index = index as SaSint;
9088 }
9089 sa[index] = p & SAINT_MAX;
9090 if p > 0 {
9091 p -= 1;
9092 let c0 = t[(p - SaSint::from(p > 0)) as usize];
9093 let c1 = t[p as usize];
9094 sa[index] = c1 as SaSint;
9095 let induced = if c0 <= c1 {
9096 p
9097 } else {
9098 c0 as SaSint | SAINT_MIN
9099 };
9100 induction_bucket[c1 as usize] -= 1;
9101 sa[induction_bucket[c1 as usize] as usize] = induced;
9102 }
9103}
9104
9105fn final_bwt_aux_ltr_step(
9106 t: &[u16],
9107 sa: &mut [SaSint],
9108 rm: SaSint,
9109 i_sample: &mut [SaSint],
9110 induction_bucket: &mut [SaSint],
9111 index: usize,
9112) {
9113 let mut p = sa[index];
9114 sa[index] = p & SAINT_MAX;
9115 if p > 0 {
9116 p -= 1;
9117 let c = t[p as usize] as usize;
9118 sa[index] = t[p as usize] as SaSint | SAINT_MIN;
9119 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
9120 SAINT_MIN
9121 } else {
9122 0
9123 };
9124 let dst = induction_bucket[c] as usize;
9125 sa[dst] = p | mark;
9126 induction_bucket[c] += 1;
9127 if (p & rm) == 0 {
9128 i_sample[(p / (rm + 1)) as usize] = induction_bucket[c];
9129 }
9130 }
9131}
9132
9133fn final_bwt_aux_rtl_step(
9134 t: &[u16],
9135 sa: &mut [SaSint],
9136 rm: SaSint,
9137 i_sample: &mut [SaSint],
9138 induction_bucket: &mut [SaSint],
9139 index: usize,
9140) {
9141 let mut p = sa[index];
9142 sa[index] = p & SAINT_MAX;
9143 if p > 0 {
9144 p -= 1;
9145 let c0 = t[(p - SaSint::from(p > 0)) as usize];
9146 let c1 = t[p as usize];
9147 sa[index] = c1 as SaSint;
9148 let induced = if c0 <= c1 {
9149 p
9150 } else {
9151 c0 as SaSint | SAINT_MIN
9152 };
9153 induction_bucket[c1 as usize] -= 1;
9154 sa[induction_bucket[c1 as usize] as usize] = induced;
9155 if (p & rm) == 0 {
9156 i_sample[(p / (rm + 1)) as usize] = induction_bucket[c1 as usize] + 1;
9157 }
9158 }
9159}
9160
9161fn main_32s_recursion(
9162 t_ptr: *mut SaSint,
9163 sa_ptr: *mut SaSint,
9164 sa_capacity: usize,
9165 n: SaSint,
9166 k: SaSint,
9167 fs: SaSint,
9168 threads: SaSint,
9169 thread_state: &mut [ThreadState],
9170 local_buffer: &mut [SaSint],
9171) -> SaSint {
9172 let fs = fs.min(SAINT_MAX - n);
9173 let local_buffer_size = SaSint::try_from(LIBSAIS_LOCAL_BUFFER_SIZE).expect("fits");
9174 let n_usize = usize::try_from(n).expect("n must be non-negative");
9175 let fs_usize = usize::try_from(fs).expect("fs must be non-negative");
9176 let total_len = n_usize + fs_usize;
9177 assert!(total_len <= sa_capacity);
9178
9179 if k > 0 && ((fs / k) >= 6 || (local_buffer_size / k) >= 6) {
9180 let k_usize = usize::try_from(k).expect("k must be non-negative");
9181 let alignment = if fs >= 1024 && ((fs - 1024) / k) >= 6 {
9182 1024usize
9183 } else {
9184 16usize
9185 };
9186 let need = 6 * k_usize;
9187 let use_local_buffer = local_buffer_size > fs;
9188 let buckets_ptr = if use_local_buffer {
9189 local_buffer.as_mut_ptr()
9190 } else {
9191 unsafe {
9192 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9193 let start =
9194 if fs_usize >= need + alignment && ((fs_usize - alignment) / k_usize) >= 6 {
9195 let byte_ptr = sa[total_len - need - alignment..].as_mut_ptr() as usize;
9196 let aligned = align_up(byte_ptr, alignment * mem::size_of::<SaSint>());
9197 (aligned - sa_ptr as usize) / mem::size_of::<SaSint>()
9198 } else {
9199 total_len - need
9200 };
9201 sa[start..].as_mut_ptr()
9202 }
9203 };
9204
9205 let m = unsafe {
9206 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9207 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9208 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9209 count_and_gather_lms_suffixes_32s_4k_omp(
9210 t,
9211 sa,
9212 n,
9213 k,
9214 buckets,
9215 SaSint::from(use_local_buffer),
9216 threads,
9217 thread_state,
9218 )
9219 };
9220 if m > 1 {
9221 let m_usize = usize::try_from(m).expect("m must be non-negative");
9222 unsafe {
9223 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9224 sa[..n_usize - m_usize].fill(0);
9225 }
9226
9227 let first_lms_suffix = unsafe {
9228 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9229 sa[n_usize - m_usize]
9230 };
9231 let left_suffixes_count = unsafe {
9232 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9233 initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(
9234 std::slice::from_raw_parts(t_ptr, n_usize),
9235 k,
9236 buckets,
9237 first_lms_suffix,
9238 )
9239 };
9240
9241 unsafe {
9242 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9243 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9244 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9245 let (_, induction_bucket) = buckets.split_at_mut(4 * k_usize);
9246 radix_sort_lms_suffixes_32s_6k_omp(t, sa, n, m, induction_bucket, threads);
9247 if (n / 8192) < k {
9248 radix_sort_set_markers_32s_6k_omp(sa, k, induction_bucket, threads);
9249 }
9250 if threads > 1 && n >= 65_536 {
9251 sa[n_usize - m_usize..n_usize].fill(0);
9252 }
9253 initialize_buckets_for_partial_sorting_32s_6k(
9254 t,
9255 k,
9256 buckets,
9257 first_lms_suffix,
9258 left_suffixes_count,
9259 );
9260 induce_partial_order_32s_6k_omp(
9261 t,
9262 sa,
9263 n,
9264 k,
9265 buckets,
9266 first_lms_suffix,
9267 left_suffixes_count,
9268 threads,
9269 thread_state,
9270 );
9271 }
9272
9273 let names = unsafe {
9274 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9275 if (n / 8192) < k {
9276 renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(
9277 sa,
9278 n,
9279 m,
9280 threads,
9281 thread_state,
9282 )
9283 } else {
9284 renumber_and_gather_lms_suffixes_omp(sa, n, m, fs, threads, thread_state)
9285 }
9286 };
9287
9288 if names < m {
9289 let f = if (n / 8192) < k {
9290 unsafe {
9291 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9292 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9293 compact_lms_suffixes_32s_omp(t, sa, n, m, fs, threads)
9294 }
9295 } else {
9296 0
9297 };
9298
9299 let new_t_start =
9300 total_len - usize::try_from(m - f).expect("m - f must be non-negative");
9301 if main_32s_recursion(
9302 unsafe {
9303 std::slice::from_raw_parts_mut(sa_ptr, total_len)[new_t_start..]
9304 .as_mut_ptr()
9305 },
9306 sa_ptr,
9307 sa_capacity,
9308 m - f,
9309 names - f,
9310 fs + n - 2 * m + f,
9311 threads,
9312 thread_state,
9313 local_buffer,
9314 ) != 0
9315 {
9316 return -2;
9317 }
9318
9319 unsafe {
9320 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9321 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9322 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9323 reconstruct_compacted_lms_suffixes_32s_2k_omp(
9324 t,
9325 sa,
9326 n,
9327 k,
9328 m,
9329 fs,
9330 f,
9331 buckets,
9332 SaSint::from(use_local_buffer),
9333 threads,
9334 thread_state,
9335 );
9336 }
9337 } else {
9338 unsafe {
9339 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9340 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9341 count_lms_suffixes_32s_2k(t, n, k, buckets);
9342 }
9343 }
9344
9345 unsafe {
9346 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9347 initialize_buckets_start_and_end_32s_4k(k, buckets);
9348 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9349 place_lms_suffixes_histogram_32s_4k(sa, n, k, m, buckets);
9350 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9351 induce_final_order_32s_4k(t, sa, n, k, buckets, threads, thread_state);
9352 }
9353 } else {
9354 unsafe {
9355 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9356 sa[0] = sa[n_usize - 1];
9357 }
9358
9359 unsafe {
9360 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9361 initialize_buckets_start_and_end_32s_6k(k, buckets);
9362 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9363 place_lms_suffixes_histogram_32s_6k(sa, n, k, m, buckets);
9364 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9365 induce_final_order_32s_6k(t, sa, n, k, buckets, threads, thread_state);
9366 }
9367 }
9368
9369 return 0;
9370 } else if k > 0 && n <= SAINT_MAX / 2 && ((fs / k) >= 4 || (local_buffer_size / k) >= 4) {
9371 let k_usize = usize::try_from(k).expect("k must be non-negative");
9372 let alignment = if fs >= 1024 && ((fs - 1024) / k) >= 4 {
9373 1024usize
9374 } else {
9375 16usize
9376 };
9377 let need = 4 * k_usize;
9378 let use_local_buffer = local_buffer_size > fs;
9379 let buckets_ptr = if use_local_buffer {
9380 local_buffer.as_mut_ptr()
9381 } else {
9382 unsafe {
9383 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9384 let start =
9385 if fs_usize >= need + alignment && ((fs_usize - alignment) / k_usize) >= 4 {
9386 let byte_ptr = sa[total_len - need - alignment..].as_mut_ptr() as usize;
9387 let aligned = align_up(byte_ptr, alignment * mem::size_of::<SaSint>());
9388 (aligned - sa_ptr as usize) / mem::size_of::<SaSint>()
9389 } else {
9390 total_len - need
9391 };
9392 sa[start..].as_mut_ptr()
9393 }
9394 };
9395
9396 let m = unsafe {
9397 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9398 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9399 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9400 count_and_gather_lms_suffixes_32s_2k_omp(
9401 t,
9402 sa,
9403 n,
9404 k,
9405 buckets,
9406 SaSint::from(use_local_buffer),
9407 threads,
9408 thread_state,
9409 )
9410 };
9411 if m > 1 {
9412 let m_usize = usize::try_from(m).expect("m must be non-negative");
9413 unsafe {
9414 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9415 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9416 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9417 initialize_buckets_for_radix_and_partial_sorting_32s_4k(
9418 t,
9419 k,
9420 buckets,
9421 sa[n_usize - m_usize],
9422 );
9423 let (_, induction_bucket) = buckets.split_at_mut(1);
9424 radix_sort_lms_suffixes_32s_2k_omp(t, sa, n, m, induction_bucket, threads);
9425 radix_sort_set_markers_32s_4k_omp(sa, k, induction_bucket, threads);
9426 place_lms_suffixes_interval_32s_4k(sa, n, k, m - 1, buckets);
9427 induce_partial_order_32s_4k_omp(t, sa, n, k, buckets, threads, thread_state);
9428 }
9429
9430 let names = unsafe {
9431 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9432 renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(sa, n, m, threads, thread_state)
9433 };
9434 if names < m {
9435 let f = unsafe {
9436 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9437 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9438 compact_lms_suffixes_32s_omp(t, sa, n, m, fs, threads)
9439 };
9440
9441 let new_t_start =
9442 total_len - usize::try_from(m - f).expect("m - f must be non-negative");
9443 if main_32s_recursion(
9444 unsafe {
9445 std::slice::from_raw_parts_mut(sa_ptr, total_len)[new_t_start..]
9446 .as_mut_ptr()
9447 },
9448 sa_ptr,
9449 sa_capacity,
9450 m - f,
9451 names - f,
9452 fs + n - 2 * m + f,
9453 threads,
9454 thread_state,
9455 local_buffer,
9456 ) != 0
9457 {
9458 return -2;
9459 }
9460
9461 unsafe {
9462 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9463 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9464 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9465 reconstruct_compacted_lms_suffixes_32s_2k_omp(
9466 t,
9467 sa,
9468 n,
9469 k,
9470 m,
9471 fs,
9472 f,
9473 buckets,
9474 SaSint::from(use_local_buffer),
9475 threads,
9476 thread_state,
9477 );
9478 }
9479 } else {
9480 unsafe {
9481 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9482 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9483 count_lms_suffixes_32s_2k(t, n, k, buckets);
9484 }
9485 }
9486 } else {
9487 unsafe {
9488 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9489 sa[0] = sa[n_usize - 1];
9490 }
9491 }
9492
9493 unsafe {
9494 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9495 initialize_buckets_start_and_end_32s_4k(k, buckets);
9496 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9497 place_lms_suffixes_histogram_32s_4k(sa, n, k, m, buckets);
9498 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9499 induce_final_order_32s_4k(t, sa, n, k, buckets, threads, thread_state);
9500 }
9501
9502 return 0;
9503 } else if k > 0 && ((fs / k) >= 2 || (local_buffer_size / k) >= 2) {
9504 let k_usize = usize::try_from(k).expect("k must be non-negative");
9505 let alignment = if fs >= 1024 && ((fs - 1024) / k) >= 2 {
9506 1024usize
9507 } else {
9508 16usize
9509 };
9510 let need = 2 * k_usize;
9511 let use_local_buffer = local_buffer_size > fs;
9512 let buckets_ptr = if use_local_buffer {
9513 local_buffer.as_mut_ptr()
9514 } else {
9515 unsafe {
9516 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9517 let start =
9518 if fs_usize >= need + alignment && ((fs_usize - alignment) / k_usize) >= 2 {
9519 let byte_ptr = sa[total_len - need - alignment..].as_mut_ptr() as usize;
9520 let aligned = align_up(byte_ptr, alignment * mem::size_of::<SaSint>());
9521 (aligned - sa_ptr as usize) / mem::size_of::<SaSint>()
9522 } else {
9523 total_len - need
9524 };
9525 sa[start..].as_mut_ptr()
9526 }
9527 };
9528
9529 let m = unsafe {
9530 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9531 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9532 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9533 count_and_gather_lms_suffixes_32s_2k_omp(
9534 t,
9535 sa,
9536 n,
9537 k,
9538 buckets,
9539 SaSint::from(use_local_buffer),
9540 threads,
9541 thread_state,
9542 )
9543 };
9544 if m > 1 {
9545 let m_usize = usize::try_from(m).expect("m must be non-negative");
9546 unsafe {
9547 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9548 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9549 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9550 initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(
9551 t,
9552 k,
9553 buckets,
9554 sa[n_usize - m_usize],
9555 );
9556 let (_, induction_bucket) = buckets.split_at_mut(1);
9557 radix_sort_lms_suffixes_32s_2k_omp(t, sa, n, m, induction_bucket, threads);
9558 place_lms_suffixes_interval_32s_2k(sa, n, k, m - 1, buckets);
9559 }
9560
9561 unsafe {
9562 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9563 initialize_buckets_start_and_end_32s_2k(k, buckets);
9564 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9565 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9566 induce_partial_order_32s_2k_omp(t, sa, n, k, buckets, threads, thread_state);
9567 }
9568
9569 let names = unsafe {
9570 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9571 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9572 renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(t, sa, n, m, threads)
9573 };
9574 if names < m {
9575 let f = unsafe {
9576 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9577 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9578 compact_lms_suffixes_32s_omp(t, sa, n, m, fs, threads)
9579 };
9580
9581 let new_t_start =
9582 total_len - usize::try_from(m - f).expect("m - f must be non-negative");
9583 if main_32s_recursion(
9584 unsafe {
9585 std::slice::from_raw_parts_mut(sa_ptr, total_len)[new_t_start..]
9586 .as_mut_ptr()
9587 },
9588 sa_ptr,
9589 sa_capacity,
9590 m - f,
9591 names - f,
9592 fs + n - 2 * m + f,
9593 threads,
9594 thread_state,
9595 local_buffer,
9596 ) != 0
9597 {
9598 return -2;
9599 }
9600
9601 unsafe {
9602 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9603 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9604 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9605 reconstruct_compacted_lms_suffixes_32s_2k_omp(
9606 t,
9607 sa,
9608 n,
9609 k,
9610 m,
9611 fs,
9612 f,
9613 buckets,
9614 SaSint::from(use_local_buffer),
9615 threads,
9616 thread_state,
9617 );
9618 }
9619 } else {
9620 unsafe {
9621 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9622 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9623 count_lms_suffixes_32s_2k(t, n, k, buckets);
9624 }
9625 }
9626 } else {
9627 unsafe {
9628 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9629 sa[0] = sa[n_usize - 1];
9630 }
9631 }
9632
9633 unsafe {
9634 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9635 initialize_buckets_end_32s_2k(k, buckets);
9636 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9637 place_lms_suffixes_histogram_32s_2k(sa, n, k, m, buckets);
9638 }
9639
9640 unsafe {
9641 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9642 initialize_buckets_start_and_end_32s_2k(k, buckets);
9643 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9644 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9645 induce_final_order_32s_2k(t, sa, n, k, buckets, threads, thread_state);
9646 }
9647
9648 0
9649 } else {
9650 let k_usize = usize::try_from(k).expect("k must be non-negative");
9651 let mut heap_buckets = if fs < k { Some(vec![0; k_usize]) } else { None };
9652 let alignment = if fs >= 1024 && (fs - 1024) >= k {
9653 1024usize
9654 } else {
9655 16usize
9656 };
9657 let mut buckets_ptr = if let Some(ref mut heap) = heap_buckets {
9658 heap.as_mut_ptr()
9659 } else {
9660 unsafe {
9661 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9662 let start = if fs_usize >= k_usize + alignment {
9663 let byte_ptr = sa[total_len - k_usize - alignment..].as_mut_ptr() as usize;
9664 let aligned = align_up(byte_ptr, alignment * mem::size_of::<SaSint>());
9665 (aligned - sa_ptr as usize) / mem::size_of::<SaSint>()
9666 } else {
9667 total_len - k_usize
9668 };
9669 sa[start..].as_mut_ptr()
9670 }
9671 };
9672
9673 if buckets_ptr.is_null() {
9674 return -2;
9675 }
9676
9677 unsafe {
9678 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9679 sa[..n_usize].fill(0);
9680 }
9681
9682 unsafe {
9683 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9684 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9685 count_suffixes_32s(t, n, k, buckets);
9686 initialize_buckets_end_32s_1k(k, buckets);
9687 }
9688
9689 let m = unsafe {
9690 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9691 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9692 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9693 radix_sort_lms_suffixes_32s_1k(t, sa, n, buckets)
9694 };
9695 if m > 1 {
9696 unsafe {
9697 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9698 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9699 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9700 induce_partial_order_32s_1k_omp(t, sa, n, k, buckets, threads, thread_state);
9701 }
9702
9703 let names = unsafe {
9704 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9705 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9706 renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(t, sa, n, m, threads)
9707 };
9708 if names < m {
9709 if heap_buckets.is_some() {
9710 let _ = heap_buckets.take();
9711 buckets_ptr = std::ptr::null_mut();
9712 }
9713
9714 let f = unsafe {
9715 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9716 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9717 compact_lms_suffixes_32s_omp(t, sa, n, m, fs, threads)
9718 };
9719
9720 let new_t_start =
9721 total_len - usize::try_from(m - f).expect("m - f must be non-negative");
9722 if main_32s_recursion(
9723 unsafe {
9724 std::slice::from_raw_parts_mut(sa_ptr, total_len)[new_t_start..]
9725 .as_mut_ptr()
9726 },
9727 sa_ptr,
9728 sa_capacity,
9729 m - f,
9730 names - f,
9731 fs + n - 2 * m + f,
9732 threads,
9733 thread_state,
9734 local_buffer,
9735 ) != 0
9736 {
9737 return -2;
9738 }
9739
9740 unsafe {
9741 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9742 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9743 reconstruct_compacted_lms_suffixes_32s_1k_omp(t, sa, n, m, fs, f, threads);
9744 }
9745
9746 if buckets_ptr.is_null() {
9747 heap_buckets = Some(vec![0; k_usize]);
9748 buckets_ptr = heap_buckets.as_mut().unwrap().as_mut_ptr();
9749 if buckets_ptr.is_null() {
9750 return -2;
9751 }
9752 }
9753 }
9754
9755 unsafe {
9756 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9757 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9758 count_suffixes_32s(t, n, k, buckets);
9759 initialize_buckets_end_32s_1k(k, buckets);
9760 }
9761 unsafe {
9762 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9763 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9764 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9765 place_lms_suffixes_interval_32s_1k(t, sa, k, m, buckets);
9766 }
9767 }
9768
9769 unsafe {
9770 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9771 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9772 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9773 induce_final_order_32s_1k(t, sa, n, k, buckets, threads, thread_state);
9774 }
9775
9776 0
9777 }
9778}
9779
9780fn main_32s_entry(
9781 t_ptr: *mut SaSint,
9782 sa: &mut [SaSint],
9783 n: SaSint,
9784 k: SaSint,
9785 fs: SaSint,
9786 threads: SaSint,
9787 thread_state: &mut [ThreadState],
9788) -> SaSint {
9789 let mut local_buffer = [0; 2 * LIBSAIS_LOCAL_BUFFER_SIZE];
9790 main_32s_recursion(
9791 t_ptr,
9792 sa.as_mut_ptr(),
9793 sa.len(),
9794 n,
9795 k,
9796 fs,
9797 threads,
9798 thread_state,
9799 &mut local_buffer[LIBSAIS_LOCAL_BUFFER_SIZE..],
9800 )
9801}
9802
9803fn main_16u(
9804 t: &[u16],
9805 sa: &mut [SaSint],
9806 n: SaSint,
9807 buckets: &mut [SaSint],
9808 flags: SaSint,
9809 r: SaSint,
9810 i_out: Option<&mut [SaSint]>,
9811 fs: SaSint,
9812 freq: Option<&mut [SaSint]>,
9813 threads: SaSint,
9814 thread_state: &mut [ThreadState],
9815) -> SaSint {
9816 let fs = fs.min(SAINT_MAX - n);
9817
9818 let m = count_and_gather_lms_suffixes_16u_omp(t, sa, n, buckets, threads, thread_state);
9819 let k = initialize_buckets_start_and_end_16u(buckets, freq);
9820
9821 if (flags & LIBSAIS_FLAGS_GSA) != 0 && (buckets[0] != 0 || buckets[2] != 0 || buckets[3] != 1) {
9822 return -1;
9823 }
9824
9825 if m > 0 {
9826 let first_lms_suffix = sa[(n - m) as usize];
9827 let left_suffixes_count =
9828 initialize_buckets_for_lms_suffixes_radix_sort_16u(t, buckets, first_lms_suffix);
9829
9830 if threads > 1 && n >= 65_536 {
9831 sa[..(n - m) as usize].fill(0);
9832 }
9833 radix_sort_lms_suffixes_16u_omp(t, sa, n, m, flags, buckets, threads, thread_state);
9834 if threads > 1 && n >= 65_536 {
9835 sa[(n - m) as usize..n as usize].fill(0);
9836 }
9837
9838 initialize_buckets_for_partial_sorting_16u(
9839 t,
9840 buckets,
9841 first_lms_suffix,
9842 left_suffixes_count,
9843 );
9844 induce_partial_order_16u_omp(
9845 t,
9846 sa,
9847 n,
9848 k,
9849 flags,
9850 buckets,
9851 first_lms_suffix,
9852 left_suffixes_count,
9853 threads,
9854 );
9855
9856 let names = renumber_and_gather_lms_suffixes_omp(sa, n, m, fs, threads, thread_state);
9857 if names < m {
9858 let recursive_t_start = (n + fs - m) as usize;
9859 let recursive_t_ptr = sa[recursive_t_start..].as_mut_ptr();
9860 if main_32s_entry(
9861 recursive_t_ptr,
9862 sa,
9863 m,
9864 names,
9865 fs + n - 2 * m,
9866 threads,
9867 thread_state,
9868 ) != 0
9869 {
9870 return -2;
9871 }
9872
9873 gather_lms_suffixes_16u_omp(t, sa, n, threads, thread_state);
9874 reconstruct_lms_suffixes_omp(sa, n, m, threads);
9875 }
9876
9877 place_lms_suffixes_interval_16u(sa, n, m, flags, buckets);
9878 } else {
9879 sa[..n as usize].fill(0);
9880 }
9881
9882 induce_final_order_16u_omp(t, sa, n, k, flags, r, i_out, buckets, threads, thread_state)
9883}
9884
9885fn main_16u_alloc(
9886 t: &[u16],
9887 sa: &mut [SaSint],
9888 flags: SaSint,
9889 r: SaSint,
9890 i_out: Option<&mut [SaSint]>,
9891 fs: SaSint,
9892 freq: Option<&mut [SaSint]>,
9893 threads: SaSint,
9894) -> SaSint {
9895 if fs < 0
9896 || threads < 0
9897 || sa.len()
9898 < t.len()
9899 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
9900 || freq.as_ref().is_some_and(|freq| freq.len() < ALPHABET_SIZE)
9901 {
9902 return -1;
9903 }
9904
9905 fill_freq(t, freq);
9906 if t.len() <= 1 {
9907 if t.len() == 1 {
9908 sa[0] = 0;
9909 }
9910 return if (flags & LIBSAIS_FLAGS_BWT) != 0 {
9911 t.len() as SaSint
9912 } else {
9913 0
9914 };
9915 }
9916
9917 let mut buckets = vec![0; 8 * ALPHABET_SIZE];
9918 let threads = normalize_threads(threads);
9919 let mut thread_state = if threads > 1 {
9920 match alloc_thread_state(threads) {
9921 Some(thread_state) => thread_state,
9922 None => return -2,
9923 }
9924 } else {
9925 Vec::new()
9926 };
9927
9928 main_16u(
9929 t,
9930 sa,
9931 t.len() as SaSint,
9932 &mut buckets,
9933 flags,
9934 r,
9935 i_out,
9936 fs,
9937 None,
9938 threads,
9939 &mut thread_state,
9940 )
9941}
9942
9943fn main_16u_ctx(
9944 ctx: &mut Context,
9945 t: &[u16],
9946 sa: &mut [SaSint],
9947 flags: SaSint,
9948 r: SaSint,
9949 i_out: Option<&mut [SaSint]>,
9950 fs: SaSint,
9951 freq: Option<&mut [SaSint]>,
9952) -> SaSint {
9953 if fs < 0
9954 || sa.len()
9955 < t.len()
9956 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
9957 || freq.as_ref().is_some_and(|freq| freq.len() < ALPHABET_SIZE)
9958 {
9959 return -1;
9960 }
9961
9962 if ctx.threads <= 0 || ctx.buckets.len() < 8 * ALPHABET_SIZE {
9963 return -2;
9964 }
9965
9966 fill_freq(t, freq);
9967 if t.len() <= 1 {
9968 if t.len() == 1 {
9969 sa[0] = 0;
9970 }
9971 return if (flags & LIBSAIS_FLAGS_BWT) != 0 {
9972 t.len() as SaSint
9973 } else {
9974 0
9975 };
9976 }
9977
9978 let mut empty_thread_state = [];
9979 let thread_state = if ctx.threads > 1 {
9980 match ctx.thread_state.as_deref_mut() {
9981 Some(thread_state) if thread_state.len() >= ctx.threads as usize => thread_state,
9982 None => return -2,
9983 Some(_) => return -2,
9984 }
9985 } else {
9986 &mut empty_thread_state
9987 };
9988
9989 main_16u(
9990 t,
9991 sa,
9992 t.len() as SaSint,
9993 &mut ctx.buckets,
9994 flags,
9995 r,
9996 i_out,
9997 fs,
9998 None,
9999 ctx.threads,
10000 thread_state,
10001 )
10002}
10003
10004fn main_int(t: &mut [SaSint], sa: &mut [SaSint], k: SaSint, fs: SaSint, threads: SaSint) -> SaSint {
10005 let threads = normalize_threads(threads);
10006 let mut thread_state = if threads > 1 {
10007 match alloc_thread_state(threads) {
10008 Some(thread_state) => thread_state,
10009 None => return -2,
10010 }
10011 } else {
10012 Vec::new()
10013 };
10014
10015 main_32s_entry(
10016 t.as_mut_ptr(),
10017 sa,
10018 t.len() as SaSint,
10019 k,
10020 fs,
10021 threads,
10022 &mut thread_state,
10023 )
10024}
10025
10026pub fn libsais16(t: &[u16], sa: &mut [SaSint], fs: SaSint, freq: Option<&mut [SaSint]>) -> SaSint {
10035 main_16u_alloc(t, sa, 0, 0, None, fs, freq, 1)
10036}
10037
10038pub fn libsais16_gsa(
10047 t: &[u16],
10048 sa: &mut [SaSint],
10049 fs: SaSint,
10050 freq: Option<&mut [SaSint]>,
10051) -> SaSint {
10052 main_16u_alloc(t, sa, LIBSAIS_FLAGS_GSA, 0, None, fs, freq, 1)
10053}
10054
10055pub fn libsais16_int(t: &mut [SaSint], sa: &mut [SaSint], k: SaSint, fs: SaSint) -> SaSint {
10066 if fs < 0
10067 || sa.len()
10068 < t.len()
10069 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
10070 {
10071 return -1;
10072 }
10073
10074 if t.len() <= 1 {
10075 if t.len() == 1 {
10076 sa[0] = 0;
10077 }
10078 return 0;
10079 }
10080
10081 main_int(t, sa, k, fs, 1)
10082}
10083
10084pub fn libsais16_ctx(
10094 ctx: &mut Context,
10095 t: &[u16],
10096 sa: &mut [SaSint],
10097 fs: SaSint,
10098 freq: Option<&mut [SaSint]>,
10099) -> SaSint {
10100 main_16u_ctx(ctx, t, sa, 0, 0, None, fs, freq)
10101}
10102
10103pub fn libsais16_gsa_ctx(
10113 ctx: &mut Context,
10114 t: &[u16],
10115 sa: &mut [SaSint],
10116 fs: SaSint,
10117 freq: Option<&mut [SaSint]>,
10118) -> SaSint {
10119 main_16u_ctx(ctx, t, sa, LIBSAIS_FLAGS_GSA, 0, None, fs, freq)
10120}
10121
10122pub fn libsais16_omp(
10132 t: &[u16],
10133 sa: &mut [SaSint],
10134 fs: SaSint,
10135 freq: Option<&mut [SaSint]>,
10136 threads: SaSint,
10137) -> SaSint {
10138 if threads < 0 {
10139 -1
10140 } else {
10141 main_16u_alloc(t, sa, 0, 0, None, fs, freq, threads)
10142 }
10143}
10144
10145pub fn libsais16_gsa_omp(
10155 t: &[u16],
10156 sa: &mut [SaSint],
10157 fs: SaSint,
10158 freq: Option<&mut [SaSint]>,
10159 threads: SaSint,
10160) -> SaSint {
10161 if threads < 0 {
10162 -1
10163 } else {
10164 main_16u_alloc(t, sa, LIBSAIS_FLAGS_GSA, 0, None, fs, freq, threads)
10165 }
10166}
10167
10168pub fn libsais16_int_omp(
10180 t: &mut [SaSint],
10181 sa: &mut [SaSint],
10182 k: SaSint,
10183 fs: SaSint,
10184 threads: SaSint,
10185) -> SaSint {
10186 if threads < 0
10187 || fs < 0
10188 || sa.len()
10189 < t.len()
10190 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
10191 {
10192 return -1;
10193 }
10194
10195 if t.len() <= 1 {
10196 if t.len() == 1 {
10197 sa[0] = 0;
10198 }
10199 return 0;
10200 }
10201
10202 main_int(t, sa, k, fs, threads)
10203}
10204
10205fn build_bwt(
10206 t: &[u16],
10207 u: &mut [u16],
10208 a: &mut [SaSint],
10209 fs: SaSint,
10210 freq: Option<&mut [SaSint]>,
10211 threads: SaSint,
10212) -> SaSint {
10213 if fs < 0
10214 || threads < 0
10215 || u.len() < t.len()
10216 || a.len()
10217 < t.len()
10218 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
10219 || freq.as_ref().is_some_and(|freq| freq.len() < ALPHABET_SIZE)
10220 {
10221 return -1;
10222 }
10223 if t.len() <= 1 {
10224 fill_freq(t, freq);
10225 if t.len() == 1 {
10226 u[0] = t[0];
10227 }
10228 return t.len() as SaSint;
10229 }
10230
10231 let n = t.len();
10232 let mut index = main_16u_alloc(t, a, LIBSAIS_FLAGS_BWT, 0, None, fs, freq, threads);
10233 if index >= 0 {
10234 index += 1;
10235 u[0] = t[n - 1];
10236 bwt_copy_16u(&mut u[1..], a, index - 1);
10237 bwt_copy_16u(
10238 &mut u[index as usize..],
10239 &a[index as usize..],
10240 n as SaSint - index,
10241 );
10242 }
10243 index
10244}
10245
10246pub fn libsais16_bwt(
10256 t: &[u16],
10257 u: &mut [u16],
10258 a: &mut [SaSint],
10259 fs: SaSint,
10260 freq: Option<&mut [SaSint]>,
10261) -> SaSint {
10262 build_bwt(t, u, a, fs, freq, 1)
10263}
10264
10265fn build_bwt_aux(
10266 t: &[u16],
10267 u: &mut [u16],
10268 a: &mut [SaSint],
10269 fs: SaSint,
10270 freq: Option<&mut [SaSint]>,
10271 r: SaSint,
10272 i: &mut [SaSint],
10273 threads: SaSint,
10274) -> SaSint {
10275 if threads < 0 || r < 2 || (r & (r - 1)) != 0 {
10276 return -1;
10277 }
10278 let samples = if t.is_empty() {
10279 1
10280 } else {
10281 (t.len() - 1) / r as usize + 1
10282 };
10283 if i.len() < samples {
10284 return -1;
10285 }
10286 let n = t.len();
10287 if n <= 1 {
10288 fill_freq(t, freq);
10289 if n == 1 {
10290 u[0] = t[0];
10291 }
10292 i[0] = n as SaSint;
10293 return 0;
10294 }
10295
10296 let index = main_16u_alloc(t, a, LIBSAIS_FLAGS_BWT, r, Some(i), fs, freq, threads);
10297 if index == 0 {
10298 u[0] = t[n - 1];
10299 bwt_copy_16u(&mut u[1..], a, i[0] - 1);
10300 bwt_copy_16u(
10301 &mut u[i[0] as usize..],
10302 &a[i[0] as usize..],
10303 n as SaSint - i[0],
10304 );
10305 }
10306 index
10307}
10308
10309pub fn libsais16_bwt_aux(
10321 t: &[u16],
10322 u: &mut [u16],
10323 a: &mut [SaSint],
10324 fs: SaSint,
10325 freq: Option<&mut [SaSint]>,
10326 r: SaSint,
10327 i: &mut [SaSint],
10328) -> SaSint {
10329 build_bwt_aux(t, u, a, fs, freq, r, i, 1)
10330}
10331
10332pub fn libsais16_bwt_ctx(
10343 ctx: &mut Context,
10344 t: &[u16],
10345 u: &mut [u16],
10346 a: &mut [SaSint],
10347 fs: SaSint,
10348 freq: Option<&mut [SaSint]>,
10349) -> SaSint {
10350 if fs < 0
10351 || u.len() < t.len()
10352 || a.len()
10353 < t.len()
10354 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
10355 || freq.as_ref().is_some_and(|freq| freq.len() < ALPHABET_SIZE)
10356 {
10357 return -1;
10358 }
10359 if t.len() <= 1 {
10360 fill_freq(t, freq);
10361 if t.len() == 1 {
10362 u[0] = t[0];
10363 }
10364 return t.len() as SaSint;
10365 }
10366
10367 let n = t.len();
10368 let mut index = main_16u_ctx(ctx, t, a, LIBSAIS_FLAGS_BWT, 0, None, fs, freq);
10369 if index >= 0 {
10370 index += 1;
10371 u[0] = t[n - 1];
10372 bwt_copy_16u(&mut u[1..], a, index - 1);
10373 bwt_copy_16u(
10374 &mut u[index as usize..],
10375 &a[index as usize..],
10376 n as SaSint - index,
10377 );
10378 }
10379 index
10380}
10381
10382pub fn libsais16_bwt_aux_ctx(
10395 ctx: &mut Context,
10396 t: &[u16],
10397 u: &mut [u16],
10398 a: &mut [SaSint],
10399 fs: SaSint,
10400 freq: Option<&mut [SaSint]>,
10401 r: SaSint,
10402 i: &mut [SaSint],
10403) -> SaSint {
10404 if fs < 0 || r < 2 || (r & (r - 1)) != 0 {
10405 return -1;
10406 }
10407 let samples = if t.is_empty() {
10408 1
10409 } else {
10410 (t.len() - 1) / r as usize + 1
10411 };
10412 if u.len() < t.len()
10413 || a.len()
10414 < t.len()
10415 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
10416 || i.len() < samples
10417 || freq.as_ref().is_some_and(|freq| freq.len() < ALPHABET_SIZE)
10418 {
10419 return -1;
10420 }
10421 if t.len() <= 1 {
10422 fill_freq(t, freq);
10423 if t.len() == 1 {
10424 u[0] = t[0];
10425 }
10426 i[0] = t.len() as SaSint;
10427 return 0;
10428 }
10429
10430 let n = t.len();
10431 let index = main_16u_ctx(ctx, t, a, LIBSAIS_FLAGS_BWT, r, Some(i), fs, freq);
10432 if index == 0 {
10433 u[0] = t[n - 1];
10434 bwt_copy_16u(&mut u[1..], a, i[0] - 1);
10435 bwt_copy_16u(
10436 &mut u[i[0] as usize..],
10437 &a[i[0] as usize..],
10438 n as SaSint - i[0],
10439 );
10440 }
10441 index
10442}
10443
10444pub fn libsais16_bwt_omp(
10455 t: &[u16],
10456 u: &mut [u16],
10457 a: &mut [SaSint],
10458 fs: SaSint,
10459 freq: Option<&mut [SaSint]>,
10460 threads: SaSint,
10461) -> SaSint {
10462 if threads < 0 {
10463 -1
10464 } else {
10465 build_bwt(t, u, a, fs, freq, threads)
10466 }
10467}
10468
10469pub fn libsais16_bwt_aux_omp(
10482 t: &[u16],
10483 u: &mut [u16],
10484 a: &mut [SaSint],
10485 fs: SaSint,
10486 freq: Option<&mut [SaSint]>,
10487 r: SaSint,
10488 i: &mut [SaSint],
10489 threads: SaSint,
10490) -> SaSint {
10491 if threads < 0 {
10492 -1
10493 } else {
10494 build_bwt_aux(t, u, a, fs, freq, r, i, threads)
10495 }
10496}
10497
10498fn validate_unbwt_aux(
10499 t: &[u16],
10500 u: &[u16],
10501 a: &[SaSint],
10502 freq: Option<&[SaSint]>,
10503 r: SaSint,
10504 i: &[SaSint],
10505) -> SaSint {
10506 let n = t.len();
10507 if u.len() < n
10508 || a.len() < n
10509 || freq.is_some_and(|freq| freq.len() < ALPHABET_SIZE)
10510 || ((r != n as SaSint) && (r < 2 || (r & (r - 1)) != 0))
10511 || i.is_empty()
10512 {
10513 return -1;
10514 }
10515 if n <= 1 {
10516 return if i[0] == n as SaSint { 0 } else { -1 };
10517 }
10518
10519 let samples = (n - 1) / r as usize + 1;
10520 if i.len() < samples {
10521 return -1;
10522 }
10523
10524 for &index in &i[..samples] {
10525 if index <= 0 || index as usize > n {
10526 return -1;
10527 }
10528 }
10529 0
10530}
10531
10532fn unbwt_compute_histogram(t: &[u16], count: &mut [usize]) {
10533 for &symbol in t {
10534 count[symbol as usize] += 1;
10535 }
10536}
10537
10538fn unbwt_shift(n: usize) -> usize {
10539 let mut shift = 0usize;
10540 while (n >> shift) > (1usize << UNBWT_FASTBITS) {
10541 shift += 1;
10542 }
10543 shift
10544}
10545
10546fn unbwt_calculate_fastbits(bucket2: &mut [usize], fastbits: &mut [u16], shift: usize) {
10547 let mut v = 0usize;
10548 let mut sum = 1usize;
10549 for (w, bucket) in bucket2.iter_mut().enumerate().take(ALPHABET_SIZE) {
10550 let prev = sum;
10551 sum += *bucket;
10552 *bucket = prev;
10553 if prev != sum {
10554 while v <= ((sum - 1) >> shift) {
10555 fastbits[v] = w as u16;
10556 v += 1;
10557 }
10558 }
10559 }
10560}
10561
10562fn unbwt_calculate_p(t: &[u16], p: &mut [usize], bucket2: &mut [usize], index: usize) {
10563 for row in 0..index {
10564 let symbol = t[row] as usize;
10565 p[bucket2[symbol]] = row;
10566 bucket2[symbol] += 1;
10567 }
10568
10569 for row in index + 1..=t.len() {
10570 let symbol = t[row - 1] as usize;
10571 p[bucket2[symbol]] = row;
10572 bucket2[symbol] += 1;
10573 }
10574}
10575
10576#[allow(dead_code, non_snake_case)]
10577fn unbwt_calculate_P(
10578 t: &[u16],
10579 p: &mut [usize],
10580 bucket2: &mut [usize],
10581 index: usize,
10582 block_start: usize,
10583 block_end: usize,
10584) {
10585 let first_end = index.min(block_end);
10586 for row in block_start..first_end {
10587 let symbol = t[row] as usize;
10588 p[bucket2[symbol]] = row;
10589 bucket2[symbol] += 1;
10590 }
10591
10592 let second_start = block_start.max(index) + 1;
10593 for row in second_start..=block_end {
10594 let symbol = t[row - 1] as usize;
10595 p[bucket2[symbol]] = row;
10596 bucket2[symbol] += 1;
10597 }
10598}
10599
10600fn unbwt_init_single(
10601 t: &[u16],
10602 p: &mut [usize],
10603 freq: Option<&[SaSint]>,
10604 i: &[SaSint],
10605 bucket2: &mut [usize],
10606 fastbits: &mut [u16],
10607) {
10608 let shift = unbwt_shift(t.len());
10609 if let Some(freq) = freq {
10610 for c in 0..ALPHABET_SIZE {
10611 bucket2[c] = freq[c] as usize;
10612 }
10613 } else {
10614 bucket2.fill(0);
10615 unbwt_compute_histogram(t, bucket2);
10616 }
10617
10618 unbwt_calculate_fastbits(bucket2, fastbits, shift);
10619 unbwt_calculate_p(t, p, bucket2, i[0] as usize);
10620}
10621
10622#[allow(dead_code)]
10623fn unbwt_init_parallel(
10624 t: &[u16],
10625 p: &mut [usize],
10626 freq: Option<&[SaSint]>,
10627 i: &[SaSint],
10628 bucket2: &mut [usize],
10629 fastbits: &mut [u16],
10630 buckets: &mut [usize],
10631 threads: SaSint,
10632) {
10633 let n = t.len();
10634 let available_threads = buckets.len() / ALPHABET_SIZE;
10635 let num_threads = if threads > 1 && n >= 65_536 && available_threads > 1 {
10636 usize::try_from(threads)
10637 .expect("threads must be non-negative")
10638 .min(available_threads)
10639 .max(1)
10640 } else {
10641 1
10642 };
10643
10644 if num_threads == 1 {
10645 unbwt_init_single(t, p, freq, i, bucket2, fastbits);
10646 return;
10647 }
10648
10649 let index = usize::try_from(i[0]).expect("primary index must be non-negative");
10650 let shift = unbwt_shift(n);
10651 let block_stride = (n / num_threads) & !15usize;
10652
10653 for thread in 0..num_threads {
10654 let block_start = thread * block_stride;
10655 let block_size = if thread + 1 < num_threads {
10656 block_stride
10657 } else {
10658 n - block_start
10659 };
10660 let local = &mut buckets[thread * ALPHABET_SIZE..(thread + 1) * ALPHABET_SIZE];
10661 local.fill(0);
10662 unbwt_compute_histogram(&t[block_start..block_start + block_size], local);
10663 }
10664
10665 bucket2.fill(0);
10666 for thread in 0..num_threads {
10667 let local = &mut buckets[thread * ALPHABET_SIZE..(thread + 1) * ALPHABET_SIZE];
10668 for c in 0..ALPHABET_SIZE {
10669 let a = bucket2[c];
10670 let b = local[c];
10671 bucket2[c] = a + b;
10672 local[c] = a;
10673 }
10674 }
10675
10676 unbwt_calculate_fastbits(bucket2, fastbits, shift);
10677
10678 for thread in 0..num_threads {
10679 let block_start = thread * block_stride;
10680 let block_size = if thread + 1 < num_threads {
10681 block_stride
10682 } else {
10683 n - block_start
10684 };
10685 let local = &mut buckets[thread * ALPHABET_SIZE..(thread + 1) * ALPHABET_SIZE];
10686 for c in 0..ALPHABET_SIZE {
10687 local[c] += bucket2[c];
10688 }
10689 unbwt_calculate_P(t, p, local, index, block_start, block_start + block_size);
10690 }
10691
10692 let last_local = &buckets[(num_threads - 1) * ALPHABET_SIZE..num_threads * ALPHABET_SIZE];
10693 bucket2.copy_from_slice(last_local);
10694}
10695
10696fn unbwt_decode_symbol(
10697 p0: usize,
10698 p: &[usize],
10699 bucket2: &[usize],
10700 fastbits: &[u16],
10701 shift: usize,
10702) -> (u16, usize) {
10703 let mut c0 = fastbits[p0 >> shift] as usize;
10704 if bucket2[c0] <= p0 {
10705 while bucket2[c0] <= p0 {
10706 c0 += 1;
10707 }
10708 }
10709 (c0 as u16, p[p0])
10710}
10711
10712#[allow(dead_code)]
10713fn unbwt_decode_1(
10714 u: &mut [u16],
10715 p: &[usize],
10716 bucket2: &[usize],
10717 fastbits: &[u16],
10718 shift: usize,
10719 i0: &mut usize,
10720 k: usize,
10721) {
10722 let mut cursors = [*i0];
10723 unbwt_decode_lanes::<1>(u, p, bucket2, fastbits, shift, k, &mut cursors, k);
10724 *i0 = cursors[0];
10725}
10726
10727#[allow(dead_code)]
10728fn unbwt_decode_2(
10729 u: &mut [u16],
10730 p: &[usize],
10731 bucket2: &[usize],
10732 fastbits: &[u16],
10733 shift: usize,
10734 r: usize,
10735 i0: &mut usize,
10736 i1: &mut usize,
10737 k: usize,
10738) {
10739 let mut cursors = [*i0, *i1];
10740 unbwt_decode_lanes::<2>(u, p, bucket2, fastbits, shift, r, &mut cursors, k);
10741 *i0 = cursors[0];
10742 *i1 = cursors[1];
10743}
10744
10745#[allow(dead_code)]
10746fn unbwt_decode_3(
10747 u: &mut [u16],
10748 p: &[usize],
10749 bucket2: &[usize],
10750 fastbits: &[u16],
10751 shift: usize,
10752 r: usize,
10753 i0: &mut usize,
10754 i1: &mut usize,
10755 i2: &mut usize,
10756 k: usize,
10757) {
10758 let mut cursors = [*i0, *i1, *i2];
10759 unbwt_decode_lanes::<3>(u, p, bucket2, fastbits, shift, r, &mut cursors, k);
10760 *i0 = cursors[0];
10761 *i1 = cursors[1];
10762 *i2 = cursors[2];
10763}
10764
10765#[allow(dead_code)]
10766fn unbwt_decode_4(
10767 u: &mut [u16],
10768 p: &[usize],
10769 bucket2: &[usize],
10770 fastbits: &[u16],
10771 shift: usize,
10772 r: usize,
10773 i0: &mut usize,
10774 i1: &mut usize,
10775 i2: &mut usize,
10776 i3: &mut usize,
10777 k: usize,
10778) {
10779 let mut cursors = [*i0, *i1, *i2, *i3];
10780 unbwt_decode_lanes::<4>(u, p, bucket2, fastbits, shift, r, &mut cursors, k);
10781 *i0 = cursors[0];
10782 *i1 = cursors[1];
10783 *i2 = cursors[2];
10784 *i3 = cursors[3];
10785}
10786
10787#[allow(dead_code)]
10788fn unbwt_decode_5(
10789 u: &mut [u16],
10790 p: &[usize],
10791 bucket2: &[usize],
10792 fastbits: &[u16],
10793 shift: usize,
10794 r: usize,
10795 cursors: &mut [usize; 5],
10796 k: usize,
10797) {
10798 unbwt_decode_lanes::<5>(u, p, bucket2, fastbits, shift, r, cursors, k);
10799}
10800
10801#[allow(dead_code)]
10802fn unbwt_decode_6(
10803 u: &mut [u16],
10804 p: &[usize],
10805 bucket2: &[usize],
10806 fastbits: &[u16],
10807 shift: usize,
10808 r: usize,
10809 cursors: &mut [usize; 6],
10810 k: usize,
10811) {
10812 unbwt_decode_lanes::<6>(u, p, bucket2, fastbits, shift, r, cursors, k);
10813}
10814
10815#[allow(dead_code)]
10816fn unbwt_decode_7(
10817 u: &mut [u16],
10818 p: &[usize],
10819 bucket2: &[usize],
10820 fastbits: &[u16],
10821 shift: usize,
10822 r: usize,
10823 cursors: &mut [usize; 7],
10824 k: usize,
10825) {
10826 unbwt_decode_lanes::<7>(u, p, bucket2, fastbits, shift, r, cursors, k);
10827}
10828
10829#[allow(dead_code)]
10830fn unbwt_decode_8(
10831 u: &mut [u16],
10832 p: &[usize],
10833 bucket2: &[usize],
10834 fastbits: &[u16],
10835 shift: usize,
10836 r: usize,
10837 cursors: &mut [usize; 8],
10838 k: usize,
10839) {
10840 unbwt_decode_lanes::<8>(u, p, bucket2, fastbits, shift, r, cursors, k);
10841}
10842
10843fn unbwt_decode(
10844 u: &mut [u16],
10845 p: &[usize],
10846 n: usize,
10847 r: usize,
10848 i: &[SaSint],
10849 bucket2: &[usize],
10850 fastbits: &[u16],
10851) {
10852 let shift = unbwt_shift(n);
10853 let blocks = 1 + (n - 1) / r;
10854 let remainder = n - r * (blocks - 1);
10855 unbwt_decode_blocks(u, p, r, i, bucket2, fastbits, shift, blocks, remainder);
10856}
10857
10858fn unbwt_decode_blocks(
10859 u: &mut [u16],
10860 p: &[usize],
10861 r: usize,
10862 i: &[SaSint],
10863 bucket2: &[usize],
10864 fastbits: &[u16],
10865 shift: usize,
10866 blocks: usize,
10867 remainder: usize,
10868) {
10869 let mut blocks_left = blocks;
10870 let mut i_offset = 0usize;
10871 let mut u_offset = 0usize;
10872
10873 while blocks_left > 8 {
10874 let mut cursors = [
10875 i[i_offset] as usize,
10876 i[i_offset + 1] as usize,
10877 i[i_offset + 2] as usize,
10878 i[i_offset + 3] as usize,
10879 i[i_offset + 4] as usize,
10880 i[i_offset + 5] as usize,
10881 i[i_offset + 6] as usize,
10882 i[i_offset + 7] as usize,
10883 ];
10884 unbwt_decode_lanes::<8>(
10885 &mut u[u_offset..],
10886 p,
10887 bucket2,
10888 fastbits,
10889 shift,
10890 r,
10891 &mut cursors,
10892 r,
10893 );
10894 i_offset += 8;
10895 blocks_left -= 8;
10896 u_offset += 8 * r;
10897 }
10898
10899 match blocks_left {
10900 1 => {
10901 let mut cursors = [i[i_offset] as usize];
10902 unbwt_decode_lanes::<1>(
10903 &mut u[u_offset..],
10904 p,
10905 bucket2,
10906 fastbits,
10907 shift,
10908 r,
10909 &mut cursors,
10910 remainder,
10911 );
10912 }
10913 2 => {
10914 let mut cursors = [i[i_offset] as usize, i[i_offset + 1] as usize];
10915 unbwt_decode_lanes::<2>(
10916 &mut u[u_offset..],
10917 p,
10918 bucket2,
10919 fastbits,
10920 shift,
10921 r,
10922 &mut cursors,
10923 remainder,
10924 );
10925 let mut first = [cursors[0]];
10926 unbwt_decode_lanes::<1>(
10927 &mut u[u_offset + remainder..],
10928 p,
10929 bucket2,
10930 fastbits,
10931 shift,
10932 r,
10933 &mut first,
10934 r - remainder,
10935 );
10936 }
10937 3 => {
10938 let mut cursors = [
10939 i[i_offset] as usize,
10940 i[i_offset + 1] as usize,
10941 i[i_offset + 2] as usize,
10942 ];
10943 unbwt_decode_lanes::<3>(
10944 &mut u[u_offset..],
10945 p,
10946 bucket2,
10947 fastbits,
10948 shift,
10949 r,
10950 &mut cursors,
10951 remainder,
10952 );
10953 let mut first = [cursors[0], cursors[1]];
10954 unbwt_decode_lanes::<2>(
10955 &mut u[u_offset + remainder..],
10956 p,
10957 bucket2,
10958 fastbits,
10959 shift,
10960 r,
10961 &mut first,
10962 r - remainder,
10963 );
10964 }
10965 4 => {
10966 let mut cursors = [
10967 i[i_offset] as usize,
10968 i[i_offset + 1] as usize,
10969 i[i_offset + 2] as usize,
10970 i[i_offset + 3] as usize,
10971 ];
10972 unbwt_decode_lanes::<4>(
10973 &mut u[u_offset..],
10974 p,
10975 bucket2,
10976 fastbits,
10977 shift,
10978 r,
10979 &mut cursors,
10980 remainder,
10981 );
10982 let mut first = [cursors[0], cursors[1], cursors[2]];
10983 unbwt_decode_lanes::<3>(
10984 &mut u[u_offset + remainder..],
10985 p,
10986 bucket2,
10987 fastbits,
10988 shift,
10989 r,
10990 &mut first,
10991 r - remainder,
10992 );
10993 }
10994 5 => {
10995 let mut cursors = [
10996 i[i_offset] as usize,
10997 i[i_offset + 1] as usize,
10998 i[i_offset + 2] as usize,
10999 i[i_offset + 3] as usize,
11000 i[i_offset + 4] as usize,
11001 ];
11002 unbwt_decode_lanes::<5>(
11003 &mut u[u_offset..],
11004 p,
11005 bucket2,
11006 fastbits,
11007 shift,
11008 r,
11009 &mut cursors,
11010 remainder,
11011 );
11012 let mut first = [cursors[0], cursors[1], cursors[2], cursors[3]];
11013 unbwt_decode_lanes::<4>(
11014 &mut u[u_offset + remainder..],
11015 p,
11016 bucket2,
11017 fastbits,
11018 shift,
11019 r,
11020 &mut first,
11021 r - remainder,
11022 );
11023 }
11024 6 => {
11025 let mut cursors = [
11026 i[i_offset] as usize,
11027 i[i_offset + 1] as usize,
11028 i[i_offset + 2] as usize,
11029 i[i_offset + 3] as usize,
11030 i[i_offset + 4] as usize,
11031 i[i_offset + 5] as usize,
11032 ];
11033 unbwt_decode_lanes::<6>(
11034 &mut u[u_offset..],
11035 p,
11036 bucket2,
11037 fastbits,
11038 shift,
11039 r,
11040 &mut cursors,
11041 remainder,
11042 );
11043 let mut first = [cursors[0], cursors[1], cursors[2], cursors[3], cursors[4]];
11044 unbwt_decode_lanes::<5>(
11045 &mut u[u_offset + remainder..],
11046 p,
11047 bucket2,
11048 fastbits,
11049 shift,
11050 r,
11051 &mut first,
11052 r - remainder,
11053 );
11054 }
11055 7 => {
11056 let mut cursors = [
11057 i[i_offset] as usize,
11058 i[i_offset + 1] as usize,
11059 i[i_offset + 2] as usize,
11060 i[i_offset + 3] as usize,
11061 i[i_offset + 4] as usize,
11062 i[i_offset + 5] as usize,
11063 i[i_offset + 6] as usize,
11064 ];
11065 unbwt_decode_lanes::<7>(
11066 &mut u[u_offset..],
11067 p,
11068 bucket2,
11069 fastbits,
11070 shift,
11071 r,
11072 &mut cursors,
11073 remainder,
11074 );
11075 let mut first = [
11076 cursors[0], cursors[1], cursors[2], cursors[3], cursors[4], cursors[5],
11077 ];
11078 unbwt_decode_lanes::<6>(
11079 &mut u[u_offset + remainder..],
11080 p,
11081 bucket2,
11082 fastbits,
11083 shift,
11084 r,
11085 &mut first,
11086 r - remainder,
11087 );
11088 }
11089 _ => {
11090 let mut cursors = [
11091 i[i_offset] as usize,
11092 i[i_offset + 1] as usize,
11093 i[i_offset + 2] as usize,
11094 i[i_offset + 3] as usize,
11095 i[i_offset + 4] as usize,
11096 i[i_offset + 5] as usize,
11097 i[i_offset + 6] as usize,
11098 i[i_offset + 7] as usize,
11099 ];
11100 unbwt_decode_lanes::<8>(
11101 &mut u[u_offset..],
11102 p,
11103 bucket2,
11104 fastbits,
11105 shift,
11106 r,
11107 &mut cursors,
11108 remainder,
11109 );
11110 let mut first = [
11111 cursors[0], cursors[1], cursors[2], cursors[3], cursors[4], cursors[5], cursors[6],
11112 ];
11113 unbwt_decode_lanes::<7>(
11114 &mut u[u_offset + remainder..],
11115 p,
11116 bucket2,
11117 fastbits,
11118 shift,
11119 r,
11120 &mut first,
11121 r - remainder,
11122 );
11123 }
11124 }
11125}
11126
11127fn unbwt_decode_omp(
11128 u: &mut [u16],
11129 p: &[usize],
11130 n: usize,
11131 r: usize,
11132 i: &[SaSint],
11133 bucket2: &[usize],
11134 fastbits: &[u16],
11135 threads: SaSint,
11136) {
11137 let blocks = 1 + (n - 1) / r;
11138 let remainder = n - r * (blocks - 1);
11139 let num_threads = if threads > 1 && n >= 65_536 {
11140 usize::try_from(threads)
11141 .expect("threads must be non-negative")
11142 .min(blocks)
11143 .max(1)
11144 } else {
11145 1
11146 };
11147
11148 if num_threads == 1 {
11149 unbwt_decode(u, p, n, r, i, bucket2, fastbits);
11150 return;
11151 }
11152
11153 let shift = unbwt_shift(n);
11154 let block_stride = blocks / num_threads;
11155 let block_remainder = blocks % num_threads;
11156 let u_ptr = SyncMutPtr::new(u);
11157 run_rayon_with_threads(num_threads, || {
11158 (0..num_threads).into_par_iter().for_each(|thread| {
11159 let block_count = block_stride + usize::from(thread < block_remainder);
11160 let block_start = block_stride * thread + thread.min(block_remainder);
11161 let tail = if thread + 1 < num_threads {
11162 r
11163 } else {
11164 remainder
11165 };
11166 let u = unsafe { u_ptr.as_slice() };
11167 unbwt_decode_blocks(
11168 &mut u[r * block_start..],
11169 p,
11170 r,
11171 &i[block_start..],
11172 bucket2,
11173 fastbits,
11174 shift,
11175 block_count,
11176 tail,
11177 );
11178 });
11179 });
11180}
11181
11182fn unbwt_decode_lanes<const LANES: usize>(
11183 u: &mut [u16],
11184 p: &[usize],
11185 bucket2: &[usize],
11186 fastbits: &[u16],
11187 shift: usize,
11188 r: usize,
11189 cursors: &mut [usize; LANES],
11190 k: usize,
11191) {
11192 for pos in 0..k {
11193 for lane in 0..LANES {
11194 let (symbol, next) = unbwt_decode_symbol(cursors[lane], p, bucket2, fastbits, shift);
11195 cursors[lane] = next;
11196 u[lane * r + pos] = symbol;
11197 }
11198 }
11199}
11200
11201fn unbwt_core(
11202 t: &[u16],
11203 u: &mut [u16],
11204 a: &mut [SaSint],
11205 freq: Option<&[SaSint]>,
11206 r: SaSint,
11207 i: &[SaSint],
11208) -> SaSint {
11209 let n = t.len();
11210 let shift = unbwt_shift(n);
11211 let mut bucket2 = vec![0usize; ALPHABET_SIZE];
11212 let mut fastbits = vec![0u16; 1 + (n >> shift)];
11213
11214 unbwt_core_with_buffers(t, u, a, freq, r, i, &mut bucket2, &mut fastbits, 1)
11215}
11216
11217fn unbwt_core_with_buffers(
11218 t: &[u16],
11219 u: &mut [u16],
11220 a: &mut [SaSint],
11221 freq: Option<&[SaSint]>,
11222 r: SaSint,
11223 i: &[SaSint],
11224 bucket2: &mut [usize],
11225 fastbits: &mut [u16],
11226 threads: SaSint,
11227) -> SaSint {
11228 let n = t.len();
11229 let shift = unbwt_shift(n);
11230 if bucket2.len() < ALPHABET_SIZE || fastbits.len() < 1 + (n >> shift) {
11231 return -2;
11232 }
11233
11234 let mut p = vec![0usize; n + 1];
11235 unbwt_init_single(
11236 t,
11237 &mut p,
11238 freq,
11239 i,
11240 &mut bucket2[..ALPHABET_SIZE],
11241 &mut fastbits[..1 + (n >> shift)],
11242 );
11243 unbwt_decode_omp(
11244 u,
11245 &p,
11246 n,
11247 r as usize,
11248 i,
11249 &bucket2[..ALPHABET_SIZE],
11250 &fastbits[..1 + (n >> shift)],
11251 threads,
11252 );
11253
11254 for (dst, &src) in a.iter_mut().zip(p.iter().skip(1)) {
11255 *dst = src as SaSint;
11256 }
11257 0
11258}
11259
11260fn inverse_bwt(
11261 t: &[u16],
11262 u: &mut [u16],
11263 a: &mut [SaSint],
11264 freq: Option<&[SaSint]>,
11265 primary: SaSint,
11266) -> SaSint {
11267 let n = t.len();
11268 let i = [primary];
11269 let rc = validate_unbwt_aux(t, u, a, freq, n as SaSint, &i);
11270 if rc != 0 {
11271 return rc;
11272 }
11273 if n <= 1 {
11274 if n == 1 {
11275 u[0] = t[0];
11276 }
11277 return 0;
11278 }
11279 unbwt_core(t, u, a, freq, n as SaSint, &i)
11280}
11281
11282pub fn libsais16_unbwt(
11292 t: &[u16],
11293 u: &mut [u16],
11294 a: &mut [SaSint],
11295 freq: Option<&[SaSint]>,
11296 i: SaSint,
11297) -> SaSint {
11298 inverse_bwt(t, u, a, freq, i)
11299}
11300
11301pub fn libsais16_unbwt_ctx(
11312 ctx: &mut UnbwtContext,
11313 t: &[u16],
11314 u: &mut [u16],
11315 a: &mut [SaSint],
11316 freq: Option<&[SaSint]>,
11317 i: SaSint,
11318) -> SaSint {
11319 libsais16_unbwt_aux_ctx(ctx, t, u, a, freq, t.len() as SaSint, &[i])
11320}
11321
11322pub fn libsais16_unbwt_aux(
11333 t: &[u16],
11334 u: &mut [u16],
11335 a: &mut [SaSint],
11336 freq: Option<&[SaSint]>,
11337 r: SaSint,
11338 i: &[SaSint],
11339) -> SaSint {
11340 let rc = validate_unbwt_aux(t, u, a, freq, r, i);
11341 if rc != 0 {
11342 return rc;
11343 }
11344 if t.len() <= 1 {
11345 if t.len() == 1 {
11346 u[0] = t[0];
11347 }
11348 return 0;
11349 }
11350 unbwt_core(t, u, a, freq, r, i)
11351}
11352
11353pub fn libsais16_unbwt_aux_ctx(
11365 ctx: &mut UnbwtContext,
11366 t: &[u16],
11367 u: &mut [u16],
11368 a: &mut [SaSint],
11369 freq: Option<&[SaSint]>,
11370 r: SaSint,
11371 i: &[SaSint],
11372) -> SaSint {
11373 let rc = validate_unbwt_aux(t, u, a, freq, r, i);
11374 if rc != 0 {
11375 return rc;
11376 }
11377 if t.len() <= 1 {
11378 if t.len() == 1 {
11379 u[0] = t[0];
11380 }
11381 return 0;
11382 }
11383 unbwt_core_with_buffers(
11384 t,
11385 u,
11386 a,
11387 freq,
11388 r,
11389 i,
11390 &mut ctx.bucket2,
11391 &mut ctx.fastbits,
11392 ctx.threads,
11393 )
11394}
11395
11396pub fn libsais16_unbwt_omp(
11407 t: &[u16],
11408 u: &mut [u16],
11409 a: &mut [SaSint],
11410 freq: Option<&[SaSint]>,
11411 i: SaSint,
11412 threads: SaSint,
11413) -> SaSint {
11414 if threads < 0 {
11415 -1
11416 } else {
11417 let primary = [i];
11418 libsais16_unbwt_aux_omp(t, u, a, freq, t.len() as SaSint, &primary, threads)
11419 }
11420}
11421
11422pub fn libsais16_unbwt_aux_omp(
11434 t: &[u16],
11435 u: &mut [u16],
11436 a: &mut [SaSint],
11437 freq: Option<&[SaSint]>,
11438 r: SaSint,
11439 i: &[SaSint],
11440 threads: SaSint,
11441) -> SaSint {
11442 if threads < 0 {
11443 -1
11444 } else {
11445 let rc = validate_unbwt_aux(t, u, a, freq, r, i);
11446 if rc != 0 {
11447 return rc;
11448 }
11449 if t.len() <= 1 {
11450 if t.len() == 1 {
11451 u[0] = t[0];
11452 }
11453 return 0;
11454 }
11455 let n = t.len();
11456 let shift = unbwt_shift(n);
11457 let mut bucket2 = vec![0usize; ALPHABET_SIZE];
11458 let mut fastbits = vec![0u16; 1 + (n >> shift)];
11459 unbwt_core_with_buffers(
11460 t,
11461 u,
11462 a,
11463 freq,
11464 r,
11465 i,
11466 &mut bucket2,
11467 &mut fastbits,
11468 normalize_threads(threads),
11469 )
11470 }
11471}
11472
11473pub fn libsais16_plcp(t: &[u16], sa: &[SaSint], plcp: &mut [SaSint]) -> SaSint {
11481 compute_plcp(t, sa, plcp, false)
11482}
11483
11484pub fn libsais16_plcp_gsa(t: &[u16], sa: &[SaSint], plcp: &mut [SaSint]) -> SaSint {
11492 if t.last().copied().unwrap_or(0) != 0 {
11493 -1
11494 } else {
11495 compute_plcp(t, sa, plcp, true)
11496 }
11497}
11498
11499fn compute_plcp(t: &[u16], sa: &[SaSint], plcp: &mut [SaSint], gsa: bool) -> SaSint {
11500 if sa.len() != t.len() || plcp.len() != t.len() {
11501 return -1;
11502 }
11503 if t.len() <= 1 {
11504 if t.len() == 1 {
11505 plcp[0] = 0;
11506 }
11507 return 0;
11508 }
11509
11510 if compute_phi(sa, plcp) != 0 {
11511 return -1;
11512 }
11513
11514 compute_plcp_from_phi(t, plcp, gsa)
11515}
11516
11517fn compute_phi(sa: &[SaSint], plcp: &mut [SaSint]) -> SaSint {
11518 let n = sa.len();
11519 let mut previous = n as SaSint;
11520 for &suffix_value in sa {
11521 let Some(suffix) = suffix_index(suffix_value, n) else {
11522 return -1;
11523 };
11524 plcp[suffix] = previous;
11525 previous = suffix_value;
11526 }
11527 0
11528}
11529
11530fn compute_plcp_from_phi(t: &[u16], plcp: &mut [SaSint], gsa: bool) -> SaSint {
11531 let n = t.len();
11532 let mut l = 0usize;
11533 for i in 0..t.len() {
11534 let previous = plcp[i];
11535 if previous == n as SaSint {
11536 plcp[i] = 0;
11537 l = 0;
11538 continue;
11539 }
11540
11541 let Some(prev) = suffix_index(previous, n) else {
11542 return -1;
11543 };
11544
11545 while i + l < t.len()
11546 && prev + l < t.len()
11547 && t[i + l] == t[prev + l]
11548 && (!gsa || t[i + l] != 0)
11549 {
11550 l += 1;
11551 }
11552 plcp[i] = l as SaSint;
11553 l = l.saturating_sub(1);
11554 }
11555 0
11556}
11557
11558fn compute_phi_omp(sa: &[SaSint], plcp: &mut [SaSint], n: SaSint, threads: SaSint) -> SaSint {
11559 let n_usize = n as usize;
11560 if threads == 1 || n < 65_536 {
11561 return compute_phi(&sa[..n_usize], &mut plcp[..n_usize]);
11562 }
11563
11564 let block_stride = (n / threads) & !15;
11565 for thread in 0..threads {
11566 let block_start = thread * block_stride;
11567 let block_size = if thread < threads - 1 {
11568 block_stride
11569 } else {
11570 n - block_start
11571 };
11572 let start = block_start as usize;
11573 let end = (block_start + block_size) as usize;
11574 let mut previous = if start > 0 { sa[start - 1] } else { n };
11575 for &suffix_value in &sa[start..end] {
11576 let Some(suffix) = suffix_index(suffix_value, n_usize) else {
11577 return -1;
11578 };
11579 plcp[suffix] = previous;
11580 previous = suffix_value;
11581 }
11582 }
11583 0
11584}
11585
11586fn compute_plcp_omp(t: &[u16], plcp: &mut [SaSint], n: SaSint, threads: SaSint) -> SaSint {
11587 if threads == 1 || n < 65_536 {
11588 let n = n as usize;
11589 return compute_plcp_from_phi(&t[..n], &mut plcp[..n], false);
11590 }
11591
11592 let block_stride = (n / threads) & !15;
11593 for thread in 0..threads {
11594 let block_start = thread * block_stride;
11595 let block_size = if thread < threads - 1 {
11596 block_stride
11597 } else {
11598 n - block_start
11599 };
11600 let rc = compute_plcp_range(
11601 t,
11602 plcp,
11603 n as usize,
11604 block_start as isize,
11605 block_size as isize,
11606 false,
11607 );
11608 if rc != 0 {
11609 return rc;
11610 }
11611 }
11612 0
11613}
11614
11615fn compute_plcp_range(
11616 t: &[u16],
11617 plcp: &mut [SaSint],
11618 n: usize,
11619 omp_block_start: isize,
11620 omp_block_size: isize,
11621 gsa: bool,
11622) -> SaSint {
11623 let mut l = 0usize;
11624 let end = (omp_block_start + omp_block_size) as usize;
11625 for i in omp_block_start as usize..end {
11626 let previous = plcp[i];
11627 if previous == n as SaSint {
11628 plcp[i] = 0;
11629 l = 0;
11630 continue;
11631 }
11632
11633 let Some(prev) = suffix_index(previous, n) else {
11634 return -1;
11635 };
11636
11637 while i + l < t.len()
11638 && prev + l < t.len()
11639 && t[i + l] == t[prev + l]
11640 && (!gsa || t[i + l] != 0)
11641 {
11642 l += 1;
11643 }
11644 plcp[i] = l as SaSint;
11645 l = l.saturating_sub(1);
11646 }
11647 0
11648}
11649
11650fn compute_plcp_gsa(
11651 t: &[u16],
11652 plcp: &mut [SaSint],
11653 omp_block_start: isize,
11654 omp_block_size: isize,
11655) -> SaSint {
11656 let n = t.len();
11657 let mut l = 0usize;
11658 let end = (omp_block_start + omp_block_size) as usize;
11659 for i in omp_block_start as usize..end {
11660 let previous = plcp[i];
11661 if previous == n as SaSint {
11662 plcp[i] = 0;
11663 l = 0;
11664 continue;
11665 }
11666
11667 let Some(prev) = suffix_index(previous, n) else {
11668 return -1;
11669 };
11670
11671 while i + l < t.len() && prev + l < t.len() && t[i + l] == t[prev + l] && t[i + l] != 0 {
11672 l += 1;
11673 }
11674 plcp[i] = l as SaSint;
11675 l = l.saturating_sub(1);
11676 }
11677 0
11678}
11679
11680fn compute_plcp_gsa_omp(t: &[u16], plcp: &mut [SaSint], n: SaSint, threads: SaSint) -> SaSint {
11681 if threads == 1 || n < 65_536 {
11682 return compute_plcp_gsa(t, plcp, 0, n as isize);
11683 }
11684
11685 let block_stride = (n / threads) & !15;
11686 for thread in 0..threads {
11687 let block_start = thread * block_stride;
11688 let block_size = if thread < threads - 1 {
11689 block_stride
11690 } else {
11691 n - block_start
11692 };
11693 let rc = compute_plcp_gsa(t, plcp, block_start as isize, block_size as isize);
11694 if rc != 0 {
11695 return rc;
11696 }
11697 }
11698 0
11699}
11700
11701fn compute_lcp(
11702 plcp: &[SaSint],
11703 sa: &[SaSint],
11704 lcp: &mut [SaSint],
11705 omp_block_start: isize,
11706 omp_block_size: isize,
11707) -> SaSint {
11708 let end = (omp_block_start + omp_block_size) as usize;
11709 for row in omp_block_start as usize..end {
11710 let Some(suffix) = suffix_index(sa[row], plcp.len()) else {
11711 return -1;
11712 };
11713 lcp[row] = plcp[suffix];
11714 }
11715 0
11716}
11717
11718fn compute_lcp_omp(
11719 plcp: &[SaSint],
11720 sa: &[SaSint],
11721 lcp: &mut [SaSint],
11722 n: SaSint,
11723 threads: SaSint,
11724) -> SaSint {
11725 if threads == 1 || n < 65_536 {
11726 return compute_lcp(plcp, sa, lcp, 0, n as isize);
11727 }
11728
11729 let block_stride = (n / threads) & !15;
11730 for thread in 0..threads {
11731 let block_start = thread * block_stride;
11732 let block_size = if thread < threads - 1 {
11733 block_stride
11734 } else {
11735 n - block_start
11736 };
11737 let rc = compute_lcp(plcp, sa, lcp, block_start as isize, block_size as isize);
11738 if rc != 0 {
11739 return rc;
11740 }
11741 }
11742 0
11743}
11744
11745pub fn libsais16_lcp(plcp: &[SaSint], sa: &[SaSint], lcp: &mut [SaSint]) -> SaSint {
11753 if plcp.len() != sa.len() || lcp.len() != sa.len() {
11754 return -1;
11755 }
11756 for (row, &suffix) in sa.iter().enumerate() {
11757 let Some(suffix) = suffix_index(suffix, plcp.len()) else {
11758 return -1;
11759 };
11760 lcp[row] = plcp[suffix];
11761 }
11762 0
11763}
11764
11765fn suffix_index(value: SaSint, len: usize) -> Option<usize> {
11766 usize::try_from(value).ok().filter(|&index| index < len)
11767}
11768
11769pub fn libsais16_plcp_omp(
11778 t: &[u16],
11779 sa: &[SaSint],
11780 plcp: &mut [SaSint],
11781 threads: SaSint,
11782) -> SaSint {
11783 if threads < 0 {
11784 return -1;
11785 }
11786 if sa.len() != t.len() || plcp.len() != t.len() {
11787 return -1;
11788 }
11789 if t.len() <= 1 {
11790 if t.len() == 1 {
11791 plcp[0] = 0;
11792 }
11793 return 0;
11794 }
11795
11796 let n = t.len() as SaSint;
11797 let threads = normalize_threads(threads);
11798 if compute_phi_omp(sa, plcp, n, threads) != 0 {
11799 return -1;
11800 }
11801 compute_plcp_omp(t, plcp, n, threads)
11802}
11803
11804pub fn libsais16_plcp_gsa_omp(
11813 t: &[u16],
11814 sa: &[SaSint],
11815 plcp: &mut [SaSint],
11816 threads: SaSint,
11817) -> SaSint {
11818 if threads < 0 {
11819 return -1;
11820 }
11821 if t.last().copied().unwrap_or(0) != 0 {
11822 return -1;
11823 }
11824 if sa.len() != t.len() || plcp.len() != t.len() {
11825 return -1;
11826 }
11827 if t.len() <= 1 {
11828 if t.len() == 1 {
11829 plcp[0] = 0;
11830 }
11831 return 0;
11832 }
11833
11834 let n = t.len() as SaSint;
11835 let threads = normalize_threads(threads);
11836 if compute_phi_omp(sa, plcp, n, threads) != 0 {
11837 return -1;
11838 }
11839 compute_plcp_gsa_omp(t, plcp, n, threads)
11840}
11841
11842pub fn libsais16_lcp_omp(
11851 plcp: &[SaSint],
11852 sa: &[SaSint],
11853 lcp: &mut [SaSint],
11854 threads: SaSint,
11855) -> SaSint {
11856 if threads < 0 {
11857 return -1;
11858 }
11859 if plcp.len() != sa.len() || lcp.len() != sa.len() {
11860 return -1;
11861 }
11862
11863 compute_lcp_omp(
11864 plcp,
11865 sa,
11866 lcp,
11867 sa.len() as SaSint,
11868 normalize_threads(threads),
11869 )
11870}
11871
11872#[cfg(all(test, feature = "upstream-c"))]
11873mod tests {
11874 use super::*;
11875
11876 unsafe extern "C" {
11877 fn probe_public_libsais16(t: *const u16, sa: *mut SaSint, n: SaSint, fs: SaSint) -> SaSint;
11878 fn probe_public_libsais16_freq(
11879 t: *const u16,
11880 sa: *mut SaSint,
11881 n: SaSint,
11882 fs: SaSint,
11883 freq: *mut SaSint,
11884 ) -> SaSint;
11885 fn probe_public_libsais16_gsa(
11886 t: *const u16,
11887 sa: *mut SaSint,
11888 n: SaSint,
11889 fs: SaSint,
11890 ) -> SaSint;
11891 fn probe_public_libsais16_gsa_freq(
11892 t: *const u16,
11893 sa: *mut SaSint,
11894 n: SaSint,
11895 fs: SaSint,
11896 freq: *mut SaSint,
11897 ) -> SaSint;
11898 fn probe_public_libsais16_int(
11899 t: *mut SaSint,
11900 sa: *mut SaSint,
11901 n: SaSint,
11902 k: SaSint,
11903 fs: SaSint,
11904 ) -> SaSint;
11905 fn probe_libsais16_main_32s_entry(
11906 t: *mut SaSint,
11907 sa: *mut SaSint,
11908 n: SaSint,
11909 k: SaSint,
11910 fs: SaSint,
11911 threads: SaSint,
11912 ) -> SaSint;
11913 fn probe_libsais16_final_sorting_scan_left_to_right_32s(
11914 t: *const SaSint,
11915 sa: *mut SaSint,
11916 induction_bucket: *mut SaSint,
11917 omp_block_start: SaSint,
11918 omp_block_size: SaSint,
11919 );
11920 fn probe_libsais16_final_sorting_scan_right_to_left_32s(
11921 t: *const SaSint,
11922 sa: *mut SaSint,
11923 induction_bucket: *mut SaSint,
11924 omp_block_start: SaSint,
11925 omp_block_size: SaSint,
11926 );
11927 fn probe_libsais16_clear_lms_suffixes_omp(
11928 sa: *mut SaSint,
11929 n: SaSint,
11930 k: SaSint,
11931 bucket_start: *mut SaSint,
11932 bucket_end: *mut SaSint,
11933 threads: SaSint,
11934 );
11935 fn probe_libsais16_flip_suffix_markers_omp(sa: *mut SaSint, l: SaSint, threads: SaSint);
11936 fn probe_libsais16_induce_final_order_32s_6k(
11937 t: *const SaSint,
11938 sa: *mut SaSint,
11939 n: SaSint,
11940 k: SaSint,
11941 buckets: *mut SaSint,
11942 threads: SaSint,
11943 );
11944 fn probe_libsais16_induce_final_order_32s_4k(
11945 t: *const SaSint,
11946 sa: *mut SaSint,
11947 n: SaSint,
11948 k: SaSint,
11949 buckets: *mut SaSint,
11950 threads: SaSint,
11951 );
11952 fn probe_libsais16_induce_final_order_32s_2k(
11953 t: *const SaSint,
11954 sa: *mut SaSint,
11955 n: SaSint,
11956 k: SaSint,
11957 buckets: *mut SaSint,
11958 threads: SaSint,
11959 );
11960 fn probe_libsais16_induce_final_order_32s_1k(
11961 t: *const SaSint,
11962 sa: *mut SaSint,
11963 n: SaSint,
11964 k: SaSint,
11965 buckets: *mut SaSint,
11966 threads: SaSint,
11967 );
11968 fn probe_libsais16_induce_partial_order_32s_6k_omp(
11969 t: *const SaSint,
11970 sa: *mut SaSint,
11971 n: SaSint,
11972 k: SaSint,
11973 buckets: *mut SaSint,
11974 first_lms_suffix: SaSint,
11975 left_suffixes_count: SaSint,
11976 threads: SaSint,
11977 );
11978 fn probe_libsais16_induce_partial_order_32s_4k_omp(
11979 t: *const SaSint,
11980 sa: *mut SaSint,
11981 n: SaSint,
11982 k: SaSint,
11983 buckets: *mut SaSint,
11984 threads: SaSint,
11985 );
11986 fn probe_libsais16_induce_partial_order_32s_2k_omp(
11987 t: *const SaSint,
11988 sa: *mut SaSint,
11989 n: SaSint,
11990 k: SaSint,
11991 buckets: *mut SaSint,
11992 threads: SaSint,
11993 );
11994 fn probe_libsais16_induce_partial_order_32s_1k_omp(
11995 t: *const SaSint,
11996 sa: *mut SaSint,
11997 n: SaSint,
11998 k: SaSint,
11999 buckets: *mut SaSint,
12000 threads: SaSint,
12001 );
12002 fn probe_libsais16_induce_partial_order_16u_omp(
12003 t: *const u16,
12004 sa: *mut SaSint,
12005 n: SaSint,
12006 k: SaSint,
12007 flags: SaSint,
12008 buckets: *mut SaSint,
12009 first_lms_suffix: SaSint,
12010 left_suffixes_count: SaSint,
12011 threads: SaSint,
12012 );
12013 fn probe_libsais16_induce_final_order_16u_omp(
12014 t: *const u16,
12015 sa: *mut SaSint,
12016 n: SaSint,
12017 k: SaSint,
12018 flags: SaSint,
12019 r: SaSint,
12020 i: *mut SaSint,
12021 buckets: *mut SaSint,
12022 threads: SaSint,
12023 ) -> SaSint;
12024 fn probe_public_libsais16_bwt(
12025 t: *const u16,
12026 u: *mut u16,
12027 a: *mut SaSint,
12028 n: SaSint,
12029 fs: SaSint,
12030 ) -> SaSint;
12031 fn probe_public_libsais16_bwt_freq(
12032 t: *const u16,
12033 u: *mut u16,
12034 a: *mut SaSint,
12035 n: SaSint,
12036 fs: SaSint,
12037 freq: *mut SaSint,
12038 ) -> SaSint;
12039 fn probe_public_libsais16_bwt_aux(
12040 t: *const u16,
12041 u: *mut u16,
12042 a: *mut SaSint,
12043 n: SaSint,
12044 fs: SaSint,
12045 r: SaSint,
12046 i: *mut SaSint,
12047 ) -> SaSint;
12048 fn probe_public_libsais16_bwt_aux_freq(
12049 t: *const u16,
12050 u: *mut u16,
12051 a: *mut SaSint,
12052 n: SaSint,
12053 fs: SaSint,
12054 freq: *mut SaSint,
12055 r: SaSint,
12056 i: *mut SaSint,
12057 ) -> SaSint;
12058 fn probe_public_libsais16_unbwt(
12059 t: *const u16,
12060 u: *mut u16,
12061 a: *mut SaSint,
12062 n: SaSint,
12063 i: SaSint,
12064 ) -> SaSint;
12065 fn probe_public_libsais16_unbwt_freq(
12066 t: *const u16,
12067 u: *mut u16,
12068 a: *mut SaSint,
12069 n: SaSint,
12070 freq: *const SaSint,
12071 i: SaSint,
12072 ) -> SaSint;
12073 fn probe_public_libsais16_unbwt_aux(
12074 t: *const u16,
12075 u: *mut u16,
12076 a: *mut SaSint,
12077 n: SaSint,
12078 r: SaSint,
12079 i: *const SaSint,
12080 ) -> SaSint;
12081 fn probe_public_libsais16_unbwt_aux_freq(
12082 t: *const u16,
12083 u: *mut u16,
12084 a: *mut SaSint,
12085 n: SaSint,
12086 freq: *const SaSint,
12087 r: SaSint,
12088 i: *const SaSint,
12089 ) -> SaSint;
12090 fn probe_public_libsais16_plcp(
12091 t: *const u16,
12092 sa: *const SaSint,
12093 plcp: *mut SaSint,
12094 n: SaSint,
12095 ) -> SaSint;
12096 fn probe_public_libsais16_plcp_gsa(
12097 t: *const u16,
12098 sa: *const SaSint,
12099 plcp: *mut SaSint,
12100 n: SaSint,
12101 ) -> SaSint;
12102 fn probe_public_libsais16_lcp(
12103 plcp: *const SaSint,
12104 sa: *const SaSint,
12105 lcp: *mut SaSint,
12106 n: SaSint,
12107 ) -> SaSint;
12108 fn probe_libsais16_gather_lms_suffixes_16u(
12109 t: *const u16,
12110 sa: *mut SaSint,
12111 n: SaSint,
12112 m: SaSint,
12113 omp_block_start: SaSint,
12114 omp_block_size: SaSint,
12115 );
12116 fn probe_libsais16_count_and_gather_lms_suffixes_16u(
12117 t: *const u16,
12118 sa: *mut SaSint,
12119 n: SaSint,
12120 buckets: *mut SaSint,
12121 omp_block_start: SaSint,
12122 omp_block_size: SaSint,
12123 ) -> SaSint;
12124 fn probe_libsais16_initialize_buckets_start_and_end_16u(
12125 buckets: *mut SaSint,
12126 freq: *mut SaSint,
12127 ) -> SaSint;
12128 fn probe_libsais16_initialize_buckets_for_lms_suffixes_radix_sort_16u(
12129 t: *const u16,
12130 buckets: *mut SaSint,
12131 first_lms_suffix: SaSint,
12132 ) -> SaSint;
12133 fn probe_libsais16_radix_sort_lms_suffixes_16u(
12134 t: *const u16,
12135 sa: *mut SaSint,
12136 induction_bucket: *mut SaSint,
12137 omp_block_start: SaSint,
12138 omp_block_size: SaSint,
12139 );
12140 fn probe_libsais16_initialize_buckets_for_partial_sorting_16u(
12141 t: *const u16,
12142 buckets: *mut SaSint,
12143 first_lms_suffix: SaSint,
12144 left_suffixes_count: SaSint,
12145 );
12146 fn probe_libsais16_partial_sorting_scan_left_to_right_16u(
12147 t: *const u16,
12148 sa: *mut SaSint,
12149 buckets: *mut SaSint,
12150 d: SaSint,
12151 omp_block_start: SaSint,
12152 omp_block_size: SaSint,
12153 ) -> SaSint;
12154 fn probe_libsais16_partial_sorting_scan_right_to_left_16u(
12155 t: *const u16,
12156 sa: *mut SaSint,
12157 buckets: *mut SaSint,
12158 d: SaSint,
12159 omp_block_start: SaSint,
12160 omp_block_size: SaSint,
12161 ) -> SaSint;
12162 fn probe_libsais16_partial_gsa_scan_right_to_left_16u(
12163 t: *const u16,
12164 sa: *mut SaSint,
12165 buckets: *mut SaSint,
12166 d: SaSint,
12167 omp_block_start: SaSint,
12168 omp_block_size: SaSint,
12169 ) -> SaSint;
12170 fn probe_libsais16_partial_sorting_shift_markers_16u_omp(
12171 sa: *mut SaSint,
12172 n: SaSint,
12173 buckets: *const SaSint,
12174 threads: SaSint,
12175 );
12176 fn probe_libsais16_final_sorting_scan_left_to_right_16u(
12177 t: *const u16,
12178 sa: *mut SaSint,
12179 induction_bucket: *mut SaSint,
12180 omp_block_start: SaSint,
12181 omp_block_size: SaSint,
12182 );
12183 fn probe_libsais16_final_sorting_scan_right_to_left_16u(
12184 t: *const u16,
12185 sa: *mut SaSint,
12186 induction_bucket: *mut SaSint,
12187 omp_block_start: SaSint,
12188 omp_block_size: SaSint,
12189 );
12190 fn probe_libsais16_final_gsa_scan_right_to_left_16u(
12191 t: *const u16,
12192 sa: *mut SaSint,
12193 induction_bucket: *mut SaSint,
12194 omp_block_start: SaSint,
12195 omp_block_size: SaSint,
12196 );
12197 fn probe_libsais16_final_bwt_scan_left_to_right_16u(
12198 t: *const u16,
12199 sa: *mut SaSint,
12200 induction_bucket: *mut SaSint,
12201 omp_block_start: SaSint,
12202 omp_block_size: SaSint,
12203 );
12204 fn probe_libsais16_final_bwt_scan_right_to_left_16u(
12205 t: *const u16,
12206 sa: *mut SaSint,
12207 induction_bucket: *mut SaSint,
12208 omp_block_start: SaSint,
12209 omp_block_size: SaSint,
12210 ) -> SaSint;
12211 fn probe_libsais16_final_bwt_aux_scan_left_to_right_16u(
12212 t: *const u16,
12213 sa: *mut SaSint,
12214 rm: SaSint,
12215 i_sample: *mut SaSint,
12216 induction_bucket: *mut SaSint,
12217 omp_block_start: SaSint,
12218 omp_block_size: SaSint,
12219 );
12220 fn probe_libsais16_final_bwt_aux_scan_right_to_left_16u(
12221 t: *const u16,
12222 sa: *mut SaSint,
12223 rm: SaSint,
12224 i_sample: *mut SaSint,
12225 induction_bucket: *mut SaSint,
12226 omp_block_start: SaSint,
12227 omp_block_size: SaSint,
12228 );
12229 fn probe_libsais16_renumber_lms_suffixes_16u(
12230 sa: *mut SaSint,
12231 m: SaSint,
12232 name: SaSint,
12233 omp_block_start: SaSint,
12234 omp_block_size: SaSint,
12235 ) -> SaSint;
12236 fn probe_libsais16_place_lms_suffixes_interval_16u(
12237 sa: *mut SaSint,
12238 n: SaSint,
12239 m: SaSint,
12240 flags: SaSint,
12241 buckets: *mut SaSint,
12242 );
12243 fn probe_libsais16_bwt_copy_16u(u: *mut u16, a: *mut SaSint, n: SaSint);
12244 fn probe_libsais16_gather_lms_suffixes_16u_omp(
12245 t: *const u16,
12246 sa: *mut SaSint,
12247 n: SaSint,
12248 threads: SaSint,
12249 );
12250 fn probe_libsais16_count_and_gather_lms_suffixes_16u_omp(
12251 t: *const u16,
12252 sa: *mut SaSint,
12253 n: SaSint,
12254 buckets: *mut SaSint,
12255 threads: SaSint,
12256 ) -> SaSint;
12257 fn probe_libsais16_radix_sort_lms_suffixes_16u_omp(
12258 t: *const u16,
12259 sa: *mut SaSint,
12260 n: SaSint,
12261 m: SaSint,
12262 flags: SaSint,
12263 buckets: *mut SaSint,
12264 threads: SaSint,
12265 );
12266 fn probe_libsais16_partial_sorting_scan_left_to_right_16u_omp(
12267 t: *const u16,
12268 sa: *mut SaSint,
12269 n: SaSint,
12270 k: SaSint,
12271 buckets: *mut SaSint,
12272 left_suffixes_count: SaSint,
12273 d: SaSint,
12274 threads: SaSint,
12275 ) -> SaSint;
12276 fn probe_libsais16_partial_sorting_scan_right_to_left_16u_omp(
12277 t: *const u16,
12278 sa: *mut SaSint,
12279 n: SaSint,
12280 k: SaSint,
12281 buckets: *mut SaSint,
12282 first_lms_suffix: SaSint,
12283 left_suffixes_count: SaSint,
12284 d: SaSint,
12285 threads: SaSint,
12286 );
12287 fn probe_libsais16_partial_gsa_scan_right_to_left_16u_omp(
12288 t: *const u16,
12289 sa: *mut SaSint,
12290 n: SaSint,
12291 k: SaSint,
12292 buckets: *mut SaSint,
12293 first_lms_suffix: SaSint,
12294 left_suffixes_count: SaSint,
12295 d: SaSint,
12296 threads: SaSint,
12297 );
12298 fn probe_libsais16_renumber_lms_suffixes_16u_omp(
12299 sa: *mut SaSint,
12300 m: SaSint,
12301 threads: SaSint,
12302 ) -> SaSint;
12303 fn probe_libsais16_final_bwt_scan_left_to_right_16u_omp(
12304 t: *const u16,
12305 sa: *mut SaSint,
12306 n: SaSint,
12307 k: SaSint,
12308 induction_bucket: *mut SaSint,
12309 threads: SaSint,
12310 );
12311 fn probe_libsais16_final_bwt_aux_scan_left_to_right_16u_omp(
12312 t: *const u16,
12313 sa: *mut SaSint,
12314 n: SaSint,
12315 k: SaSint,
12316 rm: SaSint,
12317 i_sample: *mut SaSint,
12318 induction_bucket: *mut SaSint,
12319 threads: SaSint,
12320 );
12321 fn probe_libsais16_final_sorting_scan_left_to_right_16u_omp(
12322 t: *const u16,
12323 sa: *mut SaSint,
12324 n: SaSint,
12325 k: SaSint,
12326 induction_bucket: *mut SaSint,
12327 threads: SaSint,
12328 );
12329 fn probe_libsais16_final_bwt_scan_right_to_left_16u_omp(
12330 t: *const u16,
12331 sa: *mut SaSint,
12332 n: SaSint,
12333 k: SaSint,
12334 induction_bucket: *mut SaSint,
12335 threads: SaSint,
12336 ) -> SaSint;
12337 fn probe_libsais16_final_bwt_aux_scan_right_to_left_16u_omp(
12338 t: *const u16,
12339 sa: *mut SaSint,
12340 n: SaSint,
12341 k: SaSint,
12342 rm: SaSint,
12343 i_sample: *mut SaSint,
12344 induction_bucket: *mut SaSint,
12345 threads: SaSint,
12346 );
12347 fn probe_libsais16_final_sorting_scan_right_to_left_16u_omp(
12348 t: *const u16,
12349 sa: *mut SaSint,
12350 omp_block_start: SaSint,
12351 omp_block_size: SaSint,
12352 k: SaSint,
12353 induction_bucket: *mut SaSint,
12354 threads: SaSint,
12355 );
12356 fn probe_libsais16_final_gsa_scan_right_to_left_16u_omp(
12357 t: *const u16,
12358 sa: *mut SaSint,
12359 omp_block_start: SaSint,
12360 omp_block_size: SaSint,
12361 k: SaSint,
12362 induction_bucket: *mut SaSint,
12363 threads: SaSint,
12364 );
12365 fn probe_libsais16_bwt_copy_16u_omp(
12366 u: *mut u16,
12367 a: *mut SaSint,
12368 n: SaSint,
12369 threads: SaSint,
12370 );
12371 fn probe_libsais16_gather_marked_lms_suffixes(
12372 sa: *mut SaSint,
12373 m: SaSint,
12374 l: SaSint,
12375 omp_block_start: SaSint,
12376 omp_block_size: SaSint,
12377 ) -> SaSint;
12378 fn probe_libsais16_gather_marked_lms_suffixes_omp(
12379 sa: *mut SaSint,
12380 n: SaSint,
12381 m: SaSint,
12382 fs: SaSint,
12383 threads: SaSint,
12384 );
12385 fn probe_libsais16_renumber_and_gather_lms_suffixes_omp(
12386 sa: *mut SaSint,
12387 n: SaSint,
12388 m: SaSint,
12389 fs: SaSint,
12390 threads: SaSint,
12391 ) -> SaSint;
12392 fn probe_libsais16_reconstruct_lms_suffixes(
12393 sa: *mut SaSint,
12394 n: SaSint,
12395 m: SaSint,
12396 omp_block_start: SaSint,
12397 omp_block_size: SaSint,
12398 );
12399 fn probe_libsais16_reconstruct_lms_suffixes_omp(
12400 sa: *mut SaSint,
12401 n: SaSint,
12402 m: SaSint,
12403 threads: SaSint,
12404 );
12405 fn probe_libsais16_renumber_distinct_lms_suffixes_32s_4k(
12406 sa: *mut SaSint,
12407 m: SaSint,
12408 name: SaSint,
12409 omp_block_start: SaSint,
12410 omp_block_size: SaSint,
12411 ) -> SaSint;
12412 fn probe_libsais16_mark_distinct_lms_suffixes_32s(
12413 sa: *mut SaSint,
12414 m: SaSint,
12415 omp_block_start: SaSint,
12416 omp_block_size: SaSint,
12417 );
12418 fn probe_libsais16_clamp_lms_suffixes_length_32s(
12419 sa: *mut SaSint,
12420 m: SaSint,
12421 omp_block_start: SaSint,
12422 omp_block_size: SaSint,
12423 );
12424 fn probe_libsais16_renumber_distinct_lms_suffixes_32s_4k_omp(
12425 sa: *mut SaSint,
12426 m: SaSint,
12427 threads: SaSint,
12428 ) -> SaSint;
12429 fn probe_libsais16_mark_distinct_lms_suffixes_32s_omp(
12430 sa: *mut SaSint,
12431 n: SaSint,
12432 m: SaSint,
12433 threads: SaSint,
12434 );
12435 fn probe_libsais16_clamp_lms_suffixes_length_32s_omp(
12436 sa: *mut SaSint,
12437 n: SaSint,
12438 m: SaSint,
12439 threads: SaSint,
12440 );
12441 fn probe_libsais16_renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(
12442 sa: *mut SaSint,
12443 n: SaSint,
12444 m: SaSint,
12445 threads: SaSint,
12446 ) -> SaSint;
12447 fn probe_libsais16_renumber_unique_and_nonunique_lms_suffixes_32s(
12448 t: *mut SaSint,
12449 sa: *mut SaSint,
12450 m: SaSint,
12451 f: SaSint,
12452 omp_block_start: SaSint,
12453 omp_block_size: SaSint,
12454 ) -> SaSint;
12455 fn probe_libsais16_compact_unique_and_nonunique_lms_suffixes_32s(
12456 sa: *mut SaSint,
12457 m: SaSint,
12458 pl: *mut SaSint,
12459 pr: *mut SaSint,
12460 omp_block_start: SaSint,
12461 omp_block_size: SaSint,
12462 );
12463 fn probe_libsais16_renumber_unique_and_nonunique_lms_suffixes_32s_omp(
12464 t: *mut SaSint,
12465 sa: *mut SaSint,
12466 m: SaSint,
12467 threads: SaSint,
12468 ) -> SaSint;
12469 fn probe_libsais16_compact_unique_and_nonunique_lms_suffixes_32s_omp(
12470 sa: *mut SaSint,
12471 n: SaSint,
12472 m: SaSint,
12473 fs: SaSint,
12474 f: SaSint,
12475 threads: SaSint,
12476 );
12477 fn probe_libsais16_compact_lms_suffixes_32s_omp(
12478 t: *mut SaSint,
12479 sa: *mut SaSint,
12480 n: SaSint,
12481 m: SaSint,
12482 fs: SaSint,
12483 threads: SaSint,
12484 ) -> SaSint;
12485 fn probe_libsais16_merge_unique_lms_suffixes_32s(
12486 t: *mut SaSint,
12487 sa: *mut SaSint,
12488 n: SaSint,
12489 m: SaSint,
12490 l: SaSint,
12491 omp_block_start: SaSint,
12492 omp_block_size: SaSint,
12493 );
12494 fn probe_libsais16_merge_nonunique_lms_suffixes_32s(
12495 sa: *mut SaSint,
12496 n: SaSint,
12497 m: SaSint,
12498 l: SaSint,
12499 omp_block_start: SaSint,
12500 omp_block_size: SaSint,
12501 );
12502 fn probe_libsais16_merge_unique_lms_suffixes_32s_omp(
12503 t: *mut SaSint,
12504 sa: *mut SaSint,
12505 n: SaSint,
12506 m: SaSint,
12507 threads: SaSint,
12508 );
12509 fn probe_libsais16_merge_nonunique_lms_suffixes_32s_omp(
12510 sa: *mut SaSint,
12511 n: SaSint,
12512 m: SaSint,
12513 f: SaSint,
12514 threads: SaSint,
12515 );
12516 fn probe_libsais16_merge_compacted_lms_suffixes_32s_omp(
12517 t: *mut SaSint,
12518 sa: *mut SaSint,
12519 n: SaSint,
12520 m: SaSint,
12521 f: SaSint,
12522 threads: SaSint,
12523 );
12524 fn probe_libsais16_radix_sort_lms_suffixes_32s_6k(
12525 t: *const SaSint,
12526 sa: *mut SaSint,
12527 induction_bucket: *mut SaSint,
12528 omp_block_start: SaSint,
12529 omp_block_size: SaSint,
12530 );
12531 fn probe_libsais16_radix_sort_lms_suffixes_32s_2k(
12532 t: *const SaSint,
12533 sa: *mut SaSint,
12534 induction_bucket: *mut SaSint,
12535 omp_block_start: SaSint,
12536 omp_block_size: SaSint,
12537 );
12538 fn probe_libsais16_radix_sort_lms_suffixes_32s_6k_omp(
12539 t: *const SaSint,
12540 sa: *mut SaSint,
12541 n: SaSint,
12542 m: SaSint,
12543 induction_bucket: *mut SaSint,
12544 threads: SaSint,
12545 );
12546 fn probe_libsais16_radix_sort_lms_suffixes_32s_2k_omp(
12547 t: *const SaSint,
12548 sa: *mut SaSint,
12549 n: SaSint,
12550 m: SaSint,
12551 induction_bucket: *mut SaSint,
12552 threads: SaSint,
12553 );
12554 fn probe_libsais16_radix_sort_lms_suffixes_32s_1k(
12555 t: *const SaSint,
12556 sa: *mut SaSint,
12557 n: SaSint,
12558 buckets: *mut SaSint,
12559 ) -> SaSint;
12560 fn probe_libsais16_radix_sort_set_markers_32s_6k(
12561 sa: *mut SaSint,
12562 induction_bucket: *mut SaSint,
12563 omp_block_start: SaSint,
12564 omp_block_size: SaSint,
12565 );
12566 fn probe_libsais16_radix_sort_set_markers_32s_4k(
12567 sa: *mut SaSint,
12568 induction_bucket: *mut SaSint,
12569 omp_block_start: SaSint,
12570 omp_block_size: SaSint,
12571 );
12572 fn probe_libsais16_radix_sort_set_markers_32s_6k_omp(
12573 sa: *mut SaSint,
12574 k: SaSint,
12575 induction_bucket: *mut SaSint,
12576 threads: SaSint,
12577 );
12578 fn probe_libsais16_radix_sort_set_markers_32s_4k_omp(
12579 sa: *mut SaSint,
12580 k: SaSint,
12581 induction_bucket: *mut SaSint,
12582 threads: SaSint,
12583 );
12584 fn probe_libsais16_place_lms_suffixes_histogram_32s_6k(
12585 sa: *mut SaSint,
12586 n: SaSint,
12587 k: SaSint,
12588 m: SaSint,
12589 buckets: *const SaSint,
12590 );
12591 fn probe_libsais16_place_lms_suffixes_histogram_32s_4k(
12592 sa: *mut SaSint,
12593 n: SaSint,
12594 k: SaSint,
12595 m: SaSint,
12596 buckets: *const SaSint,
12597 );
12598 fn probe_libsais16_place_lms_suffixes_histogram_32s_2k(
12599 sa: *mut SaSint,
12600 n: SaSint,
12601 k: SaSint,
12602 m: SaSint,
12603 buckets: *const SaSint,
12604 );
12605 fn probe_libsais16_gather_lms_suffixes_32s(
12606 t: *const SaSint,
12607 sa: *mut SaSint,
12608 n: SaSint,
12609 ) -> SaSint;
12610 fn probe_libsais16_gather_compacted_lms_suffixes_32s(
12611 t: *const SaSint,
12612 sa: *mut SaSint,
12613 n: SaSint,
12614 ) -> SaSint;
12615 fn probe_libsais16_count_lms_suffixes_32s_2k(
12616 t: *const SaSint,
12617 n: SaSint,
12618 k: SaSint,
12619 buckets: *mut SaSint,
12620 );
12621 fn probe_libsais16_count_and_gather_lms_suffixes_32s_4k(
12622 t: *const SaSint,
12623 sa: *mut SaSint,
12624 n: SaSint,
12625 k: SaSint,
12626 buckets: *mut SaSint,
12627 omp_block_start: SaSint,
12628 omp_block_size: SaSint,
12629 ) -> SaSint;
12630 fn probe_libsais16_count_and_gather_lms_suffixes_32s_4k_omp(
12631 t: *const SaSint,
12632 sa: *mut SaSint,
12633 n: SaSint,
12634 k: SaSint,
12635 buckets: *mut SaSint,
12636 local_buckets: SaSint,
12637 threads: SaSint,
12638 ) -> SaSint;
12639 fn probe_libsais16_count_suffixes_32s(
12640 t: *const SaSint,
12641 n: SaSint,
12642 k: SaSint,
12643 buckets: *mut SaSint,
12644 );
12645 fn probe_libsais16_initialize_buckets_start_and_end_32s_6k(k: SaSint, buckets: *mut SaSint);
12646 fn probe_libsais16_initialize_buckets_start_and_end_32s_4k(k: SaSint, buckets: *mut SaSint);
12647 fn probe_libsais16_initialize_buckets_end_32s_2k(k: SaSint, buckets: *mut SaSint);
12648 fn probe_libsais16_initialize_buckets_start_and_end_32s_2k(k: SaSint, buckets: *mut SaSint);
12649 fn probe_libsais16_initialize_buckets_start_32s_1k(k: SaSint, buckets: *mut SaSint);
12650 fn probe_libsais16_initialize_buckets_end_32s_1k(k: SaSint, buckets: *mut SaSint);
12651 fn probe_libsais16_initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(
12652 t: *const SaSint,
12653 k: SaSint,
12654 buckets: *mut SaSint,
12655 first_lms_suffix: SaSint,
12656 );
12657 fn probe_libsais16_initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(
12658 t: *const SaSint,
12659 k: SaSint,
12660 buckets: *mut SaSint,
12661 first_lms_suffix: SaSint,
12662 ) -> SaSint;
12663 fn probe_libsais16_initialize_buckets_for_radix_and_partial_sorting_32s_4k(
12664 t: *const SaSint,
12665 k: SaSint,
12666 buckets: *mut SaSint,
12667 first_lms_suffix: SaSint,
12668 );
12669 fn probe_libsais16_place_lms_suffixes_interval_32s_4k(
12670 sa: *mut SaSint,
12671 n: SaSint,
12672 k: SaSint,
12673 m: SaSint,
12674 buckets: *const SaSint,
12675 );
12676 fn probe_libsais16_place_lms_suffixes_interval_32s_2k(
12677 sa: *mut SaSint,
12678 n: SaSint,
12679 k: SaSint,
12680 m: SaSint,
12681 buckets: *const SaSint,
12682 );
12683 fn probe_libsais16_place_lms_suffixes_interval_32s_1k(
12684 t: *const SaSint,
12685 sa: *mut SaSint,
12686 k: SaSint,
12687 m: SaSint,
12688 buckets: *mut SaSint,
12689 );
12690 fn probe_libsais16_renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(
12691 t: *mut SaSint,
12692 sa: *mut SaSint,
12693 n: SaSint,
12694 m: SaSint,
12695 threads: SaSint,
12696 ) -> SaSint;
12697 fn probe_libsais16_partial_sorting_shift_markers_32s_6k_omp(
12698 sa: *mut SaSint,
12699 k: SaSint,
12700 buckets: *const SaSint,
12701 threads: SaSint,
12702 );
12703 fn probe_libsais16_partial_sorting_shift_markers_32s_4k(sa: *mut SaSint, n: SaSint);
12704 fn probe_libsais16_partial_sorting_shift_buckets_32s_6k(k: SaSint, buckets: *mut SaSint);
12705 fn probe_libsais16_partial_sorting_scan_left_to_right_32s_6k(
12706 t: *const SaSint,
12707 sa: *mut SaSint,
12708 buckets: *mut SaSint,
12709 d: SaSint,
12710 omp_block_start: SaSint,
12711 omp_block_size: SaSint,
12712 ) -> SaSint;
12713 fn probe_libsais16_partial_sorting_scan_left_to_right_32s_4k(
12714 t: *const SaSint,
12715 sa: *mut SaSint,
12716 k: SaSint,
12717 buckets: *mut SaSint,
12718 d: SaSint,
12719 omp_block_start: SaSint,
12720 omp_block_size: SaSint,
12721 ) -> SaSint;
12722 fn probe_libsais16_partial_sorting_scan_left_to_right_32s_1k(
12723 t: *const SaSint,
12724 sa: *mut SaSint,
12725 buckets: *mut SaSint,
12726 omp_block_start: SaSint,
12727 omp_block_size: SaSint,
12728 );
12729 fn probe_libsais16_partial_sorting_scan_left_to_right_32s_6k_omp(
12730 t: *const SaSint,
12731 sa: *mut SaSint,
12732 n: SaSint,
12733 buckets: *mut SaSint,
12734 left_suffixes_count: SaSint,
12735 d: SaSint,
12736 threads: SaSint,
12737 ) -> SaSint;
12738 fn probe_libsais16_partial_sorting_scan_left_to_right_32s_4k_omp(
12739 t: *const SaSint,
12740 sa: *mut SaSint,
12741 n: SaSint,
12742 k: SaSint,
12743 buckets: *mut SaSint,
12744 d: SaSint,
12745 threads: SaSint,
12746 ) -> SaSint;
12747 fn probe_libsais16_partial_sorting_scan_left_to_right_32s_1k_omp(
12748 t: *const SaSint,
12749 sa: *mut SaSint,
12750 n: SaSint,
12751 buckets: *mut SaSint,
12752 threads: SaSint,
12753 );
12754 fn probe_libsais16_partial_sorting_scan_right_to_left_32s_6k(
12755 t: *const SaSint,
12756 sa: *mut SaSint,
12757 buckets: *mut SaSint,
12758 d: SaSint,
12759 omp_block_start: SaSint,
12760 omp_block_size: SaSint,
12761 ) -> SaSint;
12762 fn probe_libsais16_partial_sorting_scan_right_to_left_32s_4k(
12763 t: *const SaSint,
12764 sa: *mut SaSint,
12765 k: SaSint,
12766 buckets: *mut SaSint,
12767 d: SaSint,
12768 omp_block_start: SaSint,
12769 omp_block_size: SaSint,
12770 ) -> SaSint;
12771 fn probe_libsais16_partial_sorting_scan_right_to_left_32s_1k(
12772 t: *const SaSint,
12773 sa: *mut SaSint,
12774 buckets: *mut SaSint,
12775 omp_block_start: SaSint,
12776 omp_block_size: SaSint,
12777 );
12778 fn probe_libsais16_partial_sorting_scan_right_to_left_32s_6k_omp(
12779 t: *const SaSint,
12780 sa: *mut SaSint,
12781 n: SaSint,
12782 buckets: *mut SaSint,
12783 first_lms_suffix: SaSint,
12784 left_suffixes_count: SaSint,
12785 d: SaSint,
12786 threads: SaSint,
12787 ) -> SaSint;
12788 fn probe_libsais16_partial_sorting_scan_right_to_left_32s_4k_omp(
12789 t: *const SaSint,
12790 sa: *mut SaSint,
12791 n: SaSint,
12792 k: SaSint,
12793 buckets: *mut SaSint,
12794 d: SaSint,
12795 threads: SaSint,
12796 ) -> SaSint;
12797 fn probe_libsais16_partial_sorting_scan_right_to_left_32s_1k_omp(
12798 t: *const SaSint,
12799 sa: *mut SaSint,
12800 n: SaSint,
12801 buckets: *mut SaSint,
12802 threads: SaSint,
12803 );
12804 fn probe_libsais16_partial_sorting_gather_lms_suffixes_32s_4k(
12805 sa: *mut SaSint,
12806 omp_block_start: SaSint,
12807 omp_block_size: SaSint,
12808 ) -> SaSint;
12809 fn probe_libsais16_partial_sorting_gather_lms_suffixes_32s_1k(
12810 sa: *mut SaSint,
12811 omp_block_start: SaSint,
12812 omp_block_size: SaSint,
12813 ) -> SaSint;
12814 fn probe_libsais16_partial_sorting_gather_lms_suffixes_32s_4k_omp(
12815 sa: *mut SaSint,
12816 n: SaSint,
12817 threads: SaSint,
12818 );
12819 fn probe_libsais16_partial_sorting_gather_lms_suffixes_32s_1k_omp(
12820 sa: *mut SaSint,
12821 n: SaSint,
12822 threads: SaSint,
12823 );
12824 fn probe_libsais16_count_and_gather_lms_suffixes_32s_2k(
12825 t: *const SaSint,
12826 sa: *mut SaSint,
12827 n: SaSint,
12828 k: SaSint,
12829 buckets: *mut SaSint,
12830 omp_block_start: SaSint,
12831 omp_block_size: SaSint,
12832 ) -> SaSint;
12833 fn probe_libsais16_count_and_gather_compacted_lms_suffixes_32s_2k(
12834 t: *const SaSint,
12835 sa: *mut SaSint,
12836 n: SaSint,
12837 k: SaSint,
12838 buckets: *mut SaSint,
12839 omp_block_start: SaSint,
12840 omp_block_size: SaSint,
12841 ) -> SaSint;
12842 fn probe_libsais16_count_and_gather_lms_suffixes_32s_2k_omp(
12843 t: *const SaSint,
12844 sa: *mut SaSint,
12845 n: SaSint,
12846 k: SaSint,
12847 buckets: *mut SaSint,
12848 local_buckets: SaSint,
12849 threads: SaSint,
12850 ) -> SaSint;
12851 fn probe_libsais16_count_and_gather_compacted_lms_suffixes_32s_2k_omp(
12852 t: *const SaSint,
12853 sa: *mut SaSint,
12854 n: SaSint,
12855 k: SaSint,
12856 buckets: *mut SaSint,
12857 local_buckets: SaSint,
12858 threads: SaSint,
12859 );
12860 fn probe_libsais16_reconstruct_compacted_lms_suffixes_32s_2k_omp(
12861 t: *mut SaSint,
12862 sa: *mut SaSint,
12863 n: SaSint,
12864 k: SaSint,
12865 m: SaSint,
12866 fs: SaSint,
12867 f: SaSint,
12868 buckets: *mut SaSint,
12869 local_buckets: SaSint,
12870 threads: SaSint,
12871 );
12872 fn probe_libsais16_reconstruct_compacted_lms_suffixes_32s_1k_omp(
12873 t: *mut SaSint,
12874 sa: *mut SaSint,
12875 n: SaSint,
12876 m: SaSint,
12877 fs: SaSint,
12878 f: SaSint,
12879 threads: SaSint,
12880 );
12881 }
12882
12883 fn brute_sa(t: &[u16]) -> Vec<SaSint> {
12884 let mut sa: Vec<_> = (0..t.len() as SaSint).collect();
12885 sa.sort_by(|&a, &b| t[a as usize..].cmp(&t[b as usize..]));
12886 sa
12887 }
12888
12889 #[test]
12890 fn libsais16_gather_lms_suffixes_16u_matches_c() {
12891 let cases: &[&[u16]] = &[
12892 &[2, 1, 3, 1, 2, 0],
12893 &[7, 7, 7, 7, 0],
12894 &[3, 1, 2, 1, 0, 4, 1, 0],
12895 &[9, 1, 9, 1, 9, 0, 2, 2, 0],
12896 ];
12897
12898 for &text in cases {
12899 let n = text.len() as SaSint;
12900 let mut rust_sa = vec![-99; text.len()];
12901 let mut c_sa = rust_sa.clone();
12902
12903 gather_lms_suffixes_16u(text, &mut rust_sa, n, n - 1, 0, n);
12904 unsafe {
12905 probe_libsais16_gather_lms_suffixes_16u(
12906 text.as_ptr(),
12907 c_sa.as_mut_ptr(),
12908 n,
12909 n - 1,
12910 0,
12911 n,
12912 );
12913 }
12914
12915 assert_eq!(rust_sa, c_sa);
12916 }
12917 }
12918
12919 #[test]
12920 fn libsais16_count_and_gather_lms_suffixes_16u_matches_c() {
12921 let cases: &[&[u16]] = &[
12922 &[2, 1, 3, 1, 2, 0],
12923 &[7, 7, 7, 7, 0],
12924 &[3, 1, 2, 1, 0, 4, 1, 0],
12925 &[9, 1, 9, 1, 9, 0, 2, 2, 0],
12926 ];
12927
12928 for &text in cases {
12929 let n = text.len() as SaSint;
12930 let mut rust_sa = vec![-99; text.len()];
12931 let mut c_sa = rust_sa.clone();
12932 let mut rust_buckets = vec![-1; 4 * ALPHABET_SIZE];
12933 let mut c_buckets = rust_buckets.clone();
12934
12935 let rust_m =
12936 count_and_gather_lms_suffixes_16u(text, &mut rust_sa, n, &mut rust_buckets, 0, n);
12937 let c_m = unsafe {
12938 probe_libsais16_count_and_gather_lms_suffixes_16u(
12939 text.as_ptr(),
12940 c_sa.as_mut_ptr(),
12941 n,
12942 c_buckets.as_mut_ptr(),
12943 0,
12944 n,
12945 )
12946 };
12947
12948 assert_eq!(rust_m, c_m);
12949 assert_eq!(rust_sa, c_sa);
12950 assert_eq!(rust_buckets, c_buckets);
12951 }
12952 }
12953
12954 #[test]
12955 fn libsais16_initialize_buckets_start_and_end_16u_matches_c() {
12956 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
12957 for (symbol, counts) in [
12958 (0usize, [1, 0, 0, 2]),
12959 (1, [0, 3, 1, 0]),
12960 (7, [2, 1, 0, 1]),
12961 (1024, [0, 0, 5, 0]),
12962 ] {
12963 for state in 0..4 {
12964 rust_buckets[buckets_index4(symbol, state)] = counts[state];
12965 }
12966 }
12967 let mut c_buckets = rust_buckets.clone();
12968 let mut rust_freq = vec![-1; ALPHABET_SIZE];
12969 let mut c_freq = rust_freq.clone();
12970
12971 let rust_k = initialize_buckets_start_and_end_16u(&mut rust_buckets, Some(&mut rust_freq));
12972 let c_k = unsafe {
12973 probe_libsais16_initialize_buckets_start_and_end_16u(
12974 c_buckets.as_mut_ptr(),
12975 c_freq.as_mut_ptr(),
12976 )
12977 };
12978
12979 assert_eq!(rust_k, c_k);
12980 assert_eq!(rust_buckets, c_buckets);
12981 assert_eq!(rust_freq, c_freq);
12982
12983 let mut rust_buckets_no_freq = vec![0; 8 * ALPHABET_SIZE];
12984 rust_buckets_no_freq[..4 * ALPHABET_SIZE]
12985 .copy_from_slice(&rust_buckets[..4 * ALPHABET_SIZE]);
12986 let mut c_buckets_no_freq = rust_buckets_no_freq.clone();
12987
12988 let rust_k = initialize_buckets_start_and_end_16u(&mut rust_buckets_no_freq, None);
12989 let c_k = unsafe {
12990 probe_libsais16_initialize_buckets_start_and_end_16u(
12991 c_buckets_no_freq.as_mut_ptr(),
12992 std::ptr::null_mut(),
12993 )
12994 };
12995
12996 assert_eq!(rust_k, c_k);
12997 assert_eq!(rust_buckets_no_freq, c_buckets_no_freq);
12998 }
12999
13000 #[test]
13001 fn libsais16_lms_radix_bucket_initialization_matches_c() {
13002 let text = [3, 1, 2, 1, 0, 4, 1, 0];
13003 let n = text.len() as SaSint;
13004 let mut rust_sa = vec![-99; text.len()];
13005 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
13006 let m = count_and_gather_lms_suffixes_16u(
13007 &text,
13008 &mut rust_sa,
13009 n,
13010 &mut rust_buckets[..4 * ALPHABET_SIZE],
13011 0,
13012 n,
13013 );
13014 initialize_buckets_start_and_end_16u(&mut rust_buckets, None);
13015 let first_lms_suffix = rust_sa[(n - m) as usize];
13016
13017 let mut c_buckets = rust_buckets.clone();
13018 let rust_count = initialize_buckets_for_lms_suffixes_radix_sort_16u(
13019 &text,
13020 &mut rust_buckets,
13021 first_lms_suffix,
13022 );
13023 let c_count = unsafe {
13024 probe_libsais16_initialize_buckets_for_lms_suffixes_radix_sort_16u(
13025 text.as_ptr(),
13026 c_buckets.as_mut_ptr(),
13027 first_lms_suffix,
13028 )
13029 };
13030
13031 assert_eq!(rust_count, c_count);
13032 assert_eq!(rust_buckets, c_buckets);
13033 }
13034
13035 #[test]
13036 fn libsais16_radix_sort_lms_suffixes_16u_matches_c() {
13037 let text = [3, 1, 2, 1, 0, 4, 1, 0];
13038 let n = text.len() as SaSint;
13039 let mut rust_sa = vec![-99; text.len()];
13040 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
13041 let m = count_and_gather_lms_suffixes_16u(
13042 &text,
13043 &mut rust_sa,
13044 n,
13045 &mut rust_buckets[..4 * ALPHABET_SIZE],
13046 0,
13047 n,
13048 );
13049 initialize_buckets_start_and_end_16u(&mut rust_buckets, None);
13050 let first_lms_suffix = rust_sa[(n - m) as usize];
13051 initialize_buckets_for_lms_suffixes_radix_sort_16u(
13052 &text,
13053 &mut rust_buckets,
13054 first_lms_suffix,
13055 );
13056
13057 let mut c_sa = rust_sa.clone();
13058 let mut c_buckets = rust_buckets.clone();
13059 {
13060 let induction_bucket = &mut rust_buckets[4 * ALPHABET_SIZE..];
13061 radix_sort_lms_suffixes_16u(&text, &mut rust_sa, induction_bucket, n - m + 1, m - 1);
13062 }
13063 unsafe {
13064 probe_libsais16_radix_sort_lms_suffixes_16u(
13065 text.as_ptr(),
13066 c_sa.as_mut_ptr(),
13067 c_buckets[4 * ALPHABET_SIZE..].as_mut_ptr(),
13068 n - m + 1,
13069 m - 1,
13070 );
13071 }
13072
13073 assert_eq!(rust_sa, c_sa);
13074 assert_eq!(rust_buckets, c_buckets);
13075 }
13076
13077 #[test]
13078 fn libsais16_initialize_buckets_for_partial_sorting_16u_matches_c() {
13079 let text = [3, 1, 2, 1, 0, 4, 1, 0];
13080 let n = text.len() as SaSint;
13081 let mut rust_sa = vec![-99; text.len()];
13082 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
13083 let m = count_and_gather_lms_suffixes_16u(
13084 &text,
13085 &mut rust_sa,
13086 n,
13087 &mut rust_buckets[..4 * ALPHABET_SIZE],
13088 0,
13089 n,
13090 );
13091 initialize_buckets_start_and_end_16u(&mut rust_buckets, None);
13092 let first_lms_suffix = rust_sa[(n - m) as usize];
13093 let left_suffixes_count = initialize_buckets_for_lms_suffixes_radix_sort_16u(
13094 &text,
13095 &mut rust_buckets,
13096 first_lms_suffix,
13097 );
13098 let mut c_buckets = rust_buckets.clone();
13099
13100 initialize_buckets_for_partial_sorting_16u(
13101 &text,
13102 &mut rust_buckets,
13103 first_lms_suffix,
13104 left_suffixes_count,
13105 );
13106 unsafe {
13107 probe_libsais16_initialize_buckets_for_partial_sorting_16u(
13108 text.as_ptr(),
13109 c_buckets.as_mut_ptr(),
13110 first_lms_suffix,
13111 left_suffixes_count,
13112 );
13113 }
13114
13115 assert_eq!(rust_buckets, c_buckets);
13116 }
13117
13118 fn partial_scan_fixture() -> ([u16; 10], Vec<SaSint>, Vec<SaSint>) {
13119 let text = [1, 0, 2, 1, 3, 0, 2, 4, 1, 0];
13120 let mut sa = vec![0; 128];
13121 sa[..5].copy_from_slice(&[3, 5 | SAINT_MIN, 7, 2, 9 | SAINT_MIN]);
13122
13123 let mut buckets = vec![0; 6 * ALPHABET_SIZE];
13124 for v in 0..32 {
13125 buckets[v] = 80 + (v as SaSint) * 4;
13126 buckets[2 * ALPHABET_SIZE + v] = if v % 3 == 0 { 2 } else { 0 };
13127 buckets[4 * ALPHABET_SIZE + v] = 20 + (v as SaSint) * 4;
13128 }
13129
13130 (text, sa, buckets)
13131 }
13132
13133 #[test]
13134 fn libsais16_partial_sorting_scan_left_to_right_16u_matches_c() {
13135 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
13136 let mut c_sa = rust_sa.clone();
13137 let mut c_buckets = rust_buckets.clone();
13138
13139 let rust_d =
13140 partial_sorting_scan_left_to_right_16u(&text, &mut rust_sa, &mut rust_buckets, 3, 0, 5);
13141 let c_d = unsafe {
13142 probe_libsais16_partial_sorting_scan_left_to_right_16u(
13143 text.as_ptr(),
13144 c_sa.as_mut_ptr(),
13145 c_buckets.as_mut_ptr(),
13146 3,
13147 0,
13148 5,
13149 )
13150 };
13151
13152 assert_eq!(rust_d, c_d);
13153 assert_eq!(rust_sa, c_sa);
13154 assert_eq!(rust_buckets, c_buckets);
13155 }
13156
13157 #[test]
13158 fn libsais16_partial_sorting_scan_right_to_left_16u_matches_c() {
13159 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
13160 let mut c_sa = rust_sa.clone();
13161 let mut c_buckets = rust_buckets.clone();
13162
13163 let rust_d =
13164 partial_sorting_scan_right_to_left_16u(&text, &mut rust_sa, &mut rust_buckets, 3, 0, 5);
13165 let c_d = unsafe {
13166 probe_libsais16_partial_sorting_scan_right_to_left_16u(
13167 text.as_ptr(),
13168 c_sa.as_mut_ptr(),
13169 c_buckets.as_mut_ptr(),
13170 3,
13171 0,
13172 5,
13173 )
13174 };
13175
13176 assert_eq!(rust_d, c_d);
13177 assert_eq!(rust_sa, c_sa);
13178 assert_eq!(rust_buckets, c_buckets);
13179 }
13180
13181 #[test]
13182 fn libsais16_partial_gsa_scan_right_to_left_16u_matches_c() {
13183 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
13184 let mut c_sa = rust_sa.clone();
13185 let mut c_buckets = rust_buckets.clone();
13186
13187 let rust_d =
13188 partial_gsa_scan_right_to_left_16u(&text, &mut rust_sa, &mut rust_buckets, 3, 0, 5);
13189 let c_d = unsafe {
13190 probe_libsais16_partial_gsa_scan_right_to_left_16u(
13191 text.as_ptr(),
13192 c_sa.as_mut_ptr(),
13193 c_buckets.as_mut_ptr(),
13194 3,
13195 0,
13196 5,
13197 )
13198 };
13199
13200 assert_eq!(rust_d, c_d);
13201 assert_eq!(rust_sa, c_sa);
13202 assert_eq!(rust_buckets, c_buckets);
13203 }
13204
13205 #[test]
13206 fn libsais16_partial_sorting_shift_markers_16u_matches_c() {
13207 let mut rust_sa = vec![0; 16];
13208 rust_sa[2..6].copy_from_slice(&[1, 2 | SAINT_MIN, 3 | SAINT_MIN, 4]);
13209 rust_sa[8..12].copy_from_slice(&[5 | SAINT_MIN, 6, 7 | SAINT_MIN, 8]);
13210 let mut c_sa = rust_sa.clone();
13211
13212 let mut buckets = vec![0; 6 * ALPHABET_SIZE];
13213 buckets[0] = 2;
13214 buckets[2] = 8;
13215 buckets[4 * ALPHABET_SIZE + 2] = 6;
13216 buckets[4 * ALPHABET_SIZE + 4] = 12;
13217
13218 let n = rust_sa.len() as SaSint;
13219 partial_sorting_shift_markers_16u_omp(&mut rust_sa, n, &buckets, 1);
13220 unsafe {
13221 probe_libsais16_partial_sorting_shift_markers_16u_omp(
13222 c_sa.as_mut_ptr(),
13223 c_sa.len() as SaSint,
13224 buckets.as_ptr(),
13225 1,
13226 );
13227 }
13228
13229 assert_eq!(rust_sa, c_sa);
13230 }
13231
13232 #[test]
13233 fn libsais16_partial_left_to_right_16u_block_omp_uses_cache_pipeline() {
13234 let block_size = 65_536usize;
13235 let k = 512usize;
13236 let text: Vec<u16> = (0..block_size + 2)
13237 .map(|i| 1 + ((i * 17 + i / 7) % (k - 1)) as u16)
13238 .collect();
13239 let sa_len = block_size + 2 * k * 100;
13240 let mut base_sa = vec![0; sa_len];
13241 for (i, slot) in base_sa.iter_mut().take(block_size).enumerate() {
13242 *slot = (i + 2) as SaSint;
13243 }
13244 let mut base_buckets = vec![0; 8 * ALPHABET_SIZE];
13245 for v in 0..2 * k {
13246 base_buckets[4 * ALPHABET_SIZE + v] = (block_size + v * 100) as SaSint;
13247 }
13248
13249 let mut scalar_sa = base_sa.clone();
13250 let mut threaded_sa = base_sa;
13251 let mut scalar_buckets = base_buckets.clone();
13252 let mut threaded_buckets = base_buckets;
13253 let mut thread_state = alloc_thread_state(4).unwrap();
13254 let scalar_d = partial_sorting_scan_left_to_right_16u(
13255 &text,
13256 &mut scalar_sa,
13257 &mut scalar_buckets,
13258 0,
13259 0,
13260 block_size as SaSint,
13261 );
13262 let threaded_d = partial_sorting_scan_left_to_right_16u_block_omp(
13263 &text,
13264 &mut threaded_sa,
13265 k as SaSint,
13266 &mut threaded_buckets,
13267 0,
13268 0,
13269 block_size as SaSint,
13270 4,
13271 &mut thread_state,
13272 );
13273
13274 assert_eq!(threaded_d, scalar_d);
13275 assert_eq!(threaded_sa, scalar_sa);
13276 assert_eq!(threaded_buckets, scalar_buckets);
13277 }
13278
13279 #[test]
13280 fn libsais16_partial_left_to_right_16u_omp_uses_block_pipeline() {
13281 let block_size = 65_536usize;
13282 let k = 512usize;
13283 let text: Vec<u16> = (0..block_size + 2)
13284 .map(|i| 1 + ((i * 17 + i / 7) % (k - 1)) as u16)
13285 .collect();
13286 let sa_len = block_size + 2 * k * 100;
13287 let mut base_sa = vec![0; sa_len];
13288 for (i, slot) in base_sa.iter_mut().take(block_size).enumerate() {
13289 let value = (i + 2) as SaSint;
13290 *slot = if i % 17 == 0 {
13291 value | SAINT_MIN
13292 } else {
13293 value
13294 };
13295 }
13296 let mut base_buckets = vec![0; 8 * ALPHABET_SIZE];
13297 for v in 0..2 * k {
13298 base_buckets[4 * ALPHABET_SIZE + v] = (block_size + v * 100) as SaSint;
13299 base_buckets[2 * ALPHABET_SIZE + v] = if v % 5 == 0 { 3 } else { 0 };
13300 }
13301
13302 let mut scalar_sa = base_sa.clone();
13303 let mut threaded_sa = base_sa;
13304 let mut scalar_buckets = base_buckets.clone();
13305 let mut threaded_buckets = base_buckets;
13306 let scalar_d = partial_sorting_scan_left_to_right_16u_omp(
13307 &text,
13308 &mut scalar_sa,
13309 text.len() as SaSint,
13310 k as SaSint,
13311 &mut scalar_buckets,
13312 block_size as SaSint,
13313 7,
13314 1,
13315 );
13316 let threaded_d = partial_sorting_scan_left_to_right_16u_omp(
13317 &text,
13318 &mut threaded_sa,
13319 text.len() as SaSint,
13320 k as SaSint,
13321 &mut threaded_buckets,
13322 block_size as SaSint,
13323 7,
13324 4,
13325 );
13326
13327 assert_eq!(threaded_d, scalar_d);
13328 assert_eq!(threaded_sa, scalar_sa);
13329 assert_eq!(threaded_buckets, scalar_buckets);
13330 }
13331
13332 #[test]
13333 fn libsais16_partial_right_to_left_16u_block_omp_uses_cache_pipeline() {
13334 let block_size = 65_536usize;
13335 let k = 512usize;
13336 let width = 2 * k;
13337 let block_start = width * 200 + 1024;
13338 let text: Vec<u16> = (0..block_size + 2)
13339 .map(|i| 1 + ((i * 17 + i / 7) % (k - 1)) as u16)
13340 .collect();
13341 let sa_len = block_start + block_size + 1;
13342 let mut base_sa = vec![0; sa_len];
13343 for i in 0..block_size {
13344 let value = (i + 2) as SaSint;
13345 base_sa[block_start + i] = if i % 17 == 0 {
13346 value | SAINT_MIN
13347 } else {
13348 value
13349 };
13350 }
13351 let mut base_buckets = vec![0; 8 * ALPHABET_SIZE];
13352 for v in 0..width {
13353 base_buckets[v] = ((v + 1) * 200) as SaSint;
13354 base_buckets[2 * ALPHABET_SIZE + v] = if v % 5 == 0 { 3 } else { 0 };
13355 }
13356
13357 let mut scalar_sa = base_sa.clone();
13358 let mut threaded_sa = base_sa.clone();
13359 let mut scalar_buckets = base_buckets.clone();
13360 let mut threaded_buckets = base_buckets.clone();
13361 let mut thread_state = alloc_thread_state(4).unwrap();
13362 let scalar_d = partial_sorting_scan_right_to_left_16u(
13363 &text,
13364 &mut scalar_sa,
13365 &mut scalar_buckets,
13366 7,
13367 block_start as SaSint,
13368 block_size as SaSint,
13369 );
13370 let threaded_d = partial_sorting_scan_right_to_left_16u_block_omp(
13371 &text,
13372 &mut threaded_sa,
13373 k as SaSint,
13374 &mut threaded_buckets,
13375 7,
13376 block_start as SaSint,
13377 block_size as SaSint,
13378 4,
13379 &mut thread_state,
13380 );
13381 assert_eq!(threaded_d, scalar_d);
13382 assert_eq!(threaded_sa, scalar_sa);
13383 assert_eq!(threaded_buckets, scalar_buckets);
13384
13385 let mut scalar_sa = base_sa;
13386 let mut threaded_sa = scalar_sa.clone();
13387 let mut scalar_buckets = base_buckets.clone();
13388 let mut threaded_buckets = base_buckets;
13389 let scalar_d = partial_gsa_scan_right_to_left_16u(
13390 &text,
13391 &mut scalar_sa,
13392 &mut scalar_buckets,
13393 7,
13394 block_start as SaSint,
13395 block_size as SaSint,
13396 );
13397 let threaded_d = partial_gsa_scan_right_to_left_16u_block_omp(
13398 &text,
13399 &mut threaded_sa,
13400 k as SaSint,
13401 &mut threaded_buckets,
13402 7,
13403 block_start as SaSint,
13404 block_size as SaSint,
13405 4,
13406 &mut thread_state,
13407 );
13408 assert_eq!(threaded_d, scalar_d);
13409 assert_eq!(threaded_sa, scalar_sa);
13410 assert_eq!(threaded_buckets, scalar_buckets);
13411 }
13412
13413 #[test]
13414 fn libsais16_partial_right_to_left_16u_omp_uses_block_pipeline() {
13415 let block_size = 65_536usize;
13416 let k = 512usize;
13417 let width = 2 * k;
13418 let block_start = width * 200 + 1024;
13419 let text: Vec<u16> = (0..block_size + 2)
13420 .map(|i| 1 + ((i * 17 + i / 7) % (k - 1)) as u16)
13421 .collect();
13422 let sa_len = block_start + block_size + 1;
13423 let n = sa_len as SaSint;
13424 let first_lms_suffix = n - (block_start + block_size) as SaSint;
13425 let left_suffixes_count = block_start as SaSint - 1;
13426 let mut base_sa = vec![0; sa_len];
13427 for i in 0..block_size {
13428 let value = (i + 2) as SaSint;
13429 base_sa[block_start + i] = if i % 17 == 0 {
13430 value | SAINT_MIN
13431 } else {
13432 value
13433 };
13434 }
13435 let mut base_buckets = vec![0; 8 * ALPHABET_SIZE];
13436 for v in 0..width {
13437 base_buckets[v] = ((v + 1) * 200) as SaSint;
13438 base_buckets[2 * ALPHABET_SIZE + v] = if v % 5 == 0 { 3 } else { 0 };
13439 }
13440
13441 let mut scalar_sa = base_sa.clone();
13442 let mut threaded_sa = base_sa.clone();
13443 let mut scalar_buckets = base_buckets.clone();
13444 let mut threaded_buckets = base_buckets.clone();
13445 partial_sorting_scan_right_to_left_16u_omp(
13446 &text,
13447 &mut scalar_sa,
13448 n,
13449 k as SaSint,
13450 &mut scalar_buckets,
13451 first_lms_suffix,
13452 left_suffixes_count,
13453 7,
13454 1,
13455 );
13456 partial_sorting_scan_right_to_left_16u_omp(
13457 &text,
13458 &mut threaded_sa,
13459 n,
13460 k as SaSint,
13461 &mut threaded_buckets,
13462 first_lms_suffix,
13463 left_suffixes_count,
13464 7,
13465 4,
13466 );
13467 assert_eq!(threaded_sa, scalar_sa);
13468 assert_eq!(threaded_buckets, scalar_buckets);
13469
13470 let mut scalar_sa = base_sa;
13471 let mut threaded_sa = scalar_sa.clone();
13472 let mut scalar_buckets = base_buckets.clone();
13473 let mut threaded_buckets = base_buckets;
13474 partial_gsa_scan_right_to_left_16u_omp(
13475 &text,
13476 &mut scalar_sa,
13477 n,
13478 k as SaSint,
13479 &mut scalar_buckets,
13480 first_lms_suffix,
13481 left_suffixes_count,
13482 7,
13483 1,
13484 );
13485 partial_gsa_scan_right_to_left_16u_omp(
13486 &text,
13487 &mut threaded_sa,
13488 n,
13489 k as SaSint,
13490 &mut threaded_buckets,
13491 first_lms_suffix,
13492 left_suffixes_count,
13493 7,
13494 4,
13495 );
13496 assert_eq!(threaded_sa, scalar_sa);
13497 assert_eq!(threaded_buckets, scalar_buckets);
13498 }
13499
13500 fn final_scan_fixture() -> ([u16; 10], Vec<SaSint>, Vec<SaSint>) {
13501 let text = [1, 0, 2, 1, 3, 0, 2, 4, 1, 0];
13502 let mut sa = vec![0; 96];
13503 sa[..6].copy_from_slice(&[3, 0, 5 | SAINT_MIN, 7, 2, 9 | SAINT_MIN]);
13504
13505 let mut induction_bucket = vec![0; ALPHABET_SIZE];
13506 for c in 0..8 {
13507 induction_bucket[c] = 24 + (c as SaSint) * 6;
13508 }
13509
13510 (text, sa, induction_bucket)
13511 }
13512
13513 fn final_order_buckets(induction_bucket: &[SaSint]) -> Vec<SaSint> {
13514 let mut buckets = vec![0; 8 * ALPHABET_SIZE];
13515 buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE].copy_from_slice(induction_bucket);
13516 buckets[7 * ALPHABET_SIZE..8 * ALPHABET_SIZE].copy_from_slice(induction_bucket);
13517 buckets
13518 }
13519
13520 #[test]
13521 fn libsais16_final_sorting_scan_left_to_right_16u_matches_c() {
13522 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
13523 let mut c_sa = rust_sa.clone();
13524 let mut c_bucket = rust_bucket.clone();
13525
13526 final_sorting_scan_left_to_right_16u(&text, &mut rust_sa, &mut rust_bucket, 0, 6);
13527 unsafe {
13528 probe_libsais16_final_sorting_scan_left_to_right_16u(
13529 text.as_ptr(),
13530 c_sa.as_mut_ptr(),
13531 c_bucket.as_mut_ptr(),
13532 0,
13533 6,
13534 );
13535 }
13536
13537 assert_eq!(rust_sa, c_sa);
13538 assert_eq!(rust_bucket, c_bucket);
13539 }
13540
13541 #[test]
13542 fn libsais16_final_sorting_scan_right_to_left_16u_matches_c() {
13543 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
13544 let mut c_sa = rust_sa.clone();
13545 let mut c_bucket = rust_bucket.clone();
13546
13547 final_sorting_scan_right_to_left_16u(&text, &mut rust_sa, &mut rust_bucket, 0, 6);
13548 unsafe {
13549 probe_libsais16_final_sorting_scan_right_to_left_16u(
13550 text.as_ptr(),
13551 c_sa.as_mut_ptr(),
13552 c_bucket.as_mut_ptr(),
13553 0,
13554 6,
13555 );
13556 }
13557
13558 assert_eq!(rust_sa, c_sa);
13559 assert_eq!(rust_bucket, c_bucket);
13560 }
13561
13562 #[test]
13563 fn libsais16_final_gsa_scan_right_to_left_16u_matches_c() {
13564 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
13565 let mut c_sa = rust_sa.clone();
13566 let mut c_bucket = rust_bucket.clone();
13567
13568 final_gsa_scan_right_to_left_16u(&text, &mut rust_sa, &mut rust_bucket, 0, 6);
13569 unsafe {
13570 probe_libsais16_final_gsa_scan_right_to_left_16u(
13571 text.as_ptr(),
13572 c_sa.as_mut_ptr(),
13573 c_bucket.as_mut_ptr(),
13574 0,
13575 6,
13576 );
13577 }
13578
13579 assert_eq!(rust_sa, c_sa);
13580 assert_eq!(rust_bucket, c_bucket);
13581 }
13582
13583 #[test]
13584 fn libsais16_final_sorting_32s_helpers_behave_like_upstream_shapes() {
13585 let t = vec![0, 1, 2, 1, 0, 1, 2, 1, 0];
13586
13587 let mut rust_sa = vec![1, 0, 0];
13588 let mut rust_bucket = vec![0, 1, 3];
13589 let mut c_sa = rust_sa.clone();
13590 let mut c_bucket = rust_bucket.clone();
13591 final_sorting_scan_left_to_right_32s(&t, &mut rust_sa, &mut rust_bucket, 0, 1);
13592 unsafe {
13593 probe_libsais16_final_sorting_scan_left_to_right_32s(
13594 t.as_ptr(),
13595 c_sa.as_mut_ptr(),
13596 c_bucket.as_mut_ptr(),
13597 0,
13598 1,
13599 );
13600 }
13601 assert_eq!(rust_sa, c_sa);
13602 assert_eq!(rust_bucket, c_bucket);
13603
13604 let mut rust_sa = vec![0, 2, 0];
13605 let mut rust_bucket = vec![1, 2, 3];
13606 let mut c_sa = rust_sa.clone();
13607 let mut c_bucket = rust_bucket.clone();
13608 final_sorting_scan_right_to_left_32s(&t, &mut rust_sa, &mut rust_bucket, 0, 2);
13609 unsafe {
13610 probe_libsais16_final_sorting_scan_right_to_left_32s(
13611 t.as_ptr(),
13612 c_sa.as_mut_ptr(),
13613 c_bucket.as_mut_ptr(),
13614 0,
13615 2,
13616 );
13617 }
13618 assert_eq!(rust_sa, c_sa);
13619 assert_eq!(rust_bucket, c_bucket);
13620
13621 let mut sa = vec![1, 2, 0, 0];
13622 let mut induction_bucket = vec![0, 1, 3];
13623 let mut cache = vec![ThreadCache::default(); PER_THREAD_CACHE_SIZE];
13624 final_sorting_scan_left_to_right_32s_block_omp(
13625 &t,
13626 &mut sa,
13627 &mut induction_bucket,
13628 &mut cache,
13629 0,
13630 2,
13631 2,
13632 );
13633 assert_eq!(sa[0] & SAINT_MAX, 0);
13634 assert_eq!(sa[1] & SAINT_MAX, 1);
13635 assert_eq!(induction_bucket[0], 1);
13636 assert_eq!(induction_bucket[1], 2);
13637
13638 let mut sa = vec![0, 2, 0, 0];
13639 let mut induction_bucket = vec![1, 2, 3];
13640 let mut cache = vec![ThreadCache::default(); PER_THREAD_CACHE_SIZE];
13641 final_sorting_scan_right_to_left_32s_block_omp(
13642 &t,
13643 &mut sa,
13644 &mut induction_bucket,
13645 &mut cache,
13646 0,
13647 2,
13648 2,
13649 );
13650 assert_eq!(sa[1] & SAINT_MAX, 1);
13651 assert_eq!(induction_bucket[1], 1);
13652 }
13653
13654 #[test]
13655 fn libsais16_final_left_to_right_16u_block_omp_uses_cache_pipeline() {
13656 let block_size = 65_536usize;
13657 let k = 512usize;
13658 let text: Vec<u16> = (0..=block_size).map(|i| 1 + (i % (k - 1)) as u16).collect();
13659 let sa_len = block_size + k * 200;
13660 let mut base_sa = vec![0; sa_len];
13661 for (i, slot) in base_sa.iter_mut().take(block_size).enumerate() {
13662 *slot = (i + 1) as SaSint;
13663 }
13664 let mut base_bucket = vec![0; k];
13665 for c in 0..k {
13666 base_bucket[c] = (block_size + c * 200) as SaSint;
13667 }
13668
13669 let mut scalar_sa = base_sa.clone();
13670 let mut threaded_sa = base_sa.clone();
13671 let mut scalar_bucket = base_bucket.clone();
13672 let mut threaded_bucket = base_bucket.clone();
13673 let mut thread_state = alloc_thread_state(4).unwrap();
13674 final_bwt_scan_left_to_right_16u(
13675 &text,
13676 &mut scalar_sa,
13677 &mut scalar_bucket,
13678 0,
13679 block_size as SaSint,
13680 );
13681 final_bwt_scan_left_to_right_16u_block_omp(
13682 &text,
13683 &mut threaded_sa,
13684 k as SaSint,
13685 &mut threaded_bucket,
13686 0,
13687 block_size as SaSint,
13688 4,
13689 &mut thread_state,
13690 );
13691 assert_eq!(threaded_sa, scalar_sa);
13692 assert_eq!(threaded_bucket, scalar_bucket);
13693
13694 let rm = 3;
13695 let mut scalar_sa = base_sa.clone();
13696 let mut threaded_sa = base_sa.clone();
13697 let mut scalar_bucket = base_bucket.clone();
13698 let mut threaded_bucket = base_bucket.clone();
13699 let mut scalar_i = vec![-1; (block_size / (rm as usize + 1)) + 2];
13700 let mut threaded_i = scalar_i.clone();
13701 final_bwt_aux_scan_left_to_right_16u(
13702 &text,
13703 &mut scalar_sa,
13704 rm,
13705 &mut scalar_i,
13706 &mut scalar_bucket,
13707 0,
13708 block_size as SaSint,
13709 );
13710 final_bwt_aux_scan_left_to_right_16u_block_omp(
13711 &text,
13712 &mut threaded_sa,
13713 k as SaSint,
13714 rm,
13715 &mut threaded_i,
13716 &mut threaded_bucket,
13717 0,
13718 block_size as SaSint,
13719 4,
13720 &mut thread_state,
13721 );
13722 assert_eq!(threaded_sa, scalar_sa);
13723 assert_eq!(threaded_i, scalar_i);
13724 assert_eq!(threaded_bucket, scalar_bucket);
13725
13726 let mut scalar_sa = base_sa;
13727 let mut threaded_sa = scalar_sa.clone();
13728 let mut scalar_bucket = base_bucket.clone();
13729 let mut threaded_bucket = base_bucket;
13730 final_sorting_scan_left_to_right_16u(
13731 &text,
13732 &mut scalar_sa,
13733 &mut scalar_bucket,
13734 0,
13735 block_size as SaSint,
13736 );
13737 final_sorting_scan_left_to_right_16u_block_omp(
13738 &text,
13739 &mut threaded_sa,
13740 k as SaSint,
13741 &mut threaded_bucket,
13742 0,
13743 block_size as SaSint,
13744 4,
13745 &mut thread_state,
13746 );
13747 assert_eq!(threaded_sa, scalar_sa);
13748 assert_eq!(threaded_bucket, scalar_bucket);
13749 }
13750
13751 #[test]
13752 fn libsais16_final_right_to_left_16u_block_omp_uses_cache_pipeline() {
13753 let block_size = 65_536usize;
13754 let k = 512usize;
13755 let block_start = k * 200 + 1024;
13756 let text: Vec<u16> = (0..=block_size + 1)
13757 .map(|i| 1 + (i % (k - 1)) as u16)
13758 .collect();
13759 let sa_len = block_start + block_size + 1;
13760 let mut base_sa = vec![0; sa_len];
13761 for i in 0..block_size {
13762 base_sa[block_start + i] = (i + 1) as SaSint;
13763 }
13764 let mut base_bucket = vec![0; k];
13765 for c in 0..k {
13766 base_bucket[c] = ((c + 1) * 200) as SaSint;
13767 }
13768
13769 let mut scalar_sa = base_sa.clone();
13770 let mut threaded_sa = base_sa.clone();
13771 let mut scalar_bucket = base_bucket.clone();
13772 let mut threaded_bucket = base_bucket.clone();
13773 let mut thread_state = alloc_thread_state(4).unwrap();
13774 final_bwt_scan_right_to_left_16u(
13775 &text,
13776 &mut scalar_sa,
13777 &mut scalar_bucket,
13778 block_start as SaSint,
13779 block_size as SaSint,
13780 );
13781 final_bwt_scan_right_to_left_16u_block_omp(
13782 &text,
13783 &mut threaded_sa,
13784 k as SaSint,
13785 &mut threaded_bucket,
13786 block_start as SaSint,
13787 block_size as SaSint,
13788 4,
13789 &mut thread_state,
13790 );
13791 assert_eq!(threaded_sa, scalar_sa);
13792 assert_eq!(threaded_bucket, scalar_bucket);
13793
13794 let rm = 3;
13795 let mut scalar_sa = base_sa.clone();
13796 let mut threaded_sa = base_sa.clone();
13797 let mut scalar_bucket = base_bucket.clone();
13798 let mut threaded_bucket = base_bucket.clone();
13799 let mut scalar_i = vec![-1; (block_size / (rm as usize + 1)) + 2];
13800 let mut threaded_i = scalar_i.clone();
13801 final_bwt_aux_scan_right_to_left_16u(
13802 &text,
13803 &mut scalar_sa,
13804 rm,
13805 &mut scalar_i,
13806 &mut scalar_bucket,
13807 block_start as SaSint,
13808 block_size as SaSint,
13809 );
13810 final_bwt_aux_scan_right_to_left_16u_block_omp(
13811 &text,
13812 &mut threaded_sa,
13813 k as SaSint,
13814 rm,
13815 &mut threaded_i,
13816 &mut threaded_bucket,
13817 block_start as SaSint,
13818 block_size as SaSint,
13819 4,
13820 &mut thread_state,
13821 );
13822 assert_eq!(threaded_sa, scalar_sa);
13823 assert_eq!(threaded_i, scalar_i);
13824 assert_eq!(threaded_bucket, scalar_bucket);
13825
13826 let mut scalar_sa = base_sa.clone();
13827 let mut threaded_sa = base_sa.clone();
13828 let mut scalar_bucket = base_bucket.clone();
13829 let mut threaded_bucket = base_bucket.clone();
13830 final_sorting_scan_right_to_left_16u(
13831 &text,
13832 &mut scalar_sa,
13833 &mut scalar_bucket,
13834 block_start as SaSint,
13835 block_size as SaSint,
13836 );
13837 final_sorting_scan_right_to_left_16u_block_omp(
13838 &text,
13839 &mut threaded_sa,
13840 k as SaSint,
13841 &mut threaded_bucket,
13842 block_start as SaSint,
13843 block_size as SaSint,
13844 4,
13845 &mut thread_state,
13846 );
13847 assert_eq!(threaded_sa, scalar_sa);
13848 assert_eq!(threaded_bucket, scalar_bucket);
13849
13850 let mut scalar_sa = base_sa;
13851 let mut threaded_sa = scalar_sa.clone();
13852 let mut scalar_bucket = base_bucket.clone();
13853 let mut threaded_bucket = base_bucket;
13854 final_gsa_scan_right_to_left_16u(
13855 &text,
13856 &mut scalar_sa,
13857 &mut scalar_bucket,
13858 block_start as SaSint,
13859 block_size as SaSint,
13860 );
13861 final_gsa_scan_right_to_left_16u_block_omp(
13862 &text,
13863 &mut threaded_sa,
13864 k as SaSint,
13865 &mut threaded_bucket,
13866 block_start as SaSint,
13867 block_size as SaSint,
13868 4,
13869 &mut thread_state,
13870 );
13871 assert_eq!(threaded_sa, scalar_sa);
13872 assert_eq!(threaded_bucket, scalar_bucket);
13873 }
13874
13875 #[test]
13876 fn libsais16_clear_lms_suffixes_omp_zeroes_requested_bucket_ranges() {
13877 let mut rust_sa = vec![5, 4, 3, 2, 1, 9];
13878 let mut c_sa = rust_sa.clone();
13879 let n = rust_sa.len() as SaSint;
13880 let mut bucket_start = vec![1, 4, 5];
13881 let mut bucket_end = vec![3, 5, 5];
13882
13883 clear_lms_suffixes_omp(&mut rust_sa, n, 3, &bucket_start, &bucket_end, 2);
13884 unsafe {
13885 probe_libsais16_clear_lms_suffixes_omp(
13886 c_sa.as_mut_ptr(),
13887 n,
13888 3,
13889 bucket_start.as_mut_ptr(),
13890 bucket_end.as_mut_ptr(),
13891 2,
13892 );
13893 }
13894
13895 assert_eq!(rust_sa, c_sa);
13896 }
13897
13898 #[test]
13899 fn libsais16_partial_order_wrapper_helpers_match_manual_sequence() {
13900 let mut rust_sa = vec![1, 2, 3, 4];
13901 let mut c_sa = rust_sa.clone();
13902 flip_suffix_markers_omp(&mut rust_sa, 3, 2);
13903 unsafe {
13904 probe_libsais16_flip_suffix_markers_omp(c_sa.as_mut_ptr(), 3, 2);
13905 }
13906 assert_eq!(rust_sa, c_sa);
13907
13908 let t = vec![0, 1, 2, 1, 0, 1, 2, 1, 0];
13909 let n = t.len() as SaSint;
13910 let k = 3;
13911 let mut wrapped_sa = vec![0; t.len()];
13912 let mut wrapped_buckets = vec![0; k as usize];
13913 let mut wrapped_state = alloc_thread_state(1).unwrap();
13914 induce_partial_order_32s_1k_omp(
13915 &t,
13916 &mut wrapped_sa,
13917 n,
13918 k,
13919 &mut wrapped_buckets,
13920 1,
13921 &mut wrapped_state,
13922 );
13923
13924 let mut manual_sa = vec![0; t.len()];
13925 let mut manual_buckets = vec![0; k as usize];
13926 let mut manual_state = alloc_thread_state(1).unwrap();
13927 count_suffixes_32s(&t, n, k, &mut manual_buckets);
13928 initialize_buckets_start_32s_1k(k, &mut manual_buckets);
13929 partial_sorting_scan_left_to_right_32s_1k_omp(
13930 &t,
13931 &mut manual_sa,
13932 n,
13933 &mut manual_buckets,
13934 1,
13935 &mut manual_state,
13936 );
13937 count_suffixes_32s(&t, n, k, &mut manual_buckets);
13938 initialize_buckets_end_32s_1k(k, &mut manual_buckets);
13939 partial_sorting_scan_right_to_left_32s_1k_omp(
13940 &t,
13941 &mut manual_sa,
13942 n,
13943 &mut manual_buckets,
13944 1,
13945 &mut manual_state,
13946 );
13947 partial_sorting_gather_lms_suffixes_32s_1k_omp(&mut manual_sa, n, 1, &mut manual_state);
13948
13949 assert_eq!(wrapped_sa, manual_sa);
13950 assert_eq!(wrapped_buckets, manual_buckets);
13951 }
13952
13953 #[test]
13954 fn libsais16_induce_partial_order_32s_wrappers_match_c() {
13955 let t = make_main_32s_stress_text(128, 24);
13956 let n = t.len() as SaSint;
13957 let k = 24;
13958 let threads = 1;
13959
13960 let mut rust_sa = vec![0; t.len()];
13961 let mut rust_buckets = vec![0; 6 * k as usize];
13962 let mut rust_state = alloc_thread_state(threads).unwrap();
13963 let m = count_and_gather_lms_suffixes_32s_4k_omp(
13964 &t,
13965 &mut rust_sa,
13966 n,
13967 k,
13968 &mut rust_buckets,
13969 1,
13970 threads,
13971 &mut rust_state,
13972 );
13973 assert!(m > 1);
13974 rust_sa[..(n - m) as usize].fill(0);
13975 let first_lms_suffix = rust_sa[(n - m) as usize];
13976 let left_suffixes_count = initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(
13977 &t,
13978 k,
13979 &mut rust_buckets,
13980 first_lms_suffix,
13981 );
13982 let (_, induction_bucket) = rust_buckets.split_at_mut(4 * k as usize);
13983 radix_sort_lms_suffixes_32s_6k_omp(&t, &mut rust_sa, n, m, induction_bucket, threads);
13984 radix_sort_set_markers_32s_6k_omp(&mut rust_sa, k, induction_bucket, threads);
13985 initialize_buckets_for_partial_sorting_32s_6k(
13986 &t,
13987 k,
13988 &mut rust_buckets,
13989 first_lms_suffix,
13990 left_suffixes_count,
13991 );
13992 let mut c_sa = rust_sa.clone();
13993 let mut c_buckets = rust_buckets.clone();
13994 induce_partial_order_32s_6k_omp(
13995 &t,
13996 &mut rust_sa,
13997 n,
13998 k,
13999 &mut rust_buckets,
14000 first_lms_suffix,
14001 left_suffixes_count,
14002 threads,
14003 &mut rust_state,
14004 );
14005 unsafe {
14006 probe_libsais16_induce_partial_order_32s_6k_omp(
14007 t.as_ptr(),
14008 c_sa.as_mut_ptr(),
14009 n,
14010 k,
14011 c_buckets.as_mut_ptr(),
14012 first_lms_suffix,
14013 left_suffixes_count,
14014 threads,
14015 );
14016 }
14017 assert_eq!(rust_sa, c_sa);
14018 assert_eq!(rust_buckets, c_buckets);
14019
14020 let mut rust_sa = vec![0; t.len()];
14021 let mut rust_buckets = vec![0; 4 * k as usize];
14022 let mut rust_state = alloc_thread_state(threads).unwrap();
14023 let m = count_and_gather_lms_suffixes_32s_2k_omp(
14024 &t,
14025 &mut rust_sa,
14026 n,
14027 k,
14028 &mut rust_buckets,
14029 1,
14030 threads,
14031 &mut rust_state,
14032 );
14033 assert!(m > 1);
14034 let first_lms_suffix = rust_sa[(n - m) as usize];
14035 initialize_buckets_for_radix_and_partial_sorting_32s_4k(
14036 &t,
14037 k,
14038 &mut rust_buckets,
14039 first_lms_suffix,
14040 );
14041 let (_, induction_bucket) = rust_buckets.split_at_mut(1);
14042 radix_sort_lms_suffixes_32s_2k_omp(&t, &mut rust_sa, n, m, induction_bucket, threads);
14043 radix_sort_set_markers_32s_4k_omp(&mut rust_sa, k, induction_bucket, threads);
14044 place_lms_suffixes_interval_32s_4k(&mut rust_sa, n, k, m - 1, &rust_buckets);
14045 let mut c_sa = rust_sa.clone();
14046 let mut c_buckets = rust_buckets.clone();
14047 induce_partial_order_32s_4k_omp(
14048 &t,
14049 &mut rust_sa,
14050 n,
14051 k,
14052 &mut rust_buckets,
14053 threads,
14054 &mut rust_state,
14055 );
14056 unsafe {
14057 probe_libsais16_induce_partial_order_32s_4k_omp(
14058 t.as_ptr(),
14059 c_sa.as_mut_ptr(),
14060 n,
14061 k,
14062 c_buckets.as_mut_ptr(),
14063 threads,
14064 );
14065 }
14066 assert_eq!(rust_sa, c_sa);
14067 assert_eq!(rust_buckets, c_buckets);
14068
14069 let mut rust_sa = vec![0; t.len()];
14070 let mut rust_buckets = vec![0; 2 * k as usize];
14071 let mut rust_state = alloc_thread_state(threads).unwrap();
14072 let m = count_and_gather_lms_suffixes_32s_2k_omp(
14073 &t,
14074 &mut rust_sa,
14075 n,
14076 k,
14077 &mut rust_buckets,
14078 1,
14079 threads,
14080 &mut rust_state,
14081 );
14082 assert!(m > 1);
14083 let first_lms_suffix = rust_sa[(n - m) as usize];
14084 initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(
14085 &t,
14086 k,
14087 &mut rust_buckets,
14088 first_lms_suffix,
14089 );
14090 let (_, induction_bucket) = rust_buckets.split_at_mut(1);
14091 radix_sort_lms_suffixes_32s_2k_omp(&t, &mut rust_sa, n, m, induction_bucket, threads);
14092 place_lms_suffixes_interval_32s_2k(&mut rust_sa, n, k, m - 1, &rust_buckets);
14093 initialize_buckets_start_and_end_32s_2k(k, &mut rust_buckets);
14094 let mut c_sa = rust_sa.clone();
14095 let mut c_buckets = rust_buckets.clone();
14096 induce_partial_order_32s_2k_omp(
14097 &t,
14098 &mut rust_sa,
14099 n,
14100 k,
14101 &mut rust_buckets,
14102 threads,
14103 &mut rust_state,
14104 );
14105 unsafe {
14106 probe_libsais16_induce_partial_order_32s_2k_omp(
14107 t.as_ptr(),
14108 c_sa.as_mut_ptr(),
14109 n,
14110 k,
14111 c_buckets.as_mut_ptr(),
14112 threads,
14113 );
14114 }
14115 assert_eq!(rust_sa, c_sa);
14116 assert_eq!(rust_buckets, c_buckets);
14117
14118 let mut rust_sa = vec![0; t.len()];
14119 let mut rust_buckets = vec![0; k as usize];
14120 let mut rust_state = alloc_thread_state(threads).unwrap();
14121 count_suffixes_32s(&t, n, k, &mut rust_buckets);
14122 initialize_buckets_end_32s_1k(k, &mut rust_buckets);
14123 let m = radix_sort_lms_suffixes_32s_1k(&t, &mut rust_sa, n, &mut rust_buckets);
14124 assert!(m > 1);
14125 let mut c_sa = rust_sa.clone();
14126 let mut c_buckets = rust_buckets.clone();
14127 induce_partial_order_32s_1k_omp(
14128 &t,
14129 &mut rust_sa,
14130 n,
14131 k,
14132 &mut rust_buckets,
14133 threads,
14134 &mut rust_state,
14135 );
14136 unsafe {
14137 probe_libsais16_induce_partial_order_32s_1k_omp(
14138 t.as_ptr(),
14139 c_sa.as_mut_ptr(),
14140 n,
14141 k,
14142 c_buckets.as_mut_ptr(),
14143 threads,
14144 );
14145 }
14146 assert_eq!(rust_sa, c_sa);
14147 assert_eq!(rust_buckets, c_buckets);
14148 }
14149
14150 #[test]
14151 fn libsais16_induce_partial_order_16u_omp_matches_c() {
14152 let text = [3, 1, 2, 1, 0, 4, 1, 0];
14153 let n = text.len() as SaSint;
14154 let flags = 0;
14155 let threads = 1;
14156 let mut rust_sa = vec![0; text.len()];
14157 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
14158
14159 let m = count_and_gather_lms_suffixes_16u_omp(
14160 &text,
14161 &mut rust_sa,
14162 n,
14163 &mut rust_buckets[..4 * ALPHABET_SIZE],
14164 threads,
14165 &mut [],
14166 );
14167 let k = initialize_buckets_start_and_end_16u(&mut rust_buckets, None);
14168 assert!(m > 0);
14169 let first_lms_suffix = rust_sa[(n - m) as usize];
14170 let left_suffixes_count = initialize_buckets_for_lms_suffixes_radix_sort_16u(
14171 &text,
14172 &mut rust_buckets,
14173 first_lms_suffix,
14174 );
14175 radix_sort_lms_suffixes_16u_omp(
14176 &text,
14177 &mut rust_sa,
14178 n,
14179 m,
14180 flags,
14181 &mut rust_buckets,
14182 threads,
14183 &mut [],
14184 );
14185 initialize_buckets_for_partial_sorting_16u(
14186 &text,
14187 &mut rust_buckets,
14188 first_lms_suffix,
14189 left_suffixes_count,
14190 );
14191
14192 let mut c_sa = rust_sa.clone();
14193 let mut c_buckets = rust_buckets.clone();
14194 induce_partial_order_16u_omp(
14195 &text,
14196 &mut rust_sa,
14197 n,
14198 k,
14199 flags,
14200 &mut rust_buckets,
14201 first_lms_suffix,
14202 left_suffixes_count,
14203 threads,
14204 );
14205 unsafe {
14206 probe_libsais16_induce_partial_order_16u_omp(
14207 text.as_ptr(),
14208 c_sa.as_mut_ptr(),
14209 n,
14210 k,
14211 flags,
14212 c_buckets.as_mut_ptr(),
14213 first_lms_suffix,
14214 left_suffixes_count,
14215 threads,
14216 );
14217 }
14218
14219 assert_eq!(rust_sa, c_sa);
14220 assert_eq!(rust_buckets, c_buckets);
14221 }
14222
14223 fn final_order_32s_fixture() -> (Vec<SaSint>, Vec<SaSint>) {
14224 (
14225 vec![0, 1, 2, 1, 0, 1, 2, 1, 0],
14226 vec![1, 0, 2, 0, 0, 0, 0, 0, 0],
14227 )
14228 }
14229
14230 fn seed_final_order_bucket_sections(buckets: &mut [SaSint], k: usize, branch_k: usize) {
14231 let left = [0, 1, 3];
14232 let right = [1, 2, 3];
14233 let left_section = match branch_k {
14234 6 => 4 * k,
14235 4 => 2 * k,
14236 2 => k,
14237 _ => 0,
14238 };
14239 let right_section = match branch_k {
14240 6 => 5 * k,
14241 4 => 3 * k,
14242 2 => 0,
14243 _ => 0,
14244 };
14245 buckets[left_section..left_section + k].copy_from_slice(&left);
14246 buckets[right_section..right_section + k].copy_from_slice(&right);
14247 }
14248
14249 #[test]
14250 fn libsais16_induce_final_order_32s_wrappers_match_c() {
14251 let (t, sa) = final_order_32s_fixture();
14252 let n = t.len() as SaSint;
14253 let k = 3;
14254 let threads = 1;
14255
14256 let mut rust_sa = sa.clone();
14257 let mut rust_buckets = vec![0; 6 * k as usize];
14258 seed_final_order_bucket_sections(&mut rust_buckets, k as usize, 6);
14259 let mut c_sa = rust_sa.clone();
14260 let mut c_buckets = rust_buckets.clone();
14261 let mut rust_state = alloc_thread_state(threads).unwrap();
14262 induce_final_order_32s_6k(
14263 &t,
14264 &mut rust_sa,
14265 n,
14266 k,
14267 &mut rust_buckets,
14268 threads,
14269 &mut rust_state,
14270 );
14271 unsafe {
14272 probe_libsais16_induce_final_order_32s_6k(
14273 t.as_ptr(),
14274 c_sa.as_mut_ptr(),
14275 n,
14276 k,
14277 c_buckets.as_mut_ptr(),
14278 threads,
14279 );
14280 }
14281 assert_eq!(rust_sa, c_sa);
14282 assert_eq!(rust_buckets, c_buckets);
14283
14284 let mut rust_sa = sa.clone();
14285 let mut rust_buckets = vec![0; 4 * k as usize];
14286 seed_final_order_bucket_sections(&mut rust_buckets, k as usize, 4);
14287 let mut c_sa = rust_sa.clone();
14288 let mut c_buckets = rust_buckets.clone();
14289 let mut rust_state = alloc_thread_state(threads).unwrap();
14290 induce_final_order_32s_4k(
14291 &t,
14292 &mut rust_sa,
14293 n,
14294 k,
14295 &mut rust_buckets,
14296 threads,
14297 &mut rust_state,
14298 );
14299 unsafe {
14300 probe_libsais16_induce_final_order_32s_4k(
14301 t.as_ptr(),
14302 c_sa.as_mut_ptr(),
14303 n,
14304 k,
14305 c_buckets.as_mut_ptr(),
14306 threads,
14307 );
14308 }
14309 assert_eq!(rust_sa, c_sa);
14310 assert_eq!(rust_buckets, c_buckets);
14311
14312 let mut rust_sa = sa.clone();
14313 let mut rust_buckets = vec![0; 2 * k as usize];
14314 seed_final_order_bucket_sections(&mut rust_buckets, k as usize, 2);
14315 let mut c_sa = rust_sa.clone();
14316 let mut c_buckets = rust_buckets.clone();
14317 let mut rust_state = alloc_thread_state(threads).unwrap();
14318 induce_final_order_32s_2k(
14319 &t,
14320 &mut rust_sa,
14321 n,
14322 k,
14323 &mut rust_buckets,
14324 threads,
14325 &mut rust_state,
14326 );
14327 unsafe {
14328 probe_libsais16_induce_final_order_32s_2k(
14329 t.as_ptr(),
14330 c_sa.as_mut_ptr(),
14331 n,
14332 k,
14333 c_buckets.as_mut_ptr(),
14334 threads,
14335 );
14336 }
14337 assert_eq!(rust_sa, c_sa);
14338 assert_eq!(rust_buckets, c_buckets);
14339
14340 let mut rust_sa = sa;
14341 let mut rust_buckets = vec![0; k as usize];
14342 let mut c_sa = rust_sa.clone();
14343 let mut c_buckets = rust_buckets.clone();
14344 let mut rust_state = alloc_thread_state(threads).unwrap();
14345 induce_final_order_32s_1k(
14346 &t,
14347 &mut rust_sa,
14348 n,
14349 k,
14350 &mut rust_buckets,
14351 threads,
14352 &mut rust_state,
14353 );
14354 unsafe {
14355 probe_libsais16_induce_final_order_32s_1k(
14356 t.as_ptr(),
14357 c_sa.as_mut_ptr(),
14358 n,
14359 k,
14360 c_buckets.as_mut_ptr(),
14361 threads,
14362 );
14363 }
14364 assert_eq!(rust_sa, c_sa);
14365 assert_eq!(rust_buckets, c_buckets);
14366 }
14367
14368 #[test]
14369 fn libsais16_induce_final_order_16u_omp_matches_manual_sequence() {
14370 let (text, mut wrapped_sa, induction_bucket) = final_scan_fixture();
14371 let mut wrapped_buckets = final_order_buckets(&induction_bucket);
14372 let mut c_sa = wrapped_sa.clone();
14373 let mut c_buckets = wrapped_buckets.clone();
14374 let mut wrapped_state = alloc_thread_state(1).unwrap();
14375 let wrapped_index = induce_final_order_16u_omp(
14376 &text,
14377 &mut wrapped_sa,
14378 text.len() as SaSint,
14379 8,
14380 0,
14381 0,
14382 None,
14383 &mut wrapped_buckets,
14384 1,
14385 &mut wrapped_state,
14386 );
14387 let c_index = unsafe {
14388 probe_libsais16_induce_final_order_16u_omp(
14389 text.as_ptr(),
14390 c_sa.as_mut_ptr(),
14391 text.len() as SaSint,
14392 8,
14393 0,
14394 0,
14395 std::ptr::null_mut(),
14396 c_buckets.as_mut_ptr(),
14397 1,
14398 )
14399 };
14400
14401 let (text, mut manual_sa, induction_bucket) = final_scan_fixture();
14402 let mut manual_buckets = final_order_buckets(&induction_bucket);
14403 {
14404 let (left_buckets, right_tail) = manual_buckets.split_at_mut(7 * ALPHABET_SIZE);
14405 final_sorting_scan_left_to_right_16u_omp(
14406 &text,
14407 &mut manual_sa,
14408 text.len() as SaSint,
14409 8,
14410 &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE],
14411 1,
14412 );
14413 final_sorting_scan_right_to_left_16u_omp(
14414 &text,
14415 &mut manual_sa,
14416 0,
14417 text.len() as SaSint,
14418 8,
14419 &mut right_tail[..ALPHABET_SIZE],
14420 1,
14421 );
14422 }
14423
14424 assert_eq!(wrapped_index, 0);
14425 assert_eq!(wrapped_index, c_index);
14426 assert_eq!(wrapped_sa, manual_sa);
14427 assert_eq!(wrapped_sa, c_sa);
14428 assert_eq!(wrapped_buckets, manual_buckets);
14429 assert_eq!(wrapped_buckets, c_buckets);
14430
14431 let (text, mut wrapped_sa, induction_bucket) = final_scan_fixture();
14432 let mut wrapped_buckets = final_order_buckets(&induction_bucket);
14433 let mut c_sa = wrapped_sa.clone();
14434 let mut c_buckets = wrapped_buckets.clone();
14435 let mut wrapped_state = alloc_thread_state(1).unwrap();
14436 let wrapped_index = induce_final_order_16u_omp(
14437 &text,
14438 &mut wrapped_sa,
14439 text.len() as SaSint,
14440 8,
14441 LIBSAIS_FLAGS_BWT,
14442 0,
14443 None,
14444 &mut wrapped_buckets,
14445 1,
14446 &mut wrapped_state,
14447 );
14448 let c_index = unsafe {
14449 probe_libsais16_induce_final_order_16u_omp(
14450 text.as_ptr(),
14451 c_sa.as_mut_ptr(),
14452 text.len() as SaSint,
14453 8,
14454 LIBSAIS_FLAGS_BWT,
14455 0,
14456 std::ptr::null_mut(),
14457 c_buckets.as_mut_ptr(),
14458 1,
14459 )
14460 };
14461
14462 let (text, mut manual_sa, induction_bucket) = final_scan_fixture();
14463 let mut manual_buckets = final_order_buckets(&induction_bucket);
14464 let manual_index = {
14465 let (left_buckets, right_tail) = manual_buckets.split_at_mut(7 * ALPHABET_SIZE);
14466 final_bwt_scan_left_to_right_16u_omp(
14467 &text,
14468 &mut manual_sa,
14469 text.len() as SaSint,
14470 8,
14471 &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE],
14472 1,
14473 );
14474 final_bwt_scan_right_to_left_16u_omp(
14475 &text,
14476 &mut manual_sa,
14477 text.len() as SaSint,
14478 8,
14479 &mut right_tail[..ALPHABET_SIZE],
14480 1,
14481 )
14482 };
14483
14484 assert_eq!(wrapped_index, manual_index);
14485 assert_eq!(wrapped_index, c_index);
14486 assert_eq!(wrapped_sa, manual_sa);
14487 assert_eq!(wrapped_sa, c_sa);
14488 assert_eq!(wrapped_buckets, manual_buckets);
14489 assert_eq!(wrapped_buckets, c_buckets);
14490
14491 let (text, mut wrapped_sa, induction_bucket) = final_scan_fixture();
14492 let mut wrapped_buckets = final_order_buckets(&induction_bucket);
14493 let mut c_sa = wrapped_sa.clone();
14494 let mut c_buckets = wrapped_buckets.clone();
14495 let mut wrapped_state = alloc_thread_state(1).unwrap();
14496 let mut wrapped_i = vec![-1; 8];
14497 let mut c_i = wrapped_i.clone();
14498 let wrapped_index = induce_final_order_16u_omp(
14499 &text,
14500 &mut wrapped_sa,
14501 text.len() as SaSint,
14502 8,
14503 LIBSAIS_FLAGS_BWT,
14504 2,
14505 Some(&mut wrapped_i),
14506 &mut wrapped_buckets,
14507 1,
14508 &mut wrapped_state,
14509 );
14510 let c_index = unsafe {
14511 probe_libsais16_induce_final_order_16u_omp(
14512 text.as_ptr(),
14513 c_sa.as_mut_ptr(),
14514 text.len() as SaSint,
14515 8,
14516 LIBSAIS_FLAGS_BWT,
14517 2,
14518 c_i.as_mut_ptr(),
14519 c_buckets.as_mut_ptr(),
14520 1,
14521 )
14522 };
14523
14524 let (text, mut manual_sa, induction_bucket) = final_scan_fixture();
14525 let mut manual_buckets = final_order_buckets(&induction_bucket);
14526 let mut manual_i = vec![-1; 8];
14527 {
14528 let (left_buckets, right_tail) = manual_buckets.split_at_mut(7 * ALPHABET_SIZE);
14529 final_bwt_aux_scan_left_to_right_16u_omp(
14530 &text,
14531 &mut manual_sa,
14532 text.len() as SaSint,
14533 8,
14534 1,
14535 &mut manual_i,
14536 &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE],
14537 1,
14538 );
14539 final_bwt_aux_scan_right_to_left_16u_omp(
14540 &text,
14541 &mut manual_sa,
14542 text.len() as SaSint,
14543 8,
14544 1,
14545 &mut manual_i,
14546 &mut right_tail[..ALPHABET_SIZE],
14547 1,
14548 );
14549 }
14550
14551 assert_eq!(wrapped_index, 0);
14552 assert_eq!(wrapped_index, c_index);
14553 assert_eq!(wrapped_sa, manual_sa);
14554 assert_eq!(wrapped_sa, c_sa);
14555 assert_eq!(wrapped_buckets, manual_buckets);
14556 assert_eq!(wrapped_buckets, c_buckets);
14557 assert_eq!(wrapped_i, manual_i);
14558 assert_eq!(wrapped_i, c_i);
14559 }
14560
14561 #[test]
14562 fn libsais16_main_16u_matches_public_c_suffix_array_paths() {
14563 let text = [3, 1, 4, 1, 5, 9, 0, 2];
14564 let n = text.len() as SaSint;
14565 let fs = 32;
14566 let mut rust_sa = vec![0; text.len() + fs as usize];
14567 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
14568 let mut rust_freq = vec![0; ALPHABET_SIZE];
14569 let mut rust_state = alloc_thread_state(1).unwrap();
14570 let rust_index = main_16u(
14571 &text,
14572 &mut rust_sa,
14573 n,
14574 &mut rust_buckets,
14575 0,
14576 0,
14577 None,
14578 fs,
14579 Some(&mut rust_freq),
14580 1,
14581 &mut rust_state,
14582 );
14583
14584 let mut c_sa = vec![0; text.len() + fs as usize];
14585 let mut c_freq = vec![0; ALPHABET_SIZE];
14586 let c_index = unsafe {
14587 probe_public_libsais16_freq(
14588 text.as_ptr(),
14589 c_sa.as_mut_ptr(),
14590 n,
14591 fs,
14592 c_freq.as_mut_ptr(),
14593 )
14594 };
14595
14596 assert_eq!(rust_index, c_index);
14597 assert_eq!(&rust_sa[..text.len()], &c_sa[..text.len()]);
14598 assert_eq!(rust_freq, c_freq);
14599
14600 let text = [2, 1, 0, 2, 0];
14601 let n = text.len() as SaSint;
14602 let fs = 24;
14603 let mut rust_sa = vec![0; text.len() + fs as usize];
14604 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
14605 let mut rust_freq = vec![0; ALPHABET_SIZE];
14606 let mut rust_state = alloc_thread_state(1).unwrap();
14607 let rust_index = main_16u(
14608 &text,
14609 &mut rust_sa,
14610 n,
14611 &mut rust_buckets,
14612 LIBSAIS_FLAGS_GSA,
14613 0,
14614 None,
14615 fs,
14616 Some(&mut rust_freq),
14617 1,
14618 &mut rust_state,
14619 );
14620
14621 let mut c_sa = vec![0; text.len() + fs as usize];
14622 let mut c_freq = vec![0; ALPHABET_SIZE];
14623 let c_index = unsafe {
14624 probe_public_libsais16_gsa_freq(
14625 text.as_ptr(),
14626 c_sa.as_mut_ptr(),
14627 n,
14628 fs,
14629 c_freq.as_mut_ptr(),
14630 )
14631 };
14632
14633 assert_eq!(rust_index, c_index);
14634 assert_eq!(&rust_sa[..text.len()], &c_sa[..text.len()]);
14635 assert_eq!(rust_freq, c_freq);
14636 }
14637
14638 fn make_main_32s_stress_text(len: usize, alphabet: SaSint) -> Vec<SaSint> {
14639 let mut state: u32 = 0x1357_9bdf;
14640 let mut t = Vec::with_capacity(len + 1);
14641
14642 for i in 0..len {
14643 state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
14644 let mut value = ((state >> 16) % (alphabet as u32 - 1)) as SaSint + 1;
14645 if i % 17 < 8 {
14646 value = ((i / 17) as SaSint % 11) + 1;
14647 }
14648 if i % 29 < 10 {
14649 value = (((i / 29) as SaSint * 3) % 19) + 1;
14650 }
14651 if i % 64 >= 48 {
14652 value = t[i - 48];
14653 }
14654 t.push(value);
14655 }
14656
14657 t.push(0);
14658 t
14659 }
14660
14661 fn make_recursive_main_32s_text(repeats: usize) -> Vec<SaSint> {
14662 let motif = [9, 4, 9, 2, 9, 4, 9, 1];
14663 let mut t = Vec::with_capacity(repeats * motif.len() + 1);
14664 for _ in 0..repeats {
14665 t.extend_from_slice(&motif);
14666 }
14667 t.push(0);
14668 t
14669 }
14670
14671 fn assert_main_32s_entry_matches_c(mut t: Vec<SaSint>, k: SaSint, fs: SaSint) {
14672 let n = t.len() as SaSint;
14673 let threads = 1;
14674 let mut sa = vec![0; t.len() + fs as usize];
14675 let initial_t = t.clone();
14676 let initial_sa = sa.clone();
14677
14678 let c_result = unsafe {
14679 probe_libsais16_main_32s_entry(t.as_mut_ptr(), sa.as_mut_ptr(), n, k, fs, threads)
14680 };
14681 let c_t = t.clone();
14682 let c_sa = sa.clone();
14683
14684 t.copy_from_slice(&initial_t);
14685 sa.copy_from_slice(&initial_sa);
14686
14687 let mut thread_state = alloc_thread_state(threads).unwrap();
14688 let rust_result = main_32s_entry(
14689 t.as_mut_ptr(),
14690 &mut sa,
14691 n,
14692 k,
14693 fs,
14694 threads,
14695 &mut thread_state,
14696 );
14697
14698 assert_eq!(rust_result, c_result);
14699 assert_eq!(t, c_t);
14700 assert_eq!(sa, c_sa);
14701 }
14702
14703 #[test]
14704 fn libsais16_main_32s_entry_matches_c_for_local_32s_paths() {
14705 assert_main_32s_entry_matches_c(make_main_32s_stress_text(1024, 300), 300, 2048);
14706 assert_main_32s_entry_matches_c(make_main_32s_stress_text(1024, 400), 400, 2048);
14707 assert_main_32s_entry_matches_c(make_main_32s_stress_text(1024, 700), 700, 2048);
14708 assert_main_32s_entry_matches_c(make_main_32s_stress_text(1024, 1501), 1501, 2048);
14709 assert_main_32s_entry_matches_c(make_recursive_main_32s_text(24), 300, 0);
14710 assert_main_32s_entry_matches_c(make_recursive_main_32s_text(24), 1501, 0);
14711 }
14712
14713 #[test]
14714 fn libsais16_final_bwt_scan_left_to_right_16u_matches_c() {
14715 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
14716 let mut c_sa = rust_sa.clone();
14717 let mut c_bucket = rust_bucket.clone();
14718
14719 final_bwt_scan_left_to_right_16u(&text, &mut rust_sa, &mut rust_bucket, 0, 6);
14720 unsafe {
14721 probe_libsais16_final_bwt_scan_left_to_right_16u(
14722 text.as_ptr(),
14723 c_sa.as_mut_ptr(),
14724 c_bucket.as_mut_ptr(),
14725 0,
14726 6,
14727 );
14728 }
14729
14730 assert_eq!(rust_sa, c_sa);
14731 assert_eq!(rust_bucket, c_bucket);
14732 }
14733
14734 #[test]
14735 fn libsais16_final_bwt_scan_right_to_left_16u_matches_c() {
14736 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
14737 let mut c_sa = rust_sa.clone();
14738 let mut c_bucket = rust_bucket.clone();
14739
14740 let rust_index =
14741 final_bwt_scan_right_to_left_16u(&text, &mut rust_sa, &mut rust_bucket, 0, 6);
14742 let c_index = unsafe {
14743 probe_libsais16_final_bwt_scan_right_to_left_16u(
14744 text.as_ptr(),
14745 c_sa.as_mut_ptr(),
14746 c_bucket.as_mut_ptr(),
14747 0,
14748 6,
14749 )
14750 };
14751
14752 assert_eq!(rust_index, c_index);
14753 assert_eq!(rust_sa, c_sa);
14754 assert_eq!(rust_bucket, c_bucket);
14755 }
14756
14757 #[test]
14758 fn libsais16_final_bwt_aux_scan_left_to_right_16u_matches_c() {
14759 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
14760 let mut c_sa = rust_sa.clone();
14761 let mut c_bucket = rust_bucket.clone();
14762 let mut rust_i = vec![-1; 8];
14763 let mut c_i = rust_i.clone();
14764
14765 final_bwt_aux_scan_left_to_right_16u(
14766 &text,
14767 &mut rust_sa,
14768 1,
14769 &mut rust_i,
14770 &mut rust_bucket,
14771 0,
14772 6,
14773 );
14774 unsafe {
14775 probe_libsais16_final_bwt_aux_scan_left_to_right_16u(
14776 text.as_ptr(),
14777 c_sa.as_mut_ptr(),
14778 1,
14779 c_i.as_mut_ptr(),
14780 c_bucket.as_mut_ptr(),
14781 0,
14782 6,
14783 );
14784 }
14785
14786 assert_eq!(rust_sa, c_sa);
14787 assert_eq!(rust_bucket, c_bucket);
14788 assert_eq!(rust_i, c_i);
14789 }
14790
14791 #[test]
14792 fn libsais16_final_bwt_aux_scan_right_to_left_16u_matches_c() {
14793 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
14794 let mut c_sa = rust_sa.clone();
14795 let mut c_bucket = rust_bucket.clone();
14796 let mut rust_i = vec![-1; 8];
14797 let mut c_i = rust_i.clone();
14798
14799 final_bwt_aux_scan_right_to_left_16u(
14800 &text,
14801 &mut rust_sa,
14802 1,
14803 &mut rust_i,
14804 &mut rust_bucket,
14805 0,
14806 6,
14807 );
14808 unsafe {
14809 probe_libsais16_final_bwt_aux_scan_right_to_left_16u(
14810 text.as_ptr(),
14811 c_sa.as_mut_ptr(),
14812 1,
14813 c_i.as_mut_ptr(),
14814 c_bucket.as_mut_ptr(),
14815 0,
14816 6,
14817 );
14818 }
14819
14820 assert_eq!(rust_sa, c_sa);
14821 assert_eq!(rust_bucket, c_bucket);
14822 assert_eq!(rust_i, c_i);
14823 }
14824
14825 #[test]
14826 fn libsais16_renumber_lms_suffixes_16u_matches_c() {
14827 let m = 6;
14828 let mut rust_sa = vec![0; 20];
14829 rust_sa[..m].copy_from_slice(&[2, 4 | SAINT_MIN, 6, 8 | SAINT_MIN, 10, 12 | SAINT_MIN]);
14830 let mut c_sa = rust_sa.clone();
14831
14832 let rust_name = renumber_lms_suffixes_16u(&mut rust_sa, m as SaSint, 5, 0, m as SaSint);
14833 let c_name = unsafe {
14834 probe_libsais16_renumber_lms_suffixes_16u(
14835 c_sa.as_mut_ptr(),
14836 m as SaSint,
14837 5,
14838 0,
14839 m as SaSint,
14840 )
14841 };
14842
14843 assert_eq!(rust_name, c_name);
14844 assert_eq!(rust_sa, c_sa);
14845 }
14846
14847 fn lms_interval_fixture() -> (Vec<SaSint>, Vec<SaSint>) {
14848 let mut sa = vec![-7; 16];
14849 sa[4..8].copy_from_slice(&[41, 42, 61, 62]);
14850
14851 let mut buckets = vec![0; 8 * ALPHABET_SIZE];
14852 buckets[buckets_index2(2, 1)] = 0;
14853 buckets[buckets_index2(3, 1)] = 2;
14854 buckets[buckets_index2(4, 1)] = 2;
14855 buckets[buckets_index2(5, 1)] = 2;
14856 buckets[buckets_index2(6, 1)] = 4;
14857 buckets[buckets_index2(7, 1)] = 4;
14858 buckets[7 * ALPHABET_SIZE + 2] = 6;
14859 buckets[7 * ALPHABET_SIZE + 5] = 12;
14860
14861 (sa, buckets)
14862 }
14863
14864 #[test]
14865 fn libsais16_place_lms_suffixes_interval_16u_matches_c() {
14866 for flags in [0, LIBSAIS_FLAGS_GSA] {
14867 let (mut rust_sa, mut rust_buckets) = lms_interval_fixture();
14868 let mut c_sa = rust_sa.clone();
14869 let mut c_buckets = rust_buckets.clone();
14870
14871 place_lms_suffixes_interval_16u(&mut rust_sa, 16, 8, flags, &mut rust_buckets);
14872 unsafe {
14873 probe_libsais16_place_lms_suffixes_interval_16u(
14874 c_sa.as_mut_ptr(),
14875 16,
14876 8,
14877 flags,
14878 c_buckets.as_mut_ptr(),
14879 );
14880 }
14881
14882 assert_eq!(rust_sa, c_sa);
14883 assert_eq!(rust_buckets, c_buckets);
14884 }
14885 }
14886
14887 #[test]
14888 fn libsais16_bwt_copy_16u_matches_c() {
14889 let mut a = vec![0, 1, 65535, 65536, -1, -2, 70000, 17, 131071, -65536];
14890 let mut rust_u = vec![999; a.len()];
14891 let mut c_u = rust_u.clone();
14892
14893 bwt_copy_16u(&mut rust_u, &a, a.len() as SaSint);
14894 unsafe {
14895 probe_libsais16_bwt_copy_16u(c_u.as_mut_ptr(), a.as_mut_ptr(), a.len() as SaSint);
14896 }
14897
14898 assert_eq!(rust_u, c_u);
14899 }
14900
14901 #[test]
14902 fn libsais16_early_omp_wrappers_match_c() {
14903 let text = [3, 1, 2, 1, 0, 4, 1, 0];
14904 let n = text.len() as SaSint;
14905
14906 let mut rust_sa = vec![-99; text.len()];
14907 let mut c_sa = rust_sa.clone();
14908 gather_lms_suffixes_16u_omp(&text, &mut rust_sa, n, 1, &mut []);
14909 unsafe {
14910 probe_libsais16_gather_lms_suffixes_16u_omp(text.as_ptr(), c_sa.as_mut_ptr(), n, 1);
14911 }
14912 assert_eq!(rust_sa, c_sa);
14913
14914 let mut rust_sa = vec![-99; text.len()];
14915 let mut c_sa = rust_sa.clone();
14916 let mut rust_buckets = vec![-1; 4 * ALPHABET_SIZE];
14917 let mut c_buckets = rust_buckets.clone();
14918 let rust_m = count_and_gather_lms_suffixes_16u_omp(
14919 &text,
14920 &mut rust_sa,
14921 n,
14922 &mut rust_buckets,
14923 1,
14924 &mut [],
14925 );
14926 let c_m = unsafe {
14927 probe_libsais16_count_and_gather_lms_suffixes_16u_omp(
14928 text.as_ptr(),
14929 c_sa.as_mut_ptr(),
14930 n,
14931 c_buckets.as_mut_ptr(),
14932 1,
14933 )
14934 };
14935 assert_eq!(rust_m, c_m);
14936 assert_eq!(rust_sa, c_sa);
14937 assert_eq!(rust_buckets, c_buckets);
14938
14939 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
14940 let m = count_and_gather_lms_suffixes_16u(
14941 &text,
14942 &mut rust_sa,
14943 n,
14944 &mut rust_buckets[..4 * ALPHABET_SIZE],
14945 0,
14946 n,
14947 );
14948 initialize_buckets_start_and_end_16u(&mut rust_buckets, None);
14949 let first_lms_suffix = rust_sa[(n - m) as usize];
14950 initialize_buckets_for_lms_suffixes_radix_sort_16u(
14951 &text,
14952 &mut rust_buckets,
14953 first_lms_suffix,
14954 );
14955 let mut c_sa = rust_sa.clone();
14956 let mut c_buckets = rust_buckets.clone();
14957 radix_sort_lms_suffixes_16u_omp(
14958 &text,
14959 &mut rust_sa,
14960 n,
14961 m,
14962 0,
14963 &mut rust_buckets,
14964 1,
14965 &mut [],
14966 );
14967 unsafe {
14968 probe_libsais16_radix_sort_lms_suffixes_16u_omp(
14969 text.as_ptr(),
14970 c_sa.as_mut_ptr(),
14971 n,
14972 m,
14973 0,
14974 c_buckets.as_mut_ptr(),
14975 1,
14976 );
14977 }
14978 assert_eq!(rust_sa, c_sa);
14979 assert_eq!(rust_buckets, c_buckets);
14980 }
14981
14982 #[test]
14983 fn libsais16_early_omp_wrappers_use_block_partition_for_large_inputs() {
14984 let n = 65_600usize;
14985 let text: Vec<u16> = (0..n)
14986 .map(|i| 1 + ((i * 37 + i / 17) % 509) as u16)
14987 .collect();
14988
14989 let mut gathered_threaded = vec![-99; n];
14990 let mut gathered_scalar = vec![-99; n];
14991 let mut thread_state = alloc_thread_state(4).unwrap();
14992 let mut count_sa = vec![-99; n];
14993 let mut count_buckets = vec![0; 4 * ALPHABET_SIZE];
14994 count_and_gather_lms_suffixes_16u_omp(
14995 &text,
14996 &mut count_sa,
14997 n as SaSint,
14998 &mut count_buckets,
14999 4,
15000 &mut thread_state,
15001 );
15002 gather_lms_suffixes_16u_omp(
15003 &text,
15004 &mut gathered_threaded,
15005 n as SaSint,
15006 4,
15007 &mut thread_state,
15008 );
15009 gather_lms_suffixes_16u(
15010 &text,
15011 &mut gathered_scalar,
15012 n as SaSint,
15013 n as SaSint - 1,
15014 0,
15015 n as SaSint,
15016 );
15017 assert_eq!(gathered_threaded, gathered_scalar);
15018
15019 let mut sa_threaded = vec![-99; n];
15020 let mut sa_scalar = vec![-99; n];
15021 let mut buckets_threaded = vec![0; 4 * ALPHABET_SIZE];
15022 let mut buckets_scalar = vec![0; 4 * ALPHABET_SIZE];
15023 let m_threaded = count_and_gather_lms_suffixes_16u_omp(
15024 &text,
15025 &mut sa_threaded,
15026 n as SaSint,
15027 &mut buckets_threaded,
15028 4,
15029 &mut thread_state,
15030 );
15031 let m_scalar = count_and_gather_lms_suffixes_16u(
15032 &text,
15033 &mut sa_scalar,
15034 n as SaSint,
15035 &mut buckets_scalar,
15036 0,
15037 n as SaSint,
15038 );
15039 assert_eq!(m_threaded, m_scalar);
15040 assert_eq!(
15041 &sa_threaded[n - m_threaded as usize..],
15042 &sa_scalar[n - m_scalar as usize..]
15043 );
15044 assert_eq!(buckets_threaded, buckets_scalar);
15045 }
15046
15047 #[test]
15048 fn libsais16_late_omp_wrappers_match_c() {
15049 let m = 6;
15050 let mut rust_sa = vec![0; 20];
15051 rust_sa[..m].copy_from_slice(&[2, 4 | SAINT_MIN, 6, 8 | SAINT_MIN, 10, 12 | SAINT_MIN]);
15052 let mut c_sa = rust_sa.clone();
15053 let mut rust_thread_state = alloc_thread_state(1).unwrap();
15054 let rust_name =
15055 renumber_lms_suffixes_16u_omp(&mut rust_sa, m as SaSint, 1, &mut rust_thread_state);
15056 let c_name = unsafe {
15057 probe_libsais16_renumber_lms_suffixes_16u_omp(c_sa.as_mut_ptr(), m as SaSint, 1)
15058 };
15059 assert_eq!(rust_name, c_name);
15060 assert_eq!(rust_sa, c_sa);
15061
15062 let mut a = vec![0, 1, 65535, 65536, -1, -2, 70000, 17, 131071, -65536];
15063 let mut rust_u = vec![999; a.len()];
15064 let mut c_u = rust_u.clone();
15065 bwt_copy_16u_omp(&mut rust_u, &a, a.len() as SaSint, 1);
15066 unsafe {
15067 probe_libsais16_bwt_copy_16u_omp(
15068 c_u.as_mut_ptr(),
15069 a.as_mut_ptr(),
15070 a.len() as SaSint,
15071 1,
15072 );
15073 }
15074 assert_eq!(rust_u, c_u);
15075 }
15076
15077 #[test]
15078 fn libsais16_gather_marked_lms_suffixes_matches_c() {
15079 let mut rust_sa = vec![0, 0, 3 | SAINT_MIN, 4, 5 | SAINT_MIN, 6, -7, 8];
15080 let mut c_sa = rust_sa.clone();
15081
15082 let rust_l = gather_marked_lms_suffixes(&mut rust_sa, 2, 8, 0, 4) as SaSint;
15083 let c_l =
15084 unsafe { probe_libsais16_gather_marked_lms_suffixes(c_sa.as_mut_ptr(), 2, 8, 0, 4) };
15085
15086 assert_eq!(rust_l, c_l);
15087 assert_eq!(rust_sa, c_sa);
15088 }
15089
15090 #[test]
15091 fn libsais16_gather_marked_lms_suffixes_omp_matches_c() {
15092 let mut rust_sa = vec![0; 10];
15093 rust_sa[4..8].copy_from_slice(&[2 | SAINT_MIN, 4, 6 | SAINT_MIN, 8]);
15094 let mut c_sa = rust_sa.clone();
15095
15096 let mut rust_thread_state = alloc_thread_state(1).unwrap();
15097 gather_marked_lms_suffixes_omp(&mut rust_sa, 8, 4, 2, 1, &mut rust_thread_state);
15098 unsafe {
15099 probe_libsais16_gather_marked_lms_suffixes_omp(c_sa.as_mut_ptr(), 8, 4, 2, 1);
15100 }
15101
15102 assert_eq!(rust_sa, c_sa);
15103 }
15104
15105 #[test]
15106 fn libsais16_renumber_and_gather_lms_suffixes_omp_matches_c() {
15107 let mut rust_sa = vec![0; 10];
15108 rust_sa[..4].copy_from_slice(&[2, 4 | SAINT_MIN, 6, 8 | SAINT_MIN]);
15109 let mut c_sa = rust_sa.clone();
15110
15111 let mut rust_thread_state = alloc_thread_state(1).unwrap();
15112 let rust_name =
15113 renumber_and_gather_lms_suffixes_omp(&mut rust_sa, 8, 4, 2, 1, &mut rust_thread_state);
15114 let c_name = unsafe {
15115 probe_libsais16_renumber_and_gather_lms_suffixes_omp(c_sa.as_mut_ptr(), 8, 4, 2, 1)
15116 };
15117
15118 assert_eq!(rust_name, c_name);
15119 assert_eq!(rust_sa, c_sa);
15120 }
15121
15122 #[test]
15123 fn libsais16_reconstruct_lms_suffixes_matches_c() {
15124 let mut rust_sa = vec![2, 0, 1, 77, 88, 10, 11, 12];
15125 let mut c_sa = rust_sa.clone();
15126
15127 reconstruct_lms_suffixes(&mut rust_sa, 8, 3, 0, 3);
15128 unsafe {
15129 probe_libsais16_reconstruct_lms_suffixes(c_sa.as_mut_ptr(), 8, 3, 0, 3);
15130 }
15131
15132 assert_eq!(rust_sa, c_sa);
15133
15134 let mut rust_sa = vec![2, 0, 1, 77, 88, 10, 11, 12];
15135 let mut c_sa = rust_sa.clone();
15136 reconstruct_lms_suffixes_omp(&mut rust_sa, 8, 3, 1);
15137 unsafe {
15138 probe_libsais16_reconstruct_lms_suffixes_omp(c_sa.as_mut_ptr(), 8, 3, 1);
15139 }
15140
15141 assert_eq!(rust_sa, c_sa);
15142 }
15143
15144 #[test]
15145 fn libsais16_lms_late_omp_wrappers_use_block_partition() {
15146 let m = 65_536usize;
15147 let mut scalar = vec![0; 2 * m + 8];
15148 for i in 0..m {
15149 let value = (2 * i) as SaSint;
15150 scalar[i] = if i % 7 == 0 { value | SAINT_MIN } else { value };
15151 }
15152 let mut threaded = scalar.clone();
15153
15154 let mut scalar_state = alloc_thread_state(1).unwrap();
15155 let mut threaded_state = alloc_thread_state(4).unwrap();
15156 let scalar_name =
15157 renumber_lms_suffixes_16u_omp(&mut scalar, m as SaSint, 1, &mut scalar_state);
15158 let threaded_name =
15159 renumber_lms_suffixes_16u_omp(&mut threaded, m as SaSint, 4, &mut threaded_state);
15160 assert_eq!(threaded_name, scalar_name);
15161 assert_eq!(threaded, scalar);
15162
15163 let n = 131_072usize;
15164 let m = 65_536usize;
15165 let fs = 128usize;
15166 let mut scalar = vec![0; n + fs];
15167 for i in 0..(n >> 1) {
15168 let value = (i as SaSint + 1) & SAINT_MAX;
15169 scalar[m + i] = if i % 7 == 0 { value | SAINT_MIN } else { value };
15170 }
15171 let marked_count = (0..(n >> 1)).filter(|i| i % 7 == 0).count();
15172 let mut threaded = scalar.clone();
15173
15174 let mut scalar_state = alloc_thread_state(1).unwrap();
15175 let mut threaded_state = alloc_thread_state(4).unwrap();
15176 gather_marked_lms_suffixes_omp(
15177 &mut scalar,
15178 n as SaSint,
15179 m as SaSint,
15180 fs as SaSint,
15181 1,
15182 &mut scalar_state,
15183 );
15184 gather_marked_lms_suffixes_omp(
15185 &mut threaded,
15186 n as SaSint,
15187 m as SaSint,
15188 fs as SaSint,
15189 4,
15190 &mut threaded_state,
15191 );
15192 assert_eq!(
15193 &threaded[n + fs - marked_count..n + fs],
15194 &scalar[n + fs - marked_count..n + fs]
15195 );
15196
15197 let m = 65_536usize;
15198 let n = 2 * m;
15199 let mut scalar = vec![0; n];
15200 for i in 0..m {
15201 scalar[i] = i as SaSint;
15202 scalar[n - m + i] = 1_000_000 + i as SaSint;
15203 }
15204 let mut threaded = scalar.clone();
15205
15206 reconstruct_lms_suffixes_omp(&mut scalar, n as SaSint, m as SaSint, 1);
15207 reconstruct_lms_suffixes_omp(&mut threaded, n as SaSint, m as SaSint, 4);
15208 assert_eq!(threaded, scalar);
15209 }
15210
15211 #[test]
15212 fn libsais16_distinct_lms_helpers_match_c() {
15213 let m = 6;
15214 let mut rust_sa = vec![0; 18];
15215 rust_sa[..m].copy_from_slice(&[
15216 2 | SAINT_MIN,
15217 4 | SAINT_MIN,
15218 6,
15219 8 | SAINT_MIN,
15220 10,
15221 12 | SAINT_MIN,
15222 ]);
15223 let mut c_sa = rust_sa.clone();
15224 let rust_name =
15225 renumber_distinct_lms_suffixes_32s_4k(&mut rust_sa, m as SaSint, 1, 0, m as isize);
15226 let c_name = unsafe {
15227 probe_libsais16_renumber_distinct_lms_suffixes_32s_4k(
15228 c_sa.as_mut_ptr(),
15229 m as SaSint,
15230 1,
15231 0,
15232 m as SaSint,
15233 )
15234 };
15235 assert_eq!(rust_name, c_name);
15236 assert_eq!(rust_sa, c_sa);
15237
15238 let mut rust_sa = vec![0; 12];
15239 rust_sa[m..m + 6].copy_from_slice(&[SAINT_MIN | 1, 0, SAINT_MIN | 2, 0, 3, 0]);
15240 let mut c_sa = rust_sa.clone();
15241 mark_distinct_lms_suffixes_32s(&mut rust_sa, m as SaSint, 0, 6);
15242 unsafe {
15243 probe_libsais16_mark_distinct_lms_suffixes_32s(c_sa.as_mut_ptr(), m as SaSint, 0, 6);
15244 }
15245 assert_eq!(rust_sa, c_sa);
15246
15247 let mut rust_sa = vec![0; 12];
15248 rust_sa[m..m + 6].copy_from_slice(&[SAINT_MIN | 1, 7, SAINT_MIN | 2, 0, -5, 9]);
15249 let mut c_sa = rust_sa.clone();
15250 clamp_lms_suffixes_length_32s(&mut rust_sa, m as SaSint, 0, 6);
15251 unsafe {
15252 probe_libsais16_clamp_lms_suffixes_length_32s(c_sa.as_mut_ptr(), m as SaSint, 0, 6);
15253 }
15254 assert_eq!(rust_sa, c_sa);
15255 }
15256
15257 #[test]
15258 fn libsais16_distinct_lms_omp_wrappers_match_c() {
15259 let n = 12;
15260 let m = 6;
15261 let mut rust_sa = vec![0; 18];
15262 rust_sa[..m].copy_from_slice(&[
15263 2 | SAINT_MIN,
15264 4 | SAINT_MIN,
15265 6,
15266 8 | SAINT_MIN,
15267 10,
15268 12 | SAINT_MIN,
15269 ]);
15270 let mut c_sa = rust_sa.clone();
15271 let mut rust_thread_state = alloc_thread_state(1).unwrap();
15272 let rust_name = renumber_distinct_lms_suffixes_32s_4k_omp(
15273 &mut rust_sa,
15274 m as SaSint,
15275 1,
15276 &mut rust_thread_state,
15277 );
15278 let c_name = unsafe {
15279 probe_libsais16_renumber_distinct_lms_suffixes_32s_4k_omp(
15280 c_sa.as_mut_ptr(),
15281 m as SaSint,
15282 1,
15283 )
15284 };
15285 assert_eq!(rust_name, c_name);
15286 assert_eq!(rust_sa, c_sa);
15287
15288 let mut rust_sa = vec![0; 18];
15289 rust_sa[m..m + 6].copy_from_slice(&[SAINT_MIN | 1, 0, SAINT_MIN | 2, 0, 3, 0]);
15290 let mut c_sa = rust_sa.clone();
15291 mark_distinct_lms_suffixes_32s_omp(&mut rust_sa, n, m as SaSint, 1);
15292 unsafe {
15293 probe_libsais16_mark_distinct_lms_suffixes_32s_omp(
15294 c_sa.as_mut_ptr(),
15295 n,
15296 m as SaSint,
15297 1,
15298 );
15299 }
15300 assert_eq!(rust_sa, c_sa);
15301
15302 let mut rust_sa = vec![0; 18];
15303 rust_sa[m..m + 6].copy_from_slice(&[SAINT_MIN | 1, 7, SAINT_MIN | 2, 0, -5, 9]);
15304 let mut c_sa = rust_sa.clone();
15305 clamp_lms_suffixes_length_32s_omp(&mut rust_sa, n, m as SaSint, 1);
15306 unsafe {
15307 probe_libsais16_clamp_lms_suffixes_length_32s_omp(c_sa.as_mut_ptr(), n, m as SaSint, 1);
15308 }
15309 assert_eq!(rust_sa, c_sa);
15310
15311 let mut rust_sa = vec![0; 18];
15312 rust_sa[..m].copy_from_slice(&[
15313 2 | SAINT_MIN,
15314 4 | SAINT_MIN,
15315 6,
15316 8 | SAINT_MIN,
15317 10,
15318 12 | SAINT_MIN,
15319 ]);
15320 let mut c_sa = rust_sa.clone();
15321 let mut rust_thread_state = alloc_thread_state(1).unwrap();
15322 let rust_name = renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(
15323 &mut rust_sa,
15324 n,
15325 m as SaSint,
15326 1,
15327 &mut rust_thread_state,
15328 );
15329 let c_name = unsafe {
15330 probe_libsais16_renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(
15331 c_sa.as_mut_ptr(),
15332 n,
15333 m as SaSint,
15334 1,
15335 )
15336 };
15337 assert_eq!(rust_name, c_name);
15338 assert_eq!(rust_sa, c_sa);
15339 }
15340
15341 #[test]
15342 fn libsais16_distinct_lms_omp_wrappers_use_block_partition() {
15343 let m = 65_536usize;
15344 let mut scalar = vec![0; 2 * m];
15345 for i in 0..m {
15346 let value = (2 * i) as SaSint;
15347 scalar[i] = if i % 7 == 0 { value | SAINT_MIN } else { value };
15348 }
15349 let mut threaded = scalar.clone();
15350
15351 let mut scalar_state = alloc_thread_state(1).unwrap();
15352 let mut threaded_state = alloc_thread_state(4).unwrap();
15353 let scalar_name = renumber_distinct_lms_suffixes_32s_4k_omp(
15354 &mut scalar,
15355 m as SaSint,
15356 1,
15357 &mut scalar_state,
15358 );
15359 let threaded_name = renumber_distinct_lms_suffixes_32s_4k_omp(
15360 &mut threaded,
15361 m as SaSint,
15362 4,
15363 &mut threaded_state,
15364 );
15365 assert_eq!(threaded_name, scalar_name);
15366 assert_eq!(threaded, scalar);
15367
15368 let n = 131_072usize;
15369 let m = 65_536usize;
15370 let mut scalar = vec![0; n];
15371 for i in 0..(n >> 1) {
15372 scalar[m + i] = if i % 5 == 0 {
15373 SAINT_MIN | (i as SaSint + 1)
15374 } else if i % 11 == 0 {
15375 0
15376 } else {
15377 i as SaSint + 1
15378 };
15379 }
15380 let mut threaded = scalar.clone();
15381 mark_distinct_lms_suffixes_32s_omp(&mut scalar, n as SaSint, m as SaSint, 1);
15382 mark_distinct_lms_suffixes_32s_omp(&mut threaded, n as SaSint, m as SaSint, 4);
15383 assert_eq!(&threaded[m..n], &scalar[m..n]);
15384
15385 let mut scalar = vec![0; n];
15386 for i in 0..(n >> 1) {
15387 scalar[m + i] = if i % 5 == 0 {
15388 SAINT_MIN | (i as SaSint + 1)
15389 } else {
15390 i as SaSint + 1
15391 };
15392 }
15393 let mut threaded = scalar.clone();
15394 clamp_lms_suffixes_length_32s_omp(&mut scalar, n as SaSint, m as SaSint, 1);
15395 clamp_lms_suffixes_length_32s_omp(&mut threaded, n as SaSint, m as SaSint, 4);
15396 assert_eq!(&threaded[m..n], &scalar[m..n]);
15397 }
15398
15399 #[test]
15400 fn libsais16_unique_nonunique_lms_helpers_match_c() {
15401 let m = 4;
15402 let mut rust_t = vec![0; 12];
15403 let mut rust_sa = vec![0; 12];
15404 rust_sa[..m].copy_from_slice(&[2, 4, 6, 8]);
15405 rust_sa[m + 1] = SAINT_MIN | 11;
15406 rust_sa[m + 2] = 22;
15407 rust_sa[m + 3] = SAINT_MIN | 33;
15408 rust_sa[m + 4] = 44;
15409 let mut c_t = rust_t.clone();
15410 let mut c_sa = rust_sa.clone();
15411
15412 let rust_f = renumber_unique_and_nonunique_lms_suffixes_32s(
15413 &mut rust_t,
15414 &mut rust_sa,
15415 m as SaSint,
15416 0,
15417 0,
15418 m as isize,
15419 );
15420 let c_f = unsafe {
15421 probe_libsais16_renumber_unique_and_nonunique_lms_suffixes_32s(
15422 c_t.as_mut_ptr(),
15423 c_sa.as_mut_ptr(),
15424 m as SaSint,
15425 0,
15426 0,
15427 m as SaSint,
15428 )
15429 };
15430 assert_eq!(rust_f, c_f);
15431 assert_eq!(rust_t, c_t);
15432 assert_eq!(rust_sa, c_sa);
15433
15434 let mut rust_sa = vec![0; 10];
15435 rust_sa[m..m + 4].copy_from_slice(&[SAINT_MIN | 3, 4, SAINT_MIN | 5, 6]);
15436 let mut c_sa = rust_sa.clone();
15437 let mut rust_l = m as isize;
15438 let mut rust_r = 10isize;
15439 let mut c_l = rust_l as SaSint;
15440 let mut c_r = rust_r as SaSint;
15441 compact_unique_and_nonunique_lms_suffixes_32s(
15442 &mut rust_sa,
15443 m as SaSint,
15444 &mut rust_l,
15445 &mut rust_r,
15446 0,
15447 4,
15448 );
15449 unsafe {
15450 probe_libsais16_compact_unique_and_nonunique_lms_suffixes_32s(
15451 c_sa.as_mut_ptr(),
15452 m as SaSint,
15453 &mut c_l,
15454 &mut c_r,
15455 0,
15456 4,
15457 );
15458 }
15459 assert_eq!(rust_l as SaSint, c_l);
15460 assert_eq!(rust_r as SaSint, c_r);
15461 assert_eq!(rust_sa, c_sa);
15462 }
15463
15464 #[test]
15465 fn libsais16_unique_nonunique_lms_omp_wrappers_match_c() {
15466 let n = 8;
15467 let m = 4;
15468 let fs = 4;
15469 let mut rust_t = vec![0; 12];
15470 let mut rust_sa = vec![0; 12];
15471 rust_sa[..m].copy_from_slice(&[2, 4, 6, 8]);
15472 rust_sa[m + 1] = SAINT_MIN | 11;
15473 rust_sa[m + 2] = 22;
15474 rust_sa[m + 3] = SAINT_MIN | 33;
15475 rust_sa[m + 4] = 44;
15476 let mut c_t = rust_t.clone();
15477 let mut c_sa = rust_sa.clone();
15478
15479 let rust_f = renumber_unique_and_nonunique_lms_suffixes_32s_omp(
15480 &mut rust_t,
15481 &mut rust_sa,
15482 m as SaSint,
15483 1,
15484 );
15485 let c_f = unsafe {
15486 probe_libsais16_renumber_unique_and_nonunique_lms_suffixes_32s_omp(
15487 c_t.as_mut_ptr(),
15488 c_sa.as_mut_ptr(),
15489 m as SaSint,
15490 1,
15491 )
15492 };
15493 assert_eq!(rust_f, c_f);
15494 assert_eq!(rust_t, c_t);
15495 assert_eq!(rust_sa, c_sa);
15496
15497 let mut rust_sa = vec![0; 12];
15498 rust_sa[m..m + 4].copy_from_slice(&[SAINT_MIN | 3, 4, SAINT_MIN | 5, 6]);
15499 rust_sa[m - 2..m].copy_from_slice(&[101, 102]);
15500 let mut c_sa = rust_sa.clone();
15501 compact_unique_and_nonunique_lms_suffixes_32s_omp(&mut rust_sa, n, m as SaSint, fs, 2, 1);
15502 unsafe {
15503 probe_libsais16_compact_unique_and_nonunique_lms_suffixes_32s_omp(
15504 c_sa.as_mut_ptr(),
15505 n,
15506 m as SaSint,
15507 fs,
15508 2,
15509 1,
15510 );
15511 }
15512 assert_eq!(rust_sa, c_sa);
15513
15514 let mut rust_t = vec![0; 12];
15515 let mut rust_sa = vec![0; 12];
15516 rust_sa[..m].copy_from_slice(&[2, 4, 6, 8]);
15517 rust_sa[m + 1] = SAINT_MIN | 11;
15518 rust_sa[m + 2] = 22;
15519 rust_sa[m + 3] = SAINT_MIN | 33;
15520 rust_sa[m + 4] = 44;
15521 let mut c_t = rust_t.clone();
15522 let mut c_sa = rust_sa.clone();
15523 let rust_f = compact_lms_suffixes_32s_omp(&mut rust_t, &mut rust_sa, n, m as SaSint, fs, 1);
15524 let c_f = unsafe {
15525 probe_libsais16_compact_lms_suffixes_32s_omp(
15526 c_t.as_mut_ptr(),
15527 c_sa.as_mut_ptr(),
15528 n,
15529 m as SaSint,
15530 fs,
15531 1,
15532 )
15533 };
15534 assert_eq!(rust_f, c_f);
15535 assert_eq!(rust_t, c_t);
15536 assert_eq!(rust_sa, c_sa);
15537 }
15538
15539 #[test]
15540 fn libsais16_unique_nonunique_lms_omp_wrappers_use_block_partition() {
15541 let m = 65_536usize;
15542 let mut scalar_t = vec![0; 2 * m];
15543 let mut scalar_sa = vec![0; 2 * m];
15544 for i in 0..m {
15545 scalar_sa[i] = (2 * i) as SaSint;
15546 scalar_sa[m + i] = if i % 5 == 0 {
15547 SAINT_MIN | (i as SaSint + 3)
15548 } else {
15549 i as SaSint + 3
15550 };
15551 }
15552 let mut threaded_t = scalar_t.clone();
15553 let mut threaded_sa = scalar_sa.clone();
15554
15555 let scalar_f = renumber_unique_and_nonunique_lms_suffixes_32s_omp(
15556 &mut scalar_t,
15557 &mut scalar_sa,
15558 m as SaSint,
15559 1,
15560 );
15561 let threaded_f = renumber_unique_and_nonunique_lms_suffixes_32s_omp(
15562 &mut threaded_t,
15563 &mut threaded_sa,
15564 m as SaSint,
15565 4,
15566 );
15567 assert_eq!(threaded_f, scalar_f);
15568 assert_eq!(threaded_t, scalar_t);
15569 assert_eq!(threaded_sa, scalar_sa);
15570
15571 let n = 131_072usize;
15572 let m = 4_096usize;
15573 let fs = 8_192usize;
15574 let mut scalar_sa = vec![0; n + fs];
15575 for i in 0..(n >> 1) {
15576 scalar_sa[m + i] = if i % 32 == 0 {
15577 SAINT_MIN | (i as SaSint + 1)
15578 } else {
15579 i as SaSint + 1
15580 };
15581 }
15582 let f = 1_024usize;
15583 for i in 0..f {
15584 scalar_sa[m - f + i] = 1_000_000 + i as SaSint;
15585 }
15586 let mut threaded_sa = scalar_sa.clone();
15587
15588 compact_unique_and_nonunique_lms_suffixes_32s_omp(
15589 &mut scalar_sa,
15590 n as SaSint,
15591 m as SaSint,
15592 fs as SaSint,
15593 f as SaSint,
15594 1,
15595 );
15596 compact_unique_and_nonunique_lms_suffixes_32s_omp(
15597 &mut threaded_sa,
15598 n as SaSint,
15599 m as SaSint,
15600 fs as SaSint,
15601 f as SaSint,
15602 4,
15603 );
15604 assert_eq!(&threaded_sa[..m], &scalar_sa[..m]);
15605 assert_eq!(
15606 &threaded_sa[n + fs - m..n + fs],
15607 &scalar_sa[n + fs - m..n + fs]
15608 );
15609 }
15610
15611 #[test]
15612 fn libsais16_merge_lms_helpers_match_c() {
15613 let n = 10;
15614 let m = 3;
15615 let mut rust_t = vec![0; n as usize];
15616 rust_t[1] = SAINT_MIN | 11;
15617 rust_t[3] = SAINT_MIN | 22;
15618 rust_t[7] = SAINT_MIN | 33;
15619 let mut rust_sa = vec![0; n as usize];
15620 rust_sa[6..10].copy_from_slice(&[2, 5, 8, 9]);
15621 let mut c_t = rust_t.clone();
15622 let mut c_sa = rust_sa.clone();
15623 merge_unique_lms_suffixes_32s(&mut rust_t, &mut rust_sa, n, m, 0, 0, n as isize);
15624 unsafe {
15625 probe_libsais16_merge_unique_lms_suffixes_32s(
15626 c_t.as_mut_ptr(),
15627 c_sa.as_mut_ptr(),
15628 n,
15629 m,
15630 0,
15631 0,
15632 n,
15633 );
15634 }
15635 assert_eq!(rust_t, c_t);
15636 assert_eq!(rust_sa, c_sa);
15637
15638 let n = 10;
15639 let m = 5;
15640 let mut rust_sa = vec![9, 0, 8, 0, 0, 7, 31, 32, 33, 34];
15641 let mut c_sa = rust_sa.clone();
15642 merge_nonunique_lms_suffixes_32s(&mut rust_sa, n, m, 2, 0, m as isize);
15643 unsafe {
15644 probe_libsais16_merge_nonunique_lms_suffixes_32s(c_sa.as_mut_ptr(), n, m, 2, 0, m);
15645 }
15646 assert_eq!(rust_sa, c_sa);
15647 }
15648
15649 #[test]
15650 fn libsais16_merge_lms_omp_wrappers_match_c() {
15651 let n = 12;
15652 let m = 4;
15653 let f = 2;
15654 let mut rust_t = vec![0; n as usize];
15655 rust_t[1] = SAINT_MIN | 11;
15656 rust_t[5] = SAINT_MIN | 22;
15657 let mut rust_sa = vec![0; n as usize];
15658 rust_sa[1] = 41;
15659 rust_sa[7..12].copy_from_slice(&[2, 6, 21, 22, 23]);
15660 let mut c_t = rust_t.clone();
15661 let mut c_sa = rust_sa.clone();
15662 merge_unique_lms_suffixes_32s_omp(&mut rust_t, &mut rust_sa, n, m, 1);
15663 unsafe {
15664 probe_libsais16_merge_unique_lms_suffixes_32s_omp(
15665 c_t.as_mut_ptr(),
15666 c_sa.as_mut_ptr(),
15667 n,
15668 m,
15669 1,
15670 );
15671 }
15672 assert_eq!(rust_t, c_t);
15673 assert_eq!(rust_sa, c_sa);
15674
15675 let mut rust_sa = vec![0, 41, 1, 0, 55, 66, 77, 2, 6, 21, 22, 23];
15676 let mut c_sa = rust_sa.clone();
15677 merge_nonunique_lms_suffixes_32s_omp(&mut rust_sa, n, m, f, 1);
15678 unsafe {
15679 probe_libsais16_merge_nonunique_lms_suffixes_32s_omp(c_sa.as_mut_ptr(), n, m, f, 1);
15680 }
15681 assert_eq!(rust_sa, c_sa);
15682
15683 let mut rust_t = vec![0; n as usize];
15684 rust_t[1] = SAINT_MIN | 11;
15685 rust_t[5] = SAINT_MIN | 22;
15686 let mut rust_sa = vec![0; n as usize];
15687 rust_sa[1] = 41;
15688 rust_sa[7..12].copy_from_slice(&[2, 6, 21, 22, 23]);
15689 let mut c_t = rust_t.clone();
15690 let mut c_sa = rust_sa.clone();
15691 merge_compacted_lms_suffixes_32s_omp(&mut rust_t, &mut rust_sa, n, m, f, 1);
15692 unsafe {
15693 probe_libsais16_merge_compacted_lms_suffixes_32s_omp(
15694 c_t.as_mut_ptr(),
15695 c_sa.as_mut_ptr(),
15696 n,
15697 m,
15698 f,
15699 1,
15700 );
15701 }
15702 assert_eq!(rust_t, c_t);
15703 assert_eq!(rust_sa, c_sa);
15704 }
15705
15706 #[test]
15707 fn libsais16_merge_lms_omp_wrappers_use_block_partition() {
15708 let n = 65_536usize;
15709 let m = 10_000usize;
15710 let mut scalar_t = vec![0; n];
15711 for i in (0..n).step_by(17) {
15712 scalar_t[i] = SAINT_MIN | (i as SaSint + 1);
15713 }
15714 let unique_count = scalar_t.iter().filter(|&&value| value < 0).count();
15715 let mut scalar_sa = vec![0; n];
15716 let source = n - m - 1;
15717 for i in 0..=unique_count {
15718 scalar_sa[source + i] = ((i * 13 + 7) % n) as SaSint;
15719 }
15720 let mut threaded_t = scalar_t.clone();
15721 let mut threaded_sa = scalar_sa.clone();
15722
15723 merge_unique_lms_suffixes_32s_omp(
15724 &mut scalar_t,
15725 &mut scalar_sa,
15726 n as SaSint,
15727 m as SaSint,
15728 1,
15729 );
15730 merge_unique_lms_suffixes_32s_omp(
15731 &mut threaded_t,
15732 &mut threaded_sa,
15733 n as SaSint,
15734 m as SaSint,
15735 4,
15736 );
15737 assert_eq!(threaded_t, scalar_t);
15738 assert_eq!(threaded_sa, scalar_sa);
15739
15740 let n = 131_072usize;
15741 let m = 65_536usize;
15742 let f = 100usize;
15743 let mut scalar_sa = vec![1; n];
15744 for i in (0..m).step_by(9) {
15745 scalar_sa[i] = 0;
15746 }
15747 let zero_count = scalar_sa[..m].iter().filter(|&&value| value == 0).count();
15748 let source = n - m - 1 + f;
15749 for i in 0..=zero_count {
15750 scalar_sa[source + i] = 2_000_000 + i as SaSint;
15751 }
15752 let mut threaded_sa = scalar_sa.clone();
15753
15754 merge_nonunique_lms_suffixes_32s_omp(
15755 &mut scalar_sa,
15756 n as SaSint,
15757 m as SaSint,
15758 f as SaSint,
15759 1,
15760 );
15761 merge_nonunique_lms_suffixes_32s_omp(
15762 &mut threaded_sa,
15763 n as SaSint,
15764 m as SaSint,
15765 f as SaSint,
15766 4,
15767 );
15768 assert_eq!(threaded_sa, scalar_sa);
15769 }
15770
15771 #[test]
15772 fn libsais16_radix_sort_lms_suffixes_32s_match_c() {
15773 let t = vec![0, 1, 2, 3, 1, 2, 3, 0];
15774 let mut rust_sa = vec![0, 0, 0, 0, 0, 1, 2, 3];
15775 let mut c_sa = rust_sa.clone();
15776 let mut rust_bucket = vec![0, 6, 7, 8];
15777 let mut c_bucket = rust_bucket.clone();
15778 radix_sort_lms_suffixes_32s_6k(&t, &mut rust_sa, &mut rust_bucket, 5, 3);
15779 unsafe {
15780 probe_libsais16_radix_sort_lms_suffixes_32s_6k(
15781 t.as_ptr(),
15782 c_sa.as_mut_ptr(),
15783 c_bucket.as_mut_ptr(),
15784 5,
15785 3,
15786 );
15787 }
15788 assert_eq!(rust_sa, c_sa);
15789 assert_eq!(rust_bucket, c_bucket);
15790
15791 let mut rust_sa = vec![0, 0, 0, 0, 0, 1, 2, 3];
15792 let mut c_sa = rust_sa.clone();
15793 let mut rust_bucket = vec![0, 0, 6, 0, 7, 0, 8, 0];
15794 let mut c_bucket = rust_bucket.clone();
15795 radix_sort_lms_suffixes_32s_2k(&t, &mut rust_sa, &mut rust_bucket, 5, 3);
15796 unsafe {
15797 probe_libsais16_radix_sort_lms_suffixes_32s_2k(
15798 t.as_ptr(),
15799 c_sa.as_mut_ptr(),
15800 c_bucket.as_mut_ptr(),
15801 5,
15802 3,
15803 );
15804 }
15805 assert_eq!(rust_sa, c_sa);
15806 assert_eq!(rust_bucket, c_bucket);
15807
15808 let mut cache = vec![ThreadCache::default(); 8];
15809 let sa = vec![0, 0, 0, 0, 0, 1, 2, 3];
15810 radix_sort_lms_suffixes_32s_block_gather(&t, &sa, &mut cache, 5, 3);
15811 assert_eq!(cache[5].index, 1);
15812 assert_eq!(cache[5].symbol, 1);
15813 assert_eq!(cache[6].index, 2);
15814 assert_eq!(cache[6].symbol, 2);
15815 assert_eq!(cache[7].index, 3);
15816 assert_eq!(cache[7].symbol, 3);
15817
15818 let mut bucket = vec![0, 6, 7, 8];
15819 radix_sort_lms_suffixes_32s_6k_block_sort(&mut bucket, &mut cache, 5, 3);
15820 assert_eq!(bucket, vec![0, 5, 6, 7]);
15821 assert_eq!(cache[5].symbol, 5);
15822 assert_eq!(cache[6].symbol, 6);
15823 assert_eq!(cache[7].symbol, 7);
15824
15825 let mut cache = vec![ThreadCache::default(); 8];
15826 radix_sort_lms_suffixes_32s_block_gather(&t, &sa, &mut cache, 5, 3);
15827 let mut bucket = vec![0, 0, 6, 0, 7, 0, 8, 0];
15828 radix_sort_lms_suffixes_32s_2k_block_sort(&mut bucket, &mut cache, 5, 3);
15829 assert_eq!(bucket, vec![0, 0, 5, 0, 6, 0, 7, 0]);
15830 assert_eq!(cache[5].symbol, 5);
15831 assert_eq!(cache[6].symbol, 6);
15832 assert_eq!(cache[7].symbol, 7);
15833
15834 let mut rust_sa = vec![0, 0, 0, 0, 0, 1, 2, 3];
15835 let mut c_sa = rust_sa.clone();
15836 let mut rust_bucket = vec![0, 6, 7, 8];
15837 let mut c_bucket = rust_bucket.clone();
15838 radix_sort_lms_suffixes_32s_6k_omp(&t, &mut rust_sa, 8, 4, &mut rust_bucket, 1);
15839 unsafe {
15840 probe_libsais16_radix_sort_lms_suffixes_32s_6k_omp(
15841 t.as_ptr(),
15842 c_sa.as_mut_ptr(),
15843 8,
15844 4,
15845 c_bucket.as_mut_ptr(),
15846 1,
15847 );
15848 }
15849 assert_eq!(rust_sa, c_sa);
15850 assert_eq!(rust_bucket, c_bucket);
15851
15852 let mut rust_sa = vec![0, 0, 0, 0, 0, 1, 2, 3];
15853 let mut c_sa = rust_sa.clone();
15854 let mut rust_bucket = vec![0, 0, 6, 0, 7, 0, 8, 0];
15855 let mut c_bucket = rust_bucket.clone();
15856 radix_sort_lms_suffixes_32s_2k_omp(&t, &mut rust_sa, 8, 4, &mut rust_bucket, 1);
15857 unsafe {
15858 probe_libsais16_radix_sort_lms_suffixes_32s_2k_omp(
15859 t.as_ptr(),
15860 c_sa.as_mut_ptr(),
15861 8,
15862 4,
15863 c_bucket.as_mut_ptr(),
15864 1,
15865 );
15866 }
15867 assert_eq!(rust_sa, c_sa);
15868 assert_eq!(rust_bucket, c_bucket);
15869
15870 let t = vec![2, 1, 3, 1, 0];
15871 let mut rust_sa = vec![0; t.len()];
15872 let mut c_sa = rust_sa.clone();
15873 let mut rust_bucket = vec![0, 2, 4, 5];
15874 let mut c_bucket = rust_bucket.clone();
15875 let rust_m =
15876 radix_sort_lms_suffixes_32s_1k(&t, &mut rust_sa, t.len() as SaSint, &mut rust_bucket);
15877 let c_m = unsafe {
15878 probe_libsais16_radix_sort_lms_suffixes_32s_1k(
15879 t.as_ptr(),
15880 c_sa.as_mut_ptr(),
15881 t.len() as SaSint,
15882 c_bucket.as_mut_ptr(),
15883 )
15884 };
15885 assert_eq!(rust_m, c_m);
15886 assert_eq!(rust_sa, c_sa);
15887 assert_eq!(rust_bucket, c_bucket);
15888 }
15889
15890 #[test]
15891 fn libsais16_radix_sort_set_markers_32s_match_c() {
15892 let mut rust_sa = vec![0; 8];
15893 let mut c_sa = rust_sa.clone();
15894 let mut induction_bucket = vec![1, 3, 5, 7];
15895 radix_sort_set_markers_32s_6k(&mut rust_sa, &induction_bucket, 0, 4);
15896 unsafe {
15897 probe_libsais16_radix_sort_set_markers_32s_6k(
15898 c_sa.as_mut_ptr(),
15899 induction_bucket.as_mut_ptr(),
15900 0,
15901 4,
15902 );
15903 }
15904 assert_eq!(rust_sa, c_sa);
15905
15906 let mut rust_sa = vec![0; 8];
15907 let mut c_sa = rust_sa.clone();
15908 radix_sort_set_markers_32s_6k_omp(&mut rust_sa, 5, &induction_bucket, 1);
15909 unsafe {
15910 probe_libsais16_radix_sort_set_markers_32s_6k_omp(
15911 c_sa.as_mut_ptr(),
15912 5,
15913 induction_bucket.as_mut_ptr(),
15914 1,
15915 );
15916 }
15917 assert_eq!(rust_sa, c_sa);
15918
15919 let mut rust_sa = vec![0; 8];
15920 let mut c_sa = rust_sa.clone();
15921 let mut induction_bucket = vec![1, 0, 3, 0, 5, 0, 7, 0];
15922 radix_sort_set_markers_32s_4k(&mut rust_sa, &induction_bucket, 0, 4);
15923 unsafe {
15924 probe_libsais16_radix_sort_set_markers_32s_4k(
15925 c_sa.as_mut_ptr(),
15926 induction_bucket.as_mut_ptr(),
15927 0,
15928 4,
15929 );
15930 }
15931 assert_eq!(rust_sa, c_sa);
15932
15933 let mut rust_sa = vec![0; 8];
15934 let mut c_sa = rust_sa.clone();
15935 radix_sort_set_markers_32s_4k_omp(&mut rust_sa, 5, &induction_bucket, 1);
15936 unsafe {
15937 probe_libsais16_radix_sort_set_markers_32s_4k_omp(
15938 c_sa.as_mut_ptr(),
15939 5,
15940 induction_bucket.as_mut_ptr(),
15941 1,
15942 );
15943 }
15944 assert_eq!(rust_sa, c_sa);
15945 }
15946
15947 #[test]
15948 fn libsais16_radix_sort_set_markers_32s_omp_partitions_large_inputs() {
15949 let k = 65_600usize;
15950 let induction_bucket_6k: Vec<SaSint> = (0..k).map(|i| i as SaSint).collect();
15951 let mut single = vec![0; k];
15952 let mut threaded = vec![0; k];
15953 radix_sort_set_markers_32s_6k_omp(&mut single, k as SaSint, &induction_bucket_6k, 1);
15954 radix_sort_set_markers_32s_6k_omp(&mut threaded, k as SaSint, &induction_bucket_6k, 4);
15955 assert_eq!(threaded, single);
15956
15957 let mut induction_bucket_4k = vec![0; 2 * k];
15958 for i in 0..k {
15959 induction_bucket_4k[buckets_index2(i, 0)] = i as SaSint;
15960 }
15961 let mut single = vec![0; k];
15962 let mut threaded = vec![0; k];
15963 radix_sort_set_markers_32s_4k_omp(&mut single, k as SaSint, &induction_bucket_4k, 1);
15964 radix_sort_set_markers_32s_4k_omp(&mut threaded, k as SaSint, &induction_bucket_4k, 4);
15965 assert_eq!(threaded, single);
15966 }
15967
15968 #[test]
15969 fn libsais16_partial_sorting_32s_helpers_match_c() {
15970 let k = 3;
15971 let mut rust_sa = vec![0, SAINT_MIN, 2, SAINT_MIN, 4, SAINT_MIN];
15972 let mut c_sa = rust_sa.clone();
15973 let mut buckets = vec![0; 6 * k as usize];
15974 buckets[buckets_index4(1, 0)] = 3;
15975 buckets[buckets_index4(2, 0)] = 6;
15976 buckets[4 * k as usize + buckets_index2(0, 0)] = 0;
15977 buckets[4 * k as usize + buckets_index2(1, 0)] = 1;
15978 partial_sorting_shift_markers_32s_6k_omp(&mut rust_sa, k, &buckets, 1);
15979 unsafe {
15980 probe_libsais16_partial_sorting_shift_markers_32s_6k_omp(
15981 c_sa.as_mut_ptr(),
15982 k,
15983 buckets.as_ptr(),
15984 1,
15985 );
15986 }
15987 assert_eq!(rust_sa, c_sa);
15988
15989 let mut rust_sa = vec![
15990 1 | SUFFIX_GROUP_MARKER,
15991 2,
15992 3 | SUFFIX_GROUP_MARKER,
15993 4 | SUFFIX_GROUP_MARKER,
15994 5,
15995 6,
15996 ];
15997 let mut c_sa = rust_sa.clone();
15998 partial_sorting_shift_markers_32s_4k(&mut rust_sa, 6);
15999 unsafe { probe_libsais16_partial_sorting_shift_markers_32s_4k(c_sa.as_mut_ptr(), 6) };
16000 assert_eq!(rust_sa, c_sa);
16001
16002 let mut rust_buckets = vec![0; 6 * k as usize];
16003 for (i, value) in rust_buckets[4 * k as usize..].iter_mut().enumerate() {
16004 *value = 100 + i as SaSint;
16005 }
16006 let mut c_buckets = rust_buckets.clone();
16007 partial_sorting_shift_buckets_32s_6k(k, &mut rust_buckets);
16008 unsafe { probe_libsais16_partial_sorting_shift_buckets_32s_6k(k, c_buckets.as_mut_ptr()) };
16009 assert_eq!(rust_buckets, c_buckets);
16010
16011 let mut rust_sa = vec![1 | SUFFIX_GROUP_MARKER, -3, 5 | SUFFIX_GROUP_MARKER, -7];
16012 let mut c_sa = rust_sa.clone();
16013 let rust_l = partial_sorting_gather_lms_suffixes_32s_4k(&mut rust_sa, 0, 4);
16014 let c_l = unsafe {
16015 probe_libsais16_partial_sorting_gather_lms_suffixes_32s_4k(c_sa.as_mut_ptr(), 0, 4)
16016 };
16017 assert_eq!(rust_l, c_l);
16018 assert_eq!(rust_sa, c_sa);
16019
16020 let mut rust_sa = vec![1, -3, 5, -7];
16021 let mut c_sa = rust_sa.clone();
16022 let rust_l = partial_sorting_gather_lms_suffixes_32s_1k(&mut rust_sa, 0, 4);
16023 let c_l = unsafe {
16024 probe_libsais16_partial_sorting_gather_lms_suffixes_32s_1k(c_sa.as_mut_ptr(), 0, 4)
16025 };
16026 assert_eq!(rust_l, c_l);
16027 assert_eq!(rust_sa, c_sa);
16028
16029 let mut rust_state = alloc_thread_state(1).unwrap();
16030 let mut rust_sa = vec![1 | SUFFIX_GROUP_MARKER, -3, 5 | SUFFIX_GROUP_MARKER, -7];
16031 let mut c_sa = rust_sa.clone();
16032 partial_sorting_gather_lms_suffixes_32s_4k_omp(&mut rust_sa, 4, 1, &mut rust_state);
16033 unsafe {
16034 probe_libsais16_partial_sorting_gather_lms_suffixes_32s_4k_omp(c_sa.as_mut_ptr(), 4, 1);
16035 }
16036 assert_eq!(rust_sa, c_sa);
16037
16038 let mut rust_state = alloc_thread_state(1).unwrap();
16039 let mut rust_sa = vec![1, -3, 5, -7];
16040 let mut c_sa = rust_sa.clone();
16041 partial_sorting_gather_lms_suffixes_32s_1k_omp(&mut rust_sa, 4, 1, &mut rust_state);
16042 unsafe {
16043 probe_libsais16_partial_sorting_gather_lms_suffixes_32s_1k_omp(c_sa.as_mut_ptr(), 4, 1);
16044 }
16045 assert_eq!(rust_sa, c_sa);
16046 }
16047
16048 #[test]
16049 fn libsais16_partial_sorting_gather_lms_suffixes_32s_omp_uses_block_partition() {
16050 let n = 65_536usize;
16051 let mut base_4k = vec![0; n];
16052 let mut base_1k = vec![0; n];
16053 for i in 0..n {
16054 let value = (i as SaSint + 1) & SAINT_MAX;
16055 base_4k[i] = if i % 7 == 0 {
16056 value | SAINT_MIN | SUFFIX_GROUP_MARKER
16057 } else if i % 11 == 0 {
16058 value | SUFFIX_GROUP_MARKER
16059 } else {
16060 value
16061 };
16062 base_1k[i] = if i % 7 == 0 { value | SAINT_MIN } else { value };
16063 }
16064 let lms_count = base_1k.iter().filter(|&&v| v < 0).count();
16065
16066 let mut scalar = base_4k.clone();
16067 let mut threaded = base_4k;
16068 let mut scalar_state = alloc_thread_state(1).unwrap();
16069 let mut threaded_state = alloc_thread_state(4).unwrap();
16070 partial_sorting_gather_lms_suffixes_32s_4k_omp(
16071 &mut scalar,
16072 n as SaSint,
16073 1,
16074 &mut scalar_state,
16075 );
16076 partial_sorting_gather_lms_suffixes_32s_4k_omp(
16077 &mut threaded,
16078 n as SaSint,
16079 4,
16080 &mut threaded_state,
16081 );
16082 assert_eq!(&threaded[..lms_count], &scalar[..lms_count]);
16083
16084 let mut scalar = base_1k.clone();
16085 let mut threaded = base_1k;
16086 partial_sorting_gather_lms_suffixes_32s_1k_omp(
16087 &mut scalar,
16088 n as SaSint,
16089 1,
16090 &mut scalar_state,
16091 );
16092 partial_sorting_gather_lms_suffixes_32s_1k_omp(
16093 &mut threaded,
16094 n as SaSint,
16095 4,
16096 &mut threaded_state,
16097 );
16098 assert_eq!(&threaded[..lms_count], &scalar[..lms_count]);
16099 }
16100
16101 #[test]
16102 fn libsais16_partial_sorting_32s_block_helpers_behave_like_upstream_shapes() {
16103 let t = vec![0, 1, 2, 1, 0];
16104 let k = 3;
16105
16106 let mut sa = vec![0, 4 | SAINT_MIN, 0];
16107 let mut cache = vec![ThreadCache::default(); sa.len()];
16108 partial_sorting_scan_right_to_left_32s_6k_block_gather(&t, &mut sa, &mut cache, 1, 1);
16109 assert_eq!(cache[1].index, 4 | SAINT_MIN);
16110 assert_eq!(cache[1].symbol, buckets_index4(1, 1) as SaSint);
16111
16112 let mut sa = vec![0, 4 | SUFFIX_GROUP_MARKER, 0];
16113 let mut cache = vec![ThreadCache::default(); sa.len()];
16114 partial_sorting_scan_right_to_left_32s_4k_block_gather(&t, &mut sa, &mut cache, 1, 1);
16115 assert_eq!(sa[1], 0);
16116 assert_eq!(cache[1].index, 4 | SUFFIX_GROUP_MARKER);
16117 assert_eq!(cache[1].symbol, buckets_index2(1, 1) as SaSint);
16118
16119 let mut sa = vec![0, 4, 0];
16120 let mut cache = vec![ThreadCache::default(); sa.len()];
16121 partial_sorting_scan_right_to_left_32s_1k_block_gather(&t, &mut sa, &mut cache, 1, 1);
16122 assert_eq!(sa[1], 0);
16123 assert_eq!(cache[1].index, 3 | SAINT_MIN);
16124 assert_eq!(cache[1].symbol, 1);
16125
16126 let mut sa = vec![4 | SAINT_MIN, 0, 0];
16127 let mut cache = vec![ThreadCache::default(); sa.len()];
16128 partial_sorting_scan_left_to_right_32s_6k_block_gather(&t, &mut sa, &mut cache, 0, 1);
16129 assert_eq!(cache[0].index, 4 | SAINT_MIN);
16130 assert_eq!(cache[0].symbol, buckets_index4(1, 1) as SaSint);
16131
16132 let mut sa = vec![4 | SUFFIX_GROUP_MARKER, 0, 0];
16133 let mut cache = vec![ThreadCache::default(); sa.len()];
16134 partial_sorting_scan_left_to_right_32s_4k_block_gather(&t, &mut sa, &mut cache, 0, 1);
16135 assert_eq!(sa[0], 0);
16136 assert_eq!(cache[0].index, 4 | SUFFIX_GROUP_MARKER);
16137 assert_eq!(cache[0].symbol, buckets_index2(1, 0) as SaSint);
16138
16139 let mut sa = vec![4, 0, 0];
16140 let mut cache = vec![ThreadCache::default(); sa.len()];
16141 partial_sorting_scan_left_to_right_32s_1k_block_gather(&t, &mut sa, &mut cache, 0, 1);
16142 assert_eq!(sa[0], 0);
16143 assert_eq!(cache[0].index, 3);
16144 assert_eq!(cache[0].symbol, 1);
16145
16146 let mut cache = vec![ThreadCache::default(); 3];
16147 cache[1].index = 4 | SAINT_MIN;
16148 cache[1].symbol = buckets_index4(1, 1) as SaSint;
16149 let mut buckets = vec![0; 4 * k];
16150 buckets[buckets_index4(1, 1)] = 2;
16151 let d = partial_sorting_scan_right_to_left_32s_6k_block_sort(
16152 &t,
16153 &mut buckets,
16154 0,
16155 &mut cache,
16156 1,
16157 1,
16158 );
16159 assert_eq!(d, 1);
16160 assert_eq!(cache[1].index, 3 | SAINT_MIN);
16161 assert_eq!(buckets[buckets_index4(1, 1)], 1);
16162 assert_eq!(buckets[buckets_index4(1, 1) + 2], 1);
16163
16164 let mut cache = vec![ThreadCache::default(); 3];
16165 cache[0].index = 4 | SAINT_MIN;
16166 cache[0].symbol = buckets_index4(1, 1) as SaSint;
16167 let mut buckets = vec![0; 4 * k];
16168 buckets[buckets_index4(1, 1)] = 1;
16169 let d = partial_sorting_scan_left_to_right_32s_6k_block_sort(
16170 &t,
16171 &mut buckets,
16172 0,
16173 &mut cache,
16174 0,
16175 1,
16176 );
16177 assert_eq!(d, 1);
16178 assert_eq!(cache[0].index, 3 | SAINT_MIN);
16179 assert_eq!(buckets[buckets_index4(1, 1)], 2);
16180 assert_eq!(buckets[buckets_index4(1, 1) + 2], 1);
16181
16182 let mut cache = vec![ThreadCache::default(); 3];
16183 cache[1].index = 4 | SUFFIX_GROUP_MARKER;
16184 cache[1].symbol = buckets_index2(1, 1) as SaSint;
16185 let mut buckets = vec![0; 4 * k];
16186 buckets[3 * k + 1] = 2;
16187 let d = partial_sorting_scan_right_to_left_32s_4k_block_sort(
16188 &t,
16189 k as SaSint,
16190 &mut buckets,
16191 0,
16192 &mut cache,
16193 1,
16194 1,
16195 );
16196 assert_eq!(d, 1);
16197 assert_eq!(cache[1].symbol, 1);
16198 assert_eq!(buckets[3 * k + 1], 1);
16199
16200 let mut cache = vec![ThreadCache::default(); 3];
16201 cache[0].index = 4 | SUFFIX_GROUP_MARKER;
16202 cache[0].symbol = buckets_index2(1, 0) as SaSint;
16203 let mut buckets = vec![0; 4 * k];
16204 buckets[2 * k + 1] = 1;
16205 let d = partial_sorting_scan_left_to_right_32s_4k_block_sort(
16206 &t,
16207 k as SaSint,
16208 &mut buckets,
16209 0,
16210 &mut cache,
16211 0,
16212 1,
16213 );
16214 assert_eq!(d, 1);
16215 assert_eq!(cache[0].symbol, 1);
16216 assert_eq!(buckets[2 * k + 1], 2);
16217
16218 let mut cache = vec![ThreadCache::default(); 3];
16219 cache[1].index = 4;
16220 cache[1].symbol = 1;
16221 let mut buckets = vec![0; k];
16222 buckets[1] = 2;
16223 partial_sorting_scan_right_to_left_32s_1k_block_sort(&t, &mut buckets, &mut cache, 1, 1);
16224 assert_eq!(cache[1].symbol, 1);
16225 assert_eq!(buckets[1], 1);
16226
16227 let mut cache = vec![ThreadCache::default(); 3];
16228 cache[0].index = 4;
16229 cache[0].symbol = 1;
16230 let mut buckets = vec![0; k];
16231 buckets[1] = 1;
16232 partial_sorting_scan_left_to_right_32s_1k_block_sort(&t, &mut buckets, &mut cache, 0, 1);
16233 assert_eq!(cache[0].symbol, 1);
16234 assert_eq!(buckets[1], 2);
16235 }
16236
16237 #[test]
16238 fn libsais16_partial_sorting_scan_32s_match_c() {
16239 let t = vec![0, 1, 2, 1, 3, 0];
16240 let k = 4;
16241
16242 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16243 let mut c_sa = rust_sa.clone();
16244 let mut rust_buckets = vec![0; 6 * k as usize];
16245 rust_buckets[buckets_index4(2, 0)] = 4;
16246 rust_buckets[buckets_index4(1, 1)] = 5;
16247 let mut c_buckets = rust_buckets.clone();
16248 let rust_d =
16249 partial_sorting_scan_left_to_right_32s_6k(&t, &mut rust_sa, &mut rust_buckets, 0, 0, 2);
16250 let c_d = unsafe {
16251 probe_libsais16_partial_sorting_scan_left_to_right_32s_6k(
16252 t.as_ptr(),
16253 c_sa.as_mut_ptr(),
16254 c_buckets.as_mut_ptr(),
16255 0,
16256 0,
16257 2,
16258 )
16259 };
16260 assert_eq!(rust_d, c_d);
16261 assert_eq!(rust_sa, c_sa);
16262 assert_eq!(rust_buckets, c_buckets);
16263
16264 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16265 let mut c_sa = rust_sa.clone();
16266 let mut rust_buckets = vec![0; 4 * k as usize];
16267 rust_buckets[2 * k as usize + 2] = 4;
16268 rust_buckets[2 * k as usize + 1] = 5;
16269 let mut c_buckets = rust_buckets.clone();
16270 let rust_d = partial_sorting_scan_left_to_right_32s_4k(
16271 &t,
16272 &mut rust_sa,
16273 k,
16274 &mut rust_buckets,
16275 0,
16276 0,
16277 2,
16278 );
16279 let c_d = unsafe {
16280 probe_libsais16_partial_sorting_scan_left_to_right_32s_4k(
16281 t.as_ptr(),
16282 c_sa.as_mut_ptr(),
16283 k,
16284 c_buckets.as_mut_ptr(),
16285 0,
16286 0,
16287 2,
16288 )
16289 };
16290 assert_eq!(rust_d, c_d);
16291 assert_eq!(rust_sa, c_sa);
16292 assert_eq!(rust_buckets, c_buckets);
16293
16294 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16295 let mut c_sa = rust_sa.clone();
16296 let mut rust_buckets = vec![0, 5, 4, 0];
16297 let mut c_buckets = rust_buckets.clone();
16298 partial_sorting_scan_left_to_right_32s_1k(&t, &mut rust_sa, &mut rust_buckets, 0, 2);
16299 unsafe {
16300 probe_libsais16_partial_sorting_scan_left_to_right_32s_1k(
16301 t.as_ptr(),
16302 c_sa.as_mut_ptr(),
16303 c_buckets.as_mut_ptr(),
16304 0,
16305 2,
16306 );
16307 }
16308 assert_eq!(rust_sa, c_sa);
16309 assert_eq!(rust_buckets, c_buckets);
16310
16311 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16312 let mut c_sa = rust_sa.clone();
16313 let mut rust_buckets = vec![0; 6 * k as usize];
16314 rust_buckets[buckets_index4(2, 0)] = 7;
16315 rust_buckets[buckets_index4(1, 1)] = 6;
16316 let mut c_buckets = rust_buckets.clone();
16317 let rust_d =
16318 partial_sorting_scan_right_to_left_32s_6k(&t, &mut rust_sa, &mut rust_buckets, 0, 0, 2);
16319 let c_d = unsafe {
16320 probe_libsais16_partial_sorting_scan_right_to_left_32s_6k(
16321 t.as_ptr(),
16322 c_sa.as_mut_ptr(),
16323 c_buckets.as_mut_ptr(),
16324 0,
16325 0,
16326 2,
16327 )
16328 };
16329 assert_eq!(rust_d, c_d);
16330 assert_eq!(rust_sa, c_sa);
16331 assert_eq!(rust_buckets, c_buckets);
16332
16333 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16334 let mut c_sa = rust_sa.clone();
16335 let mut rust_buckets = vec![0; 4 * k as usize];
16336 rust_buckets[3 * k as usize + 2] = 7;
16337 rust_buckets[3 * k as usize + 1] = 6;
16338 let mut c_buckets = rust_buckets.clone();
16339 let rust_d = partial_sorting_scan_right_to_left_32s_4k(
16340 &t,
16341 &mut rust_sa,
16342 k,
16343 &mut rust_buckets,
16344 0,
16345 0,
16346 2,
16347 );
16348 let c_d = unsafe {
16349 probe_libsais16_partial_sorting_scan_right_to_left_32s_4k(
16350 t.as_ptr(),
16351 c_sa.as_mut_ptr(),
16352 k,
16353 c_buckets.as_mut_ptr(),
16354 0,
16355 0,
16356 2,
16357 )
16358 };
16359 assert_eq!(rust_d, c_d);
16360 assert_eq!(rust_sa, c_sa);
16361 assert_eq!(rust_buckets, c_buckets);
16362
16363 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16364 let mut c_sa = rust_sa.clone();
16365 let mut rust_buckets = vec![0, 6, 7, 0];
16366 let mut c_buckets = rust_buckets.clone();
16367 partial_sorting_scan_right_to_left_32s_1k(&t, &mut rust_sa, &mut rust_buckets, 0, 2);
16368 unsafe {
16369 probe_libsais16_partial_sorting_scan_right_to_left_32s_1k(
16370 t.as_ptr(),
16371 c_sa.as_mut_ptr(),
16372 c_buckets.as_mut_ptr(),
16373 0,
16374 2,
16375 );
16376 }
16377 assert_eq!(rust_sa, c_sa);
16378 assert_eq!(rust_buckets, c_buckets);
16379
16380 let mut state = alloc_thread_state(1).unwrap();
16381 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 7, 9];
16382 let mut c_sa = rust_sa.clone();
16383 let mut rust_buckets = vec![0; 6 * k as usize];
16384 rust_buckets[buckets_index4(2, 0)] = 4;
16385 rust_buckets[buckets_index4(1, 1)] = 5;
16386 rust_buckets[buckets_index4(3, 0)] = 6;
16387 let mut c_buckets = rust_buckets.clone();
16388 let rust_d = partial_sorting_scan_left_to_right_32s_6k_omp(
16389 &t,
16390 &mut rust_sa,
16391 5,
16392 &mut rust_buckets,
16393 2,
16394 0,
16395 1,
16396 &mut state,
16397 );
16398 let c_d = unsafe {
16399 probe_libsais16_partial_sorting_scan_left_to_right_32s_6k_omp(
16400 t.as_ptr(),
16401 c_sa.as_mut_ptr(),
16402 5,
16403 c_buckets.as_mut_ptr(),
16404 2,
16405 0,
16406 1,
16407 )
16408 };
16409 assert_eq!(rust_d, c_d);
16410 assert_eq!(rust_sa, c_sa);
16411 assert_eq!(rust_buckets, c_buckets);
16412
16413 let mut state = alloc_thread_state(1).unwrap();
16414 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 7, 9];
16415 let mut c_sa = rust_sa.clone();
16416 let mut rust_buckets = vec![0; 4 * k as usize];
16417 rust_buckets[2 * k as usize + 2] = 4;
16418 rust_buckets[2 * k as usize + 1] = 5;
16419 rust_buckets[2 * k as usize + 3] = 6;
16420 let mut c_buckets = rust_buckets.clone();
16421 let rust_d = partial_sorting_scan_left_to_right_32s_4k_omp(
16422 &t,
16423 &mut rust_sa,
16424 5,
16425 k,
16426 &mut rust_buckets,
16427 0,
16428 1,
16429 &mut state,
16430 );
16431 let c_d = unsafe {
16432 probe_libsais16_partial_sorting_scan_left_to_right_32s_4k_omp(
16433 t.as_ptr(),
16434 c_sa.as_mut_ptr(),
16435 5,
16436 k,
16437 c_buckets.as_mut_ptr(),
16438 0,
16439 1,
16440 )
16441 };
16442 assert_eq!(rust_d, c_d);
16443 assert_eq!(rust_sa, c_sa);
16444 assert_eq!(rust_buckets, c_buckets);
16445
16446 let mut state = alloc_thread_state(1).unwrap();
16447 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 7, 9];
16448 let mut c_sa = rust_sa.clone();
16449 let mut rust_buckets = vec![0, 5, 4, 6];
16450 let mut c_buckets = rust_buckets.clone();
16451 partial_sorting_scan_left_to_right_32s_1k_omp(
16452 &t,
16453 &mut rust_sa,
16454 5,
16455 &mut rust_buckets,
16456 1,
16457 &mut state,
16458 );
16459 unsafe {
16460 probe_libsais16_partial_sorting_scan_left_to_right_32s_1k_omp(
16461 t.as_ptr(),
16462 c_sa.as_mut_ptr(),
16463 5,
16464 c_buckets.as_mut_ptr(),
16465 1,
16466 );
16467 }
16468 assert_eq!(rust_sa, c_sa);
16469 assert_eq!(rust_buckets, c_buckets);
16470
16471 let mut state = alloc_thread_state(1).unwrap();
16472 let mut rust_sa = vec![0, 0, 3, 4, 9, 9, 9, 9];
16473 let mut c_sa = rust_sa.clone();
16474 let mut rust_buckets = vec![0; 6 * k as usize];
16475 rust_buckets[buckets_index4(2, 0)] = 7;
16476 rust_buckets[buckets_index4(1, 1)] = 6;
16477 let mut c_buckets = rust_buckets.clone();
16478 let rust_d = partial_sorting_scan_right_to_left_32s_6k_omp(
16479 &t,
16480 &mut rust_sa,
16481 5,
16482 &mut rust_buckets,
16483 1,
16484 1,
16485 0,
16486 1,
16487 &mut state,
16488 );
16489 let c_d = unsafe {
16490 probe_libsais16_partial_sorting_scan_right_to_left_32s_6k_omp(
16491 t.as_ptr(),
16492 c_sa.as_mut_ptr(),
16493 5,
16494 c_buckets.as_mut_ptr(),
16495 1,
16496 1,
16497 0,
16498 1,
16499 )
16500 };
16501 assert_eq!(rust_d, c_d);
16502 assert_eq!(rust_sa, c_sa);
16503 assert_eq!(rust_buckets, c_buckets);
16504
16505 let mut state = alloc_thread_state(1).unwrap();
16506 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16507 let mut c_sa = rust_sa.clone();
16508 let mut rust_buckets = vec![0; 4 * k as usize];
16509 rust_buckets[3 * k as usize + 2] = 7;
16510 rust_buckets[3 * k as usize + 1] = 6;
16511 let mut c_buckets = rust_buckets.clone();
16512 let rust_d = partial_sorting_scan_right_to_left_32s_4k_omp(
16513 &t,
16514 &mut rust_sa,
16515 2,
16516 k,
16517 &mut rust_buckets,
16518 0,
16519 1,
16520 &mut state,
16521 );
16522 let c_d = unsafe {
16523 probe_libsais16_partial_sorting_scan_right_to_left_32s_4k_omp(
16524 t.as_ptr(),
16525 c_sa.as_mut_ptr(),
16526 2,
16527 k,
16528 c_buckets.as_mut_ptr(),
16529 0,
16530 1,
16531 )
16532 };
16533 assert_eq!(rust_d, c_d);
16534 assert_eq!(rust_sa, c_sa);
16535 assert_eq!(rust_buckets, c_buckets);
16536
16537 let mut state = alloc_thread_state(1).unwrap();
16538 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16539 let mut c_sa = rust_sa.clone();
16540 let mut rust_buckets = vec![0, 6, 7, 0];
16541 let mut c_buckets = rust_buckets.clone();
16542 partial_sorting_scan_right_to_left_32s_1k_omp(
16543 &t,
16544 &mut rust_sa,
16545 2,
16546 &mut rust_buckets,
16547 1,
16548 &mut state,
16549 );
16550 unsafe {
16551 probe_libsais16_partial_sorting_scan_right_to_left_32s_1k_omp(
16552 t.as_ptr(),
16553 c_sa.as_mut_ptr(),
16554 2,
16555 c_buckets.as_mut_ptr(),
16556 1,
16557 );
16558 }
16559 assert_eq!(rust_sa, c_sa);
16560 assert_eq!(rust_buckets, c_buckets);
16561 }
16562
16563 #[test]
16564 fn libsais16_place_lms_suffixes_histogram_32s_match_c() {
16565 let n = 12;
16566 let k = 4;
16567 let m = 4;
16568 let mut rust_sa = vec![101, 102, 103, 104, 9, 9, 9, 9, 9, 9, 9, 9];
16569 let mut c_sa = rust_sa.clone();
16570 let mut buckets = vec![0; 2 * k as usize];
16571 buckets[buckets_index2(1, 0)] = 7;
16572 buckets[buckets_index2(1, 1)] = 2;
16573 buckets[buckets_index2(2, 0)] = 10;
16574 buckets[buckets_index2(2, 1)] = 1;
16575 place_lms_suffixes_histogram_32s_2k(&mut rust_sa, n, k, m, &buckets);
16576 unsafe {
16577 probe_libsais16_place_lms_suffixes_histogram_32s_2k(
16578 c_sa.as_mut_ptr(),
16579 n,
16580 k,
16581 m,
16582 buckets.as_ptr(),
16583 );
16584 }
16585 assert_eq!(rust_sa, c_sa);
16586
16587 let mut rust_sa = vec![101, 102, 103, 104, 9, 9, 9, 9, 9, 9, 9, 9];
16588 let mut c_sa = rust_sa.clone();
16589 let mut buckets = vec![0; 4 * k as usize];
16590 buckets[buckets_index2(1, 1)] = 2;
16591 buckets[buckets_index2(2, 1)] = 1;
16592 buckets[3 * k as usize + 1] = 7;
16593 buckets[3 * k as usize + 2] = 10;
16594 place_lms_suffixes_histogram_32s_4k(&mut rust_sa, n, k, m, &buckets);
16595 unsafe {
16596 probe_libsais16_place_lms_suffixes_histogram_32s_4k(
16597 c_sa.as_mut_ptr(),
16598 n,
16599 k,
16600 m,
16601 buckets.as_ptr(),
16602 );
16603 }
16604 assert_eq!(rust_sa, c_sa);
16605
16606 let mut rust_sa = vec![101, 102, 103, 104, 9, 9, 9, 9, 9, 9, 9, 9];
16607 let mut c_sa = rust_sa.clone();
16608 let mut buckets = vec![0; 6 * k as usize];
16609 buckets[buckets_index4(1, 1)] = 2;
16610 buckets[buckets_index4(2, 1)] = 1;
16611 buckets[5 * k as usize + 1] = 7;
16612 buckets[5 * k as usize + 2] = 10;
16613 place_lms_suffixes_histogram_32s_6k(&mut rust_sa, n, k, m, &buckets);
16614 unsafe {
16615 probe_libsais16_place_lms_suffixes_histogram_32s_6k(
16616 c_sa.as_mut_ptr(),
16617 n,
16618 k,
16619 m,
16620 buckets.as_ptr(),
16621 );
16622 }
16623 assert_eq!(rust_sa, c_sa);
16624 }
16625
16626 #[test]
16627 fn libsais16_count_gather_lms_suffixes_32s_match_c() {
16628 let t = vec![2, 1, 3, 1, 2, 0, 1, 0];
16629 let n = t.len() as SaSint;
16630 let k = 4;
16631
16632 let mut rust_sa = vec![0; t.len()];
16633 let mut c_sa = rust_sa.clone();
16634 let rust_m = gather_lms_suffixes_32s(&t, &mut rust_sa, n);
16635 let c_m =
16636 unsafe { probe_libsais16_gather_lms_suffixes_32s(t.as_ptr(), c_sa.as_mut_ptr(), n) };
16637 assert_eq!(rust_m, c_m);
16638 assert_eq!(rust_sa, c_sa);
16639
16640 let compact_t = vec![2, SAINT_MIN | 1, 3, 1, SAINT_MIN | 2, 0, 1, 0];
16641 let mut rust_sa = vec![0; compact_t.len()];
16642 let mut c_sa = rust_sa.clone();
16643 let rust_m = gather_compacted_lms_suffixes_32s(&compact_t, &mut rust_sa, n);
16644 let c_m = unsafe {
16645 probe_libsais16_gather_compacted_lms_suffixes_32s(
16646 compact_t.as_ptr(),
16647 c_sa.as_mut_ptr(),
16648 n,
16649 )
16650 };
16651 assert_eq!(rust_m, c_m);
16652 assert_eq!(rust_sa, c_sa);
16653
16654 let mut rust_buckets = vec![99; 2 * k as usize];
16655 let mut c_buckets = rust_buckets.clone();
16656 count_lms_suffixes_32s_2k(&t, n, k, &mut rust_buckets);
16657 unsafe {
16658 probe_libsais16_count_lms_suffixes_32s_2k(t.as_ptr(), n, k, c_buckets.as_mut_ptr());
16659 }
16660 assert_eq!(rust_buckets, c_buckets);
16661
16662 let mut rust_sa = vec![0; t.len()];
16663 let mut c_sa = rust_sa.clone();
16664 let mut rust_buckets = vec![0; 2 * k as usize];
16665 let mut c_buckets = rust_buckets.clone();
16666 let rust_m = count_and_gather_lms_suffixes_32s_2k(
16667 &t,
16668 &mut rust_sa,
16669 n,
16670 k,
16671 &mut rust_buckets,
16672 0,
16673 n as isize,
16674 );
16675 let c_m = unsafe {
16676 probe_libsais16_count_and_gather_lms_suffixes_32s_2k(
16677 t.as_ptr(),
16678 c_sa.as_mut_ptr(),
16679 n,
16680 k,
16681 c_buckets.as_mut_ptr(),
16682 0,
16683 n,
16684 )
16685 };
16686 assert_eq!(rust_m, c_m);
16687 assert_eq!(rust_sa, c_sa);
16688 assert_eq!(rust_buckets, c_buckets);
16689
16690 let mut rust_sa = vec![0; compact_t.len()];
16691 let mut c_sa = rust_sa.clone();
16692 let mut rust_buckets = vec![0; 2 * k as usize];
16693 let mut c_buckets = rust_buckets.clone();
16694 let rust_m = count_and_gather_compacted_lms_suffixes_32s_2k(
16695 &compact_t,
16696 &mut rust_sa,
16697 n,
16698 k,
16699 &mut rust_buckets,
16700 0,
16701 n as isize,
16702 );
16703 let c_m = unsafe {
16704 probe_libsais16_count_and_gather_compacted_lms_suffixes_32s_2k(
16705 compact_t.as_ptr(),
16706 c_sa.as_mut_ptr(),
16707 n,
16708 k,
16709 c_buckets.as_mut_ptr(),
16710 0,
16711 n,
16712 )
16713 };
16714 assert_eq!(rust_m, c_m);
16715 assert_eq!(rust_sa, c_sa);
16716 assert_eq!(rust_buckets, c_buckets);
16717 }
16718
16719 #[test]
16720 fn libsais16_small_openmp_leaf_helpers_match_upstream_shapes() {
16721 let sa = [-1, 0, 3, SAINT_MIN, 0, 7, -5];
16722 assert_eq!(count_negative_marked_suffixes(&sa, 1, 5), 1);
16723 assert_eq!(count_zero_marked_suffixes(&sa, 1, 5), 2);
16724
16725 let mut buckets = vec![1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9, 0, 10, 11, 12, 0];
16726 accumulate_counts_s32_4(&mut buckets, 12, 3, 4);
16727 assert_eq!(&buckets[12..15], &[22, 26, 30]);
16728
16729 let mut many = Vec::new();
16730 for bucket in 0..10 {
16731 many.extend([bucket, bucket + 1, bucket + 2, 0]);
16732 }
16733 accumulate_counts_s32(&mut many, 36, 3, 4, 10);
16734 assert_eq!(&many[36..39], &[45, 55, 65]);
16735
16736 let t = [1, SAINT_MIN | 2, 0];
16737 let mut compacted_buckets = vec![0; 6];
16738 count_compacted_lms_suffixes_32s_2k(&t, t.len() as SaSint, 3, &mut compacted_buckets);
16739 assert_eq!(compacted_buckets, vec![1, 0, 1, 0, 0, 1]);
16740
16741 let unique_sa = [0, 2, 4, 6, 0, -10, 20, -30];
16742 assert_eq!(count_unique_suffixes(&unique_sa, 4, 0, 4), 2);
16743
16744 assert_eq!(get_bucket_stride(20_000, 1000, 4), 1024);
16745 assert_eq!(get_bucket_stride(3024, 1001, 4), 1008);
16746 assert_eq!(get_bucket_stride(3000, 1001, 4), 1001);
16747 }
16748
16749 #[test]
16750 fn libsais16_count_gather_lms_suffixes_32s_omp_wrappers_match_c() {
16751 let t = vec![2, 1, 3, 1, 2, 0, 1, 0];
16752 let n = t.len() as SaSint;
16753 let k = 4;
16754 let mut rust_sa = vec![0; t.len()];
16755 let mut c_sa = rust_sa.clone();
16756 let mut rust_buckets = vec![0; 2 * k as usize];
16757 let mut c_buckets = rust_buckets.clone();
16758 let mut rust_state = alloc_thread_state(1).unwrap();
16759 let rust_m = count_and_gather_lms_suffixes_32s_2k_omp(
16760 &t,
16761 &mut rust_sa,
16762 n,
16763 k,
16764 &mut rust_buckets,
16765 0,
16766 1,
16767 &mut rust_state,
16768 );
16769 let c_m = unsafe {
16770 probe_libsais16_count_and_gather_lms_suffixes_32s_2k_omp(
16771 t.as_ptr(),
16772 c_sa.as_mut_ptr(),
16773 n,
16774 k,
16775 c_buckets.as_mut_ptr(),
16776 0,
16777 1,
16778 )
16779 };
16780 assert_eq!(rust_m, c_m);
16781 assert_eq!(rust_sa, c_sa);
16782 assert_eq!(rust_buckets, c_buckets);
16783
16784 let compact_t = vec![2, SAINT_MIN | 1, 3, 1, SAINT_MIN | 2, 0, 1, 0];
16785 let mut rust_sa = vec![0; compact_t.len()];
16786 let mut c_sa = rust_sa.clone();
16787 let mut rust_buckets = vec![0; 2 * k as usize];
16788 let mut c_buckets = rust_buckets.clone();
16789 let mut rust_state = alloc_thread_state(1).unwrap();
16790 count_and_gather_compacted_lms_suffixes_32s_2k_omp(
16791 &compact_t,
16792 &mut rust_sa,
16793 n,
16794 k,
16795 &mut rust_buckets,
16796 0,
16797 1,
16798 &mut rust_state,
16799 );
16800 unsafe {
16801 probe_libsais16_count_and_gather_compacted_lms_suffixes_32s_2k_omp(
16802 compact_t.as_ptr(),
16803 c_sa.as_mut_ptr(),
16804 n,
16805 k,
16806 c_buckets.as_mut_ptr(),
16807 0,
16808 1,
16809 );
16810 }
16811 assert_eq!(rust_sa, c_sa);
16812 assert_eq!(rust_buckets, c_buckets);
16813 }
16814
16815 #[test]
16816 fn libsais16_count_gather_lms_suffixes_32s_4k_match_c() {
16817 let t = vec![2, 1, 3, 1, 2, 0, 1, 0];
16818 let n = t.len() as SaSint;
16819 let k = 4;
16820
16821 let mut rust_buckets = vec![77; 4 * k as usize];
16822 let mut c_buckets = vec![0; 4 * k as usize];
16823 let mut c_sa_for_count = vec![0; t.len()];
16824 count_lms_suffixes_32s_4k(&t, n, k, &mut rust_buckets);
16825 unsafe {
16826 probe_libsais16_count_and_gather_lms_suffixes_32s_4k(
16827 t.as_ptr(),
16828 c_sa_for_count.as_mut_ptr(),
16829 n,
16830 k,
16831 c_buckets.as_mut_ptr(),
16832 0,
16833 n,
16834 );
16835 }
16836 assert_eq!(rust_buckets, c_buckets);
16837
16838 let mut rust_sa = vec![0; t.len()];
16839 let mut c_sa = rust_sa.clone();
16840 let mut rust_buckets = vec![0; 4 * k as usize];
16841 let mut c_buckets = rust_buckets.clone();
16842 let rust_m = count_and_gather_lms_suffixes_32s_4k(
16843 &t,
16844 &mut rust_sa,
16845 n,
16846 k,
16847 &mut rust_buckets,
16848 0,
16849 n as isize,
16850 );
16851 let c_m = unsafe {
16852 probe_libsais16_count_and_gather_lms_suffixes_32s_4k(
16853 t.as_ptr(),
16854 c_sa.as_mut_ptr(),
16855 n,
16856 k,
16857 c_buckets.as_mut_ptr(),
16858 0,
16859 n,
16860 )
16861 };
16862 assert_eq!(rust_m, c_m);
16863 assert_eq!(rust_sa, c_sa);
16864 assert_eq!(rust_buckets, c_buckets);
16865
16866 let mut rust_sa = vec![0; t.len()];
16867 let mut c_sa = rust_sa.clone();
16868 let mut rust_buckets = vec![0; 4 * k as usize];
16869 let mut c_buckets = rust_buckets.clone();
16870 let mut rust_state = alloc_thread_state(1).unwrap();
16871 let rust_m = count_and_gather_lms_suffixes_32s_4k_omp(
16872 &t,
16873 &mut rust_sa,
16874 n,
16875 k,
16876 &mut rust_buckets,
16877 0,
16878 1,
16879 &mut rust_state,
16880 );
16881 let c_m = unsafe {
16882 probe_libsais16_count_and_gather_lms_suffixes_32s_4k_omp(
16883 t.as_ptr(),
16884 c_sa.as_mut_ptr(),
16885 n,
16886 k,
16887 c_buckets.as_mut_ptr(),
16888 0,
16889 1,
16890 )
16891 };
16892 assert_eq!(rust_m, c_m);
16893 assert_eq!(rust_sa, c_sa);
16894 assert_eq!(rust_buckets, c_buckets);
16895
16896 let mut rust_buckets = vec![91; k as usize];
16897 let mut c_buckets = rust_buckets.clone();
16898 count_suffixes_32s(&t, n, k, &mut rust_buckets);
16899 unsafe {
16900 probe_libsais16_count_suffixes_32s(t.as_ptr(), n, k, c_buckets.as_mut_ptr());
16901 }
16902 assert_eq!(rust_buckets, c_buckets);
16903 }
16904
16905 #[test]
16906 fn libsais16_initialize_buckets_32s_match_c() {
16907 let k = 4;
16908
16909 let base_6k = vec![
16910 1, 2, 0, 1, 0, 1, 2, 0, 3, 0, 1, 1, 2, 1, 0, 0, 9, 9, 9, 9, 8, 8, 8, 8,
16911 ];
16912 let mut rust = base_6k.clone();
16913 let mut c = base_6k.clone();
16914 initialize_buckets_start_and_end_32s_6k(k, &mut rust);
16915 unsafe { probe_libsais16_initialize_buckets_start_and_end_32s_6k(k, c.as_mut_ptr()) };
16916 assert_eq!(rust, c);
16917
16918 let base_4k = vec![1, 2, 0, 1, 3, 0, 2, 1, 9, 9, 9, 9, 8, 8, 8, 8];
16919 let mut rust = base_4k.clone();
16920 let mut c = base_4k.clone();
16921 initialize_buckets_start_and_end_32s_4k(k, &mut rust);
16922 unsafe { probe_libsais16_initialize_buckets_start_and_end_32s_4k(k, c.as_mut_ptr()) };
16923 assert_eq!(rust, c);
16924
16925 let base_2k = vec![1, 2, 0, 1, 3, 0, 2, 1];
16926 let mut rust = base_2k.clone();
16927 let mut c = base_2k.clone();
16928 initialize_buckets_end_32s_2k(k, &mut rust);
16929 unsafe { probe_libsais16_initialize_buckets_end_32s_2k(k, c.as_mut_ptr()) };
16930 assert_eq!(rust, c);
16931
16932 let mut rust = base_2k.clone();
16933 let mut c = base_2k.clone();
16934 initialize_buckets_start_and_end_32s_2k(k, &mut rust);
16935 unsafe { probe_libsais16_initialize_buckets_start_and_end_32s_2k(k, c.as_mut_ptr()) };
16936 assert_eq!(rust, c);
16937
16938 let base_1k = vec![2, 1, 3, 2];
16939 let mut rust = base_1k.clone();
16940 let mut c = base_1k.clone();
16941 initialize_buckets_start_32s_1k(k, &mut rust);
16942 unsafe { probe_libsais16_initialize_buckets_start_32s_1k(k, c.as_mut_ptr()) };
16943 assert_eq!(rust, c);
16944
16945 let mut rust = base_1k.clone();
16946 let mut c = base_1k.clone();
16947 initialize_buckets_end_32s_1k(k, &mut rust);
16948 unsafe { probe_libsais16_initialize_buckets_end_32s_1k(k, c.as_mut_ptr()) };
16949 assert_eq!(rust, c);
16950
16951 let t = vec![2, 1, 3, 1, 2, 0, 1, 0];
16952 let mut rust = vec![1, 2, 0, 1, 3, 0, 2, 1];
16953 let mut c = rust.clone();
16954 initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(&t, k, &mut rust, 4);
16955 unsafe {
16956 probe_libsais16_initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(
16957 t.as_ptr(),
16958 k,
16959 c.as_mut_ptr(),
16960 4,
16961 );
16962 }
16963 assert_eq!(rust, c);
16964
16965 let mut rust = vec![
16966 1, 2, 0, 1, 3, 0, 2, 1, 1, 0, 2, 0, 0, 1, 1, 0, 9, 9, 9, 9, 8, 8, 8, 8,
16967 ];
16968 let mut c = rust.clone();
16969 let rust_sum = initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(&t, k, &mut rust, 4);
16970 let c_sum = unsafe {
16971 probe_libsais16_initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(
16972 t.as_ptr(),
16973 k,
16974 c.as_mut_ptr(),
16975 4,
16976 )
16977 };
16978 assert_eq!(rust_sum, c_sum);
16979 assert_eq!(rust, c);
16980
16981 let mut rust = base_4k.clone();
16982 let mut c = base_4k;
16983 initialize_buckets_for_radix_and_partial_sorting_32s_4k(&t, k, &mut rust, 4);
16984 unsafe {
16985 probe_libsais16_initialize_buckets_for_radix_and_partial_sorting_32s_4k(
16986 t.as_ptr(),
16987 k,
16988 c.as_mut_ptr(),
16989 4,
16990 );
16991 }
16992 assert_eq!(rust, c);
16993 }
16994
16995 #[test]
16996 fn libsais16_place_lms_suffixes_interval_32s_match_c() {
16997 let n = 12;
16998 let k = 4;
16999 let m = 4;
17000
17001 let mut rust_sa = vec![101, 102, 103, 104, 9, 9, 9, 9, 9, 9, 9, 9];
17002 let mut c_sa = rust_sa.clone();
17003 let mut buckets = vec![0; 4 * k as usize];
17004 buckets[buckets_index2(0, 1)] = 2;
17005 buckets[buckets_index2(1, 1)] = 2;
17006 buckets[buckets_index2(2, 1)] = 3;
17007 buckets[buckets_index2(2, 1) + buckets_index2(1, 0)] = 4;
17008 buckets[3 * k as usize + 1] = 7;
17009 buckets[3 * k as usize + 2] = 10;
17010 place_lms_suffixes_interval_32s_4k(&mut rust_sa, n, k, m, &buckets);
17011 unsafe {
17012 probe_libsais16_place_lms_suffixes_interval_32s_4k(
17013 c_sa.as_mut_ptr(),
17014 n,
17015 k,
17016 m,
17017 buckets.as_ptr(),
17018 );
17019 }
17020 assert_eq!(rust_sa, c_sa);
17021
17022 let mut rust_sa = vec![101, 102, 103, 104, 9, 9, 9, 9, 9, 9, 9, 9];
17023 let mut c_sa = rust_sa.clone();
17024 let mut buckets = vec![0; 2 * k as usize];
17025 buckets[buckets_index2(1, 0)] = 7;
17026 buckets[buckets_index2(0, 1)] = 1;
17027 buckets[buckets_index2(1, 1)] = 1;
17028 buckets[buckets_index2(2, 0)] = 10;
17029 buckets[buckets_index2(2, 1)] = 2;
17030 buckets[buckets_index2(3, 1)] = 3;
17031 place_lms_suffixes_interval_32s_2k(&mut rust_sa, n, k, m, &buckets);
17032 unsafe {
17033 probe_libsais16_place_lms_suffixes_interval_32s_2k(
17034 c_sa.as_mut_ptr(),
17035 n,
17036 k,
17037 m,
17038 buckets.as_ptr(),
17039 );
17040 }
17041 assert_eq!(rust_sa, c_sa);
17042
17043 let t = vec![0, 1, 2, 1, 2, 3, 1, 3, 0, 0, 0, 0];
17044 let mut rust_sa = vec![1, 3, 4, 7, 9, 9, 9, 9, 9, 9, 9, 9];
17045 let mut c_sa = rust_sa.clone();
17046 let rust_buckets = vec![0, 3, 6, 10];
17047 let mut c_buckets = rust_buckets.clone();
17048 place_lms_suffixes_interval_32s_1k(&t, &mut rust_sa, k, m, &rust_buckets);
17049 unsafe {
17050 probe_libsais16_place_lms_suffixes_interval_32s_1k(
17051 t.as_ptr(),
17052 c_sa.as_mut_ptr(),
17053 k,
17054 m,
17055 c_buckets.as_mut_ptr(),
17056 );
17057 }
17058 assert_eq!(rust_sa, c_sa);
17059 assert_eq!(rust_buckets, c_buckets);
17060 }
17061
17062 #[test]
17063 fn libsais16_renumber_and_mark_distinct_lms_suffixes_32s_1k_matches_c() {
17064 let rust_t = vec![2, 1, 3, 1, 2, 0, 1, 0];
17065 let n = rust_t.len() as SaSint;
17066 let mut probe_sa = vec![0; rust_t.len()];
17067 let m = gather_lms_suffixes_32s(&rust_t, &mut probe_sa, n);
17068 let mut rust_sa = vec![0; rust_t.len()];
17069 let mut c_t = rust_t.clone();
17070 let mut c_sa = rust_sa.clone();
17071
17072 let rust_name =
17073 renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(&rust_t, &mut rust_sa, n, m, 1);
17074 let c_name = unsafe {
17075 probe_libsais16_renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(
17076 c_t.as_mut_ptr(),
17077 c_sa.as_mut_ptr(),
17078 n,
17079 m,
17080 1,
17081 )
17082 };
17083 assert_eq!(rust_name, c_name);
17084 assert_eq!(rust_t, c_t);
17085 assert_eq!(rust_sa, c_sa);
17086 }
17087
17088 #[test]
17089 fn libsais16_reconstruct_compacted_lms_suffixes_32s_match_c() {
17090 let n = 8;
17091 let k = 4;
17092 let fs = 0;
17093 let f = 0;
17094 let mut m_probe_sa = vec![0; n as usize];
17095 let m = gather_lms_suffixes_32s(&[2, 1, 3, 1, 2, 0, 1, 0], &mut m_probe_sa, n);
17096
17097 let mut rust_t = vec![2, 1, 3, 1, 2, 0, 1, 0];
17098 let mut c_t = rust_t.clone();
17099 let mut rust_sa = vec![0; n as usize];
17100 let mut c_sa = rust_sa.clone();
17101 let mut rust_buckets = vec![0; 2 * k as usize];
17102 let mut c_buckets = rust_buckets.clone();
17103 let mut rust_thread_state = alloc_thread_state(1).unwrap();
17104 reconstruct_compacted_lms_suffixes_32s_2k_omp(
17105 &mut rust_t,
17106 &mut rust_sa,
17107 n,
17108 k,
17109 m,
17110 fs,
17111 f,
17112 &mut rust_buckets,
17113 0,
17114 1,
17115 &mut rust_thread_state,
17116 );
17117 unsafe {
17118 probe_libsais16_reconstruct_compacted_lms_suffixes_32s_2k_omp(
17119 c_t.as_mut_ptr(),
17120 c_sa.as_mut_ptr(),
17121 n,
17122 k,
17123 m,
17124 fs,
17125 f,
17126 c_buckets.as_mut_ptr(),
17127 0,
17128 1,
17129 );
17130 }
17131 assert_eq!(rust_t, c_t);
17132 assert_eq!(rust_sa, c_sa);
17133 assert_eq!(rust_buckets, c_buckets);
17134
17135 let mut rust_t = vec![2, 1, 3, 1, 2, 0, 1, 0];
17136 let mut c_t = rust_t.clone();
17137 let mut rust_sa = vec![0; n as usize];
17138 let mut c_sa = rust_sa.clone();
17139 reconstruct_compacted_lms_suffixes_32s_1k_omp(&mut rust_t, &mut rust_sa, n, m, fs, f, 1);
17140 unsafe {
17141 probe_libsais16_reconstruct_compacted_lms_suffixes_32s_1k_omp(
17142 c_t.as_mut_ptr(),
17143 c_sa.as_mut_ptr(),
17144 n,
17145 m,
17146 fs,
17147 f,
17148 1,
17149 );
17150 }
17151 assert_eq!(rust_t, c_t);
17152 assert_eq!(rust_sa, c_sa);
17153 }
17154
17155 #[test]
17156 fn libsais16_partial_omp_wrappers_match_c() {
17157 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
17158 let mut c_sa = rust_sa.clone();
17159 let mut c_buckets = rust_buckets.clone();
17160
17161 let rust_d = partial_sorting_scan_left_to_right_16u_omp(
17162 &text,
17163 &mut rust_sa,
17164 text.len() as SaSint,
17165 8,
17166 &mut rust_buckets,
17167 5,
17168 3,
17169 1,
17170 );
17171 let c_d = unsafe {
17172 probe_libsais16_partial_sorting_scan_left_to_right_16u_omp(
17173 text.as_ptr(),
17174 c_sa.as_mut_ptr(),
17175 text.len() as SaSint,
17176 8,
17177 c_buckets.as_mut_ptr(),
17178 5,
17179 3,
17180 1,
17181 )
17182 };
17183 assert_eq!(rust_d, c_d);
17184 assert_eq!(rust_sa, c_sa);
17185 assert_eq!(rust_buckets, c_buckets);
17186
17187 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
17188 rust_sa[6..10].copy_from_slice(&[3, 5 | SAINT_MIN, 7, 9 | SAINT_MIN]);
17189 let mut c_sa = rust_sa.clone();
17190 let mut c_buckets = rust_buckets.clone();
17191 partial_sorting_scan_right_to_left_16u_omp(
17192 &text,
17193 &mut rust_sa,
17194 text.len() as SaSint,
17195 8,
17196 &mut rust_buckets,
17197 0,
17198 5,
17199 3,
17200 1,
17201 );
17202 unsafe {
17203 probe_libsais16_partial_sorting_scan_right_to_left_16u_omp(
17204 text.as_ptr(),
17205 c_sa.as_mut_ptr(),
17206 text.len() as SaSint,
17207 8,
17208 c_buckets.as_mut_ptr(),
17209 0,
17210 5,
17211 3,
17212 1,
17213 );
17214 }
17215 assert_eq!(rust_sa, c_sa);
17216 assert_eq!(rust_buckets, c_buckets);
17217
17218 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
17219 rust_sa[6..10].copy_from_slice(&[3, 5 | SAINT_MIN, 7, 9 | SAINT_MIN]);
17220 let mut c_sa = rust_sa.clone();
17221 let mut c_buckets = rust_buckets.clone();
17222 partial_gsa_scan_right_to_left_16u_omp(
17223 &text,
17224 &mut rust_sa,
17225 text.len() as SaSint,
17226 8,
17227 &mut rust_buckets,
17228 0,
17229 5,
17230 3,
17231 1,
17232 );
17233 unsafe {
17234 probe_libsais16_partial_gsa_scan_right_to_left_16u_omp(
17235 text.as_ptr(),
17236 c_sa.as_mut_ptr(),
17237 text.len() as SaSint,
17238 8,
17239 c_buckets.as_mut_ptr(),
17240 0,
17241 5,
17242 3,
17243 1,
17244 );
17245 }
17246 assert_eq!(rust_sa, c_sa);
17247 assert_eq!(rust_buckets, c_buckets);
17248 }
17249
17250 #[test]
17251 fn libsais16_final_omp_wrappers_match_c() {
17252 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17253 let mut c_sa = rust_sa.clone();
17254 let mut c_bucket = rust_bucket.clone();
17255 final_bwt_scan_left_to_right_16u_omp(
17256 &text,
17257 &mut rust_sa,
17258 text.len() as SaSint,
17259 8,
17260 &mut rust_bucket,
17261 1,
17262 );
17263 unsafe {
17264 probe_libsais16_final_bwt_scan_left_to_right_16u_omp(
17265 text.as_ptr(),
17266 c_sa.as_mut_ptr(),
17267 text.len() as SaSint,
17268 8,
17269 c_bucket.as_mut_ptr(),
17270 1,
17271 );
17272 }
17273 assert_eq!(rust_sa, c_sa);
17274 assert_eq!(rust_bucket, c_bucket);
17275
17276 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17277 let mut c_sa = rust_sa.clone();
17278 let mut c_bucket = rust_bucket.clone();
17279 let mut rust_i = vec![-1; 8];
17280 let mut c_i = rust_i.clone();
17281 final_bwt_aux_scan_left_to_right_16u_omp(
17282 &text,
17283 &mut rust_sa,
17284 text.len() as SaSint,
17285 8,
17286 1,
17287 &mut rust_i,
17288 &mut rust_bucket,
17289 1,
17290 );
17291 unsafe {
17292 probe_libsais16_final_bwt_aux_scan_left_to_right_16u_omp(
17293 text.as_ptr(),
17294 c_sa.as_mut_ptr(),
17295 text.len() as SaSint,
17296 8,
17297 1,
17298 c_i.as_mut_ptr(),
17299 c_bucket.as_mut_ptr(),
17300 1,
17301 );
17302 }
17303 assert_eq!(rust_sa, c_sa);
17304 assert_eq!(rust_bucket, c_bucket);
17305 assert_eq!(rust_i, c_i);
17306
17307 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17308 let mut c_sa = rust_sa.clone();
17309 let mut c_bucket = rust_bucket.clone();
17310 final_sorting_scan_left_to_right_16u_omp(
17311 &text,
17312 &mut rust_sa,
17313 text.len() as SaSint,
17314 8,
17315 &mut rust_bucket,
17316 1,
17317 );
17318 unsafe {
17319 probe_libsais16_final_sorting_scan_left_to_right_16u_omp(
17320 text.as_ptr(),
17321 c_sa.as_mut_ptr(),
17322 text.len() as SaSint,
17323 8,
17324 c_bucket.as_mut_ptr(),
17325 1,
17326 );
17327 }
17328 assert_eq!(rust_sa, c_sa);
17329 assert_eq!(rust_bucket, c_bucket);
17330
17331 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17332 let mut c_sa = rust_sa.clone();
17333 let mut c_bucket = rust_bucket.clone();
17334 let rust_index = final_bwt_scan_right_to_left_16u_omp(
17335 &text,
17336 &mut rust_sa,
17337 text.len() as SaSint,
17338 8,
17339 &mut rust_bucket,
17340 1,
17341 );
17342 let c_index = unsafe {
17343 probe_libsais16_final_bwt_scan_right_to_left_16u_omp(
17344 text.as_ptr(),
17345 c_sa.as_mut_ptr(),
17346 text.len() as SaSint,
17347 8,
17348 c_bucket.as_mut_ptr(),
17349 1,
17350 )
17351 };
17352 assert_eq!(rust_index, c_index);
17353 assert_eq!(rust_sa, c_sa);
17354 assert_eq!(rust_bucket, c_bucket);
17355
17356 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17357 let mut c_sa = rust_sa.clone();
17358 let mut c_bucket = rust_bucket.clone();
17359 let mut rust_i = vec![-1; 8];
17360 let mut c_i = rust_i.clone();
17361 final_bwt_aux_scan_right_to_left_16u_omp(
17362 &text,
17363 &mut rust_sa,
17364 text.len() as SaSint,
17365 8,
17366 1,
17367 &mut rust_i,
17368 &mut rust_bucket,
17369 1,
17370 );
17371 unsafe {
17372 probe_libsais16_final_bwt_aux_scan_right_to_left_16u_omp(
17373 text.as_ptr(),
17374 c_sa.as_mut_ptr(),
17375 text.len() as SaSint,
17376 8,
17377 1,
17378 c_i.as_mut_ptr(),
17379 c_bucket.as_mut_ptr(),
17380 1,
17381 );
17382 }
17383 assert_eq!(rust_sa, c_sa);
17384 assert_eq!(rust_bucket, c_bucket);
17385 assert_eq!(rust_i, c_i);
17386
17387 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17388 let mut c_sa = rust_sa.clone();
17389 let mut c_bucket = rust_bucket.clone();
17390 final_sorting_scan_right_to_left_16u_omp(&text, &mut rust_sa, 0, 6, 8, &mut rust_bucket, 1);
17391 unsafe {
17392 probe_libsais16_final_sorting_scan_right_to_left_16u_omp(
17393 text.as_ptr(),
17394 c_sa.as_mut_ptr(),
17395 0,
17396 6,
17397 8,
17398 c_bucket.as_mut_ptr(),
17399 1,
17400 );
17401 }
17402 assert_eq!(rust_sa, c_sa);
17403 assert_eq!(rust_bucket, c_bucket);
17404
17405 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17406 let mut c_sa = rust_sa.clone();
17407 let mut c_bucket = rust_bucket.clone();
17408 final_gsa_scan_right_to_left_16u_omp(&text, &mut rust_sa, 0, 6, 8, &mut rust_bucket, 1);
17409 unsafe {
17410 probe_libsais16_final_gsa_scan_right_to_left_16u_omp(
17411 text.as_ptr(),
17412 c_sa.as_mut_ptr(),
17413 0,
17414 6,
17415 8,
17416 c_bucket.as_mut_ptr(),
17417 1,
17418 );
17419 }
17420 assert_eq!(rust_sa, c_sa);
17421 assert_eq!(rust_bucket, c_bucket);
17422 }
17423
17424 #[test]
17425 fn libsais16_matches_bruteforce() {
17426 let t = [3, 1, 4, 1, 5, 9, 0, 2];
17427 let mut sa = vec![0; t.len()];
17428 let mut freq = vec![0; ALPHABET_SIZE];
17429 assert_eq!(libsais16(&t, &mut sa, 0, Some(&mut freq)), 0);
17430 assert_eq!(sa, brute_sa(&t));
17431 assert_eq!(freq[1], 2);
17432 assert_eq!(freq[9], 1);
17433 }
17434
17435 #[test]
17436 fn libsais16_bwt_round_trips() {
17437 let t = [2, 1, 3, 1, 2, 4, 1, 0];
17438 let mut bwt = vec![0; t.len()];
17439 let mut work = vec![0; t.len()];
17440 let primary = libsais16_bwt(&t, &mut bwt, &mut work, 0, None);
17441 assert!(primary > 0);
17442
17443 let mut restored = vec![0; t.len()];
17444 assert_eq!(
17445 libsais16_unbwt(&bwt, &mut restored, &mut work, None, primary),
17446 0
17447 );
17448 assert_eq!(restored, t);
17449 }
17450
17451 #[test]
17452 fn libsais16_plcp_lcp_are_consistent() {
17453 let t = [2, 1, 2, 1, 0];
17454 let sa = brute_sa(&t);
17455 let mut plcp = vec![0; t.len()];
17456 let mut lcp = vec![0; t.len()];
17457 assert_eq!(libsais16_plcp(&t, &sa, &mut plcp), 0);
17458 assert_eq!(libsais16_lcp(&plcp, &sa, &mut lcp), 0);
17459 assert_eq!(lcp[0], 0);
17460
17461 let mut named_plcp = vec![0; t.len()];
17462 assert_eq!(
17463 compute_phi_omp(&sa, &mut named_plcp, t.len() as SaSint, 1),
17464 0
17465 );
17466 assert_eq!(
17467 compute_plcp_omp(&t, &mut named_plcp, t.len() as SaSint, 1),
17468 0
17469 );
17470 assert_eq!(named_plcp, plcp);
17471
17472 let mut named_lcp = vec![0; t.len()];
17473 assert_eq!(
17474 compute_lcp_omp(&named_plcp, &sa, &mut named_lcp, t.len() as SaSint, 1),
17475 0
17476 );
17477 assert_eq!(named_lcp, lcp);
17478
17479 let mut gsa_plcp = vec![0; t.len()];
17480 let mut named_gsa_plcp = vec![0; t.len()];
17481 assert_eq!(libsais16_plcp_gsa(&t, &sa, &mut gsa_plcp), 0);
17482 assert_eq!(
17483 compute_phi_omp(&sa, &mut named_gsa_plcp, t.len() as SaSint, 1),
17484 0
17485 );
17486 assert_eq!(
17487 compute_plcp_gsa_omp(&t, &mut named_gsa_plcp, t.len() as SaSint, 1),
17488 0
17489 );
17490 assert_eq!(named_gsa_plcp, gsa_plcp);
17491 }
17492
17493 #[test]
17494 fn libsais16_bwt_copy_16u_omp_uses_block_partition_for_large_inputs() {
17495 let n = 65_600usize;
17496 let a: Vec<SaSint> = (0..n).map(|i| (i * 17) as SaSint).collect();
17497 let mut threaded = vec![0; n];
17498 let mut sequential = vec![0; n];
17499
17500 bwt_copy_16u_omp(&mut threaded, &a, n as SaSint, 4);
17501 bwt_copy_16u(&mut sequential, &a, n as SaSint);
17502
17503 assert_eq!(threaded, sequential);
17504 }
17505
17506 #[test]
17507 fn libsais16_plcp_lcp_omp_wrappers_match_single_thread_on_large_inputs() {
17508 let n = 65_600usize;
17509 let text: Vec<u16> = (0..n).map(|i| 1 + (i % 251) as u16).collect();
17510 let sa: Vec<SaSint> = (0..n as SaSint).collect();
17511
17512 let mut plcp_single = vec![0; n];
17513 let mut plcp_threaded = vec![0; n];
17514 assert_eq!(compute_phi_omp(&sa, &mut plcp_single, n as SaSint, 1), 0);
17515 assert_eq!(compute_phi_omp(&sa, &mut plcp_threaded, n as SaSint, 4), 0);
17516 assert_eq!(plcp_threaded, plcp_single);
17517
17518 assert_eq!(compute_plcp_omp(&text, &mut plcp_single, n as SaSint, 1), 0);
17519 assert_eq!(
17520 compute_plcp_omp(&text, &mut plcp_threaded, n as SaSint, 4),
17521 0
17522 );
17523 assert_eq!(plcp_threaded, plcp_single);
17524
17525 let mut lcp_single = vec![0; n];
17526 let mut lcp_threaded = vec![0; n];
17527 assert_eq!(
17528 compute_lcp_omp(&plcp_single, &sa, &mut lcp_single, n as SaSint, 1),
17529 0
17530 );
17531 assert_eq!(
17532 compute_lcp_omp(&plcp_threaded, &sa, &mut lcp_threaded, n as SaSint, 4),
17533 0
17534 );
17535 assert_eq!(lcp_threaded, lcp_single);
17536 }
17537
17538 #[test]
17539 fn libsais16_context_allocates_upstream_shaped_buffers() {
17540 let ctx = create_ctx().unwrap();
17541 assert_eq!(ctx.threads, 1);
17542 assert_eq!(ctx.buckets.len(), 8 * ALPHABET_SIZE);
17543 assert!(ctx.thread_state.is_none());
17544
17545 let ctx = create_ctx_omp(2).unwrap();
17546 assert_eq!(ctx.threads, 2);
17547 assert_eq!(ctx.buckets.len(), 8 * ALPHABET_SIZE);
17548 let thread_state = ctx.thread_state.as_ref().unwrap();
17549 assert_eq!(thread_state.len(), 2);
17550 assert_eq!(thread_state[0].buckets.len(), 4 * ALPHABET_SIZE);
17551 assert_eq!(thread_state[0].cache_entries, PER_THREAD_CACHE_SIZE);
17552
17553 let ctx = create_ctx_omp(0).unwrap();
17554 assert_eq!(ctx.threads, 1);
17555 assert!(ctx.thread_state.is_none());
17556 }
17557
17558 #[test]
17559 fn libsais16_unbwt_context_allocates_upstream_shaped_buffers() {
17560 let ctx = unbwt_create_ctx().unwrap();
17561 assert_eq!(ctx.threads, 1);
17562 assert_eq!(ctx.bucket2.len(), ALPHABET_SIZE);
17563 assert_eq!(ctx.fastbits.len(), 1 + (1 << UNBWT_FASTBITS));
17564 assert!(ctx.buckets.is_none());
17565
17566 let ctx = unbwt_create_ctx_omp(3).unwrap();
17567 assert_eq!(ctx.threads, 3);
17568 assert_eq!(ctx.bucket2.len(), ALPHABET_SIZE);
17569 assert_eq!(ctx.fastbits.len(), 1 + (1 << UNBWT_FASTBITS));
17570 assert_eq!(ctx.buckets.as_ref().unwrap().len(), 3 * ALPHABET_SIZE);
17571 }
17572
17573 #[test]
17574 fn libsais16_named_unbwt_helpers_follow_decode_shapes() {
17575 let t = [0, 1, 2];
17576 let mut p = vec![usize::MAX; 4];
17577 let mut bucket2 = vec![0; ALPHABET_SIZE];
17578 bucket2[0] = 1;
17579 bucket2[1] = 2;
17580 bucket2[2] = 3;
17581 unbwt_calculate_P(&t, &mut p, &mut bucket2, 2, 1, 3);
17582 assert_eq!(p[2], 1);
17583 assert_eq!(p[3], 3);
17584
17585 let p = [1usize, 2, 0];
17586 let mut bucket2 = vec![3; ALPHABET_SIZE];
17587 bucket2[0] = 1;
17588 bucket2[1] = 2;
17589 bucket2[2] = 3;
17590 let fastbits = vec![0; 3];
17591
17592 let mut u = vec![99; 3];
17593 let mut i0 = 0;
17594 unbwt_decode_1(&mut u, &p, &bucket2, &fastbits, 0, &mut i0, 3);
17595 assert_eq!(u, vec![0, 1, 2]);
17596 assert_eq!(i0, 0);
17597
17598 let mut u = vec![99; 6];
17599 let (mut i0, mut i1) = (0, 1);
17600 unbwt_decode_2(&mut u, &p, &bucket2, &fastbits, 0, 3, &mut i0, &mut i1, 2);
17601 assert_eq!(&u[..2], &[0, 1]);
17602 assert_eq!(&u[3..5], &[1, 2]);
17603 assert_eq!((i0, i1), (2, 0));
17604
17605 let mut u = vec![99; 8];
17606 let mut cursors = [0; 8];
17607 unbwt_decode_8(&mut u, &p, &bucket2, &fastbits, 0, 1, &mut cursors, 1);
17608 assert_eq!(u, vec![0; 8]);
17609 assert_eq!(cursors, [1; 8]);
17610 }
17611
17612 #[test]
17613 fn libsais16_unbwt_init_parallel_uses_block_partition() {
17614 let n = 70_003usize;
17615 let t: Vec<u16> = (0..n)
17616 .map(|i| ((i.wrapping_mul(37).wrapping_add(i >> 3)) % 251) as u16)
17617 .collect();
17618 let i = [12_345];
17619
17620 let mut single_p = vec![0; n + 1];
17621 let mut threaded_p = vec![0; n + 1];
17622 let mut single_bucket2 = vec![0; ALPHABET_SIZE];
17623 let mut threaded_bucket2 = vec![0; ALPHABET_SIZE];
17624 let mut single_fastbits = vec![0; 1 + (1 << UNBWT_FASTBITS)];
17625 let mut threaded_fastbits = vec![0; 1 + (1 << UNBWT_FASTBITS)];
17626 let mut buckets = vec![0; 4 * ALPHABET_SIZE];
17627
17628 unbwt_init_single(
17629 &t,
17630 &mut single_p,
17631 None,
17632 &i,
17633 &mut single_bucket2,
17634 &mut single_fastbits,
17635 );
17636 unbwt_init_parallel(
17637 &t,
17638 &mut threaded_p,
17639 None,
17640 &i,
17641 &mut threaded_bucket2,
17642 &mut threaded_fastbits,
17643 &mut buckets,
17644 4,
17645 );
17646
17647 assert_eq!(threaded_p, single_p);
17648 assert_eq!(threaded_bucket2, single_bucket2);
17649 assert_eq!(threaded_fastbits, single_fastbits);
17650 }
17651
17652 fn assert_libsais16_matches_c(text: &[u16]) {
17653 let mut rust_sa = vec![0; text.len()];
17654 let mut c_sa = vec![0; text.len()];
17655
17656 let rust_rc = libsais16(text, &mut rust_sa, 0, None);
17657 let c_rc = unsafe {
17658 probe_public_libsais16(text.as_ptr(), c_sa.as_mut_ptr(), text.len() as SaSint, 0)
17659 };
17660
17661 assert_eq!(rust_rc, c_rc);
17662 assert_eq!(rust_sa, c_sa);
17663 }
17664
17665 fn assert_libsais16_gsa_matches_c(text: &[u16]) {
17666 let mut rust_sa = vec![0; text.len()];
17667 let mut c_sa = vec![0; text.len()];
17668
17669 let rust_rc = libsais16_gsa(text, &mut rust_sa, 0, None);
17670 let c_rc = unsafe {
17671 probe_public_libsais16_gsa(text.as_ptr(), c_sa.as_mut_ptr(), text.len() as SaSint, 0)
17672 };
17673
17674 assert_eq!(rust_rc, c_rc);
17675 assert_eq!(rust_sa, c_sa);
17676 }
17677
17678 fn assert_libsais16_int_matches_c(text: &[SaSint], k: SaSint) {
17679 let mut rust_t = text.to_vec();
17680 let mut c_t = text.to_vec();
17681 let mut rust_sa = vec![0; text.len()];
17682 let mut c_sa = vec![0; text.len()];
17683
17684 let rust_rc = libsais16_int(&mut rust_t, &mut rust_sa, k, 0);
17685 let c_rc = unsafe {
17686 probe_public_libsais16_int(
17687 c_t.as_mut_ptr(),
17688 c_sa.as_mut_ptr(),
17689 c_t.len() as SaSint,
17690 k,
17691 0,
17692 )
17693 };
17694
17695 assert_eq!(rust_rc, c_rc);
17696 assert_eq!(rust_t, c_t);
17697 assert_eq!(rust_sa, c_sa);
17698 }
17699
17700 fn assert_libsais16_bwt_matches_c(text: &[u16]) {
17701 let mut rust_u = vec![0; text.len()];
17702 let mut rust_a = vec![0; text.len()];
17703 let mut c_u = vec![0; text.len()];
17704 let mut c_a = vec![0; text.len()];
17705
17706 let rust_rc = libsais16_bwt(text, &mut rust_u, &mut rust_a, 0, None);
17707 let c_rc = unsafe {
17708 probe_public_libsais16_bwt(
17709 text.as_ptr(),
17710 c_u.as_mut_ptr(),
17711 c_a.as_mut_ptr(),
17712 text.len() as SaSint,
17713 0,
17714 )
17715 };
17716
17717 assert_eq!(rust_rc, c_rc);
17718 assert_eq!(rust_u, c_u);
17719 }
17720
17721 fn assert_libsais16_bwt_aux_matches_c(text: &[u16], r: SaSint) {
17722 let aux_len = if text.is_empty() {
17723 0
17724 } else {
17725 (text.len() - 1) / r as usize + 1
17726 };
17727 let mut rust_u = vec![0; text.len()];
17728 let mut rust_a = vec![0; text.len()];
17729 let mut rust_i = vec![0; aux_len];
17730 let mut c_u = vec![0; text.len()];
17731 let mut c_a = vec![0; text.len()];
17732 let mut c_i = vec![0; aux_len];
17733
17734 let rust_rc = libsais16_bwt_aux(text, &mut rust_u, &mut rust_a, 0, None, r, &mut rust_i);
17735 let c_rc = unsafe {
17736 probe_public_libsais16_bwt_aux(
17737 text.as_ptr(),
17738 c_u.as_mut_ptr(),
17739 c_a.as_mut_ptr(),
17740 text.len() as SaSint,
17741 0,
17742 r,
17743 c_i.as_mut_ptr(),
17744 )
17745 };
17746
17747 assert_eq!(rust_rc, c_rc);
17748 assert_eq!(rust_u, c_u);
17749 assert_eq!(rust_i, c_i);
17750 }
17751
17752 fn assert_libsais16_freq_outputs_match_c(text: &[u16], gsa_text: &[u16]) {
17753 let mut rust_sa = vec![0; text.len()];
17754 let mut c_sa = vec![0; text.len()];
17755 let mut rust_freq = vec![-1; ALPHABET_SIZE];
17756 let mut c_freq = vec![-1; ALPHABET_SIZE];
17757
17758 let rust_rc = libsais16(text, &mut rust_sa, 0, Some(&mut rust_freq));
17759 let c_rc = unsafe {
17760 probe_public_libsais16_freq(
17761 text.as_ptr(),
17762 c_sa.as_mut_ptr(),
17763 text.len() as SaSint,
17764 0,
17765 c_freq.as_mut_ptr(),
17766 )
17767 };
17768 assert_eq!(rust_rc, c_rc);
17769 assert_eq!(rust_sa, c_sa);
17770 assert_eq!(rust_freq, c_freq);
17771
17772 let mut rust_gsa = vec![0; gsa_text.len()];
17773 let mut c_gsa = vec![0; gsa_text.len()];
17774 rust_freq.fill(-1);
17775 c_freq.fill(-1);
17776 let rust_rc = libsais16_gsa(gsa_text, &mut rust_gsa, 0, Some(&mut rust_freq));
17777 let c_rc = unsafe {
17778 probe_public_libsais16_gsa_freq(
17779 gsa_text.as_ptr(),
17780 c_gsa.as_mut_ptr(),
17781 gsa_text.len() as SaSint,
17782 0,
17783 c_freq.as_mut_ptr(),
17784 )
17785 };
17786 assert_eq!(rust_rc, c_rc);
17787 assert_eq!(rust_gsa, c_gsa);
17788 assert_eq!(rust_freq, c_freq);
17789
17790 let mut rust_u = vec![0; text.len()];
17791 let mut rust_a = vec![0; text.len()];
17792 let mut c_u = vec![0; text.len()];
17793 let mut c_a = vec![0; text.len()];
17794 rust_freq.fill(-1);
17795 c_freq.fill(-1);
17796 let rust_rc = libsais16_bwt(text, &mut rust_u, &mut rust_a, 0, Some(&mut rust_freq));
17797 let c_rc = unsafe {
17798 probe_public_libsais16_bwt_freq(
17799 text.as_ptr(),
17800 c_u.as_mut_ptr(),
17801 c_a.as_mut_ptr(),
17802 text.len() as SaSint,
17803 0,
17804 c_freq.as_mut_ptr(),
17805 )
17806 };
17807 assert_eq!(rust_rc, c_rc);
17808 assert_eq!(rust_u, c_u);
17809 assert_eq!(rust_freq, c_freq);
17810
17811 let r = 4;
17812 let aux_len = (text.len() - 1) / r as usize + 1;
17813 let mut rust_i = vec![0; aux_len];
17814 let mut c_i = vec![0; aux_len];
17815 rust_freq.fill(-1);
17816 c_freq.fill(-1);
17817 let rust_rc = libsais16_bwt_aux(
17818 text,
17819 &mut rust_u,
17820 &mut rust_a,
17821 0,
17822 Some(&mut rust_freq),
17823 r,
17824 &mut rust_i,
17825 );
17826 let c_rc = unsafe {
17827 probe_public_libsais16_bwt_aux_freq(
17828 text.as_ptr(),
17829 c_u.as_mut_ptr(),
17830 c_a.as_mut_ptr(),
17831 text.len() as SaSint,
17832 0,
17833 c_freq.as_mut_ptr(),
17834 r,
17835 c_i.as_mut_ptr(),
17836 )
17837 };
17838 assert_eq!(rust_rc, c_rc);
17839 assert_eq!(rust_u, c_u);
17840 assert_eq!(rust_i, c_i);
17841 assert_eq!(rust_freq, c_freq);
17842 }
17843
17844 fn assert_libsais16_unbwt_matches_c(text: &[u16]) {
17845 let mut bwt = vec![0; text.len()];
17846 let mut work = vec![0; text.len()];
17847 let primary = libsais16_bwt(text, &mut bwt, &mut work, 0, None);
17848 assert!(primary >= 0);
17849
17850 let mut rust_u = vec![0; text.len()];
17851 let mut rust_a = vec![0; text.len() + 1];
17852 let mut c_u = vec![0; text.len()];
17853 let mut c_a = vec![0; text.len() + 1];
17854
17855 let rust_rc = libsais16_unbwt(&bwt, &mut rust_u, &mut rust_a, None, primary);
17856 let c_rc = unsafe {
17857 probe_public_libsais16_unbwt(
17858 bwt.as_ptr(),
17859 c_u.as_mut_ptr(),
17860 c_a.as_mut_ptr(),
17861 bwt.len() as SaSint,
17862 primary,
17863 )
17864 };
17865
17866 assert_eq!(rust_rc, c_rc);
17867 assert_eq!(rust_u, c_u);
17868 assert_eq!(rust_u, text);
17869 }
17870
17871 fn assert_libsais16_unbwt_aux_matches_c(text: &[u16], r: SaSint) {
17872 let mut bwt = vec![0; text.len()];
17873 let mut work = vec![0; text.len()];
17874 let mut aux = vec![0; (text.len() - 1) / r as usize + 1];
17875 let bwt_rc = libsais16_bwt_aux(text, &mut bwt, &mut work, 0, None, r, &mut aux);
17876 assert_eq!(bwt_rc, 0);
17877
17878 let mut rust_u = vec![0; text.len()];
17879 let mut rust_a = vec![0; text.len() + 1];
17880 let mut c_u = vec![0; text.len()];
17881 let mut c_a = vec![0; text.len() + 1];
17882
17883 let rust_rc = libsais16_unbwt_aux(&bwt, &mut rust_u, &mut rust_a, None, r, &aux);
17884 let c_rc = unsafe {
17885 probe_public_libsais16_unbwt_aux(
17886 bwt.as_ptr(),
17887 c_u.as_mut_ptr(),
17888 c_a.as_mut_ptr(),
17889 bwt.len() as SaSint,
17890 r,
17891 aux.as_ptr(),
17892 )
17893 };
17894
17895 assert_eq!(rust_rc, c_rc);
17896 assert_eq!(rust_u, c_u);
17897 assert_eq!(rust_u, text);
17898 }
17899
17900 fn assert_libsais16_unbwt_freq_matches_c(text: &[u16]) {
17901 let mut freq = vec![0; ALPHABET_SIZE];
17902 let mut bwt = vec![0; text.len()];
17903 let mut work = vec![0; text.len()];
17904 let primary = libsais16_bwt(text, &mut bwt, &mut work, 0, Some(&mut freq));
17905 assert!(primary >= 0);
17906
17907 let mut rust_u = vec![0; text.len()];
17908 let mut rust_a = vec![0; text.len() + 1];
17909 let mut c_u = vec![0; text.len()];
17910 let mut c_a = vec![0; text.len() + 1];
17911
17912 let rust_rc = libsais16_unbwt(&bwt, &mut rust_u, &mut rust_a, Some(&freq), primary);
17913 let c_rc = unsafe {
17914 probe_public_libsais16_unbwt_freq(
17915 bwt.as_ptr(),
17916 c_u.as_mut_ptr(),
17917 c_a.as_mut_ptr(),
17918 bwt.len() as SaSint,
17919 freq.as_ptr(),
17920 primary,
17921 )
17922 };
17923 assert_eq!(rust_rc, c_rc);
17924 assert_eq!(rust_u, c_u);
17925 assert_eq!(rust_u, text);
17926
17927 let r = 4;
17928 let mut aux = vec![0; (text.len() - 1) / r as usize + 1];
17929 let bwt_rc = libsais16_bwt_aux(text, &mut bwt, &mut work, 0, Some(&mut freq), r, &mut aux);
17930 assert_eq!(bwt_rc, 0);
17931
17932 rust_u.fill(0);
17933 rust_a.fill(0);
17934 c_u.fill(0);
17935 c_a.fill(0);
17936 let rust_rc = libsais16_unbwt_aux(&bwt, &mut rust_u, &mut rust_a, Some(&freq), r, &aux);
17937 let c_rc = unsafe {
17938 probe_public_libsais16_unbwt_aux_freq(
17939 bwt.as_ptr(),
17940 c_u.as_mut_ptr(),
17941 c_a.as_mut_ptr(),
17942 bwt.len() as SaSint,
17943 freq.as_ptr(),
17944 r,
17945 aux.as_ptr(),
17946 )
17947 };
17948 assert_eq!(rust_rc, c_rc);
17949 assert_eq!(rust_u, c_u);
17950 assert_eq!(rust_u, text);
17951 }
17952
17953 fn assert_libsais16_plcp_lcp_matches_c(text: &[u16]) {
17954 let mut sa = vec![0; text.len()];
17955 assert_eq!(libsais16(text, &mut sa, 0, None), 0);
17956
17957 let mut rust_plcp = vec![0; text.len()];
17958 let mut c_plcp = vec![0; text.len()];
17959 let rust_rc = libsais16_plcp(text, &sa, &mut rust_plcp);
17960 let c_rc = unsafe {
17961 probe_public_libsais16_plcp(
17962 text.as_ptr(),
17963 sa.as_ptr(),
17964 c_plcp.as_mut_ptr(),
17965 text.len() as SaSint,
17966 )
17967 };
17968 assert_eq!(rust_rc, c_rc);
17969 assert_eq!(rust_plcp, c_plcp);
17970
17971 let mut rust_lcp = vec![0; text.len()];
17972 let mut c_lcp = vec![0; text.len()];
17973 let rust_rc = libsais16_lcp(&rust_plcp, &sa, &mut rust_lcp);
17974 let c_rc = unsafe {
17975 probe_public_libsais16_lcp(
17976 c_plcp.as_ptr(),
17977 sa.as_ptr(),
17978 c_lcp.as_mut_ptr(),
17979 text.len() as SaSint,
17980 )
17981 };
17982 assert_eq!(rust_rc, c_rc);
17983 assert_eq!(rust_lcp, c_lcp);
17984 }
17985
17986 fn assert_libsais16_plcp_gsa_matches_c(text: &[u16]) {
17987 let mut sa = vec![0; text.len()];
17988 assert_eq!(libsais16_gsa(text, &mut sa, 0, None), 0);
17989
17990 let mut rust_plcp = vec![0; text.len()];
17991 let mut c_plcp = vec![0; text.len()];
17992 let rust_rc = libsais16_plcp_gsa(text, &sa, &mut rust_plcp);
17993 let c_rc = unsafe {
17994 probe_public_libsais16_plcp_gsa(
17995 text.as_ptr(),
17996 sa.as_ptr(),
17997 c_plcp.as_mut_ptr(),
17998 text.len() as SaSint,
17999 )
18000 };
18001 assert_eq!(rust_rc, c_rc);
18002 assert_eq!(rust_plcp, c_plcp);
18003 }
18004
18005 #[test]
18006 fn public_libsais16_matches_upstream_c() {
18007 for text in [
18008 [].as_slice(),
18009 &[1][..],
18010 &[2, 1, 3, 1, 2, 0],
18011 &[2, 1, 3, 1, 2, 4, 1, 0],
18012 &[65_535, 1, 65_534, 1, 0],
18013 &[7, 7, 7, 7, 7, 0],
18014 ] {
18015 assert_libsais16_matches_c(text);
18016 }
18017 }
18018
18019 #[test]
18020 fn public_libsais16_bwt_matches_upstream_c() {
18021 for text in [
18022 [].as_slice(),
18023 &[1][..],
18024 &[2, 1, 3, 1, 2, 0],
18025 &[2, 1, 3, 1, 2, 4, 1, 0],
18026 &[65_535, 1, 65_534, 1, 0],
18027 &[7, 7, 7, 7, 7, 0],
18028 ] {
18029 assert_libsais16_bwt_matches_c(text);
18030 }
18031 }
18032
18033 #[test]
18034 fn public_libsais16_gsa_matches_upstream_c() {
18035 for text in [&[0][..], &[2, 1, 0], &[2, 1, 0, 3, 1, 0], &[7, 7, 0, 7, 0]] {
18036 assert_libsais16_gsa_matches_c(text);
18037 }
18038 }
18039
18040 #[test]
18041 fn public_libsais16_int_matches_upstream_c() {
18042 for (text, k) in [
18043 (&[][..], 0),
18044 (&[0][..], 1),
18045 (&[1, 2, 1, 0][..], 3),
18046 (&[2, 1, 2, 1, 0][..], 3),
18047 (&[3, 3, 3, 2, 1, 0][..], 4),
18048 ] {
18049 assert_libsais16_int_matches_c(text, k);
18050 }
18051 }
18052
18053 #[test]
18054 fn public_libsais16_plcp_lcp_matches_upstream_c() {
18055 for text in [
18056 &[2, 1, 3, 1, 2, 0][..],
18057 &[2, 1, 3, 1, 2, 4, 1, 0],
18058 &[65_535, 1, 65_534, 1, 0],
18059 &[7, 7, 7, 7, 7, 0],
18060 ] {
18061 assert_libsais16_plcp_lcp_matches_c(text);
18062 }
18063 }
18064
18065 #[test]
18066 fn public_libsais16_plcp_gsa_matches_upstream_c() {
18067 for text in [&[0][..], &[2, 1, 0], &[2, 1, 0, 3, 1, 0], &[7, 7, 0, 7, 0]] {
18068 assert_libsais16_plcp_gsa_matches_c(text);
18069 }
18070 }
18071
18072 #[test]
18073 fn public_libsais16_bwt_aux_matches_upstream_c() {
18074 for text in [
18075 &[2, 1, 3, 1, 2, 0][..],
18076 &[2, 1, 3, 1, 2, 4, 1, 0],
18077 &[65_535, 1, 65_534, 1, 0],
18078 &[7, 7, 7, 7, 7, 0],
18079 ] {
18080 assert_libsais16_bwt_aux_matches_c(text, 4);
18081 }
18082 }
18083
18084 #[test]
18085 fn public_libsais16_frequency_outputs_match_upstream_c() {
18086 assert_libsais16_freq_outputs_match_c(&[65_535, 1, 2, 1, 0], &[65_535, 1, 0, 2, 1, 0]);
18087 }
18088
18089 #[test]
18090 fn public_libsais16_unbwt_with_frequency_matches_upstream_c() {
18091 assert_libsais16_unbwt_freq_matches_c(&[65_535, 1, 2, 1, 0]);
18092 }
18093
18094 #[test]
18095 fn public_libsais16_unbwt_matches_upstream_c() {
18096 for text in [
18097 &[1][..],
18098 &[2, 1, 3, 1, 2, 0],
18099 &[2, 1, 3, 1, 2, 4, 1, 0],
18100 &[65_535, 1, 65_534, 1, 0],
18101 &[7, 7, 7, 7, 7, 0],
18102 ] {
18103 assert_libsais16_unbwt_matches_c(text);
18104 }
18105 }
18106
18107 #[test]
18108 fn public_libsais16_unbwt_aux_matches_upstream_c() {
18109 for text in [
18110 &[2, 1, 3, 1, 2, 0][..],
18111 &[2, 1, 3, 1, 2, 4, 1, 0],
18112 &[65_535, 1, 65_534, 1, 0],
18113 &[7, 7, 7, 7, 7, 0],
18114 ] {
18115 assert_libsais16_unbwt_aux_matches_c(text, 4);
18116 }
18117 }
18118
18119 #[test]
18120 fn public_libsais16_unbwt_aux_exercises_decode_dispatch_cases() {
18121 for len in [2usize, 5, 9, 13, 17, 21, 25, 29, 33, 37] {
18122 let text = (0..len)
18123 .map(|i| ((i * 37 + 11) % 65_535 + 1) as u16)
18124 .collect::<Vec<_>>();
18125 assert_libsais16_unbwt_aux_matches_c(&text, 4);
18126 }
18127 }
18128
18129 #[test]
18130 fn libsais16_lcp_helpers_reject_invalid_suffix_entries() {
18131 let text = [2, 1, 2, 1, 0];
18132 let mut plcp = vec![0; text.len()];
18133 let mut lcp = vec![0; text.len()];
18134
18135 assert_eq!(libsais16_plcp(&text, &[0, 1, -1, 3, 4], &mut plcp), -1);
18136 assert_eq!(libsais16_plcp(&text, &[0, 1, 2, 3, 5], &mut plcp), -1);
18137 assert_eq!(libsais16_lcp(&plcp, &[0, 1, -1, 3, 4], &mut lcp), -1);
18138 assert_eq!(libsais16_lcp(&plcp, &[0, 1, 2, 3, 5], &mut lcp), -1);
18139 }
18140
18141 #[test]
18142 fn libsais16_rejects_invalid_public_arguments() {
18143 let text = [2, 1, 3, 1, 2, 0];
18144 let int_text = [1, 2, 1, 0];
18145 let mut int_text_for_short_sa = int_text.to_vec();
18146 let mut int_text_for_negative_fs = int_text.to_vec();
18147 let mut sa = vec![0; text.len() - 1];
18148 let mut int_sa = vec![0; int_text.len() - 1];
18149 let mut full_int_sa = vec![0; int_text.len()];
18150 let mut freq = vec![0; ALPHABET_SIZE - 1];
18151 let mut u = vec![0; text.len() - 1];
18152 let mut a = vec![0; text.len() - 1];
18153 let mut full_u = vec![0; text.len()];
18154 let mut full_a = vec![0; text.len()];
18155 let mut aux = vec![0; 1];
18156
18157 assert_eq!(libsais16(&text, &mut sa, 0, None), -1);
18158 assert_eq!(libsais16(&text, &mut full_a, 0, Some(&mut freq)), -1);
18159 assert_eq!(libsais16_gsa(&[1, 2, 3], &mut full_a[..3], 0, None), -1);
18160 assert_eq!(
18161 libsais16_int(&mut int_text_for_short_sa, &mut int_sa, 3, 0),
18162 -1
18163 );
18164 assert_eq!(
18165 libsais16_int(&mut int_text_for_negative_fs, &mut full_int_sa, 3, -1),
18166 -1
18167 );
18168 assert_eq!(libsais16_bwt(&text, &mut u, &mut full_a, 0, None), -1);
18169 assert_eq!(libsais16_bwt(&text, &mut full_u, &mut a, 0, None), -1);
18170 assert_eq!(
18171 libsais16_bwt_aux(&text, &mut full_u, &mut full_a, 0, None, 0, &mut aux),
18172 -1
18173 );
18174 assert_eq!(
18175 libsais16_bwt_aux(&text, &mut full_u, &mut full_a, 0, None, 3, &mut aux),
18176 -1
18177 );
18178 assert_eq!(
18179 libsais16_bwt_aux(&text, &mut full_u, &mut full_a, 0, None, 4, &mut aux),
18180 -1
18181 );
18182 assert_eq!(create_ctx_omp(-1), None);
18183 assert_eq!(unbwt_create_ctx_omp(-1), None);
18184 }
18185
18186 #[test]
18187 fn libsais16_unbwt_rejects_invalid_public_arguments() {
18188 let text = [2, 1, 3, 1, 2, 0];
18189 let mut bwt = vec![0; text.len()];
18190 let mut work = vec![0; text.len()];
18191 let primary = libsais16_bwt(&text, &mut bwt, &mut work, 0, None);
18192
18193 let mut short_u = vec![0; text.len() - 1];
18194 let mut short_a = vec![0; text.len() - 1];
18195 let mut full_u = vec![0; text.len()];
18196 let mut full_a = vec![0; text.len()];
18197 let short_freq = vec![0; ALPHABET_SIZE - 1];
18198 let short_aux = vec![primary];
18199 let bad_aux = vec![0, 0];
18200 let good_aux = vec![primary, 4];
18201
18202 assert_eq!(
18203 libsais16_unbwt(&bwt, &mut short_u, &mut full_a, None, primary),
18204 -1
18205 );
18206 assert_eq!(
18207 libsais16_unbwt(&bwt, &mut full_u, &mut short_a, None, primary),
18208 -1
18209 );
18210 assert_eq!(
18211 libsais16_unbwt(&bwt, &mut full_u, &mut full_a, Some(&short_freq), primary),
18212 -1
18213 );
18214 assert_eq!(libsais16_unbwt(&bwt, &mut full_u, &mut full_a, None, 0), -1);
18215 assert_eq!(
18216 libsais16_unbwt(
18217 &bwt,
18218 &mut full_u,
18219 &mut full_a,
18220 None,
18221 text.len() as SaSint + 1
18222 ),
18223 -1
18224 );
18225 assert_eq!(
18226 libsais16_unbwt_aux(&bwt, &mut full_u, &mut full_a, None, 0, &good_aux),
18227 -1
18228 );
18229 assert_eq!(
18230 libsais16_unbwt_aux(&bwt, &mut full_u, &mut full_a, None, 3, &good_aux),
18231 -1
18232 );
18233 assert_eq!(
18234 libsais16_unbwt_aux(&bwt, &mut full_u, &mut full_a, None, 4, &short_aux),
18235 -1
18236 );
18237 assert_eq!(
18238 libsais16_unbwt_aux(&bwt, &mut full_u, &mut full_a, None, 4, &bad_aux),
18239 -1
18240 );
18241 }
18242
18243 #[test]
18244 fn libsais16_ctx_rejects_invalid_public_arguments() {
18245 let text = [2, 1, 3, 1, 2, 0];
18246 let mut ctx = create_ctx().unwrap();
18247 let mut sa = vec![0; text.len() - 1];
18248 let mut freq = vec![0; ALPHABET_SIZE - 1];
18249 let mut u = vec![0; text.len() - 1];
18250 let mut a = vec![0; text.len() - 1];
18251 let mut full_u = vec![0; text.len()];
18252 let mut full_a = vec![0; text.len()];
18253 let mut aux = vec![0; 1];
18254
18255 assert_eq!(libsais16_ctx(&mut ctx, &text, &mut sa, 0, None), -1);
18256 assert_eq!(
18257 libsais16_ctx(&mut ctx, &text, &mut full_a, 0, Some(&mut freq)),
18258 -1
18259 );
18260 assert_eq!(
18261 libsais16_gsa_ctx(&mut ctx, &[1, 2, 3], &mut full_a[..3], 0, None),
18262 -1
18263 );
18264 assert_eq!(
18265 libsais16_bwt_ctx(&mut ctx, &text, &mut u, &mut full_a, 0, None),
18266 -1
18267 );
18268 assert_eq!(
18269 libsais16_bwt_ctx(&mut ctx, &text, &mut full_u, &mut a, 0, None),
18270 -1
18271 );
18272 assert_eq!(
18273 libsais16_bwt_aux_ctx(
18274 &mut ctx,
18275 &text,
18276 &mut full_u,
18277 &mut full_a,
18278 0,
18279 None,
18280 0,
18281 &mut aux
18282 ),
18283 -1
18284 );
18285 assert_eq!(
18286 libsais16_bwt_aux_ctx(
18287 &mut ctx,
18288 &text,
18289 &mut full_u,
18290 &mut full_a,
18291 0,
18292 None,
18293 3,
18294 &mut aux
18295 ),
18296 -1
18297 );
18298 assert_eq!(
18299 libsais16_bwt_aux_ctx(
18300 &mut ctx,
18301 &text,
18302 &mut full_u,
18303 &mut full_a,
18304 0,
18305 None,
18306 4,
18307 &mut aux
18308 ),
18309 -1
18310 );
18311
18312 let mut default_ctx = Context::default();
18313 assert_eq!(
18314 libsais16_ctx(&mut default_ctx, &text, &mut full_a, 0, None),
18315 -2
18316 );
18317
18318 let mut bad_bucket_ctx = create_ctx().unwrap();
18319 bad_bucket_ctx.buckets.clear();
18320 assert_eq!(
18321 libsais16_ctx(&mut bad_bucket_ctx, &text, &mut full_a, 0, None),
18322 -2
18323 );
18324
18325 let mut short_thread_state_ctx = create_ctx_omp(2).unwrap();
18326 short_thread_state_ctx
18327 .thread_state
18328 .as_mut()
18329 .unwrap()
18330 .truncate(1);
18331 assert_eq!(
18332 libsais16_ctx(&mut short_thread_state_ctx, &text, &mut full_a, 0, None),
18333 -2
18334 );
18335 }
18336
18337 #[test]
18338 fn libsais16_unbwt_ctx_rejects_invalid_public_arguments() {
18339 let text = [2, 1, 3, 1, 2, 0];
18340 let mut bwt = vec![0; text.len()];
18341 let mut work = vec![0; text.len()];
18342 let primary = libsais16_bwt(&text, &mut bwt, &mut work, 0, None);
18343 let mut ctx = unbwt_create_ctx().unwrap();
18344
18345 let mut short_u = vec![0; text.len() - 1];
18346 let mut short_a = vec![0; text.len() - 1];
18347 let mut full_u = vec![0; text.len()];
18348 let mut full_a = vec![0; text.len()];
18349 let short_freq = vec![0; ALPHABET_SIZE - 1];
18350 let short_aux = vec![primary];
18351 let bad_aux = vec![0, 0];
18352 let good_aux = vec![primary, 4];
18353
18354 assert_eq!(
18355 libsais16_unbwt_ctx(&mut ctx, &bwt, &mut short_u, &mut full_a, None, primary),
18356 -1
18357 );
18358 assert_eq!(
18359 libsais16_unbwt_ctx(&mut ctx, &bwt, &mut full_u, &mut short_a, None, primary),
18360 -1
18361 );
18362 assert_eq!(
18363 libsais16_unbwt_ctx(
18364 &mut ctx,
18365 &bwt,
18366 &mut full_u,
18367 &mut full_a,
18368 Some(&short_freq),
18369 primary
18370 ),
18371 -1
18372 );
18373 assert_eq!(
18374 libsais16_unbwt_ctx(&mut ctx, &bwt, &mut full_u, &mut full_a, None, 0),
18375 -1
18376 );
18377 assert_eq!(
18378 libsais16_unbwt_aux_ctx(&mut ctx, &bwt, &mut full_u, &mut full_a, None, 0, &good_aux),
18379 -1
18380 );
18381 assert_eq!(
18382 libsais16_unbwt_aux_ctx(&mut ctx, &bwt, &mut full_u, &mut full_a, None, 3, &good_aux),
18383 -1
18384 );
18385 assert_eq!(
18386 libsais16_unbwt_aux_ctx(
18387 &mut ctx,
18388 &bwt,
18389 &mut full_u,
18390 &mut full_a,
18391 None,
18392 4,
18393 &short_aux
18394 ),
18395 -1
18396 );
18397 assert_eq!(
18398 libsais16_unbwt_aux_ctx(&mut ctx, &bwt, &mut full_u, &mut full_a, None, 4, &bad_aux),
18399 -1
18400 );
18401 }
18402
18403 #[test]
18404 fn libsais16_context_wrappers_match_direct_calls() {
18405 let text = [2, 1, 3, 1, 2, 0];
18406 let mut ctx = create_ctx().unwrap();
18407
18408 let mut direct_sa = vec![0; text.len()];
18409 let mut ctx_sa = vec![0; text.len()];
18410 assert_eq!(libsais16(&text, &mut direct_sa, 0, None), 0);
18411 assert_eq!(libsais16_ctx(&mut ctx, &text, &mut ctx_sa, 0, None), 0);
18412 assert_eq!(ctx_sa, direct_sa);
18413
18414 let mut direct_bwt = vec![0; text.len()];
18415 let mut direct_work = vec![0; text.len()];
18416 let mut ctx_bwt = vec![0; text.len()];
18417 let mut ctx_work = vec![0; text.len()];
18418 assert_eq!(
18419 libsais16_bwt(&text, &mut direct_bwt, &mut direct_work, 0, None),
18420 libsais16_bwt_ctx(&mut ctx, &text, &mut ctx_bwt, &mut ctx_work, 0, None)
18421 );
18422 assert_eq!(ctx_bwt, direct_bwt);
18423
18424 let mut direct_aux = vec![0; 2];
18425 let mut ctx_aux = vec![0; 2];
18426 assert_eq!(
18427 libsais16_bwt_aux(
18428 &text,
18429 &mut direct_bwt,
18430 &mut direct_work,
18431 0,
18432 None,
18433 4,
18434 &mut direct_aux
18435 ),
18436 libsais16_bwt_aux_ctx(
18437 &mut ctx,
18438 &text,
18439 &mut ctx_bwt,
18440 &mut ctx_work,
18441 0,
18442 None,
18443 4,
18444 &mut ctx_aux
18445 )
18446 );
18447 assert_eq!(ctx_bwt, direct_bwt);
18448 assert_eq!(ctx_aux, direct_aux);
18449 }
18450
18451 #[test]
18452 fn libsais16_unbwt_context_wrappers_match_direct_calls() {
18453 let text = [2, 1, 3, 1, 2, 0];
18454 let mut bwt = vec![0; text.len()];
18455 let mut work = vec![0; text.len()];
18456 let primary = libsais16_bwt(&text, &mut bwt, &mut work, 0, None);
18457
18458 let mut ctx = unbwt_create_ctx().unwrap();
18459 let mut direct = vec![0; text.len()];
18460 let mut direct_work = vec![0; text.len()];
18461 let mut via_ctx = vec![0; text.len()];
18462 let mut ctx_work = vec![0; text.len()];
18463
18464 assert_eq!(
18465 libsais16_unbwt(&bwt, &mut direct, &mut direct_work, None, primary),
18466 0
18467 );
18468 assert_eq!(
18469 libsais16_unbwt_ctx(&mut ctx, &bwt, &mut via_ctx, &mut ctx_work, None, primary),
18470 0
18471 );
18472 assert_eq!(via_ctx, direct);
18473
18474 let mut aux = vec![0; 2];
18475 assert_eq!(
18476 libsais16_bwt_aux(&text, &mut bwt, &mut work, 0, None, 4, &mut aux),
18477 0
18478 );
18479 assert_eq!(
18480 libsais16_unbwt_aux(&bwt, &mut direct, &mut direct_work, None, 4, &aux),
18481 0
18482 );
18483 assert_eq!(
18484 libsais16_unbwt_aux_ctx(&mut ctx, &bwt, &mut via_ctx, &mut ctx_work, None, 4, &aux),
18485 0
18486 );
18487 assert_eq!(via_ctx, direct);
18488 }
18489
18490 #[test]
18491 fn libsais16_ctx_frequency_wrappers_match_direct_calls() {
18492 let text = [2, 1, 3, 1, 2, 0];
18493 let gsa_text = [2, 1, 0, 3, 1, 0];
18494 let mut ctx = create_ctx().unwrap();
18495
18496 let mut direct_sa = vec![0; text.len()];
18497 let mut ctx_sa = vec![0; text.len()];
18498 let mut direct_freq = vec![-1; ALPHABET_SIZE];
18499 let mut ctx_freq = vec![-1; ALPHABET_SIZE];
18500 assert_eq!(
18501 libsais16(&text, &mut direct_sa, 0, Some(&mut direct_freq)),
18502 0
18503 );
18504 assert_eq!(
18505 libsais16_ctx(&mut ctx, &text, &mut ctx_sa, 0, Some(&mut ctx_freq)),
18506 0
18507 );
18508 assert_eq!(ctx_sa, direct_sa);
18509 assert_eq!(ctx_freq, direct_freq);
18510
18511 let mut direct_gsa = vec![0; gsa_text.len()];
18512 let mut ctx_gsa = vec![0; gsa_text.len()];
18513 direct_freq.fill(-1);
18514 ctx_freq.fill(-1);
18515 assert_eq!(
18516 libsais16_gsa(&gsa_text, &mut direct_gsa, 0, Some(&mut direct_freq)),
18517 0
18518 );
18519 assert_eq!(
18520 libsais16_gsa_ctx(&mut ctx, &gsa_text, &mut ctx_gsa, 0, Some(&mut ctx_freq)),
18521 0
18522 );
18523 assert_eq!(ctx_gsa, direct_gsa);
18524 assert_eq!(ctx_freq, direct_freq);
18525
18526 let mut direct_bwt = vec![0; text.len()];
18527 let mut direct_work = vec![0; text.len()];
18528 let mut ctx_bwt = vec![0; text.len()];
18529 let mut ctx_work = vec![0; text.len()];
18530 direct_freq.fill(-1);
18531 ctx_freq.fill(-1);
18532 assert_eq!(
18533 libsais16_bwt(
18534 &text,
18535 &mut direct_bwt,
18536 &mut direct_work,
18537 0,
18538 Some(&mut direct_freq)
18539 ),
18540 libsais16_bwt_ctx(
18541 &mut ctx,
18542 &text,
18543 &mut ctx_bwt,
18544 &mut ctx_work,
18545 0,
18546 Some(&mut ctx_freq)
18547 )
18548 );
18549 assert_eq!(ctx_bwt, direct_bwt);
18550 assert_eq!(ctx_freq, direct_freq);
18551
18552 let mut direct_aux = vec![0; 2];
18553 let mut ctx_aux = vec![0; 2];
18554 direct_freq.fill(-1);
18555 ctx_freq.fill(-1);
18556 assert_eq!(
18557 libsais16_bwt_aux(
18558 &text,
18559 &mut direct_bwt,
18560 &mut direct_work,
18561 0,
18562 Some(&mut direct_freq),
18563 4,
18564 &mut direct_aux
18565 ),
18566 libsais16_bwt_aux_ctx(
18567 &mut ctx,
18568 &text,
18569 &mut ctx_bwt,
18570 &mut ctx_work,
18571 0,
18572 Some(&mut ctx_freq),
18573 4,
18574 &mut ctx_aux
18575 )
18576 );
18577 assert_eq!(ctx_bwt, direct_bwt);
18578 assert_eq!(ctx_aux, direct_aux);
18579 assert_eq!(ctx_freq, direct_freq);
18580 }
18581
18582 #[test]
18583 fn libsais16_unbwt_ctx_frequency_wrappers_match_direct_calls() {
18584 let text = [2, 1, 3, 1, 2, 0];
18585 let mut freq = vec![0; ALPHABET_SIZE];
18586 let mut bwt = vec![0; text.len()];
18587 let mut work = vec![0; text.len()];
18588 let primary = libsais16_bwt(&text, &mut bwt, &mut work, 0, Some(&mut freq));
18589 assert!(primary >= 0);
18590
18591 let mut ctx = unbwt_create_ctx().unwrap();
18592 let mut direct = vec![0; text.len()];
18593 let mut direct_work = vec![0; text.len() + 1];
18594 let mut via_ctx = vec![0; text.len()];
18595 let mut ctx_work = vec![0; text.len() + 1];
18596 assert_eq!(
18597 libsais16_unbwt(&bwt, &mut direct, &mut direct_work, Some(&freq), primary),
18598 libsais16_unbwt_ctx(
18599 &mut ctx,
18600 &bwt,
18601 &mut via_ctx,
18602 &mut ctx_work,
18603 Some(&freq),
18604 primary
18605 )
18606 );
18607 assert_eq!(via_ctx, direct);
18608 assert_eq!(via_ctx, text);
18609
18610 let mut aux = vec![0; (text.len() - 1) / 4 + 1];
18611 assert_eq!(
18612 libsais16_bwt_aux(&text, &mut bwt, &mut work, 0, Some(&mut freq), 4, &mut aux),
18613 0
18614 );
18615 direct.fill(0);
18616 direct_work.fill(0);
18617 via_ctx.fill(0);
18618 ctx_work.fill(0);
18619 assert_eq!(
18620 libsais16_unbwt_aux(&bwt, &mut direct, &mut direct_work, Some(&freq), 4, &aux),
18621 libsais16_unbwt_aux_ctx(
18622 &mut ctx,
18623 &bwt,
18624 &mut via_ctx,
18625 &mut ctx_work,
18626 Some(&freq),
18627 4,
18628 &aux
18629 )
18630 );
18631 assert_eq!(via_ctx, direct);
18632 assert_eq!(via_ctx, text);
18633 }
18634
18635 #[test]
18636 fn libsais16_omp_wrappers_match_direct_calls_and_reject_negative_threads() {
18637 let text = [2, 1, 3, 1, 2, 0];
18638 let gsa_text = [2, 1, 0, 3, 1, 0];
18639 let mut direct_sa = vec![0; text.len()];
18640 let mut omp_sa = vec![0; text.len()];
18641 assert_eq!(libsais16(&text, &mut direct_sa, 0, None), 0);
18642 assert_eq!(libsais16_omp(&text, &mut omp_sa, 0, None, 2), 0);
18643 assert_eq!(omp_sa, direct_sa);
18644 assert_eq!(libsais16_omp(&text, &mut omp_sa, 0, None, -1), -1);
18645
18646 let mut direct_gsa = vec![0; gsa_text.len()];
18647 let mut omp_gsa = vec![0; gsa_text.len()];
18648 assert_eq!(libsais16_gsa(&gsa_text, &mut direct_gsa, 0, None), 0);
18649 assert_eq!(libsais16_gsa_omp(&gsa_text, &mut omp_gsa, 0, None, 2), 0);
18650 assert_eq!(omp_gsa, direct_gsa);
18651 assert_eq!(libsais16_gsa_omp(&gsa_text, &mut omp_gsa, 0, None, -1), -1);
18652
18653 let int_text = [1, 2, 1, 0];
18654 let mut direct_int_text = int_text.to_vec();
18655 let mut omp_int_text = int_text.to_vec();
18656 let mut direct_int_sa = vec![0; int_text.len()];
18657 let mut omp_int_sa = vec![0; int_text.len()];
18658 assert_eq!(
18659 libsais16_int(&mut direct_int_text, &mut direct_int_sa, 3, 0),
18660 0
18661 );
18662 assert_eq!(
18663 libsais16_int_omp(&mut omp_int_text, &mut omp_int_sa, 3, 0, 2),
18664 0
18665 );
18666 assert_eq!(omp_int_text, direct_int_text);
18667 assert_eq!(omp_int_sa, direct_int_sa);
18668 assert_eq!(
18669 libsais16_int_omp(&mut omp_int_text, &mut omp_int_sa, 3, 0, -1),
18670 -1
18671 );
18672
18673 let mut direct_bwt = vec![0; text.len()];
18674 let mut direct_work = vec![0; text.len()];
18675 let mut omp_bwt = vec![0; text.len()];
18676 let mut omp_work = vec![0; text.len()];
18677 assert_eq!(
18678 libsais16_bwt(&text, &mut direct_bwt, &mut direct_work, 0, None),
18679 libsais16_bwt_omp(&text, &mut omp_bwt, &mut omp_work, 0, None, 2)
18680 );
18681 assert_eq!(omp_bwt, direct_bwt);
18682 assert_eq!(
18683 libsais16_bwt_omp(&text, &mut omp_bwt, &mut omp_work, 0, None, -1),
18684 -1
18685 );
18686
18687 let mut direct_aux = vec![0; 2];
18688 let mut omp_aux = vec![0; 2];
18689 assert_eq!(
18690 libsais16_bwt_aux(
18691 &text,
18692 &mut direct_bwt,
18693 &mut direct_work,
18694 0,
18695 None,
18696 4,
18697 &mut direct_aux
18698 ),
18699 libsais16_bwt_aux_omp(
18700 &text,
18701 &mut omp_bwt,
18702 &mut omp_work,
18703 0,
18704 None,
18705 4,
18706 &mut omp_aux,
18707 2
18708 )
18709 );
18710 assert_eq!(omp_bwt, direct_bwt);
18711 assert_eq!(omp_aux, direct_aux);
18712 assert_eq!(
18713 libsais16_bwt_aux_omp(
18714 &text,
18715 &mut omp_bwt,
18716 &mut omp_work,
18717 0,
18718 None,
18719 4,
18720 &mut omp_aux,
18721 -1
18722 ),
18723 -1
18724 );
18725 }
18726
18727 #[test]
18728 fn libsais16_omp_frequency_wrappers_match_direct_calls() {
18729 let text = [2, 1, 3, 1, 2, 0];
18730 let gsa_text = [2, 1, 0, 3, 1, 0];
18731 let mut direct_sa = vec![0; text.len()];
18732 let mut omp_sa = vec![0; text.len()];
18733 let mut direct_freq = vec![-1; ALPHABET_SIZE];
18734 let mut omp_freq = vec![-1; ALPHABET_SIZE];
18735 assert_eq!(
18736 libsais16(&text, &mut direct_sa, 0, Some(&mut direct_freq)),
18737 0
18738 );
18739 assert_eq!(
18740 libsais16_omp(&text, &mut omp_sa, 0, Some(&mut omp_freq), 2),
18741 0
18742 );
18743 assert_eq!(omp_sa, direct_sa);
18744 assert_eq!(omp_freq, direct_freq);
18745
18746 let mut direct_gsa = vec![0; gsa_text.len()];
18747 let mut omp_gsa = vec![0; gsa_text.len()];
18748 direct_freq.fill(-1);
18749 omp_freq.fill(-1);
18750 assert_eq!(
18751 libsais16_gsa(&gsa_text, &mut direct_gsa, 0, Some(&mut direct_freq)),
18752 0
18753 );
18754 assert_eq!(
18755 libsais16_gsa_omp(&gsa_text, &mut omp_gsa, 0, Some(&mut omp_freq), 2),
18756 0
18757 );
18758 assert_eq!(omp_gsa, direct_gsa);
18759 assert_eq!(omp_freq, direct_freq);
18760
18761 let mut direct_bwt = vec![0; text.len()];
18762 let mut direct_work = vec![0; text.len()];
18763 let mut omp_bwt = vec![0; text.len()];
18764 let mut omp_work = vec![0; text.len()];
18765 direct_freq.fill(-1);
18766 omp_freq.fill(-1);
18767 assert_eq!(
18768 libsais16_bwt(
18769 &text,
18770 &mut direct_bwt,
18771 &mut direct_work,
18772 0,
18773 Some(&mut direct_freq)
18774 ),
18775 libsais16_bwt_omp(
18776 &text,
18777 &mut omp_bwt,
18778 &mut omp_work,
18779 0,
18780 Some(&mut omp_freq),
18781 2
18782 )
18783 );
18784 assert_eq!(omp_bwt, direct_bwt);
18785 assert_eq!(omp_freq, direct_freq);
18786
18787 let mut direct_aux = vec![0; 2];
18788 let mut omp_aux = vec![0; 2];
18789 direct_freq.fill(-1);
18790 omp_freq.fill(-1);
18791 assert_eq!(
18792 libsais16_bwt_aux(
18793 &text,
18794 &mut direct_bwt,
18795 &mut direct_work,
18796 0,
18797 Some(&mut direct_freq),
18798 4,
18799 &mut direct_aux
18800 ),
18801 libsais16_bwt_aux_omp(
18802 &text,
18803 &mut omp_bwt,
18804 &mut omp_work,
18805 0,
18806 Some(&mut omp_freq),
18807 4,
18808 &mut omp_aux,
18809 2
18810 )
18811 );
18812 assert_eq!(omp_bwt, direct_bwt);
18813 assert_eq!(omp_aux, direct_aux);
18814 assert_eq!(omp_freq, direct_freq);
18815 }
18816
18817 #[test]
18818 fn libsais16_unbwt_omp_frequency_wrappers_match_direct_calls() {
18819 let text = [2, 1, 3, 1, 2, 0];
18820 let mut freq = vec![0; ALPHABET_SIZE];
18821 let mut bwt = vec![0; text.len()];
18822 let mut work = vec![0; text.len()];
18823 let primary = libsais16_bwt(&text, &mut bwt, &mut work, 0, Some(&mut freq));
18824 assert!(primary >= 0);
18825
18826 let mut direct = vec![0; text.len()];
18827 let mut direct_work = vec![0; text.len() + 1];
18828 let mut omp = vec![0; text.len()];
18829 let mut omp_work = vec![0; text.len() + 1];
18830 assert_eq!(
18831 libsais16_unbwt(&bwt, &mut direct, &mut direct_work, Some(&freq), primary),
18832 libsais16_unbwt_omp(&bwt, &mut omp, &mut omp_work, Some(&freq), primary, 2)
18833 );
18834 assert_eq!(omp, direct);
18835 assert_eq!(omp, text);
18836
18837 let mut aux = vec![0; (text.len() - 1) / 4 + 1];
18838 assert_eq!(
18839 libsais16_bwt_aux(&text, &mut bwt, &mut work, 0, Some(&mut freq), 4, &mut aux),
18840 0
18841 );
18842 direct.fill(0);
18843 direct_work.fill(0);
18844 omp.fill(0);
18845 omp_work.fill(0);
18846 assert_eq!(
18847 libsais16_unbwt_aux(&bwt, &mut direct, &mut direct_work, Some(&freq), 4, &aux),
18848 libsais16_unbwt_aux_omp(&bwt, &mut omp, &mut omp_work, Some(&freq), 4, &aux, 2)
18849 );
18850 assert_eq!(omp, direct);
18851 assert_eq!(omp, text);
18852 }
18853
18854 #[test]
18855 fn libsais16_lcp_and_unbwt_omp_wrappers_match_direct_calls() {
18856 let text = [2, 1, 3, 1, 2, 0];
18857 let mut sa = vec![0; text.len()];
18858 assert_eq!(libsais16(&text, &mut sa, 0, None), 0);
18859
18860 let mut direct_plcp = vec![0; text.len()];
18861 let mut omp_plcp = vec![0; text.len()];
18862 assert_eq!(libsais16_plcp(&text, &sa, &mut direct_plcp), 0);
18863 assert_eq!(libsais16_plcp_omp(&text, &sa, &mut omp_plcp, 2), 0);
18864 assert_eq!(omp_plcp, direct_plcp);
18865 assert_eq!(libsais16_plcp_omp(&text, &sa, &mut omp_plcp, -1), -1);
18866
18867 let gsa_text = [2, 1, 0, 1, 2, 0];
18868 let mut gsa = vec![0; gsa_text.len()];
18869 assert_eq!(libsais16_gsa(&gsa_text, &mut gsa, 0, None), 0);
18870 let mut direct_gsa_plcp = vec![0; gsa_text.len()];
18871 let mut omp_gsa_plcp = vec![0; gsa_text.len()];
18872 assert_eq!(libsais16_plcp_gsa(&gsa_text, &gsa, &mut direct_gsa_plcp), 0);
18873 assert_eq!(
18874 libsais16_plcp_gsa_omp(&gsa_text, &gsa, &mut omp_gsa_plcp, 2),
18875 0
18876 );
18877 assert_eq!(omp_gsa_plcp, direct_gsa_plcp);
18878 assert_eq!(
18879 libsais16_plcp_gsa_omp(&gsa_text, &gsa, &mut omp_gsa_plcp, -1),
18880 -1
18881 );
18882
18883 let mut direct_lcp = vec![0; text.len()];
18884 let mut omp_lcp = vec![0; text.len()];
18885 assert_eq!(libsais16_lcp(&direct_plcp, &sa, &mut direct_lcp), 0);
18886 assert_eq!(libsais16_lcp_omp(&direct_plcp, &sa, &mut omp_lcp, 2), 0);
18887 assert_eq!(omp_lcp, direct_lcp);
18888 assert_eq!(libsais16_lcp_omp(&direct_plcp, &sa, &mut omp_lcp, -1), -1);
18889
18890 let mut bwt = vec![0; text.len()];
18891 let mut work = vec![0; text.len()];
18892 let primary = libsais16_bwt(&text, &mut bwt, &mut work, 0, None);
18893 let mut direct = vec![0; text.len()];
18894 let mut omp = vec![0; text.len()];
18895 let mut direct_work = vec![0; text.len()];
18896 let mut omp_work = vec![0; text.len()];
18897 assert_eq!(
18898 libsais16_unbwt(&bwt, &mut direct, &mut direct_work, None, primary),
18899 0
18900 );
18901 assert_eq!(
18902 libsais16_unbwt_omp(&bwt, &mut omp, &mut omp_work, None, primary, 2),
18903 0
18904 );
18905 assert_eq!(omp, direct);
18906 assert_eq!(
18907 libsais16_unbwt_omp(&bwt, &mut omp, &mut omp_work, None, primary, -1),
18908 -1
18909 );
18910 }
18911}