1#![forbid(unsafe_code)]
2
3use core::cmp::Ordering;
4use core::ffi::{c_int, c_uint};
5
6use crate::{
7 assert_h,
8 bzlib::{Arr2, EState, BZ_N_OVERSHOOT, BZ_N_QSORT, BZ_N_RADIX, FTAB_LEN},
9};
10use crate::{debug_log, debug_logln};
11
12#[inline]
14fn fallbackSimpleSort(fmap: &mut [u32], eclass: &[u32], lo: i32, hi: i32) {
15 let mut j: i32;
16 let mut tmp: i32;
17 let mut ec_tmp: u32;
18
19 if lo == hi {
20 return;
21 }
22
23 if hi - lo > 3 {
24 for i in (lo..=hi - 4).rev() {
25 tmp = fmap[i as usize] as i32;
26 ec_tmp = eclass[tmp as usize];
27 j = i + 4;
28 while j <= hi && ec_tmp > eclass[fmap[j as usize] as usize] {
29 fmap[(j - 4) as usize] = fmap[j as usize];
30 j += 4;
31 }
32 fmap[(j - 4) as usize] = tmp as u32;
33 }
34 }
35
36 for i in (lo..=hi - 1).rev() {
37 tmp = fmap[i as usize] as i32;
38 ec_tmp = eclass[tmp as usize];
39 j = i + 1;
40 while j <= hi && ec_tmp > eclass[fmap[j as usize] as usize] {
41 fmap[(j - 1) as usize] = fmap[j as usize];
42 j += 1;
43 }
44 fmap[(j - 1) as usize] = tmp as u32;
45 }
46}
47
48const FALLBACK_QSORT_SMALL_THRESH: i32 = 10;
49const FALLBACK_QSORT_STACK_SIZE: usize = 100;
50
51fn fallbackQSort3(fmap: &mut [u32], eclass: &[u32], loSt: i32, hiSt: i32) {
52 let mut unLo: i32;
53 let mut unHi: i32;
54 let mut ltLo: i32;
55 let mut gtHi: i32;
56 let mut n: i32;
57 let mut m: i32;
58 let mut sp: usize;
59 let mut lo: i32;
60 let mut hi: i32;
61 let mut stackLo: [i32; FALLBACK_QSORT_STACK_SIZE] = [0; FALLBACK_QSORT_STACK_SIZE];
62 let mut stackHi: [i32; FALLBACK_QSORT_STACK_SIZE] = [0; FALLBACK_QSORT_STACK_SIZE];
63
64 macro_rules! fpush {
65 ($lz:expr, $hz:expr) => {
66 stackLo[sp] = $lz;
67 stackHi[sp] = $hz;
68 sp += 1;
69 };
70 }
71
72 macro_rules! fvswap {
73 ($zzp1:expr, $zzp2:expr, $zzn:expr) => {
74 let mut yyp1: i32 = $zzp1;
75 let mut yyp2: i32 = $zzp2;
76 let mut yyn: i32 = $zzn;
77
78 while (yyn > 0) {
79 fmap.swap(yyp1 as usize, yyp2 as usize);
80 yyp1 += 1;
81 yyp2 += 1;
82 yyn -= 1;
83 }
84 };
85 }
86
87 let mut r = 0u32;
88
89 sp = 0;
90 fpush!(loSt, hiSt);
91
92 while sp > 0 {
93 assert_h!(sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004);
94
95 sp -= 1;
97 lo = stackLo[sp];
98 hi = stackHi[sp];
99
100 if hi - lo < FALLBACK_QSORT_SMALL_THRESH {
101 fallbackSimpleSort(fmap, eclass, lo, hi);
102 continue;
103 }
104
105 r = r.wrapping_mul(7621).wrapping_add(1).wrapping_rem(32768);
113 let index = match r.wrapping_rem(3) {
114 0 => fmap[lo as usize],
115 1 => fmap[((lo + hi) >> 1) as usize],
116 _ => fmap[hi as usize],
117 };
118 let med = eclass[index as usize];
119
120 ltLo = lo;
121 unLo = lo;
122
123 gtHi = hi;
124 unHi = hi;
125
126 loop {
127 while unLo <= unHi {
128 let a = eclass[fmap[unLo as usize] as usize];
129 let b = med;
130
131 if a > b {
132 break;
133 } else if a == b {
134 fmap.swap(unLo as usize, ltLo as usize);
135 ltLo += 1;
136 unLo += 1;
137 } else {
138 unLo += 1;
139 }
140 }
141
142 while unLo <= unHi {
143 let a = eclass[fmap[unHi as usize] as usize];
144 let b = med;
145
146 if a < b {
147 break;
148 } else if a == b {
149 fmap.swap(unHi as usize, gtHi as usize);
150 gtHi -= 1;
151 unHi -= 1;
152 } else {
153 unHi -= 1;
154 }
155 }
156
157 if unLo > unHi {
158 break;
159 }
160
161 fmap.swap(unLo as usize, unHi as usize);
162 unLo += 1;
163 unHi -= 1;
164 }
165
166 debug_assert_eq!(unHi, unLo - 1, "fallbackQSort3(2)");
167
168 if gtHi < ltLo {
169 continue;
170 }
171
172 n = Ord::min(ltLo - lo, unLo - ltLo);
173 fvswap!(lo, unLo - n, n);
174 m = Ord::min(hi - gtHi, gtHi - unHi);
175 fvswap!(unLo, hi - m + 1, m);
176
177 n = lo + unLo - ltLo - 1;
178 m = hi - (gtHi - unHi) + 1;
179
180 if n - lo > hi - m {
181 fpush!(lo, n);
182 fpush!(m, hi);
183 } else {
184 fpush!(m, hi);
185 fpush!(lo, n);
186 }
187 }
188}
189
190fn fallbackSort(
191 fmap: &mut [u32],
192 arr2: &mut Arr2,
193 bhtab: &mut [u32; FTAB_LEN],
194 nblock: i32,
195 verb: i32,
196) {
197 macro_rules! SET_BH {
198 ($zz:expr) => {
199 bhtab[$zz as usize >> 5] |= 1 << ($zz & 31);
200 };
201 }
202
203 macro_rules! CLEAR_BH {
204 ($zz:expr) => {
205 bhtab[$zz as usize >> 5] &= !(1 << ($zz & 31));
206 };
207 }
208
209 macro_rules! ISSET_BH {
210 ($zz:expr) => {
211 bhtab[$zz as usize >> 5] & 1u32 << ($zz & 31) != 0
212 };
213 }
214
215 macro_rules! UNALIGNED_BH {
216 ($zz:expr) => {
217 ($zz & 0x01f) != 0
218 };
219 }
220
221 macro_rules! WORD_BH {
222 ($zz:expr) => {
223 bhtab[$zz as usize >> 5]
224 };
225 }
226
227 let mut ftab: [i32; 257] = [0; 257];
228 let mut ftabCopy: [i32; 256] = [0; 256];
229 let mut H: i32;
230 let mut k: i32;
231 let mut l: i32;
232
233 if verb >= 4 {
238 debug_logln!(" bucket sorting ...");
239 }
240
241 {
242 let eclass8 = arr2.block(nblock as usize);
243
244 for e in eclass8.iter() {
245 ftab[usize::from(*e)] += 1;
246 }
247
248 ftabCopy[0..256].copy_from_slice(&ftab[0..256]);
249
250 for i in 1..257 {
251 ftab[i] += ftab[i - 1];
252 }
253
254 for (i, e) in eclass8.iter().enumerate() {
255 let j = usize::from(*e);
256 k = ftab[j] - 1;
257 ftab[j] = k;
258 fmap[k as usize] = i as u32;
259 }
260 }
261
262 bhtab[0..2 + nblock as usize / 32].fill(0);
263
264 for i in 0..256 {
265 SET_BH!(ftab[i]);
266 }
267
268 for i in 0..32 {
276 SET_BH!(nblock + 2 * i);
277 CLEAR_BH!(nblock + 2 * i + 1);
278 }
279
280 H = 1;
282 loop {
283 if verb >= 4 {
284 debug_log!(" depth {:>6} has ", H);
285 }
286 let mut j = 0;
287 for (i, x) in fmap[..nblock as usize].iter().enumerate() {
288 if ISSET_BH!(i) {
289 j = i;
290 }
291 k = x.wrapping_sub(H as c_uint) as i32;
292 if k < 0 {
293 k += nblock;
294 }
295 arr2.eclass()[k as usize] = j as u32;
296 }
297
298 let mut nNotDone = 0;
299 let mut r = -1;
300 loop {
301 k = r + 1;
303 while ISSET_BH!(k) && UNALIGNED_BH!(k) {
304 k += 1;
305 }
306 if ISSET_BH!(k) {
307 while WORD_BH!(k) == 0xffffffff {
308 k += 32;
309 }
310 while ISSET_BH!(k) {
311 k += 1;
312 }
313 }
314 l = k - 1;
315 if l >= nblock {
316 break;
317 }
318 while !ISSET_BH!(k) && UNALIGNED_BH!(k) {
319 k += 1;
320 }
321 if !ISSET_BH!(k) {
322 while WORD_BH!(k) == 0x00000000 {
323 k += 32;
324 }
325 while !ISSET_BH!(k) {
326 k += 1;
327 }
328 }
329 r = k - 1;
330 if r >= nblock {
331 break;
332 }
333
334 if r > l {
336 nNotDone += r - l + 1;
337 fallbackQSort3(fmap, arr2.eclass(), l, r);
338
339 let mut cc = -1;
341 for (i, x) in fmap[l as usize..=r as usize].iter().enumerate() {
342 let cc1 = arr2.eclass()[*x as usize] as i32;
343 if cc != cc1 {
344 SET_BH!(l + i as i32);
345 cc = cc1;
346 }
347 }
348 }
349 }
350 if verb >= 4 {
351 debug_logln!("{:>6} unresolved strings", nNotDone);
352 }
353 H *= 2;
354 if H > nblock || nNotDone == 0 {
355 break;
356 }
357 }
358
359 if verb >= 4 {
360 debug_logln!(" reconstructing block ...");
361 }
362
363 {
364 let eclass8 = arr2.block(nblock as usize);
365
366 let mut j = 0;
367 for i in 0..nblock {
368 while ftabCopy[j] == 0 {
369 j += 1;
370 }
371 ftabCopy[j] -= 1;
372 eclass8[fmap[i as usize] as usize] = j as u8;
373 }
374
375 assert_h!(j < 256, 1005);
376 }
377}
378
379#[inline]
380fn mainGtU(
381 mut i1: u32,
382 mut i2: u32,
383 block: &[u8],
384 quadrant: &[u16],
385 nblock: u32,
386 budget: &mut i32,
387) -> bool {
388 debug_assert_ne!(i1, i2, "mainGtU");
389
390 let chunk1 = &block[i1 as usize..][..12];
391 let chunk2 = &block[i2 as usize..][..12];
392
393 for (c1, c2) in chunk1.chunks_exact(4).zip(chunk2.chunks_exact(4)) {
394 let c1 = u32::from_be_bytes(c1[..4].try_into().unwrap());
395 let c2 = u32::from_be_bytes(c2[..4].try_into().unwrap());
396
397 if c1 != c2 {
398 return c1 > c2;
399 }
400 }
401
402 i1 += 12;
403 i2 += 12;
404
405 for _ in 0..nblock.div_ceil(8) {
406 let b1 = &block[i1 as usize..][..8];
407 let b2 = &block[i2 as usize..][..8];
408
409 let q1 = &quadrant[i1 as usize..][..8];
410 let q2 = &quadrant[i2 as usize..][..8];
411
412 if b1 != b2 || q1 != q2 {
413 for (((c1, c2), s1), s2) in b1.iter().zip(b2).zip(q1).zip(q2) {
414 if c1 != c2 {
415 return c1 > c2;
416 }
417 if s1 != s2 {
418 return s1 > s2;
419 }
420 }
421 }
422
423 i1 += 8;
424 i2 += 8;
425
426 if i1 >= nblock {
427 i1 = i1.wrapping_sub(nblock);
428 }
429 if i2 >= nblock {
430 i2 = i2.wrapping_sub(nblock);
431 }
432
433 *budget -= 1;
434 }
435
436 false
437}
438
439static INCS: [i32; 14] = [
440 1, 4, 13, 40, 121, 364, 1093, 3280, 9841, 29524, 88573, 265720, 797161, 2391484,
441];
442
443fn mainSimpleSort(
444 ptr: &mut [u32],
445 block: &[u8],
446 quadrant: &[u16],
447 nblock: i32,
448 lo: i32,
449 hi: i32,
450 d: i32,
451 budget: &mut i32,
452) {
453 let bigN = hi - lo + 1;
454
455 let Some(index) = INCS.iter().position(|&e| e >= bigN) else {
456 return;
457 };
458
459 for &h in INCS[..index].iter().rev() {
460 for i in lo + h..=hi {
461 let v = ptr[i as usize];
462 let mut j = i;
463 while mainGtU(
464 (ptr[(j - h) as usize]).wrapping_add(d as u32),
465 v.wrapping_add(d as u32),
466 block,
467 quadrant,
468 nblock as u32,
469 budget,
470 ) {
471 ptr[j as usize] = ptr[(j - h) as usize];
472 j -= h;
473 if j < lo + h {
474 break;
475 }
476 }
477 ptr[j as usize] = v;
478 if *budget < 0 {
479 return;
480 }
481 }
482 }
483}
484
485#[inline]
486fn median_of_3(mut a: u8, mut b: u8, mut c: u8) -> u8 {
487 if a > b {
488 (a, b) = (b, a);
489 }
490 if a > c {
491 (_, c) = (c, a);
492 }
493 if b > c {
494 (b, _) = (c, b);
495 }
496
497 debug_assert!(a <= b && b <= c);
498
499 b
500}
501
502const MAIN_QSORT_SMALL_THRESH: i32 = 20;
503const MAIN_QSORT_DEPTH_THRESH: i32 = BZ_N_RADIX + BZ_N_QSORT;
504const MAIN_QSORT_STACK_SIZE: i32 = 100;
505
506fn mainQSort3(
507 ptr: &mut [u32],
508 block: &[u8],
509 quadrant: &[u16],
510 nblock: i32,
511 loSt: i32,
512 hiSt: i32,
513 dSt: i32,
514 budget: &mut i32,
515) {
516 let mut unLo: i32;
517 let mut unHi: i32;
518 let mut ltLo: i32;
519 let mut gtHi: i32;
520 let mut n: i32;
521 let mut m: i32;
522 let mut med: i32;
523
524 let mut stack = [(0i32, 0i32, 0i32); 100];
525
526 stack[0] = (loSt, hiSt, dSt);
527
528 let mut sp = 1;
529 while sp > 0 {
530 assert_h!(sp < MAIN_QSORT_STACK_SIZE as usize - 2, 1001);
531
532 sp -= 1;
533
534 let (lo, hi, d) = stack[sp];
535
536 if hi - lo < MAIN_QSORT_SMALL_THRESH || d > MAIN_QSORT_DEPTH_THRESH {
537 mainSimpleSort(ptr, block, quadrant, nblock, lo, hi, d, budget);
538 if *budget < 0 {
539 return;
540 }
541 } else {
542 med = median_of_3(
543 block[(ptr[lo as usize]).wrapping_add(d as c_uint) as usize],
544 block[(ptr[hi as usize]).wrapping_add(d as c_uint) as usize],
545 block[((ptr[((lo + hi) >> 1) as usize]).wrapping_add(d as c_uint) as isize)
546 as usize],
547 ) as i32;
548 ltLo = lo;
549 unLo = ltLo;
550 gtHi = hi;
551 unHi = gtHi;
552 loop {
553 while unLo <= unHi {
554 n = block[(ptr[unLo as usize]).wrapping_add(d as c_uint) as usize] as i32 - med;
555 match n.cmp(&0) {
556 Ordering::Greater => break,
557 Ordering::Equal => {
558 ptr.swap(unLo as usize, ltLo as usize);
559 ltLo += 1;
560 unLo += 1;
561 }
562 Ordering::Less => unLo += 1,
563 }
564 }
565 while unLo <= unHi {
566 n = block[(ptr[unHi as usize]).wrapping_add(d as c_uint) as usize] as i32 - med;
567 match n.cmp(&0) {
568 Ordering::Less => break,
569 Ordering::Equal => {
570 ptr.swap(unHi as usize, gtHi as usize);
571 gtHi -= 1;
572 unHi -= 1;
573 }
574 Ordering::Greater => unHi -= 1,
575 }
576 }
577 if unLo > unHi {
578 break;
579 }
580 ptr.swap(unLo as usize, unHi as usize);
581 unLo += 1;
582 unHi -= 1;
583 }
584 if gtHi < ltLo {
585 stack[sp] = (lo, hi, d + 1);
586 sp += 1;
587 } else {
588 n = Ord::min(ltLo - lo, unLo - ltLo);
589 let mut yyp1: i32 = lo;
590 let mut yyp2: i32 = unLo - n;
591 for _ in 0..n {
592 ptr.swap(yyp1 as usize, yyp2 as usize);
593 yyp1 += 1;
594 yyp2 += 1;
595 }
596
597 m = Ord::min(hi - gtHi, gtHi - unHi);
598 let mut yyp1_0: i32 = unLo;
599 let mut yyp2_0: i32 = hi - m + 1;
600 for _ in 0..m {
601 ptr.swap(yyp1_0 as usize, yyp2_0 as usize);
602 yyp1_0 += 1;
603 yyp2_0 += 1;
604 }
605
606 n = lo + unLo - ltLo - 1;
607 m = hi - (gtHi - unHi) + 1;
608
609 let mut next = [(lo, n, d), (m, hi, d), (n + 1, m - 1, d + 1)];
610
611 if next[0].1 - next[0].0 < next[1].1 - next[1].0 {
612 next.swap(0, 1);
613 }
614
615 if next[1].1 - next[1].0 < next[2].1 - next[2].0 {
616 next.swap(1, 2);
617 }
618
619 if next[0].1 - next[0].0 < next[1].1 - next[1].0 {
620 next.swap(0, 1);
621 }
622
623 stack[sp..][..next.len()].copy_from_slice(&next);
624 sp += next.len();
625 }
626 }
627 }
628}
629fn mainSort(
630 ptr: &mut [u32],
631 block: &mut [u8],
632 quadrant: &mut [u16],
633 ftab: &mut [u32; FTAB_LEN],
634 nblock: i32,
635 verb: i32,
636 budget: &mut i32,
637) {
638 let mut j: i32;
639 let mut k: i32;
640 let mut ss: i32;
641 let mut sb: i32;
642 let mut bigDone: [bool; 256] = [false; 256];
643 let mut copyStart: [i32; 256] = [0; 256];
644 let mut copyEnd: [i32; 256] = [0; 256];
645 let mut c1: u8;
646 let mut numQSorted: i32;
647 let mut s: u16;
648 if verb >= 4 as c_int {
649 debug_logln!(" main sort initialise ...");
650 }
651
652 ftab.fill(0);
654
655 j = (block[0] as i32) << 8;
656 for &block in block[..nblock as usize].iter().rev() {
657 j = (j >> 8) | (i32::from(block) << 8);
658 ftab[j as usize] += 1;
659 }
660
661 for i in 0..BZ_N_OVERSHOOT {
662 block[nblock as usize + i] = block[i];
663 }
664
665 if verb >= 4 as c_int {
666 debug_logln!(" bucket sorting ...");
667 }
668
669 for i in 1..=65536 {
671 ftab[i] += ftab[i - 1];
672 }
673
674 s = ((block[0 as c_int as usize] as c_int) << 8 as c_int) as u16;
675
676 for (i, &block) in block[..nblock as usize].iter().enumerate().rev() {
677 s = (s >> 8) | (u16::from(block) << 8);
678 j = ftab[usize::from(s)] as i32 - 1;
679 ftab[usize::from(s)] = j as u32;
680 ptr[j as usize] = i as u32;
681 }
682
683 bigDone.fill(false);
684 let mut runningOrder: [i32; 256] = core::array::from_fn(|i| i as i32);
685
686 let mut vv: i32;
687 let mut h: i32 = 1 as c_int;
688 loop {
689 h = 3 as c_int * h + 1 as c_int;
690 if h > 256 as c_int {
691 break;
692 }
693 }
694
695 macro_rules! BIGFREQ {
696 ($b:expr) => {
697 ftab[(($b) + 1) << 8] - ftab[($b) << 8]
698 };
699 }
700
701 loop {
702 h /= 3 as c_int;
703 for i in h..256 {
704 vv = runningOrder[i as usize];
705 j = i;
706 while BIGFREQ!(runningOrder[(j - h) as usize] as usize) > BIGFREQ!(vv as usize) {
707 runningOrder[j as usize] = runningOrder[(j - h) as usize];
708 j -= h;
709 if j <= h - 1 as c_int {
710 break;
711 }
712 }
713 runningOrder[j as usize] = vv;
714 }
715 if h == 1 as c_int {
716 break;
717 }
718 }
719
720 numQSorted = 0 as c_int;
725
726 for i in 0..=255 {
727 ss = runningOrder[i as usize];
734
735 const SETMASK: u32 = 1 << 21;
736 const CLEARMASK: u32 = !SETMASK;
737
738 for j in 0..=255 {
747 if j != ss {
748 sb = (ss << 8 as c_int) + j;
749 if ftab[sb as usize] & SETMASK == 0 {
750 let lo: i32 = (ftab[sb as usize] & CLEARMASK) as i32;
751 let hi: i32 = ((ftab[sb as usize + 1] & CLEARMASK).wrapping_sub(1)) as i32;
752
753 if hi > lo {
754 if verb >= 4 as c_int {
755 debug_logln!(
756 " qsort [{:#x}, {:#x}] done {} this {}",
757 ss,
758 j,
759 numQSorted,
760 hi - lo + 1 as c_int,
761 );
762 }
763 mainQSort3(ptr, block, quadrant, nblock, lo, hi, 2 as c_int, budget);
764 numQSorted += hi - lo + 1 as c_int;
765 if *budget < 0 as c_int {
766 return;
767 }
768 }
769 }
770 ftab[sb as usize] |= SETMASK;
771 }
772 }
773 assert_h!(!bigDone[ss as usize], 1006);
774
775 {
783 for j in 0..=255 {
784 copyStart[j] = (ftab[(j << 8) + ss as usize] & CLEARMASK) as i32;
785 copyEnd[j] = (ftab[(j << 8) + ss as usize + 1] & CLEARMASK) as i32 - 1;
786 }
787
788 j = (ftab[(ss as usize) << 8] & CLEARMASK) as i32;
789 while j < copyStart[ss as usize] {
790 k = (ptr[j as usize]).wrapping_sub(1) as i32;
791 if k < 0 as c_int {
792 k += nblock;
793 }
794 c1 = block[k as usize];
795 if !bigDone[c1 as usize] {
796 let fresh11 = copyStart[c1 as usize];
797 copyStart[c1 as usize] += 1;
798 ptr[fresh11 as usize] = k as u32;
799 }
800 j += 1;
801 }
802
803 j = (ftab[(ss as usize + 1) << 8] & CLEARMASK) as i32 - 1;
804 while j > copyEnd[ss as usize] {
805 k = (ptr[j as usize]).wrapping_sub(1) as i32;
806 if k < 0 as c_int {
807 k += nblock;
808 }
809 c1 = block[k as usize];
810 if !bigDone[c1 as usize] {
811 let fresh12 = copyEnd[c1 as usize];
812 copyEnd[c1 as usize] -= 1;
813 ptr[fresh12 as usize] = k as u32;
814 }
815 j -= 1;
816 }
817 }
818
819 assert_h!(
820 (copyStart[ss as usize]-1 == copyEnd[ss as usize])
821 ||
822 (copyStart[ss as usize] == 0 && copyEnd[ss as usize] == nblock-1),
827 1007
828 );
829
830 for j in 0..=255 {
831 ftab[(j << 8) + ss as usize] |= SETMASK
832 }
833
834 bigDone[ss as usize] = true;
874
875 if i < 255 as c_int {
876 let bbStart: i32 = (ftab[(ss as usize) << 8] & CLEARMASK) as i32;
877 let bbSize: i32 = (ftab[(ss as usize + 1) << 8] & CLEARMASK) as i32 - bbStart;
878 let mut shifts: i32 = 0 as c_int;
879
880 while bbSize >> shifts > 65534 as c_int {
881 shifts += 1;
882 }
883
884 j = bbSize - 1 as c_int;
885 while j >= 0 as c_int {
886 let a2update: i32 = ptr[(bbStart + j) as usize] as i32;
887 let qVal: u16 = (j >> shifts) as u16;
888 quadrant[a2update as usize] = qVal;
889 if (a2update as usize) < BZ_N_OVERSHOOT {
890 quadrant[(a2update + nblock) as usize] = qVal;
891 }
892 j -= 1;
893 }
894
895 assert_h!(((bbSize - 1) >> shifts) <= 65535, 1002);
896 }
897 }
898 if verb >= 4 as c_int {
899 debug_logln!(
900 " {} pointers, {} sorted, {} scanned",
901 nblock,
902 numQSorted,
903 nblock - numQSorted,
904 );
905 }
906}
907
908pub(crate) fn block_sort(s: &mut EState) {
920 let nblock = usize::try_from(s.nblock).unwrap();
921
922 let ptr = s.arr1.ptr();
923 let ftab = s.ftab.ftab();
924
925 BZ2_blockSortHelp(ptr, &mut s.arr2, ftab, nblock, s.workFactor, s.verbosity);
926
927 s.origPtr = -1 as c_int;
928 for i in 0..s.nblock {
929 if ptr[i as usize] == 0 {
930 s.origPtr = i;
931 break;
932 }
933 }
934
935 assert_h!(s.origPtr != -1, 1003);
936}
937
938fn BZ2_blockSortHelp(
939 ptr: &mut [u32],
940 arr2: &mut Arr2,
941 ftab: &mut [u32; FTAB_LEN],
942 nblock: usize,
943 workFactor: i32,
944 verbosity: i32,
945) {
946 if nblock < 10000 {
947 fallbackSort(ptr, arr2, ftab, nblock as i32, verbosity);
948 } else {
949 let (block, quadrant) = arr2.block_and_quadrant(nblock);
950
951 let wfact = workFactor.clamp(1, 100);
959 let budgetInit = nblock as i32 * ((wfact - 1) / 3);
960 let mut budget = budgetInit;
961
962 mainSort(
963 ptr,
964 block,
965 quadrant,
966 ftab,
967 nblock as i32,
968 verbosity,
969 &mut budget,
970 );
971
972 if verbosity >= 3 {
973 debug_logln!(
974 " {} work, {} block, ratio {:5.2}",
975 budgetInit - budget,
976 nblock,
977 (budgetInit - budget) as f64 / (if nblock == 0 { 1 } else { nblock }) as f64
978 );
979 }
980
981 if budget < 0 {
982 if verbosity >= 2 as c_int {
983 debug_logln!(" too repetitive; using fallback sorting algorithm");
984 }
985
986 fallbackSort(ptr, arr2, ftab, nblock as i32, verbosity);
987 }
988 }
989}