1use std::mem;
8
9use rayon::prelude::*;
10
11use crate::{run_rayon_with_threads, SyncMutPtr};
12
13pub type SaSint = i64;
14pub type SaUint = u64;
15
16pub const ALPHABET_SIZE: usize = 1usize << 16;
17const SAINT_MAX: SaSint = SaSint::MAX;
18const SAINT_MIN: SaSint = SaSint::MIN;
19const SAINT_BIT: u32 = 64;
20const SUFFIX_GROUP_BIT: u32 = SAINT_BIT - 1;
21const SUFFIX_GROUP_MARKER: SaSint = 1_i64 << (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] {
387 *value ^= SAINT_MIN;
388 }
389}
390
391fn gather_lms_suffixes_32s(t: &[SaSint], sa: &mut [SaSint], n: SaSint) -> SaSint {
392 let mut i = n - 2;
393 let mut m = n - 1;
394 let mut f0 = 1usize;
395 let mut f1: usize;
396 let mut c0 = t[(n - 1) as usize] as isize;
397 let mut c1: isize;
398
399 while i >= 3 {
400 c1 = t[i as usize] as isize;
401 f1 = usize::from(c1 > c0 - f0 as isize);
402 sa[m as usize] = i + 1;
403 m -= (f1 & !f0) as SaSint;
404
405 c0 = t[(i - 1) as usize] as isize;
406 f0 = usize::from(c0 > c1 - f1 as isize);
407 sa[m as usize] = i;
408 m -= (f0 & !f1) as SaSint;
409
410 c1 = t[(i - 2) as usize] as isize;
411 f1 = usize::from(c1 > c0 - f0 as isize);
412 sa[m as usize] = i - 1;
413 m -= (f1 & !f0) as SaSint;
414
415 c0 = t[(i - 3) as usize] as isize;
416 f0 = usize::from(c0 > c1 - f1 as isize);
417 sa[m as usize] = i - 2;
418 m -= (f0 & !f1) as SaSint;
419
420 i -= 4;
421 }
422
423 while i >= 0 {
424 c1 = c0;
425 c0 = t[i as usize] as isize;
426 f1 = f0;
427 f0 = usize::from(c0 > c1 - f1 as isize);
428 sa[m as usize] = i + 1;
429 m -= (f0 & !f1) as SaSint;
430 i -= 1;
431 }
432
433 n - 1 - m
434}
435
436fn gather_compacted_lms_suffixes_32s(t: &[SaSint], sa: &mut [SaSint], n: SaSint) -> SaSint {
437 let mut i = n - 2;
438 let mut m = n - 1;
439 let mut f0 = 1usize;
440 let mut f1: usize;
441 let mut c0 = t[(n - 1) as usize] as isize;
442 let mut c1: isize;
443
444 while i >= 3 {
445 c1 = t[i as usize] as isize;
446 f1 = usize::from(c1 > c0 - f0 as isize);
447 sa[m as usize] = i + 1;
448 m -= (f1 & !f0 & usize::from(c0 >= 0)) as SaSint;
449
450 c0 = t[(i - 1) as usize] as isize;
451 f0 = usize::from(c0 > c1 - f1 as isize);
452 sa[m as usize] = i;
453 m -= (f0 & !f1 & usize::from(c1 >= 0)) as SaSint;
454
455 c1 = t[(i - 2) as usize] as isize;
456 f1 = usize::from(c1 > c0 - f0 as isize);
457 sa[m as usize] = i - 1;
458 m -= (f1 & !f0 & usize::from(c0 >= 0)) as SaSint;
459
460 c0 = t[(i - 3) as usize] as isize;
461 f0 = usize::from(c0 > c1 - f1 as isize);
462 sa[m as usize] = i - 2;
463 m -= (f0 & !f1 & usize::from(c1 >= 0)) as SaSint;
464
465 i -= 4;
466 }
467
468 while i >= 0 {
469 c1 = c0;
470 c0 = t[i as usize] as isize;
471 f1 = f0;
472 f0 = usize::from(c0 > c1 - f1 as isize);
473 sa[m as usize] = i + 1;
474 m -= (f0 & !f1 & usize::from(c1 >= 0)) as SaSint;
475 i -= 1;
476 }
477
478 n - 1 - m
479}
480
481fn count_lms_suffixes_32s_4k(t: &[SaSint], n: SaSint, k: SaSint, buckets: &mut [SaSint]) {
482 buckets[..4 * k as usize].fill(0);
483 let mut i = n - 2;
484 let mut f0 = 1usize;
485 let mut f1: usize;
486 let mut c0 = t[(n - 1) as usize] as isize;
487 let mut c1: isize;
488
489 while i >= 3 {
490 c1 = t[i as usize] as isize;
491 f1 = usize::from(c1 > c0 - f0 as isize);
492 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
493
494 c0 = t[(i - 1) as usize] as isize;
495 f0 = usize::from(c0 > c1 - f1 as isize);
496 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
497
498 c1 = t[(i - 2) as usize] as isize;
499 f1 = usize::from(c1 > c0 - f0 as isize);
500 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
501
502 c0 = t[(i - 3) as usize] as isize;
503 f0 = usize::from(c0 > c1 - f1 as isize);
504 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
505
506 i -= 4;
507 }
508
509 while i >= 0 {
510 c1 = c0;
511 c0 = t[i as usize] as isize;
512 f1 = f0;
513 f0 = usize::from(c0 > c1 - f1 as isize);
514 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
515 i -= 1;
516 }
517
518 buckets[buckets_index4(c0 as usize, f0 + f0)] += 1;
519}
520
521fn count_lms_suffixes_32s_2k(t: &[SaSint], n: SaSint, k: SaSint, buckets: &mut [SaSint]) {
522 buckets[..2 * k as usize].fill(0);
523 let mut i = n - 2;
524 let mut f0 = 1usize;
525 let mut f1: usize;
526 let mut c0 = t[(n - 1) as usize] as isize;
527 let mut c1: isize;
528
529 while i >= 3 {
530 c1 = t[i as usize] as isize;
531 f1 = usize::from(c1 > c0 - f0 as isize);
532 buckets[buckets_index2(c0 as usize, f1 & !f0)] += 1;
533
534 c0 = t[(i - 1) as usize] as isize;
535 f0 = usize::from(c0 > c1 - f1 as isize);
536 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
537
538 c1 = t[(i - 2) as usize] as isize;
539 f1 = usize::from(c1 > c0 - f0 as isize);
540 buckets[buckets_index2(c0 as usize, f1 & !f0)] += 1;
541
542 c0 = t[(i - 3) as usize] as isize;
543 f0 = usize::from(c0 > c1 - f1 as isize);
544 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
545
546 i -= 4;
547 }
548
549 while i >= 0 {
550 c1 = c0;
551 c0 = t[i as usize] as isize;
552 f1 = f0;
553 f0 = usize::from(c0 > c1 - f1 as isize);
554 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
555 i -= 1;
556 }
557
558 buckets[buckets_index2(c0 as usize, 0)] += 1;
559}
560
561fn count_compacted_lms_suffixes_32s_2k(t: &[SaSint], n: SaSint, k: SaSint, buckets: &mut [SaSint]) {
562 buckets[..2 * k as usize].fill(0);
563 let mut i = n - 2;
564 let mut f0 = 1usize;
565 let mut f1: usize;
566 let mut c0 = t[(n - 1) as usize] as isize;
567 let mut c1: isize;
568
569 while i >= 3 {
570 c1 = t[i as usize] as isize;
571 f1 = usize::from(c1 > c0 - f0 as isize);
572 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, f1 & !f0)] += 1;
573
574 c0 = t[(i - 1) as usize] as isize;
575 f0 = usize::from(c0 > c1 - f1 as isize);
576 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
577
578 c1 = t[(i - 2) as usize] as isize;
579 f1 = usize::from(c1 > c0 - f0 as isize);
580 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, f1 & !f0)] += 1;
581
582 c0 = t[(i - 3) as usize] as isize;
583 f0 = usize::from(c0 > c1 - f1 as isize);
584 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
585
586 i -= 4;
587 }
588
589 while i >= 0 {
590 c1 = c0;
591 c0 = t[i as usize] as isize;
592 f1 = f0;
593 f0 = usize::from(c0 > c1 - f1 as isize);
594 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
595 i -= 1;
596 }
597
598 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, 0)] += 1;
599}
600
601fn get_bucket_stride(free_space: SaSint, bucket_size: SaSint, num_buckets: SaSint) -> SaSint {
602 let bucket_size_1024 = (bucket_size + 1023) & !1023;
603 if free_space / (num_buckets - 1) >= bucket_size_1024 {
604 return bucket_size_1024;
605 }
606 let bucket_size_16 = (bucket_size + 15) & !15;
607 if free_space / (num_buckets - 1) >= bucket_size_16 {
608 return bucket_size_16;
609 }
610 bucket_size
611}
612
613fn count_and_gather_lms_suffixes_32s_4k(
614 t: &[SaSint],
615 sa: &mut [SaSint],
616 n: SaSint,
617 k: SaSint,
618 buckets: &mut [SaSint],
619 omp_block_start: isize,
620 omp_block_size: isize,
621) -> SaSint {
622 buckets[..4 * k as usize].fill(0);
623 let mut m = omp_block_start + omp_block_size - 1;
624
625 if omp_block_size > 0 {
626 let mut j = m + 1;
627 let mut c0 = t[m as usize] as isize;
628 let mut c1 = -1isize;
629 while j < n as isize {
630 c1 = t[j as usize] as isize;
631 if c1 != c0 {
632 break;
633 }
634 j += 1;
635 }
636
637 let mut f0 = usize::from(c0 >= c1);
638 let mut f1: usize;
639 let mut i = m - 1;
640 j = omp_block_start + 64 + 3;
641 while i >= j {
642 c1 = t[i as usize] as isize;
643 f1 = usize::from(c1 > c0 - f0 as isize);
644 sa[m as usize] = (i + 1) as SaSint;
645 m -= (f1 & !f0) as isize;
646 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
647
648 c0 = t[(i - 1) as usize] as isize;
649 f0 = usize::from(c0 > c1 - f1 as isize);
650 sa[m as usize] = i as SaSint;
651 m -= (f0 & !f1) as isize;
652 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
653
654 c1 = t[(i - 2) as usize] as isize;
655 f1 = usize::from(c1 > c0 - f0 as isize);
656 sa[m as usize] = (i - 1) as SaSint;
657 m -= (f1 & !f0) as isize;
658 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
659
660 c0 = t[(i - 3) as usize] as isize;
661 f0 = usize::from(c0 > c1 - f1 as isize);
662 sa[m as usize] = (i - 2) as SaSint;
663 m -= (f0 & !f1) as isize;
664 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
665
666 i -= 4;
667 }
668
669 j -= 64 + 3;
670 while i >= j {
671 c1 = c0;
672 c0 = t[i as usize] as isize;
673 f1 = f0;
674 f0 = usize::from(c0 > c1 - f1 as isize);
675 sa[m as usize] = (i + 1) as SaSint;
676 m -= (f0 & !f1) as isize;
677 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
678 i -= 1;
679 }
680
681 c1 = if i >= 0 { t[i as usize] as isize } else { -1 };
682 f1 = usize::from(c1 > c0 - f0 as isize);
683 sa[m as usize] = (i + 1) as SaSint;
684 m -= (f1 & !f0) as isize;
685 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
686 }
687
688 (omp_block_start + omp_block_size - 1 - m) as SaSint
689}
690
691fn count_and_gather_lms_suffixes_32s_2k(
692 t: &[SaSint],
693 sa: &mut [SaSint],
694 n: SaSint,
695 k: SaSint,
696 buckets: &mut [SaSint],
697 omp_block_start: isize,
698 omp_block_size: isize,
699) -> SaSint {
700 buckets[..2 * k as usize].fill(0);
701 let mut m = omp_block_start + omp_block_size - 1;
702
703 if omp_block_size > 0 {
704 let mut j = m + 1;
705 let mut c0 = t[m as usize] as isize;
706 let mut c1 = -1isize;
707 while j < n as isize {
708 c1 = t[j as usize] as isize;
709 if c1 != c0 {
710 break;
711 }
712 j += 1;
713 }
714
715 let mut f0 = usize::from(c0 >= c1);
716 let mut f1: usize;
717 let mut i = m - 1;
718 j = omp_block_start + 64 + 3;
719 while i >= j {
720 c1 = t[i as usize] as isize;
721 f1 = usize::from(c1 > c0 - f0 as isize);
722 sa[m as usize] = (i + 1) as SaSint;
723 m -= (f1 & !f0) as isize;
724 buckets[buckets_index2(c0 as usize, f1 & !f0)] += 1;
725
726 c0 = t[(i - 1) as usize] as isize;
727 f0 = usize::from(c0 > c1 - f1 as isize);
728 sa[m as usize] = i as SaSint;
729 m -= (f0 & !f1) as isize;
730 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
731
732 c1 = t[(i - 2) as usize] as isize;
733 f1 = usize::from(c1 > c0 - f0 as isize);
734 sa[m as usize] = (i - 1) as SaSint;
735 m -= (f1 & !f0) as isize;
736 buckets[buckets_index2(c0 as usize, f1 & !f0)] += 1;
737
738 c0 = t[(i - 3) as usize] as isize;
739 f0 = usize::from(c0 > c1 - f1 as isize);
740 sa[m as usize] = (i - 2) as SaSint;
741 m -= (f0 & !f1) as isize;
742 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
743
744 i -= 4;
745 }
746
747 j -= 64 + 3;
748 while i >= j {
749 c1 = c0;
750 c0 = t[i as usize] as isize;
751 f1 = f0;
752 f0 = usize::from(c0 > c1 - f1 as isize);
753 sa[m as usize] = (i + 1) as SaSint;
754 m -= (f0 & !f1) as isize;
755 buckets[buckets_index2(c1 as usize, f0 & !f1)] += 1;
756 i -= 1;
757 }
758
759 c1 = if i >= 0 { t[i as usize] as isize } else { -1 };
760 f1 = usize::from(c1 > c0 - f0 as isize);
761 sa[m as usize] = (i + 1) as SaSint;
762 m -= (f1 & !f0) as isize;
763 buckets[buckets_index2(c0 as usize, f1 & !f0)] += 1;
764 }
765
766 (omp_block_start + omp_block_size - 1 - m) as SaSint
767}
768
769fn count_and_gather_compacted_lms_suffixes_32s_2k(
770 t: &[SaSint],
771 sa: &mut [SaSint],
772 n: SaSint,
773 k: SaSint,
774 buckets: &mut [SaSint],
775 omp_block_start: isize,
776 omp_block_size: isize,
777) -> SaSint {
778 buckets[..2 * k as usize].fill(0);
779 let mut m = omp_block_start + omp_block_size - 1;
780
781 if omp_block_size > 0 {
782 let mut j = m + 1;
783 let mut c0 = t[m as usize] as isize;
784 let mut c1 = -1isize;
785 while j < n as isize {
786 c1 = t[j as usize] as isize;
787 if c1 != c0 {
788 break;
789 }
790 j += 1;
791 }
792
793 let mut f0 = usize::from(c0 >= c1);
794 let mut f1: usize;
795 let mut i = m - 1;
796 j = omp_block_start + 64 + 3;
797 while i >= j {
798 c1 = t[i as usize] as isize;
799 f1 = usize::from(c1 > c0 - f0 as isize);
800 sa[m as usize] = (i + 1) as SaSint;
801 m -= (f1 & !f0 & usize::from(c0 >= 0)) as isize;
802 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, f1 & !f0)] += 1;
803
804 c0 = t[(i - 1) as usize] as isize;
805 f0 = usize::from(c0 > c1 - f1 as isize);
806 sa[m as usize] = i as SaSint;
807 m -= (f0 & !f1 & usize::from(c1 >= 0)) as isize;
808 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
809
810 c1 = t[(i - 2) as usize] as isize;
811 f1 = usize::from(c1 > c0 - f0 as isize);
812 sa[m as usize] = (i - 1) as SaSint;
813 m -= (f1 & !f0 & usize::from(c0 >= 0)) as isize;
814 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, f1 & !f0)] += 1;
815
816 c0 = t[(i - 3) as usize] as isize;
817 f0 = usize::from(c0 > c1 - f1 as isize);
818 sa[m as usize] = (i - 2) as SaSint;
819 m -= (f0 & !f1 & usize::from(c1 >= 0)) as isize;
820 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
821
822 i -= 4;
823 }
824
825 j -= 64 + 3;
826 while i >= j {
827 c1 = c0;
828 c0 = t[i as usize] as isize;
829 f1 = f0;
830 f0 = usize::from(c0 > c1 - f1 as isize);
831 sa[m as usize] = (i + 1) as SaSint;
832 m -= (f0 & !f1 & usize::from(c1 >= 0)) as isize;
833 buckets[buckets_index2((c1 as SaSint & SAINT_MAX) as usize, f0 & !f1)] += 1;
834 i -= 1;
835 }
836
837 c1 = if i >= 0 { t[i as usize] as isize } else { -1 };
838 f1 = usize::from(c1 > c0 - f0 as isize);
839 sa[m as usize] = (i + 1) as SaSint;
840 m -= (f1 & !f0 & usize::from(c0 >= 0)) as isize;
841 buckets[buckets_index2((c0 as SaSint & SAINT_MAX) as usize, f1 & !f0)] += 1;
842 }
843
844 (omp_block_start + omp_block_size - 1 - m) as SaSint
845}
846
847fn count_and_gather_lms_suffixes_32s_4k_fs_omp(
848 t: &[SaSint],
849 sa: &mut [SaSint],
850 n: SaSint,
851 k: SaSint,
852 buckets: &mut [SaSint],
853 local_buckets: SaSint,
854 threads: SaSint,
855 thread_state: &mut [ThreadState],
856) -> SaSint {
857 if threads == 1 || n < 65_536 {
858 return count_and_gather_lms_suffixes_32s_4k(t, sa, n, k, buckets, 0, n as isize);
859 }
860
861 let thread_count = threads as usize;
862 let n_usize = n as usize;
863 let bucket_size = 4 * k as usize;
864 let block_stride = (n / threads) & !15;
865 let free_space = if local_buckets != 0 {
866 LIBSAIS_LOCAL_BUFFER_SIZE as SaSint
867 } else {
868 buckets.len() as SaSint
869 };
870 let bucket_stride = get_bucket_stride(free_space, 4 * k, threads) as usize;
871 let workspace_len = bucket_size + bucket_stride * thread_count.saturating_sub(1);
872 let mut workspace = vec![0; workspace_len];
873
874 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
875 let block_start = thread as SaSint * block_stride;
876 let block_size = if thread + 1 < thread_count {
877 block_stride
878 } else {
879 n - block_start
880 };
881 let workspace_end = workspace_len - thread * bucket_stride;
882 let workspace_start = workspace_end - bucket_size;
883 state.count = count_and_gather_lms_suffixes_32s_4k(
884 t,
885 sa,
886 n,
887 k,
888 &mut workspace[workspace_start..workspace_end],
889 block_start as isize,
890 block_size as isize,
891 );
892 state.position = block_start + block_size;
893 }
894
895 let mut m = 0usize;
896 for thread in (0..thread_count).rev() {
897 let count =
898 usize::try_from(thread_state[thread].count).expect("count must be non-negative");
899 m += count;
900 if thread + 1 != thread_count && count > 0 {
901 let src_end = usize::try_from(thread_state[thread].position)
902 .expect("position must be non-negative");
903 let src_start = src_end - count;
904 let dst_start = n_usize - m;
905 sa.copy_within(src_start..src_end, dst_start);
906 }
907 }
908
909 let accumulation_threads = thread_count - 1;
910 let block_stride = (bucket_size / accumulation_threads) & !15usize;
911 for thread in 0..accumulation_threads {
912 let block_start = thread * block_stride;
913 let block_size = if thread + 1 < accumulation_threads {
914 block_stride
915 } else {
916 bucket_size - block_start
917 };
918 accumulate_counts_s32(
919 &mut workspace,
920 block_start,
921 block_size,
922 bucket_stride,
923 accumulation_threads + 1,
924 );
925 }
926
927 buckets[..bucket_size].copy_from_slice(&workspace[..bucket_size]);
928 m as SaSint
929}
930
931fn count_and_gather_lms_suffixes_32s_2k_fs_omp(
932 t: &[SaSint],
933 sa: &mut [SaSint],
934 n: SaSint,
935 k: SaSint,
936 buckets: &mut [SaSint],
937 local_buckets: SaSint,
938 threads: SaSint,
939 thread_state: &mut [ThreadState],
940) -> SaSint {
941 if threads == 1 || n < 65_536 {
942 return count_and_gather_lms_suffixes_32s_2k(t, sa, n, k, buckets, 0, n as isize);
943 }
944
945 let thread_count = threads as usize;
946 let n_usize = n as usize;
947 let bucket_size = 2 * k as usize;
948 let block_stride = (n / threads) & !15;
949 let free_space = if local_buckets != 0 {
950 LIBSAIS_LOCAL_BUFFER_SIZE as SaSint
951 } else {
952 buckets.len() as SaSint
953 };
954 let bucket_stride = get_bucket_stride(free_space, 2 * k, threads) as usize;
955 let workspace_len = bucket_size + bucket_stride * thread_count.saturating_sub(1);
956 let mut workspace = vec![0; workspace_len];
957
958 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
959 let block_start = thread as SaSint * block_stride;
960 let block_size = if thread + 1 < thread_count {
961 block_stride
962 } else {
963 n - block_start
964 };
965 let workspace_end = workspace_len - thread * bucket_stride;
966 let workspace_start = workspace_end - bucket_size;
967 state.count = count_and_gather_lms_suffixes_32s_2k(
968 t,
969 sa,
970 n,
971 k,
972 &mut workspace[workspace_start..workspace_end],
973 block_start as isize,
974 block_size as isize,
975 );
976 state.position = block_start + block_size;
977 }
978
979 let mut m = 0usize;
980 for thread in (0..thread_count).rev() {
981 let count =
982 usize::try_from(thread_state[thread].count).expect("count must be non-negative");
983 m += count;
984 if thread + 1 != thread_count && count > 0 {
985 let src_end = usize::try_from(thread_state[thread].position)
986 .expect("position must be non-negative");
987 let src_start = src_end - count;
988 let dst_start = n_usize - m;
989 sa.copy_within(src_start..src_end, dst_start);
990 }
991 }
992
993 let accumulation_threads = thread_count - 1;
994 let block_stride = (bucket_size / accumulation_threads) & !15usize;
995 for thread in 0..accumulation_threads {
996 let block_start = thread * block_stride;
997 let block_size = if thread + 1 < accumulation_threads {
998 block_stride
999 } else {
1000 bucket_size - block_start
1001 };
1002 accumulate_counts_s32(
1003 &mut workspace,
1004 block_start,
1005 block_size,
1006 bucket_stride,
1007 accumulation_threads + 1,
1008 );
1009 }
1010
1011 buckets[..bucket_size].copy_from_slice(&workspace[..bucket_size]);
1012 m as SaSint
1013}
1014
1015fn count_and_gather_compacted_lms_suffixes_32s_2k_fs_omp(
1016 t: &[SaSint],
1017 sa: &mut [SaSint],
1018 n: SaSint,
1019 k: SaSint,
1020 buckets: &mut [SaSint],
1021 _local_buckets: SaSint,
1022 threads: SaSint,
1023 thread_state: &mut [ThreadState],
1024) {
1025 if threads == 1 || n < 65_536 {
1026 count_and_gather_compacted_lms_suffixes_32s_2k(t, sa, n, k, buckets, 0, n as isize);
1027 return;
1028 }
1029
1030 let thread_count = threads as usize;
1031 let n_usize = n as usize;
1032 let bucket_size = 2 * k as usize;
1033 let block_stride = (n / threads) & !15;
1034 let mut workspaces = vec![vec![0; bucket_size]; thread_count];
1035 let mut gathered_runs = vec![Vec::<SaSint>::new(); thread_count];
1036
1037 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
1038 let block_start = thread as SaSint * block_stride;
1039 let block_size = if thread + 1 < thread_count {
1040 block_stride
1041 } else {
1042 n - block_start
1043 };
1044 let mut temp_sa = vec![0; n_usize + block_size as usize];
1045 state.count = count_and_gather_compacted_lms_suffixes_32s_2k(
1046 t,
1047 &mut temp_sa,
1048 n,
1049 k,
1050 &mut workspaces[thread],
1051 block_start as isize,
1052 block_size as isize,
1053 );
1054 state.position = block_start + block_size;
1055 let count = usize::try_from(state.count).expect("count must be non-negative");
1056 let src_end =
1057 n_usize + usize::try_from(state.position).expect("position must be non-negative");
1058 let src_start = src_end - count;
1059 gathered_runs[thread].extend_from_slice(&temp_sa[src_start..src_end]);
1060 }
1061
1062 let mut suffixes_before = 0usize;
1063 for thread in (0..thread_count).rev() {
1064 let count =
1065 usize::try_from(thread_state[thread].count).expect("count must be non-negative");
1066 suffixes_before += count;
1067 if count > 0 {
1068 let dst_start = n_usize - suffixes_before;
1069 let dst_end = dst_start + count;
1070 sa[dst_start..dst_end].copy_from_slice(&gathered_runs[thread]);
1071 }
1072 }
1073
1074 buckets.fill(0);
1075 for workspace in &workspaces {
1076 for (dst, src) in buckets.iter_mut().zip(workspace.iter()) {
1077 *dst += *src;
1078 }
1079 }
1080}
1081
1082fn count_and_gather_lms_suffixes_32s_4k_nofs_omp(
1083 t: &[SaSint],
1084 sa: &mut [SaSint],
1085 n: SaSint,
1086 k: SaSint,
1087 buckets: &mut [SaSint],
1088 threads: SaSint,
1089) -> SaSint {
1090 if threads > 1 && n >= 65_536 {
1091 count_lms_suffixes_32s_4k(t, n, k, buckets);
1092 gather_lms_suffixes_32s(t, sa, n)
1093 } else {
1094 count_and_gather_lms_suffixes_32s_4k(t, sa, n, k, buckets, 0, n as isize)
1095 }
1096}
1097
1098fn count_and_gather_lms_suffixes_32s_2k_nofs_omp(
1099 t: &[SaSint],
1100 sa: &mut [SaSint],
1101 n: SaSint,
1102 k: SaSint,
1103 buckets: &mut [SaSint],
1104 threads: SaSint,
1105) -> SaSint {
1106 if threads > 1 && n >= 65_536 {
1107 count_lms_suffixes_32s_2k(t, n, k, buckets);
1108 gather_lms_suffixes_32s(t, sa, n)
1109 } else {
1110 count_and_gather_lms_suffixes_32s_2k(t, sa, n, k, buckets, 0, n as isize)
1111 }
1112}
1113
1114fn count_and_gather_compacted_lms_suffixes_32s_2k_nofs_omp(
1115 t: &[SaSint],
1116 sa: &mut [SaSint],
1117 n: SaSint,
1118 k: SaSint,
1119 buckets: &mut [SaSint],
1120 threads: SaSint,
1121) -> SaSint {
1122 if threads > 1 && n >= 65_536 {
1123 count_compacted_lms_suffixes_32s_2k(t, n, k, buckets);
1124 gather_compacted_lms_suffixes_32s(t, sa, n)
1125 } else {
1126 count_and_gather_compacted_lms_suffixes_32s_2k(t, sa, n, k, buckets, 0, n as isize)
1127 }
1128}
1129
1130fn count_and_gather_lms_suffixes_32s_4k_omp(
1131 t: &[SaSint],
1132 sa: &mut [SaSint],
1133 n: SaSint,
1134 k: SaSint,
1135 buckets: &mut [SaSint],
1136 local_buckets: SaSint,
1137 threads: SaSint,
1138 thread_state: &mut [ThreadState],
1139) -> SaSint {
1140 let free_space = if local_buckets != 0 {
1141 LIBSAIS_LOCAL_BUFFER_SIZE as SaSint
1142 } else {
1143 buckets.len() as SaSint
1144 };
1145 let mut max_threads = (free_space / (((4 * k) + 15) & !15)).min(threads);
1146
1147 if max_threads > 1 && n >= 65_536 && n / k >= 2 {
1148 let thread_cap = n / (16 * k);
1149 if max_threads > thread_cap {
1150 max_threads = thread_cap;
1151 }
1152 count_and_gather_lms_suffixes_32s_4k_fs_omp(
1153 t,
1154 sa,
1155 n,
1156 k,
1157 buckets,
1158 local_buckets,
1159 max_threads.max(2),
1160 thread_state,
1161 )
1162 } else if threads > 1 && n >= 65_536 {
1163 count_lms_suffixes_32s_4k(t, n, k, buckets);
1164 gather_lms_suffixes_32s(t, sa, n)
1165 } else {
1166 count_and_gather_lms_suffixes_32s_4k_nofs_omp(t, sa, n, k, buckets, threads)
1167 }
1168}
1169
1170fn count_and_gather_lms_suffixes_32s_2k_omp(
1171 t: &[SaSint],
1172 sa: &mut [SaSint],
1173 n: SaSint,
1174 k: SaSint,
1175 buckets: &mut [SaSint],
1176 local_buckets: SaSint,
1177 threads: SaSint,
1178 thread_state: &mut [ThreadState],
1179) -> SaSint {
1180 let free_space = if local_buckets != 0 {
1181 LIBSAIS_LOCAL_BUFFER_SIZE as SaSint
1182 } else {
1183 buckets.len() as SaSint
1184 };
1185 let mut max_threads = (free_space / (((2 * k) + 15) & !15)).min(threads);
1186
1187 if max_threads > 1 && n >= 65_536 && n / k >= 2 {
1188 let thread_cap = n / (8 * k);
1189 if max_threads > thread_cap {
1190 max_threads = thread_cap;
1191 }
1192 count_and_gather_lms_suffixes_32s_2k_fs_omp(
1193 t,
1194 sa,
1195 n,
1196 k,
1197 buckets,
1198 local_buckets,
1199 max_threads.max(2),
1200 thread_state,
1201 )
1202 } else if threads > 1 && n >= 65_536 {
1203 count_lms_suffixes_32s_2k(t, n, k, buckets);
1204 gather_lms_suffixes_32s(t, sa, n)
1205 } else {
1206 count_and_gather_lms_suffixes_32s_2k_nofs_omp(t, sa, n, k, buckets, threads)
1207 }
1208}
1209
1210fn count_suffixes_32s(t: &[SaSint], n: SaSint, k: SaSint, buckets: &mut [SaSint]) {
1211 buckets[..k as usize].fill(0);
1212
1213 let mut i = 0usize;
1214 let mut j = (n as usize).saturating_sub(7);
1215 while i < j {
1216 buckets[t[i] as usize] += 1;
1217 buckets[t[i + 1] as usize] += 1;
1218 buckets[t[i + 2] as usize] += 1;
1219 buckets[t[i + 3] as usize] += 1;
1220 buckets[t[i + 4] as usize] += 1;
1221 buckets[t[i + 5] as usize] += 1;
1222 buckets[t[i + 6] as usize] += 1;
1223 buckets[t[i + 7] as usize] += 1;
1224 i += 8;
1225 }
1226
1227 j += 7;
1228 while i < j {
1229 buckets[t[i] as usize] += 1;
1230 i += 1;
1231 }
1232}
1233
1234fn initialize_buckets_start_and_end_32s_6k(k: SaSint, buckets: &mut [SaSint]) {
1235 let k = k as usize;
1236 let mut sum = 0;
1237 for j in 0..k {
1238 let i = buckets_index4(j, 0);
1239 buckets[4 * k + j] = sum;
1240 sum += buckets[i] + buckets[i + 1] + buckets[i + 2] + buckets[i + 3];
1241 buckets[5 * k + j] = sum;
1242 }
1243}
1244
1245fn initialize_buckets_start_and_end_32s_4k(k: SaSint, buckets: &mut [SaSint]) {
1246 let k = k as usize;
1247 let mut sum = 0;
1248 for j in 0..k {
1249 let i = buckets_index2(j, 0);
1250 buckets[2 * k + j] = sum;
1251 sum += buckets[i] + buckets[i + 1];
1252 buckets[3 * k + j] = sum;
1253 }
1254}
1255
1256fn initialize_buckets_end_32s_2k(k: SaSint, buckets: &mut [SaSint]) {
1257 let mut sum0 = 0;
1258 for j in 0..k as usize {
1259 let i = buckets_index2(j, 0);
1260 sum0 += buckets[i] + buckets[i + 1];
1261 buckets[i] = sum0;
1262 }
1263}
1264
1265fn initialize_buckets_start_and_end_32s_2k(k: SaSint, buckets: &mut [SaSint]) {
1266 let k = k as usize;
1267 for j in 0..k {
1268 let i = buckets_index2(j, 0);
1269 buckets[j] = buckets[i];
1270 }
1271 buckets[k] = 0;
1272 buckets.copy_within(0..k - 1, k + 1);
1273}
1274
1275fn initialize_buckets_start_32s_1k(k: SaSint, buckets: &mut [SaSint]) {
1276 let mut sum = 0;
1277 for bucket in buckets.iter_mut().take(k as usize) {
1278 let tmp = *bucket;
1279 *bucket = sum;
1280 sum += tmp;
1281 }
1282}
1283
1284fn initialize_buckets_end_32s_1k(k: SaSint, buckets: &mut [SaSint]) {
1285 let mut sum = 0;
1286 for bucket in buckets.iter_mut().take(k as usize) {
1287 sum += *bucket;
1288 *bucket = sum;
1289 }
1290}
1291
1292fn initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(
1293 t: &[SaSint],
1294 k: SaSint,
1295 buckets: &mut [SaSint],
1296 first_lms_suffix: SaSint,
1297) {
1298 buckets[buckets_index2(t[first_lms_suffix as usize] as usize, 0)] += 1;
1299 buckets[buckets_index2(t[first_lms_suffix as usize] as usize, 1)] -= 1;
1300
1301 let mut sum0 = 0;
1302 let mut sum1 = 0;
1303 for j in 0..k as usize {
1304 let i = buckets_index2(j, 0);
1305 sum0 += buckets[i] + buckets[i + 1];
1306 sum1 += buckets[i + 1];
1307 buckets[i] = sum0;
1308 buckets[i + 1] = sum1;
1309 }
1310}
1311
1312fn initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(
1313 t: &[SaSint],
1314 k: SaSint,
1315 buckets: &mut [SaSint],
1316 mut first_lms_suffix: SaSint,
1317) -> SaSint {
1318 let mut f0 = 0usize;
1319 let mut c0 = t[first_lms_suffix as usize] as isize;
1320
1321 loop {
1322 first_lms_suffix -= 1;
1323 if first_lms_suffix < 0 {
1324 break;
1325 }
1326 let c1 = c0;
1327 c0 = t[first_lms_suffix as usize] as isize;
1328 let f1 = f0;
1329 f0 = usize::from(c0 > c1 - f1 as isize);
1330 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] -= 1;
1331 }
1332 buckets[buckets_index4(c0 as usize, f0 + f0)] -= 1;
1333
1334 let mut sum = 0;
1335 for j in 0..k as usize {
1336 let i = buckets_index4(j, 0);
1337 sum += buckets[i + 1] + buckets[i + 3];
1338 buckets[4 * k as usize + j] = sum;
1339 }
1340 sum
1341}
1342
1343fn initialize_buckets_for_partial_sorting_32s_6k(
1344 t: &[SaSint],
1345 k: SaSint,
1346 buckets: &mut [SaSint],
1347 first_lms_suffix: SaSint,
1348 left_suffixes_count: SaSint,
1349) {
1350 let k = k as usize;
1351 let temp_offset = 4 * k;
1352 let first_symbol = t[first_lms_suffix as usize] as usize;
1353 let mut sum0 = left_suffixes_count + 1;
1354 let mut sum1 = 0;
1355 let mut sum2 = 0;
1356
1357 for j in 0..first_symbol {
1358 let i = buckets_index4(j, 0);
1359 let tj = buckets_index2(j, 0);
1360 let ss = buckets[i];
1361 let ls = buckets[i + 1];
1362 let sl = buckets[i + 2];
1363 let ll = buckets[i + 3];
1364
1365 buckets[i] = sum0;
1366 buckets[i + 1] = sum2;
1367 buckets[i + 2] = 0;
1368 buckets[i + 3] = 0;
1369
1370 sum0 += ss + sl;
1371 sum1 += ls;
1372 sum2 += ls + ll;
1373
1374 buckets[temp_offset + tj] = sum0;
1375 buckets[temp_offset + tj + 1] = sum1;
1376 }
1377
1378 sum1 += 1;
1379 for j in first_symbol..k {
1380 let i = buckets_index4(j, 0);
1381 let tj = buckets_index2(j, 0);
1382 let ss = buckets[i];
1383 let ls = buckets[i + 1];
1384 let sl = buckets[i + 2];
1385 let ll = buckets[i + 3];
1386
1387 buckets[i] = sum0;
1388 buckets[i + 1] = sum2;
1389 buckets[i + 2] = 0;
1390 buckets[i + 3] = 0;
1391
1392 sum0 += ss + sl;
1393 sum1 += ls;
1394 sum2 += ls + ll;
1395
1396 buckets[temp_offset + tj] = sum0;
1397 buckets[temp_offset + tj + 1] = sum1;
1398 }
1399}
1400
1401fn initialize_buckets_for_radix_and_partial_sorting_32s_4k(
1402 t: &[SaSint],
1403 k: SaSint,
1404 buckets: &mut [SaSint],
1405 first_lms_suffix: SaSint,
1406) {
1407 let k = k as usize;
1408 buckets[buckets_index2(t[first_lms_suffix as usize] as usize, 0)] += 1;
1409 buckets[buckets_index2(t[first_lms_suffix as usize] as usize, 1)] -= 1;
1410
1411 let mut sum0 = 0;
1412 let mut sum1 = 0;
1413 for j in 0..k {
1414 let i = buckets_index2(j, 0);
1415 buckets[2 * k + j] = sum1;
1416 sum0 += buckets[i + 1];
1417 sum1 += buckets[i] + buckets[i + 1];
1418 buckets[i + 1] = sum0;
1419 buckets[3 * k + j] = sum1;
1420 }
1421}
1422
1423fn count_and_gather_compacted_lms_suffixes_32s_2k_omp(
1424 t: &[SaSint],
1425 sa: &mut [SaSint],
1426 n: SaSint,
1427 k: SaSint,
1428 buckets: &mut [SaSint],
1429 local_buckets: SaSint,
1430 threads: SaSint,
1431 thread_state: &mut [ThreadState],
1432) {
1433 let free_space = if local_buckets != 0 {
1434 LIBSAIS_LOCAL_BUFFER_SIZE as SaSint
1435 } else {
1436 buckets.len() as SaSint
1437 };
1438 let mut max_threads = (free_space / (((2 * k) + 15) & !15)).min(threads);
1439
1440 if local_buckets == 0 && max_threads > 1 && n >= 65_536 && n / k >= 2 {
1441 let thread_cap = n / (8 * k);
1442 if max_threads > thread_cap {
1443 max_threads = thread_cap;
1444 }
1445 count_and_gather_compacted_lms_suffixes_32s_2k_fs_omp(
1446 t,
1447 sa,
1448 n,
1449 k,
1450 buckets,
1451 local_buckets,
1452 max_threads.max(2),
1453 thread_state,
1454 );
1455 } else {
1456 count_and_gather_compacted_lms_suffixes_32s_2k_nofs_omp(t, sa, n, k, buckets, threads);
1457 }
1458}
1459
1460fn gather_lms_suffixes_16u(
1461 t: &[u16],
1462 sa: &mut [SaSint],
1463 n: SaSint,
1464 mut m: SaSint,
1465 omp_block_start: SaSint,
1466 omp_block_size: SaSint,
1467) {
1468 if omp_block_size > 0 {
1469 let n = n as isize;
1470 let mut i: isize;
1471 let mut j = (omp_block_start + omp_block_size) as isize;
1472 let mut c0 = t[(omp_block_start + omp_block_size - 1) as usize] as isize;
1473 let mut c1 = -1isize;
1474
1475 while j < n {
1476 c1 = t[j as usize] as isize;
1477 if c1 != c0 {
1478 break;
1479 }
1480 j += 1;
1481 }
1482
1483 let mut f0 = usize::from(c0 >= c1);
1484 let mut f1: usize;
1485
1486 i = (omp_block_start + omp_block_size - 2) as isize;
1487 j = (omp_block_start + 3) as isize;
1488 while i >= j {
1489 c1 = t[i as usize] as isize;
1490 f1 = usize::from(c1 > c0 - f0 as isize);
1491 sa[m as usize] = (i + 1) as SaSint;
1492 m -= (f1 & (1 - f0)) as SaSint;
1493
1494 c0 = t[(i - 1) as usize] as isize;
1495 f0 = usize::from(c0 > c1 - f1 as isize);
1496 sa[m as usize] = i as SaSint;
1497 m -= (f0 & (1 - f1)) as SaSint;
1498
1499 c1 = t[(i - 2) as usize] as isize;
1500 f1 = usize::from(c1 > c0 - f0 as isize);
1501 sa[m as usize] = (i - 1) as SaSint;
1502 m -= (f1 & (1 - f0)) as SaSint;
1503
1504 c0 = t[(i - 3) as usize] as isize;
1505 f0 = usize::from(c0 > c1 - f1 as isize);
1506 sa[m as usize] = (i - 2) as SaSint;
1507 m -= (f0 & (1 - f1)) as SaSint;
1508
1509 i -= 4;
1510 }
1511
1512 j -= 3;
1513 while i >= j {
1514 c1 = c0;
1515 c0 = t[i as usize] as isize;
1516 f1 = f0;
1517 f0 = usize::from(c0 > c1 - f1 as isize);
1518 sa[m as usize] = (i + 1) as SaSint;
1519 m -= (f0 & (1 - f1)) as SaSint;
1520 i -= 1;
1521 }
1522
1523 sa[m as usize] = (i + 1) as SaSint;
1524 }
1525}
1526
1527fn count_and_gather_lms_suffixes_16u(
1528 t: &[u16],
1529 sa: &mut [SaSint],
1530 n: SaSint,
1531 buckets: &mut [SaSint],
1532 omp_block_start: SaSint,
1533 omp_block_size: SaSint,
1534) -> SaSint {
1535 buckets[..4 * ALPHABET_SIZE].fill(0);
1536
1537 let mut m = (omp_block_start + omp_block_size - 1) as isize;
1538
1539 if omp_block_size > 0 {
1540 let n = n as isize;
1541 let mut i: isize;
1542 let mut j = m + 1;
1543 let mut c0 = t[m as usize] as isize;
1544 let mut c1 = -1isize;
1545
1546 while j < n {
1547 c1 = t[j as usize] as isize;
1548 if c1 != c0 {
1549 break;
1550 }
1551 j += 1;
1552 }
1553
1554 let mut f0 = usize::from(c0 >= c1);
1555 let mut f1: usize;
1556
1557 i = m - 1;
1558 j = (omp_block_start + 3) as isize;
1559 while i >= j {
1560 c1 = t[i as usize] as isize;
1561 f1 = usize::from(c1 > c0 - f0 as isize);
1562 sa[m as usize] = (i + 1) as SaSint;
1563 m -= (f1 & (1 - f0)) as isize;
1564 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
1565
1566 c0 = t[(i - 1) as usize] as isize;
1567 f0 = usize::from(c0 > c1 - f1 as isize);
1568 sa[m as usize] = i as SaSint;
1569 m -= (f0 & (1 - f1)) as isize;
1570 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
1571
1572 c1 = t[(i - 2) as usize] as isize;
1573 f1 = usize::from(c1 > c0 - f0 as isize);
1574 sa[m as usize] = (i - 1) as SaSint;
1575 m -= (f1 & (1 - f0)) as isize;
1576 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
1577
1578 c0 = t[(i - 3) as usize] as isize;
1579 f0 = usize::from(c0 > c1 - f1 as isize);
1580 sa[m as usize] = (i - 2) as SaSint;
1581 m -= (f0 & (1 - f1)) as isize;
1582 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
1583
1584 i -= 4;
1585 }
1586
1587 j -= 3;
1588 while i >= j {
1589 c1 = c0;
1590 c0 = t[i as usize] as isize;
1591 f1 = f0;
1592 f0 = usize::from(c0 > c1 - f1 as isize);
1593 sa[m as usize] = (i + 1) as SaSint;
1594 m -= (f0 & (1 - f1)) as isize;
1595 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] += 1;
1596 i -= 1;
1597 }
1598
1599 c1 = if i >= 0 { t[i as usize] as isize } else { -1 };
1600 f1 = usize::from(c1 > c0 - f0 as isize);
1601 sa[m as usize] = (i + 1) as SaSint;
1602 m -= (f1 & (1 - f0)) as isize;
1603 buckets[buckets_index4(c0 as usize, f0 + f0 + f1)] += 1;
1604 }
1605
1606 omp_block_start + omp_block_size - 1 - m as SaSint
1607}
1608
1609fn gather_lms_suffixes_16u_omp(
1610 t: &[u16],
1611 sa: &mut [SaSint],
1612 n: SaSint,
1613 threads: SaSint,
1614 thread_state: &mut [ThreadState],
1615) {
1616 if threads == 1 || n < 65_536 || thread_state.is_empty() {
1617 gather_lms_suffixes_16u(t, sa, n, n - 1, 0, n);
1618 return;
1619 }
1620
1621 let thread_count = threads as usize;
1622 let block_stride = (n / threads) & !15;
1623 let mut suffix_counts_after = vec![0; thread_count];
1624 let mut m = 0;
1625 for thread in (0..thread_count).rev() {
1626 suffix_counts_after[thread] = m;
1627 m += thread_state[thread].m;
1628 }
1629
1630 for thread in 0..thread_count {
1631 let block_start = thread as SaSint * block_stride;
1632 let block_size = if thread + 1 < thread_count {
1633 block_stride
1634 } else {
1635 n - block_start
1636 };
1637 gather_lms_suffixes_16u(
1638 t,
1639 sa,
1640 n,
1641 n - 1 - suffix_counts_after[thread],
1642 block_start,
1643 block_size,
1644 );
1645 }
1646
1647 for thread in 0..thread_count {
1648 if thread_state[thread].m > 0 {
1649 sa[(n - 1 - suffix_counts_after[thread]) as usize] =
1650 thread_state[thread].last_lms_suffix;
1651 }
1652 }
1653}
1654
1655fn count_and_gather_lms_suffixes_16u_omp(
1656 t: &[u16],
1657 sa: &mut [SaSint],
1658 n: SaSint,
1659 buckets: &mut [SaSint],
1660 threads: SaSint,
1661 thread_state: &mut [ThreadState],
1662) -> SaSint {
1663 if threads == 1 || n < 65_536 || thread_state.is_empty() {
1664 return count_and_gather_lms_suffixes_16u(t, sa, n, buckets, 0, n);
1665 }
1666
1667 let thread_count = threads as usize;
1668 let block_stride = (n / threads) & !15;
1669
1670 for thread in 0..thread_count {
1671 let block_start = thread as SaSint * block_stride;
1672 let block_size = if thread + 1 < thread_count {
1673 block_stride
1674 } else {
1675 n - block_start
1676 };
1677 let count = count_and_gather_lms_suffixes_16u(
1678 t,
1679 sa,
1680 n,
1681 &mut thread_state[thread].buckets,
1682 block_start,
1683 block_size,
1684 );
1685 thread_state[thread].m = count;
1686 thread_state[thread].position = block_start + block_size;
1687 if count > 0 {
1688 thread_state[thread].last_lms_suffix = sa[(block_start + block_size - 1) as usize];
1689 }
1690 }
1691
1692 buckets[..4 * ALPHABET_SIZE].fill(0);
1693 let mut m = 0;
1694 for thread in (0..thread_count).rev() {
1695 let position = thread_state[thread].position;
1696 let count = thread_state[thread].m;
1697 m += count;
1698 if thread + 1 != thread_count && count > 0 {
1699 let src_end = position as usize;
1700 let src_start = src_end - count as usize;
1701 let dst_start = (n - m) as usize;
1702 sa.copy_within(src_start..src_end, dst_start);
1703 }
1704 for s in 0..4 * ALPHABET_SIZE {
1705 let a = buckets[s];
1706 let b = thread_state[thread].buckets[s];
1707 buckets[s] = a + b;
1708 thread_state[thread].buckets[s] = a;
1709 }
1710 }
1711
1712 m
1713}
1714
1715fn initialize_buckets_start_and_end_16u(
1716 buckets: &mut [SaSint],
1717 freq: Option<&mut [SaSint]>,
1718) -> SaSint {
1719 let (count_buckets, start_end) = buckets.split_at_mut(6 * ALPHABET_SIZE);
1720 let (bucket_start, bucket_end) = start_end.split_at_mut(ALPHABET_SIZE);
1721
1722 let mut k = -1;
1723 let mut sum = 0;
1724
1725 if let Some(freq) = freq {
1726 for j in 0..ALPHABET_SIZE {
1727 let i = buckets_index4(j, 0);
1728 let total = count_buckets[i]
1729 + count_buckets[i + buckets_index4(0, 1)]
1730 + count_buckets[i + buckets_index4(0, 2)]
1731 + count_buckets[i + buckets_index4(0, 3)];
1732
1733 bucket_start[j] = sum;
1734 sum += total;
1735 bucket_end[j] = sum;
1736 if total > 0 {
1737 k = j as SaSint;
1738 }
1739 freq[j] = total;
1740 }
1741 } else {
1742 for j in 0..ALPHABET_SIZE {
1743 let i = buckets_index4(j, 0);
1744 let total = count_buckets[i]
1745 + count_buckets[i + buckets_index4(0, 1)]
1746 + count_buckets[i + buckets_index4(0, 2)]
1747 + count_buckets[i + buckets_index4(0, 3)];
1748
1749 bucket_start[j] = sum;
1750 sum += total;
1751 bucket_end[j] = sum;
1752 if total > 0 {
1753 k = j as SaSint;
1754 }
1755 }
1756 }
1757
1758 k + 1
1759}
1760
1761fn initialize_buckets_for_lms_suffixes_radix_sort_16u(
1762 t: &[u16],
1763 buckets: &mut [SaSint],
1764 mut first_lms_suffix: SaSint,
1765) -> SaSint {
1766 let mut f0 = 0usize;
1767 let mut c0 = t[first_lms_suffix as usize] as isize;
1768
1769 loop {
1770 first_lms_suffix -= 1;
1771 if first_lms_suffix < 0 {
1772 break;
1773 }
1774
1775 let c1 = c0;
1776 c0 = t[first_lms_suffix as usize] as isize;
1777 let f1 = f0;
1778 f0 = usize::from(c0 > c1 - f1 as isize);
1779 buckets[buckets_index4(c1 as usize, f1 + f1 + f0)] -= 1;
1780 }
1781
1782 buckets[buckets_index4(c0 as usize, f0 + f0)] -= 1;
1783
1784 let (count_buckets, temp_bucket) = buckets.split_at_mut(4 * ALPHABET_SIZE);
1785 let mut sum = 0;
1786 for c in 0..ALPHABET_SIZE {
1787 let i = buckets_index4(c, 0);
1788 let j = buckets_index2(c, 0);
1789 temp_bucket[j + buckets_index2(0, 1)] = sum;
1790 sum += count_buckets[i + buckets_index4(0, 1)] + count_buckets[i + buckets_index4(0, 3)];
1791 temp_bucket[j] = sum;
1792 }
1793
1794 sum
1795}
1796
1797fn radix_sort_lms_suffixes_16u(
1798 t: &[u16],
1799 sa: &mut [SaSint],
1800 induction_bucket: &mut [SaSint],
1801 omp_block_start: SaSint,
1802 omp_block_size: SaSint,
1803) {
1804 let mut i = omp_block_start + omp_block_size - 1;
1805 let mut j = omp_block_start + 64 + 3;
1806 while i >= j {
1807 let p0 = sa[i as usize];
1808 induction_bucket[buckets_index2(t[p0 as usize] as usize, 0)] -= 1;
1809 sa[induction_bucket[buckets_index2(t[p0 as usize] as usize, 0)] as usize] = p0;
1810
1811 let p1 = sa[(i - 1) as usize];
1812 induction_bucket[buckets_index2(t[p1 as usize] as usize, 0)] -= 1;
1813 sa[induction_bucket[buckets_index2(t[p1 as usize] as usize, 0)] as usize] = p1;
1814
1815 let p2 = sa[(i - 2) as usize];
1816 induction_bucket[buckets_index2(t[p2 as usize] as usize, 0)] -= 1;
1817 sa[induction_bucket[buckets_index2(t[p2 as usize] as usize, 0)] as usize] = p2;
1818
1819 let p3 = sa[(i - 3) as usize];
1820 induction_bucket[buckets_index2(t[p3 as usize] as usize, 0)] -= 1;
1821 sa[induction_bucket[buckets_index2(t[p3 as usize] as usize, 0)] as usize] = p3;
1822
1823 i -= 4;
1824 }
1825
1826 j -= 64 + 3;
1827 while i >= j {
1828 let p = sa[i as usize];
1829 induction_bucket[buckets_index2(t[p as usize] as usize, 0)] -= 1;
1830 sa[induction_bucket[buckets_index2(t[p as usize] as usize, 0)] as usize] = p;
1831 i -= 1;
1832 }
1833}
1834
1835fn radix_sort_lms_suffixes_16u_omp(
1836 t: &[u16],
1837 sa: &mut [SaSint],
1838 n: SaSint,
1839 m: SaSint,
1840 flags: SaSint,
1841 buckets: &mut [SaSint],
1842 threads: SaSint,
1843 thread_state: &mut [ThreadState],
1844) {
1845 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
1846 buckets[4 * ALPHABET_SIZE] -= 1;
1847 }
1848 if threads == 1 || n < 65_536 || m < 65_536 || thread_state.is_empty() {
1849 radix_sort_lms_suffixes_16u(t, sa, &mut buckets[4 * ALPHABET_SIZE..], n - m + 1, m - 1);
1850 return;
1851 }
1852
1853 let thread_count = threads as usize;
1854 for thread in 0..thread_count {
1855 let (src_buckets, state_buckets) = (
1856 &buckets[4 * ALPHABET_SIZE..],
1857 &mut thread_state[thread].buckets,
1858 );
1859 for c in 0..ALPHABET_SIZE {
1860 let i = buckets_index2(c, 0);
1861 let j = buckets_index4(c, 1);
1862 state_buckets[i] = src_buckets[i] - state_buckets[j];
1863 }
1864
1865 let mut block_start = 0;
1866 let mut block_size = thread_state[thread].m;
1867 for idx in (thread..thread_count).rev() {
1868 block_start += thread_state[idx].m;
1869 }
1870
1871 if block_start == m && block_size > 0 {
1872 block_start -= 1;
1873 block_size -= 1;
1874 }
1875
1876 radix_sort_lms_suffixes_16u(
1877 t,
1878 sa,
1879 &mut thread_state[thread].buckets,
1880 n - block_start,
1881 block_size,
1882 );
1883 }
1884}
1885
1886fn radix_sort_lms_suffixes_32s_6k(
1887 t: &[SaSint],
1888 sa: &mut [SaSint],
1889 induction_bucket: &mut [SaSint],
1890 omp_block_start: SaSint,
1891 omp_block_size: SaSint,
1892) {
1893 let mut i = omp_block_start + omp_block_size - 1;
1894 let mut j = omp_block_start + 64 + 3;
1895 while i >= j {
1896 let p0 = sa[i as usize];
1897 induction_bucket[t[p0 as usize] as usize] -= 1;
1898 sa[induction_bucket[t[p0 as usize] as usize] as usize] = p0;
1899 let p1 = sa[(i - 1) as usize];
1900 induction_bucket[t[p1 as usize] as usize] -= 1;
1901 sa[induction_bucket[t[p1 as usize] as usize] as usize] = p1;
1902 let p2 = sa[(i - 2) as usize];
1903 induction_bucket[t[p2 as usize] as usize] -= 1;
1904 sa[induction_bucket[t[p2 as usize] as usize] as usize] = p2;
1905 let p3 = sa[(i - 3) as usize];
1906 induction_bucket[t[p3 as usize] as usize] -= 1;
1907 sa[induction_bucket[t[p3 as usize] as usize] as usize] = p3;
1908 i -= 4;
1909 }
1910
1911 j -= 64 + 3;
1912 while i >= j {
1913 let p = sa[i as usize];
1914 induction_bucket[t[p as usize] as usize] -= 1;
1915 sa[induction_bucket[t[p as usize] as usize] as usize] = p;
1916 i -= 1;
1917 }
1918}
1919
1920fn radix_sort_lms_suffixes_32s_2k(
1921 t: &[SaSint],
1922 sa: &mut [SaSint],
1923 induction_bucket: &mut [SaSint],
1924 omp_block_start: SaSint,
1925 omp_block_size: SaSint,
1926) {
1927 let mut i = omp_block_start + omp_block_size - 1;
1928 let mut j = omp_block_start + 64 + 3;
1929 while i >= j {
1930 let p0 = sa[i as usize];
1931 induction_bucket[buckets_index2(t[p0 as usize] as usize, 0)] -= 1;
1932 sa[induction_bucket[buckets_index2(t[p0 as usize] as usize, 0)] as usize] = p0;
1933 let p1 = sa[(i - 1) as usize];
1934 induction_bucket[buckets_index2(t[p1 as usize] as usize, 0)] -= 1;
1935 sa[induction_bucket[buckets_index2(t[p1 as usize] as usize, 0)] as usize] = p1;
1936 let p2 = sa[(i - 2) as usize];
1937 induction_bucket[buckets_index2(t[p2 as usize] as usize, 0)] -= 1;
1938 sa[induction_bucket[buckets_index2(t[p2 as usize] as usize, 0)] as usize] = p2;
1939 let p3 = sa[(i - 3) as usize];
1940 induction_bucket[buckets_index2(t[p3 as usize] as usize, 0)] -= 1;
1941 sa[induction_bucket[buckets_index2(t[p3 as usize] as usize, 0)] as usize] = p3;
1942 i -= 4;
1943 }
1944
1945 j -= 64 + 3;
1946 while i >= j {
1947 let p = sa[i as usize];
1948 induction_bucket[buckets_index2(t[p as usize] as usize, 0)] -= 1;
1949 sa[induction_bucket[buckets_index2(t[p as usize] as usize, 0)] as usize] = p;
1950 i -= 1;
1951 }
1952}
1953
1954fn radix_sort_lms_suffixes_32s_block_gather(
1955 t: &[SaSint],
1956 sa: &[SaSint],
1957 cache: &mut [ThreadCache],
1958 omp_block_start: SaSint,
1959 omp_block_size: SaSint,
1960) {
1961 if omp_block_size <= 0 {
1962 return;
1963 }
1964
1965 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
1966 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
1967 let cache_base = if cache.len() >= start + size {
1968 0
1969 } else {
1970 start
1971 };
1972 let mut i = start;
1973 let mut j = if size > 67 { start + size - 67 } else { start };
1974
1975 while i < j {
1976 for current in [i, i + 1, i + 2, i + 3] {
1977 let ci = current - cache_base;
1978 let index = sa[current];
1979 cache[ci].index = index;
1980 cache[ci].symbol = t[index as usize];
1981 }
1982 i += 4;
1983 }
1984
1985 j = if size > 67 { j + 67 } else { start + size };
1986 while i < j {
1987 let ci = i - cache_base;
1988 let index = sa[i];
1989 cache[ci].index = index;
1990 cache[ci].symbol = t[index as usize];
1991 i += 1;
1992 }
1993}
1994
1995fn radix_sort_lms_suffixes_32s_6k_block_sort(
1996 induction_bucket: &mut [SaSint],
1997 cache: &mut [ThreadCache],
1998 omp_block_start: SaSint,
1999 omp_block_size: SaSint,
2000) {
2001 if omp_block_size <= 0 {
2002 return;
2003 }
2004
2005 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
2006 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
2007 let cache_base = if cache.len() >= start + size {
2008 0
2009 } else {
2010 start
2011 };
2012 let mut i = start + size - 1;
2013 let mut j = start + 64 + 3;
2014
2015 while i >= j {
2016 for current in [i, i - 1, i - 2, i - 3] {
2017 let ci = current - cache_base;
2018 let v = cache[ci].symbol as usize;
2019 induction_bucket[v] -= 1;
2020 cache[ci].symbol = induction_bucket[v];
2021 }
2022 i -= 4;
2023 }
2024
2025 j -= 64 + 3;
2026 while i >= j {
2027 let ci = i - cache_base;
2028 let v = cache[ci].symbol as usize;
2029 induction_bucket[v] -= 1;
2030 cache[ci].symbol = induction_bucket[v];
2031 if i == 0 {
2032 break;
2033 }
2034 i -= 1;
2035 }
2036}
2037
2038fn radix_sort_lms_suffixes_32s_2k_block_sort(
2039 induction_bucket: &mut [SaSint],
2040 cache: &mut [ThreadCache],
2041 omp_block_start: SaSint,
2042 omp_block_size: SaSint,
2043) {
2044 if omp_block_size <= 0 {
2045 return;
2046 }
2047
2048 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
2049 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
2050 let cache_base = if cache.len() >= start + size {
2051 0
2052 } else {
2053 start
2054 };
2055 let mut i = start + size - 1;
2056 let mut j = start + 64 + 3;
2057
2058 while i >= j {
2059 for current in [i, i - 1, i - 2, i - 3] {
2060 let ci = current - cache_base;
2061 let v = buckets_index2(cache[ci].symbol as usize, 0);
2062 induction_bucket[v] -= 1;
2063 cache[ci].symbol = induction_bucket[v];
2064 }
2065 i -= 4;
2066 }
2067
2068 j -= 64 + 3;
2069 while i >= j {
2070 let ci = i - cache_base;
2071 let v = buckets_index2(cache[ci].symbol as usize, 0);
2072 induction_bucket[v] -= 1;
2073 cache[ci].symbol = induction_bucket[v];
2074 if i == 0 {
2075 break;
2076 }
2077 i -= 1;
2078 }
2079}
2080
2081fn radix_sort_lms_suffixes_32s_6k_block_omp(
2082 t: &[SaSint],
2083 sa: &mut [SaSint],
2084 induction_bucket: &mut [SaSint],
2085 cache: &mut [ThreadCache],
2086 block_start: SaSint,
2087 block_size: SaSint,
2088 threads: SaSint,
2089) {
2090 if threads <= 1 || block_size < 16_384 {
2091 radix_sort_lms_suffixes_32s_6k(t, sa, induction_bucket, block_start, block_size);
2092 return;
2093 }
2094
2095 radix_sort_lms_suffixes_32s_block_gather(t, sa, cache, block_start, block_size);
2096 radix_sort_lms_suffixes_32s_6k_block_sort(induction_bucket, cache, block_start, block_size);
2097 place_cached_suffixes(sa, cache, block_start, block_size);
2098}
2099
2100fn radix_sort_lms_suffixes_32s_2k_block_omp(
2101 t: &[SaSint],
2102 sa: &mut [SaSint],
2103 induction_bucket: &mut [SaSint],
2104 cache: &mut [ThreadCache],
2105 block_start: SaSint,
2106 block_size: SaSint,
2107 threads: SaSint,
2108) {
2109 if threads <= 1 || block_size < 16_384 {
2110 radix_sort_lms_suffixes_32s_2k(t, sa, induction_bucket, block_start, block_size);
2111 return;
2112 }
2113
2114 radix_sort_lms_suffixes_32s_block_gather(t, sa, cache, block_start, block_size);
2115 radix_sort_lms_suffixes_32s_2k_block_sort(induction_bucket, cache, block_start, block_size);
2116 place_cached_suffixes(sa, cache, block_start, block_size);
2117}
2118
2119fn radix_sort_lms_suffixes_32s_6k_omp(
2120 t: &[SaSint],
2121 sa: &mut [SaSint],
2122 n: SaSint,
2123 m: SaSint,
2124 induction_bucket: &mut [SaSint],
2125 threads: SaSint,
2126) {
2127 if threads <= 1 || m < 65_536 {
2128 radix_sort_lms_suffixes_32s_6k(t, sa, induction_bucket, n - m + 1, m - 1);
2129 return;
2130 }
2131
2132 let threads_usize = usize::try_from(threads).expect("threads must be positive");
2133 let mut cache = vec![ThreadCache::default(); threads_usize * PER_THREAD_CACHE_SIZE];
2134 let mut block_start = 0usize;
2135 let m_usize = usize::try_from(m).expect("m must be non-negative");
2136 let n_usize = usize::try_from(n).expect("n must be non-negative");
2137 let last = m_usize - 1;
2138
2139 while block_start < last {
2140 let block_end = (block_start + threads_usize * PER_THREAD_CACHE_SIZE).min(last);
2141 radix_sort_lms_suffixes_32s_6k_block_omp(
2142 t,
2143 sa,
2144 induction_bucket,
2145 &mut cache,
2146 (n_usize - block_end) as SaSint,
2147 (block_end - block_start) as SaSint,
2148 threads,
2149 );
2150 block_start = block_end;
2151 }
2152}
2153
2154fn radix_sort_lms_suffixes_32s_2k_omp(
2155 t: &[SaSint],
2156 sa: &mut [SaSint],
2157 n: SaSint,
2158 m: SaSint,
2159 induction_bucket: &mut [SaSint],
2160 threads: SaSint,
2161) {
2162 if threads <= 1 || m < 65_536 {
2163 radix_sort_lms_suffixes_32s_2k(t, sa, induction_bucket, n - m + 1, m - 1);
2164 return;
2165 }
2166
2167 let threads_usize = usize::try_from(threads).expect("threads must be positive");
2168 let mut cache = vec![ThreadCache::default(); threads_usize * PER_THREAD_CACHE_SIZE];
2169 let mut block_start = 0usize;
2170 let m_usize = usize::try_from(m).expect("m must be non-negative");
2171 let n_usize = usize::try_from(n).expect("n must be non-negative");
2172 let last = m_usize - 1;
2173
2174 while block_start < last {
2175 let block_end = (block_start + threads_usize * PER_THREAD_CACHE_SIZE).min(last);
2176 radix_sort_lms_suffixes_32s_2k_block_omp(
2177 t,
2178 sa,
2179 induction_bucket,
2180 &mut cache,
2181 (n_usize - block_end) as SaSint,
2182 (block_end - block_start) as SaSint,
2183 threads,
2184 );
2185 block_start = block_end;
2186 }
2187}
2188
2189fn radix_sort_lms_suffixes_32s_1k(
2190 t: &[SaSint],
2191 sa: &mut [SaSint],
2192 n: SaSint,
2193 buckets: &mut [SaSint],
2194) -> SaSint {
2195 let mut i = n - 2;
2196 let mut m = 0;
2197 let mut f0 = 1usize;
2198 let mut f1: usize;
2199 let mut c0 = t[(n - 1) as usize] as isize;
2200 let mut c1: isize;
2201 let mut c2 = 0isize;
2202
2203 while i >= 64 + 3 {
2204 c1 = t[i as usize] as isize;
2205 f1 = usize::from(c1 > c0 - f0 as isize);
2206 if (f1 & !f0) != 0 {
2207 c2 = c0;
2208 buckets[c2 as usize] -= 1;
2209 sa[buckets[c2 as usize] as usize] = i + 1;
2210 m += 1;
2211 }
2212 c0 = t[(i - 1) as usize] as isize;
2213 f0 = usize::from(c0 > c1 - f1 as isize);
2214 if (f0 & !f1) != 0 {
2215 c2 = c1;
2216 buckets[c2 as usize] -= 1;
2217 sa[buckets[c2 as usize] as usize] = i;
2218 m += 1;
2219 }
2220 c1 = t[(i - 2) as usize] as isize;
2221 f1 = usize::from(c1 > c0 - f0 as isize);
2222 if (f1 & !f0) != 0 {
2223 c2 = c0;
2224 buckets[c2 as usize] -= 1;
2225 sa[buckets[c2 as usize] as usize] = i - 1;
2226 m += 1;
2227 }
2228 c0 = t[(i - 3) as usize] as isize;
2229 f0 = usize::from(c0 > c1 - f1 as isize);
2230 if (f0 & !f1) != 0 {
2231 c2 = c1;
2232 buckets[c2 as usize] -= 1;
2233 sa[buckets[c2 as usize] as usize] = i - 2;
2234 m += 1;
2235 }
2236 i -= 4;
2237 }
2238
2239 while i >= 0 {
2240 c1 = c0;
2241 c0 = t[i as usize] as isize;
2242 f1 = f0;
2243 f0 = usize::from(c0 > c1 - f1 as isize);
2244 if (f0 & !f1) != 0 {
2245 c2 = c1;
2246 buckets[c2 as usize] -= 1;
2247 sa[buckets[c2 as usize] as usize] = i + 1;
2248 m += 1;
2249 }
2250 i -= 1;
2251 }
2252
2253 if m > 1 {
2254 sa[buckets[c2 as usize] as usize] = 0;
2255 }
2256
2257 m
2258}
2259
2260fn radix_sort_set_markers_32s_6k(
2261 sa: &mut [SaSint],
2262 induction_bucket: &[SaSint],
2263 omp_block_start: SaSint,
2264 omp_block_size: SaSint,
2265) {
2266 let mut i = omp_block_start;
2267 let mut j = omp_block_start + omp_block_size - 64 - 3;
2268
2269 while i < j {
2270 sa[induction_bucket[i as usize] as usize] |= SAINT_MIN;
2271 sa[induction_bucket[(i + 1) as usize] as usize] |= SAINT_MIN;
2272 sa[induction_bucket[(i + 2) as usize] as usize] |= SAINT_MIN;
2273 sa[induction_bucket[(i + 3) as usize] as usize] |= SAINT_MIN;
2274 i += 4;
2275 }
2276
2277 j += 64 + 3;
2278 while i < j {
2279 sa[induction_bucket[i as usize] as usize] |= SAINT_MIN;
2280 i += 1;
2281 }
2282}
2283
2284fn radix_sort_set_markers_32s_4k(
2285 sa: &mut [SaSint],
2286 induction_bucket: &[SaSint],
2287 omp_block_start: SaSint,
2288 omp_block_size: SaSint,
2289) {
2290 let mut i = omp_block_start;
2291 let mut j = omp_block_start + omp_block_size - 64 - 3;
2292
2293 while i < j {
2294 sa[induction_bucket[buckets_index2(i as usize, 0)] as usize] |= SUFFIX_GROUP_MARKER;
2295 sa[induction_bucket[buckets_index2((i + 1) as usize, 0)] as usize] |= SUFFIX_GROUP_MARKER;
2296 sa[induction_bucket[buckets_index2((i + 2) as usize, 0)] as usize] |= SUFFIX_GROUP_MARKER;
2297 sa[induction_bucket[buckets_index2((i + 3) as usize, 0)] as usize] |= SUFFIX_GROUP_MARKER;
2298 i += 4;
2299 }
2300
2301 j += 64 + 3;
2302 while i < j {
2303 sa[induction_bucket[buckets_index2(i as usize, 0)] as usize] |= SUFFIX_GROUP_MARKER;
2304 i += 1;
2305 }
2306}
2307
2308fn radix_sort_set_markers_32s_6k_omp(
2309 sa: &mut [SaSint],
2310 k: SaSint,
2311 induction_bucket: &[SaSint],
2312 threads: SaSint,
2313) {
2314 if k <= 1 {
2315 return;
2316 }
2317
2318 if threads <= 1 || k < 65_536 {
2319 radix_sort_set_markers_32s_6k(sa, induction_bucket, 0, k - 1);
2320 return;
2321 }
2322
2323 let threads_usize = usize::try_from(threads).expect("threads must be positive");
2324 let last = usize::try_from(k - 1).expect("k must be positive");
2325 let stride = (last / threads_usize) & !15usize;
2326
2327 {
2328 let sa_ptr = SyncMutPtr::new(sa);
2329 run_rayon_with_threads(threads_usize, || {
2330 (0..threads_usize).into_par_iter().for_each(|thread| {
2331 let start = thread * stride;
2332 let end = if thread + 1 == threads_usize {
2333 last
2334 } else {
2335 start + stride
2336 };
2337 if end > start {
2338 let sa = unsafe { sa_ptr.as_slice() };
2339 radix_sort_set_markers_32s_6k(
2340 sa,
2341 induction_bucket,
2342 start as SaSint,
2343 (end - start) as SaSint,
2344 );
2345 }
2346 });
2347 });
2348 }
2349}
2350
2351fn radix_sort_set_markers_32s_4k_omp(
2352 sa: &mut [SaSint],
2353 k: SaSint,
2354 induction_bucket: &[SaSint],
2355 threads: SaSint,
2356) {
2357 if k <= 1 {
2358 return;
2359 }
2360
2361 if threads <= 1 || k < 65_536 {
2362 radix_sort_set_markers_32s_4k(sa, induction_bucket, 0, k - 1);
2363 return;
2364 }
2365
2366 let threads_usize = usize::try_from(threads).expect("threads must be positive");
2367 let last = usize::try_from(k - 1).expect("k must be positive");
2368 let stride = (last / threads_usize) & !15usize;
2369
2370 {
2371 let sa_ptr = SyncMutPtr::new(sa);
2372 run_rayon_with_threads(threads_usize, || {
2373 (0..threads_usize).into_par_iter().for_each(|thread| {
2374 let start = thread * stride;
2375 let end = if thread + 1 == threads_usize {
2376 last
2377 } else {
2378 start + stride
2379 };
2380 if end > start {
2381 let sa = unsafe { sa_ptr.as_slice() };
2382 radix_sort_set_markers_32s_4k(
2383 sa,
2384 induction_bucket,
2385 start as SaSint,
2386 (end - start) as SaSint,
2387 );
2388 }
2389 });
2390 });
2391 }
2392}
2393
2394fn initialize_buckets_for_partial_sorting_16u(
2395 t: &[u16],
2396 buckets: &mut [SaSint],
2397 first_lms_suffix: SaSint,
2398 left_suffixes_count: SaSint,
2399) {
2400 buckets[buckets_index4(t[first_lms_suffix as usize] as usize, 1)] += 1;
2401
2402 let (front, temp_bucket) = buckets.split_at_mut(4 * ALPHABET_SIZE);
2403 let mut sum0 = left_suffixes_count + 1;
2404 let mut sum1 = 0;
2405
2406 for c in 0..ALPHABET_SIZE {
2407 let i = buckets_index4(c, 0);
2408 let j = buckets_index2(c, 0);
2409
2410 temp_bucket[j + buckets_index2(0, 0)] = sum0;
2411
2412 sum0 += front[i + buckets_index4(0, 0)] + front[i + buckets_index4(0, 2)];
2413 sum1 += front[i + buckets_index4(0, 1)];
2414
2415 front[j + buckets_index2(0, 0)] = sum0;
2416 front[j + buckets_index2(0, 1)] = sum1;
2417 }
2418}
2419
2420fn partial_sorting_shift_markers_32s_6k_omp(
2421 sa: &mut [SaSint],
2422 k: SaSint,
2423 buckets: &[SaSint],
2424 threads: SaSint,
2425) {
2426 let k_usize = usize::try_from(k).expect("k must be non-negative");
2427 let temp_bucket = &buckets[4 * k_usize..];
2428 let thread_count = if threads > 1 && k >= 65536 {
2429 usize::try_from(threads).expect("threads must be positive")
2430 } else {
2431 1
2432 };
2433 let sa_ptr = SyncMutPtr::new(sa);
2434 let buckets_ref: &[SaSint] = buckets;
2435 let temp_bucket_ref: &[SaSint] = temp_bucket;
2436 run_rayon_with_threads(thread_count, || {
2437 (0..thread_count).into_par_iter().for_each(|t| {
2438 let mut c = k_usize as isize - 1 - t as isize;
2439 let sa = unsafe { sa_ptr.as_slice() };
2440 while c >= 1 {
2441 let c_usize = c as usize;
2442 let mut i = buckets_ref[buckets_index4(c_usize, 0)] - 1;
2443 let mut j = temp_bucket_ref[buckets_index2(c_usize - 1, 0)] + 3;
2444 let mut s = SAINT_MIN;
2445
2446 while i >= j {
2447 let p0 = sa[i as usize];
2448 let q0 = (p0 & SAINT_MIN) ^ s;
2449 s ^= q0;
2450 sa[i as usize] = p0 ^ q0;
2451
2452 let p1 = sa[(i - 1) as usize];
2453 let q1 = (p1 & SAINT_MIN) ^ s;
2454 s ^= q1;
2455 sa[(i - 1) as usize] = p1 ^ q1;
2456
2457 let p2 = sa[(i - 2) as usize];
2458 let q2 = (p2 & SAINT_MIN) ^ s;
2459 s ^= q2;
2460 sa[(i - 2) as usize] = p2 ^ q2;
2461
2462 let p3 = sa[(i - 3) as usize];
2463 let q3 = (p3 & SAINT_MIN) ^ s;
2464 s ^= q3;
2465 sa[(i - 3) as usize] = p3 ^ q3;
2466
2467 i -= 4;
2468 }
2469
2470 j -= 3;
2471 while i >= j {
2472 let p = sa[i as usize];
2473 let q = (p & SAINT_MIN) ^ s;
2474 s ^= q;
2475 sa[i as usize] = p ^ q;
2476 i -= 1;
2477 }
2478
2479 c -= thread_count as isize;
2480 }
2481 });
2482 });
2483}
2484
2485fn partial_sorting_shift_markers_32s_4k(sa: &mut [SaSint], n: SaSint) {
2486 let mut i = n - 1;
2487 let mut s = SUFFIX_GROUP_MARKER;
2488
2489 while i >= 3 {
2490 let p0 = sa[i as usize];
2491 let q0 =
2492 ((p0 & SUFFIX_GROUP_MARKER) ^ s) & (((p0 > 0) as SaSint) << (SUFFIX_GROUP_BIT - 1));
2493 s ^= q0;
2494 sa[i as usize] = p0 ^ q0;
2495
2496 let p1 = sa[(i - 1) as usize];
2497 let q1 =
2498 ((p1 & SUFFIX_GROUP_MARKER) ^ s) & (((p1 > 0) as SaSint) << (SUFFIX_GROUP_BIT - 1));
2499 s ^= q1;
2500 sa[(i - 1) as usize] = p1 ^ q1;
2501
2502 let p2 = sa[(i - 2) as usize];
2503 let q2 =
2504 ((p2 & SUFFIX_GROUP_MARKER) ^ s) & (((p2 > 0) as SaSint) << (SUFFIX_GROUP_BIT - 1));
2505 s ^= q2;
2506 sa[(i - 2) as usize] = p2 ^ q2;
2507
2508 let p3 = sa[(i - 3) as usize];
2509 let q3 =
2510 ((p3 & SUFFIX_GROUP_MARKER) ^ s) & (((p3 > 0) as SaSint) << (SUFFIX_GROUP_BIT - 1));
2511 s ^= q3;
2512 sa[(i - 3) as usize] = p3 ^ q3;
2513
2514 i -= 4;
2515 }
2516
2517 while i >= 0 {
2518 let p = sa[i as usize];
2519 let q = ((p & SUFFIX_GROUP_MARKER) ^ s) & (((p > 0) as SaSint) << (SUFFIX_GROUP_BIT - 1));
2520 s ^= q;
2521 sa[i as usize] = p ^ q;
2522 i -= 1;
2523 }
2524}
2525
2526fn partial_sorting_shift_buckets_32s_6k(k: SaSint, buckets: &mut [SaSint]) {
2527 let temp_offset = 4 * k as usize;
2528 let mut i = buckets_index2(0, 0);
2529
2530 while i <= buckets_index2(k as usize - 1, 0) {
2531 buckets[2 * i + buckets_index4(0, 0)] = buckets[temp_offset + i + buckets_index2(0, 0)];
2532 buckets[2 * i + buckets_index4(0, 1)] = buckets[temp_offset + i + buckets_index2(0, 1)];
2533 i += buckets_index2(1, 0);
2534 }
2535}
2536
2537fn partial_sorting_scan_left_to_right_16u(
2538 t: &[u16],
2539 sa: &mut [SaSint],
2540 buckets: &mut [SaSint],
2541 mut d: SaSint,
2542 omp_block_start: SaSint,
2543 omp_block_size: SaSint,
2544) -> SaSint {
2545 let mut i = omp_block_start as isize;
2546 let mut j = (omp_block_start + omp_block_size - 64 - 1) as isize;
2547 while i < j {
2548 let mut p0 = sa[i as usize];
2549 d += SaSint::from(p0 < 0);
2550 p0 &= SAINT_MAX;
2551 let v0 = buckets_index2(
2552 t[(p0 - 1) as usize] as usize,
2553 usize::from(t[(p0 - 2) as usize] >= t[(p0 - 1) as usize]),
2554 );
2555 let mark0 = if buckets[2 * ALPHABET_SIZE + v0] != d {
2556 SAINT_MIN
2557 } else {
2558 0
2559 };
2560 let dst0 = buckets[4 * ALPHABET_SIZE + v0] as usize;
2561 sa[dst0] = (p0 - 1) | mark0;
2562 buckets[4 * ALPHABET_SIZE + v0] += 1;
2563 buckets[2 * ALPHABET_SIZE + v0] = d;
2564
2565 let mut p1 = sa[(i + 1) as usize];
2566 d += SaSint::from(p1 < 0);
2567 p1 &= SAINT_MAX;
2568 let v1 = buckets_index2(
2569 t[(p1 - 1) as usize] as usize,
2570 usize::from(t[(p1 - 2) as usize] >= t[(p1 - 1) as usize]),
2571 );
2572 let mark1 = if buckets[2 * ALPHABET_SIZE + v1] != d {
2573 SAINT_MIN
2574 } else {
2575 0
2576 };
2577 let dst1 = buckets[4 * ALPHABET_SIZE + v1] as usize;
2578 sa[dst1] = (p1 - 1) | mark1;
2579 buckets[4 * ALPHABET_SIZE + v1] += 1;
2580 buckets[2 * ALPHABET_SIZE + v1] = d;
2581
2582 i += 2;
2583 }
2584
2585 j += 64 + 1;
2586 while i < j {
2587 let mut p = sa[i as usize];
2588 d += SaSint::from(p < 0);
2589 p &= SAINT_MAX;
2590 let v = buckets_index2(
2591 t[(p - 1) as usize] as usize,
2592 usize::from(t[(p - 2) as usize] >= t[(p - 1) as usize]),
2593 );
2594 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2595 SAINT_MIN
2596 } else {
2597 0
2598 };
2599 let dst = buckets[4 * ALPHABET_SIZE + v] as usize;
2600 sa[dst] = (p - 1) | mark;
2601 buckets[4 * ALPHABET_SIZE + v] += 1;
2602 buckets[2 * ALPHABET_SIZE + v] = d;
2603 i += 1;
2604 }
2605
2606 d
2607}
2608
2609fn partial_sorting_scan_left_to_right_16u_block_prepare(
2610 t: &[u16],
2611 sa: &mut [SaSint],
2612 k: SaSint,
2613 buckets: &mut [SaSint],
2614 cache: &mut [ThreadCache],
2615 omp_block_start: SaSint,
2616 omp_block_size: SaSint,
2617 state: &mut ThreadState,
2618) -> SaSint {
2619 let width = 2 * k as usize;
2620 buckets[..width].fill(0);
2621 buckets[2 * ALPHABET_SIZE..2 * ALPHABET_SIZE + width].fill(0);
2622
2623 let mut count = 0usize;
2624 let mut d = 1;
2625 for i in omp_block_start as usize..(omp_block_start + omp_block_size) as usize {
2626 let mut p = sa[i];
2627 cache[count].index = p;
2628 d += SaSint::from(p < 0);
2629 p &= SAINT_MAX;
2630 let v = buckets_index2(
2631 t[(p - 1) as usize] as usize,
2632 usize::from(t[(p - 2) as usize] >= t[(p - 1) as usize]),
2633 );
2634 cache[count].symbol = v as SaSint;
2635 buckets[v] += 1;
2636 buckets[2 * ALPHABET_SIZE + v] = d;
2637 count += 1;
2638 }
2639 state.cache_entries = count;
2640 d - 1
2641}
2642
2643fn partial_sorting_scan_left_to_right_16u_block_place(
2644 sa: &mut [SaSint],
2645 buckets: &mut [SaSint],
2646 cache: &[ThreadCache],
2647 count: SaSint,
2648 mut d: SaSint,
2649) {
2650 for entry in cache.iter().take(count as usize) {
2651 let mut p = entry.index;
2652 d += SaSint::from(p < 0);
2653 p &= SAINT_MAX;
2654 let v = entry.symbol as usize;
2655 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2656 SAINT_MIN
2657 } else {
2658 0
2659 };
2660 let dst = buckets[v] as usize;
2661 sa[dst] = (p - 1) | mark;
2662 buckets[v] += 1;
2663 buckets[2 * ALPHABET_SIZE + v] = d;
2664 }
2665}
2666
2667fn partial_sorting_scan_left_to_right_16u_block_omp(
2668 t: &[u16],
2669 sa: &mut [SaSint],
2670 k: SaSint,
2671 buckets: &mut [SaSint],
2672 d: SaSint,
2673 block_start: SaSint,
2674 block_size: SaSint,
2675 threads: SaSint,
2676 thread_state: &mut [ThreadState],
2677) -> SaSint {
2678 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
2679 usize::try_from(threads)
2680 .expect("threads must be non-negative")
2681 .min(thread_state.len())
2682 } else {
2683 1
2684 };
2685 if thread_count <= 1 {
2686 return partial_sorting_scan_left_to_right_16u(t, sa, buckets, d, block_start, block_size);
2687 }
2688
2689 let bucket_width = 2 * k as usize;
2690 let block_stride = (block_size / thread_count as SaSint) & !15;
2691
2692 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
2693 let local_start = thread as SaSint * block_stride;
2694 let local_size = if thread + 1 < thread_count {
2695 block_stride
2696 } else {
2697 block_size - local_start
2698 };
2699 let mut local_state = ThreadState::default();
2700 state.position = partial_sorting_scan_left_to_right_16u_block_prepare(
2701 t,
2702 sa,
2703 k,
2704 &mut state.buckets,
2705 &mut state.cache,
2706 block_start + local_start,
2707 local_size,
2708 &mut local_state,
2709 );
2710 state.count = local_state.cache_entries as SaSint;
2711 }
2712
2713 let mut next_d = d;
2714 for state in thread_state.iter_mut().take(thread_count) {
2715 for c in 0..bucket_width {
2716 let a = buckets[4 * ALPHABET_SIZE + c];
2717 let b = state.buckets[c];
2718 buckets[4 * ALPHABET_SIZE + c] = a + b;
2719 state.buckets[c] = a;
2720 }
2721
2722 next_d -= 1;
2723 for c in 0..bucket_width {
2724 let a = buckets[2 * ALPHABET_SIZE + c];
2725 let b = state.buckets[2 * ALPHABET_SIZE + c];
2726 let shifted = b + next_d;
2727 buckets[2 * ALPHABET_SIZE + c] = if b > 0 { shifted } else { a };
2728 state.buckets[2 * ALPHABET_SIZE + c] = a;
2729 }
2730 next_d += 1 + state.position;
2731 state.position = next_d - state.position;
2732 }
2733
2734 for state in thread_state.iter_mut().take(thread_count) {
2735 partial_sorting_scan_left_to_right_16u_block_place(
2736 sa,
2737 &mut state.buckets,
2738 &state.cache,
2739 state.count,
2740 state.position,
2741 );
2742 }
2743
2744 next_d
2745}
2746
2747fn partial_sorting_scan_left_to_right_16u_omp(
2748 t: &[u16],
2749 sa: &mut [SaSint],
2750 n: SaSint,
2751 k: SaSint,
2752 buckets: &mut [SaSint],
2753 left_suffixes_count: SaSint,
2754 mut d: SaSint,
2755 threads: SaSint,
2756) -> SaSint {
2757 let v = buckets_index2(
2758 t[(n - 1) as usize] as usize,
2759 usize::from(t[(n - 2) as usize] >= t[(n - 1) as usize]),
2760 );
2761 let dst = buckets[4 * ALPHABET_SIZE + v] as usize;
2762 buckets[4 * ALPHABET_SIZE + v] += 1;
2763 sa[dst] = (n - 1) | SAINT_MIN;
2764 d += 1;
2765 buckets[2 * ALPHABET_SIZE + v] = d;
2766
2767 if threads == 1 || left_suffixes_count < 65536 {
2768 d = partial_sorting_scan_left_to_right_16u(t, sa, buckets, d, 0, left_suffixes_count);
2769 } else {
2770 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
2771 let mut block_start = 0;
2772 while block_start < left_suffixes_count {
2773 if sa[block_start as usize] == 0 {
2774 block_start += 1;
2775 } else {
2776 let mut block_end =
2777 block_start + threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
2778 if block_end > left_suffixes_count {
2779 block_end = left_suffixes_count;
2780 }
2781 let mut block_scan_end = block_start + 1;
2782 while block_scan_end < block_end && sa[block_scan_end as usize] != 0 {
2783 block_scan_end += 1;
2784 }
2785 let block_size = block_scan_end - block_start;
2786
2787 if block_size < 32 {
2788 while block_start < block_scan_end {
2789 let mut p = sa[block_start as usize];
2790 d += SaSint::from(p < 0);
2791 p &= SAINT_MAX;
2792 let v = buckets_index2(
2793 t[(p - 1) as usize] as usize,
2794 usize::from(t[(p - 2) as usize] >= t[(p - 1) as usize]),
2795 );
2796 let dst = buckets[4 * ALPHABET_SIZE + v] as usize;
2797 buckets[4 * ALPHABET_SIZE + v] += 1;
2798 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2799 SAINT_MIN
2800 } else {
2801 0
2802 };
2803 sa[dst] = (p - 1) | mark;
2804 buckets[2 * ALPHABET_SIZE + v] = d;
2805 block_start += 1;
2806 }
2807 } else {
2808 d = partial_sorting_scan_left_to_right_16u_block_omp(
2809 t,
2810 sa,
2811 k,
2812 buckets,
2813 d,
2814 block_start,
2815 block_size,
2816 threads,
2817 &mut thread_state,
2818 );
2819 block_start = block_scan_end;
2820 }
2821 }
2822 }
2823 }
2824 d
2825}
2826
2827fn partial_sorting_scan_right_to_left_16u(
2828 t: &[u16],
2829 sa: &mut [SaSint],
2830 buckets: &mut [SaSint],
2831 mut d: SaSint,
2832 omp_block_start: SaSint,
2833 omp_block_size: SaSint,
2834) -> SaSint {
2835 let mut i = (omp_block_start + omp_block_size - 1) as isize;
2836 let mut j = (omp_block_start + 64 + 1) as isize;
2837 while i >= j {
2838 let mut p0 = sa[i as usize];
2839 d += SaSint::from(p0 < 0);
2840 p0 &= SAINT_MAX;
2841 let v0 = buckets_index2(
2842 t[(p0 - 1) as usize] as usize,
2843 usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]),
2844 );
2845 let mark0 = if buckets[2 * ALPHABET_SIZE + v0] != d {
2846 SAINT_MIN
2847 } else {
2848 0
2849 };
2850 buckets[v0] -= 1;
2851 sa[buckets[v0] as usize] = (p0 - 1) | mark0;
2852 buckets[2 * ALPHABET_SIZE + v0] = d;
2853
2854 let mut p1 = sa[(i - 1) as usize];
2855 d += SaSint::from(p1 < 0);
2856 p1 &= SAINT_MAX;
2857 let v1 = buckets_index2(
2858 t[(p1 - 1) as usize] as usize,
2859 usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]),
2860 );
2861 let mark1 = if buckets[2 * ALPHABET_SIZE + v1] != d {
2862 SAINT_MIN
2863 } else {
2864 0
2865 };
2866 buckets[v1] -= 1;
2867 sa[buckets[v1] as usize] = (p1 - 1) | mark1;
2868 buckets[2 * ALPHABET_SIZE + v1] = d;
2869
2870 i -= 2;
2871 }
2872
2873 j -= 64 + 1;
2874 while i >= j {
2875 let mut p = sa[i as usize];
2876 d += SaSint::from(p < 0);
2877 p &= SAINT_MAX;
2878 let v = buckets_index2(
2879 t[(p - 1) as usize] as usize,
2880 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
2881 );
2882 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2883 SAINT_MIN
2884 } else {
2885 0
2886 };
2887 buckets[v] -= 1;
2888 sa[buckets[v] as usize] = (p - 1) | mark;
2889 buckets[2 * ALPHABET_SIZE + v] = d;
2890 i -= 1;
2891 }
2892
2893 d
2894}
2895
2896fn partial_sorting_scan_right_to_left_16u_block_prepare(
2897 t: &[u16],
2898 sa: &mut [SaSint],
2899 k: SaSint,
2900 buckets: &mut [SaSint],
2901 cache: &mut [ThreadCache],
2902 omp_block_start: SaSint,
2903 omp_block_size: SaSint,
2904 state: &mut ThreadState,
2905) -> SaSint {
2906 let width = 2 * k as usize;
2907 buckets[..width].fill(0);
2908 buckets[2 * ALPHABET_SIZE..2 * ALPHABET_SIZE + width].fill(0);
2909
2910 let mut count = 0usize;
2911 let mut d = 1;
2912 for i in (omp_block_start as usize..(omp_block_start + omp_block_size) as usize).rev() {
2913 let mut p = sa[i];
2914 cache[count].index = p;
2915 d += SaSint::from(p < 0);
2916 p &= SAINT_MAX;
2917 let v = buckets_index2(
2918 t[(p - 1) as usize] as usize,
2919 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
2920 );
2921 cache[count].symbol = v as SaSint;
2922 buckets[v] += 1;
2923 buckets[2 * ALPHABET_SIZE + v] = d;
2924 count += 1;
2925 }
2926 state.cache_entries = count;
2927 d - 1
2928}
2929
2930fn partial_sorting_scan_right_to_left_16u_block_place(
2931 sa: &mut [SaSint],
2932 buckets: &mut [SaSint],
2933 cache: &[ThreadCache],
2934 count: SaSint,
2935 mut d: SaSint,
2936) {
2937 for entry in cache.iter().take(count as usize) {
2938 let mut p = entry.index;
2939 d += SaSint::from(p < 0);
2940 p &= SAINT_MAX;
2941 let v = entry.symbol as usize;
2942 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2943 SAINT_MIN
2944 } else {
2945 0
2946 };
2947 buckets[v] -= 1;
2948 sa[buckets[v] as usize] = (p - 1) | mark;
2949 buckets[2 * ALPHABET_SIZE + v] = d;
2950 }
2951}
2952
2953fn partial_gsa_scan_right_to_left_16u_block_place(
2954 sa: &mut [SaSint],
2955 buckets: &mut [SaSint],
2956 cache: &[ThreadCache],
2957 count: SaSint,
2958 mut d: SaSint,
2959) {
2960 for entry in cache.iter().take(count as usize) {
2961 let mut p = entry.index;
2962 d += SaSint::from(p < 0);
2963 p &= SAINT_MAX;
2964 let v = entry.symbol as usize;
2965 if v != 1 {
2966 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
2967 SAINT_MIN
2968 } else {
2969 0
2970 };
2971 buckets[v] -= 1;
2972 sa[buckets[v] as usize] = (p - 1) | mark;
2973 buckets[2 * ALPHABET_SIZE + v] = d;
2974 }
2975 }
2976}
2977
2978fn partial_sorting_scan_right_to_left_16u_block_omp(
2979 t: &[u16],
2980 sa: &mut [SaSint],
2981 k: SaSint,
2982 buckets: &mut [SaSint],
2983 d: SaSint,
2984 block_start: SaSint,
2985 block_size: SaSint,
2986 threads: SaSint,
2987 thread_state: &mut [ThreadState],
2988) -> SaSint {
2989 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
2990 usize::try_from(threads)
2991 .expect("threads must be non-negative")
2992 .min(thread_state.len())
2993 } else {
2994 1
2995 };
2996 if thread_count <= 1 {
2997 return partial_sorting_scan_right_to_left_16u(t, sa, buckets, d, block_start, block_size);
2998 }
2999
3000 let width = 2 * k as usize;
3001 let distinct_offset = 2 * ALPHABET_SIZE;
3002 let block_stride = (block_size / thread_count as SaSint) & !15;
3003
3004 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
3005 let local_start = thread as SaSint * block_stride;
3006 let local_size = if thread + 1 < thread_count {
3007 block_stride
3008 } else {
3009 block_size - local_start
3010 };
3011 let mut local_state = ThreadState::default();
3012 state.position = partial_sorting_scan_right_to_left_16u_block_prepare(
3013 t,
3014 sa,
3015 k,
3016 &mut state.buckets,
3017 &mut state.cache,
3018 block_start + local_start,
3019 local_size,
3020 &mut local_state,
3021 );
3022 state.count = local_state.cache_entries as SaSint;
3023 }
3024
3025 let mut next_d = d;
3026 for state in thread_state.iter_mut().take(thread_count).rev() {
3027 for c in 0..width {
3028 let a = buckets[c];
3029 let b = state.buckets[c];
3030 buckets[c] = a - b;
3031 state.buckets[c] = a;
3032 }
3033
3034 next_d -= 1;
3035 for c in 0..width {
3036 let offset = distinct_offset + c;
3037 let a = buckets[offset];
3038 let b = state.buckets[offset];
3039 let shifted = b + next_d;
3040 buckets[offset] = if b > 0 { shifted } else { a };
3041 state.buckets[offset] = a;
3042 }
3043 next_d += 1 + state.position;
3044 state.position = next_d - state.position;
3045 }
3046
3047 for state in thread_state.iter_mut().take(thread_count) {
3048 partial_sorting_scan_right_to_left_16u_block_place(
3049 sa,
3050 &mut state.buckets,
3051 &state.cache,
3052 state.count,
3053 state.position,
3054 );
3055 }
3056
3057 next_d
3058}
3059
3060fn partial_sorting_scan_right_to_left_16u_omp(
3061 t: &[u16],
3062 sa: &mut [SaSint],
3063 n: SaSint,
3064 k: SaSint,
3065 buckets: &mut [SaSint],
3066 first_lms_suffix: SaSint,
3067 left_suffixes_count: SaSint,
3068 d: SaSint,
3069 threads: SaSint,
3070) {
3071 let scan_start = left_suffixes_count + 1;
3072 let scan_end = n - first_lms_suffix;
3073
3074 if threads == 1 || scan_end - scan_start < 65536 {
3075 partial_sorting_scan_right_to_left_16u(
3076 t,
3077 sa,
3078 buckets,
3079 d,
3080 scan_start,
3081 scan_end - scan_start,
3082 );
3083 } else {
3084 let mut d = d;
3085 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
3086 let mut block_start = scan_end - 1;
3087 while block_start >= scan_start {
3088 if sa[block_start as usize] == 0 {
3089 block_start -= 1;
3090 } else {
3091 let block_limit = threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
3092 let mut block_max_end = block_start - block_limit;
3093 if block_max_end < scan_start {
3094 block_max_end = scan_start - 1;
3095 }
3096 let mut block_end = block_start - 1;
3097 while block_end > block_max_end && sa[block_end as usize] != 0 {
3098 block_end -= 1;
3099 }
3100 let block_size = block_start - block_end;
3101
3102 if block_size < 32 {
3103 while block_start > block_end {
3104 let mut p = sa[block_start as usize];
3105 d += SaSint::from(p < 0);
3106 p &= SAINT_MAX;
3107 let v = buckets_index2(
3108 t[(p - 1) as usize] as usize,
3109 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
3110 );
3111 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
3112 SAINT_MIN
3113 } else {
3114 0
3115 };
3116 buckets[v] -= 1;
3117 sa[buckets[v] as usize] = (p - 1) | mark;
3118 buckets[2 * ALPHABET_SIZE + v] = d;
3119 block_start -= 1;
3120 }
3121 } else {
3122 d = partial_sorting_scan_right_to_left_16u_block_omp(
3123 t,
3124 sa,
3125 k,
3126 buckets,
3127 d,
3128 block_end + 1,
3129 block_size,
3130 threads,
3131 &mut thread_state,
3132 );
3133 block_start = block_end;
3134 }
3135 }
3136 }
3137 }
3138}
3139
3140fn partial_sorting_scan_left_to_right_32s_6k(
3141 t: &[SaSint],
3142 sa: &mut [SaSint],
3143 buckets: &mut [SaSint],
3144 mut d: SaSint,
3145 omp_block_start: SaSint,
3146 omp_block_size: SaSint,
3147) -> SaSint {
3148 let mut i = omp_block_start;
3149 let mut j = omp_block_start + omp_block_size - 2 * 64 - 1;
3150
3151 while i < j {
3152 let mut p2 = sa[i as usize];
3153 d += SaSint::from(p2 < 0);
3154 p2 &= SAINT_MAX;
3155 let v2 = buckets_index4(
3156 t[(p2 - 1) as usize] as usize,
3157 usize::from(t[(p2 - 2) as usize] >= t[(p2 - 1) as usize]),
3158 );
3159 let pos2 = buckets[v2] as usize;
3160 buckets[v2] += 1;
3161 sa[pos2] = (p2 - 1) | (((buckets[2 + v2] != d) as SaSint) << (SAINT_BIT - 1));
3162 buckets[2 + v2] = d;
3163
3164 let mut p3 = sa[(i + 1) as usize];
3165 d += SaSint::from(p3 < 0);
3166 p3 &= SAINT_MAX;
3167 let v3 = buckets_index4(
3168 t[(p3 - 1) as usize] as usize,
3169 usize::from(t[(p3 - 2) as usize] >= t[(p3 - 1) as usize]),
3170 );
3171 let pos3 = buckets[v3] as usize;
3172 buckets[v3] += 1;
3173 sa[pos3] = (p3 - 1) | (((buckets[2 + v3] != d) as SaSint) << (SAINT_BIT - 1));
3174 buckets[2 + v3] = d;
3175
3176 i += 2;
3177 }
3178
3179 j += 2 * 64 + 1;
3180 while i < j {
3181 let mut p = sa[i as usize];
3182 d += SaSint::from(p < 0);
3183 p &= SAINT_MAX;
3184 let v = buckets_index4(
3185 t[(p - 1) as usize] as usize,
3186 usize::from(t[(p - 2) as usize] >= t[(p - 1) as usize]),
3187 );
3188 let pos = buckets[v] as usize;
3189 buckets[v] += 1;
3190 sa[pos] = (p - 1) | (((buckets[2 + v] != d) as SaSint) << (SAINT_BIT - 1));
3191 buckets[2 + v] = d;
3192 i += 1;
3193 }
3194
3195 d
3196}
3197
3198fn partial_sorting_scan_left_to_right_32s_4k(
3199 t: &[SaSint],
3200 sa: &mut [SaSint],
3201 k: SaSint,
3202 buckets: &mut [SaSint],
3203 mut d: SaSint,
3204 omp_block_start: SaSint,
3205 omp_block_size: SaSint,
3206) -> SaSint {
3207 let k = k as usize;
3208 let mut i = omp_block_start;
3209 let mut j = omp_block_start + omp_block_size - 2 * 64 - 1;
3210
3211 while i < j {
3212 let mut p0 = sa[i as usize];
3213 sa[i as usize] = p0 & SAINT_MAX;
3214 if p0 > 0 {
3215 sa[i as usize] = 0;
3216 d += p0 >> (SUFFIX_GROUP_BIT - 1);
3217 p0 &= !SUFFIX_GROUP_MARKER;
3218 let v0 = buckets_index2(
3219 t[(p0 - 1) as usize] as usize,
3220 usize::from(t[(p0 - 2) as usize] < t[(p0 - 1) as usize]),
3221 );
3222 let c0 = t[(p0 - 1) as usize] as usize;
3223 let pos0 = buckets[2 * k + c0] as usize;
3224 buckets[2 * k + c0] += 1;
3225 sa[pos0] = (p0 - 1)
3226 | ((usize::from(t[(p0 - 2) as usize] < t[(p0 - 1) as usize]) as SaSint)
3227 << (SAINT_BIT - 1))
3228 | (((buckets[v0] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3229 buckets[v0] = d;
3230 }
3231
3232 let mut p1 = sa[(i + 1) as usize];
3233 sa[(i + 1) as usize] = p1 & SAINT_MAX;
3234 if p1 > 0 {
3235 sa[(i + 1) as usize] = 0;
3236 d += p1 >> (SUFFIX_GROUP_BIT - 1);
3237 p1 &= !SUFFIX_GROUP_MARKER;
3238 let v1 = buckets_index2(
3239 t[(p1 - 1) as usize] as usize,
3240 usize::from(t[(p1 - 2) as usize] < t[(p1 - 1) as usize]),
3241 );
3242 let c1 = t[(p1 - 1) as usize] as usize;
3243 let pos1 = buckets[2 * k + c1] as usize;
3244 buckets[2 * k + c1] += 1;
3245 sa[pos1] = (p1 - 1)
3246 | ((usize::from(t[(p1 - 2) as usize] < t[(p1 - 1) as usize]) as SaSint)
3247 << (SAINT_BIT - 1))
3248 | (((buckets[v1] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3249 buckets[v1] = d;
3250 }
3251
3252 i += 2;
3253 }
3254
3255 j += 2 * 64 + 1;
3256 while i < j {
3257 let mut p = sa[i as usize];
3258 sa[i as usize] = p & SAINT_MAX;
3259 if p > 0 {
3260 sa[i as usize] = 0;
3261 d += p >> (SUFFIX_GROUP_BIT - 1);
3262 p &= !SUFFIX_GROUP_MARKER;
3263 let v = buckets_index2(
3264 t[(p - 1) as usize] as usize,
3265 usize::from(t[(p - 2) as usize] < t[(p - 1) as usize]),
3266 );
3267 let c = t[(p - 1) as usize] as usize;
3268 let pos = buckets[2 * k + c] as usize;
3269 buckets[2 * k + c] += 1;
3270 sa[pos] = (p - 1)
3271 | ((usize::from(t[(p - 2) as usize] < t[(p - 1) as usize]) as SaSint)
3272 << (SAINT_BIT - 1))
3273 | (((buckets[v] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3274 buckets[v] = d;
3275 }
3276 i += 1;
3277 }
3278
3279 d
3280}
3281
3282fn partial_sorting_scan_left_to_right_32s_1k(
3283 t: &[SaSint],
3284 sa: &mut [SaSint],
3285 induction_bucket: &mut [SaSint],
3286 omp_block_start: SaSint,
3287 omp_block_size: SaSint,
3288) {
3289 let mut i = omp_block_start;
3290 let mut j = omp_block_start + omp_block_size - 2 * 64 - 1;
3291
3292 while i < j {
3293 let p0 = sa[i as usize];
3294 sa[i as usize] = p0 & SAINT_MAX;
3295 if p0 > 0 {
3296 sa[i as usize] = 0;
3297 let c0 = t[(p0 - 1) as usize] as usize;
3298 let pos0 = induction_bucket[c0] as usize;
3299 induction_bucket[c0] += 1;
3300 sa[pos0] = (p0 - 1)
3301 | ((usize::from(t[(p0 - 2) as usize] < t[(p0 - 1) as usize]) as SaSint)
3302 << (SAINT_BIT - 1));
3303 }
3304
3305 let p1 = sa[(i + 1) as usize];
3306 sa[(i + 1) as usize] = p1 & SAINT_MAX;
3307 if p1 > 0 {
3308 sa[(i + 1) as usize] = 0;
3309 let c1 = t[(p1 - 1) as usize] as usize;
3310 let pos1 = induction_bucket[c1] as usize;
3311 induction_bucket[c1] += 1;
3312 sa[pos1] = (p1 - 1)
3313 | ((usize::from(t[(p1 - 2) as usize] < t[(p1 - 1) as usize]) as SaSint)
3314 << (SAINT_BIT - 1));
3315 }
3316
3317 i += 2;
3318 }
3319
3320 j += 2 * 64 + 1;
3321 while i < j {
3322 let p = sa[i as usize];
3323 sa[i as usize] = p & SAINT_MAX;
3324 if p > 0 {
3325 sa[i as usize] = 0;
3326 let c = t[(p - 1) as usize] as usize;
3327 let pos = induction_bucket[c] as usize;
3328 induction_bucket[c] += 1;
3329 sa[pos] = (p - 1)
3330 | ((usize::from(t[(p - 2) as usize] < t[(p - 1) as usize]) as SaSint)
3331 << (SAINT_BIT - 1));
3332 }
3333 i += 1;
3334 }
3335}
3336
3337fn partial_sorting_scan_left_to_right_32s_6k_omp(
3338 t: &[SaSint],
3339 sa: &mut [SaSint],
3340 n: SaSint,
3341 buckets: &mut [SaSint],
3342 left_suffixes_count: SaSint,
3343 mut d: SaSint,
3344 threads: SaSint,
3345 _thread_state: &mut [ThreadState],
3346) -> SaSint {
3347 let v = buckets_index4(
3348 t[(n - 1) as usize] as usize,
3349 usize::from(t[(n - 2) as usize] >= t[(n - 1) as usize]),
3350 );
3351 let pos = buckets[v] as usize;
3352 buckets[v] += 1;
3353 sa[pos] = (n - 1) | SAINT_MIN;
3354 d += 1;
3355 buckets[2 + v] = d;
3356
3357 if threads == 1 || left_suffixes_count < 65536 {
3358 d = partial_sorting_scan_left_to_right_32s_6k(t, sa, buckets, d, 0, left_suffixes_count);
3359 } else {
3360 let mut cache = vec![ThreadCache::default(); left_suffixes_count as usize];
3361 let mut block_start = 0;
3362 while block_start < left_suffixes_count {
3363 let mut block_end = block_start + threads * PER_THREAD_CACHE_SIZE as SaSint;
3364 if block_end > left_suffixes_count {
3365 block_end = left_suffixes_count;
3366 }
3367 d = partial_sorting_scan_left_to_right_32s_6k_block_omp(
3368 t,
3369 sa,
3370 buckets,
3371 d,
3372 &mut cache,
3373 block_start,
3374 block_end - block_start,
3375 threads,
3376 );
3377 block_start = block_end;
3378 }
3379 }
3380
3381 d
3382}
3383
3384fn partial_sorting_scan_left_to_right_32s_4k_omp(
3385 t: &[SaSint],
3386 sa: &mut [SaSint],
3387 n: SaSint,
3388 k: SaSint,
3389 buckets: &mut [SaSint],
3390 mut d: SaSint,
3391 threads: SaSint,
3392 _thread_state: &mut [ThreadState],
3393) -> SaSint {
3394 let k_usize = k as usize;
3395 let pos = buckets[2 * k_usize + t[(n - 1) as usize] as usize] as usize;
3396 buckets[2 * k_usize + t[(n - 1) as usize] as usize] += 1;
3397 sa[pos] = (n - 1)
3398 | ((usize::from(t[(n - 2) as usize] < t[(n - 1) as usize]) as SaSint) << (SAINT_BIT - 1))
3399 | SUFFIX_GROUP_MARKER;
3400 d += 1;
3401 buckets[buckets_index2(
3402 t[(n - 1) as usize] as usize,
3403 usize::from(t[(n - 2) as usize] < t[(n - 1) as usize]),
3404 )] = d;
3405
3406 if threads == 1 || n < 65536 {
3407 d = partial_sorting_scan_left_to_right_32s_4k(t, sa, k, buckets, d, 0, n);
3408 } else {
3409 let mut cache = vec![ThreadCache::default(); n as usize];
3410 let mut block_start = 0;
3411 while block_start < n {
3412 let mut block_end = block_start + threads * PER_THREAD_CACHE_SIZE as SaSint;
3413 if block_end > n {
3414 block_end = n;
3415 }
3416 d = partial_sorting_scan_left_to_right_32s_4k_block_omp(
3417 t,
3418 sa,
3419 k,
3420 buckets,
3421 d,
3422 &mut cache,
3423 block_start,
3424 block_end - block_start,
3425 threads,
3426 );
3427 block_start = block_end;
3428 }
3429 }
3430
3431 d
3432}
3433
3434fn partial_sorting_scan_left_to_right_32s_1k_omp(
3435 t: &[SaSint],
3436 sa: &mut [SaSint],
3437 n: SaSint,
3438 buckets: &mut [SaSint],
3439 threads: SaSint,
3440 _thread_state: &mut [ThreadState],
3441) {
3442 let pos = buckets[t[(n - 1) as usize] as usize] as usize;
3443 buckets[t[(n - 1) as usize] as usize] += 1;
3444 sa[pos] = (n - 1)
3445 | ((usize::from(t[(n - 2) as usize] < t[(n - 1) as usize]) as SaSint) << (SAINT_BIT - 1));
3446
3447 if threads == 1 || n < 65536 {
3448 partial_sorting_scan_left_to_right_32s_1k(t, sa, buckets, 0, n);
3449 } else {
3450 let mut cache = vec![ThreadCache::default(); n as usize];
3451 let mut block_start = 0;
3452 while block_start < n {
3453 let mut block_end = block_start + threads * PER_THREAD_CACHE_SIZE as SaSint;
3454 if block_end > n {
3455 block_end = n;
3456 }
3457 partial_sorting_scan_left_to_right_32s_1k_block_omp(
3458 t,
3459 sa,
3460 buckets,
3461 &mut cache,
3462 block_start,
3463 block_end - block_start,
3464 threads,
3465 );
3466 block_start = block_end;
3467 }
3468 }
3469}
3470
3471fn partial_sorting_scan_right_to_left_32s_6k(
3472 t: &[SaSint],
3473 sa: &mut [SaSint],
3474 buckets: &mut [SaSint],
3475 mut d: SaSint,
3476 omp_block_start: SaSint,
3477 omp_block_size: SaSint,
3478) -> SaSint {
3479 if omp_block_size <= 0 {
3480 return d;
3481 }
3482
3483 let mut i = omp_block_start + omp_block_size - 1;
3484 let mut j = omp_block_start + 2 * 64 + 1;
3485
3486 while i >= j {
3487 let mut p2 = sa[i as usize];
3488 d += SaSint::from(p2 < 0);
3489 p2 &= SAINT_MAX;
3490 let v2 = buckets_index4(
3491 t[(p2 - 1) as usize] as usize,
3492 usize::from(t[(p2 - 2) as usize] > t[(p2 - 1) as usize]),
3493 );
3494 buckets[v2] -= 1;
3495 sa[buckets[v2] as usize] =
3496 (p2 - 1) | (((buckets[2 + v2] != d) as SaSint) << (SAINT_BIT - 1));
3497 buckets[2 + v2] = d;
3498
3499 let mut p3 = sa[(i - 1) as usize];
3500 d += SaSint::from(p3 < 0);
3501 p3 &= SAINT_MAX;
3502 let v3 = buckets_index4(
3503 t[(p3 - 1) as usize] as usize,
3504 usize::from(t[(p3 - 2) as usize] > t[(p3 - 1) as usize]),
3505 );
3506 buckets[v3] -= 1;
3507 sa[buckets[v3] as usize] =
3508 (p3 - 1) | (((buckets[2 + v3] != d) as SaSint) << (SAINT_BIT - 1));
3509 buckets[2 + v3] = d;
3510
3511 i -= 2;
3512 }
3513
3514 j -= 2 * 64 + 1;
3515 while i >= j {
3516 let mut p = sa[i as usize];
3517 d += SaSint::from(p < 0);
3518 p &= SAINT_MAX;
3519 let v = buckets_index4(
3520 t[(p - 1) as usize] as usize,
3521 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
3522 );
3523 buckets[v] -= 1;
3524 sa[buckets[v] as usize] = (p - 1) | (((buckets[2 + v] != d) as SaSint) << (SAINT_BIT - 1));
3525 buckets[2 + v] = d;
3526 i -= 1;
3527 }
3528
3529 d
3530}
3531
3532fn partial_sorting_scan_right_to_left_32s_4k(
3533 t: &[SaSint],
3534 sa: &mut [SaSint],
3535 k: SaSint,
3536 buckets: &mut [SaSint],
3537 mut d: SaSint,
3538 omp_block_start: SaSint,
3539 omp_block_size: SaSint,
3540) -> SaSint {
3541 if omp_block_size <= 0 {
3542 return d;
3543 }
3544
3545 let k = k as usize;
3546 let mut i = omp_block_start + omp_block_size - 1;
3547 let mut j = omp_block_start + 2 * 64 + 1;
3548
3549 while i >= j {
3550 let mut p0 = sa[i as usize];
3551 if p0 > 0 {
3552 sa[i as usize] = 0;
3553 d += p0 >> (SUFFIX_GROUP_BIT - 1);
3554 p0 &= !SUFFIX_GROUP_MARKER;
3555 let v0 = buckets_index2(
3556 t[(p0 - 1) as usize] as usize,
3557 usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]),
3558 );
3559 let c0 = t[(p0 - 1) as usize] as usize;
3560 buckets[3 * k + c0] -= 1;
3561 sa[buckets[3 * k + c0] as usize] = (p0 - 1)
3562 | ((usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]) as SaSint)
3563 << (SAINT_BIT - 1))
3564 | (((buckets[v0] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3565 buckets[v0] = d;
3566 }
3567
3568 let mut p1 = sa[(i - 1) as usize];
3569 if p1 > 0 {
3570 sa[(i - 1) as usize] = 0;
3571 d += p1 >> (SUFFIX_GROUP_BIT - 1);
3572 p1 &= !SUFFIX_GROUP_MARKER;
3573 let v1 = buckets_index2(
3574 t[(p1 - 1) as usize] as usize,
3575 usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]),
3576 );
3577 let c1 = t[(p1 - 1) as usize] as usize;
3578 buckets[3 * k + c1] -= 1;
3579 sa[buckets[3 * k + c1] as usize] = (p1 - 1)
3580 | ((usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]) as SaSint)
3581 << (SAINT_BIT - 1))
3582 | (((buckets[v1] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3583 buckets[v1] = d;
3584 }
3585
3586 i -= 2;
3587 }
3588
3589 j -= 2 * 64 + 1;
3590 while i >= j {
3591 let mut p = sa[i as usize];
3592 if p > 0 {
3593 sa[i as usize] = 0;
3594 d += p >> (SUFFIX_GROUP_BIT - 1);
3595 p &= !SUFFIX_GROUP_MARKER;
3596 let v = buckets_index2(
3597 t[(p - 1) as usize] as usize,
3598 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
3599 );
3600 let c = t[(p - 1) as usize] as usize;
3601 buckets[3 * k + c] -= 1;
3602 sa[buckets[3 * k + c] as usize] = (p - 1)
3603 | ((usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]) as SaSint)
3604 << (SAINT_BIT - 1))
3605 | (((buckets[v] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
3606 buckets[v] = d;
3607 }
3608 i -= 1;
3609 }
3610
3611 d
3612}
3613
3614fn partial_sorting_scan_right_to_left_32s_1k(
3615 t: &[SaSint],
3616 sa: &mut [SaSint],
3617 induction_bucket: &mut [SaSint],
3618 omp_block_start: SaSint,
3619 omp_block_size: SaSint,
3620) {
3621 if omp_block_size <= 0 {
3622 return;
3623 }
3624
3625 let mut i = omp_block_start + omp_block_size - 1;
3626 let mut j = omp_block_start + 2 * 64 + 1;
3627
3628 while i >= j {
3629 let p0 = sa[i as usize];
3630 if p0 > 0 {
3631 sa[i as usize] = 0;
3632 let c0 = t[(p0 - 1) as usize] as usize;
3633 induction_bucket[c0] -= 1;
3634 sa[induction_bucket[c0] as usize] = (p0 - 1)
3635 | ((usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]) as SaSint)
3636 << (SAINT_BIT - 1));
3637 }
3638
3639 let p1 = sa[(i - 1) as usize];
3640 if p1 > 0 {
3641 sa[(i - 1) as usize] = 0;
3642 let c1 = t[(p1 - 1) as usize] as usize;
3643 induction_bucket[c1] -= 1;
3644 sa[induction_bucket[c1] as usize] = (p1 - 1)
3645 | ((usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]) as SaSint)
3646 << (SAINT_BIT - 1));
3647 }
3648
3649 i -= 2;
3650 }
3651
3652 j -= 2 * 64 + 1;
3653 while i >= j {
3654 let p = sa[i as usize];
3655 if p > 0 {
3656 sa[i as usize] = 0;
3657 let c = t[(p - 1) as usize] as usize;
3658 induction_bucket[c] -= 1;
3659 sa[induction_bucket[c] as usize] = (p - 1)
3660 | ((usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]) as SaSint)
3661 << (SAINT_BIT - 1));
3662 }
3663 i -= 1;
3664 }
3665}
3666
3667fn partial_sorting_scan_right_to_left_32s_6k_omp(
3668 t: &[SaSint],
3669 sa: &mut [SaSint],
3670 n: SaSint,
3671 buckets: &mut [SaSint],
3672 first_lms_suffix: SaSint,
3673 left_suffixes_count: SaSint,
3674 mut d: SaSint,
3675 threads: SaSint,
3676 _thread_state: &mut [ThreadState],
3677) -> SaSint {
3678 let scan_start = left_suffixes_count + 1;
3679 let scan_end = n - first_lms_suffix;
3680
3681 if threads == 1 || scan_end - scan_start < 65536 {
3682 d = partial_sorting_scan_right_to_left_32s_6k(
3683 t,
3684 sa,
3685 buckets,
3686 d,
3687 scan_start,
3688 scan_end - scan_start,
3689 );
3690 } else {
3691 let mut cache = vec![ThreadCache::default(); (scan_end - scan_start) as usize];
3692 let mut block_start = scan_end;
3693 while block_start > scan_start {
3694 let block_size =
3695 (block_start - scan_start).min(threads * PER_THREAD_CACHE_SIZE as SaSint);
3696 block_start -= block_size;
3697 d = partial_sorting_scan_right_to_left_32s_6k_block_omp(
3698 t,
3699 sa,
3700 buckets,
3701 d,
3702 &mut cache,
3703 block_start,
3704 block_size,
3705 threads,
3706 );
3707 }
3708 }
3709
3710 d
3711}
3712
3713fn partial_sorting_scan_right_to_left_32s_4k_omp(
3714 t: &[SaSint],
3715 sa: &mut [SaSint],
3716 n: SaSint,
3717 k: SaSint,
3718 buckets: &mut [SaSint],
3719 mut d: SaSint,
3720 threads: SaSint,
3721 _thread_state: &mut [ThreadState],
3722) -> SaSint {
3723 if threads == 1 || n < 65536 {
3724 d = partial_sorting_scan_right_to_left_32s_4k(t, sa, k, buckets, d, 0, n);
3725 } else {
3726 let mut cache = vec![ThreadCache::default(); n as usize];
3727 let mut block_start = n;
3728 while block_start > 0 {
3729 let block_size = block_start.min(threads * PER_THREAD_CACHE_SIZE as SaSint);
3730 block_start -= block_size;
3731 d = partial_sorting_scan_right_to_left_32s_4k_block_omp(
3732 t,
3733 sa,
3734 k,
3735 buckets,
3736 d,
3737 &mut cache,
3738 block_start,
3739 block_size,
3740 threads,
3741 );
3742 }
3743 }
3744
3745 d
3746}
3747
3748fn partial_sorting_scan_right_to_left_32s_1k_omp(
3749 t: &[SaSint],
3750 sa: &mut [SaSint],
3751 n: SaSint,
3752 buckets: &mut [SaSint],
3753 threads: SaSint,
3754 _thread_state: &mut [ThreadState],
3755) {
3756 if threads == 1 || n < 65536 {
3757 partial_sorting_scan_right_to_left_32s_1k(t, sa, buckets, 0, n);
3758 } else {
3759 let mut cache = vec![ThreadCache::default(); n as usize];
3760 let mut block_start = n;
3761 while block_start > 0 {
3762 let block_size = block_start.min(threads * PER_THREAD_CACHE_SIZE as SaSint);
3763 block_start -= block_size;
3764 partial_sorting_scan_right_to_left_32s_1k_block_omp(
3765 t,
3766 sa,
3767 buckets,
3768 &mut cache,
3769 block_start,
3770 block_size,
3771 threads,
3772 );
3773 }
3774 }
3775}
3776
3777fn partial_sorting_scan_left_to_right_32s_6k_block_gather(
3778 t: &[SaSint],
3779 sa: &mut [SaSint],
3780 cache: &mut [ThreadCache],
3781 omp_block_start: SaSint,
3782 omp_block_size: SaSint,
3783) {
3784 let mut i = omp_block_start;
3785 let mut j = omp_block_start + omp_block_size - 64 - 1;
3786
3787 while i < j {
3788 let p0 = sa[i as usize];
3789 cache[i as usize].index = p0;
3790 let p0 = p0 & SAINT_MAX;
3791 cache[i as usize].symbol = if p0 != 0 {
3792 buckets_index4(
3793 t[(p0 - 1) as usize] as usize,
3794 usize::from(t[(p0 - 2) as usize] >= t[(p0 - 1) as usize]),
3795 ) as SaSint
3796 } else {
3797 0
3798 };
3799
3800 let p1 = sa[(i + 1) as usize];
3801 cache[(i + 1) as usize].index = p1;
3802 let p1 = p1 & SAINT_MAX;
3803 cache[(i + 1) as usize].symbol = if p1 != 0 {
3804 buckets_index4(
3805 t[(p1 - 1) as usize] as usize,
3806 usize::from(t[(p1 - 2) as usize] >= t[(p1 - 1) as usize]),
3807 ) as SaSint
3808 } else {
3809 0
3810 };
3811
3812 i += 2;
3813 }
3814
3815 j += 64 + 1;
3816 while i < j {
3817 let p = sa[i as usize];
3818 cache[i as usize].index = p;
3819 let p = p & SAINT_MAX;
3820 cache[i as usize].symbol = if p != 0 {
3821 buckets_index4(
3822 t[(p - 1) as usize] as usize,
3823 usize::from(t[(p - 2) as usize] >= t[(p - 1) as usize]),
3824 ) as SaSint
3825 } else {
3826 0
3827 };
3828 i += 1;
3829 }
3830}
3831
3832fn partial_sorting_scan_left_to_right_32s_4k_block_gather(
3833 t: &[SaSint],
3834 sa: &mut [SaSint],
3835 cache: &mut [ThreadCache],
3836 omp_block_start: SaSint,
3837 omp_block_size: SaSint,
3838) {
3839 let mut i = omp_block_start;
3840 let mut j = omp_block_start + omp_block_size - 64 - 1;
3841
3842 while i < j {
3843 let mut symbol0 = SAINT_MIN;
3844 let mut p0 = sa[i as usize];
3845 if p0 > 0 {
3846 cache[i as usize].index = p0;
3847 p0 &= !SUFFIX_GROUP_MARKER;
3848 symbol0 = buckets_index2(
3849 t[(p0 - 1) as usize] as usize,
3850 usize::from(t[(p0 - 2) as usize] < t[(p0 - 1) as usize]),
3851 ) as SaSint;
3852 p0 = 0;
3853 }
3854 cache[i as usize].symbol = symbol0;
3855 sa[i as usize] = p0 & SAINT_MAX;
3856
3857 let mut symbol1 = SAINT_MIN;
3858 let mut p1 = sa[(i + 1) as usize];
3859 if p1 > 0 {
3860 cache[(i + 1) as usize].index = p1;
3861 p1 &= !SUFFIX_GROUP_MARKER;
3862 symbol1 = buckets_index2(
3863 t[(p1 - 1) as usize] as usize,
3864 usize::from(t[(p1 - 2) as usize] < t[(p1 - 1) as usize]),
3865 ) as SaSint;
3866 p1 = 0;
3867 }
3868 cache[(i + 1) as usize].symbol = symbol1;
3869 sa[(i + 1) as usize] = p1 & SAINT_MAX;
3870
3871 i += 2;
3872 }
3873
3874 j += 64 + 1;
3875 while i < j {
3876 let mut symbol = SAINT_MIN;
3877 let mut p = sa[i as usize];
3878 if p > 0 {
3879 cache[i as usize].index = p;
3880 p &= !SUFFIX_GROUP_MARKER;
3881 symbol = buckets_index2(
3882 t[(p - 1) as usize] as usize,
3883 usize::from(t[(p - 2) as usize] < t[(p - 1) as usize]),
3884 ) as SaSint;
3885 p = 0;
3886 }
3887 cache[i as usize].symbol = symbol;
3888 sa[i as usize] = p & SAINT_MAX;
3889 i += 1;
3890 }
3891}
3892
3893fn partial_sorting_scan_left_to_right_32s_1k_block_gather(
3894 t: &[SaSint],
3895 sa: &mut [SaSint],
3896 cache: &mut [ThreadCache],
3897 omp_block_start: SaSint,
3898 omp_block_size: SaSint,
3899) {
3900 let mut i = omp_block_start;
3901 let mut j = omp_block_start + omp_block_size - 64 - 1;
3902
3903 while i < j {
3904 let mut symbol0 = SAINT_MIN;
3905 let mut p0 = sa[i as usize];
3906 if p0 > 0 {
3907 cache[i as usize].index = (p0 - 1)
3908 | ((usize::from(t[(p0 - 2) as usize] < t[(p0 - 1) as usize]) as SaSint)
3909 << (SAINT_BIT - 1));
3910 symbol0 = t[(p0 - 1) as usize];
3911 p0 = 0;
3912 }
3913 cache[i as usize].symbol = symbol0;
3914 sa[i as usize] = p0 & SAINT_MAX;
3915
3916 let mut symbol1 = SAINT_MIN;
3917 let mut p1 = sa[(i + 1) as usize];
3918 if p1 > 0 {
3919 cache[(i + 1) as usize].index = (p1 - 1)
3920 | ((usize::from(t[(p1 - 2) as usize] < t[(p1 - 1) as usize]) as SaSint)
3921 << (SAINT_BIT - 1));
3922 symbol1 = t[(p1 - 1) as usize];
3923 p1 = 0;
3924 }
3925 cache[(i + 1) as usize].symbol = symbol1;
3926 sa[(i + 1) as usize] = p1 & SAINT_MAX;
3927
3928 i += 2;
3929 }
3930
3931 j += 64 + 1;
3932 while i < j {
3933 let mut symbol = SAINT_MIN;
3934 let mut p = sa[i as usize];
3935 if p > 0 {
3936 cache[i as usize].index = (p - 1)
3937 | ((usize::from(t[(p - 2) as usize] < t[(p - 1) as usize]) as SaSint)
3938 << (SAINT_BIT - 1));
3939 symbol = t[(p - 1) as usize];
3940 p = 0;
3941 }
3942 cache[i as usize].symbol = symbol;
3943 sa[i as usize] = p & SAINT_MAX;
3944 i += 1;
3945 }
3946}
3947
3948fn partial_sorting_scan_right_to_left_32s_6k_block_gather(
3949 t: &[SaSint],
3950 sa: &mut [SaSint],
3951 cache: &mut [ThreadCache],
3952 omp_block_start: SaSint,
3953 omp_block_size: SaSint,
3954) {
3955 let mut i = omp_block_start;
3956 let mut j = omp_block_start + omp_block_size - 64 - 1;
3957
3958 while i < j {
3959 let p0 = sa[i as usize];
3960 cache[i as usize].index = p0;
3961 let p0 = p0 & SAINT_MAX;
3962 cache[i as usize].symbol = if p0 != 0 {
3963 buckets_index4(
3964 t[(p0 - 1) as usize] as usize,
3965 usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]),
3966 ) as SaSint
3967 } else {
3968 0
3969 };
3970
3971 let p1 = sa[(i + 1) as usize];
3972 cache[(i + 1) as usize].index = p1;
3973 let p1 = p1 & SAINT_MAX;
3974 cache[(i + 1) as usize].symbol = if p1 != 0 {
3975 buckets_index4(
3976 t[(p1 - 1) as usize] as usize,
3977 usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]),
3978 ) as SaSint
3979 } else {
3980 0
3981 };
3982
3983 i += 2;
3984 }
3985
3986 j += 64 + 1;
3987 while i < j {
3988 let p = sa[i as usize];
3989 cache[i as usize].index = p;
3990 let p = p & SAINT_MAX;
3991 cache[i as usize].symbol = if p != 0 {
3992 buckets_index4(
3993 t[(p - 1) as usize] as usize,
3994 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
3995 ) as SaSint
3996 } else {
3997 0
3998 };
3999 i += 1;
4000 }
4001}
4002
4003fn partial_sorting_scan_right_to_left_32s_4k_block_gather(
4004 t: &[SaSint],
4005 sa: &mut [SaSint],
4006 cache: &mut [ThreadCache],
4007 omp_block_start: SaSint,
4008 omp_block_size: SaSint,
4009) {
4010 let mut i = omp_block_start;
4011 let mut j = omp_block_start + omp_block_size - 64 - 1;
4012
4013 while i < j {
4014 let mut symbol0 = SAINT_MIN;
4015 let mut p0 = sa[i as usize];
4016 if p0 > 0 {
4017 sa[i as usize] = 0;
4018 cache[i as usize].index = p0;
4019 p0 &= !SUFFIX_GROUP_MARKER;
4020 symbol0 = buckets_index2(
4021 t[(p0 - 1) as usize] as usize,
4022 usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]),
4023 ) as SaSint;
4024 }
4025 cache[i as usize].symbol = symbol0;
4026
4027 let mut symbol1 = SAINT_MIN;
4028 let mut p1 = sa[(i + 1) as usize];
4029 if p1 > 0 {
4030 sa[(i + 1) as usize] = 0;
4031 cache[(i + 1) as usize].index = p1;
4032 p1 &= !SUFFIX_GROUP_MARKER;
4033 symbol1 = buckets_index2(
4034 t[(p1 - 1) as usize] as usize,
4035 usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]),
4036 ) as SaSint;
4037 }
4038 cache[(i + 1) as usize].symbol = symbol1;
4039
4040 i += 2;
4041 }
4042
4043 j += 64 + 1;
4044 while i < j {
4045 let mut symbol = SAINT_MIN;
4046 let mut p = sa[i as usize];
4047 if p > 0 {
4048 sa[i as usize] = 0;
4049 cache[i as usize].index = p;
4050 p &= !SUFFIX_GROUP_MARKER;
4051 symbol = buckets_index2(
4052 t[(p - 1) as usize] as usize,
4053 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
4054 ) as SaSint;
4055 }
4056 cache[i as usize].symbol = symbol;
4057 i += 1;
4058 }
4059}
4060
4061fn partial_sorting_scan_right_to_left_32s_1k_block_gather(
4062 t: &[SaSint],
4063 sa: &mut [SaSint],
4064 cache: &mut [ThreadCache],
4065 omp_block_start: SaSint,
4066 omp_block_size: SaSint,
4067) {
4068 let mut i = omp_block_start;
4069 let mut j = omp_block_start + omp_block_size - 64 - 1;
4070
4071 while i < j {
4072 let mut symbol0 = SAINT_MIN;
4073 let p0 = sa[i as usize];
4074 if p0 > 0 {
4075 sa[i as usize] = 0;
4076 cache[i as usize].index = (p0 - 1)
4077 | ((usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]) as SaSint)
4078 << (SAINT_BIT - 1));
4079 symbol0 = t[(p0 - 1) as usize];
4080 }
4081 cache[i as usize].symbol = symbol0;
4082
4083 let mut symbol1 = SAINT_MIN;
4084 let p1 = sa[(i + 1) as usize];
4085 if p1 > 0 {
4086 sa[(i + 1) as usize] = 0;
4087 cache[(i + 1) as usize].index = (p1 - 1)
4088 | ((usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]) as SaSint)
4089 << (SAINT_BIT - 1));
4090 symbol1 = t[(p1 - 1) as usize];
4091 }
4092 cache[(i + 1) as usize].symbol = symbol1;
4093
4094 i += 2;
4095 }
4096
4097 j += 64 + 1;
4098 while i < j {
4099 let mut symbol = SAINT_MIN;
4100 let p = sa[i as usize];
4101 if p > 0 {
4102 sa[i as usize] = 0;
4103 cache[i as usize].index = (p - 1)
4104 | ((usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]) as SaSint)
4105 << (SAINT_BIT - 1));
4106 symbol = t[(p - 1) as usize];
4107 }
4108 cache[i as usize].symbol = symbol;
4109 i += 1;
4110 }
4111}
4112
4113fn partial_sorting_scan_left_to_right_32s_6k_block_sort(
4114 t: &[SaSint],
4115 buckets: &mut [SaSint],
4116 mut d: SaSint,
4117 cache: &mut [ThreadCache],
4118 omp_block_start: SaSint,
4119 omp_block_size: SaSint,
4120) -> SaSint {
4121 let mut i = omp_block_start;
4122 let omp_block_end = omp_block_start + omp_block_size;
4123 let mut j = omp_block_end - 64 - 1;
4124
4125 while i < j {
4126 let v0 = cache[i as usize].symbol as usize;
4127 let p0 = cache[i as usize].index;
4128 d += SaSint::from(p0 < 0);
4129 cache[i as usize].symbol = buckets[v0];
4130 buckets[v0] += 1;
4131 cache[i as usize].index =
4132 (p0 - 1) | (((buckets[2 + v0] != d) as SaSint) << (SAINT_BIT - 1));
4133 buckets[2 + v0] = d;
4134 if cache[i as usize].symbol < omp_block_end {
4135 let s = cache[i as usize].symbol as usize;
4136 let q = cache[i as usize].index & SAINT_MAX;
4137 cache[s].index = cache[i as usize].index;
4138 cache[s].symbol = buckets_index4(
4139 t[(q - 1) as usize] as usize,
4140 usize::from(t[(q - 2) as usize] >= t[(q - 1) as usize]),
4141 ) as SaSint;
4142 }
4143
4144 let v1 = cache[(i + 1) as usize].symbol as usize;
4145 let p1 = cache[(i + 1) as usize].index;
4146 d += SaSint::from(p1 < 0);
4147 cache[(i + 1) as usize].symbol = buckets[v1];
4148 buckets[v1] += 1;
4149 cache[(i + 1) as usize].index =
4150 (p1 - 1) | (((buckets[2 + v1] != d) as SaSint) << (SAINT_BIT - 1));
4151 buckets[2 + v1] = d;
4152 if cache[(i + 1) as usize].symbol < omp_block_end {
4153 let s = cache[(i + 1) as usize].symbol as usize;
4154 let q = cache[(i + 1) as usize].index & SAINT_MAX;
4155 cache[s].index = cache[(i + 1) as usize].index;
4156 cache[s].symbol = buckets_index4(
4157 t[(q - 1) as usize] as usize,
4158 usize::from(t[(q - 2) as usize] >= t[(q - 1) as usize]),
4159 ) as SaSint;
4160 }
4161
4162 i += 2;
4163 }
4164
4165 j += 64 + 1;
4166 while i < j {
4167 let v = cache[i as usize].symbol as usize;
4168 let p = cache[i as usize].index;
4169 d += SaSint::from(p < 0);
4170 cache[i as usize].symbol = buckets[v];
4171 buckets[v] += 1;
4172 cache[i as usize].index = (p - 1) | (((buckets[2 + v] != d) as SaSint) << (SAINT_BIT - 1));
4173 buckets[2 + v] = d;
4174 if cache[i as usize].symbol < omp_block_end {
4175 let s = cache[i as usize].symbol as usize;
4176 let q = cache[i as usize].index & SAINT_MAX;
4177 cache[s].index = cache[i as usize].index;
4178 cache[s].symbol = buckets_index4(
4179 t[(q - 1) as usize] as usize,
4180 usize::from(t[(q - 2) as usize] >= t[(q - 1) as usize]),
4181 ) as SaSint;
4182 }
4183 i += 1;
4184 }
4185
4186 d
4187}
4188
4189fn partial_sorting_scan_left_to_right_32s_4k_block_sort(
4190 t: &[SaSint],
4191 k: SaSint,
4192 buckets: &mut [SaSint],
4193 mut d: SaSint,
4194 cache: &mut [ThreadCache],
4195 omp_block_start: SaSint,
4196 omp_block_size: SaSint,
4197) -> SaSint {
4198 let k = k as usize;
4199 let mut i = omp_block_start;
4200 let omp_block_end = omp_block_start + omp_block_size;
4201 let mut j = omp_block_end - 64 - 1;
4202
4203 while i < j {
4204 for current in [i, i + 1] {
4205 let v = cache[current as usize].symbol;
4206 if v >= 0 {
4207 let p = cache[current as usize].index;
4208 d += p >> (SUFFIX_GROUP_BIT - 1);
4209 let bucket_index = (v >> 1) as usize;
4210 let v_usize = v as usize;
4211 cache[current as usize].symbol = buckets[2 * k + bucket_index];
4212 buckets[2 * k + bucket_index] += 1;
4213 cache[current as usize].index = (p - 1)
4214 | ((v & 1) << (SAINT_BIT - 1))
4215 | (((buckets[v_usize] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
4216 buckets[v_usize] = d;
4217 if cache[current as usize].symbol < omp_block_end {
4218 let ni = cache[current as usize].symbol as usize;
4219 let mut np = cache[current as usize].index;
4220 if np > 0 {
4221 cache[ni].index = np;
4222 np &= !SUFFIX_GROUP_MARKER;
4223 cache[ni].symbol = buckets_index2(
4224 t[(np - 1) as usize] as usize,
4225 usize::from(t[(np - 2) as usize] < t[(np - 1) as usize]),
4226 ) as SaSint;
4227 np = 0;
4228 }
4229 cache[current as usize].index = np & SAINT_MAX;
4230 }
4231 }
4232 }
4233 i += 2;
4234 }
4235
4236 j += 64 + 1;
4237 while i < j {
4238 let v = cache[i as usize].symbol;
4239 if v >= 0 {
4240 let p = cache[i as usize].index;
4241 d += p >> (SUFFIX_GROUP_BIT - 1);
4242 let bucket_index = (v >> 1) as usize;
4243 let v_usize = v as usize;
4244 cache[i as usize].symbol = buckets[2 * k + bucket_index];
4245 buckets[2 * k + bucket_index] += 1;
4246 cache[i as usize].index = (p - 1)
4247 | ((v & 1) << (SAINT_BIT - 1))
4248 | (((buckets[v_usize] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
4249 buckets[v_usize] = d;
4250 if cache[i as usize].symbol < omp_block_end {
4251 let ni = cache[i as usize].symbol as usize;
4252 let mut np = cache[i as usize].index;
4253 if np > 0 {
4254 cache[ni].index = np;
4255 np &= !SUFFIX_GROUP_MARKER;
4256 cache[ni].symbol = buckets_index2(
4257 t[(np - 1) as usize] as usize,
4258 usize::from(t[(np - 2) as usize] < t[(np - 1) as usize]),
4259 ) as SaSint;
4260 np = 0;
4261 }
4262 cache[i as usize].index = np & SAINT_MAX;
4263 }
4264 }
4265 i += 1;
4266 }
4267
4268 d
4269}
4270
4271fn partial_sorting_scan_left_to_right_32s_1k_block_sort(
4272 t: &[SaSint],
4273 induction_bucket: &mut [SaSint],
4274 cache: &mut [ThreadCache],
4275 omp_block_start: SaSint,
4276 omp_block_size: SaSint,
4277) {
4278 let mut i = omp_block_start;
4279 let omp_block_end = omp_block_start + omp_block_size;
4280 let mut j = omp_block_end - 64 - 1;
4281
4282 while i < j {
4283 for current in [i, i + 1] {
4284 let v = cache[current as usize].symbol;
4285 if v >= 0 {
4286 cache[current as usize].symbol = induction_bucket[v as usize];
4287 induction_bucket[v as usize] += 1;
4288 if cache[current as usize].symbol < omp_block_end {
4289 let ni = cache[current as usize].symbol as usize;
4290 let mut np = cache[current as usize].index;
4291 if np > 0 {
4292 cache[ni].index = (np - 1)
4293 | ((usize::from(t[(np - 2) as usize] < t[(np - 1) as usize])
4294 as SaSint)
4295 << (SAINT_BIT - 1));
4296 cache[ni].symbol = t[(np - 1) as usize];
4297 np = 0;
4298 }
4299 cache[current as usize].index = np & SAINT_MAX;
4300 }
4301 }
4302 }
4303 i += 2;
4304 }
4305
4306 j = omp_block_end;
4307 while i < j {
4308 let v = cache[i as usize].symbol;
4309 if v >= 0 {
4310 cache[i as usize].symbol = induction_bucket[v as usize];
4311 induction_bucket[v as usize] += 1;
4312 if cache[i as usize].symbol < omp_block_end {
4313 let ni = cache[i as usize].symbol as usize;
4314 let mut np = cache[i as usize].index;
4315 if np > 0 {
4316 cache[ni].index = (np - 1)
4317 | ((usize::from(t[(np - 2) as usize] < t[(np - 1) as usize]) as SaSint)
4318 << (SAINT_BIT - 1));
4319 cache[ni].symbol = t[(np - 1) as usize];
4320 np = 0;
4321 }
4322 cache[i as usize].index = np & SAINT_MAX;
4323 }
4324 }
4325 i += 1;
4326 }
4327}
4328
4329fn partial_sorting_scan_right_to_left_32s_6k_block_sort(
4330 t: &[SaSint],
4331 buckets: &mut [SaSint],
4332 mut d: SaSint,
4333 cache: &mut [ThreadCache],
4334 omp_block_start: SaSint,
4335 omp_block_size: SaSint,
4336) -> SaSint {
4337 let mut i = omp_block_start + omp_block_size - 1;
4338 let mut j = omp_block_start + 64 + 1;
4339
4340 while i >= j {
4341 let v0 = cache[i as usize].symbol as usize;
4342 let p0 = cache[i as usize].index;
4343 d += SaSint::from(p0 < 0);
4344 buckets[v0] -= 1;
4345 cache[i as usize].symbol = buckets[v0];
4346 cache[i as usize].index =
4347 (p0 - 1) | (((buckets[2 + v0] != d) as SaSint) << (SAINT_BIT - 1));
4348 buckets[2 + v0] = d;
4349 if cache[i as usize].symbol >= omp_block_start {
4350 let s = cache[i as usize].symbol as usize;
4351 let q = cache[i as usize].index & SAINT_MAX;
4352 cache[s].index = cache[i as usize].index;
4353 cache[s].symbol = buckets_index4(
4354 t[(q - 1) as usize] as usize,
4355 usize::from(t[(q - 2) as usize] > t[(q - 1) as usize]),
4356 ) as SaSint;
4357 }
4358
4359 let v1 = cache[(i - 1) as usize].symbol as usize;
4360 let p1 = cache[(i - 1) as usize].index;
4361 d += SaSint::from(p1 < 0);
4362 buckets[v1] -= 1;
4363 cache[(i - 1) as usize].symbol = buckets[v1];
4364 cache[(i - 1) as usize].index =
4365 (p1 - 1) | (((buckets[2 + v1] != d) as SaSint) << (SAINT_BIT - 1));
4366 buckets[2 + v1] = d;
4367 if cache[(i - 1) as usize].symbol >= omp_block_start {
4368 let s = cache[(i - 1) as usize].symbol as usize;
4369 let q = cache[(i - 1) as usize].index & SAINT_MAX;
4370 cache[s].index = cache[(i - 1) as usize].index;
4371 cache[s].symbol = buckets_index4(
4372 t[(q - 1) as usize] as usize,
4373 usize::from(t[(q - 2) as usize] > t[(q - 1) as usize]),
4374 ) as SaSint;
4375 }
4376
4377 i -= 2;
4378 }
4379
4380 j -= 64 + 1;
4381 while i >= j {
4382 let v = cache[i as usize].symbol as usize;
4383 let p = cache[i as usize].index;
4384 d += SaSint::from(p < 0);
4385 buckets[v] -= 1;
4386 cache[i as usize].symbol = buckets[v];
4387 cache[i as usize].index = (p - 1) | (((buckets[2 + v] != d) as SaSint) << (SAINT_BIT - 1));
4388 buckets[2 + v] = d;
4389 if cache[i as usize].symbol >= omp_block_start {
4390 let s = cache[i as usize].symbol as usize;
4391 let q = cache[i as usize].index & SAINT_MAX;
4392 cache[s].index = cache[i as usize].index;
4393 cache[s].symbol = buckets_index4(
4394 t[(q - 1) as usize] as usize,
4395 usize::from(t[(q - 2) as usize] > t[(q - 1) as usize]),
4396 ) as SaSint;
4397 }
4398 i -= 1;
4399 }
4400
4401 d
4402}
4403
4404fn partial_sorting_scan_right_to_left_32s_4k_block_sort(
4405 t: &[SaSint],
4406 k: SaSint,
4407 buckets: &mut [SaSint],
4408 mut d: SaSint,
4409 cache: &mut [ThreadCache],
4410 omp_block_start: SaSint,
4411 omp_block_size: SaSint,
4412) -> SaSint {
4413 let k = k as usize;
4414 let mut i = omp_block_start + omp_block_size - 1;
4415 let mut j = omp_block_start + 64 + 1;
4416
4417 while i >= j {
4418 for current in [i, i - 1] {
4419 let v = cache[current as usize].symbol;
4420 if v >= 0 {
4421 let p = cache[current as usize].index;
4422 d += p >> (SUFFIX_GROUP_BIT - 1);
4423 let bucket_index = (v >> 1) as usize;
4424 let v_usize = v as usize;
4425 buckets[3 * k + bucket_index] -= 1;
4426 cache[current as usize].symbol = buckets[3 * k + bucket_index];
4427 cache[current as usize].index = (p - 1)
4428 | ((v & 1) << (SAINT_BIT - 1))
4429 | (((buckets[v_usize] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
4430 buckets[v_usize] = d;
4431 if cache[current as usize].symbol >= omp_block_start {
4432 let ni = cache[current as usize].symbol as usize;
4433 let mut np = cache[current as usize].index;
4434 if np > 0 {
4435 cache[current as usize].index = 0;
4436 cache[ni].index = np;
4437 np &= !SUFFIX_GROUP_MARKER;
4438 cache[ni].symbol = buckets_index2(
4439 t[(np - 1) as usize] as usize,
4440 usize::from(t[(np - 2) as usize] > t[(np - 1) as usize]),
4441 ) as SaSint;
4442 }
4443 }
4444 }
4445 }
4446 i -= 2;
4447 }
4448
4449 j -= 64 + 1;
4450 while i >= j {
4451 let v = cache[i as usize].symbol;
4452 if v >= 0 {
4453 let p = cache[i as usize].index;
4454 d += p >> (SUFFIX_GROUP_BIT - 1);
4455 let bucket_index = (v >> 1) as usize;
4456 let v_usize = v as usize;
4457 buckets[3 * k + bucket_index] -= 1;
4458 cache[i as usize].symbol = buckets[3 * k + bucket_index];
4459 cache[i as usize].index = (p - 1)
4460 | ((v & 1) << (SAINT_BIT - 1))
4461 | (((buckets[v_usize] != d) as SaSint) << (SUFFIX_GROUP_BIT - 1));
4462 buckets[v_usize] = d;
4463 if cache[i as usize].symbol >= omp_block_start {
4464 let ni = cache[i as usize].symbol as usize;
4465 let mut np = cache[i as usize].index;
4466 if np > 0 {
4467 cache[i as usize].index = 0;
4468 cache[ni].index = np;
4469 np &= !SUFFIX_GROUP_MARKER;
4470 cache[ni].symbol = buckets_index2(
4471 t[(np - 1) as usize] as usize,
4472 usize::from(t[(np - 2) as usize] > t[(np - 1) as usize]),
4473 ) as SaSint;
4474 }
4475 }
4476 }
4477 i -= 1;
4478 }
4479
4480 d
4481}
4482
4483fn partial_sorting_scan_right_to_left_32s_1k_block_sort(
4484 t: &[SaSint],
4485 induction_bucket: &mut [SaSint],
4486 cache: &mut [ThreadCache],
4487 omp_block_start: SaSint,
4488 omp_block_size: SaSint,
4489) {
4490 let mut i = omp_block_start + omp_block_size - 1;
4491 let mut j = omp_block_start + 64 + 1;
4492
4493 while i >= j {
4494 for current in [i, i - 1] {
4495 let v = cache[current as usize].symbol;
4496 if v >= 0 {
4497 induction_bucket[v as usize] -= 1;
4498 cache[current as usize].symbol = induction_bucket[v as usize];
4499 if cache[current as usize].symbol >= omp_block_start {
4500 let ni = cache[current as usize].symbol as usize;
4501 let np = cache[current as usize].index;
4502 if np > 0 {
4503 cache[current as usize].index = 0;
4504 cache[ni].index = (np - 1)
4505 | ((usize::from(t[(np - 2) as usize] > t[(np - 1) as usize])
4506 as SaSint)
4507 << (SAINT_BIT - 1));
4508 cache[ni].symbol = t[(np - 1) as usize];
4509 }
4510 }
4511 }
4512 }
4513 i -= 2;
4514 }
4515
4516 j -= 64 + 1;
4517 while i >= j {
4518 let v = cache[i as usize].symbol;
4519 if v >= 0 {
4520 induction_bucket[v as usize] -= 1;
4521 cache[i as usize].symbol = induction_bucket[v as usize];
4522 if cache[i as usize].symbol >= omp_block_start {
4523 let ni = cache[i as usize].symbol as usize;
4524 let np = cache[i as usize].index;
4525 if np > 0 {
4526 cache[i as usize].index = 0;
4527 cache[ni].index = (np - 1)
4528 | ((usize::from(t[(np - 2) as usize] > t[(np - 1) as usize]) as SaSint)
4529 << (SAINT_BIT - 1));
4530 cache[ni].symbol = t[(np - 1) as usize];
4531 }
4532 }
4533 }
4534 i -= 1;
4535 }
4536}
4537
4538fn partial_sorting_scan_left_to_right_32s_6k_block_omp(
4539 t: &[SaSint],
4540 sa: &mut [SaSint],
4541 buckets: &mut [SaSint],
4542 d: SaSint,
4543 cache: &mut [ThreadCache],
4544 block_start: SaSint,
4545 block_size: SaSint,
4546 threads: SaSint,
4547) -> SaSint {
4548 if block_size <= 0 {
4549 return d;
4550 }
4551 if threads == 1 || block_size < 16_384 {
4552 return partial_sorting_scan_left_to_right_32s_6k(
4553 t,
4554 sa,
4555 buckets,
4556 d,
4557 block_start,
4558 block_size,
4559 );
4560 }
4561
4562 let threads_usize = usize::try_from(threads)
4563 .expect("threads must be non-negative")
4564 .max(1);
4565 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4566 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4567 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4568 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4569
4570 {
4571 let sa_ptr = SyncMutPtr::new(sa);
4572 let t_ro: &[SaSint] = t;
4573 let cache_ptr = SyncMutPtr::new(cache);
4574 run_rayon_with_threads(omp_num_threads, || {
4575 (0..omp_num_threads)
4576 .into_par_iter()
4577 .for_each(|omp_thread_num| {
4578 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4579 omp_block_stride
4580 } else {
4581 block_size_usize - omp_thread_num * omp_block_stride
4582 };
4583 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4584 if omp_block_size == 0 {
4585 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4586 }
4587 let cache = unsafe { cache_ptr.as_slice() };
4588 let sa = unsafe { sa_ptr.as_slice() };
4589 partial_sorting_scan_left_to_right_32s_6k_block_gather(
4590 t_ro,
4591 sa,
4592 &mut cache[omp_thread_num * omp_block_stride
4593 ..omp_thread_num * omp_block_stride + omp_block_size],
4594 omp_block_start as SaSint,
4595 omp_block_size as SaSint,
4596 );
4597 });
4598 });
4599 }
4600
4601 let d = partial_sorting_scan_left_to_right_32s_6k_block_sort(
4602 t,
4603 buckets,
4604 d,
4605 &mut cache[..block_size_usize],
4606 block_start,
4607 block_size,
4608 );
4609 place_cached_suffixes(sa, &cache[..block_size_usize], 0, block_size);
4610 d
4611}
4612
4613fn partial_sorting_scan_left_to_right_32s_4k_block_omp(
4614 t: &[SaSint],
4615 sa: &mut [SaSint],
4616 k: SaSint,
4617 buckets: &mut [SaSint],
4618 d: SaSint,
4619 cache: &mut [ThreadCache],
4620 block_start: SaSint,
4621 block_size: SaSint,
4622 threads: SaSint,
4623) -> SaSint {
4624 if block_size <= 0 {
4625 return d;
4626 }
4627 if threads == 1 || block_size < 16_384 {
4628 return partial_sorting_scan_left_to_right_32s_4k(
4629 t,
4630 sa,
4631 k,
4632 buckets,
4633 d,
4634 block_start,
4635 block_size,
4636 );
4637 }
4638
4639 let threads_usize = usize::try_from(threads)
4640 .expect("threads must be non-negative")
4641 .max(1);
4642 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4643 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4644 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4645 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4646
4647 {
4648 let sa_ptr = SyncMutPtr::new(sa);
4649 let t_ro: &[SaSint] = t;
4650 let cache_ptr = SyncMutPtr::new(cache);
4651 run_rayon_with_threads(omp_num_threads, || {
4652 (0..omp_num_threads)
4653 .into_par_iter()
4654 .for_each(|omp_thread_num| {
4655 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4656 omp_block_stride
4657 } else {
4658 block_size_usize - omp_thread_num * omp_block_stride
4659 };
4660 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4661 if omp_block_size == 0 {
4662 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4663 }
4664 let cache = unsafe { cache_ptr.as_slice() };
4665 let sa = unsafe { sa_ptr.as_slice() };
4666 partial_sorting_scan_left_to_right_32s_4k_block_gather(
4667 t_ro,
4668 sa,
4669 &mut cache[omp_thread_num * omp_block_stride
4670 ..omp_thread_num * omp_block_stride + omp_block_size],
4671 omp_block_start as SaSint,
4672 omp_block_size as SaSint,
4673 );
4674 });
4675 });
4676 }
4677
4678 let cache = &mut cache[..block_size_usize];
4679 let d = partial_sorting_scan_left_to_right_32s_4k_block_sort(
4680 t,
4681 k,
4682 buckets,
4683 d,
4684 cache,
4685 block_start,
4686 block_size,
4687 );
4688 for entry in cache.iter() {
4689 if entry.symbol >= 0 {
4690 sa[entry.symbol as usize] = entry.index;
4691 }
4692 }
4693 d
4694}
4695
4696fn partial_sorting_scan_left_to_right_32s_1k_block_omp(
4697 t: &[SaSint],
4698 sa: &mut [SaSint],
4699 buckets: &mut [SaSint],
4700 cache: &mut [ThreadCache],
4701 block_start: SaSint,
4702 block_size: SaSint,
4703 threads: SaSint,
4704) {
4705 if block_size <= 0 {
4706 return;
4707 }
4708 if threads == 1 || block_size < 16_384 {
4709 partial_sorting_scan_left_to_right_32s_1k(t, sa, buckets, block_start, block_size);
4710 return;
4711 }
4712
4713 let threads_usize = usize::try_from(threads)
4714 .expect("threads must be non-negative")
4715 .max(1);
4716 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4717 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4718 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4719 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4720
4721 {
4722 let sa_ptr = SyncMutPtr::new(sa);
4723 let t_ro: &[SaSint] = t;
4724 let cache_ptr = SyncMutPtr::new(cache);
4725 run_rayon_with_threads(omp_num_threads, || {
4726 (0..omp_num_threads)
4727 .into_par_iter()
4728 .for_each(|omp_thread_num| {
4729 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4730 omp_block_stride
4731 } else {
4732 block_size_usize - omp_thread_num * omp_block_stride
4733 };
4734 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4735 if omp_block_size == 0 {
4736 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4737 }
4738 let cache = unsafe { cache_ptr.as_slice() };
4739 let sa = unsafe { sa_ptr.as_slice() };
4740 partial_sorting_scan_left_to_right_32s_1k_block_gather(
4741 t_ro,
4742 sa,
4743 &mut cache[omp_thread_num * omp_block_stride
4744 ..omp_thread_num * omp_block_stride + omp_block_size],
4745 omp_block_start as SaSint,
4746 omp_block_size as SaSint,
4747 );
4748 });
4749 });
4750 }
4751
4752 let cache = &mut cache[..block_size_usize];
4753 partial_sorting_scan_left_to_right_32s_1k_block_sort(
4754 t,
4755 buckets,
4756 cache,
4757 block_start,
4758 block_size,
4759 );
4760 compact_and_place_cached_suffixes(sa, cache, block_start, block_size);
4761}
4762
4763fn partial_sorting_scan_right_to_left_32s_6k_block_omp(
4764 t: &[SaSint],
4765 sa: &mut [SaSint],
4766 buckets: &mut [SaSint],
4767 mut d: SaSint,
4768 cache: &mut [ThreadCache],
4769 block_start: SaSint,
4770 block_size: SaSint,
4771 threads: SaSint,
4772) -> SaSint {
4773 if block_size <= 0 {
4774 return d;
4775 }
4776 if threads == 1 || block_size < 16_384 {
4777 return partial_sorting_scan_right_to_left_32s_6k(
4778 t,
4779 sa,
4780 buckets,
4781 d,
4782 block_start,
4783 block_size,
4784 );
4785 }
4786
4787 let threads_usize = usize::try_from(threads)
4788 .expect("threads must be non-negative")
4789 .max(1);
4790 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4791 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4792 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4793 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4794
4795 {
4796 let sa_ptr = SyncMutPtr::new(sa);
4797 let t_ro: &[SaSint] = t;
4798 let cache_ptr = SyncMutPtr::new(cache);
4799 run_rayon_with_threads(omp_num_threads, || {
4800 (0..omp_num_threads)
4801 .into_par_iter()
4802 .for_each(|omp_thread_num| {
4803 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4804 omp_block_stride
4805 } else {
4806 block_size_usize - omp_thread_num * omp_block_stride
4807 };
4808 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4809 if omp_block_size == 0 {
4810 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4811 }
4812 let cache = unsafe { cache_ptr.as_slice() };
4813 let sa = unsafe { sa_ptr.as_slice() };
4814 partial_sorting_scan_right_to_left_32s_6k_block_gather(
4815 t_ro,
4816 sa,
4817 &mut cache[omp_thread_num * omp_block_stride
4818 ..omp_thread_num * omp_block_stride + omp_block_size],
4819 omp_block_start as SaSint,
4820 omp_block_size as SaSint,
4821 );
4822 });
4823 });
4824 }
4825
4826 d = partial_sorting_scan_right_to_left_32s_6k_block_sort(
4827 t,
4828 buckets,
4829 d,
4830 &mut cache[..block_size_usize],
4831 block_start,
4832 block_size,
4833 );
4834 {
4835 let sa_ptr = SyncMutPtr::new(sa);
4836 let cache_ro: &[ThreadCache] = cache;
4837 run_rayon_with_threads(omp_num_threads, || {
4838 (0..omp_num_threads)
4839 .into_par_iter()
4840 .for_each(|omp_thread_num| {
4841 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4842 omp_block_stride
4843 } else {
4844 block_size_usize - omp_thread_num * omp_block_stride
4845 };
4846 let cache_start = omp_thread_num * omp_block_stride;
4847 if omp_block_size == 0 {
4848 omp_block_size = block_size_usize - cache_start;
4849 }
4850 let sa = unsafe { sa_ptr.as_slice() };
4851 for entry in &cache_ro[cache_start..cache_start + omp_block_size] {
4852 sa[entry.symbol as usize] = entry.index;
4853 }
4854 });
4855 });
4856 }
4857 d
4858}
4859
4860fn partial_sorting_scan_right_to_left_32s_4k_block_omp(
4861 t: &[SaSint],
4862 sa: &mut [SaSint],
4863 k: SaSint,
4864 buckets: &mut [SaSint],
4865 mut d: SaSint,
4866 cache: &mut [ThreadCache],
4867 block_start: SaSint,
4868 block_size: SaSint,
4869 threads: SaSint,
4870) -> SaSint {
4871 if block_size <= 0 {
4872 return d;
4873 }
4874 if threads == 1 || block_size < 16_384 {
4875 return partial_sorting_scan_right_to_left_32s_4k(
4876 t,
4877 sa,
4878 k,
4879 buckets,
4880 d,
4881 block_start,
4882 block_size,
4883 );
4884 }
4885
4886 let threads_usize = usize::try_from(threads)
4887 .expect("threads must be non-negative")
4888 .max(1);
4889 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4890 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4891 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4892 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4893
4894 {
4895 let sa_ptr = SyncMutPtr::new(sa);
4896 let t_ro: &[SaSint] = t;
4897 let cache_ptr = SyncMutPtr::new(cache);
4898 run_rayon_with_threads(omp_num_threads, || {
4899 (0..omp_num_threads)
4900 .into_par_iter()
4901 .for_each(|omp_thread_num| {
4902 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4903 omp_block_stride
4904 } else {
4905 block_size_usize - omp_thread_num * omp_block_stride
4906 };
4907 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4908 if omp_block_size == 0 {
4909 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4910 }
4911 let cache = unsafe { cache_ptr.as_slice() };
4912 let sa = unsafe { sa_ptr.as_slice() };
4913 partial_sorting_scan_right_to_left_32s_4k_block_gather(
4914 t_ro,
4915 sa,
4916 &mut cache[omp_thread_num * omp_block_stride
4917 ..omp_thread_num * omp_block_stride + omp_block_size],
4918 omp_block_start as SaSint,
4919 omp_block_size as SaSint,
4920 );
4921 });
4922 });
4923 }
4924
4925 d = partial_sorting_scan_right_to_left_32s_4k_block_sort(
4926 t,
4927 k,
4928 buckets,
4929 d,
4930 &mut cache[..block_size_usize],
4931 block_start,
4932 block_size,
4933 );
4934 let mut write = 0usize;
4935 for read in 0..block_size_usize {
4936 let entry = cache[read];
4937 if entry.symbol >= 0 {
4938 cache[write] = entry;
4939 write += 1;
4940 }
4941 }
4942 for entry in &cache[..write] {
4943 sa[entry.symbol as usize] = entry.index;
4944 }
4945 d
4946}
4947
4948fn partial_sorting_scan_right_to_left_32s_1k_block_omp(
4949 t: &[SaSint],
4950 sa: &mut [SaSint],
4951 buckets: &mut [SaSint],
4952 cache: &mut [ThreadCache],
4953 block_start: SaSint,
4954 block_size: SaSint,
4955 threads: SaSint,
4956) {
4957 if block_size <= 0 {
4958 return;
4959 }
4960 if threads == 1 || block_size < 16_384 {
4961 partial_sorting_scan_right_to_left_32s_1k(t, sa, buckets, block_start, block_size);
4962 return;
4963 }
4964
4965 let threads_usize = usize::try_from(threads)
4966 .expect("threads must be non-negative")
4967 .max(1);
4968 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
4969 let block_start_usize = usize::try_from(block_start).expect("block_start must be non-negative");
4970 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
4971 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
4972
4973 {
4974 let sa_ptr = SyncMutPtr::new(sa);
4975 let t_ro: &[SaSint] = t;
4976 let cache_ptr = SyncMutPtr::new(cache);
4977 run_rayon_with_threads(omp_num_threads, || {
4978 (0..omp_num_threads)
4979 .into_par_iter()
4980 .for_each(|omp_thread_num| {
4981 let mut omp_block_size = if omp_thread_num + 1 < omp_num_threads {
4982 omp_block_stride
4983 } else {
4984 block_size_usize - omp_thread_num * omp_block_stride
4985 };
4986 let omp_block_start = block_start_usize + omp_thread_num * omp_block_stride;
4987 if omp_block_size == 0 {
4988 omp_block_size = block_size_usize - (omp_block_start - block_start_usize);
4989 }
4990 let cache = unsafe { cache_ptr.as_slice() };
4991 let sa = unsafe { sa_ptr.as_slice() };
4992 partial_sorting_scan_right_to_left_32s_1k_block_gather(
4993 t_ro,
4994 sa,
4995 &mut cache[omp_thread_num * omp_block_stride
4996 ..omp_thread_num * omp_block_stride + omp_block_size],
4997 omp_block_start as SaSint,
4998 omp_block_size as SaSint,
4999 );
5000 });
5001 });
5002 }
5003
5004 let cache = &mut cache[..block_size_usize];
5005 partial_sorting_scan_right_to_left_32s_1k_block_sort(
5006 t,
5007 buckets,
5008 cache,
5009 block_start,
5010 block_size,
5011 );
5012 compact_and_place_cached_suffixes(sa, cache, block_start, block_size);
5013}
5014
5015fn partial_sorting_gather_lms_suffixes_32s_4k(
5016 sa: &mut [SaSint],
5017 omp_block_start: SaSint,
5018 omp_block_size: SaSint,
5019) -> SaSint {
5020 let mut i = omp_block_start;
5021 let mut j = omp_block_start + omp_block_size - 3;
5022 let mut l = omp_block_start;
5023
5024 while i < j {
5025 let s0 = sa[i as usize] as SaUint;
5026 sa[l as usize] = (s0.wrapping_sub(SUFFIX_GROUP_MARKER as SaUint)
5027 & !(SUFFIX_GROUP_MARKER as SaUint)) as SaSint;
5028 l += SaSint::from((s0 as SaSint) < 0);
5029
5030 let s1 = sa[(i + 1) as usize] as SaUint;
5031 sa[l as usize] = (s1.wrapping_sub(SUFFIX_GROUP_MARKER as SaUint)
5032 & !(SUFFIX_GROUP_MARKER as SaUint)) as SaSint;
5033 l += SaSint::from((s1 as SaSint) < 0);
5034
5035 let s2 = sa[(i + 2) as usize] as SaUint;
5036 sa[l as usize] = (s2.wrapping_sub(SUFFIX_GROUP_MARKER as SaUint)
5037 & !(SUFFIX_GROUP_MARKER as SaUint)) as SaSint;
5038 l += SaSint::from((s2 as SaSint) < 0);
5039
5040 let s3 = sa[(i + 3) as usize] as SaUint;
5041 sa[l as usize] = (s3.wrapping_sub(SUFFIX_GROUP_MARKER as SaUint)
5042 & !(SUFFIX_GROUP_MARKER as SaUint)) as SaSint;
5043 l += SaSint::from((s3 as SaSint) < 0);
5044
5045 i += 4;
5046 }
5047
5048 j += 3;
5049 while i < j {
5050 let s = sa[i as usize] as SaUint;
5051 sa[l as usize] = (s.wrapping_sub(SUFFIX_GROUP_MARKER as SaUint)
5052 & !(SUFFIX_GROUP_MARKER as SaUint)) as SaSint;
5053 l += SaSint::from((s as SaSint) < 0);
5054 i += 1;
5055 }
5056
5057 l
5058}
5059
5060fn partial_sorting_gather_lms_suffixes_32s_1k(
5061 sa: &mut [SaSint],
5062 omp_block_start: SaSint,
5063 omp_block_size: SaSint,
5064) -> SaSint {
5065 let mut i = omp_block_start;
5066 let mut j = omp_block_start + omp_block_size - 3;
5067 let mut l = omp_block_start;
5068
5069 while i < j {
5070 let s0 = sa[i as usize];
5071 sa[l as usize] = s0 & SAINT_MAX;
5072 l += SaSint::from(s0 < 0);
5073
5074 let s1 = sa[(i + 1) as usize];
5075 sa[l as usize] = s1 & SAINT_MAX;
5076 l += SaSint::from(s1 < 0);
5077
5078 let s2 = sa[(i + 2) as usize];
5079 sa[l as usize] = s2 & SAINT_MAX;
5080 l += SaSint::from(s2 < 0);
5081
5082 let s3 = sa[(i + 3) as usize];
5083 sa[l as usize] = s3 & SAINT_MAX;
5084 l += SaSint::from(s3 < 0);
5085
5086 i += 4;
5087 }
5088
5089 j += 3;
5090 while i < j {
5091 let s = sa[i as usize];
5092 sa[l as usize] = s & SAINT_MAX;
5093 l += SaSint::from(s < 0);
5094 i += 1;
5095 }
5096
5097 l
5098}
5099
5100fn partial_sorting_gather_lms_suffixes_32s_4k_omp(
5101 sa: &mut [SaSint],
5102 n: SaSint,
5103 threads: SaSint,
5104 thread_state: &mut [ThreadState],
5105) {
5106 let n_usize = usize::try_from(n).expect("n must be non-negative");
5107 let thread_count = if threads > 1 && n >= 65_536 {
5108 usize::try_from(threads)
5109 .expect("threads must be non-negative")
5110 .min(thread_state.len())
5111 .max(1)
5112 } else {
5113 1
5114 };
5115
5116 if thread_count == 1 {
5117 let _ = partial_sorting_gather_lms_suffixes_32s_4k(sa, 0, n);
5118 return;
5119 }
5120
5121 let block_stride = (n_usize / thread_count) & !15usize;
5122 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
5123 let block_start = thread * block_stride;
5124 let block_size = if thread + 1 < thread_count {
5125 block_stride
5126 } else {
5127 n_usize - block_start
5128 };
5129 state.position = block_start as SaSint;
5130 state.count = partial_sorting_gather_lms_suffixes_32s_4k(
5131 sa,
5132 block_start as SaSint,
5133 block_size as SaSint,
5134 ) - block_start as SaSint;
5135 }
5136
5137 let mut position = 0usize;
5138 for (thread, state) in thread_state.iter().take(thread_count).enumerate() {
5139 let count = usize::try_from(state.count).expect("count must be non-negative");
5140 let src = usize::try_from(state.position).expect("position must be non-negative");
5141 if thread > 0 && count > 0 {
5142 sa.copy_within(src..src + count, position);
5143 }
5144 position += count;
5145 }
5146}
5147
5148fn partial_sorting_gather_lms_suffixes_32s_1k_omp(
5149 sa: &mut [SaSint],
5150 n: SaSint,
5151 threads: SaSint,
5152 thread_state: &mut [ThreadState],
5153) {
5154 let n_usize = usize::try_from(n).expect("n must be non-negative");
5155 let thread_count = if threads > 1 && n >= 65_536 {
5156 usize::try_from(threads)
5157 .expect("threads must be non-negative")
5158 .min(thread_state.len())
5159 .max(1)
5160 } else {
5161 1
5162 };
5163
5164 if thread_count == 1 {
5165 let _ = partial_sorting_gather_lms_suffixes_32s_1k(sa, 0, n);
5166 return;
5167 }
5168
5169 let block_stride = (n_usize / thread_count) & !15usize;
5170 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
5171 let block_start = thread * block_stride;
5172 let block_size = if thread + 1 < thread_count {
5173 block_stride
5174 } else {
5175 n_usize - block_start
5176 };
5177 state.position = block_start as SaSint;
5178 state.count = partial_sorting_gather_lms_suffixes_32s_1k(
5179 sa,
5180 block_start as SaSint,
5181 block_size as SaSint,
5182 ) - block_start as SaSint;
5183 }
5184
5185 let mut position = 0usize;
5186 for (thread, state) in thread_state.iter().take(thread_count).enumerate() {
5187 let count = usize::try_from(state.count).expect("count must be non-negative");
5188 let src = usize::try_from(state.position).expect("position must be non-negative");
5189 if thread > 0 && count > 0 {
5190 sa.copy_within(src..src + count, position);
5191 }
5192 position += count;
5193 }
5194}
5195
5196fn partial_gsa_scan_right_to_left_16u(
5197 t: &[u16],
5198 sa: &mut [SaSint],
5199 buckets: &mut [SaSint],
5200 mut d: SaSint,
5201 omp_block_start: SaSint,
5202 omp_block_size: SaSint,
5203) -> SaSint {
5204 let mut i = (omp_block_start + omp_block_size - 1) as isize;
5205 let mut j = (omp_block_start + 64 + 1) as isize;
5206 while i >= j {
5207 let mut p0 = sa[i as usize];
5208 d += SaSint::from(p0 < 0);
5209 p0 &= SAINT_MAX;
5210 let v0 = buckets_index2(
5211 t[(p0 - 1) as usize] as usize,
5212 usize::from(t[(p0 - 2) as usize] > t[(p0 - 1) as usize]),
5213 );
5214 if v0 != 1 {
5215 let mark0 = if buckets[2 * ALPHABET_SIZE + v0] != d {
5216 SAINT_MIN
5217 } else {
5218 0
5219 };
5220 buckets[v0] -= 1;
5221 sa[buckets[v0] as usize] = (p0 - 1) | mark0;
5222 buckets[2 * ALPHABET_SIZE + v0] = d;
5223 }
5224
5225 let mut p1 = sa[(i - 1) as usize];
5226 d += SaSint::from(p1 < 0);
5227 p1 &= SAINT_MAX;
5228 let v1 = buckets_index2(
5229 t[(p1 - 1) as usize] as usize,
5230 usize::from(t[(p1 - 2) as usize] > t[(p1 - 1) as usize]),
5231 );
5232 if v1 != 1 {
5233 let mark1 = if buckets[2 * ALPHABET_SIZE + v1] != d {
5234 SAINT_MIN
5235 } else {
5236 0
5237 };
5238 buckets[v1] -= 1;
5239 sa[buckets[v1] as usize] = (p1 - 1) | mark1;
5240 buckets[2 * ALPHABET_SIZE + v1] = d;
5241 }
5242
5243 i -= 2;
5244 }
5245
5246 j -= 64 + 1;
5247 while i >= j {
5248 let mut p = sa[i as usize];
5249 d += SaSint::from(p < 0);
5250 p &= SAINT_MAX;
5251 let v = buckets_index2(
5252 t[(p - 1) as usize] as usize,
5253 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
5254 );
5255 if v != 1 {
5256 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
5257 SAINT_MIN
5258 } else {
5259 0
5260 };
5261 buckets[v] -= 1;
5262 sa[buckets[v] as usize] = (p - 1) | mark;
5263 buckets[2 * ALPHABET_SIZE + v] = d;
5264 }
5265 i -= 1;
5266 }
5267
5268 d
5269}
5270
5271fn partial_gsa_scan_right_to_left_16u_block_omp(
5272 t: &[u16],
5273 sa: &mut [SaSint],
5274 k: SaSint,
5275 buckets: &mut [SaSint],
5276 d: SaSint,
5277 block_start: SaSint,
5278 block_size: SaSint,
5279 threads: SaSint,
5280 thread_state: &mut [ThreadState],
5281) -> SaSint {
5282 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
5283 usize::try_from(threads)
5284 .expect("threads must be non-negative")
5285 .min(thread_state.len())
5286 } else {
5287 1
5288 };
5289 if thread_count <= 1 {
5290 return partial_gsa_scan_right_to_left_16u(t, sa, buckets, d, block_start, block_size);
5291 }
5292
5293 let width = 2 * k as usize;
5294 let distinct_offset = 2 * ALPHABET_SIZE;
5295 let block_stride = (block_size / thread_count as SaSint) & !15;
5296
5297 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
5298 let local_start = thread as SaSint * block_stride;
5299 let local_size = if thread + 1 < thread_count {
5300 block_stride
5301 } else {
5302 block_size - local_start
5303 };
5304 let mut local_state = ThreadState::default();
5305 state.position = partial_sorting_scan_right_to_left_16u_block_prepare(
5306 t,
5307 sa,
5308 k,
5309 &mut state.buckets,
5310 &mut state.cache,
5311 block_start + local_start,
5312 local_size,
5313 &mut local_state,
5314 );
5315 state.count = local_state.cache_entries as SaSint;
5316 }
5317
5318 let mut next_d = d;
5319 for state in thread_state.iter_mut().take(thread_count).rev() {
5320 for c in 0..width {
5321 let a = buckets[c];
5322 let b = state.buckets[c];
5323 buckets[c] = a - b;
5324 state.buckets[c] = a;
5325 }
5326
5327 next_d -= 1;
5328 for c in 0..width {
5329 let offset = distinct_offset + c;
5330 let a = buckets[offset];
5331 let b = state.buckets[offset];
5332 let shifted = b + next_d;
5333 buckets[offset] = if b > 0 { shifted } else { a };
5334 state.buckets[offset] = a;
5335 }
5336 next_d += 1 + state.position;
5337 state.position = next_d - state.position;
5338 }
5339
5340 for state in thread_state.iter_mut().take(thread_count) {
5341 partial_gsa_scan_right_to_left_16u_block_place(
5342 sa,
5343 &mut state.buckets,
5344 &state.cache,
5345 state.count,
5346 state.position,
5347 );
5348 }
5349
5350 next_d
5351}
5352
5353fn partial_gsa_scan_right_to_left_16u_omp(
5354 t: &[u16],
5355 sa: &mut [SaSint],
5356 n: SaSint,
5357 k: SaSint,
5358 buckets: &mut [SaSint],
5359 first_lms_suffix: SaSint,
5360 left_suffixes_count: SaSint,
5361 d: SaSint,
5362 threads: SaSint,
5363) {
5364 let scan_start = left_suffixes_count + 1;
5365 let scan_end = n - first_lms_suffix;
5366
5367 if threads == 1 || scan_end - scan_start < 65536 {
5368 partial_gsa_scan_right_to_left_16u(t, sa, buckets, d, scan_start, scan_end - scan_start);
5369 } else {
5370 let mut d = d;
5371 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
5372 let mut block_start = scan_end - 1;
5373 while block_start >= scan_start {
5374 if sa[block_start as usize] == 0 {
5375 block_start -= 1;
5376 } else {
5377 let block_limit = threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
5378 let mut block_max_end = block_start - block_limit;
5379 if block_max_end < scan_start {
5380 block_max_end = scan_start - 1;
5381 }
5382 let mut block_end = block_start - 1;
5383 while block_end > block_max_end && sa[block_end as usize] != 0 {
5384 block_end -= 1;
5385 }
5386 let block_size = block_start - block_end;
5387
5388 if block_size < 32 {
5389 while block_start > block_end {
5390 let mut p = sa[block_start as usize];
5391 d += SaSint::from(p < 0);
5392 p &= SAINT_MAX;
5393 let v = buckets_index2(
5394 t[(p - 1) as usize] as usize,
5395 usize::from(t[(p - 2) as usize] > t[(p - 1) as usize]),
5396 );
5397 if v != 1 {
5398 let mark = if buckets[2 * ALPHABET_SIZE + v] != d {
5399 SAINT_MIN
5400 } else {
5401 0
5402 };
5403 buckets[v] -= 1;
5404 sa[buckets[v] as usize] = (p - 1) | mark;
5405 buckets[2 * ALPHABET_SIZE + v] = d;
5406 }
5407 block_start -= 1;
5408 }
5409 } else {
5410 d = partial_gsa_scan_right_to_left_16u_block_omp(
5411 t,
5412 sa,
5413 k,
5414 buckets,
5415 d,
5416 block_end + 1,
5417 block_size,
5418 threads,
5419 &mut thread_state,
5420 );
5421 block_start = block_end;
5422 }
5423 }
5424 }
5425 }
5426}
5427
5428fn partial_sorting_shift_markers_16u_omp(
5429 sa: &mut [SaSint],
5430 n: SaSint,
5431 buckets: &[SaSint],
5432 threads: SaSint,
5433) {
5434 let thread_count = if threads > 1 && n >= 65536 {
5435 usize::try_from(threads).expect("threads must be positive")
5436 } else {
5437 1
5438 };
5439 let c_step = buckets_index2(1, 0) as isize;
5440 let c_min = buckets_index2(1, 0) as isize;
5441 let c_max = buckets_index2(ALPHABET_SIZE - 1, 0) as isize;
5442 let sa_ptr = SyncMutPtr::new(sa);
5443 let buckets_ref: &[SaSint] = buckets;
5444 run_rayon_with_threads(thread_count, || {
5445 (0..thread_count).into_par_iter().for_each(|t| {
5446 let mut c = c_max - (t as isize * c_step);
5447 let sa = unsafe { sa_ptr.as_slice() };
5448 while c >= c_min {
5449 let c_usize = c as usize;
5450 let mut s = SAINT_MIN;
5451 let mut i = buckets_ref[4 * ALPHABET_SIZE + c_usize] as isize - 1;
5452 let mut j = buckets_ref[c_usize - buckets_index2(1, 0)] as isize + 3;
5453 while i >= j {
5454 let p0 = sa[i as usize];
5455 let q0 = (p0 & SAINT_MIN) ^ s;
5456 s ^= q0;
5457 sa[i as usize] = p0 ^ q0;
5458
5459 let p1 = sa[(i - 1) as usize];
5460 let q1 = (p1 & SAINT_MIN) ^ s;
5461 s ^= q1;
5462 sa[(i - 1) as usize] = p1 ^ q1;
5463
5464 let p2 = sa[(i - 2) as usize];
5465 let q2 = (p2 & SAINT_MIN) ^ s;
5466 s ^= q2;
5467 sa[(i - 2) as usize] = p2 ^ q2;
5468
5469 let p3 = sa[(i - 3) as usize];
5470 let q3 = (p3 & SAINT_MIN) ^ s;
5471 s ^= q3;
5472 sa[(i - 3) as usize] = p3 ^ q3;
5473
5474 i -= 4;
5475 }
5476
5477 j -= 3;
5478 while i >= j {
5479 let p = sa[i as usize];
5480 let q = (p & SAINT_MIN) ^ s;
5481 s ^= q;
5482 sa[i as usize] = p ^ q;
5483 i -= 1;
5484 }
5485
5486 c -= c_step * thread_count as isize;
5487 }
5488 });
5489 });
5490}
5491
5492fn induce_partial_order_16u_omp(
5493 t: &[u16],
5494 sa: &mut [SaSint],
5495 n: SaSint,
5496 k: SaSint,
5497 flags: SaSint,
5498 buckets: &mut [SaSint],
5499 first_lms_suffix: SaSint,
5500 left_suffixes_count: SaSint,
5501 threads: SaSint,
5502) {
5503 buckets[2 * ALPHABET_SIZE..4 * ALPHABET_SIZE].fill(0);
5504
5505 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
5506 let marker = 4 * ALPHABET_SIZE + buckets_index2(0, 1);
5507 buckets[marker] = buckets[4 * ALPHABET_SIZE + buckets_index2(1, 1)] - 1;
5508 flip_suffix_markers_omp(sa, buckets[marker], threads);
5509 }
5510
5511 let d = partial_sorting_scan_left_to_right_16u_omp(
5512 t,
5513 sa,
5514 n,
5515 k,
5516 buckets,
5517 left_suffixes_count,
5518 0,
5519 threads,
5520 );
5521 partial_sorting_shift_markers_16u_omp(sa, n, buckets, threads);
5522
5523 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
5524 partial_gsa_scan_right_to_left_16u_omp(
5525 t,
5526 sa,
5527 n,
5528 k,
5529 buckets,
5530 first_lms_suffix,
5531 left_suffixes_count,
5532 d,
5533 threads,
5534 );
5535
5536 if t[first_lms_suffix as usize] == 0 {
5537 let count = (buckets[buckets_index2(1, 1)] - 1) as usize;
5538 sa.copy_within(0..count, 1);
5539 sa[0] = first_lms_suffix | SAINT_MIN;
5540 }
5541
5542 buckets[buckets_index2(0, 1)] = 0;
5543 } else {
5544 partial_sorting_scan_right_to_left_16u_omp(
5545 t,
5546 sa,
5547 n,
5548 k,
5549 buckets,
5550 first_lms_suffix,
5551 left_suffixes_count,
5552 d,
5553 threads,
5554 );
5555 }
5556}
5557
5558fn induce_partial_order_32s_6k_omp(
5559 t: &[SaSint],
5560 sa: &mut [SaSint],
5561 n: SaSint,
5562 k: SaSint,
5563 buckets: &mut [SaSint],
5564 first_lms_suffix: SaSint,
5565 left_suffixes_count: SaSint,
5566 threads: SaSint,
5567 thread_state: &mut [ThreadState],
5568) {
5569 let d = partial_sorting_scan_left_to_right_32s_6k_omp(
5570 t,
5571 sa,
5572 n,
5573 buckets,
5574 left_suffixes_count,
5575 0,
5576 threads,
5577 thread_state,
5578 );
5579 partial_sorting_shift_markers_32s_6k_omp(sa, k, buckets, threads);
5580 partial_sorting_shift_buckets_32s_6k(k, buckets);
5581 partial_sorting_scan_right_to_left_32s_6k_omp(
5582 t,
5583 sa,
5584 n,
5585 buckets,
5586 first_lms_suffix,
5587 left_suffixes_count,
5588 d,
5589 threads,
5590 thread_state,
5591 );
5592}
5593
5594fn induce_partial_order_32s_4k_omp(
5595 t: &[SaSint],
5596 sa: &mut [SaSint],
5597 n: SaSint,
5598 k: SaSint,
5599 buckets: &mut [SaSint],
5600 threads: SaSint,
5601 thread_state: &mut [ThreadState],
5602) {
5603 buckets[..2 * k as usize].fill(0);
5604 let d = partial_sorting_scan_left_to_right_32s_4k_omp(
5605 t,
5606 sa,
5607 n,
5608 k,
5609 buckets,
5610 0,
5611 threads,
5612 thread_state,
5613 );
5614 partial_sorting_shift_markers_32s_4k(sa, n);
5615 partial_sorting_scan_right_to_left_32s_4k_omp(t, sa, n, k, buckets, d, threads, thread_state);
5616 partial_sorting_gather_lms_suffixes_32s_4k_omp(sa, n, threads, thread_state);
5617}
5618
5619fn induce_partial_order_32s_2k_omp(
5620 t: &[SaSint],
5621 sa: &mut [SaSint],
5622 n: SaSint,
5623 k: SaSint,
5624 buckets: &mut [SaSint],
5625 threads: SaSint,
5626 thread_state: &mut [ThreadState],
5627) {
5628 let k = k as usize;
5629 let (left, right) = buckets.split_at_mut(k);
5630 partial_sorting_scan_left_to_right_32s_1k_omp(t, sa, n, right, threads, thread_state);
5631 partial_sorting_scan_right_to_left_32s_1k_omp(t, sa, n, left, threads, thread_state);
5632 partial_sorting_gather_lms_suffixes_32s_1k_omp(sa, n, threads, thread_state);
5633}
5634
5635fn induce_partial_order_32s_1k_omp(
5636 t: &[SaSint],
5637 sa: &mut [SaSint],
5638 n: SaSint,
5639 k: SaSint,
5640 buckets: &mut [SaSint],
5641 threads: SaSint,
5642 thread_state: &mut [ThreadState],
5643) {
5644 count_suffixes_32s(t, n, k, buckets);
5645 initialize_buckets_start_32s_1k(k, buckets);
5646 partial_sorting_scan_left_to_right_32s_1k_omp(t, sa, n, buckets, threads, thread_state);
5647
5648 count_suffixes_32s(t, n, k, buckets);
5649 initialize_buckets_end_32s_1k(k, buckets);
5650 partial_sorting_scan_right_to_left_32s_1k_omp(t, sa, n, buckets, threads, thread_state);
5651
5652 partial_sorting_gather_lms_suffixes_32s_1k_omp(sa, n, threads, thread_state);
5653}
5654
5655fn final_sorting_scan_left_to_right_16u(
5656 t: &[u16],
5657 sa: &mut [SaSint],
5658 induction_bucket: &mut [SaSint],
5659 omp_block_start: SaSint,
5660 omp_block_size: SaSint,
5661) {
5662 let mut i = omp_block_start as isize;
5663 let mut j = (omp_block_start + omp_block_size - 64 - 1) as isize;
5664 while i < j {
5665 final_sorting_ltr_step(t, sa, induction_bucket, i as usize);
5666 final_sorting_ltr_step(t, sa, induction_bucket, (i + 1) as usize);
5667 i += 2;
5668 }
5669 j += 64 + 1;
5670 while i < j {
5671 final_sorting_ltr_step(t, sa, induction_bucket, i as usize);
5672 i += 1;
5673 }
5674}
5675
5676fn final_sorting_scan_right_to_left_16u(
5677 t: &[u16],
5678 sa: &mut [SaSint],
5679 induction_bucket: &mut [SaSint],
5680 omp_block_start: SaSint,
5681 omp_block_size: SaSint,
5682) {
5683 let mut i = (omp_block_start + omp_block_size - 1) as isize;
5684 let mut j = (omp_block_start + 64 + 1) as isize;
5685 while i >= j {
5686 final_sorting_rtl_step(t, sa, induction_bucket, i as usize, false);
5687 final_sorting_rtl_step(t, sa, induction_bucket, (i - 1) as usize, false);
5688 i -= 2;
5689 }
5690 j -= 64 + 1;
5691 while i >= j {
5692 final_sorting_rtl_step(t, sa, induction_bucket, i as usize, false);
5693 i -= 1;
5694 }
5695}
5696
5697fn final_sorting_scan_left_to_right_32s(
5698 t: &[SaSint],
5699 sa: &mut [SaSint],
5700 induction_bucket: &mut [SaSint],
5701 omp_block_start: SaSint,
5702 omp_block_size: SaSint,
5703) {
5704 let mut i = omp_block_start as isize;
5705 let mut j = (omp_block_start + omp_block_size - 2 * 64 - 1) as isize;
5706 while i < j {
5707 for current in [i, i + 1] {
5708 let current = current as usize;
5709 let mut p = sa[current];
5710 sa[current] = p ^ SAINT_MIN;
5711 if p > 0 {
5712 p -= 1;
5713 let p_usize = p as usize;
5714 let bucket = t[p_usize] as usize;
5715 let slot = induction_bucket[bucket] as usize;
5716 sa[slot] = p
5717 | ((usize::from(t[p_usize - usize::from(p > 0)] < t[p_usize]) as SaSint)
5718 << (SAINT_BIT - 1));
5719 induction_bucket[bucket] += 1;
5720 }
5721 }
5722 i += 2;
5723 }
5724
5725 j += 2 * 64 + 1;
5726 while i < j {
5727 let current = i as usize;
5728 let mut p = sa[current];
5729 sa[current] = p ^ SAINT_MIN;
5730 if p > 0 {
5731 p -= 1;
5732 let p_usize = p as usize;
5733 let bucket = t[p_usize] as usize;
5734 let slot = induction_bucket[bucket] as usize;
5735 sa[slot] = p
5736 | ((usize::from(t[p_usize - usize::from(p > 0)] < t[p_usize]) as SaSint)
5737 << (SAINT_BIT - 1));
5738 induction_bucket[bucket] += 1;
5739 }
5740 i += 1;
5741 }
5742}
5743
5744fn final_sorting_scan_left_to_right_32s_block_gather(
5745 t: &[SaSint],
5746 sa: &mut [SaSint],
5747 cache: &mut [ThreadCache],
5748 omp_block_start: SaSint,
5749 omp_block_size: SaSint,
5750) {
5751 if omp_block_size <= 0 {
5752 return;
5753 }
5754
5755 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
5756 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
5757 for offset in 0..size {
5758 let current = start + offset;
5759 let mut symbol = SAINT_MIN;
5760 let mut p = sa[current];
5761 sa[current] = p ^ SAINT_MIN;
5762 if p > 0 {
5763 p -= 1;
5764 let p_usize = p as usize;
5765 cache[offset].index = p
5766 | ((usize::from(t[p_usize - usize::from(p > 0)] < t[p_usize]) as SaSint)
5767 << (SAINT_BIT - 1));
5768 symbol = t[p_usize];
5769 }
5770 cache[offset].symbol = symbol;
5771 }
5772}
5773
5774fn final_sorting_scan_left_to_right_32s_block_sort(
5775 t: &[SaSint],
5776 induction_bucket: &mut [SaSint],
5777 cache: &mut [ThreadCache],
5778 omp_block_start: SaSint,
5779 omp_block_size: SaSint,
5780) {
5781 if omp_block_size <= 0 {
5782 return;
5783 }
5784
5785 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
5786 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
5787 let block_end = start + size;
5788
5789 for offset in 0..size {
5790 let v = cache[offset].symbol;
5791 if v >= 0 {
5792 let bucket_index = v as usize;
5793 let target = induction_bucket[bucket_index];
5794 cache[offset].symbol = target;
5795 induction_bucket[bucket_index] += 1;
5796 if target >= omp_block_start && target < block_end as SaSint {
5797 let ni = usize::try_from(target - omp_block_start)
5798 .expect("cache slot must be non-negative");
5799 let mut np = cache[offset].index;
5800 cache[offset].index = np ^ SAINT_MIN;
5801 if np > 0 {
5802 np -= 1;
5803 let np_usize = np as usize;
5804 cache[ni].index = np
5805 | ((usize::from(t[np_usize - usize::from(np > 0)] < t[np_usize])
5806 as SaSint)
5807 << (SAINT_BIT - 1));
5808 cache[ni].symbol = t[np_usize];
5809 }
5810 }
5811 }
5812 }
5813}
5814
5815fn final_sorting_scan_left_to_right_32s_block_omp(
5816 t: &[SaSint],
5817 sa: &mut [SaSint],
5818 buckets: &mut [SaSint],
5819 cache: &mut [ThreadCache],
5820 block_start: SaSint,
5821 block_size: SaSint,
5822 threads: SaSint,
5823) {
5824 if threads <= 1 || block_size < 16_384 {
5825 final_sorting_scan_left_to_right_32s(t, sa, buckets, block_start, block_size);
5826 return;
5827 }
5828
5829 final_sorting_scan_left_to_right_32s_block_gather(t, sa, cache, block_start, block_size);
5830 final_sorting_scan_left_to_right_32s_block_sort(t, buckets, cache, block_start, block_size);
5831
5832 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
5833 let threads_usize = usize::try_from(threads.max(1)).expect("threads must be positive");
5834 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
5835 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
5836 {
5837 let sa_ptr = SyncMutPtr::new(sa);
5838 let cache_ptr = SyncMutPtr::new(cache);
5839 run_rayon_with_threads(omp_num_threads, || {
5840 (0..omp_num_threads)
5841 .into_par_iter()
5842 .for_each(|omp_thread_num| {
5843 let omp_block_start = omp_thread_num * omp_block_stride;
5844 let omp_block_size = if omp_thread_num + 1 < omp_num_threads {
5845 omp_block_stride
5846 } else {
5847 block_size_usize - omp_block_start
5848 };
5849 let sa = unsafe { sa_ptr.as_slice() };
5850 let cache = unsafe { cache_ptr.as_slice() };
5851 compact_and_place_cached_suffixes(
5852 sa,
5853 cache,
5854 omp_block_start as SaSint,
5855 omp_block_size as SaSint,
5856 );
5857 });
5858 });
5859 }
5860}
5861
5862fn final_sorting_scan_left_to_right_32s_omp(
5863 t: &[SaSint],
5864 sa: &mut [SaSint],
5865 n: SaSint,
5866 induction_bucket: &mut [SaSint],
5867 threads: SaSint,
5868 thread_state: &mut [ThreadState],
5869) {
5870 let last = (n - 1) as usize;
5871 let bucket = t[last] as usize;
5872 let slot = induction_bucket[bucket] as usize;
5873 sa[slot] = (n - 1) | ((usize::from(t[last - 1] < t[last]) as SaSint) << (SAINT_BIT - 1));
5874 induction_bucket[bucket] += 1;
5875
5876 if threads == 1 || n < 65536 || thread_state.is_empty() {
5877 final_sorting_scan_left_to_right_32s(t, sa, induction_bucket, 0, n);
5878 return;
5879 }
5880
5881 let threads_usize = usize::try_from(threads)
5882 .expect("threads must be non-negative")
5883 .max(1);
5884 let block_span = threads_usize * PER_THREAD_CACHE_SIZE;
5885 let mut cache = vec![ThreadCache::default(); block_span];
5886 let mut block_start = 0;
5887 while block_start < n {
5888 let block_end = (block_start + block_span as SaSint).min(n);
5889 final_sorting_scan_left_to_right_32s_block_omp(
5890 t,
5891 sa,
5892 induction_bucket,
5893 &mut cache,
5894 block_start,
5895 block_end - block_start,
5896 threads,
5897 );
5898 block_start = block_end;
5899 }
5900}
5901
5902fn final_sorting_scan_right_to_left_32s(
5903 t: &[SaSint],
5904 sa: &mut [SaSint],
5905 induction_bucket: &mut [SaSint],
5906 omp_block_start: SaSint,
5907 omp_block_size: SaSint,
5908) {
5909 let mut i = (omp_block_start + omp_block_size - 1) as isize;
5910 let mut j = (omp_block_start + 2 * 64 + 1) as isize;
5911 while i >= j {
5912 for current in [i, i - 1] {
5913 let current = current as usize;
5914 let mut p = sa[current];
5915 sa[current] = p & SAINT_MAX;
5916 if p > 0 {
5917 p -= 1;
5918 let p_usize = p as usize;
5919 let bucket = t[p_usize] as usize;
5920 induction_bucket[bucket] -= 1;
5921 let slot = induction_bucket[bucket] as usize;
5922 sa[slot] = p
5923 | ((usize::from(t[p_usize - usize::from(p > 0)] > t[p_usize]) as SaSint)
5924 << (SAINT_BIT - 1));
5925 }
5926 }
5927 i -= 2;
5928 }
5929
5930 j -= 2 * 64 + 1;
5931 while i >= j {
5932 let current = i as usize;
5933 let mut p = sa[current];
5934 sa[current] = p & SAINT_MAX;
5935 if p > 0 {
5936 p -= 1;
5937 let p_usize = p as usize;
5938 let bucket = t[p_usize] as usize;
5939 induction_bucket[bucket] -= 1;
5940 let slot = induction_bucket[bucket] as usize;
5941 sa[slot] = p
5942 | ((usize::from(t[p_usize - usize::from(p > 0)] > t[p_usize]) as SaSint)
5943 << (SAINT_BIT - 1));
5944 }
5945 i -= 1;
5946 }
5947}
5948
5949fn final_sorting_scan_right_to_left_32s_block_gather(
5950 t: &[SaSint],
5951 sa: &mut [SaSint],
5952 cache: &mut [ThreadCache],
5953 omp_block_start: SaSint,
5954 omp_block_size: SaSint,
5955) {
5956 if omp_block_size <= 0 {
5957 return;
5958 }
5959
5960 let start = usize::try_from(omp_block_start).expect("omp_block_start must be non-negative");
5961 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
5962 for offset in 0..size {
5963 let current = start + offset;
5964 let mut symbol = SAINT_MIN;
5965 let mut p = sa[current];
5966 sa[current] = p & SAINT_MAX;
5967 if p > 0 {
5968 p -= 1;
5969 let p_usize = p as usize;
5970 cache[offset].index = p
5971 | ((usize::from(t[p_usize - usize::from(p > 0)] > t[p_usize]) as SaSint)
5972 << (SAINT_BIT - 1));
5973 symbol = t[p_usize];
5974 }
5975 cache[offset].symbol = symbol;
5976 }
5977}
5978
5979fn final_sorting_scan_right_to_left_32s_block_sort(
5980 t: &[SaSint],
5981 induction_bucket: &mut [SaSint],
5982 cache: &mut [ThreadCache],
5983 omp_block_start: SaSint,
5984 omp_block_size: SaSint,
5985) {
5986 if omp_block_size <= 0 {
5987 return;
5988 }
5989
5990 let size = usize::try_from(omp_block_size).expect("omp_block_size must be non-negative");
5991 let block_end = omp_block_start + omp_block_size;
5992 let mut offset = size;
5993
5994 while offset > 0 {
5995 offset -= 1;
5996 let v = cache[offset].symbol;
5997 if v >= 0 {
5998 let bucket_index = v as usize;
5999 induction_bucket[bucket_index] -= 1;
6000 let target = induction_bucket[bucket_index];
6001 cache[offset].symbol = target;
6002 if target >= omp_block_start && target < block_end {
6003 let ni = usize::try_from(target - omp_block_start)
6004 .expect("cache slot must be non-negative");
6005 let mut np = cache[offset].index;
6006 cache[offset].index = np & SAINT_MAX;
6007 if np > 0 {
6008 np -= 1;
6009 let np_usize = np as usize;
6010 cache[ni].index = np
6011 | ((usize::from(t[np_usize - usize::from(np > 0)] > t[np_usize])
6012 as SaSint)
6013 << (SAINT_BIT - 1));
6014 cache[ni].symbol = t[np_usize];
6015 }
6016 }
6017 }
6018 }
6019}
6020
6021fn final_sorting_scan_right_to_left_32s_block_omp(
6022 t: &[SaSint],
6023 sa: &mut [SaSint],
6024 buckets: &mut [SaSint],
6025 cache: &mut [ThreadCache],
6026 block_start: SaSint,
6027 block_size: SaSint,
6028 threads: SaSint,
6029) {
6030 if threads <= 1 || block_size < 16_384 {
6031 final_sorting_scan_right_to_left_32s(t, sa, buckets, block_start, block_size);
6032 return;
6033 }
6034
6035 final_sorting_scan_right_to_left_32s_block_gather(t, sa, cache, block_start, block_size);
6036 final_sorting_scan_right_to_left_32s_block_sort(t, buckets, cache, block_start, block_size);
6037
6038 let block_size_usize = usize::try_from(block_size).expect("block_size must be non-negative");
6039 let threads_usize = usize::try_from(threads.max(1)).expect("threads must be positive");
6040 let omp_num_threads = threads_usize.min(block_size_usize.max(1));
6041 let omp_block_stride = (block_size_usize / omp_num_threads) & !15usize;
6042 {
6043 let sa_ptr = SyncMutPtr::new(sa);
6044 let cache_ptr = SyncMutPtr::new(cache);
6045 run_rayon_with_threads(omp_num_threads, || {
6046 (0..omp_num_threads)
6047 .into_par_iter()
6048 .for_each(|omp_thread_num| {
6049 let omp_block_start = omp_thread_num * omp_block_stride;
6050 let omp_block_size = if omp_thread_num + 1 < omp_num_threads {
6051 omp_block_stride
6052 } else {
6053 block_size_usize - omp_block_start
6054 };
6055 let sa = unsafe { sa_ptr.as_slice() };
6056 let cache = unsafe { cache_ptr.as_slice() };
6057 compact_and_place_cached_suffixes(
6058 sa,
6059 cache,
6060 omp_block_start as SaSint,
6061 omp_block_size as SaSint,
6062 );
6063 });
6064 });
6065 }
6066}
6067
6068fn final_sorting_scan_right_to_left_32s_omp(
6069 t: &[SaSint],
6070 sa: &mut [SaSint],
6071 n: SaSint,
6072 induction_bucket: &mut [SaSint],
6073 threads: SaSint,
6074 thread_state: &mut [ThreadState],
6075) {
6076 if threads == 1 || n < 65536 || thread_state.is_empty() {
6077 final_sorting_scan_right_to_left_32s(t, sa, induction_bucket, 0, n);
6078 return;
6079 }
6080
6081 let threads_usize = usize::try_from(threads)
6082 .expect("threads must be non-negative")
6083 .max(1);
6084 let block_span = threads_usize * PER_THREAD_CACHE_SIZE;
6085 let mut cache = vec![ThreadCache::default(); block_span];
6086 let mut block_start = n - 1;
6087 while block_start >= 0 {
6088 let block_end = (block_start - block_span as SaSint).max(-1);
6089 final_sorting_scan_right_to_left_32s_block_omp(
6090 t,
6091 sa,
6092 induction_bucket,
6093 &mut cache,
6094 block_end + 1,
6095 block_start - block_end,
6096 threads,
6097 );
6098 block_start = block_end;
6099 }
6100}
6101
6102fn induce_final_order_32s_6k(
6103 t: &[SaSint],
6104 sa: &mut [SaSint],
6105 n: SaSint,
6106 k: SaSint,
6107 buckets: &mut [SaSint],
6108 threads: SaSint,
6109 thread_state: &mut [ThreadState],
6110) {
6111 let k = k as usize;
6112 final_sorting_scan_left_to_right_32s_omp(
6113 t,
6114 sa,
6115 n,
6116 &mut buckets[4 * k..5 * k],
6117 threads,
6118 thread_state,
6119 );
6120 final_sorting_scan_right_to_left_32s_omp(
6121 t,
6122 sa,
6123 n,
6124 &mut buckets[5 * k..6 * k],
6125 threads,
6126 thread_state,
6127 );
6128}
6129
6130fn induce_final_order_32s_4k(
6131 t: &[SaSint],
6132 sa: &mut [SaSint],
6133 n: SaSint,
6134 k: SaSint,
6135 buckets: &mut [SaSint],
6136 threads: SaSint,
6137 thread_state: &mut [ThreadState],
6138) {
6139 let k = k as usize;
6140 final_sorting_scan_left_to_right_32s_omp(
6141 t,
6142 sa,
6143 n,
6144 &mut buckets[2 * k..3 * k],
6145 threads,
6146 thread_state,
6147 );
6148 final_sorting_scan_right_to_left_32s_omp(
6149 t,
6150 sa,
6151 n,
6152 &mut buckets[3 * k..4 * k],
6153 threads,
6154 thread_state,
6155 );
6156}
6157
6158fn induce_final_order_32s_2k(
6159 t: &[SaSint],
6160 sa: &mut [SaSint],
6161 n: SaSint,
6162 k: SaSint,
6163 buckets: &mut [SaSint],
6164 threads: SaSint,
6165 thread_state: &mut [ThreadState],
6166) {
6167 let k = k as usize;
6168 final_sorting_scan_left_to_right_32s_omp(
6169 t,
6170 sa,
6171 n,
6172 &mut buckets[k..2 * k],
6173 threads,
6174 thread_state,
6175 );
6176 final_sorting_scan_right_to_left_32s_omp(t, sa, n, &mut buckets[..k], threads, thread_state);
6177}
6178
6179fn induce_final_order_32s_1k(
6180 t: &[SaSint],
6181 sa: &mut [SaSint],
6182 n: SaSint,
6183 k: SaSint,
6184 buckets: &mut [SaSint],
6185 threads: SaSint,
6186 thread_state: &mut [ThreadState],
6187) {
6188 count_suffixes_32s(t, n, k, buckets);
6189 initialize_buckets_start_32s_1k(k, buckets);
6190 final_sorting_scan_left_to_right_32s_omp(t, sa, n, buckets, threads, thread_state);
6191
6192 count_suffixes_32s(t, n, k, buckets);
6193 initialize_buckets_end_32s_1k(k, buckets);
6194 final_sorting_scan_right_to_left_32s_omp(t, sa, n, buckets, threads, thread_state);
6195}
6196
6197fn clear_lms_suffixes_omp(
6198 sa: &mut [SaSint],
6199 n: SaSint,
6200 k: SaSint,
6201 bucket_start: &[SaSint],
6202 bucket_end: &[SaSint],
6203 threads: SaSint,
6204) {
6205 let k_usize = usize::try_from(k).expect("k must be non-negative");
6206 let thread_count = if threads > 1 && n >= 65536 {
6207 usize::try_from(threads).expect("threads must be positive")
6208 } else {
6209 1
6210 };
6211 {
6212 let sa_ptr = SyncMutPtr::new(sa);
6213 let bucket_start_ref: &[SaSint] = bucket_start;
6214 let bucket_end_ref: &[SaSint] = bucket_end;
6215 run_rayon_with_threads(thread_count, || {
6216 (0..thread_count).into_par_iter().for_each(|t| {
6217 let mut c = t;
6218 let sa = unsafe { sa_ptr.as_slice() };
6219 while c < k_usize {
6220 if bucket_end_ref[c] > bucket_start_ref[c] {
6221 let start = bucket_start_ref[c] as usize;
6222 let end = bucket_end_ref[c] as usize;
6223 sa[start..end].fill(0);
6224 }
6225 c += thread_count;
6226 }
6227 });
6228 });
6229 }
6230}
6231
6232fn final_gsa_scan_right_to_left_16u(
6233 t: &[u16],
6234 sa: &mut [SaSint],
6235 induction_bucket: &mut [SaSint],
6236 omp_block_start: SaSint,
6237 omp_block_size: SaSint,
6238) {
6239 let mut i = (omp_block_start + omp_block_size - 1) as isize;
6240 let mut j = (omp_block_start + 64 + 1) as isize;
6241 while i >= j {
6242 final_sorting_rtl_step(t, sa, induction_bucket, i as usize, true);
6243 final_sorting_rtl_step(t, sa, induction_bucket, (i - 1) as usize, true);
6244 i -= 2;
6245 }
6246 j -= 64 + 1;
6247 while i >= j {
6248 final_sorting_rtl_step(t, sa, induction_bucket, i as usize, true);
6249 i -= 1;
6250 }
6251}
6252
6253fn final_sorting_ltr_step(
6254 t: &[u16],
6255 sa: &mut [SaSint],
6256 induction_bucket: &mut [SaSint],
6257 index: usize,
6258) {
6259 let mut p = sa[index];
6260 sa[index] = p ^ SAINT_MIN;
6261 if p > 0 {
6262 p -= 1;
6263 let c = t[p as usize] as usize;
6264 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
6265 SAINT_MIN
6266 } else {
6267 0
6268 };
6269 let dst = induction_bucket[c] as usize;
6270 sa[dst] = p | mark;
6271 induction_bucket[c] += 1;
6272 }
6273}
6274
6275fn final_sorting_rtl_step(
6276 t: &[u16],
6277 sa: &mut [SaSint],
6278 induction_bucket: &mut [SaSint],
6279 index: usize,
6280 gsa: bool,
6281) {
6282 let mut p = sa[index];
6283 sa[index] = p & SAINT_MAX;
6284 if p > 0 && (!gsa || t[(p - 1) as usize] > 0) {
6285 p -= 1;
6286 let c = t[p as usize] as usize;
6287 let mark = if t[(p - SaSint::from(p > 0)) as usize] > t[p as usize] {
6288 SAINT_MIN
6289 } else {
6290 0
6291 };
6292 induction_bucket[c] -= 1;
6293 sa[induction_bucket[c] as usize] = p | mark;
6294 }
6295}
6296
6297fn final_bwt_scan_left_to_right_16u(
6298 t: &[u16],
6299 sa: &mut [SaSint],
6300 induction_bucket: &mut [SaSint],
6301 omp_block_start: SaSint,
6302 omp_block_size: SaSint,
6303) {
6304 let mut i = omp_block_start as isize;
6305 let mut j = (omp_block_start + omp_block_size - 64 - 1) as isize;
6306 while i < j {
6307 final_bwt_ltr_step(t, sa, induction_bucket, i as usize);
6308 final_bwt_ltr_step(t, sa, induction_bucket, (i + 1) as usize);
6309 i += 2;
6310 }
6311 j += 64 + 1;
6312 while i < j {
6313 final_bwt_ltr_step(t, sa, induction_bucket, i as usize);
6314 i += 1;
6315 }
6316}
6317
6318fn final_bwt_scan_right_to_left_16u(
6319 t: &[u16],
6320 sa: &mut [SaSint],
6321 induction_bucket: &mut [SaSint],
6322 omp_block_start: SaSint,
6323 omp_block_size: SaSint,
6324) -> SaSint {
6325 let mut index = -1;
6326 let mut i = (omp_block_start + omp_block_size - 1) as isize;
6327 let mut j = (omp_block_start + 64 + 1) as isize;
6328 while i >= j {
6329 final_bwt_rtl_step(t, sa, induction_bucket, i as usize, &mut index);
6330 final_bwt_rtl_step(t, sa, induction_bucket, (i - 1) as usize, &mut index);
6331 i -= 2;
6332 }
6333 j -= 64 + 1;
6334 while i >= j {
6335 final_bwt_rtl_step(t, sa, induction_bucket, i as usize, &mut index);
6336 i -= 1;
6337 }
6338 index
6339}
6340
6341fn final_bwt_aux_scan_left_to_right_16u(
6342 t: &[u16],
6343 sa: &mut [SaSint],
6344 rm: SaSint,
6345 i_sample: &mut [SaSint],
6346 induction_bucket: &mut [SaSint],
6347 omp_block_start: SaSint,
6348 omp_block_size: SaSint,
6349) {
6350 let mut i = omp_block_start as isize;
6351 let mut j = (omp_block_start + omp_block_size - 64 - 1) as isize;
6352 while i < j {
6353 final_bwt_aux_ltr_step(t, sa, rm, i_sample, induction_bucket, i as usize);
6354 final_bwt_aux_ltr_step(t, sa, rm, i_sample, induction_bucket, (i + 1) as usize);
6355 i += 2;
6356 }
6357 j += 64 + 1;
6358 while i < j {
6359 final_bwt_aux_ltr_step(t, sa, rm, i_sample, induction_bucket, i as usize);
6360 i += 1;
6361 }
6362}
6363
6364fn final_bwt_aux_scan_right_to_left_16u(
6365 t: &[u16],
6366 sa: &mut [SaSint],
6367 rm: SaSint,
6368 i_sample: &mut [SaSint],
6369 induction_bucket: &mut [SaSint],
6370 omp_block_start: SaSint,
6371 omp_block_size: SaSint,
6372) {
6373 let mut i = (omp_block_start + omp_block_size - 1) as isize;
6374 let mut j = (omp_block_start + 64 + 1) as isize;
6375 while i >= j {
6376 final_bwt_aux_rtl_step(t, sa, rm, i_sample, induction_bucket, i as usize);
6377 final_bwt_aux_rtl_step(t, sa, rm, i_sample, induction_bucket, (i - 1) as usize);
6378 i -= 2;
6379 }
6380 j -= 64 + 1;
6381 while i >= j {
6382 final_bwt_aux_rtl_step(t, sa, rm, i_sample, induction_bucket, i as usize);
6383 i -= 1;
6384 }
6385}
6386
6387fn renumber_lms_suffixes_16u(
6388 sa: &mut [SaSint],
6389 m: SaSint,
6390 mut name: SaSint,
6391 omp_block_start: SaSint,
6392 omp_block_size: SaSint,
6393) -> SaSint {
6394 let mut i = omp_block_start as isize;
6395 let mut j = (omp_block_start + omp_block_size - 64 - 3) as isize;
6396 while i < j {
6397 let p0 = sa[i as usize];
6398 sa[m as usize + ((p0 & SAINT_MAX) >> 1) as usize] = name | SAINT_MIN;
6399 name += SaSint::from(p0 < 0);
6400
6401 let p1 = sa[(i + 1) as usize];
6402 sa[m as usize + ((p1 & SAINT_MAX) >> 1) as usize] = name | SAINT_MIN;
6403 name += SaSint::from(p1 < 0);
6404
6405 let p2 = sa[(i + 2) as usize];
6406 sa[m as usize + ((p2 & SAINT_MAX) >> 1) as usize] = name | SAINT_MIN;
6407 name += SaSint::from(p2 < 0);
6408
6409 let p3 = sa[(i + 3) as usize];
6410 sa[m as usize + ((p3 & SAINT_MAX) >> 1) as usize] = name | SAINT_MIN;
6411 name += SaSint::from(p3 < 0);
6412
6413 i += 4;
6414 }
6415
6416 j += 64 + 3;
6417 while i < j {
6418 let p = sa[i as usize];
6419 sa[m as usize + ((p & SAINT_MAX) >> 1) as usize] = name | SAINT_MIN;
6420 name += SaSint::from(p < 0);
6421 i += 1;
6422 }
6423
6424 name
6425}
6426
6427fn renumber_lms_suffixes_16u_omp(
6428 sa: &mut [SaSint],
6429 m: SaSint,
6430 threads: SaSint,
6431 thread_state: &mut [ThreadState],
6432) -> SaSint {
6433 if threads == 1 || m < 65_536 || thread_state.is_empty() {
6434 return renumber_lms_suffixes_16u(sa, m, 0, 0, m);
6435 }
6436
6437 let thread_count = usize::try_from(threads)
6438 .expect("threads must be non-negative")
6439 .min(thread_state.len());
6440 let block_stride = (m / thread_count as SaSint) & !15;
6441
6442 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
6443 let block_start = thread as SaSint * block_stride;
6444 let block_size = if thread + 1 < thread_count {
6445 block_stride
6446 } else {
6447 m - block_start
6448 };
6449 state.count = count_negative_marked_suffixes(sa, block_start, block_size);
6450 }
6451
6452 let mut name = 0;
6453 for thread in 0..thread_count {
6454 let block_start = thread as SaSint * block_stride;
6455 let block_size = if thread + 1 < thread_count {
6456 block_stride
6457 } else {
6458 m - block_start
6459 };
6460 renumber_lms_suffixes_16u(sa, m, name, block_start, block_size);
6461 name += thread_state[thread].count;
6462 }
6463
6464 name
6465}
6466
6467fn gather_marked_lms_suffixes(
6468 sa: &mut [SaSint],
6469 m: SaSint,
6470 mut l: isize,
6471 omp_block_start: isize,
6472 omp_block_size: isize,
6473) -> isize {
6474 if omp_block_size <= 0 {
6475 return l;
6476 }
6477
6478 l -= 1;
6479 let mut i = m as isize + omp_block_start + omp_block_size - 1;
6480 let mut j = m as isize + omp_block_start + 3;
6481 while i >= j {
6482 let s0 = sa[i as usize];
6483 sa[l as usize] = s0 & SAINT_MAX;
6484 l -= isize::from(s0 < 0);
6485
6486 let s1 = sa[(i - 1) as usize];
6487 sa[l as usize] = s1 & SAINT_MAX;
6488 l -= isize::from(s1 < 0);
6489
6490 let s2 = sa[(i - 2) as usize];
6491 sa[l as usize] = s2 & SAINT_MAX;
6492 l -= isize::from(s2 < 0);
6493
6494 let s3 = sa[(i - 3) as usize];
6495 sa[l as usize] = s3 & SAINT_MAX;
6496 l -= isize::from(s3 < 0);
6497
6498 i -= 4;
6499 }
6500
6501 j -= 3;
6502 while i >= j {
6503 let s = sa[i as usize];
6504 sa[l as usize] = s & SAINT_MAX;
6505 l -= isize::from(s < 0);
6506 i -= 1;
6507 }
6508
6509 l + 1
6510}
6511
6512fn gather_marked_lms_suffixes_omp(
6513 sa: &mut [SaSint],
6514 n: SaSint,
6515 m: SaSint,
6516 fs: SaSint,
6517 threads: SaSint,
6518 thread_state: &mut [ThreadState],
6519) {
6520 let half_n = n >> 1;
6521 if threads == 1 || n < 131_072 || thread_state.is_empty() {
6522 let _ = gather_marked_lms_suffixes(sa, m, (n + fs) as isize, 0, half_n as isize);
6523 return;
6524 }
6525
6526 let thread_count = usize::try_from(threads)
6527 .expect("threads must be non-negative")
6528 .min(thread_state.len());
6529 let block_stride = (half_n / thread_count as SaSint) & !15;
6530
6531 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
6532 let block_start = thread as SaSint * block_stride;
6533 let block_size = if thread + 1 < thread_count {
6534 block_stride
6535 } else {
6536 half_n - block_start
6537 };
6538 let local_end = if thread + 1 < thread_count {
6539 m + block_start + block_size
6540 } else {
6541 n + fs
6542 } as isize;
6543 let gathered_position =
6544 gather_marked_lms_suffixes(sa, m, local_end, block_start as isize, block_size as isize);
6545 state.position = gathered_position as SaSint;
6546 state.count = (local_end - gathered_position) as SaSint;
6547 }
6548
6549 let mut position = (n + fs) as isize;
6550 for thread in (0..thread_count).rev() {
6551 let count =
6552 usize::try_from(thread_state[thread].count).expect("count must be non-negative");
6553 position -= thread_state[thread].count as isize;
6554 if thread + 1 != thread_count && count > 0 {
6555 let src = usize::try_from(thread_state[thread].position)
6556 .expect("position must be non-negative");
6557 let dst = position as usize;
6558 sa.copy_within(src..src + count, dst);
6559 }
6560 }
6561}
6562
6563fn renumber_and_gather_lms_suffixes_omp(
6564 sa: &mut [SaSint],
6565 n: SaSint,
6566 m: SaSint,
6567 fs: SaSint,
6568 threads: SaSint,
6569 thread_state: &mut [ThreadState],
6570) -> SaSint {
6571 let m_usize = m as usize;
6572 let half_n = (n >> 1) as usize;
6573 sa[m_usize..m_usize + half_n].fill(0);
6574
6575 let name = renumber_lms_suffixes_16u_omp(sa, m, threads, thread_state);
6576 if name < m {
6577 gather_marked_lms_suffixes_omp(sa, n, m, fs, threads, thread_state);
6578 } else {
6579 for item in &mut sa[..m_usize] {
6580 *item &= SAINT_MAX;
6581 }
6582 }
6583
6584 name
6585}
6586
6587fn reconstruct_lms_suffixes(
6588 sa: &mut [SaSint],
6589 n: SaSint,
6590 m: SaSint,
6591 omp_block_start: isize,
6592 omp_block_size: isize,
6593) {
6594 if omp_block_size <= 0 {
6595 return;
6596 }
6597
6598 let base = (n - m) as usize;
6599 let mut i = omp_block_start;
6600 let mut j = omp_block_start + omp_block_size - 64 - 3;
6601 while i < j {
6602 let iu = i as usize;
6603 let s0 = sa[iu] as usize;
6604 let s1 = sa[iu + 1] as usize;
6605 let s2 = sa[iu + 2] as usize;
6606 let s3 = sa[iu + 3] as usize;
6607 sa[iu] = sa[base + s0];
6608 sa[iu + 1] = sa[base + s1];
6609 sa[iu + 2] = sa[base + s2];
6610 sa[iu + 3] = sa[base + s3];
6611 i += 4;
6612 }
6613
6614 j += 64 + 3;
6615 while i < j {
6616 let iu = i as usize;
6617 let s = sa[iu] as usize;
6618 sa[iu] = sa[base + s];
6619 i += 1;
6620 }
6621}
6622
6623fn reconstruct_lms_suffixes_omp(sa: &mut [SaSint], n: SaSint, m: SaSint, threads: SaSint) {
6624 if threads == 1 || m < 65_536 {
6625 reconstruct_lms_suffixes(sa, n, m, 0, m as isize);
6626 return;
6627 }
6628
6629 let thread_count = threads as usize;
6630 let block_stride = (m / threads) & !15;
6631 for thread in 0..thread_count {
6632 let block_start = thread as SaSint * block_stride;
6633 let block_size = if thread + 1 < thread_count {
6634 block_stride
6635 } else {
6636 m - block_start
6637 };
6638 reconstruct_lms_suffixes(sa, n, m, block_start as isize, block_size as isize);
6639 }
6640}
6641
6642fn renumber_distinct_lms_suffixes_32s_4k(
6643 sa: &mut [SaSint],
6644 m: SaSint,
6645 mut name: SaSint,
6646 omp_block_start: isize,
6647 omp_block_size: isize,
6648) -> SaSint {
6649 if omp_block_size <= 0 {
6650 return name;
6651 }
6652
6653 let m_usize = m as usize;
6654 let start = omp_block_start as usize;
6655 let size = omp_block_size as usize;
6656 let (sa_head, sam) = sa.split_at_mut(m_usize);
6657 let mut i = start;
6658 let mut j = start + size.saturating_sub(64 + 3);
6659 let mut p3 = 0;
6660
6661 while i < j {
6662 let p0 = sa_head[i];
6663 sa_head[i] = p0 & SAINT_MAX;
6664 sam[(sa_head[i] >> 1) as usize] = name | (p0 & p3 & SAINT_MIN);
6665 name += SaSint::from(p0 < 0);
6666
6667 let p1 = sa_head[i + 1];
6668 sa_head[i + 1] = p1 & SAINT_MAX;
6669 sam[(sa_head[i + 1] >> 1) as usize] = name | (p1 & p0 & SAINT_MIN);
6670 name += SaSint::from(p1 < 0);
6671
6672 let p2 = sa_head[i + 2];
6673 sa_head[i + 2] = p2 & SAINT_MAX;
6674 sam[(sa_head[i + 2] >> 1) as usize] = name | (p2 & p1 & SAINT_MIN);
6675 name += SaSint::from(p2 < 0);
6676
6677 p3 = sa_head[i + 3];
6678 sa_head[i + 3] = p3 & SAINT_MAX;
6679 sam[(sa_head[i + 3] >> 1) as usize] = name | (p3 & p2 & SAINT_MIN);
6680 name += SaSint::from(p3 < 0);
6681
6682 i += 4;
6683 }
6684
6685 j = start + size;
6686 while i < j {
6687 let p2 = p3;
6688 p3 = sa_head[i];
6689 sa_head[i] = p3 & SAINT_MAX;
6690 sam[(sa_head[i] >> 1) as usize] = name | (p3 & p2 & SAINT_MIN);
6691 name += SaSint::from(p3 < 0);
6692 i += 1;
6693 }
6694
6695 name
6696}
6697
6698fn mark_distinct_lms_suffixes_32s(
6699 sa: &mut [SaSint],
6700 m: SaSint,
6701 omp_block_start: isize,
6702 omp_block_size: isize,
6703) {
6704 if omp_block_size <= 0 {
6705 return;
6706 }
6707
6708 let mut i = m as usize + omp_block_start as usize;
6709 let mut j = i + (omp_block_size as usize).saturating_sub(3);
6710 let mut p3 = 0;
6711 while i < j {
6712 let mut p0 = sa[i];
6713 sa[i] = p0 & (p3 | SAINT_MAX);
6714 p0 = if p0 == 0 { p3 } else { p0 };
6715
6716 let mut p1 = sa[i + 1];
6717 sa[i + 1] = p1 & (p0 | SAINT_MAX);
6718 p1 = if p1 == 0 { p0 } else { p1 };
6719
6720 let mut p2 = sa[i + 2];
6721 sa[i + 2] = p2 & (p1 | SAINT_MAX);
6722 p2 = if p2 == 0 { p1 } else { p2 };
6723
6724 p3 = sa[i + 3];
6725 sa[i + 3] = p3 & (p2 | SAINT_MAX);
6726 p3 = if p3 == 0 { p2 } else { p3 };
6727 i += 4;
6728 }
6729
6730 j = m as usize + omp_block_start as usize + omp_block_size as usize;
6731 while i < j {
6732 let p2 = p3;
6733 p3 = sa[i];
6734 sa[i] = p3 & (p2 | SAINT_MAX);
6735 p3 = if p3 == 0 { p2 } else { p3 };
6736 i += 1;
6737 }
6738}
6739
6740fn clamp_lms_suffixes_length_32s(
6741 sa: &mut [SaSint],
6742 m: SaSint,
6743 omp_block_start: isize,
6744 omp_block_size: isize,
6745) {
6746 if omp_block_size <= 0 {
6747 return;
6748 }
6749
6750 let mut i = m as usize + omp_block_start as usize;
6751 let mut j = i + (omp_block_size as usize).saturating_sub(3);
6752 while i < j {
6753 let s0 = sa[i];
6754 sa[i] = if s0 < 0 { s0 } else { 0 } & SAINT_MAX;
6755
6756 let s1 = sa[i + 1];
6757 sa[i + 1] = if s1 < 0 { s1 } else { 0 } & SAINT_MAX;
6758
6759 let s2 = sa[i + 2];
6760 sa[i + 2] = if s2 < 0 { s2 } else { 0 } & SAINT_MAX;
6761
6762 let s3 = sa[i + 3];
6763 sa[i + 3] = if s3 < 0 { s3 } else { 0 } & SAINT_MAX;
6764
6765 i += 4;
6766 }
6767
6768 j = m as usize + omp_block_start as usize + omp_block_size as usize;
6769 while i < j {
6770 let s = sa[i];
6771 sa[i] = if s < 0 { s } else { 0 } & SAINT_MAX;
6772 i += 1;
6773 }
6774}
6775
6776fn renumber_distinct_lms_suffixes_32s_4k_omp(
6777 sa: &mut [SaSint],
6778 m: SaSint,
6779 threads: SaSint,
6780 thread_state: &mut [ThreadState],
6781) -> SaSint {
6782 if threads == 1 || m < 65_536 || thread_state.is_empty() {
6783 return renumber_distinct_lms_suffixes_32s_4k(sa, m, 1, 0, m as isize) - 1;
6784 }
6785
6786 let thread_count = usize::try_from(threads)
6787 .expect("threads must be non-negative")
6788 .min(thread_state.len());
6789 let block_stride = (m / thread_count as SaSint) & !15;
6790
6791 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
6792 let block_start = thread as SaSint * block_stride;
6793 let block_size = if thread + 1 < thread_count {
6794 block_stride
6795 } else {
6796 m - block_start
6797 };
6798 state.count = count_negative_marked_suffixes(sa, block_start, block_size);
6799 }
6800
6801 let mut count = 1;
6802 for thread in 0..thread_count {
6803 let block_start = thread as SaSint * block_stride;
6804 let block_size = if thread + 1 < thread_count {
6805 block_stride
6806 } else {
6807 m - block_start
6808 };
6809 renumber_distinct_lms_suffixes_32s_4k(
6810 sa,
6811 m,
6812 count,
6813 block_start as isize,
6814 block_size as isize,
6815 );
6816 count += thread_state[thread].count;
6817 }
6818
6819 count - 1
6820}
6821
6822fn mark_distinct_lms_suffixes_32s_omp(sa: &mut [SaSint], n: SaSint, m: SaSint, threads: SaSint) {
6823 let half_n = n >> 1;
6824 if threads == 1 || n < 131_072 {
6825 mark_distinct_lms_suffixes_32s(sa, m, 0, half_n as isize);
6826 return;
6827 }
6828
6829 let thread_count = threads as usize;
6830 let block_stride = (half_n / threads) & !15;
6831 for thread in 0..thread_count {
6832 let block_start = thread as SaSint * block_stride;
6833 let block_size = if thread + 1 < thread_count {
6834 block_stride
6835 } else {
6836 half_n - block_start
6837 };
6838 mark_distinct_lms_suffixes_32s(sa, m, block_start as isize, block_size as isize);
6839 }
6840}
6841
6842fn clamp_lms_suffixes_length_32s_omp(sa: &mut [SaSint], n: SaSint, m: SaSint, threads: SaSint) {
6843 let half_n = n >> 1;
6844 if threads == 1 || n < 131_072 {
6845 clamp_lms_suffixes_length_32s(sa, m, 0, half_n as isize);
6846 return;
6847 }
6848
6849 let thread_count = threads as usize;
6850 let block_stride = (half_n / threads) & !15;
6851 for thread in 0..thread_count {
6852 let block_start = thread as SaSint * block_stride;
6853 let block_size = if thread + 1 < thread_count {
6854 block_stride
6855 } else {
6856 half_n - block_start
6857 };
6858 clamp_lms_suffixes_length_32s(sa, m, block_start as isize, block_size as isize);
6859 }
6860}
6861
6862fn renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(
6863 sa: &mut [SaSint],
6864 n: SaSint,
6865 m: SaSint,
6866 threads: SaSint,
6867 thread_state: &mut [ThreadState],
6868) -> SaSint {
6869 let m_usize = m as usize;
6870 let half_n = (n >> 1) as usize;
6871 sa[m_usize..m_usize + half_n].fill(0);
6872
6873 let name = renumber_distinct_lms_suffixes_32s_4k_omp(sa, m, threads, thread_state);
6874 if name < m {
6875 mark_distinct_lms_suffixes_32s_omp(sa, n, m, threads);
6876 }
6877
6878 name
6879}
6880
6881fn renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(
6882 t: &[SaSint],
6883 sa: &mut [SaSint],
6884 n: SaSint,
6885 m: SaSint,
6886 threads: SaSint,
6887) -> SaSint {
6888 let m_usize = m as usize;
6889 let n_usize = n as usize;
6890
6891 gather_lms_suffixes_32s(t, sa, n);
6892 sa[m_usize..n_usize - m_usize].fill(0);
6893
6894 let mut i = n - m;
6895 let mut j = n - 1 - 64 - 3;
6896 while i < j {
6897 let s0 = (sa[i as usize] as SaUint >> 1) as usize;
6898 let s1 = (sa[(i + 1) as usize] as SaUint >> 1) as usize;
6899 let s2 = (sa[(i + 2) as usize] as SaUint >> 1) as usize;
6900 let s3 = (sa[(i + 3) as usize] as SaUint >> 1) as usize;
6901 sa[m_usize + s0] = sa[(i + 1) as usize] - sa[i as usize] + 1 + SAINT_MIN;
6902 sa[m_usize + s1] = sa[(i + 2) as usize] - sa[(i + 1) as usize] + 1 + SAINT_MIN;
6903 sa[m_usize + s2] = sa[(i + 3) as usize] - sa[(i + 2) as usize] + 1 + SAINT_MIN;
6904 sa[m_usize + s3] = sa[(i + 4) as usize] - sa[(i + 3) as usize] + 1 + SAINT_MIN;
6905 i += 4;
6906 }
6907
6908 j += 64 + 3;
6909 while i < j {
6910 let s = (sa[i as usize] as SaUint >> 1) as usize;
6911 sa[m_usize + s] = sa[(i + 1) as usize] - sa[i as usize] + 1 + SAINT_MIN;
6912 i += 1;
6913 }
6914
6915 let tail = (sa[n_usize - 1] as SaUint >> 1) as usize;
6916 sa[m_usize + tail] = 1 + SAINT_MIN;
6917
6918 clamp_lms_suffixes_length_32s_omp(sa, n, m, threads);
6919
6920 let mut name = 1;
6921 if m_usize > 0 {
6922 let mut i = 1usize;
6923 let mut j = m_usize.saturating_sub(64 + 1);
6924 let mut p = sa[0] as usize;
6925 let mut plen = sa[m_usize + (p >> 1)];
6926 let mut pdiff = SAINT_MIN;
6927
6928 while i < j {
6929 let q = sa[i] as usize;
6930 let qlen = sa[m_usize + (q >> 1)];
6931 let mut qdiff = SAINT_MIN;
6932 if plen == qlen {
6933 let mut l = 0;
6934 while l < qlen as usize {
6935 if t[p + l] != t[q + l] {
6936 break;
6937 }
6938 l += 1;
6939 }
6940 qdiff = ((l as SaSint) - qlen) & SAINT_MIN;
6941 }
6942 sa[m_usize + (p >> 1)] = name | (pdiff & qdiff);
6943 name += SaSint::from(qdiff < 0);
6944
6945 p = sa[i + 1] as usize;
6946 plen = sa[m_usize + (p >> 1)];
6947 pdiff = SAINT_MIN;
6948 if qlen == plen {
6949 let mut l = 0;
6950 while l < plen as usize {
6951 if t[q + l] != t[p + l] {
6952 break;
6953 }
6954 l += 1;
6955 }
6956 pdiff = ((l as SaSint) - plen) & SAINT_MIN;
6957 }
6958 sa[m_usize + (q >> 1)] = name | (qdiff & pdiff);
6959 name += SaSint::from(pdiff < 0);
6960 i += 2;
6961 }
6962
6963 j = m_usize;
6964 while i < j {
6965 let q = sa[i] as usize;
6966 let qlen = sa[m_usize + (q >> 1)];
6967 let mut qdiff = SAINT_MIN;
6968 if plen == qlen {
6969 let mut l = 0;
6970 while l < plen as usize {
6971 if t[p + l] != t[q + l] {
6972 break;
6973 }
6974 l += 1;
6975 }
6976 qdiff = ((l as SaSint) - plen) & SAINT_MIN;
6977 }
6978 sa[m_usize + (p >> 1)] = name | (pdiff & qdiff);
6979 name += SaSint::from(qdiff < 0);
6980 p = q;
6981 plen = qlen;
6982 pdiff = qdiff;
6983 i += 1;
6984 }
6985
6986 sa[m_usize + (p >> 1)] = name | pdiff;
6987 name += 1;
6988 }
6989
6990 if name <= m {
6991 mark_distinct_lms_suffixes_32s_omp(sa, n, m, threads);
6992 }
6993
6994 name - 1
6995}
6996
6997fn renumber_unique_and_nonunique_lms_suffixes_32s(
6998 t: &mut [SaSint],
6999 sa: &mut [SaSint],
7000 m: SaSint,
7001 mut f: SaSint,
7002 omp_block_start: isize,
7003 omp_block_size: isize,
7004) -> SaSint {
7005 if omp_block_size <= 0 {
7006 return f;
7007 }
7008
7009 let m_usize = m as usize;
7010 let (sa_head, sam) = sa.split_at_mut(m_usize);
7011 let mut i = omp_block_start;
7012 let mut j = omp_block_start + omp_block_size - 128 - 3;
7013 while i < j {
7014 for offset in 0..4 {
7015 let idx = (i + offset) as usize;
7016 let p = sa_head[idx] as SaUint;
7017 let mut s = sam[(p >> 1) as usize];
7018 if s < 0 {
7019 t[p as usize] |= SAINT_MIN;
7020 f += 1;
7021 s = i as SaSint + offset as SaSint + SAINT_MIN + f;
7022 }
7023 sam[(p >> 1) as usize] = s - f;
7024 }
7025 i += 4;
7026 }
7027
7028 j += 128 + 3;
7029 while i < j {
7030 let p = sa_head[i as usize] as SaUint;
7031 let mut s = sam[(p >> 1) as usize];
7032 if s < 0 {
7033 t[p as usize] |= SAINT_MIN;
7034 f += 1;
7035 s = i as SaSint + SAINT_MIN + f;
7036 }
7037 sam[(p >> 1) as usize] = s - f;
7038 i += 1;
7039 }
7040
7041 f
7042}
7043
7044fn compact_unique_and_nonunique_lms_suffixes_32s(
7045 sa: &mut [SaSint],
7046 m: SaSint,
7047 pl: &mut isize,
7048 pr: &mut isize,
7049 omp_block_start: isize,
7050 omp_block_size: isize,
7051) {
7052 if omp_block_size <= 0 {
7053 return;
7054 }
7055
7056 let m_usize = m as usize;
7057 let source: Vec<SaSint> = sa
7058 [m_usize + omp_block_start as usize..m_usize + (omp_block_start + omp_block_size) as usize]
7059 .to_vec();
7060 let mut l = *pl - 1;
7061 let mut r = *pr - 1;
7062
7063 for &p in source.iter().rev() {
7064 sa[l as usize] = p & SAINT_MAX;
7065 l -= isize::from(p < 0);
7066
7067 sa[r as usize] = p.wrapping_sub(1);
7068 r -= isize::from(p > 0);
7069 }
7070
7071 *pl = l + 1;
7072 *pr = r + 1;
7073}
7074
7075fn count_unique_suffixes(
7076 sa: &[SaSint],
7077 m: SaSint,
7078 omp_block_start: isize,
7079 omp_block_size: isize,
7080) -> SaSint {
7081 let base = m as usize;
7082 let start = omp_block_start as usize;
7083 let end = start + omp_block_size as usize;
7084 let mut count = 0;
7085 for i in start..end {
7086 count += SaSint::from(sa[base + ((sa[i] as SaUint) >> 1) as usize] < 0);
7087 }
7088 count
7089}
7090
7091fn renumber_unique_and_nonunique_lms_suffixes_32s_omp(
7092 t: &mut [SaSint],
7093 sa: &mut [SaSint],
7094 m: SaSint,
7095 threads: SaSint,
7096) -> SaSint {
7097 if threads == 1 || m < 65_536 {
7098 return renumber_unique_and_nonunique_lms_suffixes_32s(t, sa, m, 0, 0, m as isize);
7099 }
7100
7101 let thread_count = threads as usize;
7102 let block_stride = (m / threads) & !15;
7103 let mut counts = vec![0; thread_count];
7104
7105 for thread in 0..thread_count {
7106 let block_start = thread as SaSint * block_stride;
7107 let block_size = if thread + 1 < thread_count {
7108 block_stride
7109 } else {
7110 m - block_start
7111 };
7112 counts[thread] = count_unique_suffixes(sa, m, block_start as isize, block_size as isize);
7113 }
7114
7115 let mut f = 0;
7116 for thread in 0..thread_count {
7117 let block_start = thread as SaSint * block_stride;
7118 let block_size = if thread + 1 < thread_count {
7119 block_stride
7120 } else {
7121 m - block_start
7122 };
7123 renumber_unique_and_nonunique_lms_suffixes_32s(
7124 t,
7125 sa,
7126 m,
7127 f,
7128 block_start as isize,
7129 block_size as isize,
7130 );
7131 f += counts[thread];
7132 }
7133
7134 f
7135}
7136
7137fn compact_unique_and_nonunique_lms_suffixes_32s_omp(
7138 sa: &mut [SaSint],
7139 n: SaSint,
7140 m: SaSint,
7141 fs: SaSint,
7142 f: SaSint,
7143 threads: SaSint,
7144) {
7145 let half_n = n >> 1;
7146 if threads == 1 || n < 131_072 || m >= fs {
7147 let mut l = m as isize;
7148 let mut r = (n + fs) as isize;
7149 compact_unique_and_nonunique_lms_suffixes_32s(sa, m, &mut l, &mut r, 0, half_n as isize);
7150 } else {
7151 let thread_count = threads as usize;
7152 let block_stride = (half_n / threads) & !15;
7153 let mut positions = vec![0isize; thread_count];
7154 let mut counts = vec![0isize; thread_count];
7155
7156 for thread in 0..thread_count {
7157 let block_start = thread as SaSint * block_stride;
7158 let block_size = if thread + 1 < thread_count {
7159 block_stride
7160 } else {
7161 half_n - block_start
7162 };
7163 let mut position = (m + half_n + block_start + block_size) as isize;
7164 let mut count = (m + block_start + block_size) as isize;
7165 compact_unique_and_nonunique_lms_suffixes_32s(
7166 sa,
7167 m,
7168 &mut position,
7169 &mut count,
7170 block_start as isize,
7171 block_size as isize,
7172 );
7173 positions[thread] = position;
7174 counts[thread] = count;
7175 }
7176
7177 let mut position = m as isize;
7178 for thread in (0..thread_count).rev() {
7179 let block_end = if thread + 1 < thread_count {
7180 block_stride * (thread as SaSint + 1)
7181 } else {
7182 half_n
7183 };
7184 let count = (m + half_n + block_end) as isize - positions[thread];
7185 if count > 0 {
7186 position -= count;
7187 let src = positions[thread] as usize;
7188 let dst = position as usize;
7189 sa.copy_within(src..src + count as usize, dst);
7190 }
7191 }
7192
7193 let mut position = (n + fs) as isize;
7194 for thread in (0..thread_count).rev() {
7195 let block_end = if thread + 1 < thread_count {
7196 block_stride * (thread as SaSint + 1)
7197 } else {
7198 half_n
7199 };
7200 let count = (m + block_end) as isize - counts[thread];
7201 if count > 0 {
7202 position -= count;
7203 let src = counts[thread] as usize;
7204 let dst = position as usize;
7205 sa.copy_within(src..src + count as usize, dst);
7206 }
7207 }
7208 }
7209
7210 let dst = (n + fs - m) as usize;
7211 let src = (m - f) as usize;
7212 sa.copy_within(src..src + f as usize, dst);
7213}
7214
7215fn compact_lms_suffixes_32s_omp(
7216 t: &mut [SaSint],
7217 sa: &mut [SaSint],
7218 n: SaSint,
7219 m: SaSint,
7220 fs: SaSint,
7221 threads: SaSint,
7222) -> SaSint {
7223 let f = renumber_unique_and_nonunique_lms_suffixes_32s_omp(t, sa, m, threads);
7224 compact_unique_and_nonunique_lms_suffixes_32s_omp(sa, n, m, fs, f, threads);
7225 f
7226}
7227
7228fn merge_unique_lms_suffixes_32s(
7229 t: &mut [SaSint],
7230 sa: &mut [SaSint],
7231 n: SaSint,
7232 m: SaSint,
7233 l: isize,
7234 omp_block_start: isize,
7235 omp_block_size: isize,
7236) {
7237 let mut src_index = (n as isize - m as isize - 1 + l) as usize;
7238 let mut tmp = sa[src_index] as isize;
7239 src_index += 1;
7240
7241 let mut i = omp_block_start;
7242 let mut j = omp_block_start + omp_block_size - 6;
7243 while i < j {
7244 let iu = i as usize;
7245
7246 let c0 = t[iu];
7247 if c0 < 0 {
7248 t[iu] = c0 & SAINT_MAX;
7249 sa[tmp as usize] = i as SaSint;
7250 i += 1;
7251 tmp = sa[src_index] as isize;
7252 src_index += 1;
7253 }
7254
7255 let c1 = t[(i + 1) as usize];
7256 if c1 < 0 {
7257 t[(i + 1) as usize] = c1 & SAINT_MAX;
7258 sa[tmp as usize] = i as SaSint + 1;
7259 i += 1;
7260 tmp = sa[src_index] as isize;
7261 src_index += 1;
7262 }
7263
7264 let c2 = t[(i + 2) as usize];
7265 if c2 < 0 {
7266 t[(i + 2) as usize] = c2 & SAINT_MAX;
7267 sa[tmp as usize] = i as SaSint + 2;
7268 i += 1;
7269 tmp = sa[src_index] as isize;
7270 src_index += 1;
7271 }
7272
7273 let c3 = t[(i + 3) as usize];
7274 if c3 < 0 {
7275 t[(i + 3) as usize] = c3 & SAINT_MAX;
7276 sa[tmp as usize] = i as SaSint + 3;
7277 i += 1;
7278 tmp = sa[src_index] as isize;
7279 src_index += 1;
7280 }
7281
7282 i += 4;
7283 }
7284
7285 j += 6;
7286 while i < j {
7287 let c = t[i as usize];
7288 if c < 0 {
7289 t[i as usize] = c & SAINT_MAX;
7290 sa[tmp as usize] = i as SaSint;
7291 i += 1;
7292 tmp = sa[src_index] as isize;
7293 src_index += 1;
7294 }
7295 i += 1;
7296 }
7297}
7298
7299fn merge_nonunique_lms_suffixes_32s(
7300 sa: &mut [SaSint],
7301 n: SaSint,
7302 m: SaSint,
7303 l: isize,
7304 omp_block_start: isize,
7305 omp_block_size: isize,
7306) {
7307 let mut src_index = (n as isize - m as isize - 1 + l) as usize;
7308 let mut tmp = sa[src_index];
7309 src_index += 1;
7310
7311 let mut i = omp_block_start;
7312 let mut j = omp_block_start + omp_block_size - 3;
7313 while i < j {
7314 if sa[i as usize] == 0 {
7315 sa[i as usize] = tmp;
7316 tmp = sa[src_index];
7317 src_index += 1;
7318 }
7319 if sa[(i + 1) as usize] == 0 {
7320 sa[(i + 1) as usize] = tmp;
7321 tmp = sa[src_index];
7322 src_index += 1;
7323 }
7324 if sa[(i + 2) as usize] == 0 {
7325 sa[(i + 2) as usize] = tmp;
7326 tmp = sa[src_index];
7327 src_index += 1;
7328 }
7329 if sa[(i + 3) as usize] == 0 {
7330 sa[(i + 3) as usize] = tmp;
7331 tmp = sa[src_index];
7332 src_index += 1;
7333 }
7334 i += 4;
7335 }
7336
7337 j += 3;
7338 while i < j {
7339 if sa[i as usize] == 0 {
7340 sa[i as usize] = tmp;
7341 tmp = sa[src_index];
7342 src_index += 1;
7343 }
7344 i += 1;
7345 }
7346}
7347
7348fn merge_unique_lms_suffixes_32s_omp(
7349 t: &mut [SaSint],
7350 sa: &mut [SaSint],
7351 n: SaSint,
7352 m: SaSint,
7353 threads: SaSint,
7354) {
7355 if threads == 1 || n < 65_536 {
7356 merge_unique_lms_suffixes_32s(t, sa, n, m, 0, 0, n as isize);
7357 return;
7358 }
7359
7360 let thread_count = threads as usize;
7361 let block_stride = (n / threads) & !15;
7362 let mut counts = vec![0; thread_count];
7363
7364 for thread in 0..thread_count {
7365 let block_start = thread as SaSint * block_stride;
7366 let block_size = if thread + 1 < thread_count {
7367 block_stride
7368 } else {
7369 n - block_start
7370 };
7371 counts[thread] = count_negative_marked_suffixes(t, block_start, block_size);
7372 }
7373
7374 let mut count = 0;
7375 for thread in 0..thread_count {
7376 let block_start = thread as SaSint * block_stride;
7377 let block_size = if thread + 1 < thread_count {
7378 block_stride
7379 } else {
7380 n - block_start
7381 };
7382 merge_unique_lms_suffixes_32s(
7383 t,
7384 sa,
7385 n,
7386 m,
7387 count as isize,
7388 block_start as isize,
7389 block_size as isize,
7390 );
7391 count += counts[thread];
7392 }
7393}
7394
7395fn merge_nonunique_lms_suffixes_32s_omp(
7396 sa: &mut [SaSint],
7397 n: SaSint,
7398 m: SaSint,
7399 f: SaSint,
7400 threads: SaSint,
7401) {
7402 if threads == 1 || m < 65_536 {
7403 merge_nonunique_lms_suffixes_32s(sa, n, m, f as isize, 0, m as isize);
7404 return;
7405 }
7406
7407 let thread_count = threads as usize;
7408 let block_stride = (m / threads) & !15;
7409 let mut counts = vec![0; thread_count];
7410
7411 for thread in 0..thread_count {
7412 let block_start = thread as SaSint * block_stride;
7413 let block_size = if thread + 1 < thread_count {
7414 block_stride
7415 } else {
7416 m - block_start
7417 };
7418 counts[thread] = count_zero_marked_suffixes(sa, block_start, block_size);
7419 }
7420
7421 let mut count = f;
7422 for thread in 0..thread_count {
7423 let block_start = thread as SaSint * block_stride;
7424 let block_size = if thread + 1 < thread_count {
7425 block_stride
7426 } else {
7427 m - block_start
7428 };
7429 merge_nonunique_lms_suffixes_32s(
7430 sa,
7431 n,
7432 m,
7433 count as isize,
7434 block_start as isize,
7435 block_size as isize,
7436 );
7437 count += counts[thread];
7438 }
7439}
7440
7441fn merge_compacted_lms_suffixes_32s_omp(
7442 t: &mut [SaSint],
7443 sa: &mut [SaSint],
7444 n: SaSint,
7445 m: SaSint,
7446 f: SaSint,
7447 threads: SaSint,
7448) {
7449 merge_unique_lms_suffixes_32s_omp(t, sa, n, m, threads);
7450 merge_nonunique_lms_suffixes_32s_omp(sa, n, m, f, threads);
7451}
7452
7453fn reconstruct_compacted_lms_suffixes_32s_2k_omp(
7454 t: &mut [SaSint],
7455 sa: &mut [SaSint],
7456 n: SaSint,
7457 k: SaSint,
7458 m: SaSint,
7459 fs: SaSint,
7460 f: SaSint,
7461 buckets: &mut [SaSint],
7462 local_buckets: SaSint,
7463 threads: SaSint,
7464 thread_state: &mut [ThreadState],
7465) {
7466 if f > 0 {
7467 let dst = (n - m - 1) as usize;
7468 let src = (n + fs - m) as usize;
7469 sa.copy_within(src..src + f as usize, dst);
7470
7471 count_and_gather_compacted_lms_suffixes_32s_2k_omp(
7472 t,
7473 sa,
7474 n,
7475 k,
7476 buckets,
7477 local_buckets,
7478 threads,
7479 thread_state,
7480 );
7481 reconstruct_lms_suffixes_omp(sa, n, m - f, threads);
7482
7483 let dst = (n - m - 1 + f) as usize;
7484 sa.copy_within(0..(m - f) as usize, dst);
7485 sa[..m as usize].fill(0);
7486
7487 merge_compacted_lms_suffixes_32s_omp(t, sa, n, m, f, threads);
7488 } else {
7489 count_and_gather_lms_suffixes_32s_2k(t, sa, n, k, buckets, 0, n as isize);
7490 reconstruct_lms_suffixes_omp(sa, n, m, threads);
7491 }
7492}
7493
7494fn reconstruct_compacted_lms_suffixes_32s_1k_omp(
7495 t: &mut [SaSint],
7496 sa: &mut [SaSint],
7497 n: SaSint,
7498 m: SaSint,
7499 fs: SaSint,
7500 f: SaSint,
7501 threads: SaSint,
7502) {
7503 if f > 0 {
7504 let dst = (n - m - 1) as usize;
7505 let src = (n + fs - m) as usize;
7506 sa.copy_within(src..src + f as usize, dst);
7507
7508 gather_compacted_lms_suffixes_32s(t, sa, n);
7509 reconstruct_lms_suffixes_omp(sa, n, m - f, threads);
7510
7511 let dst = (n - m - 1 + f) as usize;
7512 sa.copy_within(0..(m - f) as usize, dst);
7513 sa[..m as usize].fill(0);
7514
7515 merge_compacted_lms_suffixes_32s_omp(t, sa, n, m, f, threads);
7516 } else {
7517 gather_lms_suffixes_32s(t, sa, n);
7518 reconstruct_lms_suffixes_omp(sa, n, m, threads);
7519 }
7520}
7521
7522fn place_lms_suffixes_interval_16u(
7523 sa: &mut [SaSint],
7524 n: SaSint,
7525 mut m: SaSint,
7526 flags: SaSint,
7527 buckets: &mut [SaSint],
7528) {
7529 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
7530 buckets[7 * ALPHABET_SIZE] -= 1;
7531 }
7532
7533 let mut j = n as isize;
7534 let mut c = ALPHABET_SIZE as isize - 2;
7535 while c >= 0 {
7536 let ci = c as usize;
7537 let l =
7538 buckets[buckets_index2(ci, 1) + buckets_index2(1, 0)] - buckets[buckets_index2(ci, 1)];
7539 if l > 0 {
7540 let i = buckets[7 * ALPHABET_SIZE + ci] as isize;
7541 if j - i > 0 {
7542 sa[i as usize..j as usize].fill(0);
7543 }
7544
7545 m -= l;
7546 j = i - l as isize;
7547 let src = m as usize;
7548 let dst = j as usize;
7549 sa.copy_within(src..src + l as usize, dst);
7550 }
7551 c -= 1;
7552 }
7553
7554 sa[..j as usize].fill(0);
7555
7556 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
7557 buckets[7 * ALPHABET_SIZE] += 1;
7558 }
7559}
7560
7561fn place_lms_suffixes_interval_32s_4k(
7562 sa: &mut [SaSint],
7563 n: SaSint,
7564 k: SaSint,
7565 mut m: SaSint,
7566 buckets: &[SaSint],
7567) {
7568 let bucket_end = &buckets[3 * k as usize..4 * k as usize];
7569 let mut j = n as usize;
7570 let mut c = k - 2;
7571 while c >= 0 {
7572 let cu = c as usize;
7573 let l =
7574 buckets[buckets_index2(cu, 1) + buckets_index2(1, 0)] - buckets[buckets_index2(cu, 1)];
7575 if l > 0 {
7576 let i = bucket_end[cu] as usize;
7577 if j > i {
7578 sa[i..j].fill(0);
7579 }
7580
7581 m -= l;
7582 let dst = i - l as usize;
7583 sa.copy_within(m as usize..m as usize + l as usize, dst);
7584 j = dst;
7585 }
7586 c -= 1;
7587 }
7588
7589 sa[..j].fill(0);
7590}
7591
7592fn place_lms_suffixes_interval_32s_2k(
7593 sa: &mut [SaSint],
7594 n: SaSint,
7595 k: SaSint,
7596 mut m: SaSint,
7597 buckets: &[SaSint],
7598) {
7599 let mut j = n as usize;
7600 if k > 1 {
7601 let mut c = buckets_index2(k as usize - 2, 0) as isize;
7602 while c >= buckets_index2(0, 0) as isize {
7603 let cu = c as usize;
7604 let l = buckets[cu + buckets_index2(1, 1)] - buckets[cu + buckets_index2(0, 1)];
7605 if l > 0 {
7606 let i = buckets[cu] as usize;
7607 if j > i {
7608 sa[i..j].fill(0);
7609 }
7610
7611 m -= l;
7612 let dst = i - l as usize;
7613 sa.copy_within(m as usize..m as usize + l as usize, dst);
7614 j = dst;
7615 }
7616 c -= buckets_index2(1, 0) as isize;
7617 }
7618 }
7619
7620 sa[..j].fill(0);
7621}
7622
7623fn place_lms_suffixes_interval_32s_1k(
7624 t: &[SaSint],
7625 sa: &mut [SaSint],
7626 k: SaSint,
7627 m: SaSint,
7628 buckets: &[SaSint],
7629) {
7630 let mut c = k - 1;
7631 let mut l = buckets[c as usize] as usize;
7632
7633 let mut i = m - 1;
7634 while i >= 0 {
7635 let p = sa[i as usize] as usize;
7636 if t[p] != c {
7637 c = t[p];
7638 let bucket_pos = buckets[c as usize] as usize;
7639 if l > bucket_pos {
7640 sa[bucket_pos..l].fill(0);
7641 }
7642 l = bucket_pos;
7643 }
7644 l -= 1;
7645 sa[l] = p as SaSint;
7646 i -= 1;
7647 }
7648
7649 sa[..l].fill(0);
7650}
7651
7652fn place_lms_suffixes_histogram_32s_6k(
7653 sa: &mut [SaSint],
7654 n: SaSint,
7655 k: SaSint,
7656 mut m: SaSint,
7657 buckets: &[SaSint],
7658) {
7659 let bucket_end = &buckets[5 * k as usize..6 * k as usize];
7660 let mut j = n as usize;
7661 let mut c = k - 2;
7662 while c >= 0 {
7663 let l = buckets[buckets_index4(c as usize, 1)] as usize;
7664 if l > 0 {
7665 let i = bucket_end[c as usize] as usize;
7666 if j > i {
7667 sa[i..j].fill(0);
7668 }
7669 let dst = i - l;
7670 m -= l as SaSint;
7671 sa.copy_within(m as usize..m as usize + l, dst);
7672 j = dst;
7673 }
7674 c -= 1;
7675 }
7676 sa[..j].fill(0);
7677}
7678
7679fn place_lms_suffixes_histogram_32s_4k(
7680 sa: &mut [SaSint],
7681 n: SaSint,
7682 k: SaSint,
7683 mut m: SaSint,
7684 buckets: &[SaSint],
7685) {
7686 let bucket_end = &buckets[3 * k as usize..4 * k as usize];
7687 let mut j = n as usize;
7688 let mut c = k - 2;
7689 while c >= 0 {
7690 let l = buckets[buckets_index2(c as usize, 1)] as usize;
7691 if l > 0 {
7692 let i = bucket_end[c as usize] as usize;
7693 if j > i {
7694 sa[i..j].fill(0);
7695 }
7696 let dst = i - l;
7697 m -= l as SaSint;
7698 sa.copy_within(m as usize..m as usize + l, dst);
7699 j = dst;
7700 }
7701 c -= 1;
7702 }
7703 sa[..j].fill(0);
7704}
7705
7706fn place_lms_suffixes_histogram_32s_2k(
7707 sa: &mut [SaSint],
7708 n: SaSint,
7709 k: SaSint,
7710 mut m: SaSint,
7711 buckets: &[SaSint],
7712) {
7713 let mut j = n as usize;
7714 if k > 1 {
7715 let mut c = buckets_index2(k as usize - 2, 0) as isize;
7716 while c >= buckets_index2(0, 0) as isize {
7717 let cu = c as usize;
7718 let l = buckets[cu + buckets_index2(0, 1)] as usize;
7719 if l > 0 {
7720 let i = buckets[cu] as usize;
7721 if j > i {
7722 sa[i..j].fill(0);
7723 }
7724 let dst = i - l;
7725 m -= l as SaSint;
7726 sa.copy_within(m as usize..m as usize + l, dst);
7727 j = dst;
7728 }
7729 c -= buckets_index2(1, 0) as isize;
7730 }
7731 }
7732 sa[..j].fill(0);
7733}
7734
7735fn final_bwt_scan_left_to_right_16u_block_prepare(
7736 t: &[u16],
7737 sa: &mut [SaSint],
7738 k: SaSint,
7739 buckets: &mut [SaSint],
7740 cache: &mut [ThreadCache],
7741 omp_block_start: SaSint,
7742 omp_block_size: SaSint,
7743) -> SaSint {
7744 buckets[..k as usize].fill(0);
7745 let mut count = 0usize;
7746 for i in omp_block_start as usize..(omp_block_start + omp_block_size) as usize {
7747 let mut p = sa[i];
7748 sa[i] = p & SAINT_MAX;
7749 if p > 0 {
7750 p -= 1;
7751 let c = t[p as usize] as usize;
7752 sa[i] = c as SaSint | SAINT_MIN;
7753 buckets[c] += 1;
7754 cache[count].symbol = c as SaSint;
7755 cache[count].index = p
7756 | ((usize::from(t[(p - SaSint::from(p > 0)) as usize] < t[p as usize]) as SaSint)
7757 << (SAINT_BIT - 1));
7758 count += 1;
7759 }
7760 }
7761 count as SaSint
7762}
7763
7764fn final_sorting_scan_left_to_right_16u_block_prepare(
7765 t: &[u16],
7766 sa: &mut [SaSint],
7767 k: SaSint,
7768 buckets: &mut [SaSint],
7769 cache: &mut [ThreadCache],
7770 omp_block_start: SaSint,
7771 omp_block_size: SaSint,
7772) -> SaSint {
7773 buckets[..k as usize].fill(0);
7774 let mut count = 0usize;
7775 for i in omp_block_start as usize..(omp_block_start + omp_block_size) as usize {
7776 let mut p = sa[i];
7777 sa[i] = p ^ SAINT_MIN;
7778 if p > 0 {
7779 p -= 1;
7780 let c = t[p as usize] as usize;
7781 buckets[c] += 1;
7782 cache[count].symbol = c as SaSint;
7783 cache[count].index = p
7784 | ((usize::from(t[(p - SaSint::from(p > 0)) as usize] < t[p as usize]) as SaSint)
7785 << (SAINT_BIT - 1));
7786 count += 1;
7787 }
7788 }
7789 count as SaSint
7790}
7791
7792fn final_order_scan_left_to_right_16u_block_place(
7793 sa: &mut [SaSint],
7794 buckets: &mut [SaSint],
7795 cache: &[ThreadCache],
7796 count: SaSint,
7797) {
7798 for entry in cache.iter().take(count as usize) {
7799 let c = entry.symbol as usize;
7800 let dst = buckets[c] as usize;
7801 sa[dst] = entry.index;
7802 buckets[c] += 1;
7803 }
7804}
7805
7806fn final_bwt_aux_scan_left_to_right_16u_block_place(
7807 sa: &mut [SaSint],
7808 rm: SaSint,
7809 i_sample: &mut [SaSint],
7810 buckets: &mut [SaSint],
7811 cache: &[ThreadCache],
7812 count: SaSint,
7813) {
7814 for entry in cache.iter().take(count as usize) {
7815 let c = entry.symbol as usize;
7816 let dst = buckets[c] as usize;
7817 sa[dst] = entry.index;
7818 buckets[c] += 1;
7819 let p = entry.index & SAINT_MAX;
7820 if (p & rm) == 0 {
7821 i_sample[(p / (rm + 1)) as usize] = buckets[c];
7822 }
7823 }
7824}
7825
7826fn final_bwt_scan_left_to_right_16u_block_omp(
7827 t: &[u16],
7828 sa: &mut [SaSint],
7829 k: SaSint,
7830 induction_bucket: &mut [SaSint],
7831 block_start: SaSint,
7832 block_size: SaSint,
7833 threads: SaSint,
7834 thread_state: &mut [ThreadState],
7835) {
7836 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
7837 usize::try_from(threads)
7838 .expect("threads must be non-negative")
7839 .min(thread_state.len())
7840 } else {
7841 1
7842 };
7843 if thread_count <= 1 {
7844 final_bwt_scan_left_to_right_16u(t, sa, induction_bucket, block_start, block_size);
7845 return;
7846 }
7847
7848 let k_usize = usize::try_from(k).expect("k must be non-negative");
7849 let block_stride = (block_size / thread_count as SaSint) & !15;
7850
7851 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
7852 let local_start = thread as SaSint * block_stride;
7853 let local_size = if thread + 1 < thread_count {
7854 block_stride
7855 } else {
7856 block_size - local_start
7857 };
7858 state.count = final_bwt_scan_left_to_right_16u_block_prepare(
7859 t,
7860 sa,
7861 k,
7862 &mut state.buckets[..k_usize],
7863 &mut state.cache,
7864 block_start + local_start,
7865 local_size,
7866 );
7867 }
7868
7869 for state in thread_state.iter_mut().take(thread_count) {
7870 for c in 0..k_usize {
7871 let a = induction_bucket[c];
7872 let b = state.buckets[c];
7873 induction_bucket[c] = a + b;
7874 state.buckets[c] = a;
7875 }
7876 }
7877
7878 for state in thread_state.iter_mut().take(thread_count) {
7879 final_order_scan_left_to_right_16u_block_place(
7880 sa,
7881 &mut state.buckets[..k_usize],
7882 &state.cache,
7883 state.count,
7884 );
7885 }
7886}
7887
7888fn final_bwt_aux_scan_left_to_right_16u_block_omp(
7889 t: &[u16],
7890 sa: &mut [SaSint],
7891 k: SaSint,
7892 rm: SaSint,
7893 i_sample: &mut [SaSint],
7894 induction_bucket: &mut [SaSint],
7895 block_start: SaSint,
7896 block_size: SaSint,
7897 threads: SaSint,
7898 thread_state: &mut [ThreadState],
7899) {
7900 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
7901 usize::try_from(threads)
7902 .expect("threads must be non-negative")
7903 .min(thread_state.len())
7904 } else {
7905 1
7906 };
7907 if thread_count <= 1 {
7908 final_bwt_aux_scan_left_to_right_16u(
7909 t,
7910 sa,
7911 rm,
7912 i_sample,
7913 induction_bucket,
7914 block_start,
7915 block_size,
7916 );
7917 return;
7918 }
7919
7920 let k_usize = usize::try_from(k).expect("k must be non-negative");
7921 let block_stride = (block_size / thread_count as SaSint) & !15;
7922
7923 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
7924 let local_start = thread as SaSint * block_stride;
7925 let local_size = if thread + 1 < thread_count {
7926 block_stride
7927 } else {
7928 block_size - local_start
7929 };
7930 state.count = final_bwt_scan_left_to_right_16u_block_prepare(
7931 t,
7932 sa,
7933 k,
7934 &mut state.buckets[..k_usize],
7935 &mut state.cache,
7936 block_start + local_start,
7937 local_size,
7938 );
7939 }
7940
7941 for state in thread_state.iter_mut().take(thread_count) {
7942 for c in 0..k_usize {
7943 let a = induction_bucket[c];
7944 let b = state.buckets[c];
7945 induction_bucket[c] = a + b;
7946 state.buckets[c] = a;
7947 }
7948 }
7949
7950 for state in thread_state.iter_mut().take(thread_count) {
7951 final_bwt_aux_scan_left_to_right_16u_block_place(
7952 sa,
7953 rm,
7954 i_sample,
7955 &mut state.buckets[..k_usize],
7956 &state.cache,
7957 state.count,
7958 );
7959 }
7960}
7961
7962fn final_sorting_scan_left_to_right_16u_block_omp(
7963 t: &[u16],
7964 sa: &mut [SaSint],
7965 k: SaSint,
7966 induction_bucket: &mut [SaSint],
7967 block_start: SaSint,
7968 block_size: SaSint,
7969 threads: SaSint,
7970 thread_state: &mut [ThreadState],
7971) {
7972 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
7973 usize::try_from(threads)
7974 .expect("threads must be non-negative")
7975 .min(thread_state.len())
7976 } else {
7977 1
7978 };
7979 if thread_count <= 1 {
7980 final_sorting_scan_left_to_right_16u(t, sa, induction_bucket, block_start, block_size);
7981 return;
7982 }
7983
7984 let k_usize = usize::try_from(k).expect("k must be non-negative");
7985 let block_stride = (block_size / thread_count as SaSint) & !15;
7986
7987 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
7988 let local_start = thread as SaSint * block_stride;
7989 let local_size = if thread + 1 < thread_count {
7990 block_stride
7991 } else {
7992 block_size - local_start
7993 };
7994 state.count = final_sorting_scan_left_to_right_16u_block_prepare(
7995 t,
7996 sa,
7997 k,
7998 &mut state.buckets[..k_usize],
7999 &mut state.cache,
8000 block_start + local_start,
8001 local_size,
8002 );
8003 }
8004
8005 for state in thread_state.iter_mut().take(thread_count) {
8006 for c in 0..k_usize {
8007 let a = induction_bucket[c];
8008 let b = state.buckets[c];
8009 induction_bucket[c] = a + b;
8010 state.buckets[c] = a;
8011 }
8012 }
8013
8014 for state in thread_state.iter_mut().take(thread_count) {
8015 final_order_scan_left_to_right_16u_block_place(
8016 sa,
8017 &mut state.buckets[..k_usize],
8018 &state.cache,
8019 state.count,
8020 );
8021 }
8022}
8023
8024fn final_bwt_scan_left_to_right_16u_omp(
8025 t: &[u16],
8026 sa: &mut [SaSint],
8027 n: SaSint,
8028 k: SaSint,
8029 induction_bucket: &mut [SaSint],
8030 threads: SaSint,
8031) {
8032 let c = t[(n - 1) as usize] as usize;
8033 let dst = induction_bucket[c] as usize;
8034 induction_bucket[c] += 1;
8035 let mark = if t[(n - 2) as usize] < t[(n - 1) as usize] {
8036 SAINT_MIN
8037 } else {
8038 0
8039 };
8040 sa[dst] = (n - 1) | mark;
8041
8042 if threads == 1 || n < 65536 {
8043 final_bwt_scan_left_to_right_16u(t, sa, induction_bucket, 0, n);
8044 } else {
8045 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8046 let mut block_start = 0;
8047 while block_start < n {
8048 if sa[block_start as usize] == 0 {
8049 block_start += 1;
8050 } else {
8051 let mut block_end =
8052 block_start + threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8053 if block_end > n {
8054 block_end = n;
8055 }
8056 let mut block_scan_end = block_start + 1;
8057 while block_scan_end < block_end && sa[block_scan_end as usize] != 0 {
8058 block_scan_end += 1;
8059 }
8060 let block_size = block_scan_end - block_start;
8061 if block_size < 32 {
8062 while block_start < block_scan_end {
8063 let mut p = sa[block_start as usize];
8064 sa[block_start as usize] = p & SAINT_MAX;
8065 if p > 0 {
8066 p -= 1;
8067 let c = t[p as usize] as usize;
8068 sa[block_start as usize] = c as SaSint | SAINT_MIN;
8069 let dst = induction_bucket[c] as usize;
8070 induction_bucket[c] += 1;
8071 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
8072 SAINT_MIN
8073 } else {
8074 0
8075 };
8076 sa[dst] = p | mark;
8077 }
8078 block_start += 1;
8079 }
8080 } else {
8081 final_bwt_scan_left_to_right_16u_block_omp(
8082 t,
8083 sa,
8084 k,
8085 induction_bucket,
8086 block_start,
8087 block_size,
8088 threads,
8089 &mut thread_state,
8090 );
8091 block_start = block_scan_end;
8092 }
8093 }
8094 }
8095 }
8096}
8097
8098fn final_bwt_aux_scan_left_to_right_16u_omp(
8099 t: &[u16],
8100 sa: &mut [SaSint],
8101 n: SaSint,
8102 k: SaSint,
8103 rm: SaSint,
8104 i_sample: &mut [SaSint],
8105 induction_bucket: &mut [SaSint],
8106 threads: SaSint,
8107) {
8108 let c = t[(n - 1) as usize] as usize;
8109 let dst = induction_bucket[c] as usize;
8110 induction_bucket[c] += 1;
8111 let mark = if t[(n - 2) as usize] < t[(n - 1) as usize] {
8112 SAINT_MIN
8113 } else {
8114 0
8115 };
8116 sa[dst] = (n - 1) | mark;
8117
8118 if ((n - 1) & rm) == 0 {
8119 i_sample[((n - 1) / (rm + 1)) as usize] = induction_bucket[c];
8120 }
8121
8122 if threads == 1 || n < 65536 {
8123 final_bwt_aux_scan_left_to_right_16u(t, sa, rm, i_sample, induction_bucket, 0, n);
8124 } else {
8125 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8126 let mut block_start = 0;
8127 while block_start < n {
8128 if sa[block_start as usize] == 0 {
8129 block_start += 1;
8130 } else {
8131 let mut block_end =
8132 block_start + threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8133 if block_end > n {
8134 block_end = n;
8135 }
8136 let mut block_scan_end = block_start + 1;
8137 while block_scan_end < block_end && sa[block_scan_end as usize] != 0 {
8138 block_scan_end += 1;
8139 }
8140 let block_size = block_scan_end - block_start;
8141 if block_size < 32 {
8142 while block_start < block_scan_end {
8143 let mut p = sa[block_start as usize];
8144 sa[block_start as usize] = p & SAINT_MAX;
8145 if p > 0 {
8146 p -= 1;
8147 let c = t[p as usize] as usize;
8148 sa[block_start as usize] = c as SaSint | SAINT_MIN;
8149 let dst = induction_bucket[c] as usize;
8150 induction_bucket[c] += 1;
8151 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
8152 SAINT_MIN
8153 } else {
8154 0
8155 };
8156 sa[dst] = p | mark;
8157 if (p & rm) == 0 {
8158 i_sample[(p / (rm + 1)) as usize] = induction_bucket[c];
8159 }
8160 }
8161 block_start += 1;
8162 }
8163 } else {
8164 final_bwt_aux_scan_left_to_right_16u_block_omp(
8165 t,
8166 sa,
8167 k,
8168 rm,
8169 i_sample,
8170 induction_bucket,
8171 block_start,
8172 block_size,
8173 threads,
8174 &mut thread_state,
8175 );
8176 block_start = block_scan_end;
8177 }
8178 }
8179 }
8180 }
8181}
8182
8183fn final_sorting_scan_left_to_right_16u_omp(
8184 t: &[u16],
8185 sa: &mut [SaSint],
8186 n: SaSint,
8187 k: SaSint,
8188 induction_bucket: &mut [SaSint],
8189 threads: SaSint,
8190) {
8191 let c = t[(n - 1) as usize] as usize;
8192 let dst = induction_bucket[c] as usize;
8193 induction_bucket[c] += 1;
8194 let mark = if t[(n - 2) as usize] < t[(n - 1) as usize] {
8195 SAINT_MIN
8196 } else {
8197 0
8198 };
8199 sa[dst] = (n - 1) | mark;
8200
8201 if threads == 1 || n < 65536 {
8202 final_sorting_scan_left_to_right_16u(t, sa, induction_bucket, 0, n);
8203 } else {
8204 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8205 let mut block_start = 0;
8206 while block_start < n {
8207 if sa[block_start as usize] == 0 {
8208 block_start += 1;
8209 } else {
8210 let mut block_end =
8211 block_start + threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8212 if block_end > n {
8213 block_end = n;
8214 }
8215 let mut block_scan_end = block_start + 1;
8216 while block_scan_end < block_end && sa[block_scan_end as usize] != 0 {
8217 block_scan_end += 1;
8218 }
8219 let block_size = block_scan_end - block_start;
8220 if block_size < 32 {
8221 while block_start < block_scan_end {
8222 let mut p = sa[block_start as usize];
8223 sa[block_start as usize] = p ^ SAINT_MIN;
8224 if p > 0 {
8225 p -= 1;
8226 let c = t[p as usize] as usize;
8227 let dst = induction_bucket[c] as usize;
8228 induction_bucket[c] += 1;
8229 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
8230 SAINT_MIN
8231 } else {
8232 0
8233 };
8234 sa[dst] = p | mark;
8235 }
8236 block_start += 1;
8237 }
8238 } else {
8239 final_sorting_scan_left_to_right_16u_block_omp(
8240 t,
8241 sa,
8242 k,
8243 induction_bucket,
8244 block_start,
8245 block_size,
8246 threads,
8247 &mut thread_state,
8248 );
8249 block_start = block_scan_end;
8250 }
8251 }
8252 }
8253 }
8254}
8255
8256fn final_bwt_scan_right_to_left_16u_block_prepare(
8257 t: &[u16],
8258 sa: &mut [SaSint],
8259 k: SaSint,
8260 buckets: &mut [SaSint],
8261 cache: &mut [ThreadCache],
8262 omp_block_start: SaSint,
8263 omp_block_size: SaSint,
8264) -> SaSint {
8265 buckets[..k as usize].fill(0);
8266 let mut count = 0usize;
8267 for i in (omp_block_start as usize..(omp_block_start + omp_block_size) as usize).rev() {
8268 let mut p = sa[i];
8269 sa[i] = p & SAINT_MAX;
8270 if p > 0 {
8271 p -= 1;
8272 let c0 = t[(p - SaSint::from(p > 0)) as usize];
8273 let c1 = t[p as usize];
8274 sa[i] = c1 as SaSint;
8275 buckets[c1 as usize] += 1;
8276 cache[count].symbol = c1 as SaSint;
8277 cache[count].index = if c0 <= c1 {
8278 p
8279 } else {
8280 c0 as SaSint | SAINT_MIN
8281 };
8282 count += 1;
8283 }
8284 }
8285 count as SaSint
8286}
8287
8288fn final_bwt_aux_scan_right_to_left_16u_block_prepare(
8289 t: &[u16],
8290 sa: &mut [SaSint],
8291 k: SaSint,
8292 buckets: &mut [SaSint],
8293 cache: &mut [ThreadCache],
8294 omp_block_start: SaSint,
8295 omp_block_size: SaSint,
8296) -> SaSint {
8297 buckets[..k as usize].fill(0);
8298 let mut count = 0usize;
8299 for i in (omp_block_start as usize..(omp_block_start + omp_block_size) as usize).rev() {
8300 let mut p = sa[i];
8301 sa[i] = p & SAINT_MAX;
8302 if p > 0 {
8303 p -= 1;
8304 let c0 = t[(p - SaSint::from(p > 0)) as usize];
8305 let c1 = t[p as usize];
8306 sa[i] = c1 as SaSint;
8307 buckets[c1 as usize] += 1;
8308 cache[count].symbol = c1 as SaSint;
8309 cache[count].index = if c0 <= c1 {
8310 p
8311 } else {
8312 c0 as SaSint | SAINT_MIN
8313 };
8314 cache[count + 1].index = p;
8315 count += 2;
8316 }
8317 }
8318 count as SaSint
8319}
8320
8321fn final_sorting_scan_right_to_left_16u_block_prepare(
8322 t: &[u16],
8323 sa: &mut [SaSint],
8324 k: SaSint,
8325 buckets: &mut [SaSint],
8326 cache: &mut [ThreadCache],
8327 omp_block_start: SaSint,
8328 omp_block_size: SaSint,
8329) -> SaSint {
8330 buckets[..k as usize].fill(0);
8331 let mut count = 0usize;
8332 for i in (omp_block_start as usize..(omp_block_start + omp_block_size) as usize).rev() {
8333 let mut p = sa[i];
8334 sa[i] = p & SAINT_MAX;
8335 if p > 0 {
8336 p -= 1;
8337 let c = t[p as usize] as usize;
8338 buckets[c] += 1;
8339 cache[count].symbol = c as SaSint;
8340 cache[count].index = p
8341 | ((usize::from(t[(p - SaSint::from(p > 0)) as usize] > t[p as usize]) as SaSint)
8342 << (SAINT_BIT - 1));
8343 count += 1;
8344 }
8345 }
8346 count as SaSint
8347}
8348
8349fn final_order_scan_right_to_left_16u_block_place(
8350 sa: &mut [SaSint],
8351 buckets: &mut [SaSint],
8352 cache: &[ThreadCache],
8353 count: SaSint,
8354) {
8355 for entry in cache.iter().take(count as usize) {
8356 let c = entry.symbol as usize;
8357 buckets[c] -= 1;
8358 sa[buckets[c] as usize] = entry.index;
8359 }
8360}
8361
8362fn final_gsa_scan_right_to_left_16u_block_place(
8363 sa: &mut [SaSint],
8364 buckets: &mut [SaSint],
8365 cache: &[ThreadCache],
8366 count: SaSint,
8367) {
8368 for entry in cache.iter().take(count as usize) {
8369 let c = entry.symbol as usize;
8370 if c > 0 {
8371 buckets[c] -= 1;
8372 sa[buckets[c] as usize] = entry.index;
8373 }
8374 }
8375}
8376
8377fn final_bwt_aux_scan_right_to_left_16u_block_place(
8378 sa: &mut [SaSint],
8379 rm: SaSint,
8380 i_sample: &mut [SaSint],
8381 buckets: &mut [SaSint],
8382 cache: &[ThreadCache],
8383 count: SaSint,
8384) {
8385 let mut i = 0usize;
8386 while i < count as usize {
8387 let c = cache[i].symbol as usize;
8388 buckets[c] -= 1;
8389 sa[buckets[c] as usize] = cache[i].index;
8390 let p = cache[i + 1].index;
8391 if (p & rm) == 0 {
8392 i_sample[(p / (rm + 1)) as usize] = buckets[c] + 1;
8393 }
8394 i += 2;
8395 }
8396}
8397
8398fn final_bwt_scan_right_to_left_16u_block_omp(
8399 t: &[u16],
8400 sa: &mut [SaSint],
8401 k: SaSint,
8402 induction_bucket: &mut [SaSint],
8403 block_start: SaSint,
8404 block_size: SaSint,
8405 threads: SaSint,
8406 thread_state: &mut [ThreadState],
8407) -> SaSint {
8408 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
8409 usize::try_from(threads)
8410 .expect("threads must be non-negative")
8411 .min(thread_state.len())
8412 } else {
8413 1
8414 };
8415 if thread_count <= 1 {
8416 return final_bwt_scan_right_to_left_16u(t, sa, induction_bucket, block_start, block_size);
8417 }
8418
8419 let k_usize = usize::try_from(k).expect("k must be non-negative");
8420 let block_stride = (block_size / thread_count as SaSint) & !15;
8421
8422 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
8423 let local_start = thread as SaSint * block_stride;
8424 let local_size = if thread + 1 < thread_count {
8425 block_stride
8426 } else {
8427 block_size - local_start
8428 };
8429 state.count = final_bwt_scan_right_to_left_16u_block_prepare(
8430 t,
8431 sa,
8432 k,
8433 &mut state.buckets[..k_usize],
8434 &mut state.cache,
8435 block_start + local_start,
8436 local_size,
8437 );
8438 }
8439
8440 for state in thread_state.iter_mut().take(thread_count).rev() {
8441 for c in 0..k_usize {
8442 let a = induction_bucket[c];
8443 let b = state.buckets[c];
8444 induction_bucket[c] = a - b;
8445 state.buckets[c] = a;
8446 }
8447 }
8448
8449 for state in thread_state.iter_mut().take(thread_count) {
8450 final_order_scan_right_to_left_16u_block_place(
8451 sa,
8452 &mut state.buckets[..k_usize],
8453 &state.cache,
8454 state.count,
8455 );
8456 }
8457
8458 -1
8459}
8460
8461fn final_bwt_aux_scan_right_to_left_16u_block_omp(
8462 t: &[u16],
8463 sa: &mut [SaSint],
8464 k: SaSint,
8465 rm: SaSint,
8466 i_sample: &mut [SaSint],
8467 induction_bucket: &mut [SaSint],
8468 block_start: SaSint,
8469 block_size: SaSint,
8470 threads: SaSint,
8471 thread_state: &mut [ThreadState],
8472) {
8473 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
8474 usize::try_from(threads)
8475 .expect("threads must be non-negative")
8476 .min(thread_state.len())
8477 } else {
8478 1
8479 };
8480 if thread_count <= 1 {
8481 final_bwt_aux_scan_right_to_left_16u(
8482 t,
8483 sa,
8484 rm,
8485 i_sample,
8486 induction_bucket,
8487 block_start,
8488 block_size,
8489 );
8490 return;
8491 }
8492
8493 let k_usize = usize::try_from(k).expect("k must be non-negative");
8494 let block_stride = (block_size / thread_count as SaSint) & !15;
8495
8496 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
8497 let local_start = thread as SaSint * block_stride;
8498 let local_size = if thread + 1 < thread_count {
8499 block_stride
8500 } else {
8501 block_size - local_start
8502 };
8503 state.count = final_bwt_aux_scan_right_to_left_16u_block_prepare(
8504 t,
8505 sa,
8506 k,
8507 &mut state.buckets[..k_usize],
8508 &mut state.cache,
8509 block_start + local_start,
8510 local_size,
8511 );
8512 }
8513
8514 for state in thread_state.iter_mut().take(thread_count).rev() {
8515 for c in 0..k_usize {
8516 let a = induction_bucket[c];
8517 let b = state.buckets[c];
8518 induction_bucket[c] = a - b;
8519 state.buckets[c] = a;
8520 }
8521 }
8522
8523 for state in thread_state.iter_mut().take(thread_count) {
8524 final_bwt_aux_scan_right_to_left_16u_block_place(
8525 sa,
8526 rm,
8527 i_sample,
8528 &mut state.buckets[..k_usize],
8529 &state.cache,
8530 state.count,
8531 );
8532 }
8533}
8534
8535fn final_sorting_scan_right_to_left_16u_block_omp(
8536 t: &[u16],
8537 sa: &mut [SaSint],
8538 k: SaSint,
8539 induction_bucket: &mut [SaSint],
8540 block_start: SaSint,
8541 block_size: SaSint,
8542 threads: SaSint,
8543 thread_state: &mut [ThreadState],
8544) {
8545 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
8546 usize::try_from(threads)
8547 .expect("threads must be non-negative")
8548 .min(thread_state.len())
8549 } else {
8550 1
8551 };
8552 if thread_count <= 1 {
8553 final_sorting_scan_right_to_left_16u(t, sa, induction_bucket, block_start, block_size);
8554 return;
8555 }
8556
8557 let k_usize = usize::try_from(k).expect("k must be non-negative");
8558 let block_stride = (block_size / thread_count as SaSint) & !15;
8559
8560 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
8561 let local_start = thread as SaSint * block_stride;
8562 let local_size = if thread + 1 < thread_count {
8563 block_stride
8564 } else {
8565 block_size - local_start
8566 };
8567 state.count = final_sorting_scan_right_to_left_16u_block_prepare(
8568 t,
8569 sa,
8570 k,
8571 &mut state.buckets[..k_usize],
8572 &mut state.cache,
8573 block_start + local_start,
8574 local_size,
8575 );
8576 }
8577
8578 for state in thread_state.iter_mut().take(thread_count).rev() {
8579 for c in 0..k_usize {
8580 let a = induction_bucket[c];
8581 let b = state.buckets[c];
8582 induction_bucket[c] = a - b;
8583 state.buckets[c] = a;
8584 }
8585 }
8586
8587 for state in thread_state.iter_mut().take(thread_count) {
8588 final_order_scan_right_to_left_16u_block_place(
8589 sa,
8590 &mut state.buckets[..k_usize],
8591 &state.cache,
8592 state.count,
8593 );
8594 }
8595}
8596
8597fn final_gsa_scan_right_to_left_16u_block_omp(
8598 t: &[u16],
8599 sa: &mut [SaSint],
8600 k: SaSint,
8601 induction_bucket: &mut [SaSint],
8602 block_start: SaSint,
8603 block_size: SaSint,
8604 threads: SaSint,
8605 thread_state: &mut [ThreadState],
8606) {
8607 let thread_count = if threads > 1 && block_size >= 64 * k.max(256) {
8608 usize::try_from(threads)
8609 .expect("threads must be non-negative")
8610 .min(thread_state.len())
8611 } else {
8612 1
8613 };
8614 if thread_count <= 1 {
8615 final_gsa_scan_right_to_left_16u(t, sa, induction_bucket, block_start, block_size);
8616 return;
8617 }
8618
8619 let k_usize = usize::try_from(k).expect("k must be non-negative");
8620 let block_stride = (block_size / thread_count as SaSint) & !15;
8621
8622 for (thread, state) in thread_state.iter_mut().take(thread_count).enumerate() {
8623 let local_start = thread as SaSint * block_stride;
8624 let local_size = if thread + 1 < thread_count {
8625 block_stride
8626 } else {
8627 block_size - local_start
8628 };
8629 state.count = final_sorting_scan_right_to_left_16u_block_prepare(
8630 t,
8631 sa,
8632 k,
8633 &mut state.buckets[..k_usize],
8634 &mut state.cache,
8635 block_start + local_start,
8636 local_size,
8637 );
8638 }
8639
8640 for state in thread_state.iter_mut().take(thread_count).rev() {
8641 for c in 0..k_usize {
8642 let a = induction_bucket[c];
8643 let b = state.buckets[c];
8644 induction_bucket[c] = a - b;
8645 state.buckets[c] = a;
8646 }
8647 }
8648
8649 for state in thread_state.iter_mut().take(thread_count) {
8650 final_gsa_scan_right_to_left_16u_block_place(
8651 sa,
8652 &mut state.buckets[..k_usize],
8653 &state.cache,
8654 state.count,
8655 );
8656 }
8657}
8658
8659fn final_bwt_scan_right_to_left_16u_omp(
8660 t: &[u16],
8661 sa: &mut [SaSint],
8662 n: SaSint,
8663 k: SaSint,
8664 induction_bucket: &mut [SaSint],
8665 threads: SaSint,
8666) -> SaSint {
8667 let mut index = -1;
8668
8669 if threads == 1 || n < 65536 {
8670 index = final_bwt_scan_right_to_left_16u(t, sa, induction_bucket, 0, n);
8671 } else {
8672 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8673 let mut block_start = n - 1;
8674 while block_start >= 0 {
8675 if sa[block_start as usize] == 0 {
8676 index = block_start;
8677 block_start -= 1;
8678 } else {
8679 let mut block_max_end =
8680 block_start - threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8681 if block_max_end < 0 {
8682 block_max_end = -1;
8683 }
8684 let mut block_end = block_start - 1;
8685 while block_end > block_max_end && sa[block_end as usize] != 0 {
8686 block_end -= 1;
8687 }
8688 let block_size = block_start - block_end;
8689 if block_size < 32 {
8690 while block_start > block_end {
8691 let mut p = sa[block_start as usize];
8692 sa[block_start as usize] = p & SAINT_MAX;
8693 if p > 0 {
8694 p -= 1;
8695 let c0 = t[(p - SaSint::from(p > 0)) as usize];
8696 let c1 = t[p as usize] as usize;
8697 sa[block_start as usize] = c1 as SaSint;
8698 induction_bucket[c1] -= 1;
8699 sa[induction_bucket[c1] as usize] = if c0 <= c1 as u16 {
8700 p
8701 } else {
8702 c0 as SaSint | SAINT_MIN
8703 };
8704 }
8705 block_start -= 1;
8706 }
8707 } else {
8708 final_bwt_scan_right_to_left_16u_block_omp(
8709 t,
8710 sa,
8711 k,
8712 induction_bucket,
8713 block_end + 1,
8714 block_size,
8715 threads,
8716 &mut thread_state,
8717 );
8718 block_start = block_end;
8719 }
8720 }
8721 }
8722 }
8723 index
8724}
8725
8726fn final_bwt_aux_scan_right_to_left_16u_omp(
8727 t: &[u16],
8728 sa: &mut [SaSint],
8729 n: SaSint,
8730 k: SaSint,
8731 rm: SaSint,
8732 i_sample: &mut [SaSint],
8733 induction_bucket: &mut [SaSint],
8734 threads: SaSint,
8735) {
8736 if threads == 1 || n < 65536 {
8737 final_bwt_aux_scan_right_to_left_16u(t, sa, rm, i_sample, induction_bucket, 0, n);
8738 } else {
8739 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8740 let mut block_start = n - 1;
8741 while block_start >= 0 {
8742 if sa[block_start as usize] == 0 {
8743 block_start -= 1;
8744 } else {
8745 let mut block_max_end =
8746 block_start - threads * ((PER_THREAD_CACHE_SIZE as SaSint - 16 * threads) / 2);
8747 if block_max_end < 0 {
8748 block_max_end = -1;
8749 }
8750 let mut block_end = block_start - 1;
8751 while block_end > block_max_end && sa[block_end as usize] != 0 {
8752 block_end -= 1;
8753 }
8754 let block_size = block_start - block_end;
8755 if block_size < 32 {
8756 while block_start > block_end {
8757 let mut p = sa[block_start as usize];
8758 sa[block_start as usize] = p & SAINT_MAX;
8759 if p > 0 {
8760 p -= 1;
8761 let c0 = t[(p - SaSint::from(p > 0)) as usize];
8762 let c1 = t[p as usize] as usize;
8763 sa[block_start as usize] = c1 as SaSint;
8764 induction_bucket[c1] -= 1;
8765 sa[induction_bucket[c1] as usize] = if c0 <= c1 as u16 {
8766 p
8767 } else {
8768 c0 as SaSint | SAINT_MIN
8769 };
8770 if (p & rm) == 0 {
8771 i_sample[(p / (rm + 1)) as usize] = induction_bucket[c1] + 1;
8772 }
8773 }
8774 block_start -= 1;
8775 }
8776 } else {
8777 final_bwt_aux_scan_right_to_left_16u_block_omp(
8778 t,
8779 sa,
8780 k,
8781 rm,
8782 i_sample,
8783 induction_bucket,
8784 block_end + 1,
8785 block_size,
8786 threads,
8787 &mut thread_state,
8788 );
8789 block_start = block_end;
8790 }
8791 }
8792 }
8793 }
8794}
8795
8796fn final_sorting_scan_right_to_left_16u_omp(
8797 t: &[u16],
8798 sa: &mut [SaSint],
8799 omp_block_start: SaSint,
8800 omp_block_size: SaSint,
8801 k: SaSint,
8802 induction_bucket: &mut [SaSint],
8803 threads: SaSint,
8804) {
8805 if threads == 1 || omp_block_size < 65536 {
8806 final_sorting_scan_right_to_left_16u(
8807 t,
8808 sa,
8809 induction_bucket,
8810 omp_block_start,
8811 omp_block_size,
8812 );
8813 } else {
8814 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8815 let mut block_start = omp_block_start + omp_block_size - 1;
8816 while block_start >= omp_block_start {
8817 if sa[block_start as usize] == 0 {
8818 block_start -= 1;
8819 } else {
8820 let mut block_max_end =
8821 block_start - threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8822 if block_max_end < omp_block_start {
8823 block_max_end = omp_block_start - 1;
8824 }
8825 let mut block_end = block_start - 1;
8826 while block_end > block_max_end && sa[block_end as usize] != 0 {
8827 block_end -= 1;
8828 }
8829 let block_size = block_start - block_end;
8830 if block_size < 32 {
8831 while block_start > block_end {
8832 let mut p = sa[block_start as usize];
8833 sa[block_start as usize] = p & SAINT_MAX;
8834 if p > 0 {
8835 p -= 1;
8836 let c = t[p as usize] as usize;
8837 induction_bucket[c] -= 1;
8838 let mark = if t[(p - SaSint::from(p > 0)) as usize] > t[p as usize] {
8839 SAINT_MIN
8840 } else {
8841 0
8842 };
8843 sa[induction_bucket[c] as usize] = p | mark;
8844 }
8845 block_start -= 1;
8846 }
8847 } else {
8848 final_sorting_scan_right_to_left_16u_block_omp(
8849 t,
8850 sa,
8851 k,
8852 induction_bucket,
8853 block_end + 1,
8854 block_size,
8855 threads,
8856 &mut thread_state,
8857 );
8858 block_start = block_end;
8859 }
8860 }
8861 }
8862 }
8863}
8864
8865fn final_gsa_scan_right_to_left_16u_omp(
8866 t: &[u16],
8867 sa: &mut [SaSint],
8868 omp_block_start: SaSint,
8869 omp_block_size: SaSint,
8870 k: SaSint,
8871 induction_bucket: &mut [SaSint],
8872 threads: SaSint,
8873) {
8874 if threads == 1 || omp_block_size < 65536 {
8875 final_gsa_scan_right_to_left_16u(t, sa, induction_bucket, omp_block_start, omp_block_size);
8876 } else {
8877 let mut thread_state = alloc_thread_state(threads).unwrap_or_default();
8878 let mut block_start = omp_block_start + omp_block_size - 1;
8879 while block_start >= omp_block_start {
8880 if sa[block_start as usize] == 0 {
8881 block_start -= 1;
8882 } else {
8883 let mut block_max_end =
8884 block_start - threads * (PER_THREAD_CACHE_SIZE as SaSint - 16 * threads);
8885 if block_max_end < omp_block_start {
8886 block_max_end = omp_block_start - 1;
8887 }
8888 let mut block_end = block_start - 1;
8889 while block_end > block_max_end && sa[block_end as usize] != 0 {
8890 block_end -= 1;
8891 }
8892 let block_size = block_start - block_end;
8893 if block_size < 32 {
8894 while block_start > block_end {
8895 let mut p = sa[block_start as usize];
8896 sa[block_start as usize] = p & SAINT_MAX;
8897 if p > 0 && t[(p - 1) as usize] > 0 {
8898 p -= 1;
8899 let c = t[p as usize] as usize;
8900 induction_bucket[c] -= 1;
8901 let mark = if t[(p - SaSint::from(p > 0)) as usize] > t[p as usize] {
8902 SAINT_MIN
8903 } else {
8904 0
8905 };
8906 sa[induction_bucket[c] as usize] = p | mark;
8907 }
8908 block_start -= 1;
8909 }
8910 } else {
8911 final_gsa_scan_right_to_left_16u_block_omp(
8912 t,
8913 sa,
8914 k,
8915 induction_bucket,
8916 block_end + 1,
8917 block_size,
8918 threads,
8919 &mut thread_state,
8920 );
8921 block_start = block_end;
8922 }
8923 }
8924 }
8925 }
8926}
8927
8928fn induce_final_order_16u_omp(
8929 t: &[u16],
8930 sa: &mut [SaSint],
8931 n: SaSint,
8932 k: SaSint,
8933 flags: SaSint,
8934 r: SaSint,
8935 i_out: Option<&mut [SaSint]>,
8936 buckets: &mut [SaSint],
8937 threads: SaSint,
8938 _thread_state: &mut [ThreadState],
8939) -> SaSint {
8940 if (flags & LIBSAIS_FLAGS_BWT) == 0 {
8941 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
8942 buckets[6 * ALPHABET_SIZE] = buckets[7 * ALPHABET_SIZE] - 1;
8943 }
8944
8945 let (left_buckets, right_tail) = buckets.split_at_mut(7 * ALPHABET_SIZE);
8946 let bucket_start = &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE];
8947 let bucket_end = &mut right_tail[..ALPHABET_SIZE];
8948
8949 final_sorting_scan_left_to_right_16u_omp(t, sa, n, k, bucket_start, threads);
8950 if threads > 1 && n >= 65_536 {
8951 clear_lms_suffixes_omp(
8952 sa,
8953 n,
8954 ALPHABET_SIZE as SaSint,
8955 bucket_start,
8956 bucket_end,
8957 threads,
8958 );
8959 }
8960
8961 if (flags & LIBSAIS_FLAGS_GSA) != 0 {
8962 flip_suffix_markers_omp(sa, bucket_end[0], threads);
8963 final_gsa_scan_right_to_left_16u_omp(
8964 t,
8965 sa,
8966 bucket_end[0],
8967 n - bucket_end[0],
8968 k,
8969 bucket_end,
8970 threads,
8971 );
8972 } else {
8973 final_sorting_scan_right_to_left_16u_omp(t, sa, 0, n, k, bucket_end, threads);
8974 }
8975
8976 0
8977 } else if let Some(i_out) = i_out {
8978 let (left_buckets, right_tail) = buckets.split_at_mut(7 * ALPHABET_SIZE);
8979 let bucket_start = &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE];
8980 let bucket_end = &mut right_tail[..ALPHABET_SIZE];
8981
8982 final_bwt_aux_scan_left_to_right_16u_omp(t, sa, n, k, r - 1, i_out, bucket_start, threads);
8983 if threads > 1 && n >= 65_536 {
8984 clear_lms_suffixes_omp(
8985 sa,
8986 n,
8987 ALPHABET_SIZE as SaSint,
8988 bucket_start,
8989 bucket_end,
8990 threads,
8991 );
8992 }
8993 final_bwt_aux_scan_right_to_left_16u_omp(t, sa, n, k, r - 1, i_out, bucket_end, threads);
8994 0
8995 } else {
8996 let (left_buckets, right_tail) = buckets.split_at_mut(7 * ALPHABET_SIZE);
8997 let bucket_start = &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE];
8998 let bucket_end = &mut right_tail[..ALPHABET_SIZE];
8999
9000 final_bwt_scan_left_to_right_16u_omp(t, sa, n, k, bucket_start, threads);
9001 if threads > 1 && n >= 65_536 {
9002 clear_lms_suffixes_omp(
9003 sa,
9004 n,
9005 ALPHABET_SIZE as SaSint,
9006 bucket_start,
9007 bucket_end,
9008 threads,
9009 );
9010 }
9011 final_bwt_scan_right_to_left_16u_omp(t, sa, n, k, bucket_end, threads)
9012 }
9013}
9014
9015fn bwt_copy_16u(u: &mut [u16], a: &[SaSint], n: SaSint) {
9016 let mut i = 0isize;
9017 let mut j = n as isize - 7;
9018 while i < j {
9019 u[i as usize] = a[i as usize] as u16;
9020 u[(i + 1) as usize] = a[(i + 1) as usize] as u16;
9021 u[(i + 2) as usize] = a[(i + 2) as usize] as u16;
9022 u[(i + 3) as usize] = a[(i + 3) as usize] as u16;
9023 u[(i + 4) as usize] = a[(i + 4) as usize] as u16;
9024 u[(i + 5) as usize] = a[(i + 5) as usize] as u16;
9025 u[(i + 6) as usize] = a[(i + 6) as usize] as u16;
9026 u[(i + 7) as usize] = a[(i + 7) as usize] as u16;
9027 i += 8;
9028 }
9029
9030 j += 7;
9031 while i < j {
9032 u[i as usize] = a[i as usize] as u16;
9033 i += 1;
9034 }
9035}
9036
9037#[allow(dead_code)]
9038fn bwt_copy_16u_omp(u: &mut [u16], a: &[SaSint], n: SaSint, threads: SaSint) {
9039 if threads == 1 || n < 65_536 {
9040 bwt_copy_16u(u, a, n);
9041 return;
9042 }
9043
9044 let block_stride = (n / threads) & !15;
9045 for thread in 0..threads {
9046 let block_start = thread * block_stride;
9047 let block_size = if thread < threads - 1 {
9048 block_stride
9049 } else {
9050 n - block_start
9051 };
9052 let start = block_start as usize;
9053 bwt_copy_16u(&mut u[start..], &a[start..], block_size);
9054 }
9055}
9056
9057#[allow(dead_code)]
9058fn convert_32u_to_64u(s: &[u32], d: &mut [u64], block_start: usize, block_size: usize) {
9059 for i in block_start..block_start + block_size {
9060 d[i] = u64::from(s[i]);
9061 }
9062}
9063
9064#[allow(dead_code)]
9065fn convert_inplace_32u_to_64u(v: &mut [u32], block_start: usize, block_size: usize) {
9066 for i in (block_start..block_start + block_size).rev() {
9067 v[i + i] = v[i];
9068 v[i + i + 1] = 0;
9069 }
9070}
9071
9072#[allow(dead_code)]
9073fn convert_inplace_64u_to_32u(v: &mut [u32], block_start: usize, block_size: usize) {
9074 for i in block_start..block_start + block_size {
9075 v[i] = v[i + i];
9076 }
9077}
9078
9079#[allow(dead_code)]
9080fn convert_inplace_32u_to_64u_omp(v: &mut [u32], n: SaSint, threads: SaSint) {
9081 let mut n = usize::try_from(n).expect("n must be non-negative");
9082 let threads = usize::try_from(threads.max(1)).expect("threads must be non-negative");
9083
9084 while n >= 65_536 {
9085 let block_size = n >> 1;
9086 n -= block_size;
9087
9088 let omp_block_stride = (block_size / threads) & !15usize;
9089 for thread in 0..threads {
9090 let block_start = thread * omp_block_stride;
9091 let size = if thread + 1 < threads {
9092 omp_block_stride
9093 } else {
9094 block_size - block_start
9095 };
9096 convert_inplace_32u_to_64u(v, n + block_start, size);
9097 }
9098 }
9099
9100 convert_inplace_32u_to_64u(v, 0, n);
9101}
9102
9103fn final_bwt_ltr_step(t: &[u16], sa: &mut [SaSint], induction_bucket: &mut [SaSint], index: usize) {
9104 let mut p = sa[index];
9105 sa[index] = p & SAINT_MAX;
9106 if p > 0 {
9107 p -= 1;
9108 let c = t[p as usize] as usize;
9109 sa[index] = t[p as usize] as SaSint | SAINT_MIN;
9110 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
9111 SAINT_MIN
9112 } else {
9113 0
9114 };
9115 let dst = induction_bucket[c] as usize;
9116 sa[dst] = p | mark;
9117 induction_bucket[c] += 1;
9118 }
9119}
9120
9121fn final_bwt_rtl_step(
9122 t: &[u16],
9123 sa: &mut [SaSint],
9124 induction_bucket: &mut [SaSint],
9125 index: usize,
9126 primary_index: &mut SaSint,
9127) {
9128 let mut p = sa[index];
9129 if p == 0 {
9130 *primary_index = index as SaSint;
9131 }
9132 sa[index] = p & SAINT_MAX;
9133 if p > 0 {
9134 p -= 1;
9135 let c0 = t[(p - SaSint::from(p > 0)) as usize];
9136 let c1 = t[p as usize];
9137 sa[index] = c1 as SaSint;
9138 let induced = if c0 <= c1 {
9139 p
9140 } else {
9141 c0 as SaSint | SAINT_MIN
9142 };
9143 induction_bucket[c1 as usize] -= 1;
9144 sa[induction_bucket[c1 as usize] as usize] = induced;
9145 }
9146}
9147
9148fn final_bwt_aux_ltr_step(
9149 t: &[u16],
9150 sa: &mut [SaSint],
9151 rm: SaSint,
9152 i_sample: &mut [SaSint],
9153 induction_bucket: &mut [SaSint],
9154 index: usize,
9155) {
9156 let mut p = sa[index];
9157 sa[index] = p & SAINT_MAX;
9158 if p > 0 {
9159 p -= 1;
9160 let c = t[p as usize] as usize;
9161 sa[index] = t[p as usize] as SaSint | SAINT_MIN;
9162 let mark = if t[(p - SaSint::from(p > 0)) as usize] < t[p as usize] {
9163 SAINT_MIN
9164 } else {
9165 0
9166 };
9167 let dst = induction_bucket[c] as usize;
9168 sa[dst] = p | mark;
9169 induction_bucket[c] += 1;
9170 if (p & rm) == 0 {
9171 i_sample[(p / (rm + 1)) as usize] = induction_bucket[c];
9172 }
9173 }
9174}
9175
9176fn final_bwt_aux_rtl_step(
9177 t: &[u16],
9178 sa: &mut [SaSint],
9179 rm: SaSint,
9180 i_sample: &mut [SaSint],
9181 induction_bucket: &mut [SaSint],
9182 index: usize,
9183) {
9184 let mut p = sa[index];
9185 sa[index] = p & SAINT_MAX;
9186 if p > 0 {
9187 p -= 1;
9188 let c0 = t[(p - SaSint::from(p > 0)) as usize];
9189 let c1 = t[p as usize];
9190 sa[index] = c1 as SaSint;
9191 let induced = if c0 <= c1 {
9192 p
9193 } else {
9194 c0 as SaSint | SAINT_MIN
9195 };
9196 induction_bucket[c1 as usize] -= 1;
9197 sa[induction_bucket[c1 as usize] as usize] = induced;
9198 if (p & rm) == 0 {
9199 i_sample[(p / (rm + 1)) as usize] = induction_bucket[c1 as usize] + 1;
9200 }
9201 }
9202}
9203
9204fn main_32s_recursion(
9205 t_ptr: *mut SaSint,
9206 sa_ptr: *mut SaSint,
9207 sa_capacity: usize,
9208 n: SaSint,
9209 k: SaSint,
9210 fs: SaSint,
9211 threads: SaSint,
9212 thread_state: &mut [ThreadState],
9213 local_buffer: &mut [SaSint],
9214) -> SaSint {
9215 let fs = fs.min(SAINT_MAX - n);
9216 let local_buffer_size = SaSint::try_from(LIBSAIS_LOCAL_BUFFER_SIZE).expect("fits");
9217 let n_usize = usize::try_from(n).expect("n must be non-negative");
9218 let fs_usize = usize::try_from(fs).expect("fs must be non-negative");
9219 let total_len = n_usize + fs_usize;
9220 assert!(total_len <= sa_capacity);
9221
9222 if n <= i32::MAX as SaSint && k > 0 {
9223 let doubled_space = i128::from(fs) + i128::from(fs) + i128::from(n) + i128::from(n);
9224 let new_fs = if doubled_space <= i128::from(i32::MAX) {
9225 fs + fs + n
9226 } else {
9227 i32::MAX as SaSint - n
9228 };
9229
9230 if (new_fs / k >= 6)
9231 || (new_fs / k >= 4 && n <= (i32::MAX as SaSint) / 2)
9232 || (new_fs / k < 4 && new_fs >= fs)
9233 {
9234 let t = unsafe { std::slice::from_raw_parts_mut(t_ptr, n_usize) };
9235 let mut t32 = Vec::with_capacity(n_usize);
9236 for &value in t.iter() {
9237 let Ok(value) = i32::try_from(value) else {
9238 break;
9239 };
9240 t32.push(value);
9241 }
9242
9243 if t32.len() == n_usize {
9244 let mut sa32 = vec![0_i32; n_usize + usize::try_from(new_fs).expect("fits")];
9245 let index = crate::libsais16::libsais16_int_omp(
9246 &mut t32,
9247 &mut sa32,
9248 k as i32,
9249 new_fs as i32,
9250 threads as i32,
9251 ) as SaSint;
9252
9253 if index >= 0 {
9254 let sa = unsafe { std::slice::from_raw_parts_mut(sa_ptr, n_usize) };
9255 for (dst, src) in sa.iter_mut().zip(sa32.iter()) {
9256 *dst = SaSint::from(*src);
9257 }
9258 }
9259
9260 return index;
9261 }
9262 }
9263 }
9264
9265 if k > 0 && ((fs / k) >= 6 || (local_buffer_size / k) >= 6) {
9266 let k_usize = usize::try_from(k).expect("k must be non-negative");
9267 let alignment = if fs >= 1024 && ((fs - 1024) / k) >= 6 {
9268 1024usize
9269 } else {
9270 16usize
9271 };
9272 let need = 6 * k_usize;
9273 let use_local_buffer = local_buffer_size > fs;
9274 let buckets_ptr = if use_local_buffer {
9275 local_buffer.as_mut_ptr()
9276 } else {
9277 unsafe {
9278 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9279 let start =
9280 if fs_usize >= need + alignment && ((fs_usize - alignment) / k_usize) >= 6 {
9281 let byte_ptr = sa[total_len - need - alignment..].as_mut_ptr() as usize;
9282 let aligned = align_up(byte_ptr, alignment * mem::size_of::<SaSint>());
9283 (aligned - sa_ptr as usize) / mem::size_of::<SaSint>()
9284 } else {
9285 total_len - need
9286 };
9287 sa[start..].as_mut_ptr()
9288 }
9289 };
9290
9291 let m = unsafe {
9292 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9293 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9294 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9295 count_and_gather_lms_suffixes_32s_4k_omp(
9296 t,
9297 sa,
9298 n,
9299 k,
9300 buckets,
9301 SaSint::from(use_local_buffer),
9302 threads,
9303 thread_state,
9304 )
9305 };
9306 if m > 1 {
9307 let m_usize = usize::try_from(m).expect("m must be non-negative");
9308 unsafe {
9309 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9310 sa[..n_usize - m_usize].fill(0);
9311 }
9312
9313 let first_lms_suffix = unsafe {
9314 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9315 sa[n_usize - m_usize]
9316 };
9317 let left_suffixes_count = unsafe {
9318 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9319 initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(
9320 std::slice::from_raw_parts(t_ptr, n_usize),
9321 k,
9322 buckets,
9323 first_lms_suffix,
9324 )
9325 };
9326
9327 unsafe {
9328 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9329 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9330 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9331 let (_, induction_bucket) = buckets.split_at_mut(4 * k_usize);
9332 radix_sort_lms_suffixes_32s_6k_omp(t, sa, n, m, induction_bucket, threads);
9333 if (n / 8192) < k {
9334 radix_sort_set_markers_32s_6k_omp(sa, k, induction_bucket, threads);
9335 }
9336 if threads > 1 && n >= 65_536 {
9337 sa[n_usize - m_usize..n_usize].fill(0);
9338 }
9339 initialize_buckets_for_partial_sorting_32s_6k(
9340 t,
9341 k,
9342 buckets,
9343 first_lms_suffix,
9344 left_suffixes_count,
9345 );
9346 induce_partial_order_32s_6k_omp(
9347 t,
9348 sa,
9349 n,
9350 k,
9351 buckets,
9352 first_lms_suffix,
9353 left_suffixes_count,
9354 threads,
9355 thread_state,
9356 );
9357 }
9358
9359 let names = unsafe {
9360 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9361 if (n / 8192) < k {
9362 renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(
9363 sa,
9364 n,
9365 m,
9366 threads,
9367 thread_state,
9368 )
9369 } else {
9370 renumber_and_gather_lms_suffixes_omp(sa, n, m, fs, threads, thread_state)
9371 }
9372 };
9373
9374 if names < m {
9375 let f = if (n / 8192) < k {
9376 unsafe {
9377 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9378 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9379 compact_lms_suffixes_32s_omp(t, sa, n, m, fs, threads)
9380 }
9381 } else {
9382 0
9383 };
9384
9385 let new_t_start =
9386 total_len - usize::try_from(m - f).expect("m - f must be non-negative");
9387 if main_32s_recursion(
9388 unsafe {
9389 std::slice::from_raw_parts_mut(sa_ptr, total_len)[new_t_start..]
9390 .as_mut_ptr()
9391 },
9392 sa_ptr,
9393 sa_capacity,
9394 m - f,
9395 names - f,
9396 fs + n - 2 * m + f,
9397 threads,
9398 thread_state,
9399 local_buffer,
9400 ) != 0
9401 {
9402 return -2;
9403 }
9404
9405 unsafe {
9406 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9407 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9408 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9409 reconstruct_compacted_lms_suffixes_32s_2k_omp(
9410 t,
9411 sa,
9412 n,
9413 k,
9414 m,
9415 fs,
9416 f,
9417 buckets,
9418 SaSint::from(use_local_buffer),
9419 threads,
9420 thread_state,
9421 );
9422 }
9423 } else {
9424 unsafe {
9425 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9426 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9427 count_lms_suffixes_32s_2k(t, n, k, buckets);
9428 }
9429 }
9430
9431 unsafe {
9432 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9433 initialize_buckets_start_and_end_32s_4k(k, buckets);
9434 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9435 place_lms_suffixes_histogram_32s_4k(sa, n, k, m, buckets);
9436 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9437 induce_final_order_32s_4k(t, sa, n, k, buckets, threads, thread_state);
9438 }
9439 } else {
9440 unsafe {
9441 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9442 sa[0] = sa[n_usize - 1];
9443 }
9444
9445 unsafe {
9446 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9447 initialize_buckets_start_and_end_32s_6k(k, buckets);
9448 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9449 place_lms_suffixes_histogram_32s_6k(sa, n, k, m, buckets);
9450 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9451 induce_final_order_32s_6k(t, sa, n, k, buckets, threads, thread_state);
9452 }
9453 }
9454
9455 return 0;
9456 } else if k > 0 && n <= SAINT_MAX / 2 && ((fs / k) >= 4 || (local_buffer_size / k) >= 4) {
9457 let k_usize = usize::try_from(k).expect("k must be non-negative");
9458 let alignment = if fs >= 1024 && ((fs - 1024) / k) >= 4 {
9459 1024usize
9460 } else {
9461 16usize
9462 };
9463 let need = 4 * k_usize;
9464 let use_local_buffer = local_buffer_size > fs;
9465 let buckets_ptr = if use_local_buffer {
9466 local_buffer.as_mut_ptr()
9467 } else {
9468 unsafe {
9469 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9470 let start =
9471 if fs_usize >= need + alignment && ((fs_usize - alignment) / k_usize) >= 4 {
9472 let byte_ptr = sa[total_len - need - alignment..].as_mut_ptr() as usize;
9473 let aligned = align_up(byte_ptr, alignment * mem::size_of::<SaSint>());
9474 (aligned - sa_ptr as usize) / mem::size_of::<SaSint>()
9475 } else {
9476 total_len - need
9477 };
9478 sa[start..].as_mut_ptr()
9479 }
9480 };
9481
9482 let m = unsafe {
9483 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9484 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9485 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9486 count_and_gather_lms_suffixes_32s_2k_omp(
9487 t,
9488 sa,
9489 n,
9490 k,
9491 buckets,
9492 SaSint::from(use_local_buffer),
9493 threads,
9494 thread_state,
9495 )
9496 };
9497 if m > 1 {
9498 let m_usize = usize::try_from(m).expect("m must be non-negative");
9499 unsafe {
9500 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9501 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9502 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9503 initialize_buckets_for_radix_and_partial_sorting_32s_4k(
9504 t,
9505 k,
9506 buckets,
9507 sa[n_usize - m_usize],
9508 );
9509 let (_, induction_bucket) = buckets.split_at_mut(1);
9510 radix_sort_lms_suffixes_32s_2k_omp(t, sa, n, m, induction_bucket, threads);
9511 radix_sort_set_markers_32s_4k_omp(sa, k, induction_bucket, threads);
9512 place_lms_suffixes_interval_32s_4k(sa, n, k, m - 1, buckets);
9513 induce_partial_order_32s_4k_omp(t, sa, n, k, buckets, threads, thread_state);
9514 }
9515
9516 let names = unsafe {
9517 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9518 renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(sa, n, m, threads, thread_state)
9519 };
9520 if names < m {
9521 let f = unsafe {
9522 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9523 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9524 compact_lms_suffixes_32s_omp(t, sa, n, m, fs, threads)
9525 };
9526
9527 let new_t_start =
9528 total_len - usize::try_from(m - f).expect("m - f must be non-negative");
9529 if main_32s_recursion(
9530 unsafe {
9531 std::slice::from_raw_parts_mut(sa_ptr, total_len)[new_t_start..]
9532 .as_mut_ptr()
9533 },
9534 sa_ptr,
9535 sa_capacity,
9536 m - f,
9537 names - f,
9538 fs + n - 2 * m + f,
9539 threads,
9540 thread_state,
9541 local_buffer,
9542 ) != 0
9543 {
9544 return -2;
9545 }
9546
9547 unsafe {
9548 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9549 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9550 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9551 reconstruct_compacted_lms_suffixes_32s_2k_omp(
9552 t,
9553 sa,
9554 n,
9555 k,
9556 m,
9557 fs,
9558 f,
9559 buckets,
9560 SaSint::from(use_local_buffer),
9561 threads,
9562 thread_state,
9563 );
9564 }
9565 } else {
9566 unsafe {
9567 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9568 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9569 count_lms_suffixes_32s_2k(t, n, k, buckets);
9570 }
9571 }
9572 } else {
9573 unsafe {
9574 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9575 sa[0] = sa[n_usize - 1];
9576 }
9577 }
9578
9579 unsafe {
9580 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9581 initialize_buckets_start_and_end_32s_4k(k, buckets);
9582 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9583 place_lms_suffixes_histogram_32s_4k(sa, n, k, m, buckets);
9584 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9585 induce_final_order_32s_4k(t, sa, n, k, buckets, threads, thread_state);
9586 }
9587
9588 return 0;
9589 } else if k > 0 && ((fs / k) >= 2 || (local_buffer_size / k) >= 2) {
9590 let k_usize = usize::try_from(k).expect("k must be non-negative");
9591 let alignment = if fs >= 1024 && ((fs - 1024) / k) >= 2 {
9592 1024usize
9593 } else {
9594 16usize
9595 };
9596 let need = 2 * k_usize;
9597 let use_local_buffer = local_buffer_size > fs;
9598 let buckets_ptr = if use_local_buffer {
9599 local_buffer.as_mut_ptr()
9600 } else {
9601 unsafe {
9602 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9603 let start =
9604 if fs_usize >= need + alignment && ((fs_usize - alignment) / k_usize) >= 2 {
9605 let byte_ptr = sa[total_len - need - alignment..].as_mut_ptr() as usize;
9606 let aligned = align_up(byte_ptr, alignment * mem::size_of::<SaSint>());
9607 (aligned - sa_ptr as usize) / mem::size_of::<SaSint>()
9608 } else {
9609 total_len - need
9610 };
9611 sa[start..].as_mut_ptr()
9612 }
9613 };
9614
9615 let m = unsafe {
9616 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9617 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9618 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9619 count_and_gather_lms_suffixes_32s_2k_omp(
9620 t,
9621 sa,
9622 n,
9623 k,
9624 buckets,
9625 SaSint::from(use_local_buffer),
9626 threads,
9627 thread_state,
9628 )
9629 };
9630 if m > 1 {
9631 let m_usize = usize::try_from(m).expect("m must be non-negative");
9632 unsafe {
9633 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9634 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9635 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9636 initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(
9637 t,
9638 k,
9639 buckets,
9640 sa[n_usize - m_usize],
9641 );
9642 let (_, induction_bucket) = buckets.split_at_mut(1);
9643 radix_sort_lms_suffixes_32s_2k_omp(t, sa, n, m, induction_bucket, threads);
9644 place_lms_suffixes_interval_32s_2k(sa, n, k, m - 1, buckets);
9645 }
9646
9647 unsafe {
9648 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9649 initialize_buckets_start_and_end_32s_2k(k, buckets);
9650 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9651 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9652 induce_partial_order_32s_2k_omp(t, sa, n, k, buckets, threads, thread_state);
9653 }
9654
9655 let names = unsafe {
9656 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9657 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9658 renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(t, sa, n, m, threads)
9659 };
9660 if names < m {
9661 let f = unsafe {
9662 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9663 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9664 compact_lms_suffixes_32s_omp(t, sa, n, m, fs, threads)
9665 };
9666
9667 let new_t_start =
9668 total_len - usize::try_from(m - f).expect("m - f must be non-negative");
9669 if main_32s_recursion(
9670 unsafe {
9671 std::slice::from_raw_parts_mut(sa_ptr, total_len)[new_t_start..]
9672 .as_mut_ptr()
9673 },
9674 sa_ptr,
9675 sa_capacity,
9676 m - f,
9677 names - f,
9678 fs + n - 2 * m + f,
9679 threads,
9680 thread_state,
9681 local_buffer,
9682 ) != 0
9683 {
9684 return -2;
9685 }
9686
9687 unsafe {
9688 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9689 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9690 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9691 reconstruct_compacted_lms_suffixes_32s_2k_omp(
9692 t,
9693 sa,
9694 n,
9695 k,
9696 m,
9697 fs,
9698 f,
9699 buckets,
9700 SaSint::from(use_local_buffer),
9701 threads,
9702 thread_state,
9703 );
9704 }
9705 } else {
9706 unsafe {
9707 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9708 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9709 count_lms_suffixes_32s_2k(t, n, k, buckets);
9710 }
9711 }
9712 } else {
9713 unsafe {
9714 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9715 sa[0] = sa[n_usize - 1];
9716 }
9717 }
9718
9719 unsafe {
9720 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9721 initialize_buckets_end_32s_2k(k, buckets);
9722 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9723 place_lms_suffixes_histogram_32s_2k(sa, n, k, m, buckets);
9724 }
9725
9726 unsafe {
9727 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, need);
9728 initialize_buckets_start_and_end_32s_2k(k, buckets);
9729 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9730 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9731 induce_final_order_32s_2k(t, sa, n, k, buckets, threads, thread_state);
9732 }
9733
9734 0
9735 } else {
9736 let k_usize = usize::try_from(k).expect("k must be non-negative");
9737 let mut heap_buckets = if fs < k { Some(vec![0; k_usize]) } else { None };
9738 let alignment = if fs >= 1024 && (fs - 1024) >= k {
9739 1024usize
9740 } else {
9741 16usize
9742 };
9743 let mut buckets_ptr = if let Some(ref mut heap) = heap_buckets {
9744 heap.as_mut_ptr()
9745 } else {
9746 unsafe {
9747 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9748 let start = if fs_usize >= k_usize + alignment {
9749 let byte_ptr = sa[total_len - k_usize - alignment..].as_mut_ptr() as usize;
9750 let aligned = align_up(byte_ptr, alignment * mem::size_of::<SaSint>());
9751 (aligned - sa_ptr as usize) / mem::size_of::<SaSint>()
9752 } else {
9753 total_len - k_usize
9754 };
9755 sa[start..].as_mut_ptr()
9756 }
9757 };
9758
9759 if buckets_ptr.is_null() {
9760 return -2;
9761 }
9762
9763 unsafe {
9764 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9765 sa[..n_usize].fill(0);
9766 }
9767
9768 unsafe {
9769 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9770 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9771 count_suffixes_32s(t, n, k, buckets);
9772 initialize_buckets_end_32s_1k(k, buckets);
9773 }
9774
9775 let m = unsafe {
9776 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9777 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9778 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9779 radix_sort_lms_suffixes_32s_1k(t, sa, n, buckets)
9780 };
9781 if m > 1 {
9782 unsafe {
9783 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9784 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9785 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9786 induce_partial_order_32s_1k_omp(t, sa, n, k, buckets, threads, thread_state);
9787 }
9788
9789 let names = unsafe {
9790 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9791 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9792 renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(t, sa, n, m, threads)
9793 };
9794 if names < m {
9795 if heap_buckets.is_some() {
9796 let _ = heap_buckets.take();
9797 buckets_ptr = std::ptr::null_mut();
9798 }
9799
9800 let f = unsafe {
9801 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9802 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9803 compact_lms_suffixes_32s_omp(t, sa, n, m, fs, threads)
9804 };
9805
9806 let new_t_start =
9807 total_len - usize::try_from(m - f).expect("m - f must be non-negative");
9808 if main_32s_recursion(
9809 unsafe {
9810 std::slice::from_raw_parts_mut(sa_ptr, total_len)[new_t_start..]
9811 .as_mut_ptr()
9812 },
9813 sa_ptr,
9814 sa_capacity,
9815 m - f,
9816 names - f,
9817 fs + n - 2 * m + f,
9818 threads,
9819 thread_state,
9820 local_buffer,
9821 ) != 0
9822 {
9823 return -2;
9824 }
9825
9826 unsafe {
9827 let t = std::slice::from_raw_parts_mut(t_ptr, n_usize);
9828 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9829 reconstruct_compacted_lms_suffixes_32s_1k_omp(t, sa, n, m, fs, f, threads);
9830 }
9831
9832 if buckets_ptr.is_null() {
9833 heap_buckets = Some(vec![0; k_usize]);
9834 buckets_ptr = heap_buckets.as_mut().unwrap().as_mut_ptr();
9835 if buckets_ptr.is_null() {
9836 return -2;
9837 }
9838 }
9839 }
9840
9841 unsafe {
9842 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9843 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9844 count_suffixes_32s(t, n, k, buckets);
9845 initialize_buckets_end_32s_1k(k, buckets);
9846 }
9847 unsafe {
9848 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9849 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9850 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9851 place_lms_suffixes_interval_32s_1k(t, sa, k, m, buckets);
9852 }
9853 }
9854
9855 unsafe {
9856 let t = std::slice::from_raw_parts(t_ptr, n_usize);
9857 let sa = std::slice::from_raw_parts_mut(sa_ptr, total_len);
9858 let buckets = std::slice::from_raw_parts_mut(buckets_ptr, k_usize);
9859 induce_final_order_32s_1k(t, sa, n, k, buckets, threads, thread_state);
9860 }
9861
9862 0
9863 }
9864}
9865
9866fn main_32s_entry(
9867 t_ptr: *mut SaSint,
9868 sa: &mut [SaSint],
9869 n: SaSint,
9870 k: SaSint,
9871 fs: SaSint,
9872 threads: SaSint,
9873 thread_state: &mut [ThreadState],
9874) -> SaSint {
9875 let mut local_buffer = [0; 2 * LIBSAIS_LOCAL_BUFFER_SIZE];
9876 main_32s_recursion(
9877 t_ptr,
9878 sa.as_mut_ptr(),
9879 sa.len(),
9880 n,
9881 k,
9882 fs,
9883 threads,
9884 thread_state,
9885 &mut local_buffer[LIBSAIS_LOCAL_BUFFER_SIZE..],
9886 )
9887}
9888
9889fn main_16u(
9890 t: &[u16],
9891 sa: &mut [SaSint],
9892 n: SaSint,
9893 buckets: &mut [SaSint],
9894 flags: SaSint,
9895 r: SaSint,
9896 i_out: Option<&mut [SaSint]>,
9897 fs: SaSint,
9898 freq: Option<&mut [SaSint]>,
9899 threads: SaSint,
9900 thread_state: &mut [ThreadState],
9901) -> SaSint {
9902 let fs = fs.min(SAINT_MAX - n);
9903
9904 let m = count_and_gather_lms_suffixes_16u_omp(t, sa, n, buckets, threads, thread_state);
9905 let k = initialize_buckets_start_and_end_16u(buckets, freq);
9906
9907 if (flags & LIBSAIS_FLAGS_GSA) != 0 && (buckets[0] != 0 || buckets[2] != 0 || buckets[3] != 1) {
9908 return -1;
9909 }
9910
9911 if m > 0 {
9912 let first_lms_suffix = sa[(n - m) as usize];
9913 let left_suffixes_count =
9914 initialize_buckets_for_lms_suffixes_radix_sort_16u(t, buckets, first_lms_suffix);
9915
9916 if threads > 1 && n >= 65_536 {
9917 sa[..(n - m) as usize].fill(0);
9918 }
9919 radix_sort_lms_suffixes_16u_omp(t, sa, n, m, flags, buckets, threads, thread_state);
9920 if threads > 1 && n >= 65_536 {
9921 sa[(n - m) as usize..n as usize].fill(0);
9922 }
9923
9924 initialize_buckets_for_partial_sorting_16u(
9925 t,
9926 buckets,
9927 first_lms_suffix,
9928 left_suffixes_count,
9929 );
9930 induce_partial_order_16u_omp(
9931 t,
9932 sa,
9933 n,
9934 k,
9935 flags,
9936 buckets,
9937 first_lms_suffix,
9938 left_suffixes_count,
9939 threads,
9940 );
9941
9942 let names = renumber_and_gather_lms_suffixes_omp(sa, n, m, fs, threads, thread_state);
9943 if names < m {
9944 let recursive_t_start = (n + fs - m) as usize;
9945 let recursive_t_ptr = sa[recursive_t_start..].as_mut_ptr();
9946 if main_32s_entry(
9947 recursive_t_ptr,
9948 sa,
9949 m,
9950 names,
9951 fs + n - 2 * m,
9952 threads,
9953 thread_state,
9954 ) != 0
9955 {
9956 return -2;
9957 }
9958
9959 gather_lms_suffixes_16u_omp(t, sa, n, threads, thread_state);
9960 reconstruct_lms_suffixes_omp(sa, n, m, threads);
9961 }
9962
9963 place_lms_suffixes_interval_16u(sa, n, m, flags, buckets);
9964 } else {
9965 sa[..n as usize].fill(0);
9966 }
9967
9968 induce_final_order_16u_omp(t, sa, n, k, flags, r, i_out, buckets, threads, thread_state)
9969}
9970
9971fn main_16u_alloc(
9972 t: &[u16],
9973 sa: &mut [SaSint],
9974 flags: SaSint,
9975 r: SaSint,
9976 i_out: Option<&mut [SaSint]>,
9977 fs: SaSint,
9978 freq: Option<&mut [SaSint]>,
9979 threads: SaSint,
9980) -> SaSint {
9981 if fs < 0
9982 || threads < 0
9983 || sa.len()
9984 < t.len()
9985 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
9986 || freq.as_ref().is_some_and(|freq| freq.len() < ALPHABET_SIZE)
9987 {
9988 return -1;
9989 }
9990
9991 fill_freq(t, freq);
9992 if t.len() <= 1 {
9993 if t.len() == 1 {
9994 sa[0] = 0;
9995 }
9996 return if (flags & LIBSAIS_FLAGS_BWT) != 0 {
9997 t.len() as SaSint
9998 } else {
9999 0
10000 };
10001 }
10002
10003 let mut buckets = vec![0; 8 * ALPHABET_SIZE];
10004 let threads = normalize_threads(threads);
10005 let mut thread_state = if threads > 1 {
10006 match alloc_thread_state(threads) {
10007 Some(thread_state) => thread_state,
10008 None => return -2,
10009 }
10010 } else {
10011 Vec::new()
10012 };
10013
10014 main_16u(
10015 t,
10016 sa,
10017 t.len() as SaSint,
10018 &mut buckets,
10019 flags,
10020 r,
10021 i_out,
10022 fs,
10023 None,
10024 threads,
10025 &mut thread_state,
10026 )
10027}
10028
10029fn main_16u_ctx(
10030 ctx: &mut Context,
10031 t: &[u16],
10032 sa: &mut [SaSint],
10033 flags: SaSint,
10034 r: SaSint,
10035 i_out: Option<&mut [SaSint]>,
10036 fs: SaSint,
10037 freq: Option<&mut [SaSint]>,
10038) -> SaSint {
10039 if fs < 0
10040 || sa.len()
10041 < t.len()
10042 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
10043 || freq.as_ref().is_some_and(|freq| freq.len() < ALPHABET_SIZE)
10044 {
10045 return -1;
10046 }
10047
10048 if ctx.threads <= 0 || ctx.buckets.len() < 8 * ALPHABET_SIZE {
10049 return -2;
10050 }
10051
10052 fill_freq(t, freq);
10053 if t.len() <= 1 {
10054 if t.len() == 1 {
10055 sa[0] = 0;
10056 }
10057 return if (flags & LIBSAIS_FLAGS_BWT) != 0 {
10058 t.len() as SaSint
10059 } else {
10060 0
10061 };
10062 }
10063
10064 let mut empty_thread_state = [];
10065 let thread_state = if ctx.threads > 1 {
10066 match ctx.thread_state.as_deref_mut() {
10067 Some(thread_state) if thread_state.len() >= ctx.threads as usize => thread_state,
10068 None => return -2,
10069 Some(_) => return -2,
10070 }
10071 } else {
10072 &mut empty_thread_state
10073 };
10074
10075 main_16u(
10076 t,
10077 sa,
10078 t.len() as SaSint,
10079 &mut ctx.buckets,
10080 flags,
10081 r,
10082 i_out,
10083 fs,
10084 None,
10085 ctx.threads,
10086 thread_state,
10087 )
10088}
10089
10090fn main_long(
10091 t: &mut [SaSint],
10092 sa: &mut [SaSint],
10093 k: SaSint,
10094 fs: SaSint,
10095 threads: SaSint,
10096) -> SaSint {
10097 let threads = normalize_threads(threads);
10098 let mut thread_state = if threads > 1 {
10099 match alloc_thread_state(threads) {
10100 Some(thread_state) => thread_state,
10101 None => return -2,
10102 }
10103 } else {
10104 Vec::new()
10105 };
10106
10107 main_32s_entry(
10108 t.as_mut_ptr(),
10109 sa,
10110 t.len() as SaSint,
10111 k,
10112 fs,
10113 threads,
10114 &mut thread_state,
10115 )
10116}
10117
10118pub fn libsais16x64(
10130 t: &[u16],
10131 sa: &mut [SaSint],
10132 fs: SaSint,
10133 freq: Option<&mut [SaSint]>,
10134) -> SaSint {
10135 main_16u_alloc(t, sa, 0, 0, None, fs, freq, 1)
10136}
10137
10138pub fn libsais16x64_gsa(
10150 t: &[u16],
10151 sa: &mut [SaSint],
10152 fs: SaSint,
10153 freq: Option<&mut [SaSint]>,
10154) -> SaSint {
10155 main_16u_alloc(t, sa, LIBSAIS_FLAGS_GSA, 0, None, fs, freq, 1)
10156}
10157
10158pub fn libsais16x64_int(t: &mut [SaSint], sa: &mut [SaSint], k: SaSint, fs: SaSint) -> SaSint {
10160 if fs < 0
10161 || sa.len()
10162 < t.len()
10163 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
10164 {
10165 return -1;
10166 }
10167
10168 if t.len() <= 1 {
10169 if t.len() == 1 {
10170 sa[0] = 0;
10171 }
10172 return 0;
10173 }
10174
10175 main_long(t, sa, k, fs, 1)
10176}
10177
10178pub fn libsais16x64_long(t: &mut [SaSint], sa: &mut [SaSint], k: SaSint, fs: SaSint) -> SaSint {
10192 libsais16x64_int(t, sa, k, fs)
10193}
10194
10195pub fn libsais16x64_ctx(
10205 ctx: &mut Context,
10206 t: &[u16],
10207 sa: &mut [SaSint],
10208 fs: SaSint,
10209 freq: Option<&mut [SaSint]>,
10210) -> SaSint {
10211 main_16u_ctx(ctx, t, sa, 0, 0, None, fs, freq)
10212}
10213
10214pub fn libsais16x64_gsa_ctx(
10224 ctx: &mut Context,
10225 t: &[u16],
10226 sa: &mut [SaSint],
10227 fs: SaSint,
10228 freq: Option<&mut [SaSint]>,
10229) -> SaSint {
10230 main_16u_ctx(ctx, t, sa, LIBSAIS_FLAGS_GSA, 0, None, fs, freq)
10231}
10232
10233pub fn libsais16x64_omp(
10246 t: &[u16],
10247 sa: &mut [SaSint],
10248 fs: SaSint,
10249 freq: Option<&mut [SaSint]>,
10250 threads: SaSint,
10251) -> SaSint {
10252 if threads < 0 {
10253 -1
10254 } else {
10255 main_16u_alloc(t, sa, 0, 0, None, fs, freq, threads)
10256 }
10257}
10258
10259pub fn libsais16x64_gsa_omp(
10272 t: &[u16],
10273 sa: &mut [SaSint],
10274 fs: SaSint,
10275 freq: Option<&mut [SaSint]>,
10276 threads: SaSint,
10277) -> SaSint {
10278 if threads < 0 {
10279 -1
10280 } else {
10281 main_16u_alloc(t, sa, LIBSAIS_FLAGS_GSA, 0, None, fs, freq, threads)
10282 }
10283}
10284
10285pub fn libsais16x64_int_omp(
10287 t: &mut [SaSint],
10288 sa: &mut [SaSint],
10289 k: SaSint,
10290 fs: SaSint,
10291 threads: SaSint,
10292) -> SaSint {
10293 if threads < 0
10294 || fs < 0
10295 || sa.len()
10296 < t.len()
10297 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
10298 {
10299 return -1;
10300 }
10301
10302 if t.len() <= 1 {
10303 if t.len() == 1 {
10304 sa[0] = 0;
10305 }
10306 return 0;
10307 }
10308
10309 main_long(t, sa, k, fs, threads)
10310}
10311
10312pub fn libsais16x64_long_omp(
10327 t: &mut [SaSint],
10328 sa: &mut [SaSint],
10329 k: SaSint,
10330 fs: SaSint,
10331 threads: SaSint,
10332) -> SaSint {
10333 libsais16x64_int_omp(t, sa, k, fs, threads)
10334}
10335
10336fn build_bwt(
10337 t: &[u16],
10338 u: &mut [u16],
10339 a: &mut [SaSint],
10340 fs: SaSint,
10341 freq: Option<&mut [SaSint]>,
10342 threads: SaSint,
10343) -> SaSint {
10344 if fs < 0
10345 || threads < 0
10346 || u.len() < t.len()
10347 || a.len()
10348 < t.len()
10349 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
10350 || freq.as_ref().is_some_and(|freq| freq.len() < ALPHABET_SIZE)
10351 {
10352 return -1;
10353 }
10354 if t.len() <= 1 {
10355 fill_freq(t, freq);
10356 if t.len() == 1 {
10357 u[0] = t[0];
10358 }
10359 return t.len() as SaSint;
10360 }
10361
10362 let n = t.len();
10363 let mut index = main_16u_alloc(t, a, LIBSAIS_FLAGS_BWT, 0, None, fs, freq, threads);
10364 if index >= 0 {
10365 index += 1;
10366 u[0] = t[n - 1];
10367 bwt_copy_16u(&mut u[1..], a, index - 1);
10368 bwt_copy_16u(
10369 &mut u[index as usize..],
10370 &a[index as usize..],
10371 n as SaSint - index,
10372 );
10373 }
10374 index
10375}
10376
10377pub fn libsais16x64_bwt(
10390 t: &[u16],
10391 u: &mut [u16],
10392 a: &mut [SaSint],
10393 fs: SaSint,
10394 freq: Option<&mut [SaSint]>,
10395) -> SaSint {
10396 build_bwt(t, u, a, fs, freq, 1)
10397}
10398
10399fn build_bwt_aux(
10400 t: &[u16],
10401 u: &mut [u16],
10402 a: &mut [SaSint],
10403 fs: SaSint,
10404 freq: Option<&mut [SaSint]>,
10405 r: SaSint,
10406 i: &mut [SaSint],
10407 threads: SaSint,
10408) -> SaSint {
10409 if threads < 0 || r < 2 || (r & (r - 1)) != 0 {
10410 return -1;
10411 }
10412 let samples = if t.is_empty() {
10413 1
10414 } else {
10415 (t.len() - 1) / r as usize + 1
10416 };
10417 if i.len() < samples {
10418 return -1;
10419 }
10420 let n = t.len();
10421 if n <= 1 {
10422 fill_freq(t, freq);
10423 if n == 1 {
10424 u[0] = t[0];
10425 }
10426 i[0] = n as SaSint;
10427 return 0;
10428 }
10429
10430 let index = main_16u_alloc(t, a, LIBSAIS_FLAGS_BWT, r, Some(i), fs, freq, threads);
10431 if index == 0 {
10432 u[0] = t[n - 1];
10433 bwt_copy_16u(&mut u[1..], a, i[0] - 1);
10434 bwt_copy_16u(
10435 &mut u[i[0] as usize..],
10436 &a[i[0] as usize..],
10437 n as SaSint - i[0],
10438 );
10439 }
10440 index
10441}
10442
10443pub fn libsais16x64_bwt_aux(
10458 t: &[u16],
10459 u: &mut [u16],
10460 a: &mut [SaSint],
10461 fs: SaSint,
10462 freq: Option<&mut [SaSint]>,
10463 r: SaSint,
10464 i: &mut [SaSint],
10465) -> SaSint {
10466 build_bwt_aux(t, u, a, fs, freq, r, i, 1)
10467}
10468
10469pub fn libsais16x64_bwt_ctx(
10480 ctx: &mut Context,
10481 t: &[u16],
10482 u: &mut [u16],
10483 a: &mut [SaSint],
10484 fs: SaSint,
10485 freq: Option<&mut [SaSint]>,
10486) -> SaSint {
10487 if fs < 0
10488 || u.len() < t.len()
10489 || a.len()
10490 < t.len()
10491 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
10492 || freq.as_ref().is_some_and(|freq| freq.len() < ALPHABET_SIZE)
10493 {
10494 return -1;
10495 }
10496 if t.len() <= 1 {
10497 fill_freq(t, freq);
10498 if t.len() == 1 {
10499 u[0] = t[0];
10500 }
10501 return t.len() as SaSint;
10502 }
10503
10504 let n = t.len();
10505 let mut index = main_16u_ctx(ctx, t, a, LIBSAIS_FLAGS_BWT, 0, None, fs, freq);
10506 if index >= 0 {
10507 index += 1;
10508 u[0] = t[n - 1];
10509 bwt_copy_16u(&mut u[1..], a, index - 1);
10510 bwt_copy_16u(
10511 &mut u[index as usize..],
10512 &a[index as usize..],
10513 n as SaSint - index,
10514 );
10515 }
10516 index
10517}
10518
10519pub fn libsais16x64_bwt_aux_ctx(
10532 ctx: &mut Context,
10533 t: &[u16],
10534 u: &mut [u16],
10535 a: &mut [SaSint],
10536 fs: SaSint,
10537 freq: Option<&mut [SaSint]>,
10538 r: SaSint,
10539 i: &mut [SaSint],
10540) -> SaSint {
10541 if fs < 0 || r < 2 || (r & (r - 1)) != 0 {
10542 return -1;
10543 }
10544 let samples = if t.is_empty() {
10545 1
10546 } else {
10547 (t.len() - 1) / r as usize + 1
10548 };
10549 if u.len() < t.len()
10550 || a.len()
10551 < t.len()
10552 .saturating_add(usize::try_from(fs).unwrap_or(usize::MAX))
10553 || i.len() < samples
10554 || freq.as_ref().is_some_and(|freq| freq.len() < ALPHABET_SIZE)
10555 {
10556 return -1;
10557 }
10558 if t.len() <= 1 {
10559 fill_freq(t, freq);
10560 if t.len() == 1 {
10561 u[0] = t[0];
10562 }
10563 i[0] = t.len() as SaSint;
10564 return 0;
10565 }
10566
10567 let n = t.len();
10568 let index = main_16u_ctx(ctx, t, a, LIBSAIS_FLAGS_BWT, r, Some(i), fs, freq);
10569 if index == 0 {
10570 u[0] = t[n - 1];
10571 bwt_copy_16u(&mut u[1..], a, i[0] - 1);
10572 bwt_copy_16u(
10573 &mut u[i[0] as usize..],
10574 &a[i[0] as usize..],
10575 n as SaSint - i[0],
10576 );
10577 }
10578 index
10579}
10580
10581pub fn libsais16x64_bwt_omp(
10595 t: &[u16],
10596 u: &mut [u16],
10597 a: &mut [SaSint],
10598 fs: SaSint,
10599 freq: Option<&mut [SaSint]>,
10600 threads: SaSint,
10601) -> SaSint {
10602 if threads < 0 {
10603 -1
10604 } else {
10605 build_bwt(t, u, a, fs, freq, threads)
10606 }
10607}
10608
10609pub fn libsais16x64_bwt_aux_omp(
10625 t: &[u16],
10626 u: &mut [u16],
10627 a: &mut [SaSint],
10628 fs: SaSint,
10629 freq: Option<&mut [SaSint]>,
10630 r: SaSint,
10631 i: &mut [SaSint],
10632 threads: SaSint,
10633) -> SaSint {
10634 if threads < 0 {
10635 -1
10636 } else {
10637 build_bwt_aux(t, u, a, fs, freq, r, i, threads)
10638 }
10639}
10640
10641fn validate_unbwt_aux(
10642 t: &[u16],
10643 u: &[u16],
10644 a: &[SaSint],
10645 freq: Option<&[SaSint]>,
10646 r: SaSint,
10647 i: &[SaSint],
10648) -> SaSint {
10649 let n = t.len();
10650 if u.len() < n
10651 || a.len() < n
10652 || freq.is_some_and(|freq| freq.len() < ALPHABET_SIZE)
10653 || ((r != n as SaSint) && (r < 2 || (r & (r - 1)) != 0))
10654 || i.is_empty()
10655 {
10656 return -1;
10657 }
10658 if n <= 1 {
10659 return if i[0] == n as SaSint { 0 } else { -1 };
10660 }
10661
10662 let samples = (n - 1) / r as usize + 1;
10663 if i.len() < samples {
10664 return -1;
10665 }
10666
10667 for &index in &i[..samples] {
10668 if index <= 0 || index as usize > n {
10669 return -1;
10670 }
10671 }
10672 0
10673}
10674
10675fn unbwt_compute_histogram(t: &[u16], count: &mut [usize]) {
10676 for &symbol in t {
10677 count[symbol as usize] += 1;
10678 }
10679}
10680
10681fn unbwt_shift(n: usize) -> usize {
10682 let mut shift = 0usize;
10683 while (n >> shift) > (1usize << UNBWT_FASTBITS) {
10684 shift += 1;
10685 }
10686 shift
10687}
10688
10689fn unbwt_calculate_fastbits(bucket2: &mut [usize], fastbits: &mut [u16], shift: usize) {
10690 let mut v = 0usize;
10691 let mut sum = 1usize;
10692 for (w, bucket) in bucket2.iter_mut().enumerate().take(ALPHABET_SIZE) {
10693 let prev = sum;
10694 sum += *bucket;
10695 *bucket = prev;
10696 if prev != sum {
10697 while v <= ((sum - 1) >> shift) {
10698 fastbits[v] = w as u16;
10699 v += 1;
10700 }
10701 }
10702 }
10703}
10704
10705fn unbwt_calculate_p(t: &[u16], p: &mut [usize], bucket2: &mut [usize], index: usize) {
10706 for row in 0..index {
10707 let symbol = t[row] as usize;
10708 p[bucket2[symbol]] = row;
10709 bucket2[symbol] += 1;
10710 }
10711
10712 for row in index + 1..=t.len() {
10713 let symbol = t[row - 1] as usize;
10714 p[bucket2[symbol]] = row;
10715 bucket2[symbol] += 1;
10716 }
10717}
10718
10719#[allow(dead_code, non_snake_case)]
10720fn unbwt_calculate_P(
10721 t: &[u16],
10722 p: &mut [usize],
10723 bucket2: &mut [usize],
10724 index: usize,
10725 block_start: usize,
10726 block_end: usize,
10727) {
10728 let first_end = index.min(block_end);
10729 for row in block_start..first_end {
10730 let symbol = t[row] as usize;
10731 p[bucket2[symbol]] = row;
10732 bucket2[symbol] += 1;
10733 }
10734
10735 let second_start = block_start.max(index) + 1;
10736 for row in second_start..=block_end {
10737 let symbol = t[row - 1] as usize;
10738 p[bucket2[symbol]] = row;
10739 bucket2[symbol] += 1;
10740 }
10741}
10742
10743fn unbwt_init_single(
10744 t: &[u16],
10745 p: &mut [usize],
10746 freq: Option<&[SaSint]>,
10747 i: &[SaSint],
10748 bucket2: &mut [usize],
10749 fastbits: &mut [u16],
10750) {
10751 let shift = unbwt_shift(t.len());
10752 if let Some(freq) = freq {
10753 for c in 0..ALPHABET_SIZE {
10754 bucket2[c] = freq[c] as usize;
10755 }
10756 } else {
10757 bucket2.fill(0);
10758 unbwt_compute_histogram(t, bucket2);
10759 }
10760
10761 unbwt_calculate_fastbits(bucket2, fastbits, shift);
10762 unbwt_calculate_p(t, p, bucket2, i[0] as usize);
10763}
10764
10765#[allow(dead_code)]
10766fn unbwt_init_parallel(
10767 t: &[u16],
10768 p: &mut [usize],
10769 freq: Option<&[SaSint]>,
10770 i: &[SaSint],
10771 bucket2: &mut [usize],
10772 fastbits: &mut [u16],
10773 buckets: &mut [usize],
10774 threads: SaSint,
10775) {
10776 let n = t.len();
10777 let available_threads = buckets.len() / ALPHABET_SIZE;
10778 let num_threads = if threads > 1 && n >= 65_536 && available_threads > 1 {
10779 usize::try_from(threads)
10780 .expect("threads must be non-negative")
10781 .min(available_threads)
10782 .max(1)
10783 } else {
10784 1
10785 };
10786
10787 if num_threads == 1 {
10788 unbwt_init_single(t, p, freq, i, bucket2, fastbits);
10789 return;
10790 }
10791
10792 let index = usize::try_from(i[0]).expect("primary index must be non-negative");
10793 let shift = unbwt_shift(n);
10794 let block_stride = (n / num_threads) & !15usize;
10795
10796 for thread in 0..num_threads {
10797 let block_start = thread * block_stride;
10798 let block_size = if thread + 1 < num_threads {
10799 block_stride
10800 } else {
10801 n - block_start
10802 };
10803 let local = &mut buckets[thread * ALPHABET_SIZE..(thread + 1) * ALPHABET_SIZE];
10804 local.fill(0);
10805 unbwt_compute_histogram(&t[block_start..block_start + block_size], local);
10806 }
10807
10808 bucket2.fill(0);
10809 for thread in 0..num_threads {
10810 let local = &mut buckets[thread * ALPHABET_SIZE..(thread + 1) * ALPHABET_SIZE];
10811 for c in 0..ALPHABET_SIZE {
10812 let a = bucket2[c];
10813 let b = local[c];
10814 bucket2[c] = a + b;
10815 local[c] = a;
10816 }
10817 }
10818
10819 unbwt_calculate_fastbits(bucket2, fastbits, shift);
10820
10821 for thread in 0..num_threads {
10822 let block_start = thread * block_stride;
10823 let block_size = if thread + 1 < num_threads {
10824 block_stride
10825 } else {
10826 n - block_start
10827 };
10828 let local = &mut buckets[thread * ALPHABET_SIZE..(thread + 1) * ALPHABET_SIZE];
10829 for c in 0..ALPHABET_SIZE {
10830 local[c] += bucket2[c];
10831 }
10832 unbwt_calculate_P(t, p, local, index, block_start, block_start + block_size);
10833 }
10834
10835 let last_local = &buckets[(num_threads - 1) * ALPHABET_SIZE..num_threads * ALPHABET_SIZE];
10836 bucket2.copy_from_slice(last_local);
10837}
10838
10839fn unbwt_decode_symbol(
10840 p0: usize,
10841 p: &[usize],
10842 bucket2: &[usize],
10843 fastbits: &[u16],
10844 shift: usize,
10845) -> (u16, usize) {
10846 let mut c0 = fastbits[p0 >> shift] as usize;
10847 if bucket2[c0] <= p0 {
10848 while bucket2[c0] <= p0 {
10849 c0 += 1;
10850 }
10851 }
10852 (c0 as u16, p[p0])
10853}
10854
10855#[allow(dead_code)]
10856fn unbwt_decode_1(
10857 u: &mut [u16],
10858 p: &[usize],
10859 bucket2: &[usize],
10860 fastbits: &[u16],
10861 shift: usize,
10862 i0: &mut usize,
10863 k: usize,
10864) {
10865 let mut cursors = [*i0];
10866 unbwt_decode_lanes::<1>(u, p, bucket2, fastbits, shift, k, &mut cursors, k);
10867 *i0 = cursors[0];
10868}
10869
10870#[allow(dead_code)]
10871fn unbwt_decode_2(
10872 u: &mut [u16],
10873 p: &[usize],
10874 bucket2: &[usize],
10875 fastbits: &[u16],
10876 shift: usize,
10877 r: usize,
10878 i0: &mut usize,
10879 i1: &mut usize,
10880 k: usize,
10881) {
10882 let mut cursors = [*i0, *i1];
10883 unbwt_decode_lanes::<2>(u, p, bucket2, fastbits, shift, r, &mut cursors, k);
10884 *i0 = cursors[0];
10885 *i1 = cursors[1];
10886}
10887
10888#[allow(dead_code)]
10889fn unbwt_decode_3(
10890 u: &mut [u16],
10891 p: &[usize],
10892 bucket2: &[usize],
10893 fastbits: &[u16],
10894 shift: usize,
10895 r: usize,
10896 i0: &mut usize,
10897 i1: &mut usize,
10898 i2: &mut usize,
10899 k: usize,
10900) {
10901 let mut cursors = [*i0, *i1, *i2];
10902 unbwt_decode_lanes::<3>(u, p, bucket2, fastbits, shift, r, &mut cursors, k);
10903 *i0 = cursors[0];
10904 *i1 = cursors[1];
10905 *i2 = cursors[2];
10906}
10907
10908#[allow(dead_code)]
10909fn unbwt_decode_4(
10910 u: &mut [u16],
10911 p: &[usize],
10912 bucket2: &[usize],
10913 fastbits: &[u16],
10914 shift: usize,
10915 r: usize,
10916 i0: &mut usize,
10917 i1: &mut usize,
10918 i2: &mut usize,
10919 i3: &mut usize,
10920 k: usize,
10921) {
10922 let mut cursors = [*i0, *i1, *i2, *i3];
10923 unbwt_decode_lanes::<4>(u, p, bucket2, fastbits, shift, r, &mut cursors, k);
10924 *i0 = cursors[0];
10925 *i1 = cursors[1];
10926 *i2 = cursors[2];
10927 *i3 = cursors[3];
10928}
10929
10930#[allow(dead_code)]
10931fn unbwt_decode_5(
10932 u: &mut [u16],
10933 p: &[usize],
10934 bucket2: &[usize],
10935 fastbits: &[u16],
10936 shift: usize,
10937 r: usize,
10938 cursors: &mut [usize; 5],
10939 k: usize,
10940) {
10941 unbwt_decode_lanes::<5>(u, p, bucket2, fastbits, shift, r, cursors, k);
10942}
10943
10944#[allow(dead_code)]
10945fn unbwt_decode_6(
10946 u: &mut [u16],
10947 p: &[usize],
10948 bucket2: &[usize],
10949 fastbits: &[u16],
10950 shift: usize,
10951 r: usize,
10952 cursors: &mut [usize; 6],
10953 k: usize,
10954) {
10955 unbwt_decode_lanes::<6>(u, p, bucket2, fastbits, shift, r, cursors, k);
10956}
10957
10958#[allow(dead_code)]
10959fn unbwt_decode_7(
10960 u: &mut [u16],
10961 p: &[usize],
10962 bucket2: &[usize],
10963 fastbits: &[u16],
10964 shift: usize,
10965 r: usize,
10966 cursors: &mut [usize; 7],
10967 k: usize,
10968) {
10969 unbwt_decode_lanes::<7>(u, p, bucket2, fastbits, shift, r, cursors, k);
10970}
10971
10972#[allow(dead_code)]
10973fn unbwt_decode_8(
10974 u: &mut [u16],
10975 p: &[usize],
10976 bucket2: &[usize],
10977 fastbits: &[u16],
10978 shift: usize,
10979 r: usize,
10980 cursors: &mut [usize; 8],
10981 k: usize,
10982) {
10983 unbwt_decode_lanes::<8>(u, p, bucket2, fastbits, shift, r, cursors, k);
10984}
10985
10986fn unbwt_decode(
10987 u: &mut [u16],
10988 p: &[usize],
10989 n: usize,
10990 r: usize,
10991 i: &[SaSint],
10992 bucket2: &[usize],
10993 fastbits: &[u16],
10994) {
10995 let shift = unbwt_shift(n);
10996 let blocks = 1 + (n - 1) / r;
10997 let remainder = n - r * (blocks - 1);
10998 unbwt_decode_blocks(u, p, r, i, bucket2, fastbits, shift, blocks, remainder);
10999}
11000
11001fn unbwt_decode_blocks(
11002 u: &mut [u16],
11003 p: &[usize],
11004 r: usize,
11005 i: &[SaSint],
11006 bucket2: &[usize],
11007 fastbits: &[u16],
11008 shift: usize,
11009 blocks: usize,
11010 remainder: usize,
11011) {
11012 let mut blocks_left = blocks;
11013 let mut i_offset = 0usize;
11014 let mut u_offset = 0usize;
11015
11016 while blocks_left > 8 {
11017 let mut cursors = [
11018 i[i_offset] as usize,
11019 i[i_offset + 1] as usize,
11020 i[i_offset + 2] as usize,
11021 i[i_offset + 3] as usize,
11022 i[i_offset + 4] as usize,
11023 i[i_offset + 5] as usize,
11024 i[i_offset + 6] as usize,
11025 i[i_offset + 7] as usize,
11026 ];
11027 unbwt_decode_lanes::<8>(
11028 &mut u[u_offset..],
11029 p,
11030 bucket2,
11031 fastbits,
11032 shift,
11033 r,
11034 &mut cursors,
11035 r,
11036 );
11037 i_offset += 8;
11038 blocks_left -= 8;
11039 u_offset += 8 * r;
11040 }
11041
11042 match blocks_left {
11043 1 => {
11044 let mut cursors = [i[i_offset] as usize];
11045 unbwt_decode_lanes::<1>(
11046 &mut u[u_offset..],
11047 p,
11048 bucket2,
11049 fastbits,
11050 shift,
11051 r,
11052 &mut cursors,
11053 remainder,
11054 );
11055 }
11056 2 => {
11057 let mut cursors = [i[i_offset] as usize, i[i_offset + 1] as usize];
11058 unbwt_decode_lanes::<2>(
11059 &mut u[u_offset..],
11060 p,
11061 bucket2,
11062 fastbits,
11063 shift,
11064 r,
11065 &mut cursors,
11066 remainder,
11067 );
11068 let mut first = [cursors[0]];
11069 unbwt_decode_lanes::<1>(
11070 &mut u[u_offset + remainder..],
11071 p,
11072 bucket2,
11073 fastbits,
11074 shift,
11075 r,
11076 &mut first,
11077 r - remainder,
11078 );
11079 }
11080 3 => {
11081 let mut cursors = [
11082 i[i_offset] as usize,
11083 i[i_offset + 1] as usize,
11084 i[i_offset + 2] as usize,
11085 ];
11086 unbwt_decode_lanes::<3>(
11087 &mut u[u_offset..],
11088 p,
11089 bucket2,
11090 fastbits,
11091 shift,
11092 r,
11093 &mut cursors,
11094 remainder,
11095 );
11096 let mut first = [cursors[0], cursors[1]];
11097 unbwt_decode_lanes::<2>(
11098 &mut u[u_offset + remainder..],
11099 p,
11100 bucket2,
11101 fastbits,
11102 shift,
11103 r,
11104 &mut first,
11105 r - remainder,
11106 );
11107 }
11108 4 => {
11109 let mut cursors = [
11110 i[i_offset] as usize,
11111 i[i_offset + 1] as usize,
11112 i[i_offset + 2] as usize,
11113 i[i_offset + 3] as usize,
11114 ];
11115 unbwt_decode_lanes::<4>(
11116 &mut u[u_offset..],
11117 p,
11118 bucket2,
11119 fastbits,
11120 shift,
11121 r,
11122 &mut cursors,
11123 remainder,
11124 );
11125 let mut first = [cursors[0], cursors[1], cursors[2]];
11126 unbwt_decode_lanes::<3>(
11127 &mut u[u_offset + remainder..],
11128 p,
11129 bucket2,
11130 fastbits,
11131 shift,
11132 r,
11133 &mut first,
11134 r - remainder,
11135 );
11136 }
11137 5 => {
11138 let mut cursors = [
11139 i[i_offset] as usize,
11140 i[i_offset + 1] as usize,
11141 i[i_offset + 2] as usize,
11142 i[i_offset + 3] as usize,
11143 i[i_offset + 4] as usize,
11144 ];
11145 unbwt_decode_lanes::<5>(
11146 &mut u[u_offset..],
11147 p,
11148 bucket2,
11149 fastbits,
11150 shift,
11151 r,
11152 &mut cursors,
11153 remainder,
11154 );
11155 let mut first = [cursors[0], cursors[1], cursors[2], cursors[3]];
11156 unbwt_decode_lanes::<4>(
11157 &mut u[u_offset + remainder..],
11158 p,
11159 bucket2,
11160 fastbits,
11161 shift,
11162 r,
11163 &mut first,
11164 r - remainder,
11165 );
11166 }
11167 6 => {
11168 let mut cursors = [
11169 i[i_offset] as usize,
11170 i[i_offset + 1] as usize,
11171 i[i_offset + 2] as usize,
11172 i[i_offset + 3] as usize,
11173 i[i_offset + 4] as usize,
11174 i[i_offset + 5] as usize,
11175 ];
11176 unbwt_decode_lanes::<6>(
11177 &mut u[u_offset..],
11178 p,
11179 bucket2,
11180 fastbits,
11181 shift,
11182 r,
11183 &mut cursors,
11184 remainder,
11185 );
11186 let mut first = [cursors[0], cursors[1], cursors[2], cursors[3], cursors[4]];
11187 unbwt_decode_lanes::<5>(
11188 &mut u[u_offset + remainder..],
11189 p,
11190 bucket2,
11191 fastbits,
11192 shift,
11193 r,
11194 &mut first,
11195 r - remainder,
11196 );
11197 }
11198 7 => {
11199 let mut cursors = [
11200 i[i_offset] as usize,
11201 i[i_offset + 1] as usize,
11202 i[i_offset + 2] as usize,
11203 i[i_offset + 3] as usize,
11204 i[i_offset + 4] as usize,
11205 i[i_offset + 5] as usize,
11206 i[i_offset + 6] as usize,
11207 ];
11208 unbwt_decode_lanes::<7>(
11209 &mut u[u_offset..],
11210 p,
11211 bucket2,
11212 fastbits,
11213 shift,
11214 r,
11215 &mut cursors,
11216 remainder,
11217 );
11218 let mut first = [
11219 cursors[0], cursors[1], cursors[2], cursors[3], cursors[4], cursors[5],
11220 ];
11221 unbwt_decode_lanes::<6>(
11222 &mut u[u_offset + remainder..],
11223 p,
11224 bucket2,
11225 fastbits,
11226 shift,
11227 r,
11228 &mut first,
11229 r - remainder,
11230 );
11231 }
11232 _ => {
11233 let mut cursors = [
11234 i[i_offset] as usize,
11235 i[i_offset + 1] as usize,
11236 i[i_offset + 2] as usize,
11237 i[i_offset + 3] as usize,
11238 i[i_offset + 4] as usize,
11239 i[i_offset + 5] as usize,
11240 i[i_offset + 6] as usize,
11241 i[i_offset + 7] as usize,
11242 ];
11243 unbwt_decode_lanes::<8>(
11244 &mut u[u_offset..],
11245 p,
11246 bucket2,
11247 fastbits,
11248 shift,
11249 r,
11250 &mut cursors,
11251 remainder,
11252 );
11253 let mut first = [
11254 cursors[0], cursors[1], cursors[2], cursors[3], cursors[4], cursors[5], cursors[6],
11255 ];
11256 unbwt_decode_lanes::<7>(
11257 &mut u[u_offset + remainder..],
11258 p,
11259 bucket2,
11260 fastbits,
11261 shift,
11262 r,
11263 &mut first,
11264 r - remainder,
11265 );
11266 }
11267 }
11268}
11269
11270fn unbwt_decode_omp(
11271 u: &mut [u16],
11272 p: &[usize],
11273 n: usize,
11274 r: usize,
11275 i: &[SaSint],
11276 bucket2: &[usize],
11277 fastbits: &[u16],
11278 threads: SaSint,
11279) {
11280 let blocks = 1 + (n - 1) / r;
11281 let remainder = n - r * (blocks - 1);
11282 let num_threads = if threads > 1 && n >= 65_536 {
11283 usize::try_from(threads)
11284 .expect("threads must be non-negative")
11285 .min(blocks)
11286 .max(1)
11287 } else {
11288 1
11289 };
11290
11291 if num_threads == 1 {
11292 unbwt_decode(u, p, n, r, i, bucket2, fastbits);
11293 return;
11294 }
11295
11296 let shift = unbwt_shift(n);
11297 let block_stride = blocks / num_threads;
11298 let block_remainder = blocks % num_threads;
11299 let u_ptr = SyncMutPtr::new(u);
11300 run_rayon_with_threads(num_threads, || {
11301 (0..num_threads).into_par_iter().for_each(|thread| {
11302 let block_count = block_stride + usize::from(thread < block_remainder);
11303 let block_start = block_stride * thread + thread.min(block_remainder);
11304 let tail = if thread + 1 < num_threads {
11305 r
11306 } else {
11307 remainder
11308 };
11309 let u = unsafe { u_ptr.as_slice() };
11310 unbwt_decode_blocks(
11311 &mut u[r * block_start..],
11312 p,
11313 r,
11314 &i[block_start..],
11315 bucket2,
11316 fastbits,
11317 shift,
11318 block_count,
11319 tail,
11320 );
11321 });
11322 });
11323}
11324
11325fn unbwt_decode_lanes<const LANES: usize>(
11326 u: &mut [u16],
11327 p: &[usize],
11328 bucket2: &[usize],
11329 fastbits: &[u16],
11330 shift: usize,
11331 r: usize,
11332 cursors: &mut [usize; LANES],
11333 k: usize,
11334) {
11335 for pos in 0..k {
11336 for lane in 0..LANES {
11337 let (symbol, next) = unbwt_decode_symbol(cursors[lane], p, bucket2, fastbits, shift);
11338 cursors[lane] = next;
11339 u[lane * r + pos] = symbol;
11340 }
11341 }
11342}
11343
11344fn unbwt_core(
11345 t: &[u16],
11346 u: &mut [u16],
11347 a: &mut [SaSint],
11348 freq: Option<&[SaSint]>,
11349 r: SaSint,
11350 i: &[SaSint],
11351) -> SaSint {
11352 let n = t.len();
11353 let shift = unbwt_shift(n);
11354 let mut bucket2 = vec![0usize; ALPHABET_SIZE];
11355 let mut fastbits = vec![0u16; 1 + (n >> shift)];
11356
11357 unbwt_core_with_buffers(t, u, a, freq, r, i, &mut bucket2, &mut fastbits, 1)
11358}
11359
11360fn unbwt_core_with_buffers(
11361 t: &[u16],
11362 u: &mut [u16],
11363 a: &mut [SaSint],
11364 freq: Option<&[SaSint]>,
11365 r: SaSint,
11366 i: &[SaSint],
11367 bucket2: &mut [usize],
11368 fastbits: &mut [u16],
11369 threads: SaSint,
11370) -> SaSint {
11371 let n = t.len();
11372 let shift = unbwt_shift(n);
11373 if bucket2.len() < ALPHABET_SIZE || fastbits.len() < 1 + (n >> shift) {
11374 return -2;
11375 }
11376
11377 let mut p = vec![0usize; n + 1];
11378 unbwt_init_single(
11379 t,
11380 &mut p,
11381 freq,
11382 i,
11383 &mut bucket2[..ALPHABET_SIZE],
11384 &mut fastbits[..1 + (n >> shift)],
11385 );
11386 unbwt_decode_omp(
11387 u,
11388 &p,
11389 n,
11390 r as usize,
11391 i,
11392 &bucket2[..ALPHABET_SIZE],
11393 &fastbits[..1 + (n >> shift)],
11394 threads,
11395 );
11396
11397 for (dst, &src) in a.iter_mut().zip(p.iter().skip(1)) {
11398 *dst = src as SaSint;
11399 }
11400 0
11401}
11402
11403fn inverse_bwt(
11404 t: &[u16],
11405 u: &mut [u16],
11406 a: &mut [SaSint],
11407 freq: Option<&[SaSint]>,
11408 primary: SaSint,
11409) -> SaSint {
11410 let n = t.len();
11411 let i = [primary];
11412 let rc = validate_unbwt_aux(t, u, a, freq, n as SaSint, &i);
11413 if rc != 0 {
11414 return rc;
11415 }
11416 if n <= 1 {
11417 if n == 1 {
11418 u[0] = t[0];
11419 }
11420 return 0;
11421 }
11422 unbwt_core(t, u, a, freq, n as SaSint, &i)
11423}
11424
11425pub fn libsais16x64_unbwt(
11438 t: &[u16],
11439 u: &mut [u16],
11440 a: &mut [SaSint],
11441 freq: Option<&[SaSint]>,
11442 i: SaSint,
11443) -> SaSint {
11444 inverse_bwt(t, u, a, freq, i)
11445}
11446
11447pub fn libsais16x64_unbwt_ctx(
11458 ctx: &mut UnbwtContext,
11459 t: &[u16],
11460 u: &mut [u16],
11461 a: &mut [SaSint],
11462 freq: Option<&[SaSint]>,
11463 i: SaSint,
11464) -> SaSint {
11465 libsais16x64_unbwt_aux_ctx(ctx, t, u, a, freq, t.len() as SaSint, &[i])
11466}
11467
11468pub fn libsais16x64_unbwt_aux(
11482 t: &[u16],
11483 u: &mut [u16],
11484 a: &mut [SaSint],
11485 freq: Option<&[SaSint]>,
11486 r: SaSint,
11487 i: &[SaSint],
11488) -> SaSint {
11489 let rc = validate_unbwt_aux(t, u, a, freq, r, i);
11490 if rc != 0 {
11491 return rc;
11492 }
11493 if t.len() <= 1 {
11494 if t.len() == 1 {
11495 u[0] = t[0];
11496 }
11497 return 0;
11498 }
11499 unbwt_core(t, u, a, freq, r, i)
11500}
11501
11502pub fn libsais16x64_unbwt_aux_ctx(
11514 ctx: &mut UnbwtContext,
11515 t: &[u16],
11516 u: &mut [u16],
11517 a: &mut [SaSint],
11518 freq: Option<&[SaSint]>,
11519 r: SaSint,
11520 i: &[SaSint],
11521) -> SaSint {
11522 let rc = validate_unbwt_aux(t, u, a, freq, r, i);
11523 if rc != 0 {
11524 return rc;
11525 }
11526 if t.len() <= 1 {
11527 if t.len() == 1 {
11528 u[0] = t[0];
11529 }
11530 return 0;
11531 }
11532 unbwt_core_with_buffers(
11533 t,
11534 u,
11535 a,
11536 freq,
11537 r,
11538 i,
11539 &mut ctx.bucket2,
11540 &mut ctx.fastbits,
11541 ctx.threads,
11542 )
11543}
11544
11545pub fn libsais16x64_unbwt_omp(
11559 t: &[u16],
11560 u: &mut [u16],
11561 a: &mut [SaSint],
11562 freq: Option<&[SaSint]>,
11563 i: SaSint,
11564 threads: SaSint,
11565) -> SaSint {
11566 if threads < 0 {
11567 -1
11568 } else {
11569 let primary = [i];
11570 libsais16x64_unbwt_aux_omp(t, u, a, freq, t.len() as SaSint, &primary, threads)
11571 }
11572}
11573
11574pub fn libsais16x64_unbwt_aux_omp(
11589 t: &[u16],
11590 u: &mut [u16],
11591 a: &mut [SaSint],
11592 freq: Option<&[SaSint]>,
11593 r: SaSint,
11594 i: &[SaSint],
11595 threads: SaSint,
11596) -> SaSint {
11597 if threads < 0 {
11598 -1
11599 } else {
11600 let rc = validate_unbwt_aux(t, u, a, freq, r, i);
11601 if rc != 0 {
11602 return rc;
11603 }
11604 if t.len() <= 1 {
11605 if t.len() == 1 {
11606 u[0] = t[0];
11607 }
11608 return 0;
11609 }
11610 let n = t.len();
11611 let shift = unbwt_shift(n);
11612 let mut bucket2 = vec![0usize; ALPHABET_SIZE];
11613 let mut fastbits = vec![0u16; 1 + (n >> shift)];
11614 unbwt_core_with_buffers(
11615 t,
11616 u,
11617 a,
11618 freq,
11619 r,
11620 i,
11621 &mut bucket2,
11622 &mut fastbits,
11623 normalize_threads(threads),
11624 )
11625 }
11626}
11627
11628pub fn libsais16x64_plcp(t: &[u16], sa: &[SaSint], plcp: &mut [SaSint]) -> SaSint {
11639 compute_plcp(t, sa, plcp, false)
11640}
11641
11642pub fn libsais16x64_plcp_gsa(t: &[u16], sa: &[SaSint], plcp: &mut [SaSint]) -> SaSint {
11653 if t.last().copied().unwrap_or(0) != 0 {
11654 -1
11655 } else {
11656 compute_plcp(t, sa, plcp, true)
11657 }
11658}
11659
11660fn compute_plcp(t: &[u16], sa: &[SaSint], plcp: &mut [SaSint], gsa: bool) -> SaSint {
11661 if sa.len() != t.len() || plcp.len() != t.len() {
11662 return -1;
11663 }
11664 if t.len() <= 1 {
11665 if t.len() == 1 {
11666 plcp[0] = 0;
11667 }
11668 return 0;
11669 }
11670
11671 if compute_phi(sa, plcp) != 0 {
11672 return -1;
11673 }
11674
11675 compute_plcp_from_phi(t, plcp, gsa)
11676}
11677
11678fn compute_phi(sa: &[SaSint], plcp: &mut [SaSint]) -> SaSint {
11679 let n = sa.len();
11680 let mut previous = n as SaSint;
11681 for &suffix_value in sa {
11682 let Some(suffix) = suffix_index(suffix_value, n) else {
11683 return -1;
11684 };
11685 plcp[suffix] = previous;
11686 previous = suffix_value;
11687 }
11688 0
11689}
11690
11691fn compute_plcp_from_phi(t: &[u16], plcp: &mut [SaSint], gsa: bool) -> SaSint {
11692 let n = t.len();
11693 let mut l = 0usize;
11694 for i in 0..t.len() {
11695 let previous = plcp[i];
11696 if previous == n as SaSint {
11697 plcp[i] = 0;
11698 l = 0;
11699 continue;
11700 }
11701
11702 let Some(prev) = suffix_index(previous, n) else {
11703 return -1;
11704 };
11705
11706 while i + l < t.len()
11707 && prev + l < t.len()
11708 && t[i + l] == t[prev + l]
11709 && (!gsa || t[i + l] != 0)
11710 {
11711 l += 1;
11712 }
11713 plcp[i] = l as SaSint;
11714 l = l.saturating_sub(1);
11715 }
11716 0
11717}
11718
11719fn compute_phi_omp(sa: &[SaSint], plcp: &mut [SaSint], n: SaSint, threads: SaSint) -> SaSint {
11720 let n_usize = n as usize;
11721 if threads == 1 || n < 65_536 {
11722 return compute_phi(&sa[..n_usize], &mut plcp[..n_usize]);
11723 }
11724
11725 let block_stride = (n / threads) & !15;
11726 for thread in 0..threads {
11727 let block_start = thread * block_stride;
11728 let block_size = if thread < threads - 1 {
11729 block_stride
11730 } else {
11731 n - block_start
11732 };
11733 let start = block_start as usize;
11734 let end = (block_start + block_size) as usize;
11735 let mut previous = if start > 0 { sa[start - 1] } else { n };
11736 for &suffix_value in &sa[start..end] {
11737 let Some(suffix) = suffix_index(suffix_value, n_usize) else {
11738 return -1;
11739 };
11740 plcp[suffix] = previous;
11741 previous = suffix_value;
11742 }
11743 }
11744 0
11745}
11746
11747fn compute_plcp_omp(t: &[u16], plcp: &mut [SaSint], n: SaSint, threads: SaSint) -> SaSint {
11748 if threads == 1 || n < 65_536 {
11749 let n = n as usize;
11750 return compute_plcp_from_phi(&t[..n], &mut plcp[..n], false);
11751 }
11752
11753 let block_stride = (n / threads) & !15;
11754 for thread in 0..threads {
11755 let block_start = thread * block_stride;
11756 let block_size = if thread < threads - 1 {
11757 block_stride
11758 } else {
11759 n - block_start
11760 };
11761 let rc = compute_plcp_range(
11762 t,
11763 plcp,
11764 n as usize,
11765 block_start as isize,
11766 block_size as isize,
11767 false,
11768 );
11769 if rc != 0 {
11770 return rc;
11771 }
11772 }
11773 0
11774}
11775
11776fn compute_plcp_range(
11777 t: &[u16],
11778 plcp: &mut [SaSint],
11779 n: usize,
11780 omp_block_start: isize,
11781 omp_block_size: isize,
11782 gsa: bool,
11783) -> SaSint {
11784 let mut l = 0usize;
11785 let end = (omp_block_start + omp_block_size) as usize;
11786 for i in omp_block_start as usize..end {
11787 let previous = plcp[i];
11788 if previous == n as SaSint {
11789 plcp[i] = 0;
11790 l = 0;
11791 continue;
11792 }
11793
11794 let Some(prev) = suffix_index(previous, n) else {
11795 return -1;
11796 };
11797
11798 while i + l < t.len()
11799 && prev + l < t.len()
11800 && t[i + l] == t[prev + l]
11801 && (!gsa || t[i + l] != 0)
11802 {
11803 l += 1;
11804 }
11805 plcp[i] = l as SaSint;
11806 l = l.saturating_sub(1);
11807 }
11808 0
11809}
11810
11811fn compute_plcp_gsa(
11812 t: &[u16],
11813 plcp: &mut [SaSint],
11814 omp_block_start: isize,
11815 omp_block_size: isize,
11816) -> SaSint {
11817 let n = t.len();
11818 let mut l = 0usize;
11819 let end = (omp_block_start + omp_block_size) as usize;
11820 for i in omp_block_start as usize..end {
11821 let previous = plcp[i];
11822 if previous == n as SaSint {
11823 plcp[i] = 0;
11824 l = 0;
11825 continue;
11826 }
11827
11828 let Some(prev) = suffix_index(previous, n) else {
11829 return -1;
11830 };
11831
11832 while i + l < t.len() && prev + l < t.len() && t[i + l] == t[prev + l] && t[i + l] != 0 {
11833 l += 1;
11834 }
11835 plcp[i] = l as SaSint;
11836 l = l.saturating_sub(1);
11837 }
11838 0
11839}
11840
11841fn compute_plcp_gsa_omp(t: &[u16], plcp: &mut [SaSint], n: SaSint, threads: SaSint) -> SaSint {
11842 if threads == 1 || n < 65_536 {
11843 return compute_plcp_gsa(t, plcp, 0, n as isize);
11844 }
11845
11846 let block_stride = (n / threads) & !15;
11847 for thread in 0..threads {
11848 let block_start = thread * block_stride;
11849 let block_size = if thread < threads - 1 {
11850 block_stride
11851 } else {
11852 n - block_start
11853 };
11854 let rc = compute_plcp_gsa(t, plcp, block_start as isize, block_size as isize);
11855 if rc != 0 {
11856 return rc;
11857 }
11858 }
11859 0
11860}
11861
11862fn compute_lcp(
11863 plcp: &[SaSint],
11864 sa: &[SaSint],
11865 lcp: &mut [SaSint],
11866 omp_block_start: isize,
11867 omp_block_size: isize,
11868) -> SaSint {
11869 let end = (omp_block_start + omp_block_size) as usize;
11870 for row in omp_block_start as usize..end {
11871 let Some(suffix) = suffix_index(sa[row], plcp.len()) else {
11872 return -1;
11873 };
11874 lcp[row] = plcp[suffix];
11875 }
11876 0
11877}
11878
11879fn compute_lcp_omp(
11880 plcp: &[SaSint],
11881 sa: &[SaSint],
11882 lcp: &mut [SaSint],
11883 n: SaSint,
11884 threads: SaSint,
11885) -> SaSint {
11886 if threads == 1 || n < 65_536 {
11887 return compute_lcp(plcp, sa, lcp, 0, n as isize);
11888 }
11889
11890 let block_stride = (n / threads) & !15;
11891 for thread in 0..threads {
11892 let block_start = thread * block_stride;
11893 let block_size = if thread < threads - 1 {
11894 block_stride
11895 } else {
11896 n - block_start
11897 };
11898 let rc = compute_lcp(plcp, sa, lcp, block_start as isize, block_size as isize);
11899 if rc != 0 {
11900 return rc;
11901 }
11902 }
11903 0
11904}
11905
11906pub fn libsais16x64_lcp(plcp: &[SaSint], sa: &[SaSint], lcp: &mut [SaSint]) -> SaSint {
11917 if plcp.len() != sa.len() || lcp.len() != sa.len() {
11918 return -1;
11919 }
11920 for (row, &suffix) in sa.iter().enumerate() {
11921 let Some(suffix) = suffix_index(suffix, plcp.len()) else {
11922 return -1;
11923 };
11924 lcp[row] = plcp[suffix];
11925 }
11926 0
11927}
11928
11929fn suffix_index(value: SaSint, len: usize) -> Option<usize> {
11930 usize::try_from(value).ok().filter(|&index| index < len)
11931}
11932
11933pub fn libsais16x64_plcp_omp(
11945 t: &[u16],
11946 sa: &[SaSint],
11947 plcp: &mut [SaSint],
11948 threads: SaSint,
11949) -> SaSint {
11950 if threads < 0 {
11951 return -1;
11952 }
11953 if sa.len() != t.len() || plcp.len() != t.len() {
11954 return -1;
11955 }
11956 if t.len() <= 1 {
11957 if t.len() == 1 {
11958 plcp[0] = 0;
11959 }
11960 return 0;
11961 }
11962
11963 let n = t.len() as SaSint;
11964 let threads = normalize_threads(threads);
11965 if compute_phi_omp(sa, plcp, n, threads) != 0 {
11966 return -1;
11967 }
11968 compute_plcp_omp(t, plcp, n, threads)
11969}
11970
11971pub fn libsais16x64_plcp_gsa_omp(
11983 t: &[u16],
11984 sa: &[SaSint],
11985 plcp: &mut [SaSint],
11986 threads: SaSint,
11987) -> SaSint {
11988 if threads < 0 {
11989 return -1;
11990 }
11991 if t.last().copied().unwrap_or(0) != 0 {
11992 return -1;
11993 }
11994 if sa.len() != t.len() || plcp.len() != t.len() {
11995 return -1;
11996 }
11997 if t.len() <= 1 {
11998 if t.len() == 1 {
11999 plcp[0] = 0;
12000 }
12001 return 0;
12002 }
12003
12004 let n = t.len() as SaSint;
12005 let threads = normalize_threads(threads);
12006 if compute_phi_omp(sa, plcp, n, threads) != 0 {
12007 return -1;
12008 }
12009 compute_plcp_gsa_omp(t, plcp, n, threads)
12010}
12011
12012pub fn libsais16x64_lcp_omp(
12024 plcp: &[SaSint],
12025 sa: &[SaSint],
12026 lcp: &mut [SaSint],
12027 threads: SaSint,
12028) -> SaSint {
12029 if threads < 0 {
12030 return -1;
12031 }
12032 if plcp.len() != sa.len() || lcp.len() != sa.len() {
12033 return -1;
12034 }
12035
12036 compute_lcp_omp(
12037 plcp,
12038 sa,
12039 lcp,
12040 sa.len() as SaSint,
12041 normalize_threads(threads),
12042 )
12043}
12044
12045#[cfg(all(test, feature = "upstream-c"))]
12046mod tests {
12047 use super::*;
12048
12049 unsafe extern "C" {
12050 fn probe_public_libsais16x64(
12051 t: *const u16,
12052 sa: *mut SaSint,
12053 n: SaSint,
12054 fs: SaSint,
12055 ) -> SaSint;
12056 fn probe_public_libsais16x64_freq(
12057 t: *const u16,
12058 sa: *mut SaSint,
12059 n: SaSint,
12060 fs: SaSint,
12061 freq: *mut SaSint,
12062 ) -> SaSint;
12063 fn probe_public_libsais16x64_gsa(
12064 t: *const u16,
12065 sa: *mut SaSint,
12066 n: SaSint,
12067 fs: SaSint,
12068 ) -> SaSint;
12069 fn probe_public_libsais16x64_gsa_freq(
12070 t: *const u16,
12071 sa: *mut SaSint,
12072 n: SaSint,
12073 fs: SaSint,
12074 freq: *mut SaSint,
12075 ) -> SaSint;
12076 fn probe_public_libsais16x64_long(
12077 t: *mut SaSint,
12078 sa: *mut SaSint,
12079 n: SaSint,
12080 k: SaSint,
12081 fs: SaSint,
12082 ) -> SaSint;
12083 fn probe_libsais16x64_main_32s_entry(
12084 t: *mut SaSint,
12085 sa: *mut SaSint,
12086 n: SaSint,
12087 k: SaSint,
12088 fs: SaSint,
12089 threads: SaSint,
12090 ) -> SaSint;
12091 fn probe_libsais16x64_final_sorting_scan_left_to_right_32s(
12092 t: *const SaSint,
12093 sa: *mut SaSint,
12094 induction_bucket: *mut SaSint,
12095 omp_block_start: SaSint,
12096 omp_block_size: SaSint,
12097 );
12098 fn probe_libsais16x64_final_sorting_scan_right_to_left_32s(
12099 t: *const SaSint,
12100 sa: *mut SaSint,
12101 induction_bucket: *mut SaSint,
12102 omp_block_start: SaSint,
12103 omp_block_size: SaSint,
12104 );
12105 fn probe_libsais16x64_clear_lms_suffixes_omp(
12106 sa: *mut SaSint,
12107 n: SaSint,
12108 k: SaSint,
12109 bucket_start: *mut SaSint,
12110 bucket_end: *mut SaSint,
12111 threads: SaSint,
12112 );
12113 fn probe_libsais16x64_flip_suffix_markers_omp(sa: *mut SaSint, l: SaSint, threads: SaSint);
12114 fn probe_libsais16x64_induce_final_order_32s_6k(
12115 t: *const SaSint,
12116 sa: *mut SaSint,
12117 n: SaSint,
12118 k: SaSint,
12119 buckets: *mut SaSint,
12120 threads: SaSint,
12121 );
12122 fn probe_libsais16x64_induce_final_order_32s_4k(
12123 t: *const SaSint,
12124 sa: *mut SaSint,
12125 n: SaSint,
12126 k: SaSint,
12127 buckets: *mut SaSint,
12128 threads: SaSint,
12129 );
12130 fn probe_libsais16x64_induce_final_order_32s_2k(
12131 t: *const SaSint,
12132 sa: *mut SaSint,
12133 n: SaSint,
12134 k: SaSint,
12135 buckets: *mut SaSint,
12136 threads: SaSint,
12137 );
12138 fn probe_libsais16x64_induce_final_order_32s_1k(
12139 t: *const SaSint,
12140 sa: *mut SaSint,
12141 n: SaSint,
12142 k: SaSint,
12143 buckets: *mut SaSint,
12144 threads: SaSint,
12145 );
12146 fn probe_libsais16x64_induce_partial_order_32s_6k_omp(
12147 t: *const SaSint,
12148 sa: *mut SaSint,
12149 n: SaSint,
12150 k: SaSint,
12151 buckets: *mut SaSint,
12152 first_lms_suffix: SaSint,
12153 left_suffixes_count: SaSint,
12154 threads: SaSint,
12155 );
12156 fn probe_libsais16x64_induce_partial_order_32s_4k_omp(
12157 t: *const SaSint,
12158 sa: *mut SaSint,
12159 n: SaSint,
12160 k: SaSint,
12161 buckets: *mut SaSint,
12162 threads: SaSint,
12163 );
12164 fn probe_libsais16x64_induce_partial_order_32s_2k_omp(
12165 t: *const SaSint,
12166 sa: *mut SaSint,
12167 n: SaSint,
12168 k: SaSint,
12169 buckets: *mut SaSint,
12170 threads: SaSint,
12171 );
12172 fn probe_libsais16x64_induce_partial_order_32s_1k_omp(
12173 t: *const SaSint,
12174 sa: *mut SaSint,
12175 n: SaSint,
12176 k: SaSint,
12177 buckets: *mut SaSint,
12178 threads: SaSint,
12179 );
12180 fn probe_libsais16x64_induce_partial_order_16u_omp(
12181 t: *const u16,
12182 sa: *mut SaSint,
12183 n: SaSint,
12184 k: SaSint,
12185 flags: SaSint,
12186 buckets: *mut SaSint,
12187 first_lms_suffix: SaSint,
12188 left_suffixes_count: SaSint,
12189 threads: SaSint,
12190 );
12191 fn probe_libsais16x64_induce_final_order_16u_omp(
12192 t: *const u16,
12193 sa: *mut SaSint,
12194 n: SaSint,
12195 k: SaSint,
12196 flags: SaSint,
12197 r: SaSint,
12198 i: *mut SaSint,
12199 buckets: *mut SaSint,
12200 threads: SaSint,
12201 ) -> SaSint;
12202 fn probe_public_libsais16x64_bwt(
12203 t: *const u16,
12204 u: *mut u16,
12205 a: *mut SaSint,
12206 n: SaSint,
12207 fs: SaSint,
12208 ) -> SaSint;
12209 fn probe_public_libsais16x64_bwt_freq(
12210 t: *const u16,
12211 u: *mut u16,
12212 a: *mut SaSint,
12213 n: SaSint,
12214 fs: SaSint,
12215 freq: *mut SaSint,
12216 ) -> SaSint;
12217 fn probe_public_libsais16x64_bwt_aux(
12218 t: *const u16,
12219 u: *mut u16,
12220 a: *mut SaSint,
12221 n: SaSint,
12222 fs: SaSint,
12223 r: SaSint,
12224 i: *mut SaSint,
12225 ) -> SaSint;
12226 fn probe_public_libsais16x64_bwt_aux_freq(
12227 t: *const u16,
12228 u: *mut u16,
12229 a: *mut SaSint,
12230 n: SaSint,
12231 fs: SaSint,
12232 freq: *mut SaSint,
12233 r: SaSint,
12234 i: *mut SaSint,
12235 ) -> SaSint;
12236 fn probe_public_libsais16x64_unbwt(
12237 t: *const u16,
12238 u: *mut u16,
12239 a: *mut SaSint,
12240 n: SaSint,
12241 i: SaSint,
12242 ) -> SaSint;
12243 fn probe_public_libsais16x64_unbwt_freq(
12244 t: *const u16,
12245 u: *mut u16,
12246 a: *mut SaSint,
12247 n: SaSint,
12248 freq: *const SaSint,
12249 i: SaSint,
12250 ) -> SaSint;
12251 fn probe_public_libsais16x64_unbwt_aux(
12252 t: *const u16,
12253 u: *mut u16,
12254 a: *mut SaSint,
12255 n: SaSint,
12256 r: SaSint,
12257 i: *const SaSint,
12258 ) -> SaSint;
12259 fn probe_public_libsais16x64_unbwt_aux_freq(
12260 t: *const u16,
12261 u: *mut u16,
12262 a: *mut SaSint,
12263 n: SaSint,
12264 freq: *const SaSint,
12265 r: SaSint,
12266 i: *const SaSint,
12267 ) -> SaSint;
12268 fn probe_public_libsais16x64_plcp(
12269 t: *const u16,
12270 sa: *const SaSint,
12271 plcp: *mut SaSint,
12272 n: SaSint,
12273 ) -> SaSint;
12274 fn probe_public_libsais16x64_plcp_gsa(
12275 t: *const u16,
12276 sa: *const SaSint,
12277 plcp: *mut SaSint,
12278 n: SaSint,
12279 ) -> SaSint;
12280 fn probe_public_libsais16x64_lcp(
12281 plcp: *const SaSint,
12282 sa: *const SaSint,
12283 lcp: *mut SaSint,
12284 n: SaSint,
12285 ) -> SaSint;
12286 fn probe_libsais16x64_gather_lms_suffixes_16u(
12287 t: *const u16,
12288 sa: *mut SaSint,
12289 n: SaSint,
12290 m: SaSint,
12291 omp_block_start: SaSint,
12292 omp_block_size: SaSint,
12293 );
12294 fn probe_libsais16x64_count_and_gather_lms_suffixes_16u(
12295 t: *const u16,
12296 sa: *mut SaSint,
12297 n: SaSint,
12298 buckets: *mut SaSint,
12299 omp_block_start: SaSint,
12300 omp_block_size: SaSint,
12301 ) -> SaSint;
12302 fn probe_libsais16x64_initialize_buckets_start_and_end_16u(
12303 buckets: *mut SaSint,
12304 freq: *mut SaSint,
12305 ) -> SaSint;
12306 fn probe_libsais16x64_initialize_buckets_for_lms_suffixes_radix_sort_16u(
12307 t: *const u16,
12308 buckets: *mut SaSint,
12309 first_lms_suffix: SaSint,
12310 ) -> SaSint;
12311 fn probe_libsais16x64_radix_sort_lms_suffixes_16u(
12312 t: *const u16,
12313 sa: *mut SaSint,
12314 induction_bucket: *mut SaSint,
12315 omp_block_start: SaSint,
12316 omp_block_size: SaSint,
12317 );
12318 fn probe_libsais16x64_initialize_buckets_for_partial_sorting_16u(
12319 t: *const u16,
12320 buckets: *mut SaSint,
12321 first_lms_suffix: SaSint,
12322 left_suffixes_count: SaSint,
12323 );
12324 fn probe_libsais16x64_partial_sorting_scan_left_to_right_16u(
12325 t: *const u16,
12326 sa: *mut SaSint,
12327 buckets: *mut SaSint,
12328 d: SaSint,
12329 omp_block_start: SaSint,
12330 omp_block_size: SaSint,
12331 ) -> SaSint;
12332 fn probe_libsais16x64_partial_sorting_scan_right_to_left_16u(
12333 t: *const u16,
12334 sa: *mut SaSint,
12335 buckets: *mut SaSint,
12336 d: SaSint,
12337 omp_block_start: SaSint,
12338 omp_block_size: SaSint,
12339 ) -> SaSint;
12340 fn probe_libsais16x64_partial_gsa_scan_right_to_left_16u(
12341 t: *const u16,
12342 sa: *mut SaSint,
12343 buckets: *mut SaSint,
12344 d: SaSint,
12345 omp_block_start: SaSint,
12346 omp_block_size: SaSint,
12347 ) -> SaSint;
12348 fn probe_libsais16x64_partial_sorting_shift_markers_16u_omp(
12349 sa: *mut SaSint,
12350 n: SaSint,
12351 buckets: *const SaSint,
12352 threads: SaSint,
12353 );
12354 fn probe_libsais16x64_final_sorting_scan_left_to_right_16u(
12355 t: *const u16,
12356 sa: *mut SaSint,
12357 induction_bucket: *mut SaSint,
12358 omp_block_start: SaSint,
12359 omp_block_size: SaSint,
12360 );
12361 fn probe_libsais16x64_final_sorting_scan_right_to_left_16u(
12362 t: *const u16,
12363 sa: *mut SaSint,
12364 induction_bucket: *mut SaSint,
12365 omp_block_start: SaSint,
12366 omp_block_size: SaSint,
12367 );
12368 fn probe_libsais16x64_final_gsa_scan_right_to_left_16u(
12369 t: *const u16,
12370 sa: *mut SaSint,
12371 induction_bucket: *mut SaSint,
12372 omp_block_start: SaSint,
12373 omp_block_size: SaSint,
12374 );
12375 fn probe_libsais16x64_final_bwt_scan_left_to_right_16u(
12376 t: *const u16,
12377 sa: *mut SaSint,
12378 induction_bucket: *mut SaSint,
12379 omp_block_start: SaSint,
12380 omp_block_size: SaSint,
12381 );
12382 fn probe_libsais16x64_final_bwt_scan_right_to_left_16u(
12383 t: *const u16,
12384 sa: *mut SaSint,
12385 induction_bucket: *mut SaSint,
12386 omp_block_start: SaSint,
12387 omp_block_size: SaSint,
12388 ) -> SaSint;
12389 fn probe_libsais16x64_final_bwt_aux_scan_left_to_right_16u(
12390 t: *const u16,
12391 sa: *mut SaSint,
12392 rm: SaSint,
12393 i_sample: *mut SaSint,
12394 induction_bucket: *mut SaSint,
12395 omp_block_start: SaSint,
12396 omp_block_size: SaSint,
12397 );
12398 fn probe_libsais16x64_final_bwt_aux_scan_right_to_left_16u(
12399 t: *const u16,
12400 sa: *mut SaSint,
12401 rm: SaSint,
12402 i_sample: *mut SaSint,
12403 induction_bucket: *mut SaSint,
12404 omp_block_start: SaSint,
12405 omp_block_size: SaSint,
12406 );
12407 fn probe_libsais16x64_renumber_lms_suffixes_16u(
12408 sa: *mut SaSint,
12409 m: SaSint,
12410 name: SaSint,
12411 omp_block_start: SaSint,
12412 omp_block_size: SaSint,
12413 ) -> SaSint;
12414 fn probe_libsais16x64_place_lms_suffixes_interval_16u(
12415 sa: *mut SaSint,
12416 n: SaSint,
12417 m: SaSint,
12418 flags: SaSint,
12419 buckets: *mut SaSint,
12420 );
12421 fn probe_libsais16x64_bwt_copy_16u(u: *mut u16, a: *mut SaSint, n: SaSint);
12422 fn probe_libsais16x64_gather_lms_suffixes_16u_omp(
12423 t: *const u16,
12424 sa: *mut SaSint,
12425 n: SaSint,
12426 threads: SaSint,
12427 );
12428 fn probe_libsais16x64_count_and_gather_lms_suffixes_16u_omp(
12429 t: *const u16,
12430 sa: *mut SaSint,
12431 n: SaSint,
12432 buckets: *mut SaSint,
12433 threads: SaSint,
12434 ) -> SaSint;
12435 fn probe_libsais16x64_radix_sort_lms_suffixes_16u_omp(
12436 t: *const u16,
12437 sa: *mut SaSint,
12438 n: SaSint,
12439 m: SaSint,
12440 flags: SaSint,
12441 buckets: *mut SaSint,
12442 threads: SaSint,
12443 );
12444 fn probe_libsais16x64_partial_sorting_scan_left_to_right_16u_omp(
12445 t: *const u16,
12446 sa: *mut SaSint,
12447 n: SaSint,
12448 k: SaSint,
12449 buckets: *mut SaSint,
12450 left_suffixes_count: SaSint,
12451 d: SaSint,
12452 threads: SaSint,
12453 ) -> SaSint;
12454 fn probe_libsais16x64_partial_sorting_scan_right_to_left_16u_omp(
12455 t: *const u16,
12456 sa: *mut SaSint,
12457 n: SaSint,
12458 k: SaSint,
12459 buckets: *mut SaSint,
12460 first_lms_suffix: SaSint,
12461 left_suffixes_count: SaSint,
12462 d: SaSint,
12463 threads: SaSint,
12464 );
12465 fn probe_libsais16x64_partial_gsa_scan_right_to_left_16u_omp(
12466 t: *const u16,
12467 sa: *mut SaSint,
12468 n: SaSint,
12469 k: SaSint,
12470 buckets: *mut SaSint,
12471 first_lms_suffix: SaSint,
12472 left_suffixes_count: SaSint,
12473 d: SaSint,
12474 threads: SaSint,
12475 );
12476 fn probe_libsais16x64_renumber_lms_suffixes_16u_omp(
12477 sa: *mut SaSint,
12478 m: SaSint,
12479 threads: SaSint,
12480 ) -> SaSint;
12481 fn probe_libsais16x64_final_bwt_scan_left_to_right_16u_omp(
12482 t: *const u16,
12483 sa: *mut SaSint,
12484 n: SaSint,
12485 k: SaSint,
12486 induction_bucket: *mut SaSint,
12487 threads: SaSint,
12488 );
12489 fn probe_libsais16x64_final_bwt_aux_scan_left_to_right_16u_omp(
12490 t: *const u16,
12491 sa: *mut SaSint,
12492 n: SaSint,
12493 k: SaSint,
12494 rm: SaSint,
12495 i_sample: *mut SaSint,
12496 induction_bucket: *mut SaSint,
12497 threads: SaSint,
12498 );
12499 fn probe_libsais16x64_final_sorting_scan_left_to_right_16u_omp(
12500 t: *const u16,
12501 sa: *mut SaSint,
12502 n: SaSint,
12503 k: SaSint,
12504 induction_bucket: *mut SaSint,
12505 threads: SaSint,
12506 );
12507 fn probe_libsais16x64_final_bwt_scan_right_to_left_16u_omp(
12508 t: *const u16,
12509 sa: *mut SaSint,
12510 n: SaSint,
12511 k: SaSint,
12512 induction_bucket: *mut SaSint,
12513 threads: SaSint,
12514 ) -> SaSint;
12515 fn probe_libsais16x64_final_bwt_aux_scan_right_to_left_16u_omp(
12516 t: *const u16,
12517 sa: *mut SaSint,
12518 n: SaSint,
12519 k: SaSint,
12520 rm: SaSint,
12521 i_sample: *mut SaSint,
12522 induction_bucket: *mut SaSint,
12523 threads: SaSint,
12524 );
12525 fn probe_libsais16x64_final_sorting_scan_right_to_left_16u_omp(
12526 t: *const u16,
12527 sa: *mut SaSint,
12528 omp_block_start: SaSint,
12529 omp_block_size: SaSint,
12530 k: SaSint,
12531 induction_bucket: *mut SaSint,
12532 threads: SaSint,
12533 );
12534 fn probe_libsais16x64_final_gsa_scan_right_to_left_16u_omp(
12535 t: *const u16,
12536 sa: *mut SaSint,
12537 omp_block_start: SaSint,
12538 omp_block_size: SaSint,
12539 k: SaSint,
12540 induction_bucket: *mut SaSint,
12541 threads: SaSint,
12542 );
12543 fn probe_libsais16x64_bwt_copy_16u_omp(
12544 u: *mut u16,
12545 a: *mut SaSint,
12546 n: SaSint,
12547 threads: SaSint,
12548 );
12549 fn probe_libsais16x64_gather_marked_lms_suffixes(
12550 sa: *mut SaSint,
12551 m: SaSint,
12552 l: SaSint,
12553 omp_block_start: SaSint,
12554 omp_block_size: SaSint,
12555 ) -> SaSint;
12556 fn probe_libsais16x64_gather_marked_lms_suffixes_omp(
12557 sa: *mut SaSint,
12558 n: SaSint,
12559 m: SaSint,
12560 fs: SaSint,
12561 threads: SaSint,
12562 );
12563 fn probe_libsais16x64_renumber_and_gather_lms_suffixes_omp(
12564 sa: *mut SaSint,
12565 n: SaSint,
12566 m: SaSint,
12567 fs: SaSint,
12568 threads: SaSint,
12569 ) -> SaSint;
12570 fn probe_libsais16x64_reconstruct_lms_suffixes(
12571 sa: *mut SaSint,
12572 n: SaSint,
12573 m: SaSint,
12574 omp_block_start: SaSint,
12575 omp_block_size: SaSint,
12576 );
12577 fn probe_libsais16x64_reconstruct_lms_suffixes_omp(
12578 sa: *mut SaSint,
12579 n: SaSint,
12580 m: SaSint,
12581 threads: SaSint,
12582 );
12583 fn probe_libsais16x64_renumber_distinct_lms_suffixes_32s_4k(
12584 sa: *mut SaSint,
12585 m: SaSint,
12586 name: SaSint,
12587 omp_block_start: SaSint,
12588 omp_block_size: SaSint,
12589 ) -> SaSint;
12590 fn probe_libsais16x64_mark_distinct_lms_suffixes_32s(
12591 sa: *mut SaSint,
12592 m: SaSint,
12593 omp_block_start: SaSint,
12594 omp_block_size: SaSint,
12595 );
12596 fn probe_libsais16x64_clamp_lms_suffixes_length_32s(
12597 sa: *mut SaSint,
12598 m: SaSint,
12599 omp_block_start: SaSint,
12600 omp_block_size: SaSint,
12601 );
12602 fn probe_libsais16x64_renumber_distinct_lms_suffixes_32s_4k_omp(
12603 sa: *mut SaSint,
12604 m: SaSint,
12605 threads: SaSint,
12606 ) -> SaSint;
12607 fn probe_libsais16x64_mark_distinct_lms_suffixes_32s_omp(
12608 sa: *mut SaSint,
12609 n: SaSint,
12610 m: SaSint,
12611 threads: SaSint,
12612 );
12613 fn probe_libsais16x64_clamp_lms_suffixes_length_32s_omp(
12614 sa: *mut SaSint,
12615 n: SaSint,
12616 m: SaSint,
12617 threads: SaSint,
12618 );
12619 fn probe_libsais16x64_renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(
12620 sa: *mut SaSint,
12621 n: SaSint,
12622 m: SaSint,
12623 threads: SaSint,
12624 ) -> SaSint;
12625 fn probe_libsais16x64_renumber_unique_and_nonunique_lms_suffixes_32s(
12626 t: *mut SaSint,
12627 sa: *mut SaSint,
12628 m: SaSint,
12629 f: SaSint,
12630 omp_block_start: SaSint,
12631 omp_block_size: SaSint,
12632 ) -> SaSint;
12633 fn probe_libsais16x64_compact_unique_and_nonunique_lms_suffixes_32s(
12634 sa: *mut SaSint,
12635 m: SaSint,
12636 pl: *mut SaSint,
12637 pr: *mut SaSint,
12638 omp_block_start: SaSint,
12639 omp_block_size: SaSint,
12640 );
12641 fn probe_libsais16x64_renumber_unique_and_nonunique_lms_suffixes_32s_omp(
12642 t: *mut SaSint,
12643 sa: *mut SaSint,
12644 m: SaSint,
12645 threads: SaSint,
12646 ) -> SaSint;
12647 fn probe_libsais16x64_compact_unique_and_nonunique_lms_suffixes_32s_omp(
12648 sa: *mut SaSint,
12649 n: SaSint,
12650 m: SaSint,
12651 fs: SaSint,
12652 f: SaSint,
12653 threads: SaSint,
12654 );
12655 fn probe_libsais16x64_compact_lms_suffixes_32s_omp(
12656 t: *mut SaSint,
12657 sa: *mut SaSint,
12658 n: SaSint,
12659 m: SaSint,
12660 fs: SaSint,
12661 threads: SaSint,
12662 ) -> SaSint;
12663 fn probe_libsais16x64_merge_unique_lms_suffixes_32s(
12664 t: *mut SaSint,
12665 sa: *mut SaSint,
12666 n: SaSint,
12667 m: SaSint,
12668 l: SaSint,
12669 omp_block_start: SaSint,
12670 omp_block_size: SaSint,
12671 );
12672 fn probe_libsais16x64_merge_nonunique_lms_suffixes_32s(
12673 sa: *mut SaSint,
12674 n: SaSint,
12675 m: SaSint,
12676 l: SaSint,
12677 omp_block_start: SaSint,
12678 omp_block_size: SaSint,
12679 );
12680 fn probe_libsais16x64_merge_unique_lms_suffixes_32s_omp(
12681 t: *mut SaSint,
12682 sa: *mut SaSint,
12683 n: SaSint,
12684 m: SaSint,
12685 threads: SaSint,
12686 );
12687 fn probe_libsais16x64_merge_nonunique_lms_suffixes_32s_omp(
12688 sa: *mut SaSint,
12689 n: SaSint,
12690 m: SaSint,
12691 f: SaSint,
12692 threads: SaSint,
12693 );
12694 fn probe_libsais16x64_merge_compacted_lms_suffixes_32s_omp(
12695 t: *mut SaSint,
12696 sa: *mut SaSint,
12697 n: SaSint,
12698 m: SaSint,
12699 f: SaSint,
12700 threads: SaSint,
12701 );
12702 fn probe_libsais16x64_radix_sort_lms_suffixes_32s_6k(
12703 t: *const SaSint,
12704 sa: *mut SaSint,
12705 induction_bucket: *mut SaSint,
12706 omp_block_start: SaSint,
12707 omp_block_size: SaSint,
12708 );
12709 fn probe_libsais16x64_radix_sort_lms_suffixes_32s_2k(
12710 t: *const SaSint,
12711 sa: *mut SaSint,
12712 induction_bucket: *mut SaSint,
12713 omp_block_start: SaSint,
12714 omp_block_size: SaSint,
12715 );
12716 fn probe_libsais16x64_radix_sort_lms_suffixes_32s_6k_omp(
12717 t: *const SaSint,
12718 sa: *mut SaSint,
12719 n: SaSint,
12720 m: SaSint,
12721 induction_bucket: *mut SaSint,
12722 threads: SaSint,
12723 );
12724 fn probe_libsais16x64_radix_sort_lms_suffixes_32s_2k_omp(
12725 t: *const SaSint,
12726 sa: *mut SaSint,
12727 n: SaSint,
12728 m: SaSint,
12729 induction_bucket: *mut SaSint,
12730 threads: SaSint,
12731 );
12732 fn probe_libsais16x64_radix_sort_lms_suffixes_32s_1k(
12733 t: *const SaSint,
12734 sa: *mut SaSint,
12735 n: SaSint,
12736 buckets: *mut SaSint,
12737 ) -> SaSint;
12738 fn probe_libsais16x64_radix_sort_set_markers_32s_6k(
12739 sa: *mut SaSint,
12740 induction_bucket: *mut SaSint,
12741 omp_block_start: SaSint,
12742 omp_block_size: SaSint,
12743 );
12744 fn probe_libsais16x64_radix_sort_set_markers_32s_4k(
12745 sa: *mut SaSint,
12746 induction_bucket: *mut SaSint,
12747 omp_block_start: SaSint,
12748 omp_block_size: SaSint,
12749 );
12750 fn probe_libsais16x64_radix_sort_set_markers_32s_6k_omp(
12751 sa: *mut SaSint,
12752 k: SaSint,
12753 induction_bucket: *mut SaSint,
12754 threads: SaSint,
12755 );
12756 fn probe_libsais16x64_radix_sort_set_markers_32s_4k_omp(
12757 sa: *mut SaSint,
12758 k: SaSint,
12759 induction_bucket: *mut SaSint,
12760 threads: SaSint,
12761 );
12762 fn probe_libsais16x64_place_lms_suffixes_histogram_32s_6k(
12763 sa: *mut SaSint,
12764 n: SaSint,
12765 k: SaSint,
12766 m: SaSint,
12767 buckets: *const SaSint,
12768 );
12769 fn probe_libsais16x64_place_lms_suffixes_histogram_32s_4k(
12770 sa: *mut SaSint,
12771 n: SaSint,
12772 k: SaSint,
12773 m: SaSint,
12774 buckets: *const SaSint,
12775 );
12776 fn probe_libsais16x64_place_lms_suffixes_histogram_32s_2k(
12777 sa: *mut SaSint,
12778 n: SaSint,
12779 k: SaSint,
12780 m: SaSint,
12781 buckets: *const SaSint,
12782 );
12783 fn probe_libsais16x64_gather_lms_suffixes_32s(
12784 t: *const SaSint,
12785 sa: *mut SaSint,
12786 n: SaSint,
12787 ) -> SaSint;
12788 fn probe_libsais16x64_gather_compacted_lms_suffixes_32s(
12789 t: *const SaSint,
12790 sa: *mut SaSint,
12791 n: SaSint,
12792 ) -> SaSint;
12793 fn probe_libsais16x64_count_lms_suffixes_32s_2k(
12794 t: *const SaSint,
12795 n: SaSint,
12796 k: SaSint,
12797 buckets: *mut SaSint,
12798 );
12799 fn probe_libsais16x64_count_and_gather_lms_suffixes_32s_4k(
12800 t: *const SaSint,
12801 sa: *mut SaSint,
12802 n: SaSint,
12803 k: SaSint,
12804 buckets: *mut SaSint,
12805 omp_block_start: SaSint,
12806 omp_block_size: SaSint,
12807 ) -> SaSint;
12808 fn probe_libsais16x64_count_and_gather_lms_suffixes_32s_4k_omp(
12809 t: *const SaSint,
12810 sa: *mut SaSint,
12811 n: SaSint,
12812 k: SaSint,
12813 buckets: *mut SaSint,
12814 local_buckets: SaSint,
12815 threads: SaSint,
12816 ) -> SaSint;
12817 fn probe_libsais16x64_count_suffixes_32s(
12818 t: *const SaSint,
12819 n: SaSint,
12820 k: SaSint,
12821 buckets: *mut SaSint,
12822 );
12823 fn probe_libsais16x64_initialize_buckets_start_and_end_32s_6k(
12824 k: SaSint,
12825 buckets: *mut SaSint,
12826 );
12827 fn probe_libsais16x64_initialize_buckets_start_and_end_32s_4k(
12828 k: SaSint,
12829 buckets: *mut SaSint,
12830 );
12831 fn probe_libsais16x64_initialize_buckets_end_32s_2k(k: SaSint, buckets: *mut SaSint);
12832 fn probe_libsais16x64_initialize_buckets_start_and_end_32s_2k(
12833 k: SaSint,
12834 buckets: *mut SaSint,
12835 );
12836 fn probe_libsais16x64_initialize_buckets_start_32s_1k(k: SaSint, buckets: *mut SaSint);
12837 fn probe_libsais16x64_initialize_buckets_end_32s_1k(k: SaSint, buckets: *mut SaSint);
12838 fn probe_libsais16x64_initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(
12839 t: *const SaSint,
12840 k: SaSint,
12841 buckets: *mut SaSint,
12842 first_lms_suffix: SaSint,
12843 );
12844 fn probe_libsais16x64_initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(
12845 t: *const SaSint,
12846 k: SaSint,
12847 buckets: *mut SaSint,
12848 first_lms_suffix: SaSint,
12849 ) -> SaSint;
12850 fn probe_libsais16x64_initialize_buckets_for_radix_and_partial_sorting_32s_4k(
12851 t: *const SaSint,
12852 k: SaSint,
12853 buckets: *mut SaSint,
12854 first_lms_suffix: SaSint,
12855 );
12856 fn probe_libsais16x64_place_lms_suffixes_interval_32s_4k(
12857 sa: *mut SaSint,
12858 n: SaSint,
12859 k: SaSint,
12860 m: SaSint,
12861 buckets: *const SaSint,
12862 );
12863 fn probe_libsais16x64_place_lms_suffixes_interval_32s_2k(
12864 sa: *mut SaSint,
12865 n: SaSint,
12866 k: SaSint,
12867 m: SaSint,
12868 buckets: *const SaSint,
12869 );
12870 fn probe_libsais16x64_place_lms_suffixes_interval_32s_1k(
12871 t: *const SaSint,
12872 sa: *mut SaSint,
12873 k: SaSint,
12874 m: SaSint,
12875 buckets: *mut SaSint,
12876 );
12877 fn probe_libsais16x64_renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(
12878 t: *mut SaSint,
12879 sa: *mut SaSint,
12880 n: SaSint,
12881 m: SaSint,
12882 threads: SaSint,
12883 ) -> SaSint;
12884 fn probe_libsais16x64_partial_sorting_shift_markers_32s_6k_omp(
12885 sa: *mut SaSint,
12886 k: SaSint,
12887 buckets: *const SaSint,
12888 threads: SaSint,
12889 );
12890 fn probe_libsais16x64_partial_sorting_shift_markers_32s_4k(sa: *mut SaSint, n: SaSint);
12891 fn probe_libsais16x64_partial_sorting_shift_buckets_32s_6k(k: SaSint, buckets: *mut SaSint);
12892 fn probe_libsais16x64_partial_sorting_scan_left_to_right_32s_6k(
12893 t: *const SaSint,
12894 sa: *mut SaSint,
12895 buckets: *mut SaSint,
12896 d: SaSint,
12897 omp_block_start: SaSint,
12898 omp_block_size: SaSint,
12899 ) -> SaSint;
12900 fn probe_libsais16x64_partial_sorting_scan_left_to_right_32s_4k(
12901 t: *const SaSint,
12902 sa: *mut SaSint,
12903 k: SaSint,
12904 buckets: *mut SaSint,
12905 d: SaSint,
12906 omp_block_start: SaSint,
12907 omp_block_size: SaSint,
12908 ) -> SaSint;
12909 fn probe_libsais16x64_partial_sorting_scan_left_to_right_32s_1k(
12910 t: *const SaSint,
12911 sa: *mut SaSint,
12912 buckets: *mut SaSint,
12913 omp_block_start: SaSint,
12914 omp_block_size: SaSint,
12915 );
12916 fn probe_libsais16x64_partial_sorting_scan_left_to_right_32s_6k_omp(
12917 t: *const SaSint,
12918 sa: *mut SaSint,
12919 n: SaSint,
12920 buckets: *mut SaSint,
12921 left_suffixes_count: SaSint,
12922 d: SaSint,
12923 threads: SaSint,
12924 ) -> SaSint;
12925 fn probe_libsais16x64_partial_sorting_scan_left_to_right_32s_4k_omp(
12926 t: *const SaSint,
12927 sa: *mut SaSint,
12928 n: SaSint,
12929 k: SaSint,
12930 buckets: *mut SaSint,
12931 d: SaSint,
12932 threads: SaSint,
12933 ) -> SaSint;
12934 fn probe_libsais16x64_partial_sorting_scan_left_to_right_32s_1k_omp(
12935 t: *const SaSint,
12936 sa: *mut SaSint,
12937 n: SaSint,
12938 buckets: *mut SaSint,
12939 threads: SaSint,
12940 );
12941 fn probe_libsais16x64_partial_sorting_scan_right_to_left_32s_6k(
12942 t: *const SaSint,
12943 sa: *mut SaSint,
12944 buckets: *mut SaSint,
12945 d: SaSint,
12946 omp_block_start: SaSint,
12947 omp_block_size: SaSint,
12948 ) -> SaSint;
12949 fn probe_libsais16x64_partial_sorting_scan_right_to_left_32s_4k(
12950 t: *const SaSint,
12951 sa: *mut SaSint,
12952 k: SaSint,
12953 buckets: *mut SaSint,
12954 d: SaSint,
12955 omp_block_start: SaSint,
12956 omp_block_size: SaSint,
12957 ) -> SaSint;
12958 fn probe_libsais16x64_partial_sorting_scan_right_to_left_32s_1k(
12959 t: *const SaSint,
12960 sa: *mut SaSint,
12961 buckets: *mut SaSint,
12962 omp_block_start: SaSint,
12963 omp_block_size: SaSint,
12964 );
12965 fn probe_libsais16x64_partial_sorting_scan_right_to_left_32s_6k_omp(
12966 t: *const SaSint,
12967 sa: *mut SaSint,
12968 n: SaSint,
12969 buckets: *mut SaSint,
12970 first_lms_suffix: SaSint,
12971 left_suffixes_count: SaSint,
12972 d: SaSint,
12973 threads: SaSint,
12974 ) -> SaSint;
12975 fn probe_libsais16x64_partial_sorting_scan_right_to_left_32s_4k_omp(
12976 t: *const SaSint,
12977 sa: *mut SaSint,
12978 n: SaSint,
12979 k: SaSint,
12980 buckets: *mut SaSint,
12981 d: SaSint,
12982 threads: SaSint,
12983 ) -> SaSint;
12984 fn probe_libsais16x64_partial_sorting_scan_right_to_left_32s_1k_omp(
12985 t: *const SaSint,
12986 sa: *mut SaSint,
12987 n: SaSint,
12988 buckets: *mut SaSint,
12989 threads: SaSint,
12990 );
12991 fn probe_libsais16x64_partial_sorting_gather_lms_suffixes_32s_4k(
12992 sa: *mut SaSint,
12993 omp_block_start: SaSint,
12994 omp_block_size: SaSint,
12995 ) -> SaSint;
12996 fn probe_libsais16x64_partial_sorting_gather_lms_suffixes_32s_1k(
12997 sa: *mut SaSint,
12998 omp_block_start: SaSint,
12999 omp_block_size: SaSint,
13000 ) -> SaSint;
13001 fn probe_libsais16x64_partial_sorting_gather_lms_suffixes_32s_4k_omp(
13002 sa: *mut SaSint,
13003 n: SaSint,
13004 threads: SaSint,
13005 );
13006 fn probe_libsais16x64_partial_sorting_gather_lms_suffixes_32s_1k_omp(
13007 sa: *mut SaSint,
13008 n: SaSint,
13009 threads: SaSint,
13010 );
13011 fn probe_libsais16x64_count_and_gather_lms_suffixes_32s_2k(
13012 t: *const SaSint,
13013 sa: *mut SaSint,
13014 n: SaSint,
13015 k: SaSint,
13016 buckets: *mut SaSint,
13017 omp_block_start: SaSint,
13018 omp_block_size: SaSint,
13019 ) -> SaSint;
13020 fn probe_libsais16x64_count_and_gather_compacted_lms_suffixes_32s_2k(
13021 t: *const SaSint,
13022 sa: *mut SaSint,
13023 n: SaSint,
13024 k: SaSint,
13025 buckets: *mut SaSint,
13026 omp_block_start: SaSint,
13027 omp_block_size: SaSint,
13028 ) -> SaSint;
13029 fn probe_libsais16x64_count_and_gather_lms_suffixes_32s_2k_omp(
13030 t: *const SaSint,
13031 sa: *mut SaSint,
13032 n: SaSint,
13033 k: SaSint,
13034 buckets: *mut SaSint,
13035 local_buckets: SaSint,
13036 threads: SaSint,
13037 ) -> SaSint;
13038 fn probe_libsais16x64_count_and_gather_compacted_lms_suffixes_32s_2k_omp(
13039 t: *const SaSint,
13040 sa: *mut SaSint,
13041 n: SaSint,
13042 k: SaSint,
13043 buckets: *mut SaSint,
13044 local_buckets: SaSint,
13045 threads: SaSint,
13046 );
13047 fn probe_libsais16x64_reconstruct_compacted_lms_suffixes_32s_2k_omp(
13048 t: *mut SaSint,
13049 sa: *mut SaSint,
13050 n: SaSint,
13051 k: SaSint,
13052 m: SaSint,
13053 fs: SaSint,
13054 f: SaSint,
13055 buckets: *mut SaSint,
13056 local_buckets: SaSint,
13057 threads: SaSint,
13058 );
13059 fn probe_libsais16x64_reconstruct_compacted_lms_suffixes_32s_1k_omp(
13060 t: *mut SaSint,
13061 sa: *mut SaSint,
13062 n: SaSint,
13063 m: SaSint,
13064 fs: SaSint,
13065 f: SaSint,
13066 threads: SaSint,
13067 );
13068 }
13069
13070 fn brute_sa(t: &[u16]) -> Vec<SaSint> {
13071 let mut sa: Vec<_> = (0..t.len() as SaSint).collect();
13072 sa.sort_by(|&a, &b| t[a as usize..].cmp(&t[b as usize..]));
13073 sa
13074 }
13075
13076 #[test]
13077 fn libsais16x64_gather_lms_suffixes_16u_matches_c() {
13078 let cases: &[&[u16]] = &[
13079 &[2, 1, 3, 1, 2, 0],
13080 &[7, 7, 7, 7, 0],
13081 &[3, 1, 2, 1, 0, 4, 1, 0],
13082 &[9, 1, 9, 1, 9, 0, 2, 2, 0],
13083 ];
13084
13085 for &text in cases {
13086 let n = text.len() as SaSint;
13087 let mut rust_sa = vec![-99; text.len()];
13088 let mut c_sa = rust_sa.clone();
13089
13090 gather_lms_suffixes_16u(text, &mut rust_sa, n, n - 1, 0, n);
13091 unsafe {
13092 probe_libsais16x64_gather_lms_suffixes_16u(
13093 text.as_ptr(),
13094 c_sa.as_mut_ptr(),
13095 n,
13096 n - 1,
13097 0,
13098 n,
13099 );
13100 }
13101
13102 assert_eq!(rust_sa, c_sa);
13103 }
13104 }
13105
13106 #[test]
13107 fn libsais16x64_count_and_gather_lms_suffixes_16u_matches_c() {
13108 let cases: &[&[u16]] = &[
13109 &[2, 1, 3, 1, 2, 0],
13110 &[7, 7, 7, 7, 0],
13111 &[3, 1, 2, 1, 0, 4, 1, 0],
13112 &[9, 1, 9, 1, 9, 0, 2, 2, 0],
13113 ];
13114
13115 for &text in cases {
13116 let n = text.len() as SaSint;
13117 let mut rust_sa = vec![-99; text.len()];
13118 let mut c_sa = rust_sa.clone();
13119 let mut rust_buckets = vec![-1; 4 * ALPHABET_SIZE];
13120 let mut c_buckets = rust_buckets.clone();
13121
13122 let rust_m =
13123 count_and_gather_lms_suffixes_16u(text, &mut rust_sa, n, &mut rust_buckets, 0, n);
13124 let c_m = unsafe {
13125 probe_libsais16x64_count_and_gather_lms_suffixes_16u(
13126 text.as_ptr(),
13127 c_sa.as_mut_ptr(),
13128 n,
13129 c_buckets.as_mut_ptr(),
13130 0,
13131 n,
13132 )
13133 };
13134
13135 assert_eq!(rust_m, c_m);
13136 assert_eq!(rust_sa, c_sa);
13137 assert_eq!(rust_buckets, c_buckets);
13138 }
13139 }
13140
13141 #[test]
13142 fn libsais16x64_initialize_buckets_start_and_end_16u_matches_c() {
13143 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
13144 for (symbol, counts) in [
13145 (0usize, [1, 0, 0, 2]),
13146 (1, [0, 3, 1, 0]),
13147 (7, [2, 1, 0, 1]),
13148 (1024, [0, 0, 5, 0]),
13149 ] {
13150 for state in 0..4 {
13151 rust_buckets[buckets_index4(symbol, state)] = counts[state];
13152 }
13153 }
13154 let mut c_buckets = rust_buckets.clone();
13155 let mut rust_freq = vec![-1; ALPHABET_SIZE];
13156 let mut c_freq = rust_freq.clone();
13157
13158 let rust_k = initialize_buckets_start_and_end_16u(&mut rust_buckets, Some(&mut rust_freq));
13159 let c_k = unsafe {
13160 probe_libsais16x64_initialize_buckets_start_and_end_16u(
13161 c_buckets.as_mut_ptr(),
13162 c_freq.as_mut_ptr(),
13163 )
13164 };
13165
13166 assert_eq!(rust_k, c_k);
13167 assert_eq!(rust_buckets, c_buckets);
13168 assert_eq!(rust_freq, c_freq);
13169
13170 let mut rust_buckets_no_freq = vec![0; 8 * ALPHABET_SIZE];
13171 rust_buckets_no_freq[..4 * ALPHABET_SIZE]
13172 .copy_from_slice(&rust_buckets[..4 * ALPHABET_SIZE]);
13173 let mut c_buckets_no_freq = rust_buckets_no_freq.clone();
13174
13175 let rust_k = initialize_buckets_start_and_end_16u(&mut rust_buckets_no_freq, None);
13176 let c_k = unsafe {
13177 probe_libsais16x64_initialize_buckets_start_and_end_16u(
13178 c_buckets_no_freq.as_mut_ptr(),
13179 std::ptr::null_mut(),
13180 )
13181 };
13182
13183 assert_eq!(rust_k, c_k);
13184 assert_eq!(rust_buckets_no_freq, c_buckets_no_freq);
13185 }
13186
13187 #[test]
13188 fn libsais16x64_lms_radix_bucket_initialization_matches_c() {
13189 let text = [3, 1, 2, 1, 0, 4, 1, 0];
13190 let n = text.len() as SaSint;
13191 let mut rust_sa = vec![-99; text.len()];
13192 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
13193 let m = count_and_gather_lms_suffixes_16u(
13194 &text,
13195 &mut rust_sa,
13196 n,
13197 &mut rust_buckets[..4 * ALPHABET_SIZE],
13198 0,
13199 n,
13200 );
13201 initialize_buckets_start_and_end_16u(&mut rust_buckets, None);
13202 let first_lms_suffix = rust_sa[(n - m) as usize];
13203
13204 let mut c_buckets = rust_buckets.clone();
13205 let rust_count = initialize_buckets_for_lms_suffixes_radix_sort_16u(
13206 &text,
13207 &mut rust_buckets,
13208 first_lms_suffix,
13209 );
13210 let c_count = unsafe {
13211 probe_libsais16x64_initialize_buckets_for_lms_suffixes_radix_sort_16u(
13212 text.as_ptr(),
13213 c_buckets.as_mut_ptr(),
13214 first_lms_suffix,
13215 )
13216 };
13217
13218 assert_eq!(rust_count, c_count);
13219 assert_eq!(rust_buckets, c_buckets);
13220 }
13221
13222 #[test]
13223 fn libsais16x64_radix_sort_lms_suffixes_16u_matches_c() {
13224 let text = [3, 1, 2, 1, 0, 4, 1, 0];
13225 let n = text.len() as SaSint;
13226 let mut rust_sa = vec![-99; text.len()];
13227 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
13228 let m = count_and_gather_lms_suffixes_16u(
13229 &text,
13230 &mut rust_sa,
13231 n,
13232 &mut rust_buckets[..4 * ALPHABET_SIZE],
13233 0,
13234 n,
13235 );
13236 initialize_buckets_start_and_end_16u(&mut rust_buckets, None);
13237 let first_lms_suffix = rust_sa[(n - m) as usize];
13238 initialize_buckets_for_lms_suffixes_radix_sort_16u(
13239 &text,
13240 &mut rust_buckets,
13241 first_lms_suffix,
13242 );
13243
13244 let mut c_sa = rust_sa.clone();
13245 let mut c_buckets = rust_buckets.clone();
13246 {
13247 let induction_bucket = &mut rust_buckets[4 * ALPHABET_SIZE..];
13248 radix_sort_lms_suffixes_16u(&text, &mut rust_sa, induction_bucket, n - m + 1, m - 1);
13249 }
13250 unsafe {
13251 probe_libsais16x64_radix_sort_lms_suffixes_16u(
13252 text.as_ptr(),
13253 c_sa.as_mut_ptr(),
13254 c_buckets[4 * ALPHABET_SIZE..].as_mut_ptr(),
13255 n - m + 1,
13256 m - 1,
13257 );
13258 }
13259
13260 assert_eq!(rust_sa, c_sa);
13261 assert_eq!(rust_buckets, c_buckets);
13262 }
13263
13264 #[test]
13265 fn libsais16x64_initialize_buckets_for_partial_sorting_16u_matches_c() {
13266 let text = [3, 1, 2, 1, 0, 4, 1, 0];
13267 let n = text.len() as SaSint;
13268 let mut rust_sa = vec![-99; text.len()];
13269 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
13270 let m = count_and_gather_lms_suffixes_16u(
13271 &text,
13272 &mut rust_sa,
13273 n,
13274 &mut rust_buckets[..4 * ALPHABET_SIZE],
13275 0,
13276 n,
13277 );
13278 initialize_buckets_start_and_end_16u(&mut rust_buckets, None);
13279 let first_lms_suffix = rust_sa[(n - m) as usize];
13280 let left_suffixes_count = initialize_buckets_for_lms_suffixes_radix_sort_16u(
13281 &text,
13282 &mut rust_buckets,
13283 first_lms_suffix,
13284 );
13285 let mut c_buckets = rust_buckets.clone();
13286
13287 initialize_buckets_for_partial_sorting_16u(
13288 &text,
13289 &mut rust_buckets,
13290 first_lms_suffix,
13291 left_suffixes_count,
13292 );
13293 unsafe {
13294 probe_libsais16x64_initialize_buckets_for_partial_sorting_16u(
13295 text.as_ptr(),
13296 c_buckets.as_mut_ptr(),
13297 first_lms_suffix,
13298 left_suffixes_count,
13299 );
13300 }
13301
13302 assert_eq!(rust_buckets, c_buckets);
13303 }
13304
13305 fn partial_scan_fixture() -> ([u16; 10], Vec<SaSint>, Vec<SaSint>) {
13306 let text = [1, 0, 2, 1, 3, 0, 2, 4, 1, 0];
13307 let mut sa = vec![0; 128];
13308 sa[..5].copy_from_slice(&[3, 5 | SAINT_MIN, 7, 2, 9 | SAINT_MIN]);
13309
13310 let mut buckets = vec![0; 6 * ALPHABET_SIZE];
13311 for v in 0..32 {
13312 buckets[v] = 80 + (v as SaSint) * 4;
13313 buckets[2 * ALPHABET_SIZE + v] = if v % 3 == 0 { 2 } else { 0 };
13314 buckets[4 * ALPHABET_SIZE + v] = 20 + (v as SaSint) * 4;
13315 }
13316
13317 (text, sa, buckets)
13318 }
13319
13320 #[test]
13321 fn libsais16x64_partial_sorting_scan_left_to_right_16u_matches_c() {
13322 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
13323 let mut c_sa = rust_sa.clone();
13324 let mut c_buckets = rust_buckets.clone();
13325
13326 let rust_d =
13327 partial_sorting_scan_left_to_right_16u(&text, &mut rust_sa, &mut rust_buckets, 3, 0, 5);
13328 let c_d = unsafe {
13329 probe_libsais16x64_partial_sorting_scan_left_to_right_16u(
13330 text.as_ptr(),
13331 c_sa.as_mut_ptr(),
13332 c_buckets.as_mut_ptr(),
13333 3,
13334 0,
13335 5,
13336 )
13337 };
13338
13339 assert_eq!(rust_d, c_d);
13340 assert_eq!(rust_sa, c_sa);
13341 assert_eq!(rust_buckets, c_buckets);
13342 }
13343
13344 #[test]
13345 fn libsais16x64_partial_sorting_scan_right_to_left_16u_matches_c() {
13346 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
13347 let mut c_sa = rust_sa.clone();
13348 let mut c_buckets = rust_buckets.clone();
13349
13350 let rust_d =
13351 partial_sorting_scan_right_to_left_16u(&text, &mut rust_sa, &mut rust_buckets, 3, 0, 5);
13352 let c_d = unsafe {
13353 probe_libsais16x64_partial_sorting_scan_right_to_left_16u(
13354 text.as_ptr(),
13355 c_sa.as_mut_ptr(),
13356 c_buckets.as_mut_ptr(),
13357 3,
13358 0,
13359 5,
13360 )
13361 };
13362
13363 assert_eq!(rust_d, c_d);
13364 assert_eq!(rust_sa, c_sa);
13365 assert_eq!(rust_buckets, c_buckets);
13366 }
13367
13368 #[test]
13369 fn libsais16x64_partial_gsa_scan_right_to_left_16u_matches_c() {
13370 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
13371 let mut c_sa = rust_sa.clone();
13372 let mut c_buckets = rust_buckets.clone();
13373
13374 let rust_d =
13375 partial_gsa_scan_right_to_left_16u(&text, &mut rust_sa, &mut rust_buckets, 3, 0, 5);
13376 let c_d = unsafe {
13377 probe_libsais16x64_partial_gsa_scan_right_to_left_16u(
13378 text.as_ptr(),
13379 c_sa.as_mut_ptr(),
13380 c_buckets.as_mut_ptr(),
13381 3,
13382 0,
13383 5,
13384 )
13385 };
13386
13387 assert_eq!(rust_d, c_d);
13388 assert_eq!(rust_sa, c_sa);
13389 assert_eq!(rust_buckets, c_buckets);
13390 }
13391
13392 #[test]
13393 fn libsais16x64_partial_sorting_shift_markers_16u_matches_c() {
13394 let mut rust_sa = vec![0; 16];
13395 rust_sa[2..6].copy_from_slice(&[1, 2 | SAINT_MIN, 3 | SAINT_MIN, 4]);
13396 rust_sa[8..12].copy_from_slice(&[5 | SAINT_MIN, 6, 7 | SAINT_MIN, 8]);
13397 let mut c_sa = rust_sa.clone();
13398
13399 let mut buckets = vec![0; 6 * ALPHABET_SIZE];
13400 buckets[0] = 2;
13401 buckets[2] = 8;
13402 buckets[4 * ALPHABET_SIZE + 2] = 6;
13403 buckets[4 * ALPHABET_SIZE + 4] = 12;
13404
13405 let n = rust_sa.len() as SaSint;
13406 partial_sorting_shift_markers_16u_omp(&mut rust_sa, n, &buckets, 1);
13407 unsafe {
13408 probe_libsais16x64_partial_sorting_shift_markers_16u_omp(
13409 c_sa.as_mut_ptr(),
13410 c_sa.len() as SaSint,
13411 buckets.as_ptr(),
13412 1,
13413 );
13414 }
13415
13416 assert_eq!(rust_sa, c_sa);
13417 }
13418
13419 #[test]
13420 fn libsais16x64_partial_left_to_right_16u_block_omp_uses_cache_pipeline() {
13421 let block_size = 65_536usize;
13422 let k = 512usize;
13423 let text: Vec<u16> = (0..block_size + 2)
13424 .map(|i| 1 + ((i * 17 + i / 7) % (k - 1)) as u16)
13425 .collect();
13426 let sa_len = block_size + 2 * k * 100;
13427 let mut base_sa = vec![0; sa_len];
13428 for (i, slot) in base_sa.iter_mut().take(block_size).enumerate() {
13429 *slot = (i + 2) as SaSint;
13430 }
13431 let mut base_buckets = vec![0; 8 * ALPHABET_SIZE];
13432 for v in 0..2 * k {
13433 base_buckets[4 * ALPHABET_SIZE + v] = (block_size + v * 100) as SaSint;
13434 }
13435
13436 let mut scalar_sa = base_sa.clone();
13437 let mut threaded_sa = base_sa;
13438 let mut scalar_buckets = base_buckets.clone();
13439 let mut threaded_buckets = base_buckets;
13440 let mut thread_state = alloc_thread_state(4).unwrap();
13441 let scalar_d = partial_sorting_scan_left_to_right_16u(
13442 &text,
13443 &mut scalar_sa,
13444 &mut scalar_buckets,
13445 0,
13446 0,
13447 block_size as SaSint,
13448 );
13449 let threaded_d = partial_sorting_scan_left_to_right_16u_block_omp(
13450 &text,
13451 &mut threaded_sa,
13452 k as SaSint,
13453 &mut threaded_buckets,
13454 0,
13455 0,
13456 block_size as SaSint,
13457 4,
13458 &mut thread_state,
13459 );
13460
13461 assert_eq!(threaded_d, scalar_d);
13462 assert_eq!(threaded_sa, scalar_sa);
13463 assert_eq!(threaded_buckets, scalar_buckets);
13464 }
13465
13466 #[test]
13467 fn libsais16x64_partial_left_to_right_16u_omp_uses_block_pipeline() {
13468 let block_size = 65_536usize;
13469 let k = 512usize;
13470 let text: Vec<u16> = (0..block_size + 2)
13471 .map(|i| 1 + ((i * 17 + i / 7) % (k - 1)) as u16)
13472 .collect();
13473 let sa_len = block_size + 2 * k * 100;
13474 let mut base_sa = vec![0; sa_len];
13475 for (i, slot) in base_sa.iter_mut().take(block_size).enumerate() {
13476 let value = (i + 2) as SaSint;
13477 *slot = if i % 17 == 0 {
13478 value | SAINT_MIN
13479 } else {
13480 value
13481 };
13482 }
13483 let mut base_buckets = vec![0; 8 * ALPHABET_SIZE];
13484 for v in 0..2 * k {
13485 base_buckets[4 * ALPHABET_SIZE + v] = (block_size + v * 100) as SaSint;
13486 base_buckets[2 * ALPHABET_SIZE + v] = if v % 5 == 0 { 3 } else { 0 };
13487 }
13488
13489 let mut scalar_sa = base_sa.clone();
13490 let mut threaded_sa = base_sa;
13491 let mut scalar_buckets = base_buckets.clone();
13492 let mut threaded_buckets = base_buckets;
13493 let scalar_d = partial_sorting_scan_left_to_right_16u_omp(
13494 &text,
13495 &mut scalar_sa,
13496 text.len() as SaSint,
13497 k as SaSint,
13498 &mut scalar_buckets,
13499 block_size as SaSint,
13500 7,
13501 1,
13502 );
13503 let threaded_d = partial_sorting_scan_left_to_right_16u_omp(
13504 &text,
13505 &mut threaded_sa,
13506 text.len() as SaSint,
13507 k as SaSint,
13508 &mut threaded_buckets,
13509 block_size as SaSint,
13510 7,
13511 4,
13512 );
13513
13514 assert_eq!(threaded_d, scalar_d);
13515 assert_eq!(threaded_sa, scalar_sa);
13516 assert_eq!(threaded_buckets, scalar_buckets);
13517 }
13518
13519 #[test]
13520 fn libsais16x64_partial_right_to_left_16u_block_omp_uses_cache_pipeline() {
13521 let block_size = 65_536usize;
13522 let k = 512usize;
13523 let width = 2 * k;
13524 let block_start = width * 200 + 1024;
13525 let text: Vec<u16> = (0..block_size + 2)
13526 .map(|i| 1 + ((i * 17 + i / 7) % (k - 1)) as u16)
13527 .collect();
13528 let sa_len = block_start + block_size + 1;
13529 let mut base_sa = vec![0; sa_len];
13530 for i in 0..block_size {
13531 let value = (i + 2) as SaSint;
13532 base_sa[block_start + i] = if i % 17 == 0 {
13533 value | SAINT_MIN
13534 } else {
13535 value
13536 };
13537 }
13538 let mut base_buckets = vec![0; 8 * ALPHABET_SIZE];
13539 for v in 0..width {
13540 base_buckets[v] = ((v + 1) * 200) as SaSint;
13541 base_buckets[2 * ALPHABET_SIZE + v] = if v % 5 == 0 { 3 } else { 0 };
13542 }
13543
13544 let mut scalar_sa = base_sa.clone();
13545 let mut threaded_sa = base_sa.clone();
13546 let mut scalar_buckets = base_buckets.clone();
13547 let mut threaded_buckets = base_buckets.clone();
13548 let mut thread_state = alloc_thread_state(4).unwrap();
13549 let scalar_d = partial_sorting_scan_right_to_left_16u(
13550 &text,
13551 &mut scalar_sa,
13552 &mut scalar_buckets,
13553 7,
13554 block_start as SaSint,
13555 block_size as SaSint,
13556 );
13557 let threaded_d = partial_sorting_scan_right_to_left_16u_block_omp(
13558 &text,
13559 &mut threaded_sa,
13560 k as SaSint,
13561 &mut threaded_buckets,
13562 7,
13563 block_start as SaSint,
13564 block_size as SaSint,
13565 4,
13566 &mut thread_state,
13567 );
13568 assert_eq!(threaded_d, scalar_d);
13569 assert_eq!(threaded_sa, scalar_sa);
13570 assert_eq!(threaded_buckets, scalar_buckets);
13571
13572 let mut scalar_sa = base_sa;
13573 let mut threaded_sa = scalar_sa.clone();
13574 let mut scalar_buckets = base_buckets.clone();
13575 let mut threaded_buckets = base_buckets;
13576 let scalar_d = partial_gsa_scan_right_to_left_16u(
13577 &text,
13578 &mut scalar_sa,
13579 &mut scalar_buckets,
13580 7,
13581 block_start as SaSint,
13582 block_size as SaSint,
13583 );
13584 let threaded_d = partial_gsa_scan_right_to_left_16u_block_omp(
13585 &text,
13586 &mut threaded_sa,
13587 k as SaSint,
13588 &mut threaded_buckets,
13589 7,
13590 block_start as SaSint,
13591 block_size as SaSint,
13592 4,
13593 &mut thread_state,
13594 );
13595 assert_eq!(threaded_d, scalar_d);
13596 assert_eq!(threaded_sa, scalar_sa);
13597 assert_eq!(threaded_buckets, scalar_buckets);
13598 }
13599
13600 #[test]
13601 fn libsais16x64_partial_right_to_left_16u_omp_uses_block_pipeline() {
13602 let block_size = 65_536usize;
13603 let k = 512usize;
13604 let width = 2 * k;
13605 let block_start = width * 200 + 1024;
13606 let text: Vec<u16> = (0..block_size + 2)
13607 .map(|i| 1 + ((i * 17 + i / 7) % (k - 1)) as u16)
13608 .collect();
13609 let sa_len = block_start + block_size + 1;
13610 let n = sa_len as SaSint;
13611 let first_lms_suffix = n - (block_start + block_size) as SaSint;
13612 let left_suffixes_count = block_start as SaSint - 1;
13613 let mut base_sa = vec![0; sa_len];
13614 for i in 0..block_size {
13615 let value = (i + 2) as SaSint;
13616 base_sa[block_start + i] = if i % 17 == 0 {
13617 value | SAINT_MIN
13618 } else {
13619 value
13620 };
13621 }
13622 let mut base_buckets = vec![0; 8 * ALPHABET_SIZE];
13623 for v in 0..width {
13624 base_buckets[v] = ((v + 1) * 200) as SaSint;
13625 base_buckets[2 * ALPHABET_SIZE + v] = if v % 5 == 0 { 3 } else { 0 };
13626 }
13627
13628 let mut scalar_sa = base_sa.clone();
13629 let mut threaded_sa = base_sa.clone();
13630 let mut scalar_buckets = base_buckets.clone();
13631 let mut threaded_buckets = base_buckets.clone();
13632 partial_sorting_scan_right_to_left_16u_omp(
13633 &text,
13634 &mut scalar_sa,
13635 n,
13636 k as SaSint,
13637 &mut scalar_buckets,
13638 first_lms_suffix,
13639 left_suffixes_count,
13640 7,
13641 1,
13642 );
13643 partial_sorting_scan_right_to_left_16u_omp(
13644 &text,
13645 &mut threaded_sa,
13646 n,
13647 k as SaSint,
13648 &mut threaded_buckets,
13649 first_lms_suffix,
13650 left_suffixes_count,
13651 7,
13652 4,
13653 );
13654 assert_eq!(threaded_sa, scalar_sa);
13655 assert_eq!(threaded_buckets, scalar_buckets);
13656
13657 let mut scalar_sa = base_sa;
13658 let mut threaded_sa = scalar_sa.clone();
13659 let mut scalar_buckets = base_buckets.clone();
13660 let mut threaded_buckets = base_buckets;
13661 partial_gsa_scan_right_to_left_16u_omp(
13662 &text,
13663 &mut scalar_sa,
13664 n,
13665 k as SaSint,
13666 &mut scalar_buckets,
13667 first_lms_suffix,
13668 left_suffixes_count,
13669 7,
13670 1,
13671 );
13672 partial_gsa_scan_right_to_left_16u_omp(
13673 &text,
13674 &mut threaded_sa,
13675 n,
13676 k as SaSint,
13677 &mut threaded_buckets,
13678 first_lms_suffix,
13679 left_suffixes_count,
13680 7,
13681 4,
13682 );
13683 assert_eq!(threaded_sa, scalar_sa);
13684 assert_eq!(threaded_buckets, scalar_buckets);
13685 }
13686
13687 fn final_scan_fixture() -> ([u16; 10], Vec<SaSint>, Vec<SaSint>) {
13688 let text = [1, 0, 2, 1, 3, 0, 2, 4, 1, 0];
13689 let mut sa = vec![0; 96];
13690 sa[..6].copy_from_slice(&[3, 0, 5 | SAINT_MIN, 7, 2, 9 | SAINT_MIN]);
13691
13692 let mut induction_bucket = vec![0; ALPHABET_SIZE];
13693 for c in 0..8 {
13694 induction_bucket[c] = 24 + (c as SaSint) * 6;
13695 }
13696
13697 (text, sa, induction_bucket)
13698 }
13699
13700 fn final_order_buckets(induction_bucket: &[SaSint]) -> Vec<SaSint> {
13701 let mut buckets = vec![0; 8 * ALPHABET_SIZE];
13702 buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE].copy_from_slice(induction_bucket);
13703 buckets[7 * ALPHABET_SIZE..8 * ALPHABET_SIZE].copy_from_slice(induction_bucket);
13704 buckets
13705 }
13706
13707 #[test]
13708 fn libsais16x64_final_sorting_scan_left_to_right_16u_matches_c() {
13709 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
13710 let mut c_sa = rust_sa.clone();
13711 let mut c_bucket = rust_bucket.clone();
13712
13713 final_sorting_scan_left_to_right_16u(&text, &mut rust_sa, &mut rust_bucket, 0, 6);
13714 unsafe {
13715 probe_libsais16x64_final_sorting_scan_left_to_right_16u(
13716 text.as_ptr(),
13717 c_sa.as_mut_ptr(),
13718 c_bucket.as_mut_ptr(),
13719 0,
13720 6,
13721 );
13722 }
13723
13724 assert_eq!(rust_sa, c_sa);
13725 assert_eq!(rust_bucket, c_bucket);
13726 }
13727
13728 #[test]
13729 fn libsais16x64_final_sorting_scan_right_to_left_16u_matches_c() {
13730 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
13731 let mut c_sa = rust_sa.clone();
13732 let mut c_bucket = rust_bucket.clone();
13733
13734 final_sorting_scan_right_to_left_16u(&text, &mut rust_sa, &mut rust_bucket, 0, 6);
13735 unsafe {
13736 probe_libsais16x64_final_sorting_scan_right_to_left_16u(
13737 text.as_ptr(),
13738 c_sa.as_mut_ptr(),
13739 c_bucket.as_mut_ptr(),
13740 0,
13741 6,
13742 );
13743 }
13744
13745 assert_eq!(rust_sa, c_sa);
13746 assert_eq!(rust_bucket, c_bucket);
13747 }
13748
13749 #[test]
13750 fn libsais16x64_final_gsa_scan_right_to_left_16u_matches_c() {
13751 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
13752 let mut c_sa = rust_sa.clone();
13753 let mut c_bucket = rust_bucket.clone();
13754
13755 final_gsa_scan_right_to_left_16u(&text, &mut rust_sa, &mut rust_bucket, 0, 6);
13756 unsafe {
13757 probe_libsais16x64_final_gsa_scan_right_to_left_16u(
13758 text.as_ptr(),
13759 c_sa.as_mut_ptr(),
13760 c_bucket.as_mut_ptr(),
13761 0,
13762 6,
13763 );
13764 }
13765
13766 assert_eq!(rust_sa, c_sa);
13767 assert_eq!(rust_bucket, c_bucket);
13768 }
13769
13770 #[test]
13771 fn libsais16x64_final_sorting_32s_helpers_behave_like_upstream_shapes() {
13772 let t = vec![0, 1, 2, 1, 0, 1, 2, 1, 0];
13773
13774 let mut rust_sa = vec![1, 0, 0];
13775 let mut rust_bucket = vec![0, 1, 3];
13776 let mut c_sa = rust_sa.clone();
13777 let mut c_bucket = rust_bucket.clone();
13778 final_sorting_scan_left_to_right_32s(&t, &mut rust_sa, &mut rust_bucket, 0, 1);
13779 unsafe {
13780 probe_libsais16x64_final_sorting_scan_left_to_right_32s(
13781 t.as_ptr(),
13782 c_sa.as_mut_ptr(),
13783 c_bucket.as_mut_ptr(),
13784 0,
13785 1,
13786 );
13787 }
13788 assert_eq!(rust_sa, c_sa);
13789 assert_eq!(rust_bucket, c_bucket);
13790
13791 let mut rust_sa = vec![0, 2, 0];
13792 let mut rust_bucket = vec![1, 2, 3];
13793 let mut c_sa = rust_sa.clone();
13794 let mut c_bucket = rust_bucket.clone();
13795 final_sorting_scan_right_to_left_32s(&t, &mut rust_sa, &mut rust_bucket, 0, 2);
13796 unsafe {
13797 probe_libsais16x64_final_sorting_scan_right_to_left_32s(
13798 t.as_ptr(),
13799 c_sa.as_mut_ptr(),
13800 c_bucket.as_mut_ptr(),
13801 0,
13802 2,
13803 );
13804 }
13805 assert_eq!(rust_sa, c_sa);
13806 assert_eq!(rust_bucket, c_bucket);
13807
13808 let mut sa = vec![1, 2, 0, 0];
13809 let mut induction_bucket = vec![0, 1, 3];
13810 let mut cache = vec![ThreadCache::default(); PER_THREAD_CACHE_SIZE];
13811 final_sorting_scan_left_to_right_32s_block_omp(
13812 &t,
13813 &mut sa,
13814 &mut induction_bucket,
13815 &mut cache,
13816 0,
13817 2,
13818 2,
13819 );
13820 assert_eq!(sa[0] & SAINT_MAX, 0);
13821 assert_eq!(sa[1] & SAINT_MAX, 1);
13822 assert_eq!(induction_bucket[0], 1);
13823 assert_eq!(induction_bucket[1], 2);
13824
13825 let mut sa = vec![0, 2, 0, 0];
13826 let mut induction_bucket = vec![1, 2, 3];
13827 let mut cache = vec![ThreadCache::default(); PER_THREAD_CACHE_SIZE];
13828 final_sorting_scan_right_to_left_32s_block_omp(
13829 &t,
13830 &mut sa,
13831 &mut induction_bucket,
13832 &mut cache,
13833 0,
13834 2,
13835 2,
13836 );
13837 assert_eq!(sa[1] & SAINT_MAX, 1);
13838 assert_eq!(induction_bucket[1], 1);
13839 }
13840
13841 #[test]
13842 fn libsais16x64_final_left_to_right_16u_block_omp_uses_cache_pipeline() {
13843 let block_size = 65_536usize;
13844 let k = 512usize;
13845 let text: Vec<u16> = (0..=block_size).map(|i| 1 + (i % (k - 1)) as u16).collect();
13846 let sa_len = block_size + k * 200;
13847 let mut base_sa = vec![0; sa_len];
13848 for (i, slot) in base_sa.iter_mut().take(block_size).enumerate() {
13849 *slot = (i + 1) as SaSint;
13850 }
13851 let mut base_bucket = vec![0; k];
13852 for c in 0..k {
13853 base_bucket[c] = (block_size + c * 200) as SaSint;
13854 }
13855
13856 let mut scalar_sa = base_sa.clone();
13857 let mut threaded_sa = base_sa.clone();
13858 let mut scalar_bucket = base_bucket.clone();
13859 let mut threaded_bucket = base_bucket.clone();
13860 let mut thread_state = alloc_thread_state(4).unwrap();
13861 final_bwt_scan_left_to_right_16u(
13862 &text,
13863 &mut scalar_sa,
13864 &mut scalar_bucket,
13865 0,
13866 block_size as SaSint,
13867 );
13868 final_bwt_scan_left_to_right_16u_block_omp(
13869 &text,
13870 &mut threaded_sa,
13871 k as SaSint,
13872 &mut threaded_bucket,
13873 0,
13874 block_size as SaSint,
13875 4,
13876 &mut thread_state,
13877 );
13878 assert_eq!(threaded_sa, scalar_sa);
13879 assert_eq!(threaded_bucket, scalar_bucket);
13880
13881 let rm = 3;
13882 let mut scalar_sa = base_sa.clone();
13883 let mut threaded_sa = base_sa.clone();
13884 let mut scalar_bucket = base_bucket.clone();
13885 let mut threaded_bucket = base_bucket.clone();
13886 let mut scalar_i = vec![-1; (block_size / (rm as usize + 1)) + 2];
13887 let mut threaded_i = scalar_i.clone();
13888 final_bwt_aux_scan_left_to_right_16u(
13889 &text,
13890 &mut scalar_sa,
13891 rm,
13892 &mut scalar_i,
13893 &mut scalar_bucket,
13894 0,
13895 block_size as SaSint,
13896 );
13897 final_bwt_aux_scan_left_to_right_16u_block_omp(
13898 &text,
13899 &mut threaded_sa,
13900 k as SaSint,
13901 rm,
13902 &mut threaded_i,
13903 &mut threaded_bucket,
13904 0,
13905 block_size as SaSint,
13906 4,
13907 &mut thread_state,
13908 );
13909 assert_eq!(threaded_sa, scalar_sa);
13910 assert_eq!(threaded_i, scalar_i);
13911 assert_eq!(threaded_bucket, scalar_bucket);
13912
13913 let mut scalar_sa = base_sa;
13914 let mut threaded_sa = scalar_sa.clone();
13915 let mut scalar_bucket = base_bucket.clone();
13916 let mut threaded_bucket = base_bucket;
13917 final_sorting_scan_left_to_right_16u(
13918 &text,
13919 &mut scalar_sa,
13920 &mut scalar_bucket,
13921 0,
13922 block_size as SaSint,
13923 );
13924 final_sorting_scan_left_to_right_16u_block_omp(
13925 &text,
13926 &mut threaded_sa,
13927 k as SaSint,
13928 &mut threaded_bucket,
13929 0,
13930 block_size as SaSint,
13931 4,
13932 &mut thread_state,
13933 );
13934 assert_eq!(threaded_sa, scalar_sa);
13935 assert_eq!(threaded_bucket, scalar_bucket);
13936 }
13937
13938 #[test]
13939 fn libsais16x64_final_right_to_left_16u_block_omp_uses_cache_pipeline() {
13940 let block_size = 65_536usize;
13941 let k = 512usize;
13942 let block_start = k * 200 + 1024;
13943 let text: Vec<u16> = (0..=block_size + 1)
13944 .map(|i| 1 + (i % (k - 1)) as u16)
13945 .collect();
13946 let sa_len = block_start + block_size + 1;
13947 let mut base_sa = vec![0; sa_len];
13948 for i in 0..block_size {
13949 base_sa[block_start + i] = (i + 1) as SaSint;
13950 }
13951 let mut base_bucket = vec![0; k];
13952 for c in 0..k {
13953 base_bucket[c] = ((c + 1) * 200) as SaSint;
13954 }
13955
13956 let mut scalar_sa = base_sa.clone();
13957 let mut threaded_sa = base_sa.clone();
13958 let mut scalar_bucket = base_bucket.clone();
13959 let mut threaded_bucket = base_bucket.clone();
13960 let mut thread_state = alloc_thread_state(4).unwrap();
13961 final_bwt_scan_right_to_left_16u(
13962 &text,
13963 &mut scalar_sa,
13964 &mut scalar_bucket,
13965 block_start as SaSint,
13966 block_size as SaSint,
13967 );
13968 final_bwt_scan_right_to_left_16u_block_omp(
13969 &text,
13970 &mut threaded_sa,
13971 k as SaSint,
13972 &mut threaded_bucket,
13973 block_start as SaSint,
13974 block_size as SaSint,
13975 4,
13976 &mut thread_state,
13977 );
13978 assert_eq!(threaded_sa, scalar_sa);
13979 assert_eq!(threaded_bucket, scalar_bucket);
13980
13981 let rm = 3;
13982 let mut scalar_sa = base_sa.clone();
13983 let mut threaded_sa = base_sa.clone();
13984 let mut scalar_bucket = base_bucket.clone();
13985 let mut threaded_bucket = base_bucket.clone();
13986 let mut scalar_i = vec![-1; (block_size / (rm as usize + 1)) + 2];
13987 let mut threaded_i = scalar_i.clone();
13988 final_bwt_aux_scan_right_to_left_16u(
13989 &text,
13990 &mut scalar_sa,
13991 rm,
13992 &mut scalar_i,
13993 &mut scalar_bucket,
13994 block_start as SaSint,
13995 block_size as SaSint,
13996 );
13997 final_bwt_aux_scan_right_to_left_16u_block_omp(
13998 &text,
13999 &mut threaded_sa,
14000 k as SaSint,
14001 rm,
14002 &mut threaded_i,
14003 &mut threaded_bucket,
14004 block_start as SaSint,
14005 block_size as SaSint,
14006 4,
14007 &mut thread_state,
14008 );
14009 assert_eq!(threaded_sa, scalar_sa);
14010 assert_eq!(threaded_i, scalar_i);
14011 assert_eq!(threaded_bucket, scalar_bucket);
14012
14013 let mut scalar_sa = base_sa.clone();
14014 let mut threaded_sa = base_sa.clone();
14015 let mut scalar_bucket = base_bucket.clone();
14016 let mut threaded_bucket = base_bucket.clone();
14017 final_sorting_scan_right_to_left_16u(
14018 &text,
14019 &mut scalar_sa,
14020 &mut scalar_bucket,
14021 block_start as SaSint,
14022 block_size as SaSint,
14023 );
14024 final_sorting_scan_right_to_left_16u_block_omp(
14025 &text,
14026 &mut threaded_sa,
14027 k as SaSint,
14028 &mut threaded_bucket,
14029 block_start as SaSint,
14030 block_size as SaSint,
14031 4,
14032 &mut thread_state,
14033 );
14034 assert_eq!(threaded_sa, scalar_sa);
14035 assert_eq!(threaded_bucket, scalar_bucket);
14036
14037 let mut scalar_sa = base_sa;
14038 let mut threaded_sa = scalar_sa.clone();
14039 let mut scalar_bucket = base_bucket.clone();
14040 let mut threaded_bucket = base_bucket;
14041 final_gsa_scan_right_to_left_16u(
14042 &text,
14043 &mut scalar_sa,
14044 &mut scalar_bucket,
14045 block_start as SaSint,
14046 block_size as SaSint,
14047 );
14048 final_gsa_scan_right_to_left_16u_block_omp(
14049 &text,
14050 &mut threaded_sa,
14051 k as SaSint,
14052 &mut threaded_bucket,
14053 block_start as SaSint,
14054 block_size as SaSint,
14055 4,
14056 &mut thread_state,
14057 );
14058 assert_eq!(threaded_sa, scalar_sa);
14059 assert_eq!(threaded_bucket, scalar_bucket);
14060 }
14061
14062 #[test]
14063 fn libsais16x64_clear_lms_suffixes_omp_zeroes_requested_bucket_ranges() {
14064 let mut rust_sa = vec![5, 4, 3, 2, 1, 9];
14065 let mut c_sa = rust_sa.clone();
14066 let n = rust_sa.len() as SaSint;
14067 let mut bucket_start = vec![1, 4, 5];
14068 let mut bucket_end = vec![3, 5, 5];
14069
14070 clear_lms_suffixes_omp(&mut rust_sa, n, 3, &bucket_start, &bucket_end, 2);
14071 unsafe {
14072 probe_libsais16x64_clear_lms_suffixes_omp(
14073 c_sa.as_mut_ptr(),
14074 n,
14075 3,
14076 bucket_start.as_mut_ptr(),
14077 bucket_end.as_mut_ptr(),
14078 2,
14079 );
14080 }
14081
14082 assert_eq!(rust_sa, c_sa);
14083 }
14084
14085 #[test]
14086 fn libsais16x64_partial_order_wrapper_helpers_match_manual_sequence() {
14087 let mut rust_sa = vec![1, 2, 3, 4];
14088 let mut c_sa = rust_sa.clone();
14089 flip_suffix_markers_omp(&mut rust_sa, 3, 2);
14090 unsafe {
14091 probe_libsais16x64_flip_suffix_markers_omp(c_sa.as_mut_ptr(), 3, 2);
14092 }
14093 assert_eq!(rust_sa, c_sa);
14094
14095 let t = vec![0, 1, 2, 1, 0, 1, 2, 1, 0];
14096 let n = t.len() as SaSint;
14097 let k = 3;
14098 let mut wrapped_sa = vec![0; t.len()];
14099 let mut wrapped_buckets = vec![0; k as usize];
14100 let mut wrapped_state = alloc_thread_state(1).unwrap();
14101 induce_partial_order_32s_1k_omp(
14102 &t,
14103 &mut wrapped_sa,
14104 n,
14105 k,
14106 &mut wrapped_buckets,
14107 1,
14108 &mut wrapped_state,
14109 );
14110
14111 let mut manual_sa = vec![0; t.len()];
14112 let mut manual_buckets = vec![0; k as usize];
14113 let mut manual_state = alloc_thread_state(1).unwrap();
14114 count_suffixes_32s(&t, n, k, &mut manual_buckets);
14115 initialize_buckets_start_32s_1k(k, &mut manual_buckets);
14116 partial_sorting_scan_left_to_right_32s_1k_omp(
14117 &t,
14118 &mut manual_sa,
14119 n,
14120 &mut manual_buckets,
14121 1,
14122 &mut manual_state,
14123 );
14124 count_suffixes_32s(&t, n, k, &mut manual_buckets);
14125 initialize_buckets_end_32s_1k(k, &mut manual_buckets);
14126 partial_sorting_scan_right_to_left_32s_1k_omp(
14127 &t,
14128 &mut manual_sa,
14129 n,
14130 &mut manual_buckets,
14131 1,
14132 &mut manual_state,
14133 );
14134 partial_sorting_gather_lms_suffixes_32s_1k_omp(&mut manual_sa, n, 1, &mut manual_state);
14135
14136 assert_eq!(wrapped_sa, manual_sa);
14137 assert_eq!(wrapped_buckets, manual_buckets);
14138 }
14139
14140 #[test]
14141 fn libsais16x64_induce_partial_order_32s_wrappers_match_c() {
14142 let t = make_main_32s_stress_text(128, 24);
14143 let n = t.len() as SaSint;
14144 let k = 24;
14145 let threads = 1;
14146
14147 let mut rust_sa = vec![0; t.len()];
14148 let mut rust_buckets = vec![0; 6 * k as usize];
14149 let mut rust_state = alloc_thread_state(threads).unwrap();
14150 let m = count_and_gather_lms_suffixes_32s_4k_omp(
14151 &t,
14152 &mut rust_sa,
14153 n,
14154 k,
14155 &mut rust_buckets,
14156 1,
14157 threads,
14158 &mut rust_state,
14159 );
14160 assert!(m > 1);
14161 rust_sa[..(n - m) as usize].fill(0);
14162 let first_lms_suffix = rust_sa[(n - m) as usize];
14163 let left_suffixes_count = initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(
14164 &t,
14165 k,
14166 &mut rust_buckets,
14167 first_lms_suffix,
14168 );
14169 let (_, induction_bucket) = rust_buckets.split_at_mut(4 * k as usize);
14170 radix_sort_lms_suffixes_32s_6k_omp(&t, &mut rust_sa, n, m, induction_bucket, threads);
14171 radix_sort_set_markers_32s_6k_omp(&mut rust_sa, k, induction_bucket, threads);
14172 initialize_buckets_for_partial_sorting_32s_6k(
14173 &t,
14174 k,
14175 &mut rust_buckets,
14176 first_lms_suffix,
14177 left_suffixes_count,
14178 );
14179 let mut c_sa = rust_sa.clone();
14180 let mut c_buckets = rust_buckets.clone();
14181 induce_partial_order_32s_6k_omp(
14182 &t,
14183 &mut rust_sa,
14184 n,
14185 k,
14186 &mut rust_buckets,
14187 first_lms_suffix,
14188 left_suffixes_count,
14189 threads,
14190 &mut rust_state,
14191 );
14192 unsafe {
14193 probe_libsais16x64_induce_partial_order_32s_6k_omp(
14194 t.as_ptr(),
14195 c_sa.as_mut_ptr(),
14196 n,
14197 k,
14198 c_buckets.as_mut_ptr(),
14199 first_lms_suffix,
14200 left_suffixes_count,
14201 threads,
14202 );
14203 }
14204 assert_eq!(rust_sa, c_sa);
14205 assert_eq!(rust_buckets, c_buckets);
14206
14207 let mut rust_sa = vec![0; t.len()];
14208 let mut rust_buckets = vec![0; 4 * k as usize];
14209 let mut rust_state = alloc_thread_state(threads).unwrap();
14210 let m = count_and_gather_lms_suffixes_32s_2k_omp(
14211 &t,
14212 &mut rust_sa,
14213 n,
14214 k,
14215 &mut rust_buckets,
14216 1,
14217 threads,
14218 &mut rust_state,
14219 );
14220 assert!(m > 1);
14221 let first_lms_suffix = rust_sa[(n - m) as usize];
14222 initialize_buckets_for_radix_and_partial_sorting_32s_4k(
14223 &t,
14224 k,
14225 &mut rust_buckets,
14226 first_lms_suffix,
14227 );
14228 let (_, induction_bucket) = rust_buckets.split_at_mut(1);
14229 radix_sort_lms_suffixes_32s_2k_omp(&t, &mut rust_sa, n, m, induction_bucket, threads);
14230 radix_sort_set_markers_32s_4k_omp(&mut rust_sa, k, induction_bucket, threads);
14231 place_lms_suffixes_interval_32s_4k(&mut rust_sa, n, k, m - 1, &rust_buckets);
14232 let mut c_sa = rust_sa.clone();
14233 let mut c_buckets = rust_buckets.clone();
14234 induce_partial_order_32s_4k_omp(
14235 &t,
14236 &mut rust_sa,
14237 n,
14238 k,
14239 &mut rust_buckets,
14240 threads,
14241 &mut rust_state,
14242 );
14243 unsafe {
14244 probe_libsais16x64_induce_partial_order_32s_4k_omp(
14245 t.as_ptr(),
14246 c_sa.as_mut_ptr(),
14247 n,
14248 k,
14249 c_buckets.as_mut_ptr(),
14250 threads,
14251 );
14252 }
14253 assert_eq!(rust_sa, c_sa);
14254 assert_eq!(rust_buckets, c_buckets);
14255
14256 let mut rust_sa = vec![0; t.len()];
14257 let mut rust_buckets = vec![0; 2 * k as usize];
14258 let mut rust_state = alloc_thread_state(threads).unwrap();
14259 let m = count_and_gather_lms_suffixes_32s_2k_omp(
14260 &t,
14261 &mut rust_sa,
14262 n,
14263 k,
14264 &mut rust_buckets,
14265 1,
14266 threads,
14267 &mut rust_state,
14268 );
14269 assert!(m > 1);
14270 let first_lms_suffix = rust_sa[(n - m) as usize];
14271 initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(
14272 &t,
14273 k,
14274 &mut rust_buckets,
14275 first_lms_suffix,
14276 );
14277 let (_, induction_bucket) = rust_buckets.split_at_mut(1);
14278 radix_sort_lms_suffixes_32s_2k_omp(&t, &mut rust_sa, n, m, induction_bucket, threads);
14279 place_lms_suffixes_interval_32s_2k(&mut rust_sa, n, k, m - 1, &rust_buckets);
14280 initialize_buckets_start_and_end_32s_2k(k, &mut rust_buckets);
14281 let mut c_sa = rust_sa.clone();
14282 let mut c_buckets = rust_buckets.clone();
14283 induce_partial_order_32s_2k_omp(
14284 &t,
14285 &mut rust_sa,
14286 n,
14287 k,
14288 &mut rust_buckets,
14289 threads,
14290 &mut rust_state,
14291 );
14292 unsafe {
14293 probe_libsais16x64_induce_partial_order_32s_2k_omp(
14294 t.as_ptr(),
14295 c_sa.as_mut_ptr(),
14296 n,
14297 k,
14298 c_buckets.as_mut_ptr(),
14299 threads,
14300 );
14301 }
14302 assert_eq!(rust_sa, c_sa);
14303 assert_eq!(rust_buckets, c_buckets);
14304
14305 let mut rust_sa = vec![0; t.len()];
14306 let mut rust_buckets = vec![0; k as usize];
14307 let mut rust_state = alloc_thread_state(threads).unwrap();
14308 count_suffixes_32s(&t, n, k, &mut rust_buckets);
14309 initialize_buckets_end_32s_1k(k, &mut rust_buckets);
14310 let m = radix_sort_lms_suffixes_32s_1k(&t, &mut rust_sa, n, &mut rust_buckets);
14311 assert!(m > 1);
14312 let mut c_sa = rust_sa.clone();
14313 let mut c_buckets = rust_buckets.clone();
14314 induce_partial_order_32s_1k_omp(
14315 &t,
14316 &mut rust_sa,
14317 n,
14318 k,
14319 &mut rust_buckets,
14320 threads,
14321 &mut rust_state,
14322 );
14323 unsafe {
14324 probe_libsais16x64_induce_partial_order_32s_1k_omp(
14325 t.as_ptr(),
14326 c_sa.as_mut_ptr(),
14327 n,
14328 k,
14329 c_buckets.as_mut_ptr(),
14330 threads,
14331 );
14332 }
14333 assert_eq!(rust_sa, c_sa);
14334 assert_eq!(rust_buckets, c_buckets);
14335 }
14336
14337 #[test]
14338 fn libsais16x64_induce_partial_order_16u_omp_matches_c() {
14339 let text = [3, 1, 2, 1, 0, 4, 1, 0];
14340 let n = text.len() as SaSint;
14341 let flags = 0;
14342 let threads = 1;
14343 let mut rust_sa = vec![0; text.len()];
14344 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
14345
14346 let m = count_and_gather_lms_suffixes_16u_omp(
14347 &text,
14348 &mut rust_sa,
14349 n,
14350 &mut rust_buckets[..4 * ALPHABET_SIZE],
14351 threads,
14352 &mut [],
14353 );
14354 let k = initialize_buckets_start_and_end_16u(&mut rust_buckets, None);
14355 assert!(m > 0);
14356 let first_lms_suffix = rust_sa[(n - m) as usize];
14357 let left_suffixes_count = initialize_buckets_for_lms_suffixes_radix_sort_16u(
14358 &text,
14359 &mut rust_buckets,
14360 first_lms_suffix,
14361 );
14362 radix_sort_lms_suffixes_16u_omp(
14363 &text,
14364 &mut rust_sa,
14365 n,
14366 m,
14367 flags,
14368 &mut rust_buckets,
14369 threads,
14370 &mut [],
14371 );
14372 initialize_buckets_for_partial_sorting_16u(
14373 &text,
14374 &mut rust_buckets,
14375 first_lms_suffix,
14376 left_suffixes_count,
14377 );
14378
14379 let mut c_sa = rust_sa.clone();
14380 let mut c_buckets = rust_buckets.clone();
14381 induce_partial_order_16u_omp(
14382 &text,
14383 &mut rust_sa,
14384 n,
14385 k,
14386 flags,
14387 &mut rust_buckets,
14388 first_lms_suffix,
14389 left_suffixes_count,
14390 threads,
14391 );
14392 unsafe {
14393 probe_libsais16x64_induce_partial_order_16u_omp(
14394 text.as_ptr(),
14395 c_sa.as_mut_ptr(),
14396 n,
14397 k,
14398 flags,
14399 c_buckets.as_mut_ptr(),
14400 first_lms_suffix,
14401 left_suffixes_count,
14402 threads,
14403 );
14404 }
14405
14406 assert_eq!(rust_sa, c_sa);
14407 assert_eq!(rust_buckets, c_buckets);
14408 }
14409
14410 fn final_order_32s_fixture() -> (Vec<SaSint>, Vec<SaSint>) {
14411 (
14412 vec![0, 1, 2, 1, 0, 1, 2, 1, 0],
14413 vec![1, 0, 2, 0, 0, 0, 0, 0, 0],
14414 )
14415 }
14416
14417 fn seed_final_order_bucket_sections(buckets: &mut [SaSint], k: usize, branch_k: usize) {
14418 let left = [0, 1, 3];
14419 let right = [1, 2, 3];
14420 let left_section = match branch_k {
14421 6 => 4 * k,
14422 4 => 2 * k,
14423 2 => k,
14424 _ => 0,
14425 };
14426 let right_section = match branch_k {
14427 6 => 5 * k,
14428 4 => 3 * k,
14429 2 => 0,
14430 _ => 0,
14431 };
14432 buckets[left_section..left_section + k].copy_from_slice(&left);
14433 buckets[right_section..right_section + k].copy_from_slice(&right);
14434 }
14435
14436 #[test]
14437 fn libsais16x64_induce_final_order_32s_wrappers_match_c() {
14438 let (t, sa) = final_order_32s_fixture();
14439 let n = t.len() as SaSint;
14440 let k = 3;
14441 let threads = 1;
14442
14443 let mut rust_sa = sa.clone();
14444 let mut rust_buckets = vec![0; 6 * k as usize];
14445 seed_final_order_bucket_sections(&mut rust_buckets, k as usize, 6);
14446 let mut c_sa = rust_sa.clone();
14447 let mut c_buckets = rust_buckets.clone();
14448 let mut rust_state = alloc_thread_state(threads).unwrap();
14449 induce_final_order_32s_6k(
14450 &t,
14451 &mut rust_sa,
14452 n,
14453 k,
14454 &mut rust_buckets,
14455 threads,
14456 &mut rust_state,
14457 );
14458 unsafe {
14459 probe_libsais16x64_induce_final_order_32s_6k(
14460 t.as_ptr(),
14461 c_sa.as_mut_ptr(),
14462 n,
14463 k,
14464 c_buckets.as_mut_ptr(),
14465 threads,
14466 );
14467 }
14468 assert_eq!(rust_sa, c_sa);
14469 assert_eq!(rust_buckets, c_buckets);
14470
14471 let mut rust_sa = sa.clone();
14472 let mut rust_buckets = vec![0; 4 * k as usize];
14473 seed_final_order_bucket_sections(&mut rust_buckets, k as usize, 4);
14474 let mut c_sa = rust_sa.clone();
14475 let mut c_buckets = rust_buckets.clone();
14476 let mut rust_state = alloc_thread_state(threads).unwrap();
14477 induce_final_order_32s_4k(
14478 &t,
14479 &mut rust_sa,
14480 n,
14481 k,
14482 &mut rust_buckets,
14483 threads,
14484 &mut rust_state,
14485 );
14486 unsafe {
14487 probe_libsais16x64_induce_final_order_32s_4k(
14488 t.as_ptr(),
14489 c_sa.as_mut_ptr(),
14490 n,
14491 k,
14492 c_buckets.as_mut_ptr(),
14493 threads,
14494 );
14495 }
14496 assert_eq!(rust_sa, c_sa);
14497 assert_eq!(rust_buckets, c_buckets);
14498
14499 let mut rust_sa = sa.clone();
14500 let mut rust_buckets = vec![0; 2 * k as usize];
14501 seed_final_order_bucket_sections(&mut rust_buckets, k as usize, 2);
14502 let mut c_sa = rust_sa.clone();
14503 let mut c_buckets = rust_buckets.clone();
14504 let mut rust_state = alloc_thread_state(threads).unwrap();
14505 induce_final_order_32s_2k(
14506 &t,
14507 &mut rust_sa,
14508 n,
14509 k,
14510 &mut rust_buckets,
14511 threads,
14512 &mut rust_state,
14513 );
14514 unsafe {
14515 probe_libsais16x64_induce_final_order_32s_2k(
14516 t.as_ptr(),
14517 c_sa.as_mut_ptr(),
14518 n,
14519 k,
14520 c_buckets.as_mut_ptr(),
14521 threads,
14522 );
14523 }
14524 assert_eq!(rust_sa, c_sa);
14525 assert_eq!(rust_buckets, c_buckets);
14526
14527 let mut rust_sa = sa;
14528 let mut rust_buckets = vec![0; k as usize];
14529 let mut c_sa = rust_sa.clone();
14530 let mut c_buckets = rust_buckets.clone();
14531 let mut rust_state = alloc_thread_state(threads).unwrap();
14532 induce_final_order_32s_1k(
14533 &t,
14534 &mut rust_sa,
14535 n,
14536 k,
14537 &mut rust_buckets,
14538 threads,
14539 &mut rust_state,
14540 );
14541 unsafe {
14542 probe_libsais16x64_induce_final_order_32s_1k(
14543 t.as_ptr(),
14544 c_sa.as_mut_ptr(),
14545 n,
14546 k,
14547 c_buckets.as_mut_ptr(),
14548 threads,
14549 );
14550 }
14551 assert_eq!(rust_sa, c_sa);
14552 assert_eq!(rust_buckets, c_buckets);
14553 }
14554
14555 #[test]
14556 fn libsais16x64_induce_final_order_16u_omp_matches_manual_sequence() {
14557 let (text, mut wrapped_sa, induction_bucket) = final_scan_fixture();
14558 let mut wrapped_buckets = final_order_buckets(&induction_bucket);
14559 let mut c_sa = wrapped_sa.clone();
14560 let mut c_buckets = wrapped_buckets.clone();
14561 let mut wrapped_state = alloc_thread_state(1).unwrap();
14562 let wrapped_index = induce_final_order_16u_omp(
14563 &text,
14564 &mut wrapped_sa,
14565 text.len() as SaSint,
14566 8,
14567 0,
14568 0,
14569 None,
14570 &mut wrapped_buckets,
14571 1,
14572 &mut wrapped_state,
14573 );
14574 let c_index = unsafe {
14575 probe_libsais16x64_induce_final_order_16u_omp(
14576 text.as_ptr(),
14577 c_sa.as_mut_ptr(),
14578 text.len() as SaSint,
14579 8,
14580 0,
14581 0,
14582 std::ptr::null_mut(),
14583 c_buckets.as_mut_ptr(),
14584 1,
14585 )
14586 };
14587
14588 let (text, mut manual_sa, induction_bucket) = final_scan_fixture();
14589 let mut manual_buckets = final_order_buckets(&induction_bucket);
14590 {
14591 let (left_buckets, right_tail) = manual_buckets.split_at_mut(7 * ALPHABET_SIZE);
14592 final_sorting_scan_left_to_right_16u_omp(
14593 &text,
14594 &mut manual_sa,
14595 text.len() as SaSint,
14596 8,
14597 &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE],
14598 1,
14599 );
14600 final_sorting_scan_right_to_left_16u_omp(
14601 &text,
14602 &mut manual_sa,
14603 0,
14604 text.len() as SaSint,
14605 8,
14606 &mut right_tail[..ALPHABET_SIZE],
14607 1,
14608 );
14609 }
14610
14611 assert_eq!(wrapped_index, 0);
14612 assert_eq!(wrapped_index, c_index);
14613 assert_eq!(wrapped_sa, manual_sa);
14614 assert_eq!(wrapped_sa, c_sa);
14615 assert_eq!(wrapped_buckets, manual_buckets);
14616 assert_eq!(wrapped_buckets, c_buckets);
14617
14618 let (text, mut wrapped_sa, induction_bucket) = final_scan_fixture();
14619 let mut wrapped_buckets = final_order_buckets(&induction_bucket);
14620 let mut c_sa = wrapped_sa.clone();
14621 let mut c_buckets = wrapped_buckets.clone();
14622 let mut wrapped_state = alloc_thread_state(1).unwrap();
14623 let wrapped_index = induce_final_order_16u_omp(
14624 &text,
14625 &mut wrapped_sa,
14626 text.len() as SaSint,
14627 8,
14628 LIBSAIS_FLAGS_BWT,
14629 0,
14630 None,
14631 &mut wrapped_buckets,
14632 1,
14633 &mut wrapped_state,
14634 );
14635 let c_index = unsafe {
14636 probe_libsais16x64_induce_final_order_16u_omp(
14637 text.as_ptr(),
14638 c_sa.as_mut_ptr(),
14639 text.len() as SaSint,
14640 8,
14641 LIBSAIS_FLAGS_BWT,
14642 0,
14643 std::ptr::null_mut(),
14644 c_buckets.as_mut_ptr(),
14645 1,
14646 )
14647 };
14648
14649 let (text, mut manual_sa, induction_bucket) = final_scan_fixture();
14650 let mut manual_buckets = final_order_buckets(&induction_bucket);
14651 let manual_index = {
14652 let (left_buckets, right_tail) = manual_buckets.split_at_mut(7 * ALPHABET_SIZE);
14653 final_bwt_scan_left_to_right_16u_omp(
14654 &text,
14655 &mut manual_sa,
14656 text.len() as SaSint,
14657 8,
14658 &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE],
14659 1,
14660 );
14661 final_bwt_scan_right_to_left_16u_omp(
14662 &text,
14663 &mut manual_sa,
14664 text.len() as SaSint,
14665 8,
14666 &mut right_tail[..ALPHABET_SIZE],
14667 1,
14668 )
14669 };
14670
14671 assert_eq!(wrapped_index, manual_index);
14672 assert_eq!(wrapped_index, c_index);
14673 assert_eq!(wrapped_sa, manual_sa);
14674 assert_eq!(wrapped_sa, c_sa);
14675 assert_eq!(wrapped_buckets, manual_buckets);
14676 assert_eq!(wrapped_buckets, c_buckets);
14677
14678 let (text, mut wrapped_sa, induction_bucket) = final_scan_fixture();
14679 let mut wrapped_buckets = final_order_buckets(&induction_bucket);
14680 let mut c_sa = wrapped_sa.clone();
14681 let mut c_buckets = wrapped_buckets.clone();
14682 let mut wrapped_state = alloc_thread_state(1).unwrap();
14683 let mut wrapped_i = vec![-1; 8];
14684 let mut c_i = wrapped_i.clone();
14685 let wrapped_index = induce_final_order_16u_omp(
14686 &text,
14687 &mut wrapped_sa,
14688 text.len() as SaSint,
14689 8,
14690 LIBSAIS_FLAGS_BWT,
14691 2,
14692 Some(&mut wrapped_i),
14693 &mut wrapped_buckets,
14694 1,
14695 &mut wrapped_state,
14696 );
14697 let c_index = unsafe {
14698 probe_libsais16x64_induce_final_order_16u_omp(
14699 text.as_ptr(),
14700 c_sa.as_mut_ptr(),
14701 text.len() as SaSint,
14702 8,
14703 LIBSAIS_FLAGS_BWT,
14704 2,
14705 c_i.as_mut_ptr(),
14706 c_buckets.as_mut_ptr(),
14707 1,
14708 )
14709 };
14710
14711 let (text, mut manual_sa, induction_bucket) = final_scan_fixture();
14712 let mut manual_buckets = final_order_buckets(&induction_bucket);
14713 let mut manual_i = vec![-1; 8];
14714 {
14715 let (left_buckets, right_tail) = manual_buckets.split_at_mut(7 * ALPHABET_SIZE);
14716 final_bwt_aux_scan_left_to_right_16u_omp(
14717 &text,
14718 &mut manual_sa,
14719 text.len() as SaSint,
14720 8,
14721 1,
14722 &mut manual_i,
14723 &mut left_buckets[6 * ALPHABET_SIZE..7 * ALPHABET_SIZE],
14724 1,
14725 );
14726 final_bwt_aux_scan_right_to_left_16u_omp(
14727 &text,
14728 &mut manual_sa,
14729 text.len() as SaSint,
14730 8,
14731 1,
14732 &mut manual_i,
14733 &mut right_tail[..ALPHABET_SIZE],
14734 1,
14735 );
14736 }
14737
14738 assert_eq!(wrapped_index, 0);
14739 assert_eq!(wrapped_index, c_index);
14740 assert_eq!(wrapped_sa, manual_sa);
14741 assert_eq!(wrapped_sa, c_sa);
14742 assert_eq!(wrapped_buckets, manual_buckets);
14743 assert_eq!(wrapped_buckets, c_buckets);
14744 assert_eq!(wrapped_i, manual_i);
14745 assert_eq!(wrapped_i, c_i);
14746 }
14747
14748 #[test]
14749 fn libsais16x64_main_16u_matches_public_c_suffix_array_paths() {
14750 let text = [3, 1, 4, 1, 5, 9, 0, 2];
14751 let n = text.len() as SaSint;
14752 let fs = 32;
14753 let mut rust_sa = vec![0; text.len() + fs as usize];
14754 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
14755 let mut rust_freq = vec![0; ALPHABET_SIZE];
14756 let mut rust_state = alloc_thread_state(1).unwrap();
14757 let rust_index = main_16u(
14758 &text,
14759 &mut rust_sa,
14760 n,
14761 &mut rust_buckets,
14762 0,
14763 0,
14764 None,
14765 fs,
14766 Some(&mut rust_freq),
14767 1,
14768 &mut rust_state,
14769 );
14770
14771 let mut c_sa = vec![0; text.len() + fs as usize];
14772 let mut c_freq = vec![0; ALPHABET_SIZE];
14773 let c_index = unsafe {
14774 probe_public_libsais16x64_freq(
14775 text.as_ptr(),
14776 c_sa.as_mut_ptr(),
14777 n,
14778 fs,
14779 c_freq.as_mut_ptr(),
14780 )
14781 };
14782
14783 assert_eq!(rust_index, c_index);
14784 assert_eq!(&rust_sa[..text.len()], &c_sa[..text.len()]);
14785 assert_eq!(rust_freq, c_freq);
14786
14787 let text = [2, 1, 0, 2, 0];
14788 let n = text.len() as SaSint;
14789 let fs = 24;
14790 let mut rust_sa = vec![0; text.len() + fs as usize];
14791 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
14792 let mut rust_freq = vec![0; ALPHABET_SIZE];
14793 let mut rust_state = alloc_thread_state(1).unwrap();
14794 let rust_index = main_16u(
14795 &text,
14796 &mut rust_sa,
14797 n,
14798 &mut rust_buckets,
14799 LIBSAIS_FLAGS_GSA,
14800 0,
14801 None,
14802 fs,
14803 Some(&mut rust_freq),
14804 1,
14805 &mut rust_state,
14806 );
14807
14808 let mut c_sa = vec![0; text.len() + fs as usize];
14809 let mut c_freq = vec![0; ALPHABET_SIZE];
14810 let c_index = unsafe {
14811 probe_public_libsais16x64_gsa_freq(
14812 text.as_ptr(),
14813 c_sa.as_mut_ptr(),
14814 n,
14815 fs,
14816 c_freq.as_mut_ptr(),
14817 )
14818 };
14819
14820 assert_eq!(rust_index, c_index);
14821 assert_eq!(&rust_sa[..text.len()], &c_sa[..text.len()]);
14822 assert_eq!(rust_freq, c_freq);
14823 }
14824
14825 #[test]
14826 fn libsais16x64_final_bwt_scan_left_to_right_16u_matches_c() {
14827 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
14828 let mut c_sa = rust_sa.clone();
14829 let mut c_bucket = rust_bucket.clone();
14830
14831 final_bwt_scan_left_to_right_16u(&text, &mut rust_sa, &mut rust_bucket, 0, 6);
14832 unsafe {
14833 probe_libsais16x64_final_bwt_scan_left_to_right_16u(
14834 text.as_ptr(),
14835 c_sa.as_mut_ptr(),
14836 c_bucket.as_mut_ptr(),
14837 0,
14838 6,
14839 );
14840 }
14841
14842 assert_eq!(rust_sa, c_sa);
14843 assert_eq!(rust_bucket, c_bucket);
14844 }
14845
14846 #[test]
14847 fn libsais16x64_final_bwt_scan_right_to_left_16u_matches_c() {
14848 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
14849 let mut c_sa = rust_sa.clone();
14850 let mut c_bucket = rust_bucket.clone();
14851
14852 let rust_index =
14853 final_bwt_scan_right_to_left_16u(&text, &mut rust_sa, &mut rust_bucket, 0, 6);
14854 let c_index = unsafe {
14855 probe_libsais16x64_final_bwt_scan_right_to_left_16u(
14856 text.as_ptr(),
14857 c_sa.as_mut_ptr(),
14858 c_bucket.as_mut_ptr(),
14859 0,
14860 6,
14861 )
14862 };
14863
14864 assert_eq!(rust_index, c_index);
14865 assert_eq!(rust_sa, c_sa);
14866 assert_eq!(rust_bucket, c_bucket);
14867 }
14868
14869 #[test]
14870 fn libsais16x64_final_bwt_aux_scan_left_to_right_16u_matches_c() {
14871 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
14872 let mut c_sa = rust_sa.clone();
14873 let mut c_bucket = rust_bucket.clone();
14874 let mut rust_i = vec![-1; 8];
14875 let mut c_i = rust_i.clone();
14876
14877 final_bwt_aux_scan_left_to_right_16u(
14878 &text,
14879 &mut rust_sa,
14880 1,
14881 &mut rust_i,
14882 &mut rust_bucket,
14883 0,
14884 6,
14885 );
14886 unsafe {
14887 probe_libsais16x64_final_bwt_aux_scan_left_to_right_16u(
14888 text.as_ptr(),
14889 c_sa.as_mut_ptr(),
14890 1,
14891 c_i.as_mut_ptr(),
14892 c_bucket.as_mut_ptr(),
14893 0,
14894 6,
14895 );
14896 }
14897
14898 assert_eq!(rust_sa, c_sa);
14899 assert_eq!(rust_bucket, c_bucket);
14900 assert_eq!(rust_i, c_i);
14901 }
14902
14903 #[test]
14904 fn libsais16x64_final_bwt_aux_scan_right_to_left_16u_matches_c() {
14905 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
14906 let mut c_sa = rust_sa.clone();
14907 let mut c_bucket = rust_bucket.clone();
14908 let mut rust_i = vec![-1; 8];
14909 let mut c_i = rust_i.clone();
14910
14911 final_bwt_aux_scan_right_to_left_16u(
14912 &text,
14913 &mut rust_sa,
14914 1,
14915 &mut rust_i,
14916 &mut rust_bucket,
14917 0,
14918 6,
14919 );
14920 unsafe {
14921 probe_libsais16x64_final_bwt_aux_scan_right_to_left_16u(
14922 text.as_ptr(),
14923 c_sa.as_mut_ptr(),
14924 1,
14925 c_i.as_mut_ptr(),
14926 c_bucket.as_mut_ptr(),
14927 0,
14928 6,
14929 );
14930 }
14931
14932 assert_eq!(rust_sa, c_sa);
14933 assert_eq!(rust_bucket, c_bucket);
14934 assert_eq!(rust_i, c_i);
14935 }
14936
14937 #[test]
14938 fn libsais16x64_renumber_lms_suffixes_16u_matches_c() {
14939 let m = 6;
14940 let mut rust_sa = vec![0; 20];
14941 rust_sa[..m].copy_from_slice(&[2, 4 | SAINT_MIN, 6, 8 | SAINT_MIN, 10, 12 | SAINT_MIN]);
14942 let mut c_sa = rust_sa.clone();
14943
14944 let rust_name = renumber_lms_suffixes_16u(&mut rust_sa, m as SaSint, 5, 0, m as SaSint);
14945 let c_name = unsafe {
14946 probe_libsais16x64_renumber_lms_suffixes_16u(
14947 c_sa.as_mut_ptr(),
14948 m as SaSint,
14949 5,
14950 0,
14951 m as SaSint,
14952 )
14953 };
14954
14955 assert_eq!(rust_name, c_name);
14956 assert_eq!(rust_sa, c_sa);
14957 }
14958
14959 fn lms_interval_fixture() -> (Vec<SaSint>, Vec<SaSint>) {
14960 let mut sa = vec![-7; 16];
14961 sa[4..8].copy_from_slice(&[41, 42, 61, 62]);
14962
14963 let mut buckets = vec![0; 8 * ALPHABET_SIZE];
14964 buckets[buckets_index2(2, 1)] = 0;
14965 buckets[buckets_index2(3, 1)] = 2;
14966 buckets[buckets_index2(4, 1)] = 2;
14967 buckets[buckets_index2(5, 1)] = 2;
14968 buckets[buckets_index2(6, 1)] = 4;
14969 buckets[buckets_index2(7, 1)] = 4;
14970 buckets[7 * ALPHABET_SIZE + 2] = 6;
14971 buckets[7 * ALPHABET_SIZE + 5] = 12;
14972
14973 (sa, buckets)
14974 }
14975
14976 #[test]
14977 fn libsais16x64_place_lms_suffixes_interval_16u_matches_c() {
14978 for flags in [0, LIBSAIS_FLAGS_GSA] {
14979 let (mut rust_sa, mut rust_buckets) = lms_interval_fixture();
14980 let mut c_sa = rust_sa.clone();
14981 let mut c_buckets = rust_buckets.clone();
14982
14983 place_lms_suffixes_interval_16u(&mut rust_sa, 16, 8, flags, &mut rust_buckets);
14984 unsafe {
14985 probe_libsais16x64_place_lms_suffixes_interval_16u(
14986 c_sa.as_mut_ptr(),
14987 16,
14988 8,
14989 flags,
14990 c_buckets.as_mut_ptr(),
14991 );
14992 }
14993
14994 assert_eq!(rust_sa, c_sa);
14995 assert_eq!(rust_buckets, c_buckets);
14996 }
14997 }
14998
14999 #[test]
15000 fn libsais16x64_bwt_copy_16u_matches_c() {
15001 let mut a = vec![0, 1, 65535, 65536, -1, -2, 70000, 17, 131071, -65536];
15002 let mut rust_u = vec![999; a.len()];
15003 let mut c_u = rust_u.clone();
15004
15005 bwt_copy_16u(&mut rust_u, &a, a.len() as SaSint);
15006 unsafe {
15007 probe_libsais16x64_bwt_copy_16u(c_u.as_mut_ptr(), a.as_mut_ptr(), a.len() as SaSint);
15008 }
15009
15010 assert_eq!(rust_u, c_u);
15011 }
15012
15013 #[test]
15014 fn libsais16x64_early_omp_wrappers_match_c() {
15015 let text = [3, 1, 2, 1, 0, 4, 1, 0];
15016 let n = text.len() as SaSint;
15017
15018 let mut rust_sa = vec![-99; text.len()];
15019 let mut c_sa = rust_sa.clone();
15020 gather_lms_suffixes_16u_omp(&text, &mut rust_sa, n, 1, &mut []);
15021 unsafe {
15022 probe_libsais16x64_gather_lms_suffixes_16u_omp(text.as_ptr(), c_sa.as_mut_ptr(), n, 1);
15023 }
15024 assert_eq!(rust_sa, c_sa);
15025
15026 let mut rust_sa = vec![-99; text.len()];
15027 let mut c_sa = rust_sa.clone();
15028 let mut rust_buckets = vec![-1; 4 * ALPHABET_SIZE];
15029 let mut c_buckets = rust_buckets.clone();
15030 let rust_m = count_and_gather_lms_suffixes_16u_omp(
15031 &text,
15032 &mut rust_sa,
15033 n,
15034 &mut rust_buckets,
15035 1,
15036 &mut [],
15037 );
15038 let c_m = unsafe {
15039 probe_libsais16x64_count_and_gather_lms_suffixes_16u_omp(
15040 text.as_ptr(),
15041 c_sa.as_mut_ptr(),
15042 n,
15043 c_buckets.as_mut_ptr(),
15044 1,
15045 )
15046 };
15047 assert_eq!(rust_m, c_m);
15048 assert_eq!(rust_sa, c_sa);
15049 assert_eq!(rust_buckets, c_buckets);
15050
15051 let mut rust_buckets = vec![0; 8 * ALPHABET_SIZE];
15052 let m = count_and_gather_lms_suffixes_16u(
15053 &text,
15054 &mut rust_sa,
15055 n,
15056 &mut rust_buckets[..4 * ALPHABET_SIZE],
15057 0,
15058 n,
15059 );
15060 initialize_buckets_start_and_end_16u(&mut rust_buckets, None);
15061 let first_lms_suffix = rust_sa[(n - m) as usize];
15062 initialize_buckets_for_lms_suffixes_radix_sort_16u(
15063 &text,
15064 &mut rust_buckets,
15065 first_lms_suffix,
15066 );
15067 let mut c_sa = rust_sa.clone();
15068 let mut c_buckets = rust_buckets.clone();
15069 radix_sort_lms_suffixes_16u_omp(
15070 &text,
15071 &mut rust_sa,
15072 n,
15073 m,
15074 0,
15075 &mut rust_buckets,
15076 1,
15077 &mut [],
15078 );
15079 unsafe {
15080 probe_libsais16x64_radix_sort_lms_suffixes_16u_omp(
15081 text.as_ptr(),
15082 c_sa.as_mut_ptr(),
15083 n,
15084 m,
15085 0,
15086 c_buckets.as_mut_ptr(),
15087 1,
15088 );
15089 }
15090 assert_eq!(rust_sa, c_sa);
15091 assert_eq!(rust_buckets, c_buckets);
15092 }
15093
15094 #[test]
15095 fn libsais16x64_early_omp_wrappers_use_block_partition_for_large_inputs() {
15096 let n = 65_600usize;
15097 let text: Vec<u16> = (0..n)
15098 .map(|i| 1 + ((i * 37 + i / 17) % 509) as u16)
15099 .collect();
15100
15101 let mut gathered_threaded = vec![-99; n];
15102 let mut gathered_scalar = vec![-99; n];
15103 let mut thread_state = alloc_thread_state(4).unwrap();
15104 let mut count_sa = vec![-99; n];
15105 let mut count_buckets = vec![0; 4 * ALPHABET_SIZE];
15106 count_and_gather_lms_suffixes_16u_omp(
15107 &text,
15108 &mut count_sa,
15109 n as SaSint,
15110 &mut count_buckets,
15111 4,
15112 &mut thread_state,
15113 );
15114 gather_lms_suffixes_16u_omp(
15115 &text,
15116 &mut gathered_threaded,
15117 n as SaSint,
15118 4,
15119 &mut thread_state,
15120 );
15121 gather_lms_suffixes_16u(
15122 &text,
15123 &mut gathered_scalar,
15124 n as SaSint,
15125 n as SaSint - 1,
15126 0,
15127 n as SaSint,
15128 );
15129 assert_eq!(gathered_threaded, gathered_scalar);
15130
15131 let mut sa_threaded = vec![-99; n];
15132 let mut sa_scalar = vec![-99; n];
15133 let mut buckets_threaded = vec![0; 4 * ALPHABET_SIZE];
15134 let mut buckets_scalar = vec![0; 4 * ALPHABET_SIZE];
15135 let m_threaded = count_and_gather_lms_suffixes_16u_omp(
15136 &text,
15137 &mut sa_threaded,
15138 n as SaSint,
15139 &mut buckets_threaded,
15140 4,
15141 &mut thread_state,
15142 );
15143 let m_scalar = count_and_gather_lms_suffixes_16u(
15144 &text,
15145 &mut sa_scalar,
15146 n as SaSint,
15147 &mut buckets_scalar,
15148 0,
15149 n as SaSint,
15150 );
15151 assert_eq!(m_threaded, m_scalar);
15152 assert_eq!(
15153 &sa_threaded[n - m_threaded as usize..],
15154 &sa_scalar[n - m_scalar as usize..]
15155 );
15156 assert_eq!(buckets_threaded, buckets_scalar);
15157 }
15158
15159 #[test]
15160 fn libsais16x64_late_omp_wrappers_match_c() {
15161 let m = 6;
15162 let mut rust_sa = vec![0; 20];
15163 rust_sa[..m].copy_from_slice(&[2, 4 | SAINT_MIN, 6, 8 | SAINT_MIN, 10, 12 | SAINT_MIN]);
15164 let mut c_sa = rust_sa.clone();
15165 let mut rust_thread_state = alloc_thread_state(1).unwrap();
15166 let rust_name =
15167 renumber_lms_suffixes_16u_omp(&mut rust_sa, m as SaSint, 1, &mut rust_thread_state);
15168 let c_name = unsafe {
15169 probe_libsais16x64_renumber_lms_suffixes_16u_omp(c_sa.as_mut_ptr(), m as SaSint, 1)
15170 };
15171 assert_eq!(rust_name, c_name);
15172 assert_eq!(rust_sa, c_sa);
15173
15174 let mut a = vec![0, 1, 65535, 65536, -1, -2, 70000, 17, 131071, -65536];
15175 let mut rust_u = vec![999; a.len()];
15176 let mut c_u = rust_u.clone();
15177 bwt_copy_16u_omp(&mut rust_u, &a, a.len() as SaSint, 1);
15178 unsafe {
15179 probe_libsais16x64_bwt_copy_16u_omp(
15180 c_u.as_mut_ptr(),
15181 a.as_mut_ptr(),
15182 a.len() as SaSint,
15183 1,
15184 );
15185 }
15186 assert_eq!(rust_u, c_u);
15187 }
15188
15189 #[test]
15190 fn libsais16x64_gather_marked_lms_suffixes_matches_c() {
15191 let mut rust_sa = vec![0, 0, 3 | SAINT_MIN, 4, 5 | SAINT_MIN, 6, -7, 8];
15192 let mut c_sa = rust_sa.clone();
15193
15194 let rust_l = gather_marked_lms_suffixes(&mut rust_sa, 2, 8, 0, 4) as SaSint;
15195 let c_l =
15196 unsafe { probe_libsais16x64_gather_marked_lms_suffixes(c_sa.as_mut_ptr(), 2, 8, 0, 4) };
15197
15198 assert_eq!(rust_l, c_l);
15199 assert_eq!(rust_sa, c_sa);
15200 }
15201
15202 #[test]
15203 fn libsais16x64_gather_marked_lms_suffixes_omp_matches_c() {
15204 let mut rust_sa = vec![0; 10];
15205 rust_sa[4..8].copy_from_slice(&[2 | SAINT_MIN, 4, 6 | SAINT_MIN, 8]);
15206 let mut c_sa = rust_sa.clone();
15207
15208 let mut rust_thread_state = alloc_thread_state(1).unwrap();
15209 gather_marked_lms_suffixes_omp(&mut rust_sa, 8, 4, 2, 1, &mut rust_thread_state);
15210 unsafe {
15211 probe_libsais16x64_gather_marked_lms_suffixes_omp(c_sa.as_mut_ptr(), 8, 4, 2, 1);
15212 }
15213
15214 assert_eq!(rust_sa, c_sa);
15215 }
15216
15217 #[test]
15218 fn libsais16x64_renumber_and_gather_lms_suffixes_omp_matches_c() {
15219 let mut rust_sa = vec![0; 10];
15220 rust_sa[..4].copy_from_slice(&[2, 4 | SAINT_MIN, 6, 8 | SAINT_MIN]);
15221 let mut c_sa = rust_sa.clone();
15222
15223 let mut rust_thread_state = alloc_thread_state(1).unwrap();
15224 let rust_name =
15225 renumber_and_gather_lms_suffixes_omp(&mut rust_sa, 8, 4, 2, 1, &mut rust_thread_state);
15226 let c_name = unsafe {
15227 probe_libsais16x64_renumber_and_gather_lms_suffixes_omp(c_sa.as_mut_ptr(), 8, 4, 2, 1)
15228 };
15229
15230 assert_eq!(rust_name, c_name);
15231 assert_eq!(rust_sa, c_sa);
15232 }
15233
15234 #[test]
15235 fn libsais16x64_reconstruct_lms_suffixes_matches_c() {
15236 let mut rust_sa = vec![2, 0, 1, 77, 88, 10, 11, 12];
15237 let mut c_sa = rust_sa.clone();
15238
15239 reconstruct_lms_suffixes(&mut rust_sa, 8, 3, 0, 3);
15240 unsafe {
15241 probe_libsais16x64_reconstruct_lms_suffixes(c_sa.as_mut_ptr(), 8, 3, 0, 3);
15242 }
15243
15244 assert_eq!(rust_sa, c_sa);
15245
15246 let mut rust_sa = vec![2, 0, 1, 77, 88, 10, 11, 12];
15247 let mut c_sa = rust_sa.clone();
15248 reconstruct_lms_suffixes_omp(&mut rust_sa, 8, 3, 1);
15249 unsafe {
15250 probe_libsais16x64_reconstruct_lms_suffixes_omp(c_sa.as_mut_ptr(), 8, 3, 1);
15251 }
15252
15253 assert_eq!(rust_sa, c_sa);
15254 }
15255
15256 #[test]
15257 fn libsais16x64_lms_late_omp_wrappers_use_block_partition() {
15258 let m = 65_536usize;
15259 let mut scalar = vec![0; 2 * m + 8];
15260 for i in 0..m {
15261 let value = (2 * i) as SaSint;
15262 scalar[i] = if i % 7 == 0 { value | SAINT_MIN } else { value };
15263 }
15264 let mut threaded = scalar.clone();
15265
15266 let mut scalar_state = alloc_thread_state(1).unwrap();
15267 let mut threaded_state = alloc_thread_state(4).unwrap();
15268 let scalar_name =
15269 renumber_lms_suffixes_16u_omp(&mut scalar, m as SaSint, 1, &mut scalar_state);
15270 let threaded_name =
15271 renumber_lms_suffixes_16u_omp(&mut threaded, m as SaSint, 4, &mut threaded_state);
15272 assert_eq!(threaded_name, scalar_name);
15273 assert_eq!(threaded, scalar);
15274
15275 let n = 131_072usize;
15276 let m = 65_536usize;
15277 let fs = 128usize;
15278 let mut scalar = vec![0; n + fs];
15279 for i in 0..(n >> 1) {
15280 let value = (i as SaSint + 1) & SAINT_MAX;
15281 scalar[m + i] = if i % 7 == 0 { value | SAINT_MIN } else { value };
15282 }
15283 let marked_count = (0..(n >> 1)).filter(|i| i % 7 == 0).count();
15284 let mut threaded = scalar.clone();
15285
15286 let mut scalar_state = alloc_thread_state(1).unwrap();
15287 let mut threaded_state = alloc_thread_state(4).unwrap();
15288 gather_marked_lms_suffixes_omp(
15289 &mut scalar,
15290 n as SaSint,
15291 m as SaSint,
15292 fs as SaSint,
15293 1,
15294 &mut scalar_state,
15295 );
15296 gather_marked_lms_suffixes_omp(
15297 &mut threaded,
15298 n as SaSint,
15299 m as SaSint,
15300 fs as SaSint,
15301 4,
15302 &mut threaded_state,
15303 );
15304 assert_eq!(
15305 &threaded[n + fs - marked_count..n + fs],
15306 &scalar[n + fs - marked_count..n + fs]
15307 );
15308
15309 let m = 65_536usize;
15310 let n = 2 * m;
15311 let mut scalar = vec![0; n];
15312 for i in 0..m {
15313 scalar[i] = i as SaSint;
15314 scalar[n - m + i] = 1_000_000 + i as SaSint;
15315 }
15316 let mut threaded = scalar.clone();
15317
15318 reconstruct_lms_suffixes_omp(&mut scalar, n as SaSint, m as SaSint, 1);
15319 reconstruct_lms_suffixes_omp(&mut threaded, n as SaSint, m as SaSint, 4);
15320 assert_eq!(threaded, scalar);
15321 }
15322
15323 #[test]
15324 fn libsais16x64_distinct_lms_helpers_match_c() {
15325 let m = 6;
15326 let mut rust_sa = vec![0; 18];
15327 rust_sa[..m].copy_from_slice(&[
15328 2 | SAINT_MIN,
15329 4 | SAINT_MIN,
15330 6,
15331 8 | SAINT_MIN,
15332 10,
15333 12 | SAINT_MIN,
15334 ]);
15335 let mut c_sa = rust_sa.clone();
15336 let rust_name =
15337 renumber_distinct_lms_suffixes_32s_4k(&mut rust_sa, m as SaSint, 1, 0, m as isize);
15338 let c_name = unsafe {
15339 probe_libsais16x64_renumber_distinct_lms_suffixes_32s_4k(
15340 c_sa.as_mut_ptr(),
15341 m as SaSint,
15342 1,
15343 0,
15344 m as SaSint,
15345 )
15346 };
15347 assert_eq!(rust_name, c_name);
15348 assert_eq!(rust_sa, c_sa);
15349
15350 let mut rust_sa = vec![0; 12];
15351 rust_sa[m..m + 6].copy_from_slice(&[SAINT_MIN | 1, 0, SAINT_MIN | 2, 0, 3, 0]);
15352 let mut c_sa = rust_sa.clone();
15353 mark_distinct_lms_suffixes_32s(&mut rust_sa, m as SaSint, 0, 6);
15354 unsafe {
15355 probe_libsais16x64_mark_distinct_lms_suffixes_32s(c_sa.as_mut_ptr(), m as SaSint, 0, 6);
15356 }
15357 assert_eq!(rust_sa, c_sa);
15358
15359 let mut rust_sa = vec![0; 12];
15360 rust_sa[m..m + 6].copy_from_slice(&[SAINT_MIN | 1, 7, SAINT_MIN | 2, 0, -5, 9]);
15361 let mut c_sa = rust_sa.clone();
15362 clamp_lms_suffixes_length_32s(&mut rust_sa, m as SaSint, 0, 6);
15363 unsafe {
15364 probe_libsais16x64_clamp_lms_suffixes_length_32s(c_sa.as_mut_ptr(), m as SaSint, 0, 6);
15365 }
15366 assert_eq!(rust_sa, c_sa);
15367 }
15368
15369 #[test]
15370 fn libsais16x64_distinct_lms_omp_wrappers_match_c() {
15371 let n = 12;
15372 let m = 6;
15373 let mut rust_sa = vec![0; 18];
15374 rust_sa[..m].copy_from_slice(&[
15375 2 | SAINT_MIN,
15376 4 | SAINT_MIN,
15377 6,
15378 8 | SAINT_MIN,
15379 10,
15380 12 | SAINT_MIN,
15381 ]);
15382 let mut c_sa = rust_sa.clone();
15383 let mut rust_thread_state = alloc_thread_state(1).unwrap();
15384 let rust_name = renumber_distinct_lms_suffixes_32s_4k_omp(
15385 &mut rust_sa,
15386 m as SaSint,
15387 1,
15388 &mut rust_thread_state,
15389 );
15390 let c_name = unsafe {
15391 probe_libsais16x64_renumber_distinct_lms_suffixes_32s_4k_omp(
15392 c_sa.as_mut_ptr(),
15393 m as SaSint,
15394 1,
15395 )
15396 };
15397 assert_eq!(rust_name, c_name);
15398 assert_eq!(rust_sa, c_sa);
15399
15400 let mut rust_sa = vec![0; 18];
15401 rust_sa[m..m + 6].copy_from_slice(&[SAINT_MIN | 1, 0, SAINT_MIN | 2, 0, 3, 0]);
15402 let mut c_sa = rust_sa.clone();
15403 mark_distinct_lms_suffixes_32s_omp(&mut rust_sa, n, m as SaSint, 1);
15404 unsafe {
15405 probe_libsais16x64_mark_distinct_lms_suffixes_32s_omp(
15406 c_sa.as_mut_ptr(),
15407 n,
15408 m as SaSint,
15409 1,
15410 );
15411 }
15412 assert_eq!(rust_sa, c_sa);
15413
15414 let mut rust_sa = vec![0; 18];
15415 rust_sa[m..m + 6].copy_from_slice(&[SAINT_MIN | 1, 7, SAINT_MIN | 2, 0, -5, 9]);
15416 let mut c_sa = rust_sa.clone();
15417 clamp_lms_suffixes_length_32s_omp(&mut rust_sa, n, m as SaSint, 1);
15418 unsafe {
15419 probe_libsais16x64_clamp_lms_suffixes_length_32s_omp(
15420 c_sa.as_mut_ptr(),
15421 n,
15422 m as SaSint,
15423 1,
15424 );
15425 }
15426 assert_eq!(rust_sa, c_sa);
15427
15428 let mut rust_sa = vec![0; 18];
15429 rust_sa[..m].copy_from_slice(&[
15430 2 | SAINT_MIN,
15431 4 | SAINT_MIN,
15432 6,
15433 8 | SAINT_MIN,
15434 10,
15435 12 | SAINT_MIN,
15436 ]);
15437 let mut c_sa = rust_sa.clone();
15438 let mut rust_thread_state = alloc_thread_state(1).unwrap();
15439 let rust_name = renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(
15440 &mut rust_sa,
15441 n,
15442 m as SaSint,
15443 1,
15444 &mut rust_thread_state,
15445 );
15446 let c_name = unsafe {
15447 probe_libsais16x64_renumber_and_mark_distinct_lms_suffixes_32s_4k_omp(
15448 c_sa.as_mut_ptr(),
15449 n,
15450 m as SaSint,
15451 1,
15452 )
15453 };
15454 assert_eq!(rust_name, c_name);
15455 assert_eq!(rust_sa, c_sa);
15456 }
15457
15458 #[test]
15459 fn libsais16x64_distinct_lms_omp_wrappers_use_block_partition() {
15460 let m = 65_536usize;
15461 let mut scalar = vec![0; 2 * m];
15462 for i in 0..m {
15463 let value = (2 * i) as SaSint;
15464 scalar[i] = if i % 7 == 0 { value | SAINT_MIN } else { value };
15465 }
15466 let mut threaded = scalar.clone();
15467
15468 let mut scalar_state = alloc_thread_state(1).unwrap();
15469 let mut threaded_state = alloc_thread_state(4).unwrap();
15470 let scalar_name = renumber_distinct_lms_suffixes_32s_4k_omp(
15471 &mut scalar,
15472 m as SaSint,
15473 1,
15474 &mut scalar_state,
15475 );
15476 let threaded_name = renumber_distinct_lms_suffixes_32s_4k_omp(
15477 &mut threaded,
15478 m as SaSint,
15479 4,
15480 &mut threaded_state,
15481 );
15482 assert_eq!(threaded_name, scalar_name);
15483 assert_eq!(threaded, scalar);
15484
15485 let n = 131_072usize;
15486 let m = 65_536usize;
15487 let mut scalar = vec![0; n];
15488 for i in 0..(n >> 1) {
15489 scalar[m + i] = if i % 5 == 0 {
15490 SAINT_MIN | (i as SaSint + 1)
15491 } else if i % 11 == 0 {
15492 0
15493 } else {
15494 i as SaSint + 1
15495 };
15496 }
15497 let mut threaded = scalar.clone();
15498 mark_distinct_lms_suffixes_32s_omp(&mut scalar, n as SaSint, m as SaSint, 1);
15499 mark_distinct_lms_suffixes_32s_omp(&mut threaded, n as SaSint, m as SaSint, 4);
15500 assert_eq!(&threaded[m..n], &scalar[m..n]);
15501
15502 let mut scalar = vec![0; n];
15503 for i in 0..(n >> 1) {
15504 scalar[m + i] = if i % 5 == 0 {
15505 SAINT_MIN | (i as SaSint + 1)
15506 } else {
15507 i as SaSint + 1
15508 };
15509 }
15510 let mut threaded = scalar.clone();
15511 clamp_lms_suffixes_length_32s_omp(&mut scalar, n as SaSint, m as SaSint, 1);
15512 clamp_lms_suffixes_length_32s_omp(&mut threaded, n as SaSint, m as SaSint, 4);
15513 assert_eq!(&threaded[m..n], &scalar[m..n]);
15514 }
15515
15516 #[test]
15517 fn libsais16x64_unique_nonunique_lms_helpers_match_c() {
15518 let m = 4;
15519 let mut rust_t = vec![0; 12];
15520 let mut rust_sa = vec![0; 12];
15521 rust_sa[..m].copy_from_slice(&[2, 4, 6, 8]);
15522 rust_sa[m + 1] = SAINT_MIN | 11;
15523 rust_sa[m + 2] = 22;
15524 rust_sa[m + 3] = SAINT_MIN | 33;
15525 rust_sa[m + 4] = 44;
15526 let mut c_t = rust_t.clone();
15527 let mut c_sa = rust_sa.clone();
15528
15529 let rust_f = renumber_unique_and_nonunique_lms_suffixes_32s(
15530 &mut rust_t,
15531 &mut rust_sa,
15532 m as SaSint,
15533 0,
15534 0,
15535 m as isize,
15536 );
15537 let c_f = unsafe {
15538 probe_libsais16x64_renumber_unique_and_nonunique_lms_suffixes_32s(
15539 c_t.as_mut_ptr(),
15540 c_sa.as_mut_ptr(),
15541 m as SaSint,
15542 0,
15543 0,
15544 m as SaSint,
15545 )
15546 };
15547 assert_eq!(rust_f, c_f);
15548 assert_eq!(rust_t, c_t);
15549 assert_eq!(rust_sa, c_sa);
15550
15551 let mut rust_sa = vec![0; 10];
15552 rust_sa[m..m + 4].copy_from_slice(&[SAINT_MIN | 3, 4, SAINT_MIN | 5, 6]);
15553 let mut c_sa = rust_sa.clone();
15554 let mut rust_l = m as isize;
15555 let mut rust_r = 10isize;
15556 let mut c_l = rust_l as SaSint;
15557 let mut c_r = rust_r as SaSint;
15558 compact_unique_and_nonunique_lms_suffixes_32s(
15559 &mut rust_sa,
15560 m as SaSint,
15561 &mut rust_l,
15562 &mut rust_r,
15563 0,
15564 4,
15565 );
15566 unsafe {
15567 probe_libsais16x64_compact_unique_and_nonunique_lms_suffixes_32s(
15568 c_sa.as_mut_ptr(),
15569 m as SaSint,
15570 &mut c_l,
15571 &mut c_r,
15572 0,
15573 4,
15574 );
15575 }
15576 assert_eq!(rust_l as SaSint, c_l);
15577 assert_eq!(rust_r as SaSint, c_r);
15578 assert_eq!(rust_sa, c_sa);
15579 }
15580
15581 #[test]
15582 fn libsais16x64_unique_nonunique_lms_omp_wrappers_match_c() {
15583 let n = 8;
15584 let m = 4;
15585 let fs = 4;
15586 let mut rust_t = vec![0; 12];
15587 let mut rust_sa = vec![0; 12];
15588 rust_sa[..m].copy_from_slice(&[2, 4, 6, 8]);
15589 rust_sa[m + 1] = SAINT_MIN | 11;
15590 rust_sa[m + 2] = 22;
15591 rust_sa[m + 3] = SAINT_MIN | 33;
15592 rust_sa[m + 4] = 44;
15593 let mut c_t = rust_t.clone();
15594 let mut c_sa = rust_sa.clone();
15595
15596 let rust_f = renumber_unique_and_nonunique_lms_suffixes_32s_omp(
15597 &mut rust_t,
15598 &mut rust_sa,
15599 m as SaSint,
15600 1,
15601 );
15602 let c_f = unsafe {
15603 probe_libsais16x64_renumber_unique_and_nonunique_lms_suffixes_32s_omp(
15604 c_t.as_mut_ptr(),
15605 c_sa.as_mut_ptr(),
15606 m as SaSint,
15607 1,
15608 )
15609 };
15610 assert_eq!(rust_f, c_f);
15611 assert_eq!(rust_t, c_t);
15612 assert_eq!(rust_sa, c_sa);
15613
15614 let mut rust_sa = vec![0; 12];
15615 rust_sa[m..m + 4].copy_from_slice(&[SAINT_MIN | 3, 4, SAINT_MIN | 5, 6]);
15616 rust_sa[m - 2..m].copy_from_slice(&[101, 102]);
15617 let mut c_sa = rust_sa.clone();
15618 compact_unique_and_nonunique_lms_suffixes_32s_omp(&mut rust_sa, n, m as SaSint, fs, 2, 1);
15619 unsafe {
15620 probe_libsais16x64_compact_unique_and_nonunique_lms_suffixes_32s_omp(
15621 c_sa.as_mut_ptr(),
15622 n,
15623 m as SaSint,
15624 fs,
15625 2,
15626 1,
15627 );
15628 }
15629 assert_eq!(rust_sa, c_sa);
15630
15631 let mut rust_t = vec![0; 12];
15632 let mut rust_sa = vec![0; 12];
15633 rust_sa[..m].copy_from_slice(&[2, 4, 6, 8]);
15634 rust_sa[m + 1] = SAINT_MIN | 11;
15635 rust_sa[m + 2] = 22;
15636 rust_sa[m + 3] = SAINT_MIN | 33;
15637 rust_sa[m + 4] = 44;
15638 let mut c_t = rust_t.clone();
15639 let mut c_sa = rust_sa.clone();
15640 let rust_f = compact_lms_suffixes_32s_omp(&mut rust_t, &mut rust_sa, n, m as SaSint, fs, 1);
15641 let c_f = unsafe {
15642 probe_libsais16x64_compact_lms_suffixes_32s_omp(
15643 c_t.as_mut_ptr(),
15644 c_sa.as_mut_ptr(),
15645 n,
15646 m as SaSint,
15647 fs,
15648 1,
15649 )
15650 };
15651 assert_eq!(rust_f, c_f);
15652 assert_eq!(rust_t, c_t);
15653 assert_eq!(rust_sa, c_sa);
15654 }
15655
15656 #[test]
15657 fn libsais16x64_unique_nonunique_lms_omp_wrappers_use_block_partition() {
15658 let m = 65_536usize;
15659 let mut scalar_t = vec![0; 2 * m];
15660 let mut scalar_sa = vec![0; 2 * m];
15661 for i in 0..m {
15662 scalar_sa[i] = (2 * i) as SaSint;
15663 scalar_sa[m + i] = if i % 5 == 0 {
15664 SAINT_MIN | (i as SaSint + 3)
15665 } else {
15666 i as SaSint + 3
15667 };
15668 }
15669 let mut threaded_t = scalar_t.clone();
15670 let mut threaded_sa = scalar_sa.clone();
15671
15672 let scalar_f = renumber_unique_and_nonunique_lms_suffixes_32s_omp(
15673 &mut scalar_t,
15674 &mut scalar_sa,
15675 m as SaSint,
15676 1,
15677 );
15678 let threaded_f = renumber_unique_and_nonunique_lms_suffixes_32s_omp(
15679 &mut threaded_t,
15680 &mut threaded_sa,
15681 m as SaSint,
15682 4,
15683 );
15684 assert_eq!(threaded_f, scalar_f);
15685 assert_eq!(threaded_t, scalar_t);
15686 assert_eq!(threaded_sa, scalar_sa);
15687
15688 let n = 131_072usize;
15689 let m = 4_096usize;
15690 let fs = 8_192usize;
15691 let mut scalar_sa = vec![0; n + fs];
15692 for i in 0..(n >> 1) {
15693 scalar_sa[m + i] = if i % 32 == 0 {
15694 SAINT_MIN | (i as SaSint + 1)
15695 } else {
15696 i as SaSint + 1
15697 };
15698 }
15699 let f = 1_024usize;
15700 for i in 0..f {
15701 scalar_sa[m - f + i] = 1_000_000 + i as SaSint;
15702 }
15703 let mut threaded_sa = scalar_sa.clone();
15704
15705 compact_unique_and_nonunique_lms_suffixes_32s_omp(
15706 &mut scalar_sa,
15707 n as SaSint,
15708 m as SaSint,
15709 fs as SaSint,
15710 f as SaSint,
15711 1,
15712 );
15713 compact_unique_and_nonunique_lms_suffixes_32s_omp(
15714 &mut threaded_sa,
15715 n as SaSint,
15716 m as SaSint,
15717 fs as SaSint,
15718 f as SaSint,
15719 4,
15720 );
15721 assert_eq!(&threaded_sa[..m], &scalar_sa[..m]);
15722 assert_eq!(
15723 &threaded_sa[n + fs - m..n + fs],
15724 &scalar_sa[n + fs - m..n + fs]
15725 );
15726 }
15727
15728 #[test]
15729 fn libsais16x64_merge_lms_helpers_match_c() {
15730 let n = 10;
15731 let m = 3;
15732 let mut rust_t = vec![0; n as usize];
15733 rust_t[1] = SAINT_MIN | 11;
15734 rust_t[3] = SAINT_MIN | 22;
15735 rust_t[7] = SAINT_MIN | 33;
15736 let mut rust_sa = vec![0; n as usize];
15737 rust_sa[6..10].copy_from_slice(&[2, 5, 8, 9]);
15738 let mut c_t = rust_t.clone();
15739 let mut c_sa = rust_sa.clone();
15740 merge_unique_lms_suffixes_32s(&mut rust_t, &mut rust_sa, n, m, 0, 0, n as isize);
15741 unsafe {
15742 probe_libsais16x64_merge_unique_lms_suffixes_32s(
15743 c_t.as_mut_ptr(),
15744 c_sa.as_mut_ptr(),
15745 n,
15746 m,
15747 0,
15748 0,
15749 n,
15750 );
15751 }
15752 assert_eq!(rust_t, c_t);
15753 assert_eq!(rust_sa, c_sa);
15754
15755 let n = 10;
15756 let m = 5;
15757 let mut rust_sa = vec![9, 0, 8, 0, 0, 7, 31, 32, 33, 34];
15758 let mut c_sa = rust_sa.clone();
15759 merge_nonunique_lms_suffixes_32s(&mut rust_sa, n, m, 2, 0, m as isize);
15760 unsafe {
15761 probe_libsais16x64_merge_nonunique_lms_suffixes_32s(c_sa.as_mut_ptr(), n, m, 2, 0, m);
15762 }
15763 assert_eq!(rust_sa, c_sa);
15764 }
15765
15766 #[test]
15767 fn libsais16x64_merge_lms_omp_wrappers_match_c() {
15768 let n = 12;
15769 let m = 4;
15770 let f = 2;
15771 let mut rust_t = vec![0; n as usize];
15772 rust_t[1] = SAINT_MIN | 11;
15773 rust_t[5] = SAINT_MIN | 22;
15774 let mut rust_sa = vec![0; n as usize];
15775 rust_sa[1] = 41;
15776 rust_sa[7..12].copy_from_slice(&[2, 6, 21, 22, 23]);
15777 let mut c_t = rust_t.clone();
15778 let mut c_sa = rust_sa.clone();
15779 merge_unique_lms_suffixes_32s_omp(&mut rust_t, &mut rust_sa, n, m, 1);
15780 unsafe {
15781 probe_libsais16x64_merge_unique_lms_suffixes_32s_omp(
15782 c_t.as_mut_ptr(),
15783 c_sa.as_mut_ptr(),
15784 n,
15785 m,
15786 1,
15787 );
15788 }
15789 assert_eq!(rust_t, c_t);
15790 assert_eq!(rust_sa, c_sa);
15791
15792 let mut rust_sa = vec![0, 41, 1, 0, 55, 66, 77, 2, 6, 21, 22, 23];
15793 let mut c_sa = rust_sa.clone();
15794 merge_nonunique_lms_suffixes_32s_omp(&mut rust_sa, n, m, f, 1);
15795 unsafe {
15796 probe_libsais16x64_merge_nonunique_lms_suffixes_32s_omp(c_sa.as_mut_ptr(), n, m, f, 1);
15797 }
15798 assert_eq!(rust_sa, c_sa);
15799
15800 let mut rust_t = vec![0; n as usize];
15801 rust_t[1] = SAINT_MIN | 11;
15802 rust_t[5] = SAINT_MIN | 22;
15803 let mut rust_sa = vec![0; n as usize];
15804 rust_sa[1] = 41;
15805 rust_sa[7..12].copy_from_slice(&[2, 6, 21, 22, 23]);
15806 let mut c_t = rust_t.clone();
15807 let mut c_sa = rust_sa.clone();
15808 merge_compacted_lms_suffixes_32s_omp(&mut rust_t, &mut rust_sa, n, m, f, 1);
15809 unsafe {
15810 probe_libsais16x64_merge_compacted_lms_suffixes_32s_omp(
15811 c_t.as_mut_ptr(),
15812 c_sa.as_mut_ptr(),
15813 n,
15814 m,
15815 f,
15816 1,
15817 );
15818 }
15819 assert_eq!(rust_t, c_t);
15820 assert_eq!(rust_sa, c_sa);
15821 }
15822
15823 #[test]
15824 fn libsais16x64_merge_lms_omp_wrappers_use_block_partition() {
15825 let n = 65_536usize;
15826 let m = 10_000usize;
15827 let mut scalar_t = vec![0; n];
15828 for i in (0..n).step_by(17) {
15829 scalar_t[i] = SAINT_MIN | (i as SaSint + 1);
15830 }
15831 let unique_count = scalar_t.iter().filter(|&&value| value < 0).count();
15832 let mut scalar_sa = vec![0; n];
15833 let source = n - m - 1;
15834 for i in 0..=unique_count {
15835 scalar_sa[source + i] = ((i * 13 + 7) % n) as SaSint;
15836 }
15837 let mut threaded_t = scalar_t.clone();
15838 let mut threaded_sa = scalar_sa.clone();
15839
15840 merge_unique_lms_suffixes_32s_omp(
15841 &mut scalar_t,
15842 &mut scalar_sa,
15843 n as SaSint,
15844 m as SaSint,
15845 1,
15846 );
15847 merge_unique_lms_suffixes_32s_omp(
15848 &mut threaded_t,
15849 &mut threaded_sa,
15850 n as SaSint,
15851 m as SaSint,
15852 4,
15853 );
15854 assert_eq!(threaded_t, scalar_t);
15855 assert_eq!(threaded_sa, scalar_sa);
15856
15857 let n = 131_072usize;
15858 let m = 65_536usize;
15859 let f = 100usize;
15860 let mut scalar_sa = vec![1; n];
15861 for i in (0..m).step_by(9) {
15862 scalar_sa[i] = 0;
15863 }
15864 let zero_count = scalar_sa[..m].iter().filter(|&&value| value == 0).count();
15865 let source = n - m - 1 + f;
15866 for i in 0..=zero_count {
15867 scalar_sa[source + i] = 2_000_000 + i as SaSint;
15868 }
15869 let mut threaded_sa = scalar_sa.clone();
15870
15871 merge_nonunique_lms_suffixes_32s_omp(
15872 &mut scalar_sa,
15873 n as SaSint,
15874 m as SaSint,
15875 f as SaSint,
15876 1,
15877 );
15878 merge_nonunique_lms_suffixes_32s_omp(
15879 &mut threaded_sa,
15880 n as SaSint,
15881 m as SaSint,
15882 f as SaSint,
15883 4,
15884 );
15885 assert_eq!(threaded_sa, scalar_sa);
15886 }
15887
15888 #[test]
15889 fn libsais16x64_radix_sort_lms_suffixes_32s_match_c() {
15890 let t = vec![0, 1, 2, 3, 1, 2, 3, 0];
15891 let mut rust_sa = vec![0, 0, 0, 0, 0, 1, 2, 3];
15892 let mut c_sa = rust_sa.clone();
15893 let mut rust_bucket = vec![0, 6, 7, 8];
15894 let mut c_bucket = rust_bucket.clone();
15895 radix_sort_lms_suffixes_32s_6k(&t, &mut rust_sa, &mut rust_bucket, 5, 3);
15896 unsafe {
15897 probe_libsais16x64_radix_sort_lms_suffixes_32s_6k(
15898 t.as_ptr(),
15899 c_sa.as_mut_ptr(),
15900 c_bucket.as_mut_ptr(),
15901 5,
15902 3,
15903 );
15904 }
15905 assert_eq!(rust_sa, c_sa);
15906 assert_eq!(rust_bucket, c_bucket);
15907
15908 let mut rust_sa = vec![0, 0, 0, 0, 0, 1, 2, 3];
15909 let mut c_sa = rust_sa.clone();
15910 let mut rust_bucket = vec![0, 0, 6, 0, 7, 0, 8, 0];
15911 let mut c_bucket = rust_bucket.clone();
15912 radix_sort_lms_suffixes_32s_2k(&t, &mut rust_sa, &mut rust_bucket, 5, 3);
15913 unsafe {
15914 probe_libsais16x64_radix_sort_lms_suffixes_32s_2k(
15915 t.as_ptr(),
15916 c_sa.as_mut_ptr(),
15917 c_bucket.as_mut_ptr(),
15918 5,
15919 3,
15920 );
15921 }
15922 assert_eq!(rust_sa, c_sa);
15923 assert_eq!(rust_bucket, c_bucket);
15924
15925 let mut cache = vec![ThreadCache::default(); 8];
15926 let sa = vec![0, 0, 0, 0, 0, 1, 2, 3];
15927 radix_sort_lms_suffixes_32s_block_gather(&t, &sa, &mut cache, 5, 3);
15928 assert_eq!(cache[5].index, 1);
15929 assert_eq!(cache[5].symbol, 1);
15930 assert_eq!(cache[6].index, 2);
15931 assert_eq!(cache[6].symbol, 2);
15932 assert_eq!(cache[7].index, 3);
15933 assert_eq!(cache[7].symbol, 3);
15934
15935 let mut bucket = vec![0, 6, 7, 8];
15936 radix_sort_lms_suffixes_32s_6k_block_sort(&mut bucket, &mut cache, 5, 3);
15937 assert_eq!(bucket, vec![0, 5, 6, 7]);
15938 assert_eq!(cache[5].symbol, 5);
15939 assert_eq!(cache[6].symbol, 6);
15940 assert_eq!(cache[7].symbol, 7);
15941
15942 let mut cache = vec![ThreadCache::default(); 8];
15943 radix_sort_lms_suffixes_32s_block_gather(&t, &sa, &mut cache, 5, 3);
15944 let mut bucket = vec![0, 0, 6, 0, 7, 0, 8, 0];
15945 radix_sort_lms_suffixes_32s_2k_block_sort(&mut bucket, &mut cache, 5, 3);
15946 assert_eq!(bucket, vec![0, 0, 5, 0, 6, 0, 7, 0]);
15947 assert_eq!(cache[5].symbol, 5);
15948 assert_eq!(cache[6].symbol, 6);
15949 assert_eq!(cache[7].symbol, 7);
15950
15951 let mut rust_sa = vec![0, 0, 0, 0, 0, 1, 2, 3];
15952 let mut c_sa = rust_sa.clone();
15953 let mut rust_bucket = vec![0, 6, 7, 8];
15954 let mut c_bucket = rust_bucket.clone();
15955 radix_sort_lms_suffixes_32s_6k_omp(&t, &mut rust_sa, 8, 4, &mut rust_bucket, 1);
15956 unsafe {
15957 probe_libsais16x64_radix_sort_lms_suffixes_32s_6k_omp(
15958 t.as_ptr(),
15959 c_sa.as_mut_ptr(),
15960 8,
15961 4,
15962 c_bucket.as_mut_ptr(),
15963 1,
15964 );
15965 }
15966 assert_eq!(rust_sa, c_sa);
15967 assert_eq!(rust_bucket, c_bucket);
15968
15969 let mut rust_sa = vec![0, 0, 0, 0, 0, 1, 2, 3];
15970 let mut c_sa = rust_sa.clone();
15971 let mut rust_bucket = vec![0, 0, 6, 0, 7, 0, 8, 0];
15972 let mut c_bucket = rust_bucket.clone();
15973 radix_sort_lms_suffixes_32s_2k_omp(&t, &mut rust_sa, 8, 4, &mut rust_bucket, 1);
15974 unsafe {
15975 probe_libsais16x64_radix_sort_lms_suffixes_32s_2k_omp(
15976 t.as_ptr(),
15977 c_sa.as_mut_ptr(),
15978 8,
15979 4,
15980 c_bucket.as_mut_ptr(),
15981 1,
15982 );
15983 }
15984 assert_eq!(rust_sa, c_sa);
15985 assert_eq!(rust_bucket, c_bucket);
15986
15987 let t = vec![2, 1, 3, 1, 0];
15988 let mut rust_sa = vec![0; t.len()];
15989 let mut c_sa = rust_sa.clone();
15990 let mut rust_bucket = vec![0, 2, 4, 5];
15991 let mut c_bucket = rust_bucket.clone();
15992 let rust_m =
15993 radix_sort_lms_suffixes_32s_1k(&t, &mut rust_sa, t.len() as SaSint, &mut rust_bucket);
15994 let c_m = unsafe {
15995 probe_libsais16x64_radix_sort_lms_suffixes_32s_1k(
15996 t.as_ptr(),
15997 c_sa.as_mut_ptr(),
15998 t.len() as SaSint,
15999 c_bucket.as_mut_ptr(),
16000 )
16001 };
16002 assert_eq!(rust_m, c_m);
16003 assert_eq!(rust_sa, c_sa);
16004 assert_eq!(rust_bucket, c_bucket);
16005 }
16006
16007 #[test]
16008 fn libsais16x64_radix_sort_set_markers_32s_match_c() {
16009 let mut rust_sa = vec![0; 8];
16010 let mut c_sa = rust_sa.clone();
16011 let mut induction_bucket = vec![1, 3, 5, 7];
16012 radix_sort_set_markers_32s_6k(&mut rust_sa, &induction_bucket, 0, 4);
16013 unsafe {
16014 probe_libsais16x64_radix_sort_set_markers_32s_6k(
16015 c_sa.as_mut_ptr(),
16016 induction_bucket.as_mut_ptr(),
16017 0,
16018 4,
16019 );
16020 }
16021 assert_eq!(rust_sa, c_sa);
16022
16023 let mut rust_sa = vec![0; 8];
16024 let mut c_sa = rust_sa.clone();
16025 radix_sort_set_markers_32s_6k_omp(&mut rust_sa, 5, &induction_bucket, 1);
16026 unsafe {
16027 probe_libsais16x64_radix_sort_set_markers_32s_6k_omp(
16028 c_sa.as_mut_ptr(),
16029 5,
16030 induction_bucket.as_mut_ptr(),
16031 1,
16032 );
16033 }
16034 assert_eq!(rust_sa, c_sa);
16035
16036 let mut rust_sa = vec![0; 8];
16037 let mut c_sa = rust_sa.clone();
16038 let mut induction_bucket = vec![1, 0, 3, 0, 5, 0, 7, 0];
16039 radix_sort_set_markers_32s_4k(&mut rust_sa, &induction_bucket, 0, 4);
16040 unsafe {
16041 probe_libsais16x64_radix_sort_set_markers_32s_4k(
16042 c_sa.as_mut_ptr(),
16043 induction_bucket.as_mut_ptr(),
16044 0,
16045 4,
16046 );
16047 }
16048 assert_eq!(rust_sa, c_sa);
16049
16050 let mut rust_sa = vec![0; 8];
16051 let mut c_sa = rust_sa.clone();
16052 radix_sort_set_markers_32s_4k_omp(&mut rust_sa, 5, &induction_bucket, 1);
16053 unsafe {
16054 probe_libsais16x64_radix_sort_set_markers_32s_4k_omp(
16055 c_sa.as_mut_ptr(),
16056 5,
16057 induction_bucket.as_mut_ptr(),
16058 1,
16059 );
16060 }
16061 assert_eq!(rust_sa, c_sa);
16062 }
16063
16064 #[test]
16065 fn libsais16x64_radix_sort_set_markers_32s_omp_partitions_large_inputs() {
16066 let k = 65_600usize;
16067 let induction_bucket_6k: Vec<SaSint> = (0..k).map(|i| i as SaSint).collect();
16068 let mut single = vec![0; k];
16069 let mut threaded = vec![0; k];
16070 radix_sort_set_markers_32s_6k_omp(&mut single, k as SaSint, &induction_bucket_6k, 1);
16071 radix_sort_set_markers_32s_6k_omp(&mut threaded, k as SaSint, &induction_bucket_6k, 4);
16072 assert_eq!(threaded, single);
16073
16074 let mut induction_bucket_4k = vec![0; 2 * k];
16075 for i in 0..k {
16076 induction_bucket_4k[buckets_index2(i, 0)] = i as SaSint;
16077 }
16078 let mut single = vec![0; k];
16079 let mut threaded = vec![0; k];
16080 radix_sort_set_markers_32s_4k_omp(&mut single, k as SaSint, &induction_bucket_4k, 1);
16081 radix_sort_set_markers_32s_4k_omp(&mut threaded, k as SaSint, &induction_bucket_4k, 4);
16082 assert_eq!(threaded, single);
16083 }
16084
16085 #[test]
16086 fn libsais16x64_partial_sorting_32s_helpers_match_c() {
16087 let k = 3;
16088 let mut rust_sa = vec![0, SAINT_MIN, 2, SAINT_MIN, 4, SAINT_MIN];
16089 let mut c_sa = rust_sa.clone();
16090 let mut buckets = vec![0; 6 * k as usize];
16091 buckets[buckets_index4(1, 0)] = 3;
16092 buckets[buckets_index4(2, 0)] = 6;
16093 buckets[4 * k as usize + buckets_index2(0, 0)] = 0;
16094 buckets[4 * k as usize + buckets_index2(1, 0)] = 1;
16095 partial_sorting_shift_markers_32s_6k_omp(&mut rust_sa, k, &buckets, 1);
16096 unsafe {
16097 probe_libsais16x64_partial_sorting_shift_markers_32s_6k_omp(
16098 c_sa.as_mut_ptr(),
16099 k,
16100 buckets.as_ptr(),
16101 1,
16102 );
16103 }
16104 assert_eq!(rust_sa, c_sa);
16105
16106 let mut rust_sa = vec![
16107 1 | SUFFIX_GROUP_MARKER,
16108 2,
16109 3 | SUFFIX_GROUP_MARKER,
16110 4 | SUFFIX_GROUP_MARKER,
16111 5,
16112 6,
16113 ];
16114 let mut c_sa = rust_sa.clone();
16115 partial_sorting_shift_markers_32s_4k(&mut rust_sa, 6);
16116 unsafe { probe_libsais16x64_partial_sorting_shift_markers_32s_4k(c_sa.as_mut_ptr(), 6) };
16117 assert_eq!(rust_sa, c_sa);
16118
16119 let mut rust_buckets = vec![0; 6 * k as usize];
16120 for (i, value) in rust_buckets[4 * k as usize..].iter_mut().enumerate() {
16121 *value = 100 + i as SaSint;
16122 }
16123 let mut c_buckets = rust_buckets.clone();
16124 partial_sorting_shift_buckets_32s_6k(k, &mut rust_buckets);
16125 unsafe {
16126 probe_libsais16x64_partial_sorting_shift_buckets_32s_6k(k, c_buckets.as_mut_ptr())
16127 };
16128 assert_eq!(rust_buckets, c_buckets);
16129
16130 let mut rust_sa = vec![1 | SUFFIX_GROUP_MARKER, -3, 5 | SUFFIX_GROUP_MARKER, -7];
16131 let mut c_sa = rust_sa.clone();
16132 let rust_l = partial_sorting_gather_lms_suffixes_32s_4k(&mut rust_sa, 0, 4);
16133 let c_l = unsafe {
16134 probe_libsais16x64_partial_sorting_gather_lms_suffixes_32s_4k(c_sa.as_mut_ptr(), 0, 4)
16135 };
16136 assert_eq!(rust_l, c_l);
16137 assert_eq!(rust_sa, c_sa);
16138
16139 let mut rust_sa = vec![1, -3, 5, -7];
16140 let mut c_sa = rust_sa.clone();
16141 let rust_l = partial_sorting_gather_lms_suffixes_32s_1k(&mut rust_sa, 0, 4);
16142 let c_l = unsafe {
16143 probe_libsais16x64_partial_sorting_gather_lms_suffixes_32s_1k(c_sa.as_mut_ptr(), 0, 4)
16144 };
16145 assert_eq!(rust_l, c_l);
16146 assert_eq!(rust_sa, c_sa);
16147
16148 let mut rust_state = alloc_thread_state(1).unwrap();
16149 let mut rust_sa = vec![1 | SUFFIX_GROUP_MARKER, -3, 5 | SUFFIX_GROUP_MARKER, -7];
16150 let mut c_sa = rust_sa.clone();
16151 partial_sorting_gather_lms_suffixes_32s_4k_omp(&mut rust_sa, 4, 1, &mut rust_state);
16152 unsafe {
16153 probe_libsais16x64_partial_sorting_gather_lms_suffixes_32s_4k_omp(
16154 c_sa.as_mut_ptr(),
16155 4,
16156 1,
16157 );
16158 }
16159 assert_eq!(rust_sa, c_sa);
16160
16161 let mut rust_state = alloc_thread_state(1).unwrap();
16162 let mut rust_sa = vec![1, -3, 5, -7];
16163 let mut c_sa = rust_sa.clone();
16164 partial_sorting_gather_lms_suffixes_32s_1k_omp(&mut rust_sa, 4, 1, &mut rust_state);
16165 unsafe {
16166 probe_libsais16x64_partial_sorting_gather_lms_suffixes_32s_1k_omp(
16167 c_sa.as_mut_ptr(),
16168 4,
16169 1,
16170 );
16171 }
16172 assert_eq!(rust_sa, c_sa);
16173 }
16174
16175 #[test]
16176 fn libsais16x64_partial_sorting_gather_lms_suffixes_32s_omp_uses_block_partition() {
16177 let n = 65_536usize;
16178 let mut base_4k = vec![0; n];
16179 let mut base_1k = vec![0; n];
16180 for i in 0..n {
16181 let value = (i as SaSint + 1) & SAINT_MAX;
16182 base_4k[i] = if i % 7 == 0 {
16183 value | SAINT_MIN | SUFFIX_GROUP_MARKER
16184 } else if i % 11 == 0 {
16185 value | SUFFIX_GROUP_MARKER
16186 } else {
16187 value
16188 };
16189 base_1k[i] = if i % 7 == 0 { value | SAINT_MIN } else { value };
16190 }
16191 let lms_count = base_1k.iter().filter(|&&v| v < 0).count();
16192
16193 let mut scalar = base_4k.clone();
16194 let mut threaded = base_4k;
16195 let mut scalar_state = alloc_thread_state(1).unwrap();
16196 let mut threaded_state = alloc_thread_state(4).unwrap();
16197 partial_sorting_gather_lms_suffixes_32s_4k_omp(
16198 &mut scalar,
16199 n as SaSint,
16200 1,
16201 &mut scalar_state,
16202 );
16203 partial_sorting_gather_lms_suffixes_32s_4k_omp(
16204 &mut threaded,
16205 n as SaSint,
16206 4,
16207 &mut threaded_state,
16208 );
16209 assert_eq!(&threaded[..lms_count], &scalar[..lms_count]);
16210
16211 let mut scalar = base_1k.clone();
16212 let mut threaded = base_1k;
16213 partial_sorting_gather_lms_suffixes_32s_1k_omp(
16214 &mut scalar,
16215 n as SaSint,
16216 1,
16217 &mut scalar_state,
16218 );
16219 partial_sorting_gather_lms_suffixes_32s_1k_omp(
16220 &mut threaded,
16221 n as SaSint,
16222 4,
16223 &mut threaded_state,
16224 );
16225 assert_eq!(&threaded[..lms_count], &scalar[..lms_count]);
16226 }
16227
16228 #[test]
16229 fn libsais16x64_partial_sorting_32s_block_helpers_behave_like_upstream_shapes() {
16230 let t = vec![0, 1, 2, 1, 0];
16231 let k = 3;
16232
16233 let mut sa = vec![0, 4 | SAINT_MIN, 0];
16234 let mut cache = vec![ThreadCache::default(); sa.len()];
16235 partial_sorting_scan_right_to_left_32s_6k_block_gather(&t, &mut sa, &mut cache, 1, 1);
16236 assert_eq!(cache[1].index, 4 | SAINT_MIN);
16237 assert_eq!(cache[1].symbol, buckets_index4(1, 1) as SaSint);
16238
16239 let mut sa = vec![0, 4 | SUFFIX_GROUP_MARKER, 0];
16240 let mut cache = vec![ThreadCache::default(); sa.len()];
16241 partial_sorting_scan_right_to_left_32s_4k_block_gather(&t, &mut sa, &mut cache, 1, 1);
16242 assert_eq!(sa[1], 0);
16243 assert_eq!(cache[1].index, 4 | SUFFIX_GROUP_MARKER);
16244 assert_eq!(cache[1].symbol, buckets_index2(1, 1) as SaSint);
16245
16246 let mut sa = vec![0, 4, 0];
16247 let mut cache = vec![ThreadCache::default(); sa.len()];
16248 partial_sorting_scan_right_to_left_32s_1k_block_gather(&t, &mut sa, &mut cache, 1, 1);
16249 assert_eq!(sa[1], 0);
16250 assert_eq!(cache[1].index, 3 | SAINT_MIN);
16251 assert_eq!(cache[1].symbol, 1);
16252
16253 let mut sa = vec![4 | SAINT_MIN, 0, 0];
16254 let mut cache = vec![ThreadCache::default(); sa.len()];
16255 partial_sorting_scan_left_to_right_32s_6k_block_gather(&t, &mut sa, &mut cache, 0, 1);
16256 assert_eq!(cache[0].index, 4 | SAINT_MIN);
16257 assert_eq!(cache[0].symbol, buckets_index4(1, 1) as SaSint);
16258
16259 let mut sa = vec![4 | SUFFIX_GROUP_MARKER, 0, 0];
16260 let mut cache = vec![ThreadCache::default(); sa.len()];
16261 partial_sorting_scan_left_to_right_32s_4k_block_gather(&t, &mut sa, &mut cache, 0, 1);
16262 assert_eq!(sa[0], 0);
16263 assert_eq!(cache[0].index, 4 | SUFFIX_GROUP_MARKER);
16264 assert_eq!(cache[0].symbol, buckets_index2(1, 0) as SaSint);
16265
16266 let mut sa = vec![4, 0, 0];
16267 let mut cache = vec![ThreadCache::default(); sa.len()];
16268 partial_sorting_scan_left_to_right_32s_1k_block_gather(&t, &mut sa, &mut cache, 0, 1);
16269 assert_eq!(sa[0], 0);
16270 assert_eq!(cache[0].index, 3);
16271 assert_eq!(cache[0].symbol, 1);
16272
16273 let mut cache = vec![ThreadCache::default(); 3];
16274 cache[1].index = 4 | SAINT_MIN;
16275 cache[1].symbol = buckets_index4(1, 1) as SaSint;
16276 let mut buckets = vec![0; 4 * k];
16277 buckets[buckets_index4(1, 1)] = 2;
16278 let d = partial_sorting_scan_right_to_left_32s_6k_block_sort(
16279 &t,
16280 &mut buckets,
16281 0,
16282 &mut cache,
16283 1,
16284 1,
16285 );
16286 assert_eq!(d, 1);
16287 assert_eq!(cache[1].index, 3 | SAINT_MIN);
16288 assert_eq!(buckets[buckets_index4(1, 1)], 1);
16289 assert_eq!(buckets[buckets_index4(1, 1) + 2], 1);
16290
16291 let mut cache = vec![ThreadCache::default(); 3];
16292 cache[0].index = 4 | SAINT_MIN;
16293 cache[0].symbol = buckets_index4(1, 1) as SaSint;
16294 let mut buckets = vec![0; 4 * k];
16295 buckets[buckets_index4(1, 1)] = 1;
16296 let d = partial_sorting_scan_left_to_right_32s_6k_block_sort(
16297 &t,
16298 &mut buckets,
16299 0,
16300 &mut cache,
16301 0,
16302 1,
16303 );
16304 assert_eq!(d, 1);
16305 assert_eq!(cache[0].index, 3 | SAINT_MIN);
16306 assert_eq!(buckets[buckets_index4(1, 1)], 2);
16307 assert_eq!(buckets[buckets_index4(1, 1) + 2], 1);
16308
16309 let mut cache = vec![ThreadCache::default(); 3];
16310 cache[1].index = 4 | SUFFIX_GROUP_MARKER;
16311 cache[1].symbol = buckets_index2(1, 1) as SaSint;
16312 let mut buckets = vec![0; 4 * k];
16313 buckets[3 * k + 1] = 2;
16314 let d = partial_sorting_scan_right_to_left_32s_4k_block_sort(
16315 &t,
16316 k as SaSint,
16317 &mut buckets,
16318 0,
16319 &mut cache,
16320 1,
16321 1,
16322 );
16323 assert_eq!(d, 1);
16324 assert_eq!(cache[1].symbol, 1);
16325 assert_eq!(buckets[3 * k + 1], 1);
16326
16327 let mut cache = vec![ThreadCache::default(); 3];
16328 cache[0].index = 4 | SUFFIX_GROUP_MARKER;
16329 cache[0].symbol = buckets_index2(1, 0) as SaSint;
16330 let mut buckets = vec![0; 4 * k];
16331 buckets[2 * k + 1] = 1;
16332 let d = partial_sorting_scan_left_to_right_32s_4k_block_sort(
16333 &t,
16334 k as SaSint,
16335 &mut buckets,
16336 0,
16337 &mut cache,
16338 0,
16339 1,
16340 );
16341 assert_eq!(d, 1);
16342 assert_eq!(cache[0].symbol, 1);
16343 assert_eq!(buckets[2 * k + 1], 2);
16344
16345 let mut cache = vec![ThreadCache::default(); 3];
16346 cache[1].index = 4;
16347 cache[1].symbol = 1;
16348 let mut buckets = vec![0; k];
16349 buckets[1] = 2;
16350 partial_sorting_scan_right_to_left_32s_1k_block_sort(&t, &mut buckets, &mut cache, 1, 1);
16351 assert_eq!(cache[1].symbol, 1);
16352 assert_eq!(buckets[1], 1);
16353
16354 let mut cache = vec![ThreadCache::default(); 3];
16355 cache[0].index = 4;
16356 cache[0].symbol = 1;
16357 let mut buckets = vec![0; k];
16358 buckets[1] = 1;
16359 partial_sorting_scan_left_to_right_32s_1k_block_sort(&t, &mut buckets, &mut cache, 0, 1);
16360 assert_eq!(cache[0].symbol, 1);
16361 assert_eq!(buckets[1], 2);
16362 }
16363
16364 #[test]
16365 fn libsais16x64_partial_sorting_scan_32s_match_c() {
16366 let t = vec![0, 1, 2, 1, 3, 0];
16367 let k = 4;
16368
16369 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16370 let mut c_sa = rust_sa.clone();
16371 let mut rust_buckets = vec![0; 6 * k as usize];
16372 rust_buckets[buckets_index4(2, 0)] = 4;
16373 rust_buckets[buckets_index4(1, 1)] = 5;
16374 let mut c_buckets = rust_buckets.clone();
16375 let rust_d =
16376 partial_sorting_scan_left_to_right_32s_6k(&t, &mut rust_sa, &mut rust_buckets, 0, 0, 2);
16377 let c_d = unsafe {
16378 probe_libsais16x64_partial_sorting_scan_left_to_right_32s_6k(
16379 t.as_ptr(),
16380 c_sa.as_mut_ptr(),
16381 c_buckets.as_mut_ptr(),
16382 0,
16383 0,
16384 2,
16385 )
16386 };
16387 assert_eq!(rust_d, c_d);
16388 assert_eq!(rust_sa, c_sa);
16389 assert_eq!(rust_buckets, c_buckets);
16390
16391 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16392 let mut c_sa = rust_sa.clone();
16393 let mut rust_buckets = vec![0; 4 * k as usize];
16394 rust_buckets[2 * k as usize + 2] = 4;
16395 rust_buckets[2 * k as usize + 1] = 5;
16396 let mut c_buckets = rust_buckets.clone();
16397 let rust_d = partial_sorting_scan_left_to_right_32s_4k(
16398 &t,
16399 &mut rust_sa,
16400 k,
16401 &mut rust_buckets,
16402 0,
16403 0,
16404 2,
16405 );
16406 let c_d = unsafe {
16407 probe_libsais16x64_partial_sorting_scan_left_to_right_32s_4k(
16408 t.as_ptr(),
16409 c_sa.as_mut_ptr(),
16410 k,
16411 c_buckets.as_mut_ptr(),
16412 0,
16413 0,
16414 2,
16415 )
16416 };
16417 assert_eq!(rust_d, c_d);
16418 assert_eq!(rust_sa, c_sa);
16419 assert_eq!(rust_buckets, c_buckets);
16420
16421 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16422 let mut c_sa = rust_sa.clone();
16423 let mut rust_buckets = vec![0, 5, 4, 0];
16424 let mut c_buckets = rust_buckets.clone();
16425 partial_sorting_scan_left_to_right_32s_1k(&t, &mut rust_sa, &mut rust_buckets, 0, 2);
16426 unsafe {
16427 probe_libsais16x64_partial_sorting_scan_left_to_right_32s_1k(
16428 t.as_ptr(),
16429 c_sa.as_mut_ptr(),
16430 c_buckets.as_mut_ptr(),
16431 0,
16432 2,
16433 );
16434 }
16435 assert_eq!(rust_sa, c_sa);
16436 assert_eq!(rust_buckets, c_buckets);
16437
16438 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16439 let mut c_sa = rust_sa.clone();
16440 let mut rust_buckets = vec![0; 6 * k as usize];
16441 rust_buckets[buckets_index4(2, 0)] = 7;
16442 rust_buckets[buckets_index4(1, 1)] = 6;
16443 let mut c_buckets = rust_buckets.clone();
16444 let rust_d =
16445 partial_sorting_scan_right_to_left_32s_6k(&t, &mut rust_sa, &mut rust_buckets, 0, 0, 2);
16446 let c_d = unsafe {
16447 probe_libsais16x64_partial_sorting_scan_right_to_left_32s_6k(
16448 t.as_ptr(),
16449 c_sa.as_mut_ptr(),
16450 c_buckets.as_mut_ptr(),
16451 0,
16452 0,
16453 2,
16454 )
16455 };
16456 assert_eq!(rust_d, c_d);
16457 assert_eq!(rust_sa, c_sa);
16458 assert_eq!(rust_buckets, c_buckets);
16459
16460 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16461 let mut c_sa = rust_sa.clone();
16462 let mut rust_buckets = vec![0; 4 * k as usize];
16463 rust_buckets[3 * k as usize + 2] = 7;
16464 rust_buckets[3 * k as usize + 1] = 6;
16465 let mut c_buckets = rust_buckets.clone();
16466 let rust_d = partial_sorting_scan_right_to_left_32s_4k(
16467 &t,
16468 &mut rust_sa,
16469 k,
16470 &mut rust_buckets,
16471 0,
16472 0,
16473 2,
16474 );
16475 let c_d = unsafe {
16476 probe_libsais16x64_partial_sorting_scan_right_to_left_32s_4k(
16477 t.as_ptr(),
16478 c_sa.as_mut_ptr(),
16479 k,
16480 c_buckets.as_mut_ptr(),
16481 0,
16482 0,
16483 2,
16484 )
16485 };
16486 assert_eq!(rust_d, c_d);
16487 assert_eq!(rust_sa, c_sa);
16488 assert_eq!(rust_buckets, c_buckets);
16489
16490 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16491 let mut c_sa = rust_sa.clone();
16492 let mut rust_buckets = vec![0, 6, 7, 0];
16493 let mut c_buckets = rust_buckets.clone();
16494 partial_sorting_scan_right_to_left_32s_1k(&t, &mut rust_sa, &mut rust_buckets, 0, 2);
16495 unsafe {
16496 probe_libsais16x64_partial_sorting_scan_right_to_left_32s_1k(
16497 t.as_ptr(),
16498 c_sa.as_mut_ptr(),
16499 c_buckets.as_mut_ptr(),
16500 0,
16501 2,
16502 );
16503 }
16504 assert_eq!(rust_sa, c_sa);
16505 assert_eq!(rust_buckets, c_buckets);
16506
16507 let mut state = alloc_thread_state(1).unwrap();
16508 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 7, 9];
16509 let mut c_sa = rust_sa.clone();
16510 let mut rust_buckets = vec![0; 6 * k as usize];
16511 rust_buckets[buckets_index4(2, 0)] = 4;
16512 rust_buckets[buckets_index4(1, 1)] = 5;
16513 rust_buckets[buckets_index4(3, 0)] = 6;
16514 let mut c_buckets = rust_buckets.clone();
16515 let rust_d = partial_sorting_scan_left_to_right_32s_6k_omp(
16516 &t,
16517 &mut rust_sa,
16518 5,
16519 &mut rust_buckets,
16520 2,
16521 0,
16522 1,
16523 &mut state,
16524 );
16525 let c_d = unsafe {
16526 probe_libsais16x64_partial_sorting_scan_left_to_right_32s_6k_omp(
16527 t.as_ptr(),
16528 c_sa.as_mut_ptr(),
16529 5,
16530 c_buckets.as_mut_ptr(),
16531 2,
16532 0,
16533 1,
16534 )
16535 };
16536 assert_eq!(rust_d, c_d);
16537 assert_eq!(rust_sa, c_sa);
16538 assert_eq!(rust_buckets, c_buckets);
16539
16540 let mut state = alloc_thread_state(1).unwrap();
16541 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 7, 9];
16542 let mut c_sa = rust_sa.clone();
16543 let mut rust_buckets = vec![0; 4 * k as usize];
16544 rust_buckets[2 * k as usize + 2] = 4;
16545 rust_buckets[2 * k as usize + 1] = 5;
16546 rust_buckets[2 * k as usize + 3] = 6;
16547 let mut c_buckets = rust_buckets.clone();
16548 let rust_d = partial_sorting_scan_left_to_right_32s_4k_omp(
16549 &t,
16550 &mut rust_sa,
16551 5,
16552 k,
16553 &mut rust_buckets,
16554 0,
16555 1,
16556 &mut state,
16557 );
16558 let c_d = unsafe {
16559 probe_libsais16x64_partial_sorting_scan_left_to_right_32s_4k_omp(
16560 t.as_ptr(),
16561 c_sa.as_mut_ptr(),
16562 5,
16563 k,
16564 c_buckets.as_mut_ptr(),
16565 0,
16566 1,
16567 )
16568 };
16569 assert_eq!(rust_d, c_d);
16570 assert_eq!(rust_sa, c_sa);
16571 assert_eq!(rust_buckets, c_buckets);
16572
16573 let mut state = alloc_thread_state(1).unwrap();
16574 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 7, 9];
16575 let mut c_sa = rust_sa.clone();
16576 let mut rust_buckets = vec![0, 5, 4, 6];
16577 let mut c_buckets = rust_buckets.clone();
16578 partial_sorting_scan_left_to_right_32s_1k_omp(
16579 &t,
16580 &mut rust_sa,
16581 5,
16582 &mut rust_buckets,
16583 1,
16584 &mut state,
16585 );
16586 unsafe {
16587 probe_libsais16x64_partial_sorting_scan_left_to_right_32s_1k_omp(
16588 t.as_ptr(),
16589 c_sa.as_mut_ptr(),
16590 5,
16591 c_buckets.as_mut_ptr(),
16592 1,
16593 );
16594 }
16595 assert_eq!(rust_sa, c_sa);
16596 assert_eq!(rust_buckets, c_buckets);
16597
16598 let mut state = alloc_thread_state(1).unwrap();
16599 let mut rust_sa = vec![0, 0, 3, 4, 9, 9, 9, 9];
16600 let mut c_sa = rust_sa.clone();
16601 let mut rust_buckets = vec![0; 6 * k as usize];
16602 rust_buckets[buckets_index4(2, 0)] = 7;
16603 rust_buckets[buckets_index4(1, 1)] = 6;
16604 let mut c_buckets = rust_buckets.clone();
16605 let rust_d = partial_sorting_scan_right_to_left_32s_6k_omp(
16606 &t,
16607 &mut rust_sa,
16608 5,
16609 &mut rust_buckets,
16610 1,
16611 1,
16612 0,
16613 1,
16614 &mut state,
16615 );
16616 let c_d = unsafe {
16617 probe_libsais16x64_partial_sorting_scan_right_to_left_32s_6k_omp(
16618 t.as_ptr(),
16619 c_sa.as_mut_ptr(),
16620 5,
16621 c_buckets.as_mut_ptr(),
16622 1,
16623 1,
16624 0,
16625 1,
16626 )
16627 };
16628 assert_eq!(rust_d, c_d);
16629 assert_eq!(rust_sa, c_sa);
16630 assert_eq!(rust_buckets, c_buckets);
16631
16632 let mut state = alloc_thread_state(1).unwrap();
16633 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16634 let mut c_sa = rust_sa.clone();
16635 let mut rust_buckets = vec![0; 4 * k as usize];
16636 rust_buckets[3 * k as usize + 2] = 7;
16637 rust_buckets[3 * k as usize + 1] = 6;
16638 let mut c_buckets = rust_buckets.clone();
16639 let rust_d = partial_sorting_scan_right_to_left_32s_4k_omp(
16640 &t,
16641 &mut rust_sa,
16642 2,
16643 k,
16644 &mut rust_buckets,
16645 0,
16646 1,
16647 &mut state,
16648 );
16649 let c_d = unsafe {
16650 probe_libsais16x64_partial_sorting_scan_right_to_left_32s_4k_omp(
16651 t.as_ptr(),
16652 c_sa.as_mut_ptr(),
16653 2,
16654 k,
16655 c_buckets.as_mut_ptr(),
16656 0,
16657 1,
16658 )
16659 };
16660 assert_eq!(rust_d, c_d);
16661 assert_eq!(rust_sa, c_sa);
16662 assert_eq!(rust_buckets, c_buckets);
16663
16664 let mut state = alloc_thread_state(1).unwrap();
16665 let mut rust_sa = vec![3, 4, 0, 0, 9, 9, 9, 9];
16666 let mut c_sa = rust_sa.clone();
16667 let mut rust_buckets = vec![0, 6, 7, 0];
16668 let mut c_buckets = rust_buckets.clone();
16669 partial_sorting_scan_right_to_left_32s_1k_omp(
16670 &t,
16671 &mut rust_sa,
16672 2,
16673 &mut rust_buckets,
16674 1,
16675 &mut state,
16676 );
16677 unsafe {
16678 probe_libsais16x64_partial_sorting_scan_right_to_left_32s_1k_omp(
16679 t.as_ptr(),
16680 c_sa.as_mut_ptr(),
16681 2,
16682 c_buckets.as_mut_ptr(),
16683 1,
16684 );
16685 }
16686 assert_eq!(rust_sa, c_sa);
16687 assert_eq!(rust_buckets, c_buckets);
16688 }
16689
16690 #[test]
16691 fn libsais16x64_place_lms_suffixes_histogram_32s_match_c() {
16692 let n = 12;
16693 let k = 4;
16694 let m = 4;
16695 let mut rust_sa = vec![101, 102, 103, 104, 9, 9, 9, 9, 9, 9, 9, 9];
16696 let mut c_sa = rust_sa.clone();
16697 let mut buckets = vec![0; 2 * k as usize];
16698 buckets[buckets_index2(1, 0)] = 7;
16699 buckets[buckets_index2(1, 1)] = 2;
16700 buckets[buckets_index2(2, 0)] = 10;
16701 buckets[buckets_index2(2, 1)] = 1;
16702 place_lms_suffixes_histogram_32s_2k(&mut rust_sa, n, k, m, &buckets);
16703 unsafe {
16704 probe_libsais16x64_place_lms_suffixes_histogram_32s_2k(
16705 c_sa.as_mut_ptr(),
16706 n,
16707 k,
16708 m,
16709 buckets.as_ptr(),
16710 );
16711 }
16712 assert_eq!(rust_sa, c_sa);
16713
16714 let mut rust_sa = vec![101, 102, 103, 104, 9, 9, 9, 9, 9, 9, 9, 9];
16715 let mut c_sa = rust_sa.clone();
16716 let mut buckets = vec![0; 4 * k as usize];
16717 buckets[buckets_index2(1, 1)] = 2;
16718 buckets[buckets_index2(2, 1)] = 1;
16719 buckets[3 * k as usize + 1] = 7;
16720 buckets[3 * k as usize + 2] = 10;
16721 place_lms_suffixes_histogram_32s_4k(&mut rust_sa, n, k, m, &buckets);
16722 unsafe {
16723 probe_libsais16x64_place_lms_suffixes_histogram_32s_4k(
16724 c_sa.as_mut_ptr(),
16725 n,
16726 k,
16727 m,
16728 buckets.as_ptr(),
16729 );
16730 }
16731 assert_eq!(rust_sa, c_sa);
16732
16733 let mut rust_sa = vec![101, 102, 103, 104, 9, 9, 9, 9, 9, 9, 9, 9];
16734 let mut c_sa = rust_sa.clone();
16735 let mut buckets = vec![0; 6 * k as usize];
16736 buckets[buckets_index4(1, 1)] = 2;
16737 buckets[buckets_index4(2, 1)] = 1;
16738 buckets[5 * k as usize + 1] = 7;
16739 buckets[5 * k as usize + 2] = 10;
16740 place_lms_suffixes_histogram_32s_6k(&mut rust_sa, n, k, m, &buckets);
16741 unsafe {
16742 probe_libsais16x64_place_lms_suffixes_histogram_32s_6k(
16743 c_sa.as_mut_ptr(),
16744 n,
16745 k,
16746 m,
16747 buckets.as_ptr(),
16748 );
16749 }
16750 assert_eq!(rust_sa, c_sa);
16751 }
16752
16753 #[test]
16754 fn libsais16x64_count_gather_lms_suffixes_32s_match_c() {
16755 let t = vec![2, 1, 3, 1, 2, 0, 1, 0];
16756 let n = t.len() as SaSint;
16757 let k = 4;
16758
16759 let mut rust_sa = vec![0; t.len()];
16760 let mut c_sa = rust_sa.clone();
16761 let rust_m = gather_lms_suffixes_32s(&t, &mut rust_sa, n);
16762 let c_m =
16763 unsafe { probe_libsais16x64_gather_lms_suffixes_32s(t.as_ptr(), c_sa.as_mut_ptr(), n) };
16764 assert_eq!(rust_m, c_m);
16765 assert_eq!(rust_sa, c_sa);
16766
16767 let compact_t = vec![2, SAINT_MIN | 1, 3, 1, SAINT_MIN | 2, 0, 1, 0];
16768 let mut rust_sa = vec![0; compact_t.len()];
16769 let mut c_sa = rust_sa.clone();
16770 let rust_m = gather_compacted_lms_suffixes_32s(&compact_t, &mut rust_sa, n);
16771 let c_m = unsafe {
16772 probe_libsais16x64_gather_compacted_lms_suffixes_32s(
16773 compact_t.as_ptr(),
16774 c_sa.as_mut_ptr(),
16775 n,
16776 )
16777 };
16778 assert_eq!(rust_m, c_m);
16779 assert_eq!(rust_sa, c_sa);
16780
16781 let mut rust_buckets = vec![99; 2 * k as usize];
16782 let mut c_buckets = rust_buckets.clone();
16783 count_lms_suffixes_32s_2k(&t, n, k, &mut rust_buckets);
16784 unsafe {
16785 probe_libsais16x64_count_lms_suffixes_32s_2k(t.as_ptr(), n, k, c_buckets.as_mut_ptr());
16786 }
16787 assert_eq!(rust_buckets, c_buckets);
16788
16789 let mut rust_sa = vec![0; t.len()];
16790 let mut c_sa = rust_sa.clone();
16791 let mut rust_buckets = vec![0; 2 * k as usize];
16792 let mut c_buckets = rust_buckets.clone();
16793 let rust_m = count_and_gather_lms_suffixes_32s_2k(
16794 &t,
16795 &mut rust_sa,
16796 n,
16797 k,
16798 &mut rust_buckets,
16799 0,
16800 n as isize,
16801 );
16802 let c_m = unsafe {
16803 probe_libsais16x64_count_and_gather_lms_suffixes_32s_2k(
16804 t.as_ptr(),
16805 c_sa.as_mut_ptr(),
16806 n,
16807 k,
16808 c_buckets.as_mut_ptr(),
16809 0,
16810 n,
16811 )
16812 };
16813 assert_eq!(rust_m, c_m);
16814 assert_eq!(rust_sa, c_sa);
16815 assert_eq!(rust_buckets, c_buckets);
16816
16817 let mut rust_sa = vec![0; compact_t.len()];
16818 let mut c_sa = rust_sa.clone();
16819 let mut rust_buckets = vec![0; 2 * k as usize];
16820 let mut c_buckets = rust_buckets.clone();
16821 let rust_m = count_and_gather_compacted_lms_suffixes_32s_2k(
16822 &compact_t,
16823 &mut rust_sa,
16824 n,
16825 k,
16826 &mut rust_buckets,
16827 0,
16828 n as isize,
16829 );
16830 let c_m = unsafe {
16831 probe_libsais16x64_count_and_gather_compacted_lms_suffixes_32s_2k(
16832 compact_t.as_ptr(),
16833 c_sa.as_mut_ptr(),
16834 n,
16835 k,
16836 c_buckets.as_mut_ptr(),
16837 0,
16838 n,
16839 )
16840 };
16841 assert_eq!(rust_m, c_m);
16842 assert_eq!(rust_sa, c_sa);
16843 assert_eq!(rust_buckets, c_buckets);
16844 }
16845
16846 #[test]
16847 fn libsais16x64_small_openmp_leaf_helpers_match_upstream_shapes() {
16848 let sa = [-1, 0, 3, SAINT_MIN, 0, 7, -5];
16849 assert_eq!(count_negative_marked_suffixes(&sa, 1, 5), 1);
16850 assert_eq!(count_zero_marked_suffixes(&sa, 1, 5), 2);
16851
16852 let mut buckets = vec![1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9, 0, 10, 11, 12, 0];
16853 accumulate_counts_s32_4(&mut buckets, 12, 3, 4);
16854 assert_eq!(&buckets[12..15], &[22, 26, 30]);
16855
16856 let mut many = Vec::new();
16857 for bucket in 0..10 {
16858 many.extend([bucket, bucket + 1, bucket + 2, 0]);
16859 }
16860 accumulate_counts_s32(&mut many, 36, 3, 4, 10);
16861 assert_eq!(&many[36..39], &[45, 55, 65]);
16862
16863 let t = [1, SAINT_MIN | 2, 0];
16864 let mut compacted_buckets = vec![0; 6];
16865 count_compacted_lms_suffixes_32s_2k(&t, t.len() as SaSint, 3, &mut compacted_buckets);
16866 assert_eq!(compacted_buckets, vec![1, 0, 1, 0, 0, 1]);
16867
16868 let unique_sa = [0, 2, 4, 6, 0, -10, 20, -30];
16869 assert_eq!(count_unique_suffixes(&unique_sa, 4, 0, 4), 2);
16870
16871 let s = [10u32, 11, 12, 13];
16872 let mut d = [0u64; 4];
16873 convert_32u_to_64u(&s, &mut d, 1, 2);
16874 assert_eq!(d, [0, 11, 12, 0]);
16875
16876 let mut words = [10u32, 11, 12, 13, 99, 99, 99, 99];
16877 convert_inplace_32u_to_64u(&mut words, 0, 4);
16878 assert_eq!(words, [10, 0, 11, 0, 12, 0, 13, 0]);
16879 convert_inplace_64u_to_32u(&mut words, 0, 4);
16880 assert_eq!(&words[..4], &[10, 11, 12, 13]);
16881
16882 let mut words = [20u32, 21, 22, 23, 99, 99, 99, 99];
16883 convert_inplace_32u_to_64u_omp(&mut words, 4, 2);
16884 assert_eq!(words, [20, 0, 21, 0, 22, 0, 23, 0]);
16885
16886 assert_eq!(get_bucket_stride(20_000, 1000, 4), 1024);
16887 assert_eq!(get_bucket_stride(3024, 1001, 4), 1008);
16888 assert_eq!(get_bucket_stride(3000, 1001, 4), 1001);
16889 }
16890
16891 #[test]
16892 fn libsais16x64_count_gather_lms_suffixes_32s_omp_wrappers_match_c() {
16893 let t = vec![2, 1, 3, 1, 2, 0, 1, 0];
16894 let n = t.len() as SaSint;
16895 let k = 4;
16896 let mut rust_sa = vec![0; t.len()];
16897 let mut c_sa = rust_sa.clone();
16898 let mut rust_buckets = vec![0; 2 * k as usize];
16899 let mut c_buckets = rust_buckets.clone();
16900 let mut rust_state = alloc_thread_state(1).unwrap();
16901 let rust_m = count_and_gather_lms_suffixes_32s_2k_omp(
16902 &t,
16903 &mut rust_sa,
16904 n,
16905 k,
16906 &mut rust_buckets,
16907 0,
16908 1,
16909 &mut rust_state,
16910 );
16911 let c_m = unsafe {
16912 probe_libsais16x64_count_and_gather_lms_suffixes_32s_2k_omp(
16913 t.as_ptr(),
16914 c_sa.as_mut_ptr(),
16915 n,
16916 k,
16917 c_buckets.as_mut_ptr(),
16918 0,
16919 1,
16920 )
16921 };
16922 assert_eq!(rust_m, c_m);
16923 assert_eq!(rust_sa, c_sa);
16924 assert_eq!(rust_buckets, c_buckets);
16925
16926 let compact_t = vec![2, SAINT_MIN | 1, 3, 1, SAINT_MIN | 2, 0, 1, 0];
16927 let mut rust_sa = vec![0; compact_t.len()];
16928 let mut c_sa = rust_sa.clone();
16929 let mut rust_buckets = vec![0; 2 * k as usize];
16930 let mut c_buckets = rust_buckets.clone();
16931 let mut rust_state = alloc_thread_state(1).unwrap();
16932 count_and_gather_compacted_lms_suffixes_32s_2k_omp(
16933 &compact_t,
16934 &mut rust_sa,
16935 n,
16936 k,
16937 &mut rust_buckets,
16938 0,
16939 1,
16940 &mut rust_state,
16941 );
16942 unsafe {
16943 probe_libsais16x64_count_and_gather_compacted_lms_suffixes_32s_2k_omp(
16944 compact_t.as_ptr(),
16945 c_sa.as_mut_ptr(),
16946 n,
16947 k,
16948 c_buckets.as_mut_ptr(),
16949 0,
16950 1,
16951 );
16952 }
16953 assert_eq!(rust_sa, c_sa);
16954 assert_eq!(rust_buckets, c_buckets);
16955 }
16956
16957 #[test]
16958 fn libsais16x64_count_gather_lms_suffixes_32s_4k_match_c() {
16959 let t = vec![2, 1, 3, 1, 2, 0, 1, 0];
16960 let n = t.len() as SaSint;
16961 let k = 4;
16962
16963 let mut rust_buckets = vec![77; 4 * k as usize];
16964 let mut c_buckets = vec![0; 4 * k as usize];
16965 let mut c_sa_for_count = vec![0; t.len()];
16966 count_lms_suffixes_32s_4k(&t, n, k, &mut rust_buckets);
16967 unsafe {
16968 probe_libsais16x64_count_and_gather_lms_suffixes_32s_4k(
16969 t.as_ptr(),
16970 c_sa_for_count.as_mut_ptr(),
16971 n,
16972 k,
16973 c_buckets.as_mut_ptr(),
16974 0,
16975 n,
16976 );
16977 }
16978 assert_eq!(rust_buckets, c_buckets);
16979
16980 let mut rust_sa = vec![0; t.len()];
16981 let mut c_sa = rust_sa.clone();
16982 let mut rust_buckets = vec![0; 4 * k as usize];
16983 let mut c_buckets = rust_buckets.clone();
16984 let rust_m = count_and_gather_lms_suffixes_32s_4k(
16985 &t,
16986 &mut rust_sa,
16987 n,
16988 k,
16989 &mut rust_buckets,
16990 0,
16991 n as isize,
16992 );
16993 let c_m = unsafe {
16994 probe_libsais16x64_count_and_gather_lms_suffixes_32s_4k(
16995 t.as_ptr(),
16996 c_sa.as_mut_ptr(),
16997 n,
16998 k,
16999 c_buckets.as_mut_ptr(),
17000 0,
17001 n,
17002 )
17003 };
17004 assert_eq!(rust_m, c_m);
17005 assert_eq!(rust_sa, c_sa);
17006 assert_eq!(rust_buckets, c_buckets);
17007
17008 let mut rust_sa = vec![0; t.len()];
17009 let mut c_sa = rust_sa.clone();
17010 let mut rust_buckets = vec![0; 4 * k as usize];
17011 let mut c_buckets = rust_buckets.clone();
17012 let mut rust_state = alloc_thread_state(1).unwrap();
17013 let rust_m = count_and_gather_lms_suffixes_32s_4k_omp(
17014 &t,
17015 &mut rust_sa,
17016 n,
17017 k,
17018 &mut rust_buckets,
17019 0,
17020 1,
17021 &mut rust_state,
17022 );
17023 let c_m = unsafe {
17024 probe_libsais16x64_count_and_gather_lms_suffixes_32s_4k_omp(
17025 t.as_ptr(),
17026 c_sa.as_mut_ptr(),
17027 n,
17028 k,
17029 c_buckets.as_mut_ptr(),
17030 0,
17031 1,
17032 )
17033 };
17034 assert_eq!(rust_m, c_m);
17035 assert_eq!(rust_sa, c_sa);
17036 assert_eq!(rust_buckets, c_buckets);
17037
17038 let mut rust_buckets = vec![91; k as usize];
17039 let mut c_buckets = rust_buckets.clone();
17040 count_suffixes_32s(&t, n, k, &mut rust_buckets);
17041 unsafe {
17042 probe_libsais16x64_count_suffixes_32s(t.as_ptr(), n, k, c_buckets.as_mut_ptr());
17043 }
17044 assert_eq!(rust_buckets, c_buckets);
17045 }
17046
17047 #[test]
17048 fn libsais16x64_initialize_buckets_32s_match_c() {
17049 let k = 4;
17050
17051 let base_6k = vec![
17052 1, 2, 0, 1, 0, 1, 2, 0, 3, 0, 1, 1, 2, 1, 0, 0, 9, 9, 9, 9, 8, 8, 8, 8,
17053 ];
17054 let mut rust = base_6k.clone();
17055 let mut c = base_6k.clone();
17056 initialize_buckets_start_and_end_32s_6k(k, &mut rust);
17057 unsafe { probe_libsais16x64_initialize_buckets_start_and_end_32s_6k(k, c.as_mut_ptr()) };
17058 assert_eq!(rust, c);
17059
17060 let base_4k = vec![1, 2, 0, 1, 3, 0, 2, 1, 9, 9, 9, 9, 8, 8, 8, 8];
17061 let mut rust = base_4k.clone();
17062 let mut c = base_4k.clone();
17063 initialize_buckets_start_and_end_32s_4k(k, &mut rust);
17064 unsafe { probe_libsais16x64_initialize_buckets_start_and_end_32s_4k(k, c.as_mut_ptr()) };
17065 assert_eq!(rust, c);
17066
17067 let base_2k = vec![1, 2, 0, 1, 3, 0, 2, 1];
17068 let mut rust = base_2k.clone();
17069 let mut c = base_2k.clone();
17070 initialize_buckets_end_32s_2k(k, &mut rust);
17071 unsafe { probe_libsais16x64_initialize_buckets_end_32s_2k(k, c.as_mut_ptr()) };
17072 assert_eq!(rust, c);
17073
17074 let mut rust = base_2k.clone();
17075 let mut c = base_2k.clone();
17076 initialize_buckets_start_and_end_32s_2k(k, &mut rust);
17077 unsafe { probe_libsais16x64_initialize_buckets_start_and_end_32s_2k(k, c.as_mut_ptr()) };
17078 assert_eq!(rust, c);
17079
17080 let base_1k = vec![2, 1, 3, 2];
17081 let mut rust = base_1k.clone();
17082 let mut c = base_1k.clone();
17083 initialize_buckets_start_32s_1k(k, &mut rust);
17084 unsafe { probe_libsais16x64_initialize_buckets_start_32s_1k(k, c.as_mut_ptr()) };
17085 assert_eq!(rust, c);
17086
17087 let mut rust = base_1k.clone();
17088 let mut c = base_1k.clone();
17089 initialize_buckets_end_32s_1k(k, &mut rust);
17090 unsafe { probe_libsais16x64_initialize_buckets_end_32s_1k(k, c.as_mut_ptr()) };
17091 assert_eq!(rust, c);
17092
17093 let t = vec![2, 1, 3, 1, 2, 0, 1, 0];
17094 let mut rust = vec![1, 2, 0, 1, 3, 0, 2, 1];
17095 let mut c = rust.clone();
17096 initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(&t, k, &mut rust, 4);
17097 unsafe {
17098 probe_libsais16x64_initialize_buckets_for_lms_suffixes_radix_sort_32s_2k(
17099 t.as_ptr(),
17100 k,
17101 c.as_mut_ptr(),
17102 4,
17103 );
17104 }
17105 assert_eq!(rust, c);
17106
17107 let mut rust = vec![
17108 1, 2, 0, 1, 3, 0, 2, 1, 1, 0, 2, 0, 0, 1, 1, 0, 9, 9, 9, 9, 8, 8, 8, 8,
17109 ];
17110 let mut c = rust.clone();
17111 let rust_sum = initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(&t, k, &mut rust, 4);
17112 let c_sum = unsafe {
17113 probe_libsais16x64_initialize_buckets_for_lms_suffixes_radix_sort_32s_6k(
17114 t.as_ptr(),
17115 k,
17116 c.as_mut_ptr(),
17117 4,
17118 )
17119 };
17120 assert_eq!(rust_sum, c_sum);
17121 assert_eq!(rust, c);
17122
17123 let mut rust = base_4k.clone();
17124 let mut c = base_4k;
17125 initialize_buckets_for_radix_and_partial_sorting_32s_4k(&t, k, &mut rust, 4);
17126 unsafe {
17127 probe_libsais16x64_initialize_buckets_for_radix_and_partial_sorting_32s_4k(
17128 t.as_ptr(),
17129 k,
17130 c.as_mut_ptr(),
17131 4,
17132 );
17133 }
17134 assert_eq!(rust, c);
17135 }
17136
17137 #[test]
17138 fn libsais16x64_place_lms_suffixes_interval_32s_match_c() {
17139 let n = 12;
17140 let k = 4;
17141 let m = 4;
17142
17143 let mut rust_sa = vec![101, 102, 103, 104, 9, 9, 9, 9, 9, 9, 9, 9];
17144 let mut c_sa = rust_sa.clone();
17145 let mut buckets = vec![0; 4 * k as usize];
17146 buckets[buckets_index2(0, 1)] = 2;
17147 buckets[buckets_index2(1, 1)] = 2;
17148 buckets[buckets_index2(2, 1)] = 3;
17149 buckets[buckets_index2(2, 1) + buckets_index2(1, 0)] = 4;
17150 buckets[3 * k as usize + 1] = 7;
17151 buckets[3 * k as usize + 2] = 10;
17152 place_lms_suffixes_interval_32s_4k(&mut rust_sa, n, k, m, &buckets);
17153 unsafe {
17154 probe_libsais16x64_place_lms_suffixes_interval_32s_4k(
17155 c_sa.as_mut_ptr(),
17156 n,
17157 k,
17158 m,
17159 buckets.as_ptr(),
17160 );
17161 }
17162 assert_eq!(rust_sa, c_sa);
17163
17164 let mut rust_sa = vec![101, 102, 103, 104, 9, 9, 9, 9, 9, 9, 9, 9];
17165 let mut c_sa = rust_sa.clone();
17166 let mut buckets = vec![0; 2 * k as usize];
17167 buckets[buckets_index2(1, 0)] = 7;
17168 buckets[buckets_index2(0, 1)] = 1;
17169 buckets[buckets_index2(1, 1)] = 1;
17170 buckets[buckets_index2(2, 0)] = 10;
17171 buckets[buckets_index2(2, 1)] = 2;
17172 buckets[buckets_index2(3, 1)] = 3;
17173 place_lms_suffixes_interval_32s_2k(&mut rust_sa, n, k, m, &buckets);
17174 unsafe {
17175 probe_libsais16x64_place_lms_suffixes_interval_32s_2k(
17176 c_sa.as_mut_ptr(),
17177 n,
17178 k,
17179 m,
17180 buckets.as_ptr(),
17181 );
17182 }
17183 assert_eq!(rust_sa, c_sa);
17184
17185 let t = vec![0, 1, 2, 1, 2, 3, 1, 3, 0, 0, 0, 0];
17186 let mut rust_sa = vec![1, 3, 4, 7, 9, 9, 9, 9, 9, 9, 9, 9];
17187 let mut c_sa = rust_sa.clone();
17188 let rust_buckets = vec![0, 3, 6, 10];
17189 let mut c_buckets = rust_buckets.clone();
17190 place_lms_suffixes_interval_32s_1k(&t, &mut rust_sa, k, m, &rust_buckets);
17191 unsafe {
17192 probe_libsais16x64_place_lms_suffixes_interval_32s_1k(
17193 t.as_ptr(),
17194 c_sa.as_mut_ptr(),
17195 k,
17196 m,
17197 c_buckets.as_mut_ptr(),
17198 );
17199 }
17200 assert_eq!(rust_sa, c_sa);
17201 assert_eq!(rust_buckets, c_buckets);
17202 }
17203
17204 #[test]
17205 fn libsais16x64_renumber_and_mark_distinct_lms_suffixes_32s_1k_matches_c() {
17206 let rust_t = vec![2, 1, 3, 1, 2, 0, 1, 0];
17207 let n = rust_t.len() as SaSint;
17208 let mut probe_sa = vec![0; rust_t.len()];
17209 let m = gather_lms_suffixes_32s(&rust_t, &mut probe_sa, n);
17210 let mut rust_sa = vec![0; rust_t.len()];
17211 let mut c_t = rust_t.clone();
17212 let mut c_sa = rust_sa.clone();
17213
17214 let rust_name =
17215 renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(&rust_t, &mut rust_sa, n, m, 1);
17216 let c_name = unsafe {
17217 probe_libsais16x64_renumber_and_mark_distinct_lms_suffixes_32s_1k_omp(
17218 c_t.as_mut_ptr(),
17219 c_sa.as_mut_ptr(),
17220 n,
17221 m,
17222 1,
17223 )
17224 };
17225 assert_eq!(rust_name, c_name);
17226 assert_eq!(rust_t, c_t);
17227 assert_eq!(rust_sa, c_sa);
17228 }
17229
17230 #[test]
17231 fn libsais16x64_reconstruct_compacted_lms_suffixes_32s_match_c() {
17232 let n = 8;
17233 let k = 4;
17234 let fs = 0;
17235 let f = 0;
17236 let mut m_probe_sa = vec![0; n as usize];
17237 let m = gather_lms_suffixes_32s(&[2, 1, 3, 1, 2, 0, 1, 0], &mut m_probe_sa, n);
17238
17239 let mut rust_t = vec![2, 1, 3, 1, 2, 0, 1, 0];
17240 let mut c_t = rust_t.clone();
17241 let mut rust_sa = vec![0; n as usize];
17242 let mut c_sa = rust_sa.clone();
17243 let mut rust_buckets = vec![0; 2 * k as usize];
17244 let mut c_buckets = rust_buckets.clone();
17245 let mut rust_thread_state = alloc_thread_state(1).unwrap();
17246 reconstruct_compacted_lms_suffixes_32s_2k_omp(
17247 &mut rust_t,
17248 &mut rust_sa,
17249 n,
17250 k,
17251 m,
17252 fs,
17253 f,
17254 &mut rust_buckets,
17255 0,
17256 1,
17257 &mut rust_thread_state,
17258 );
17259 unsafe {
17260 probe_libsais16x64_reconstruct_compacted_lms_suffixes_32s_2k_omp(
17261 c_t.as_mut_ptr(),
17262 c_sa.as_mut_ptr(),
17263 n,
17264 k,
17265 m,
17266 fs,
17267 f,
17268 c_buckets.as_mut_ptr(),
17269 0,
17270 1,
17271 );
17272 }
17273 assert_eq!(rust_t, c_t);
17274 assert_eq!(rust_sa, c_sa);
17275 assert_eq!(rust_buckets, c_buckets);
17276
17277 let mut rust_t = vec![2, 1, 3, 1, 2, 0, 1, 0];
17278 let mut c_t = rust_t.clone();
17279 let mut rust_sa = vec![0; n as usize];
17280 let mut c_sa = rust_sa.clone();
17281 reconstruct_compacted_lms_suffixes_32s_1k_omp(&mut rust_t, &mut rust_sa, n, m, fs, f, 1);
17282 unsafe {
17283 probe_libsais16x64_reconstruct_compacted_lms_suffixes_32s_1k_omp(
17284 c_t.as_mut_ptr(),
17285 c_sa.as_mut_ptr(),
17286 n,
17287 m,
17288 fs,
17289 f,
17290 1,
17291 );
17292 }
17293 assert_eq!(rust_t, c_t);
17294 assert_eq!(rust_sa, c_sa);
17295 }
17296
17297 #[test]
17298 fn libsais16x64_partial_omp_wrappers_match_c() {
17299 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
17300 let mut c_sa = rust_sa.clone();
17301 let mut c_buckets = rust_buckets.clone();
17302
17303 let rust_d = partial_sorting_scan_left_to_right_16u_omp(
17304 &text,
17305 &mut rust_sa,
17306 text.len() as SaSint,
17307 8,
17308 &mut rust_buckets,
17309 5,
17310 3,
17311 1,
17312 );
17313 let c_d = unsafe {
17314 probe_libsais16x64_partial_sorting_scan_left_to_right_16u_omp(
17315 text.as_ptr(),
17316 c_sa.as_mut_ptr(),
17317 text.len() as SaSint,
17318 8,
17319 c_buckets.as_mut_ptr(),
17320 5,
17321 3,
17322 1,
17323 )
17324 };
17325 assert_eq!(rust_d, c_d);
17326 assert_eq!(rust_sa, c_sa);
17327 assert_eq!(rust_buckets, c_buckets);
17328
17329 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
17330 rust_sa[6..10].copy_from_slice(&[3, 5 | SAINT_MIN, 7, 9 | SAINT_MIN]);
17331 let mut c_sa = rust_sa.clone();
17332 let mut c_buckets = rust_buckets.clone();
17333 partial_sorting_scan_right_to_left_16u_omp(
17334 &text,
17335 &mut rust_sa,
17336 text.len() as SaSint,
17337 8,
17338 &mut rust_buckets,
17339 0,
17340 5,
17341 3,
17342 1,
17343 );
17344 unsafe {
17345 probe_libsais16x64_partial_sorting_scan_right_to_left_16u_omp(
17346 text.as_ptr(),
17347 c_sa.as_mut_ptr(),
17348 text.len() as SaSint,
17349 8,
17350 c_buckets.as_mut_ptr(),
17351 0,
17352 5,
17353 3,
17354 1,
17355 );
17356 }
17357 assert_eq!(rust_sa, c_sa);
17358 assert_eq!(rust_buckets, c_buckets);
17359
17360 let (text, mut rust_sa, mut rust_buckets) = partial_scan_fixture();
17361 rust_sa[6..10].copy_from_slice(&[3, 5 | SAINT_MIN, 7, 9 | SAINT_MIN]);
17362 let mut c_sa = rust_sa.clone();
17363 let mut c_buckets = rust_buckets.clone();
17364 partial_gsa_scan_right_to_left_16u_omp(
17365 &text,
17366 &mut rust_sa,
17367 text.len() as SaSint,
17368 8,
17369 &mut rust_buckets,
17370 0,
17371 5,
17372 3,
17373 1,
17374 );
17375 unsafe {
17376 probe_libsais16x64_partial_gsa_scan_right_to_left_16u_omp(
17377 text.as_ptr(),
17378 c_sa.as_mut_ptr(),
17379 text.len() as SaSint,
17380 8,
17381 c_buckets.as_mut_ptr(),
17382 0,
17383 5,
17384 3,
17385 1,
17386 );
17387 }
17388 assert_eq!(rust_sa, c_sa);
17389 assert_eq!(rust_buckets, c_buckets);
17390 }
17391
17392 #[test]
17393 fn libsais16x64_final_omp_wrappers_match_c() {
17394 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17395 let mut c_sa = rust_sa.clone();
17396 let mut c_bucket = rust_bucket.clone();
17397 final_bwt_scan_left_to_right_16u_omp(
17398 &text,
17399 &mut rust_sa,
17400 text.len() as SaSint,
17401 8,
17402 &mut rust_bucket,
17403 1,
17404 );
17405 unsafe {
17406 probe_libsais16x64_final_bwt_scan_left_to_right_16u_omp(
17407 text.as_ptr(),
17408 c_sa.as_mut_ptr(),
17409 text.len() as SaSint,
17410 8,
17411 c_bucket.as_mut_ptr(),
17412 1,
17413 );
17414 }
17415 assert_eq!(rust_sa, c_sa);
17416 assert_eq!(rust_bucket, c_bucket);
17417
17418 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17419 let mut c_sa = rust_sa.clone();
17420 let mut c_bucket = rust_bucket.clone();
17421 let mut rust_i = vec![-1; 8];
17422 let mut c_i = rust_i.clone();
17423 final_bwt_aux_scan_left_to_right_16u_omp(
17424 &text,
17425 &mut rust_sa,
17426 text.len() as SaSint,
17427 8,
17428 1,
17429 &mut rust_i,
17430 &mut rust_bucket,
17431 1,
17432 );
17433 unsafe {
17434 probe_libsais16x64_final_bwt_aux_scan_left_to_right_16u_omp(
17435 text.as_ptr(),
17436 c_sa.as_mut_ptr(),
17437 text.len() as SaSint,
17438 8,
17439 1,
17440 c_i.as_mut_ptr(),
17441 c_bucket.as_mut_ptr(),
17442 1,
17443 );
17444 }
17445 assert_eq!(rust_sa, c_sa);
17446 assert_eq!(rust_bucket, c_bucket);
17447 assert_eq!(rust_i, c_i);
17448
17449 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17450 let mut c_sa = rust_sa.clone();
17451 let mut c_bucket = rust_bucket.clone();
17452 final_sorting_scan_left_to_right_16u_omp(
17453 &text,
17454 &mut rust_sa,
17455 text.len() as SaSint,
17456 8,
17457 &mut rust_bucket,
17458 1,
17459 );
17460 unsafe {
17461 probe_libsais16x64_final_sorting_scan_left_to_right_16u_omp(
17462 text.as_ptr(),
17463 c_sa.as_mut_ptr(),
17464 text.len() as SaSint,
17465 8,
17466 c_bucket.as_mut_ptr(),
17467 1,
17468 );
17469 }
17470 assert_eq!(rust_sa, c_sa);
17471 assert_eq!(rust_bucket, c_bucket);
17472
17473 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17474 let mut c_sa = rust_sa.clone();
17475 let mut c_bucket = rust_bucket.clone();
17476 let rust_index = final_bwt_scan_right_to_left_16u_omp(
17477 &text,
17478 &mut rust_sa,
17479 text.len() as SaSint,
17480 8,
17481 &mut rust_bucket,
17482 1,
17483 );
17484 let c_index = unsafe {
17485 probe_libsais16x64_final_bwt_scan_right_to_left_16u_omp(
17486 text.as_ptr(),
17487 c_sa.as_mut_ptr(),
17488 text.len() as SaSint,
17489 8,
17490 c_bucket.as_mut_ptr(),
17491 1,
17492 )
17493 };
17494 assert_eq!(rust_index, c_index);
17495 assert_eq!(rust_sa, c_sa);
17496 assert_eq!(rust_bucket, c_bucket);
17497
17498 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17499 let mut c_sa = rust_sa.clone();
17500 let mut c_bucket = rust_bucket.clone();
17501 let mut rust_i = vec![-1; 8];
17502 let mut c_i = rust_i.clone();
17503 final_bwt_aux_scan_right_to_left_16u_omp(
17504 &text,
17505 &mut rust_sa,
17506 text.len() as SaSint,
17507 8,
17508 1,
17509 &mut rust_i,
17510 &mut rust_bucket,
17511 1,
17512 );
17513 unsafe {
17514 probe_libsais16x64_final_bwt_aux_scan_right_to_left_16u_omp(
17515 text.as_ptr(),
17516 c_sa.as_mut_ptr(),
17517 text.len() as SaSint,
17518 8,
17519 1,
17520 c_i.as_mut_ptr(),
17521 c_bucket.as_mut_ptr(),
17522 1,
17523 );
17524 }
17525 assert_eq!(rust_sa, c_sa);
17526 assert_eq!(rust_bucket, c_bucket);
17527 assert_eq!(rust_i, c_i);
17528
17529 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17530 let mut c_sa = rust_sa.clone();
17531 let mut c_bucket = rust_bucket.clone();
17532 final_sorting_scan_right_to_left_16u_omp(&text, &mut rust_sa, 0, 6, 8, &mut rust_bucket, 1);
17533 unsafe {
17534 probe_libsais16x64_final_sorting_scan_right_to_left_16u_omp(
17535 text.as_ptr(),
17536 c_sa.as_mut_ptr(),
17537 0,
17538 6,
17539 8,
17540 c_bucket.as_mut_ptr(),
17541 1,
17542 );
17543 }
17544 assert_eq!(rust_sa, c_sa);
17545 assert_eq!(rust_bucket, c_bucket);
17546
17547 let (text, mut rust_sa, mut rust_bucket) = final_scan_fixture();
17548 let mut c_sa = rust_sa.clone();
17549 let mut c_bucket = rust_bucket.clone();
17550 final_gsa_scan_right_to_left_16u_omp(&text, &mut rust_sa, 0, 6, 8, &mut rust_bucket, 1);
17551 unsafe {
17552 probe_libsais16x64_final_gsa_scan_right_to_left_16u_omp(
17553 text.as_ptr(),
17554 c_sa.as_mut_ptr(),
17555 0,
17556 6,
17557 8,
17558 c_bucket.as_mut_ptr(),
17559 1,
17560 );
17561 }
17562 assert_eq!(rust_sa, c_sa);
17563 assert_eq!(rust_bucket, c_bucket);
17564 }
17565
17566 #[test]
17567 fn libsais16x64_matches_bruteforce() {
17568 let t = [3, 1, 4, 1, 5, 9, 0, 2];
17569 let mut sa = vec![0; t.len()];
17570 let mut freq = vec![0; ALPHABET_SIZE];
17571 assert_eq!(libsais16x64(&t, &mut sa, 0, Some(&mut freq)), 0);
17572 assert_eq!(sa, brute_sa(&t));
17573 assert_eq!(freq[1], 2);
17574 assert_eq!(freq[9], 1);
17575 }
17576
17577 #[test]
17578 fn libsais16x64_bwt_round_trips() {
17579 let t = [2, 1, 3, 1, 2, 4, 1, 0];
17580 let mut bwt = vec![0; t.len()];
17581 let mut work = vec![0; t.len()];
17582 let primary = libsais16x64_bwt(&t, &mut bwt, &mut work, 0, None);
17583 assert!(primary > 0);
17584
17585 let mut restored = vec![0; t.len()];
17586 assert_eq!(
17587 libsais16x64_unbwt(&bwt, &mut restored, &mut work, None, primary),
17588 0
17589 );
17590 assert_eq!(restored, t);
17591 }
17592
17593 #[test]
17594 fn libsais16x64_plcp_lcp_are_consistent() {
17595 let t = [2, 1, 2, 1, 0];
17596 let sa = brute_sa(&t);
17597 let mut plcp = vec![0; t.len()];
17598 let mut lcp = vec![0; t.len()];
17599 assert_eq!(libsais16x64_plcp(&t, &sa, &mut plcp), 0);
17600 assert_eq!(libsais16x64_lcp(&plcp, &sa, &mut lcp), 0);
17601 assert_eq!(lcp[0], 0);
17602
17603 let mut named_plcp = vec![0; t.len()];
17604 assert_eq!(
17605 compute_phi_omp(&sa, &mut named_plcp, t.len() as SaSint, 1),
17606 0
17607 );
17608 assert_eq!(
17609 compute_plcp_omp(&t, &mut named_plcp, t.len() as SaSint, 1),
17610 0
17611 );
17612 assert_eq!(named_plcp, plcp);
17613
17614 let mut named_lcp = vec![0; t.len()];
17615 assert_eq!(
17616 compute_lcp_omp(&named_plcp, &sa, &mut named_lcp, t.len() as SaSint, 1),
17617 0
17618 );
17619 assert_eq!(named_lcp, lcp);
17620
17621 let mut gsa_plcp = vec![0; t.len()];
17622 let mut named_gsa_plcp = vec![0; t.len()];
17623 assert_eq!(libsais16x64_plcp_gsa(&t, &sa, &mut gsa_plcp), 0);
17624 assert_eq!(
17625 compute_phi_omp(&sa, &mut named_gsa_plcp, t.len() as SaSint, 1),
17626 0
17627 );
17628 assert_eq!(
17629 compute_plcp_gsa_omp(&t, &mut named_gsa_plcp, t.len() as SaSint, 1),
17630 0
17631 );
17632 assert_eq!(named_gsa_plcp, gsa_plcp);
17633 }
17634
17635 #[test]
17636 fn libsais16x64_bwt_copy_16u_omp_uses_block_partition_for_large_inputs() {
17637 let n = 65_600usize;
17638 let a: Vec<SaSint> = (0..n).map(|i| (i * 17) as SaSint).collect();
17639 let mut threaded = vec![0; n];
17640 let mut sequential = vec![0; n];
17641
17642 bwt_copy_16u_omp(&mut threaded, &a, n as SaSint, 4);
17643 bwt_copy_16u(&mut sequential, &a, n as SaSint);
17644
17645 assert_eq!(threaded, sequential);
17646 }
17647
17648 #[test]
17649 fn libsais16x64_plcp_lcp_omp_wrappers_match_single_thread_on_large_inputs() {
17650 let n = 65_600usize;
17651 let text: Vec<u16> = (0..n).map(|i| 1 + (i % 251) as u16).collect();
17652 let sa: Vec<SaSint> = (0..n as SaSint).collect();
17653
17654 let mut plcp_single = vec![0; n];
17655 let mut plcp_threaded = vec![0; n];
17656 assert_eq!(compute_phi_omp(&sa, &mut plcp_single, n as SaSint, 1), 0);
17657 assert_eq!(compute_phi_omp(&sa, &mut plcp_threaded, n as SaSint, 4), 0);
17658 assert_eq!(plcp_threaded, plcp_single);
17659
17660 assert_eq!(compute_plcp_omp(&text, &mut plcp_single, n as SaSint, 1), 0);
17661 assert_eq!(
17662 compute_plcp_omp(&text, &mut plcp_threaded, n as SaSint, 4),
17663 0
17664 );
17665 assert_eq!(plcp_threaded, plcp_single);
17666
17667 let mut lcp_single = vec![0; n];
17668 let mut lcp_threaded = vec![0; n];
17669 assert_eq!(
17670 compute_lcp_omp(&plcp_single, &sa, &mut lcp_single, n as SaSint, 1),
17671 0
17672 );
17673 assert_eq!(
17674 compute_lcp_omp(&plcp_threaded, &sa, &mut lcp_threaded, n as SaSint, 4),
17675 0
17676 );
17677 assert_eq!(lcp_threaded, lcp_single);
17678 }
17679
17680 #[test]
17681 fn libsais16x64_context_allocates_upstream_shaped_buffers() {
17682 let ctx = create_ctx().unwrap();
17683 assert_eq!(ctx.threads, 1);
17684 assert_eq!(ctx.buckets.len(), 8 * ALPHABET_SIZE);
17685 assert!(ctx.thread_state.is_none());
17686
17687 let ctx = create_ctx_omp(2).unwrap();
17688 assert_eq!(ctx.threads, 2);
17689 assert_eq!(ctx.buckets.len(), 8 * ALPHABET_SIZE);
17690 let thread_state = ctx.thread_state.as_ref().unwrap();
17691 assert_eq!(thread_state.len(), 2);
17692 assert_eq!(thread_state[0].buckets.len(), 4 * ALPHABET_SIZE);
17693 assert_eq!(thread_state[0].cache_entries, PER_THREAD_CACHE_SIZE);
17694
17695 let ctx = create_ctx_omp(0).unwrap();
17696 assert_eq!(ctx.threads, 1);
17697 assert!(ctx.thread_state.is_none());
17698 }
17699
17700 #[test]
17701 fn libsais16x64_unbwt_context_allocates_upstream_shaped_buffers() {
17702 let ctx = unbwt_create_ctx().unwrap();
17703 assert_eq!(ctx.threads, 1);
17704 assert_eq!(ctx.bucket2.len(), ALPHABET_SIZE);
17705 assert_eq!(ctx.fastbits.len(), 1 + (1 << UNBWT_FASTBITS));
17706 assert!(ctx.buckets.is_none());
17707
17708 let ctx = unbwt_create_ctx_omp(3).unwrap();
17709 assert_eq!(ctx.threads, 3);
17710 assert_eq!(ctx.bucket2.len(), ALPHABET_SIZE);
17711 assert_eq!(ctx.fastbits.len(), 1 + (1 << UNBWT_FASTBITS));
17712 assert_eq!(ctx.buckets.as_ref().unwrap().len(), 3 * ALPHABET_SIZE);
17713 }
17714
17715 #[test]
17716 fn libsais16x64_named_unbwt_helpers_follow_decode_shapes() {
17717 let t = [0, 1, 2];
17718 let mut p = vec![usize::MAX; 4];
17719 let mut bucket2 = vec![0; ALPHABET_SIZE];
17720 bucket2[0] = 1;
17721 bucket2[1] = 2;
17722 bucket2[2] = 3;
17723 unbwt_calculate_P(&t, &mut p, &mut bucket2, 2, 1, 3);
17724 assert_eq!(p[2], 1);
17725 assert_eq!(p[3], 3);
17726
17727 let p = [1usize, 2, 0];
17728 let mut bucket2 = vec![3; ALPHABET_SIZE];
17729 bucket2[0] = 1;
17730 bucket2[1] = 2;
17731 bucket2[2] = 3;
17732 let fastbits = vec![0; 3];
17733
17734 let mut u = vec![99; 3];
17735 let mut i0 = 0;
17736 unbwt_decode_1(&mut u, &p, &bucket2, &fastbits, 0, &mut i0, 3);
17737 assert_eq!(u, vec![0, 1, 2]);
17738 assert_eq!(i0, 0);
17739
17740 let mut u = vec![99; 6];
17741 let (mut i0, mut i1) = (0, 1);
17742 unbwt_decode_2(&mut u, &p, &bucket2, &fastbits, 0, 3, &mut i0, &mut i1, 2);
17743 assert_eq!(&u[..2], &[0, 1]);
17744 assert_eq!(&u[3..5], &[1, 2]);
17745 assert_eq!((i0, i1), (2, 0));
17746
17747 let mut u = vec![99; 8];
17748 let mut cursors = [0; 8];
17749 unbwt_decode_8(&mut u, &p, &bucket2, &fastbits, 0, 1, &mut cursors, 1);
17750 assert_eq!(u, vec![0; 8]);
17751 assert_eq!(cursors, [1; 8]);
17752 }
17753
17754 #[test]
17755 fn libsais16x64_unbwt_init_parallel_uses_block_partition() {
17756 let n = 70_003usize;
17757 let t: Vec<u16> = (0..n)
17758 .map(|i| ((i.wrapping_mul(37).wrapping_add(i >> 3)) % 251) as u16)
17759 .collect();
17760 let i = [12_345];
17761
17762 let mut single_p = vec![0; n + 1];
17763 let mut threaded_p = vec![0; n + 1];
17764 let mut single_bucket2 = vec![0; ALPHABET_SIZE];
17765 let mut threaded_bucket2 = vec![0; ALPHABET_SIZE];
17766 let mut single_fastbits = vec![0; 1 + (1 << UNBWT_FASTBITS)];
17767 let mut threaded_fastbits = vec![0; 1 + (1 << UNBWT_FASTBITS)];
17768 let mut buckets = vec![0; 4 * ALPHABET_SIZE];
17769
17770 unbwt_init_single(
17771 &t,
17772 &mut single_p,
17773 None,
17774 &i,
17775 &mut single_bucket2,
17776 &mut single_fastbits,
17777 );
17778 unbwt_init_parallel(
17779 &t,
17780 &mut threaded_p,
17781 None,
17782 &i,
17783 &mut threaded_bucket2,
17784 &mut threaded_fastbits,
17785 &mut buckets,
17786 4,
17787 );
17788
17789 assert_eq!(threaded_p, single_p);
17790 assert_eq!(threaded_bucket2, single_bucket2);
17791 assert_eq!(threaded_fastbits, single_fastbits);
17792 }
17793
17794 fn assert_libsais16x64_matches_c(text: &[u16]) {
17795 let mut rust_sa = vec![0; text.len()];
17796 let mut c_sa = vec![0; text.len()];
17797
17798 let rust_rc = libsais16x64(text, &mut rust_sa, 0, None);
17799 let c_rc = unsafe {
17800 probe_public_libsais16x64(text.as_ptr(), c_sa.as_mut_ptr(), text.len() as SaSint, 0)
17801 };
17802
17803 assert_eq!(rust_rc, c_rc);
17804 assert_eq!(rust_sa, c_sa);
17805 }
17806
17807 fn assert_libsais16x64_gsa_matches_c(text: &[u16]) {
17808 let mut rust_sa = vec![0; text.len()];
17809 let mut c_sa = vec![0; text.len()];
17810
17811 let rust_rc = libsais16x64_gsa(text, &mut rust_sa, 0, None);
17812 let c_rc = unsafe {
17813 probe_public_libsais16x64_gsa(text.as_ptr(), c_sa.as_mut_ptr(), text.len() as SaSint, 0)
17814 };
17815
17816 assert_eq!(rust_rc, c_rc);
17817 assert_eq!(rust_sa, c_sa);
17818 }
17819
17820 fn assert_libsais16x64_long_matches_c_with_fs(text: &[SaSint], k: SaSint, fs: SaSint) {
17821 let mut rust_t = text.to_vec();
17822 let mut c_t = text.to_vec();
17823 let mut rust_sa = vec![0; text.len() + fs as usize];
17824 let mut c_sa = vec![0; text.len() + fs as usize];
17825
17826 let rust_rc = libsais16x64_long(&mut rust_t, &mut rust_sa, k, fs);
17827 let c_rc = unsafe {
17828 probe_public_libsais16x64_long(
17829 c_t.as_mut_ptr(),
17830 c_sa.as_mut_ptr(),
17831 c_t.len() as SaSint,
17832 k,
17833 fs,
17834 )
17835 };
17836
17837 assert_eq!(rust_rc, c_rc);
17838 assert_eq!(rust_t, c_t);
17839 assert_eq!(rust_sa, c_sa);
17840 }
17841
17842 fn assert_libsais16x64_long_matches_c(text: &[SaSint], k: SaSint) {
17843 assert_libsais16x64_long_matches_c_with_fs(text, k, 0);
17844 }
17845
17846 fn make_main_32s_stress_text(len: usize, alphabet: SaSint) -> Vec<SaSint> {
17847 let mut state: u32 = 0x1357_9bdf;
17848 let mut t = Vec::with_capacity(len + 1);
17849
17850 for i in 0..len {
17851 state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
17852 let mut value = ((state >> 16) % (alphabet as u32 - 1)) as SaSint + 1;
17853 if i % 17 < 8 {
17854 value = ((i / 17) as SaSint % 11) + 1;
17855 }
17856 if i % 29 < 10 {
17857 value = (((i / 29) as SaSint * 3) % 19) + 1;
17858 }
17859 if i % 64 >= 48 {
17860 value = t[i - 48];
17861 }
17862 t.push(value);
17863 }
17864
17865 t.push(0);
17866 t
17867 }
17868
17869 fn make_recursive_main_32s_text(repeats: usize) -> Vec<SaSint> {
17870 let motif = [9, 4, 9, 2, 9, 4, 9, 1];
17871 let mut t = Vec::with_capacity(repeats * motif.len() + 1);
17872 for _ in 0..repeats {
17873 t.extend_from_slice(&motif);
17874 }
17875 t.push(0);
17876 t
17877 }
17878
17879 fn assert_main_32s_entry_matches_c(mut t: Vec<SaSint>, k: SaSint, fs: SaSint) {
17880 let n = t.len() as SaSint;
17881 let threads = 1;
17882 let mut sa = vec![0; t.len() + fs as usize];
17883 let initial_t = t.clone();
17884 let initial_sa = sa.clone();
17885
17886 let c_result = unsafe {
17887 probe_libsais16x64_main_32s_entry(t.as_mut_ptr(), sa.as_mut_ptr(), n, k, fs, threads)
17888 };
17889 let c_t = t.clone();
17890 let c_sa = sa.clone();
17891
17892 t.copy_from_slice(&initial_t);
17893 sa.copy_from_slice(&initial_sa);
17894
17895 let mut thread_state = alloc_thread_state(threads).unwrap();
17896 let rust_result = main_32s_entry(
17897 t.as_mut_ptr(),
17898 &mut sa,
17899 n,
17900 k,
17901 fs,
17902 threads,
17903 &mut thread_state,
17904 );
17905
17906 assert_eq!(rust_result, c_result);
17907 assert_eq!(t, c_t);
17908 assert_eq!(&sa[..n as usize], &c_sa[..n as usize]);
17909 if fs == 0 {
17910 assert_eq!(sa, c_sa);
17911 }
17912 }
17913
17914 #[test]
17915 fn libsais16x64_main_32s_entry_matches_c_for_local_32s_paths() {
17916 assert_main_32s_entry_matches_c(make_main_32s_stress_text(1024, 300), 300, 2048);
17917 assert_main_32s_entry_matches_c(make_main_32s_stress_text(1024, 400), 400, 2048);
17918 assert_main_32s_entry_matches_c(make_main_32s_stress_text(1024, 700), 700, 2048);
17919 assert_main_32s_entry_matches_c(make_main_32s_stress_text(1024, 1501), 1501, 2048);
17920 assert_main_32s_entry_matches_c(make_recursive_main_32s_text(24), 300, 0);
17921 assert_main_32s_entry_matches_c(make_recursive_main_32s_text(24), 1501, 0);
17922 }
17923
17924 fn assert_libsais16x64_bwt_matches_c(text: &[u16]) {
17925 let mut rust_u = vec![0; text.len()];
17926 let mut rust_a = vec![0; text.len()];
17927 let mut c_u = vec![0; text.len()];
17928 let mut c_a = vec![0; text.len()];
17929
17930 let rust_rc = libsais16x64_bwt(text, &mut rust_u, &mut rust_a, 0, None);
17931 let c_rc = unsafe {
17932 probe_public_libsais16x64_bwt(
17933 text.as_ptr(),
17934 c_u.as_mut_ptr(),
17935 c_a.as_mut_ptr(),
17936 text.len() as SaSint,
17937 0,
17938 )
17939 };
17940
17941 assert_eq!(rust_rc, c_rc);
17942 assert_eq!(rust_u, c_u);
17943 }
17944
17945 fn assert_libsais16x64_bwt_aux_matches_c(text: &[u16], r: SaSint) {
17946 let aux_len = if text.is_empty() {
17947 0
17948 } else {
17949 (text.len() - 1) / r as usize + 1
17950 };
17951 let mut rust_u = vec![0; text.len()];
17952 let mut rust_a = vec![0; text.len()];
17953 let mut rust_i = vec![0; aux_len];
17954 let mut c_u = vec![0; text.len()];
17955 let mut c_a = vec![0; text.len()];
17956 let mut c_i = vec![0; aux_len];
17957
17958 let rust_rc = libsais16x64_bwt_aux(text, &mut rust_u, &mut rust_a, 0, None, r, &mut rust_i);
17959 let c_rc = unsafe {
17960 probe_public_libsais16x64_bwt_aux(
17961 text.as_ptr(),
17962 c_u.as_mut_ptr(),
17963 c_a.as_mut_ptr(),
17964 text.len() as SaSint,
17965 0,
17966 r,
17967 c_i.as_mut_ptr(),
17968 )
17969 };
17970
17971 assert_eq!(rust_rc, c_rc);
17972 assert_eq!(rust_u, c_u);
17973 assert_eq!(rust_i, c_i);
17974 }
17975
17976 fn assert_libsais16x64_freq_outputs_match_c(text: &[u16], gsa_text: &[u16]) {
17977 let mut rust_sa = vec![0; text.len()];
17978 let mut c_sa = vec![0; text.len()];
17979 let mut rust_freq = vec![-1; ALPHABET_SIZE];
17980 let mut c_freq = vec![-1; ALPHABET_SIZE];
17981
17982 let rust_rc = libsais16x64(text, &mut rust_sa, 0, Some(&mut rust_freq));
17983 let c_rc = unsafe {
17984 probe_public_libsais16x64_freq(
17985 text.as_ptr(),
17986 c_sa.as_mut_ptr(),
17987 text.len() as SaSint,
17988 0,
17989 c_freq.as_mut_ptr(),
17990 )
17991 };
17992 assert_eq!(rust_rc, c_rc);
17993 assert_eq!(rust_sa, c_sa);
17994 assert_eq!(rust_freq, c_freq);
17995
17996 let mut rust_gsa = vec![0; gsa_text.len()];
17997 let mut c_gsa = vec![0; gsa_text.len()];
17998 rust_freq.fill(-1);
17999 c_freq.fill(-1);
18000 let rust_rc = libsais16x64_gsa(gsa_text, &mut rust_gsa, 0, Some(&mut rust_freq));
18001 let c_rc = unsafe {
18002 probe_public_libsais16x64_gsa_freq(
18003 gsa_text.as_ptr(),
18004 c_gsa.as_mut_ptr(),
18005 gsa_text.len() as SaSint,
18006 0,
18007 c_freq.as_mut_ptr(),
18008 )
18009 };
18010 assert_eq!(rust_rc, c_rc);
18011 assert_eq!(rust_gsa, c_gsa);
18012 assert_eq!(rust_freq, c_freq);
18013
18014 let mut rust_u = vec![0; text.len()];
18015 let mut rust_a = vec![0; text.len()];
18016 let mut c_u = vec![0; text.len()];
18017 let mut c_a = vec![0; text.len()];
18018 rust_freq.fill(-1);
18019 c_freq.fill(-1);
18020 let rust_rc = libsais16x64_bwt(text, &mut rust_u, &mut rust_a, 0, Some(&mut rust_freq));
18021 let c_rc = unsafe {
18022 probe_public_libsais16x64_bwt_freq(
18023 text.as_ptr(),
18024 c_u.as_mut_ptr(),
18025 c_a.as_mut_ptr(),
18026 text.len() as SaSint,
18027 0,
18028 c_freq.as_mut_ptr(),
18029 )
18030 };
18031 assert_eq!(rust_rc, c_rc);
18032 assert_eq!(rust_u, c_u);
18033 assert_eq!(rust_freq, c_freq);
18034
18035 let r = 4;
18036 let aux_len = (text.len() - 1) / r as usize + 1;
18037 let mut rust_i = vec![0; aux_len];
18038 let mut c_i = vec![0; aux_len];
18039 rust_freq.fill(-1);
18040 c_freq.fill(-1);
18041 let rust_rc = libsais16x64_bwt_aux(
18042 text,
18043 &mut rust_u,
18044 &mut rust_a,
18045 0,
18046 Some(&mut rust_freq),
18047 r,
18048 &mut rust_i,
18049 );
18050 let c_rc = unsafe {
18051 probe_public_libsais16x64_bwt_aux_freq(
18052 text.as_ptr(),
18053 c_u.as_mut_ptr(),
18054 c_a.as_mut_ptr(),
18055 text.len() as SaSint,
18056 0,
18057 c_freq.as_mut_ptr(),
18058 r,
18059 c_i.as_mut_ptr(),
18060 )
18061 };
18062 assert_eq!(rust_rc, c_rc);
18063 assert_eq!(rust_u, c_u);
18064 assert_eq!(rust_i, c_i);
18065 assert_eq!(rust_freq, c_freq);
18066 }
18067
18068 fn assert_libsais16x64_unbwt_matches_c(text: &[u16]) {
18069 let mut bwt = vec![0; text.len()];
18070 let mut work = vec![0; text.len()];
18071 let primary = libsais16x64_bwt(text, &mut bwt, &mut work, 0, None);
18072 assert!(primary >= 0);
18073
18074 let mut rust_u = vec![0; text.len()];
18075 let mut rust_a = vec![0; text.len() + 1];
18076 let mut c_u = vec![0; text.len()];
18077 let mut c_a = vec![0; text.len() + 1];
18078
18079 let rust_rc = libsais16x64_unbwt(&bwt, &mut rust_u, &mut rust_a, None, primary);
18080 let c_rc = unsafe {
18081 probe_public_libsais16x64_unbwt(
18082 bwt.as_ptr(),
18083 c_u.as_mut_ptr(),
18084 c_a.as_mut_ptr(),
18085 bwt.len() as SaSint,
18086 primary,
18087 )
18088 };
18089
18090 assert_eq!(rust_rc, c_rc);
18091 assert_eq!(rust_u, c_u);
18092 assert_eq!(rust_u, text);
18093 }
18094
18095 fn assert_libsais16x64_unbwt_aux_matches_c(text: &[u16], r: SaSint) {
18096 let mut bwt = vec![0; text.len()];
18097 let mut work = vec![0; text.len()];
18098 let mut aux = vec![0; (text.len() - 1) / r as usize + 1];
18099 let bwt_rc = libsais16x64_bwt_aux(text, &mut bwt, &mut work, 0, None, r, &mut aux);
18100 assert_eq!(bwt_rc, 0);
18101
18102 let mut rust_u = vec![0; text.len()];
18103 let mut rust_a = vec![0; text.len() + 1];
18104 let mut c_u = vec![0; text.len()];
18105 let mut c_a = vec![0; text.len() + 1];
18106
18107 let rust_rc = libsais16x64_unbwt_aux(&bwt, &mut rust_u, &mut rust_a, None, r, &aux);
18108 let c_rc = unsafe {
18109 probe_public_libsais16x64_unbwt_aux(
18110 bwt.as_ptr(),
18111 c_u.as_mut_ptr(),
18112 c_a.as_mut_ptr(),
18113 bwt.len() as SaSint,
18114 r,
18115 aux.as_ptr(),
18116 )
18117 };
18118
18119 assert_eq!(rust_rc, c_rc);
18120 assert_eq!(rust_u, c_u);
18121 assert_eq!(rust_u, text);
18122 }
18123
18124 fn assert_libsais16x64_unbwt_freq_matches_c(text: &[u16]) {
18125 let mut freq = vec![0; ALPHABET_SIZE];
18126 let mut bwt = vec![0; text.len()];
18127 let mut work = vec![0; text.len()];
18128 let primary = libsais16x64_bwt(text, &mut bwt, &mut work, 0, Some(&mut freq));
18129 assert!(primary >= 0);
18130
18131 let mut rust_u = vec![0; text.len()];
18132 let mut rust_a = vec![0; text.len() + 1];
18133 let mut c_u = vec![0; text.len()];
18134 let mut c_a = vec![0; text.len() + 1];
18135
18136 let rust_rc = libsais16x64_unbwt(&bwt, &mut rust_u, &mut rust_a, Some(&freq), primary);
18137 let c_rc = unsafe {
18138 probe_public_libsais16x64_unbwt_freq(
18139 bwt.as_ptr(),
18140 c_u.as_mut_ptr(),
18141 c_a.as_mut_ptr(),
18142 bwt.len() as SaSint,
18143 freq.as_ptr(),
18144 primary,
18145 )
18146 };
18147 assert_eq!(rust_rc, c_rc);
18148 assert_eq!(rust_u, c_u);
18149 assert_eq!(rust_u, text);
18150
18151 let r = 4;
18152 let mut aux = vec![0; (text.len() - 1) / r as usize + 1];
18153 let bwt_rc =
18154 libsais16x64_bwt_aux(text, &mut bwt, &mut work, 0, Some(&mut freq), r, &mut aux);
18155 assert_eq!(bwt_rc, 0);
18156
18157 rust_u.fill(0);
18158 rust_a.fill(0);
18159 c_u.fill(0);
18160 c_a.fill(0);
18161 let rust_rc = libsais16x64_unbwt_aux(&bwt, &mut rust_u, &mut rust_a, Some(&freq), r, &aux);
18162 let c_rc = unsafe {
18163 probe_public_libsais16x64_unbwt_aux_freq(
18164 bwt.as_ptr(),
18165 c_u.as_mut_ptr(),
18166 c_a.as_mut_ptr(),
18167 bwt.len() as SaSint,
18168 freq.as_ptr(),
18169 r,
18170 aux.as_ptr(),
18171 )
18172 };
18173 assert_eq!(rust_rc, c_rc);
18174 assert_eq!(rust_u, c_u);
18175 assert_eq!(rust_u, text);
18176 }
18177
18178 fn assert_libsais16x64_plcp_lcp_matches_c(text: &[u16]) {
18179 let mut sa = vec![0; text.len()];
18180 assert_eq!(libsais16x64(text, &mut sa, 0, None), 0);
18181
18182 let mut rust_plcp = vec![0; text.len()];
18183 let mut c_plcp = vec![0; text.len()];
18184 let rust_rc = libsais16x64_plcp(text, &sa, &mut rust_plcp);
18185 let c_rc = unsafe {
18186 probe_public_libsais16x64_plcp(
18187 text.as_ptr(),
18188 sa.as_ptr(),
18189 c_plcp.as_mut_ptr(),
18190 text.len() as SaSint,
18191 )
18192 };
18193 assert_eq!(rust_rc, c_rc);
18194 assert_eq!(rust_plcp, c_plcp);
18195
18196 let mut rust_lcp = vec![0; text.len()];
18197 let mut c_lcp = vec![0; text.len()];
18198 let rust_rc = libsais16x64_lcp(&rust_plcp, &sa, &mut rust_lcp);
18199 let c_rc = unsafe {
18200 probe_public_libsais16x64_lcp(
18201 c_plcp.as_ptr(),
18202 sa.as_ptr(),
18203 c_lcp.as_mut_ptr(),
18204 text.len() as SaSint,
18205 )
18206 };
18207 assert_eq!(rust_rc, c_rc);
18208 assert_eq!(rust_lcp, c_lcp);
18209 }
18210
18211 fn assert_libsais16x64_plcp_gsa_matches_c(text: &[u16]) {
18212 let mut sa = vec![0; text.len()];
18213 assert_eq!(libsais16x64_gsa(text, &mut sa, 0, None), 0);
18214
18215 let mut rust_plcp = vec![0; text.len()];
18216 let mut c_plcp = vec![0; text.len()];
18217 let rust_rc = libsais16x64_plcp_gsa(text, &sa, &mut rust_plcp);
18218 let c_rc = unsafe {
18219 probe_public_libsais16x64_plcp_gsa(
18220 text.as_ptr(),
18221 sa.as_ptr(),
18222 c_plcp.as_mut_ptr(),
18223 text.len() as SaSint,
18224 )
18225 };
18226 assert_eq!(rust_rc, c_rc);
18227 assert_eq!(rust_plcp, c_plcp);
18228 }
18229
18230 #[test]
18231 fn public_libsais16x64_matches_upstream_c() {
18232 for text in [
18233 [].as_slice(),
18234 &[1][..],
18235 &[2, 1, 3, 1, 2, 0],
18236 &[2, 1, 3, 1, 2, 4, 1, 0],
18237 &[65_535, 1, 65_534, 1, 0],
18238 &[7, 7, 7, 7, 7, 0],
18239 ] {
18240 assert_libsais16x64_matches_c(text);
18241 }
18242 }
18243
18244 #[test]
18245 fn public_libsais16x64_bwt_matches_upstream_c() {
18246 for text in [
18247 [].as_slice(),
18248 &[1][..],
18249 &[2, 1, 3, 1, 2, 0],
18250 &[2, 1, 3, 1, 2, 4, 1, 0],
18251 &[65_535, 1, 65_534, 1, 0],
18252 &[7, 7, 7, 7, 7, 0],
18253 ] {
18254 assert_libsais16x64_bwt_matches_c(text);
18255 }
18256 }
18257
18258 #[test]
18259 fn public_libsais16x64_gsa_matches_upstream_c() {
18260 for text in [&[0][..], &[2, 1, 0], &[2, 1, 0, 3, 1, 0], &[7, 7, 0, 7, 0]] {
18261 assert_libsais16x64_gsa_matches_c(text);
18262 }
18263 }
18264
18265 #[test]
18266 fn public_libsais16x64_long_matches_upstream_c() {
18267 for (text, k) in [
18268 (&[][..], 0),
18269 (&[0][..], 1),
18270 (&[1, 2, 1, 0][..], 3),
18271 (&[2, 1, 2, 1, 0][..], 3),
18272 (&[3, 3, 3, 2, 1, 0][..], 4),
18273 ] {
18274 assert_libsais16x64_long_matches_c(text, k);
18275 }
18276
18277 assert_libsais16x64_long_matches_c_with_fs(&[2, 1, 3, 1, 2, 0], 4, 64);
18278 }
18279
18280 #[test]
18281 fn public_libsais16x64_plcp_lcp_matches_upstream_c() {
18282 for text in [
18283 &[2, 1, 3, 1, 2, 0][..],
18284 &[2, 1, 3, 1, 2, 4, 1, 0],
18285 &[65_535, 1, 65_534, 1, 0],
18286 &[7, 7, 7, 7, 7, 0],
18287 ] {
18288 assert_libsais16x64_plcp_lcp_matches_c(text);
18289 }
18290 }
18291
18292 #[test]
18293 fn public_libsais16x64_plcp_gsa_matches_upstream_c() {
18294 for text in [&[0][..], &[2, 1, 0], &[2, 1, 0, 3, 1, 0], &[7, 7, 0, 7, 0]] {
18295 assert_libsais16x64_plcp_gsa_matches_c(text);
18296 }
18297 }
18298
18299 #[test]
18300 fn public_libsais16x64_bwt_aux_matches_upstream_c() {
18301 for text in [
18302 &[2, 1, 3, 1, 2, 0][..],
18303 &[2, 1, 3, 1, 2, 4, 1, 0],
18304 &[65_535, 1, 65_534, 1, 0],
18305 &[7, 7, 7, 7, 7, 0],
18306 ] {
18307 assert_libsais16x64_bwt_aux_matches_c(text, 4);
18308 }
18309 }
18310
18311 #[test]
18312 fn public_libsais16x64_frequency_outputs_match_upstream_c() {
18313 assert_libsais16x64_freq_outputs_match_c(&[65_535, 1, 2, 1, 0], &[65_535, 1, 0, 2, 1, 0]);
18314 }
18315
18316 #[test]
18317 fn public_libsais16x64_unbwt_with_frequency_matches_upstream_c() {
18318 assert_libsais16x64_unbwt_freq_matches_c(&[65_535, 1, 2, 1, 0]);
18319 }
18320
18321 #[test]
18322 fn public_libsais16x64_unbwt_matches_upstream_c() {
18323 for text in [
18324 &[1][..],
18325 &[2, 1, 3, 1, 2, 0],
18326 &[2, 1, 3, 1, 2, 4, 1, 0],
18327 &[65_535, 1, 65_534, 1, 0],
18328 &[7, 7, 7, 7, 7, 0],
18329 ] {
18330 assert_libsais16x64_unbwt_matches_c(text);
18331 }
18332 }
18333
18334 #[test]
18335 fn public_libsais16x64_unbwt_aux_matches_upstream_c() {
18336 for text in [
18337 &[2, 1, 3, 1, 2, 0][..],
18338 &[2, 1, 3, 1, 2, 4, 1, 0],
18339 &[65_535, 1, 65_534, 1, 0],
18340 &[7, 7, 7, 7, 7, 0],
18341 ] {
18342 assert_libsais16x64_unbwt_aux_matches_c(text, 4);
18343 }
18344 }
18345
18346 #[test]
18347 fn public_libsais16x64_unbwt_aux_exercises_decode_dispatch_cases() {
18348 for len in [2usize, 5, 9, 13, 17, 21, 25, 29, 33, 37] {
18349 let text = (0..len)
18350 .map(|i| ((i * 37 + 11) % 65_535 + 1) as u16)
18351 .collect::<Vec<_>>();
18352 assert_libsais16x64_unbwt_aux_matches_c(&text, 4);
18353 }
18354 }
18355
18356 #[test]
18357 fn libsais16x64_lcp_helpers_reject_invalid_suffix_entries() {
18358 let text = [2, 1, 2, 1, 0];
18359 let mut plcp = vec![0; text.len()];
18360 let mut lcp = vec![0; text.len()];
18361
18362 assert_eq!(libsais16x64_plcp(&text, &[0, 1, -1, 3, 4], &mut plcp), -1);
18363 assert_eq!(libsais16x64_plcp(&text, &[0, 1, 2, 3, 5], &mut plcp), -1);
18364 assert_eq!(libsais16x64_lcp(&plcp, &[0, 1, -1, 3, 4], &mut lcp), -1);
18365 assert_eq!(libsais16x64_lcp(&plcp, &[0, 1, 2, 3, 5], &mut lcp), -1);
18366 }
18367
18368 #[test]
18369 fn libsais16x64_rejects_invalid_public_arguments() {
18370 let text = [2, 1, 3, 1, 2, 0];
18371 let int_text = [1, 2, 1, 0];
18372 let mut int_text_for_short_sa = int_text.to_vec();
18373 let mut int_text_for_negative_fs = int_text.to_vec();
18374 let mut int_text_for_alias = int_text.to_vec();
18375 let mut sa = vec![0; text.len() - 1];
18376 let mut int_sa = vec![0; int_text.len() - 1];
18377 let mut full_int_sa = vec![0; int_text.len()];
18378 let mut freq = vec![0; ALPHABET_SIZE - 1];
18379 let mut u = vec![0; text.len() - 1];
18380 let mut a = vec![0; text.len() - 1];
18381 let mut full_u = vec![0; text.len()];
18382 let mut full_a = vec![0; text.len()];
18383 let mut aux = vec![0; 1];
18384
18385 assert_eq!(libsais16x64(&text, &mut sa, 0, None), -1);
18386 assert_eq!(libsais16x64(&text, &mut full_a, 0, Some(&mut freq)), -1);
18387 assert_eq!(libsais16x64_gsa(&[1, 2, 3], &mut full_a[..3], 0, None), -1);
18388 assert_eq!(
18389 libsais16x64_long(&mut int_text_for_short_sa, &mut int_sa, 3, 0),
18390 -1
18391 );
18392 assert_eq!(
18393 libsais16x64_long(&mut int_text_for_negative_fs, &mut full_int_sa, 3, -1),
18394 -1
18395 );
18396 assert_eq!(
18397 libsais16x64_int(&mut int_text_for_alias, &mut full_int_sa, 3, -1),
18398 -1
18399 );
18400 assert_eq!(libsais16x64_bwt(&text, &mut u, &mut full_a, 0, None), -1);
18401 assert_eq!(libsais16x64_bwt(&text, &mut full_u, &mut a, 0, None), -1);
18402 assert_eq!(
18403 libsais16x64_bwt_aux(&text, &mut full_u, &mut full_a, 0, None, 0, &mut aux),
18404 -1
18405 );
18406 assert_eq!(
18407 libsais16x64_bwt_aux(&text, &mut full_u, &mut full_a, 0, None, 3, &mut aux),
18408 -1
18409 );
18410 assert_eq!(
18411 libsais16x64_bwt_aux(&text, &mut full_u, &mut full_a, 0, None, 4, &mut aux),
18412 -1
18413 );
18414 assert_eq!(create_ctx_omp(-1), None);
18415 assert_eq!(unbwt_create_ctx_omp(-1), None);
18416 }
18417
18418 #[test]
18419 fn libsais16x64_unbwt_rejects_invalid_public_arguments() {
18420 let text = [2, 1, 3, 1, 2, 0];
18421 let mut bwt = vec![0; text.len()];
18422 let mut work = vec![0; text.len()];
18423 let primary = libsais16x64_bwt(&text, &mut bwt, &mut work, 0, None);
18424
18425 let mut short_u = vec![0; text.len() - 1];
18426 let mut short_a = vec![0; text.len() - 1];
18427 let mut full_u = vec![0; text.len()];
18428 let mut full_a = vec![0; text.len()];
18429 let short_freq = vec![0; ALPHABET_SIZE - 1];
18430 let short_aux = vec![primary];
18431 let bad_aux = vec![0, 0];
18432 let good_aux = vec![primary, 4];
18433
18434 assert_eq!(
18435 libsais16x64_unbwt(&bwt, &mut short_u, &mut full_a, None, primary),
18436 -1
18437 );
18438 assert_eq!(
18439 libsais16x64_unbwt(&bwt, &mut full_u, &mut short_a, None, primary),
18440 -1
18441 );
18442 assert_eq!(
18443 libsais16x64_unbwt(&bwt, &mut full_u, &mut full_a, Some(&short_freq), primary),
18444 -1
18445 );
18446 assert_eq!(
18447 libsais16x64_unbwt(&bwt, &mut full_u, &mut full_a, None, 0),
18448 -1
18449 );
18450 assert_eq!(
18451 libsais16x64_unbwt(
18452 &bwt,
18453 &mut full_u,
18454 &mut full_a,
18455 None,
18456 text.len() as SaSint + 1
18457 ),
18458 -1
18459 );
18460 assert_eq!(
18461 libsais16x64_unbwt_aux(&bwt, &mut full_u, &mut full_a, None, 0, &good_aux),
18462 -1
18463 );
18464 assert_eq!(
18465 libsais16x64_unbwt_aux(&bwt, &mut full_u, &mut full_a, None, 3, &good_aux),
18466 -1
18467 );
18468 assert_eq!(
18469 libsais16x64_unbwt_aux(&bwt, &mut full_u, &mut full_a, None, 4, &short_aux),
18470 -1
18471 );
18472 assert_eq!(
18473 libsais16x64_unbwt_aux(&bwt, &mut full_u, &mut full_a, None, 4, &bad_aux),
18474 -1
18475 );
18476 }
18477
18478 #[test]
18479 fn libsais16x64_ctx_rejects_invalid_public_arguments() {
18480 let text = [2, 1, 3, 1, 2, 0];
18481 let mut ctx = create_ctx().unwrap();
18482 let mut sa = vec![0; text.len() - 1];
18483 let mut freq = vec![0; ALPHABET_SIZE - 1];
18484 let mut u = vec![0; text.len() - 1];
18485 let mut a = vec![0; text.len() - 1];
18486 let mut full_u = vec![0; text.len()];
18487 let mut full_a = vec![0; text.len()];
18488 let mut aux = vec![0; 1];
18489
18490 assert_eq!(libsais16x64_ctx(&mut ctx, &text, &mut sa, 0, None), -1);
18491 assert_eq!(
18492 libsais16x64_ctx(&mut ctx, &text, &mut full_a, 0, Some(&mut freq)),
18493 -1
18494 );
18495 assert_eq!(
18496 libsais16x64_gsa_ctx(&mut ctx, &[1, 2, 3], &mut full_a[..3], 0, None),
18497 -1
18498 );
18499 assert_eq!(
18500 libsais16x64_bwt_ctx(&mut ctx, &text, &mut u, &mut full_a, 0, None),
18501 -1
18502 );
18503 assert_eq!(
18504 libsais16x64_bwt_ctx(&mut ctx, &text, &mut full_u, &mut a, 0, None),
18505 -1
18506 );
18507 assert_eq!(
18508 libsais16x64_bwt_aux_ctx(
18509 &mut ctx,
18510 &text,
18511 &mut full_u,
18512 &mut full_a,
18513 0,
18514 None,
18515 0,
18516 &mut aux
18517 ),
18518 -1
18519 );
18520 assert_eq!(
18521 libsais16x64_bwt_aux_ctx(
18522 &mut ctx,
18523 &text,
18524 &mut full_u,
18525 &mut full_a,
18526 0,
18527 None,
18528 3,
18529 &mut aux
18530 ),
18531 -1
18532 );
18533 assert_eq!(
18534 libsais16x64_bwt_aux_ctx(
18535 &mut ctx,
18536 &text,
18537 &mut full_u,
18538 &mut full_a,
18539 0,
18540 None,
18541 4,
18542 &mut aux
18543 ),
18544 -1
18545 );
18546
18547 let mut default_ctx = Context::default();
18548 assert_eq!(
18549 libsais16x64_ctx(&mut default_ctx, &text, &mut full_a, 0, None),
18550 -2
18551 );
18552
18553 let mut bad_bucket_ctx = create_ctx().unwrap();
18554 bad_bucket_ctx.buckets.clear();
18555 assert_eq!(
18556 libsais16x64_ctx(&mut bad_bucket_ctx, &text, &mut full_a, 0, None),
18557 -2
18558 );
18559
18560 let mut short_thread_state_ctx = create_ctx_omp(2).unwrap();
18561 short_thread_state_ctx
18562 .thread_state
18563 .as_mut()
18564 .unwrap()
18565 .truncate(1);
18566 assert_eq!(
18567 libsais16x64_ctx(&mut short_thread_state_ctx, &text, &mut full_a, 0, None),
18568 -2
18569 );
18570 }
18571
18572 #[test]
18573 fn libsais16x64_unbwt_ctx_rejects_invalid_public_arguments() {
18574 let text = [2, 1, 3, 1, 2, 0];
18575 let mut bwt = vec![0; text.len()];
18576 let mut work = vec![0; text.len()];
18577 let primary = libsais16x64_bwt(&text, &mut bwt, &mut work, 0, None);
18578 let mut ctx = unbwt_create_ctx().unwrap();
18579
18580 let mut short_u = vec![0; text.len() - 1];
18581 let mut short_a = vec![0; text.len() - 1];
18582 let mut full_u = vec![0; text.len()];
18583 let mut full_a = vec![0; text.len()];
18584 let short_freq = vec![0; ALPHABET_SIZE - 1];
18585 let short_aux = vec![primary];
18586 let bad_aux = vec![0, 0];
18587 let good_aux = vec![primary, 4];
18588
18589 assert_eq!(
18590 libsais16x64_unbwt_ctx(&mut ctx, &bwt, &mut short_u, &mut full_a, None, primary),
18591 -1
18592 );
18593 assert_eq!(
18594 libsais16x64_unbwt_ctx(&mut ctx, &bwt, &mut full_u, &mut short_a, None, primary),
18595 -1
18596 );
18597 assert_eq!(
18598 libsais16x64_unbwt_ctx(
18599 &mut ctx,
18600 &bwt,
18601 &mut full_u,
18602 &mut full_a,
18603 Some(&short_freq),
18604 primary
18605 ),
18606 -1
18607 );
18608 assert_eq!(
18609 libsais16x64_unbwt_ctx(&mut ctx, &bwt, &mut full_u, &mut full_a, None, 0),
18610 -1
18611 );
18612 assert_eq!(
18613 libsais16x64_unbwt_aux_ctx(
18614 &mut ctx,
18615 &bwt,
18616 &mut full_u,
18617 &mut full_a,
18618 None,
18619 0,
18620 &good_aux
18621 ),
18622 -1
18623 );
18624 assert_eq!(
18625 libsais16x64_unbwt_aux_ctx(
18626 &mut ctx,
18627 &bwt,
18628 &mut full_u,
18629 &mut full_a,
18630 None,
18631 3,
18632 &good_aux
18633 ),
18634 -1
18635 );
18636 assert_eq!(
18637 libsais16x64_unbwt_aux_ctx(
18638 &mut ctx,
18639 &bwt,
18640 &mut full_u,
18641 &mut full_a,
18642 None,
18643 4,
18644 &short_aux
18645 ),
18646 -1
18647 );
18648 assert_eq!(
18649 libsais16x64_unbwt_aux_ctx(&mut ctx, &bwt, &mut full_u, &mut full_a, None, 4, &bad_aux),
18650 -1
18651 );
18652 }
18653
18654 #[test]
18655 fn libsais16x64_context_wrappers_match_direct_calls() {
18656 let text = [2, 1, 3, 1, 2, 0];
18657 let mut ctx = create_ctx().unwrap();
18658
18659 let mut direct_sa = vec![0; text.len()];
18660 let mut ctx_sa = vec![0; text.len()];
18661 assert_eq!(libsais16x64(&text, &mut direct_sa, 0, None), 0);
18662 assert_eq!(libsais16x64_ctx(&mut ctx, &text, &mut ctx_sa, 0, None), 0);
18663 assert_eq!(ctx_sa, direct_sa);
18664
18665 let mut direct_bwt = vec![0; text.len()];
18666 let mut direct_work = vec![0; text.len()];
18667 let mut ctx_bwt = vec![0; text.len()];
18668 let mut ctx_work = vec![0; text.len()];
18669 assert_eq!(
18670 libsais16x64_bwt(&text, &mut direct_bwt, &mut direct_work, 0, None),
18671 libsais16x64_bwt_ctx(&mut ctx, &text, &mut ctx_bwt, &mut ctx_work, 0, None)
18672 );
18673 assert_eq!(ctx_bwt, direct_bwt);
18674
18675 let mut direct_aux = vec![0; 2];
18676 let mut ctx_aux = vec![0; 2];
18677 assert_eq!(
18678 libsais16x64_bwt_aux(
18679 &text,
18680 &mut direct_bwt,
18681 &mut direct_work,
18682 0,
18683 None,
18684 4,
18685 &mut direct_aux
18686 ),
18687 libsais16x64_bwt_aux_ctx(
18688 &mut ctx,
18689 &text,
18690 &mut ctx_bwt,
18691 &mut ctx_work,
18692 0,
18693 None,
18694 4,
18695 &mut ctx_aux
18696 )
18697 );
18698 assert_eq!(ctx_bwt, direct_bwt);
18699 assert_eq!(ctx_aux, direct_aux);
18700 }
18701
18702 #[test]
18703 fn libsais16x64_unbwt_context_wrappers_match_direct_calls() {
18704 let text = [2, 1, 3, 1, 2, 0];
18705 let mut bwt = vec![0; text.len()];
18706 let mut work = vec![0; text.len()];
18707 let primary = libsais16x64_bwt(&text, &mut bwt, &mut work, 0, None);
18708
18709 let mut ctx = unbwt_create_ctx().unwrap();
18710 let mut direct = vec![0; text.len()];
18711 let mut direct_work = vec![0; text.len()];
18712 let mut via_ctx = vec![0; text.len()];
18713 let mut ctx_work = vec![0; text.len()];
18714
18715 assert_eq!(
18716 libsais16x64_unbwt(&bwt, &mut direct, &mut direct_work, None, primary),
18717 0
18718 );
18719 assert_eq!(
18720 libsais16x64_unbwt_ctx(&mut ctx, &bwt, &mut via_ctx, &mut ctx_work, None, primary),
18721 0
18722 );
18723 assert_eq!(via_ctx, direct);
18724
18725 let mut aux = vec![0; 2];
18726 assert_eq!(
18727 libsais16x64_bwt_aux(&text, &mut bwt, &mut work, 0, None, 4, &mut aux),
18728 0
18729 );
18730 assert_eq!(
18731 libsais16x64_unbwt_aux(&bwt, &mut direct, &mut direct_work, None, 4, &aux),
18732 0
18733 );
18734 assert_eq!(
18735 libsais16x64_unbwt_aux_ctx(&mut ctx, &bwt, &mut via_ctx, &mut ctx_work, None, 4, &aux),
18736 0
18737 );
18738 assert_eq!(via_ctx, direct);
18739 }
18740
18741 #[test]
18742 fn libsais16x64_ctx_frequency_wrappers_match_direct_calls() {
18743 let text = [2, 1, 3, 1, 2, 0];
18744 let gsa_text = [2, 1, 0, 3, 1, 0];
18745 let mut ctx = create_ctx().unwrap();
18746
18747 let mut direct_sa = vec![0; text.len()];
18748 let mut ctx_sa = vec![0; text.len()];
18749 let mut direct_freq = vec![-1; ALPHABET_SIZE];
18750 let mut ctx_freq = vec![-1; ALPHABET_SIZE];
18751 assert_eq!(
18752 libsais16x64(&text, &mut direct_sa, 0, Some(&mut direct_freq)),
18753 0
18754 );
18755 assert_eq!(
18756 libsais16x64_ctx(&mut ctx, &text, &mut ctx_sa, 0, Some(&mut ctx_freq)),
18757 0
18758 );
18759 assert_eq!(ctx_sa, direct_sa);
18760 assert_eq!(ctx_freq, direct_freq);
18761
18762 let mut direct_gsa = vec![0; gsa_text.len()];
18763 let mut ctx_gsa = vec![0; gsa_text.len()];
18764 direct_freq.fill(-1);
18765 ctx_freq.fill(-1);
18766 assert_eq!(
18767 libsais16x64_gsa(&gsa_text, &mut direct_gsa, 0, Some(&mut direct_freq)),
18768 0
18769 );
18770 assert_eq!(
18771 libsais16x64_gsa_ctx(&mut ctx, &gsa_text, &mut ctx_gsa, 0, Some(&mut ctx_freq)),
18772 0
18773 );
18774 assert_eq!(ctx_gsa, direct_gsa);
18775 assert_eq!(ctx_freq, direct_freq);
18776
18777 let mut direct_bwt = vec![0; text.len()];
18778 let mut direct_work = vec![0; text.len()];
18779 let mut ctx_bwt = vec![0; text.len()];
18780 let mut ctx_work = vec![0; text.len()];
18781 direct_freq.fill(-1);
18782 ctx_freq.fill(-1);
18783 assert_eq!(
18784 libsais16x64_bwt(
18785 &text,
18786 &mut direct_bwt,
18787 &mut direct_work,
18788 0,
18789 Some(&mut direct_freq)
18790 ),
18791 libsais16x64_bwt_ctx(
18792 &mut ctx,
18793 &text,
18794 &mut ctx_bwt,
18795 &mut ctx_work,
18796 0,
18797 Some(&mut ctx_freq)
18798 )
18799 );
18800 assert_eq!(ctx_bwt, direct_bwt);
18801 assert_eq!(ctx_freq, direct_freq);
18802
18803 let mut direct_aux = vec![0; 2];
18804 let mut ctx_aux = vec![0; 2];
18805 direct_freq.fill(-1);
18806 ctx_freq.fill(-1);
18807 assert_eq!(
18808 libsais16x64_bwt_aux(
18809 &text,
18810 &mut direct_bwt,
18811 &mut direct_work,
18812 0,
18813 Some(&mut direct_freq),
18814 4,
18815 &mut direct_aux
18816 ),
18817 libsais16x64_bwt_aux_ctx(
18818 &mut ctx,
18819 &text,
18820 &mut ctx_bwt,
18821 &mut ctx_work,
18822 0,
18823 Some(&mut ctx_freq),
18824 4,
18825 &mut ctx_aux
18826 )
18827 );
18828 assert_eq!(ctx_bwt, direct_bwt);
18829 assert_eq!(ctx_aux, direct_aux);
18830 assert_eq!(ctx_freq, direct_freq);
18831 }
18832
18833 #[test]
18834 fn libsais16x64_unbwt_ctx_frequency_wrappers_match_direct_calls() {
18835 let text = [2, 1, 3, 1, 2, 0];
18836 let mut freq = vec![0; ALPHABET_SIZE];
18837 let mut bwt = vec![0; text.len()];
18838 let mut work = vec![0; text.len()];
18839 let primary = libsais16x64_bwt(&text, &mut bwt, &mut work, 0, Some(&mut freq));
18840 assert!(primary >= 0);
18841
18842 let mut ctx = unbwt_create_ctx().unwrap();
18843 let mut direct = vec![0; text.len()];
18844 let mut direct_work = vec![0; text.len() + 1];
18845 let mut via_ctx = vec![0; text.len()];
18846 let mut ctx_work = vec![0; text.len() + 1];
18847 assert_eq!(
18848 libsais16x64_unbwt(&bwt, &mut direct, &mut direct_work, Some(&freq), primary),
18849 libsais16x64_unbwt_ctx(
18850 &mut ctx,
18851 &bwt,
18852 &mut via_ctx,
18853 &mut ctx_work,
18854 Some(&freq),
18855 primary
18856 )
18857 );
18858 assert_eq!(via_ctx, direct);
18859 assert_eq!(via_ctx, text);
18860
18861 let mut aux = vec![0; (text.len() - 1) / 4 + 1];
18862 assert_eq!(
18863 libsais16x64_bwt_aux(&text, &mut bwt, &mut work, 0, Some(&mut freq), 4, &mut aux),
18864 0
18865 );
18866 direct.fill(0);
18867 direct_work.fill(0);
18868 via_ctx.fill(0);
18869 ctx_work.fill(0);
18870 assert_eq!(
18871 libsais16x64_unbwt_aux(&bwt, &mut direct, &mut direct_work, Some(&freq), 4, &aux),
18872 libsais16x64_unbwt_aux_ctx(
18873 &mut ctx,
18874 &bwt,
18875 &mut via_ctx,
18876 &mut ctx_work,
18877 Some(&freq),
18878 4,
18879 &aux
18880 )
18881 );
18882 assert_eq!(via_ctx, direct);
18883 assert_eq!(via_ctx, text);
18884 }
18885
18886 #[test]
18887 fn libsais16x64_omp_wrappers_match_direct_calls_and_reject_negative_threads() {
18888 let text = [2, 1, 3, 1, 2, 0];
18889 let gsa_text = [2, 1, 0, 3, 1, 0];
18890 let mut direct_sa = vec![0; text.len()];
18891 let mut omp_sa = vec![0; text.len()];
18892 assert_eq!(libsais16x64(&text, &mut direct_sa, 0, None), 0);
18893 assert_eq!(libsais16x64_omp(&text, &mut omp_sa, 0, None, 2), 0);
18894 assert_eq!(omp_sa, direct_sa);
18895 assert_eq!(libsais16x64_omp(&text, &mut omp_sa, 0, None, -1), -1);
18896
18897 let mut direct_gsa = vec![0; gsa_text.len()];
18898 let mut omp_gsa = vec![0; gsa_text.len()];
18899 assert_eq!(libsais16x64_gsa(&gsa_text, &mut direct_gsa, 0, None), 0);
18900 assert_eq!(libsais16x64_gsa_omp(&gsa_text, &mut omp_gsa, 0, None, 2), 0);
18901 assert_eq!(omp_gsa, direct_gsa);
18902 assert_eq!(
18903 libsais16x64_gsa_omp(&gsa_text, &mut omp_gsa, 0, None, -1),
18904 -1
18905 );
18906
18907 let int_text = [1, 2, 1, 0];
18908 let mut direct_int_text = int_text.to_vec();
18909 let mut omp_int_text = int_text.to_vec();
18910 let mut direct_int_sa = vec![0; int_text.len()];
18911 let mut omp_int_sa = vec![0; int_text.len()];
18912 assert_eq!(
18913 libsais16x64_long(&mut direct_int_text, &mut direct_int_sa, 3, 0),
18914 0
18915 );
18916 assert_eq!(
18917 libsais16x64_long_omp(&mut omp_int_text, &mut omp_int_sa, 3, 0, 2),
18918 0
18919 );
18920 assert_eq!(omp_int_text, direct_int_text);
18921 assert_eq!(omp_int_sa, direct_int_sa);
18922 assert_eq!(
18923 libsais16x64_long_omp(&mut omp_int_text, &mut omp_int_sa, 3, 0, -1),
18924 -1
18925 );
18926
18927 let mut direct_bwt = vec![0; text.len()];
18928 let mut direct_work = vec![0; text.len()];
18929 let mut omp_bwt = vec![0; text.len()];
18930 let mut omp_work = vec![0; text.len()];
18931 assert_eq!(
18932 libsais16x64_bwt(&text, &mut direct_bwt, &mut direct_work, 0, None),
18933 libsais16x64_bwt_omp(&text, &mut omp_bwt, &mut omp_work, 0, None, 2)
18934 );
18935 assert_eq!(omp_bwt, direct_bwt);
18936 assert_eq!(
18937 libsais16x64_bwt_omp(&text, &mut omp_bwt, &mut omp_work, 0, None, -1),
18938 -1
18939 );
18940
18941 let mut direct_aux = vec![0; 2];
18942 let mut omp_aux = vec![0; 2];
18943 assert_eq!(
18944 libsais16x64_bwt_aux(
18945 &text,
18946 &mut direct_bwt,
18947 &mut direct_work,
18948 0,
18949 None,
18950 4,
18951 &mut direct_aux
18952 ),
18953 libsais16x64_bwt_aux_omp(
18954 &text,
18955 &mut omp_bwt,
18956 &mut omp_work,
18957 0,
18958 None,
18959 4,
18960 &mut omp_aux,
18961 2
18962 )
18963 );
18964 assert_eq!(omp_bwt, direct_bwt);
18965 assert_eq!(omp_aux, direct_aux);
18966 assert_eq!(
18967 libsais16x64_bwt_aux_omp(
18968 &text,
18969 &mut omp_bwt,
18970 &mut omp_work,
18971 0,
18972 None,
18973 4,
18974 &mut omp_aux,
18975 -1
18976 ),
18977 -1
18978 );
18979 }
18980
18981 #[test]
18982 fn libsais16x64_omp_frequency_wrappers_match_direct_calls() {
18983 let text = [2, 1, 3, 1, 2, 0];
18984 let gsa_text = [2, 1, 0, 3, 1, 0];
18985 let mut direct_sa = vec![0; text.len()];
18986 let mut omp_sa = vec![0; text.len()];
18987 let mut direct_freq = vec![-1; ALPHABET_SIZE];
18988 let mut omp_freq = vec![-1; ALPHABET_SIZE];
18989 assert_eq!(
18990 libsais16x64(&text, &mut direct_sa, 0, Some(&mut direct_freq)),
18991 0
18992 );
18993 assert_eq!(
18994 libsais16x64_omp(&text, &mut omp_sa, 0, Some(&mut omp_freq), 2),
18995 0
18996 );
18997 assert_eq!(omp_sa, direct_sa);
18998 assert_eq!(omp_freq, direct_freq);
18999
19000 let mut direct_gsa = vec![0; gsa_text.len()];
19001 let mut omp_gsa = vec![0; gsa_text.len()];
19002 direct_freq.fill(-1);
19003 omp_freq.fill(-1);
19004 assert_eq!(
19005 libsais16x64_gsa(&gsa_text, &mut direct_gsa, 0, Some(&mut direct_freq)),
19006 0
19007 );
19008 assert_eq!(
19009 libsais16x64_gsa_omp(&gsa_text, &mut omp_gsa, 0, Some(&mut omp_freq), 2),
19010 0
19011 );
19012 assert_eq!(omp_gsa, direct_gsa);
19013 assert_eq!(omp_freq, direct_freq);
19014
19015 let mut direct_bwt = vec![0; text.len()];
19016 let mut direct_work = vec![0; text.len()];
19017 let mut omp_bwt = vec![0; text.len()];
19018 let mut omp_work = vec![0; text.len()];
19019 direct_freq.fill(-1);
19020 omp_freq.fill(-1);
19021 assert_eq!(
19022 libsais16x64_bwt(
19023 &text,
19024 &mut direct_bwt,
19025 &mut direct_work,
19026 0,
19027 Some(&mut direct_freq)
19028 ),
19029 libsais16x64_bwt_omp(
19030 &text,
19031 &mut omp_bwt,
19032 &mut omp_work,
19033 0,
19034 Some(&mut omp_freq),
19035 2
19036 )
19037 );
19038 assert_eq!(omp_bwt, direct_bwt);
19039 assert_eq!(omp_freq, direct_freq);
19040
19041 let mut direct_aux = vec![0; 2];
19042 let mut omp_aux = vec![0; 2];
19043 direct_freq.fill(-1);
19044 omp_freq.fill(-1);
19045 assert_eq!(
19046 libsais16x64_bwt_aux(
19047 &text,
19048 &mut direct_bwt,
19049 &mut direct_work,
19050 0,
19051 Some(&mut direct_freq),
19052 4,
19053 &mut direct_aux
19054 ),
19055 libsais16x64_bwt_aux_omp(
19056 &text,
19057 &mut omp_bwt,
19058 &mut omp_work,
19059 0,
19060 Some(&mut omp_freq),
19061 4,
19062 &mut omp_aux,
19063 2
19064 )
19065 );
19066 assert_eq!(omp_bwt, direct_bwt);
19067 assert_eq!(omp_aux, direct_aux);
19068 assert_eq!(omp_freq, direct_freq);
19069 }
19070
19071 #[test]
19072 fn libsais16x64_unbwt_omp_frequency_wrappers_match_direct_calls() {
19073 let text = [2, 1, 3, 1, 2, 0];
19074 let mut freq = vec![0; ALPHABET_SIZE];
19075 let mut bwt = vec![0; text.len()];
19076 let mut work = vec![0; text.len()];
19077 let primary = libsais16x64_bwt(&text, &mut bwt, &mut work, 0, Some(&mut freq));
19078 assert!(primary >= 0);
19079
19080 let mut direct = vec![0; text.len()];
19081 let mut direct_work = vec![0; text.len() + 1];
19082 let mut omp = vec![0; text.len()];
19083 let mut omp_work = vec![0; text.len() + 1];
19084 assert_eq!(
19085 libsais16x64_unbwt(&bwt, &mut direct, &mut direct_work, Some(&freq), primary),
19086 libsais16x64_unbwt_omp(&bwt, &mut omp, &mut omp_work, Some(&freq), primary, 2)
19087 );
19088 assert_eq!(omp, direct);
19089 assert_eq!(omp, text);
19090
19091 let mut aux = vec![0; (text.len() - 1) / 4 + 1];
19092 assert_eq!(
19093 libsais16x64_bwt_aux(&text, &mut bwt, &mut work, 0, Some(&mut freq), 4, &mut aux),
19094 0
19095 );
19096 direct.fill(0);
19097 direct_work.fill(0);
19098 omp.fill(0);
19099 omp_work.fill(0);
19100 assert_eq!(
19101 libsais16x64_unbwt_aux(&bwt, &mut direct, &mut direct_work, Some(&freq), 4, &aux),
19102 libsais16x64_unbwt_aux_omp(&bwt, &mut omp, &mut omp_work, Some(&freq), 4, &aux, 2)
19103 );
19104 assert_eq!(omp, direct);
19105 assert_eq!(omp, text);
19106 }
19107
19108 #[test]
19109 fn libsais16x64_lcp_and_unbwt_omp_wrappers_match_direct_calls() {
19110 let text = [2, 1, 3, 1, 2, 0];
19111 let mut sa = vec![0; text.len()];
19112 assert_eq!(libsais16x64(&text, &mut sa, 0, None), 0);
19113
19114 let mut direct_plcp = vec![0; text.len()];
19115 let mut omp_plcp = vec![0; text.len()];
19116 assert_eq!(libsais16x64_plcp(&text, &sa, &mut direct_plcp), 0);
19117 assert_eq!(libsais16x64_plcp_omp(&text, &sa, &mut omp_plcp, 2), 0);
19118 assert_eq!(omp_plcp, direct_plcp);
19119 assert_eq!(libsais16x64_plcp_omp(&text, &sa, &mut omp_plcp, -1), -1);
19120
19121 let gsa_text = [2, 1, 0, 1, 2, 0];
19122 let mut gsa = vec![0; gsa_text.len()];
19123 assert_eq!(libsais16x64_gsa(&gsa_text, &mut gsa, 0, None), 0);
19124 let mut direct_gsa_plcp = vec![0; gsa_text.len()];
19125 let mut omp_gsa_plcp = vec![0; gsa_text.len()];
19126 assert_eq!(
19127 libsais16x64_plcp_gsa(&gsa_text, &gsa, &mut direct_gsa_plcp),
19128 0
19129 );
19130 assert_eq!(
19131 libsais16x64_plcp_gsa_omp(&gsa_text, &gsa, &mut omp_gsa_plcp, 2),
19132 0
19133 );
19134 assert_eq!(omp_gsa_plcp, direct_gsa_plcp);
19135 assert_eq!(
19136 libsais16x64_plcp_gsa_omp(&gsa_text, &gsa, &mut omp_gsa_plcp, -1),
19137 -1
19138 );
19139
19140 let mut direct_lcp = vec![0; text.len()];
19141 let mut omp_lcp = vec![0; text.len()];
19142 assert_eq!(libsais16x64_lcp(&direct_plcp, &sa, &mut direct_lcp), 0);
19143 assert_eq!(libsais16x64_lcp_omp(&direct_plcp, &sa, &mut omp_lcp, 2), 0);
19144 assert_eq!(omp_lcp, direct_lcp);
19145 assert_eq!(
19146 libsais16x64_lcp_omp(&direct_plcp, &sa, &mut omp_lcp, -1),
19147 -1
19148 );
19149
19150 let mut bwt = vec![0; text.len()];
19151 let mut work = vec![0; text.len()];
19152 let primary = libsais16x64_bwt(&text, &mut bwt, &mut work, 0, None);
19153 let mut direct = vec![0; text.len()];
19154 let mut omp = vec![0; text.len()];
19155 let mut direct_work = vec![0; text.len()];
19156 let mut omp_work = vec![0; text.len()];
19157 assert_eq!(
19158 libsais16x64_unbwt(&bwt, &mut direct, &mut direct_work, None, primary),
19159 0
19160 );
19161 assert_eq!(
19162 libsais16x64_unbwt_omp(&bwt, &mut omp, &mut omp_work, None, primary, 2),
19163 0
19164 );
19165 assert_eq!(omp, direct);
19166 assert_eq!(
19167 libsais16x64_unbwt_omp(&bwt, &mut omp, &mut omp_work, None, primary, -1),
19168 -1
19169 );
19170 }
19171}