1#[cfg(feature = "simd_sse2")]
4use crate::sse2::*;
5
6#[cfg(feature = "simd_avx2")]
7use crate::avx2::*;
8
9#[cfg(feature = "simd_wasm")]
10use crate::simd128::*;
11
12#[cfg(feature = "simd_neon")]
13use crate::neon::*;
14
15use std::i8;
16
17pub trait Matrix {
18 const NULL: u8;
20 fn new() -> Self;
24 fn set(&mut self, a: u8, b: u8, score: i8);
26 fn get(&self, a: u8, b: u8) -> i8;
28 fn as_ptr(&self, i: usize) -> *const i8;
30 unsafe fn get_scores(&self, c: u8, v: HalfSimd, right: bool) -> Simd;
32 fn convert_char(c: u8) -> u8;
35}
36
37#[repr(C, align(32))]
41#[derive(Clone, PartialEq, Debug)]
42pub struct AAMatrix {
43 scores: [i8; 27 * 32]
44}
45
46impl AAMatrix {
47 pub const fn new_simple(match_score: i8, mismatch_score: i8) -> Self {
49 let mut scores = [i8::MIN; 27 * 32];
50 let mut i = b'A';
51 while i <= b'Z' {
52 let mut j = b'A';
53 while j <= b'Z' {
54 let idx = ((i - b'A') as usize) * 32 + ((j - b'A') as usize);
55 scores[idx] = if i == j { match_score } else { mismatch_score };
56 j += 1;
57 }
58 i += 1;
59 }
60 Self { scores }
61 }
62
63 pub fn from_tsv(tsv: &str, aa_order: &str) -> Self {
67 let tsv = tsv.trim();
68 let aa_order = aa_order.split_ascii_whitespace().map(|s| s.as_bytes()[0]).collect::<Vec<_>>();
69 let mut res = Self::new();
70
71 for (line, &a) in tsv.split("\n").zip(&aa_order) {
72 for (score, &b) in line.split_ascii_whitespace().zip(&aa_order) {
73 let score = score.parse::<i8>().unwrap();
74 res.set(a, b, score);
75 }
76 }
77
78 res
79 }
80}
81
82impl Matrix for AAMatrix {
83 const NULL: u8 = b'A' + 26u8;
84
85 fn new() -> Self {
86 Self { scores: [i8::MIN; 27 * 32] }
87 }
88
89 fn set(&mut self, a: u8, b: u8, score: i8) {
90 let a = a.to_ascii_uppercase();
91 let b = b.to_ascii_uppercase();
92 assert!(b'A' <= a && a <= b'Z' + 1);
93 assert!(b'A' <= b && b <= b'Z' + 1);
94 let idx = ((a - b'A') as usize) * 32 + ((b - b'A') as usize);
95 self.scores[idx] = score;
96 let idx = ((b - b'A') as usize) * 32 + ((a - b'A') as usize);
97 self.scores[idx] = score;
98 }
99
100 fn get(&self, a: u8, b: u8) -> i8 {
101 let a = a.to_ascii_uppercase();
102 let b = b.to_ascii_uppercase();
103 assert!(b'A' <= a && a <= b'Z' + 1);
104 assert!(b'A' <= b && b <= b'Z' + 1);
105 let idx = ((a - b'A') as usize) * 32 + ((b - b'A') as usize);
106 self.scores[idx]
107 }
108
109 #[inline]
110 fn as_ptr(&self, i: usize) -> *const i8 {
111 debug_assert!(i < 27);
112 unsafe { self.scores.as_ptr().add(i * 32) }
113 }
114
115 #[cfg_attr(feature = "simd_sse2", target_feature(enable = "sse2"))]
117 #[cfg_attr(feature = "simd_avx2", target_feature(enable = "avx2"))]
118 #[cfg_attr(feature = "simd_wasm", target_feature(enable = "simd128"))]
119 #[cfg_attr(feature = "simd_neon", target_feature(enable = "neon"))]
120 #[inline]
121 unsafe fn get_scores(&self, c: u8, v: HalfSimd, _right: bool) -> Simd {
122 let matrix_ptr = self.as_ptr(c as usize);
124 let scores1 = lutsimd_load(matrix_ptr as *const LutSimd);
125 let scores2 = lutsimd_load((matrix_ptr as *const LutSimd).add(1));
126 halfsimd_lookup2_i16(scores1, scores2, v)
127 }
128
129 #[inline]
130 fn convert_char(c: u8) -> u8 {
131 let c = c.to_ascii_uppercase();
132 assert!(c >= b'A' && c <= Self::NULL);
133 c - b'A'
134 }
135}
136
137#[repr(C, align(32))]
143#[derive(Clone, PartialEq, Debug)]
144pub struct NucMatrix {
145 scores: [i8; 8 * 16]
146}
147
148impl NucMatrix {
149 pub const fn new_simple(match_score: i8, mismatch_score: i8) -> Self {
151 let mut scores = [i8::MIN; 8 * 16];
152 let alpha = [b'A', b'T', b'C', b'G', b'N'];
153 let mut i = 0;
154 while i < alpha.len() {
155 let mut j = 0;
156 while j < alpha.len() {
157 let idx = ((alpha[i] & 0b111) as usize) * 16 + ((alpha[j] & 0b1111) as usize);
158 scores[idx] = if i == j { match_score } else { mismatch_score };
159 j += 1;
160 }
161 i += 1;
162 }
163 Self { scores }
164 }
165}
166
167impl Matrix for NucMatrix {
168 const NULL: u8 = b'Z';
169
170 fn new() -> Self {
171 Self { scores: [i8::MIN; 8 * 16] }
172 }
173
174 fn set(&mut self, a: u8, b: u8, score: i8) {
175 let a = a.to_ascii_uppercase();
176 let b = b.to_ascii_uppercase();
177 assert!(b'A' <= a && a <= b'Z');
178 assert!(b'A' <= b && b <= b'Z');
179 let idx = ((a & 0b111) as usize) * 16 + ((b & 0b1111) as usize);
180 self.scores[idx] = score;
181 let idx = ((b & 0b111) as usize) * 16 + ((a & 0b1111) as usize);
182 self.scores[idx] = score;
183 }
184
185 fn get(&self, a: u8, b: u8) -> i8 {
186 let a = a.to_ascii_uppercase();
187 let b = b.to_ascii_uppercase();
188 assert!(b'A' <= a && a <= b'Z');
189 assert!(b'A' <= b && b <= b'Z');
190 let idx = ((a & 0b111) as usize) * 16 + ((b & 0b1111) as usize);
191 self.scores[idx]
192 }
193
194 #[inline]
195 fn as_ptr(&self, i: usize) -> *const i8 {
196 unsafe { self.scores.as_ptr().add((i & 0b111) * 16) }
197 }
198
199 #[cfg_attr(feature = "simd_sse2", target_feature(enable = "sse2"))]
200 #[cfg_attr(feature = "simd_avx2", target_feature(enable = "avx2"))]
201 #[cfg_attr(feature = "simd_wasm", target_feature(enable = "simd128"))]
202 #[cfg_attr(feature = "simd_neon", target_feature(enable = "neon"))]
203 #[inline]
204 unsafe fn get_scores(&self, c: u8, v: HalfSimd, _right: bool) -> Simd {
205 let matrix_ptr = self.as_ptr(c as usize);
207 let scores = lutsimd_load(matrix_ptr as *const LutSimd);
208 halfsimd_lookup1_i16(scores, v)
209 }
210
211 #[inline]
212 fn convert_char(c: u8) -> u8 {
213 let c = c.to_ascii_uppercase();
214 assert!(c >= b'A' && c <= Self::NULL);
215 c
216 }
217}
218
219#[repr(C)]
221#[derive(Clone, PartialEq, Debug)]
222pub struct ByteMatrix {
223 match_score: i8,
224 mismatch_score: i8
225}
226
227impl ByteMatrix {
228 pub const fn new_simple(match_score: i8, mismatch_score: i8) -> Self {
230 Self { match_score, mismatch_score }
231 }
232}
233
234impl Matrix for ByteMatrix {
235 const NULL: u8 = b'\0';
240
241 fn new() -> Self {
242 Self { match_score: i8::MIN, mismatch_score: i8::MIN }
243 }
244
245 fn set(&mut self, _a: u8, _b: u8, _score: i8) {
246 unimplemented!();
247 }
248
249 fn get(&self, a: u8, b: u8) -> i8 {
250 if a == b { self.match_score } else { self.mismatch_score }
251 }
252
253 #[inline]
254 fn as_ptr(&self, _i: usize) -> *const i8 {
255 unimplemented!()
256 }
257
258 #[cfg_attr(feature = "simd_sse2", target_feature(enable = "sse2"))]
259 #[cfg_attr(feature = "simd_avx2", target_feature(enable = "avx2"))]
260 #[cfg_attr(feature = "simd_wasm", target_feature(enable = "simd128"))]
261 #[cfg_attr(feature = "simd_neon", target_feature(enable = "neon"))]
262 #[inline]
263 unsafe fn get_scores(&self, c: u8, v: HalfSimd, _right: bool) -> Simd {
264 let match_scores = halfsimd_set1_i8(self.match_score);
265 let mismatch_scores = halfsimd_set1_i8(self.mismatch_score);
266 halfsimd_lookup_bytes_i16(match_scores, mismatch_scores, halfsimd_set1_i8(c as i8), v)
267 }
268
269 #[inline]
270 fn convert_char(c: u8) -> u8 {
271 c
272 }
273}
274
275#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
277pub static NW1: NucMatrix = NucMatrix::new_simple(1, -1);
278
279#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
280pub static BLOSUM45: AAMatrix = AAMatrix { scores: include!("../matrices/BLOSUM45") };
281
282#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
283pub static BLOSUM50: AAMatrix = AAMatrix { scores: include!("../matrices/BLOSUM50") };
284
285#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
286pub static BLOSUM62: AAMatrix = AAMatrix { scores: include!("../matrices/BLOSUM62") };
287
288#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
289pub static BLOSUM80: AAMatrix = AAMatrix { scores: include!("../matrices/BLOSUM80") };
290
291#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
292pub static BLOSUM90: AAMatrix = AAMatrix { scores: include!("../matrices/BLOSUM90") };
293
294#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
295pub static PAM100: AAMatrix = AAMatrix { scores: include!("../matrices/PAM100") };
296
297#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
298pub static PAM120: AAMatrix = AAMatrix { scores: include!("../matrices/PAM120") };
299
300#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
301pub static PAM160: AAMatrix = AAMatrix { scores: include!("../matrices/PAM160") };
302
303#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
304pub static PAM200: AAMatrix = AAMatrix { scores: include!("../matrices/PAM200") };
305
306#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
307pub static PAM250: AAMatrix = AAMatrix { scores: include!("../matrices/PAM250") };
308
309#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
311pub static BYTES1: ByteMatrix = ByteMatrix::new_simple(1, -1);
312
313#[derive(Copy, Clone, PartialEq, Debug)]
334#[repr(C)]
335pub struct Gaps {
336 pub open: i8,
337 pub extend: i8
338}
339
340#[allow(non_snake_case)]
341pub trait Profile {
342 const NULL: u8;
344
345 fn new(str_len: usize, block_size: usize, gap_extend: i8) -> Self;
353 fn from_bytes(b: &[u8], block_size: usize, match_score: i8, mismatch_score: i8, gap_open_C: i8, gap_close_C: i8, gap_open_R: i8, gap_extend: i8) -> Self;
355
356 fn len(&self) -> usize;
358 fn clear(&mut self, str_len: usize, block_size: usize);
361
362 fn set(&mut self, i: usize, b: u8, score: i8);
369 fn set_all(&mut self, order: &[u8], scores: &[i8], left_shift: usize, right_shift: usize);
379 fn set_all_rev(&mut self, order: &[u8], scores: &[i8], left_shift: usize, right_shift: usize);
389
390 fn set_gap_open_C(&mut self, i: usize, gap: i8);
396 fn set_gap_close_C(&mut self, i: usize, gap: i8);
402 fn set_gap_open_R(&mut self, i: usize, gap: i8);
408
409 fn set_all_gap_open_C(&mut self, gap: i8);
411 fn set_all_gap_close_C(&mut self, gap: i8);
413 fn set_all_gap_open_R(&mut self, gap: i8);
415
416 fn get(&self, i: usize, b: u8) -> i8;
418 fn get_gap_extend(&self) -> i8;
420 fn as_ptr_pos(&self, i: usize) -> *const i8;
422 fn as_ptr_aa(&self, a: usize) -> *const i16;
424
425 unsafe fn get_scores_pos(&self, i: usize, v: HalfSimd, right: bool) -> Simd;
427 unsafe fn get_scores_aa(&self, i: usize, c: u8, right: bool) -> Simd;
429
430 unsafe fn get_gap_open_right_C(&self, i: usize) -> Simd;
432 unsafe fn get_gap_close_right_C(&self, i: usize) -> Simd;
434 unsafe fn get_gap_open_right_R(&self, i: usize) -> Simd;
436
437 unsafe fn get_gap_open_down_C(&self, i: usize) -> Simd;
439 unsafe fn get_gap_close_down_C(&self, i: usize) -> Simd;
441 unsafe fn get_gap_open_down_R(&self, i: usize) -> Simd;
443
444 fn convert_char(c: u8) -> u8;
447}
448
449#[allow(non_snake_case)]
453#[derive(Clone, PartialEq, Debug)]
454pub struct AAProfile {
455 aa_pos: Vec<i16>,
456 pos_aa: Vec<i8>,
457 gap_extend: i8,
458 pos_gap_open_C: Vec<i16>,
459 pos_gap_close_C: Vec<i16>,
460 pos_gap_open_R: Vec<i16>,
461 max_len: usize,
463 curr_len: usize,
465 str_len: usize
468}
469
470impl Profile for AAProfile {
471 const NULL: u8 = b'A' + 26u8;
472
473 fn new(str_len: usize, block_size: usize, gap_extend: i8) -> Self {
474 let max_len = str_len + block_size + 1;
475 Self {
476 aa_pos: vec![i8::MIN as i16; 32 * max_len],
477 pos_aa: vec![i8::MIN; max_len * 32],
478 gap_extend,
479 pos_gap_open_C: vec![i8::MIN as i16; max_len],
480 pos_gap_close_C: vec![i8::MIN as i16; max_len],
481 pos_gap_open_R: vec![i8::MIN as i16; max_len],
482 max_len,
483 curr_len: max_len,
484 str_len
485 }
486 }
487
488 #[allow(non_snake_case)]
489 fn from_bytes(b: &[u8], block_size: usize, match_score: i8, mismatch_score: i8, gap_open_C: i8, gap_close_C: i8, gap_open_R: i8, gap_extend: i8) -> Self {
490 let mut res = Self::new(b.len(), block_size, gap_extend);
491
492 for i in 0..b.len() {
493 for c in b'A'..=b'Z' {
494 res.set(i + 1, c, if c == b[i] { match_score } else { mismatch_score });
495 }
496 }
497
498 for i in 0..b.len() + 1 {
499 res.set_gap_open_C(i, gap_open_C);
500 res.set_gap_close_C(i, gap_close_C);
501 res.set_gap_open_R(i, gap_open_R);
502 }
503
504 res
505 }
506
507 fn len(&self) -> usize {
508 self.str_len
509 }
510
511 fn clear(&mut self, str_len: usize, block_size: usize) {
512 let curr_len = str_len + block_size + 1;
513 assert!(curr_len <= self.max_len);
514 self.aa_pos[..32 * curr_len].fill(i8::MIN as i16);
515 self.pos_aa[..curr_len * 32].fill(i8::MIN);
516 self.pos_gap_open_C[..curr_len].fill(i8::MIN as i16);
517 self.pos_gap_close_C[..curr_len].fill(i8::MIN as i16);
518 self.pos_gap_open_R[..curr_len].fill(i8::MIN as i16);
519 self.str_len = str_len;
520 self.curr_len = curr_len;
521 }
522
523 fn set(&mut self, i: usize, b: u8, score: i8) {
524 let b = b.to_ascii_uppercase();
525 assert!(b'A' <= b && b <= b'Z' + 1);
526 let idx = i * 32 + ((b - b'A') as usize);
527 self.pos_aa[idx] = score;
528 let idx = ((b - b'A') as usize) * self.curr_len + i;
529 self.aa_pos[idx] = score as i16;
530 }
531
532 fn set_all(&mut self, order: &[u8], scores: &[i8], left_shift: usize, right_shift: usize) {
533 self.set_all_core::<false>(order, scores, left_shift, right_shift);
534 }
535
536 fn set_all_rev(&mut self, order: &[u8], scores: &[i8], left_shift: usize, right_shift: usize) {
537 self.set_all_core::<true>(order, scores, left_shift, right_shift);
538 }
539
540 fn set_gap_open_C(&mut self, i: usize, gap: i8) {
541 assert!(gap < 0, "Gap open cost must be negative!");
542 self.pos_gap_open_C[i] = gap as i16;
543 }
544
545 fn set_gap_close_C(&mut self, i: usize, gap: i8) {
546 self.pos_gap_close_C[i] = gap as i16;
547 }
548
549 fn set_gap_open_R(&mut self, i: usize, gap: i8) {
550 assert!(gap < 0, "Gap open cost must be negative!");
551 self.pos_gap_open_R[i] = gap as i16;
552 }
553
554 fn set_all_gap_open_C(&mut self, gap: i8) {
555 assert!(gap < 0, "Gap open cost must be negative!");
556 self.pos_gap_open_C[..self.str_len + 1].fill(gap as i16);
557 }
558
559 fn set_all_gap_close_C(&mut self, gap: i8) {
560 self.pos_gap_close_C[..self.str_len + 1].fill(gap as i16);
561 }
562
563 fn set_all_gap_open_R(&mut self, gap: i8) {
564 assert!(gap < 0, "Gap open cost must be negative!");
565 self.pos_gap_open_R[..self.str_len + 1].fill(gap as i16);
566 }
567
568 fn get(&self, i: usize, b: u8) -> i8 {
569 let b = b.to_ascii_uppercase();
570 assert!(b'A' <= b && b <= b'Z' + 1);
571 let idx = i * 32 + ((b - b'A') as usize);
572 self.pos_aa[idx]
573 }
574
575 fn get_gap_extend(&self) -> i8 {
576 self.gap_extend
577 }
578
579 #[inline]
580 fn as_ptr_pos(&self, i: usize) -> *const i8 {
581 debug_assert!(i < self.curr_len);
582 unsafe { self.pos_aa.as_ptr().add(i * 32) }
583 }
584
585 #[inline]
586 fn as_ptr_aa(&self, a: usize) -> *const i16 {
587 debug_assert!(a < 27);
588 unsafe { self.aa_pos.as_ptr().add(a * self.curr_len) }
589 }
590
591 #[cfg_attr(feature = "simd_sse2", target_feature(enable = "sse2"))]
592 #[cfg_attr(feature = "simd_avx2", target_feature(enable = "avx2"))]
593 #[cfg_attr(feature = "simd_wasm", target_feature(enable = "simd128"))]
594 #[cfg_attr(feature = "simd_neon", target_feature(enable = "neon"))]
595 #[inline]
596 unsafe fn get_scores_pos(&self, i: usize, v: HalfSimd, _right: bool) -> Simd {
597 let matrix_ptr = self.as_ptr_pos(i);
599 let scores1 = lutsimd_loadu(matrix_ptr as *const LutSimd);
600 let scores2 = lutsimd_loadu((matrix_ptr as *const LutSimd).add(1));
601 halfsimd_lookup2_i16(scores1, scores2, v)
602 }
603
604 #[cfg_attr(feature = "simd_sse2", target_feature(enable = "sse2"))]
605 #[cfg_attr(feature = "simd_avx2", target_feature(enable = "avx2"))]
606 #[cfg_attr(feature = "simd_wasm", target_feature(enable = "simd128"))]
607 #[cfg_attr(feature = "simd_neon", target_feature(enable = "neon"))]
608 #[inline]
609 unsafe fn get_scores_aa(&self, i: usize, c: u8, _right: bool) -> Simd {
610 let matrix_ptr = self.as_ptr_aa(c as usize);
611 simd_loadu(matrix_ptr.add(i) as *const Simd)
612 }
613
614 #[cfg_attr(feature = "simd_sse2", target_feature(enable = "sse2"))]
615 #[cfg_attr(feature = "simd_avx2", target_feature(enable = "avx2"))]
616 #[cfg_attr(feature = "simd_wasm", target_feature(enable = "simd128"))]
617 #[cfg_attr(feature = "simd_neon", target_feature(enable = "neon"))]
618 #[inline]
619 unsafe fn get_gap_open_right_C(&self, i: usize) -> Simd {
620 simd_set1_i16(*self.pos_gap_open_C.as_ptr().add(i))
621 }
622
623 #[cfg_attr(feature = "simd_sse2", target_feature(enable = "sse2"))]
624 #[cfg_attr(feature = "simd_avx2", target_feature(enable = "avx2"))]
625 #[cfg_attr(feature = "simd_wasm", target_feature(enable = "simd128"))]
626 #[cfg_attr(feature = "simd_neon", target_feature(enable = "neon"))]
627 #[inline]
628 unsafe fn get_gap_close_right_C(&self, i: usize) -> Simd {
629 simd_set1_i16(*self.pos_gap_close_C.as_ptr().add(i))
630 }
631
632 #[cfg_attr(feature = "simd_sse2", target_feature(enable = "sse2"))]
633 #[cfg_attr(feature = "simd_avx2", target_feature(enable = "avx2"))]
634 #[cfg_attr(feature = "simd_wasm", target_feature(enable = "simd128"))]
635 #[cfg_attr(feature = "simd_neon", target_feature(enable = "neon"))]
636 #[inline]
637 unsafe fn get_gap_open_right_R(&self, i: usize) -> Simd {
638 simd_set1_i16(*self.pos_gap_open_R.as_ptr().add(i))
639 }
640
641 #[cfg_attr(feature = "simd_sse2", target_feature(enable = "sse2"))]
642 #[cfg_attr(feature = "simd_avx2", target_feature(enable = "avx2"))]
643 #[cfg_attr(feature = "simd_wasm", target_feature(enable = "simd128"))]
644 #[cfg_attr(feature = "simd_neon", target_feature(enable = "neon"))]
645 #[inline]
646 unsafe fn get_gap_open_down_C(&self, i: usize) -> Simd {
647 simd_loadu(self.pos_gap_open_C.as_ptr().add(i) as *const Simd)
648 }
649
650 #[cfg_attr(feature = "simd_sse2", target_feature(enable = "sse2"))]
651 #[cfg_attr(feature = "simd_avx2", target_feature(enable = "avx2"))]
652 #[cfg_attr(feature = "simd_wasm", target_feature(enable = "simd128"))]
653 #[cfg_attr(feature = "simd_neon", target_feature(enable = "neon"))]
654 #[inline]
655 unsafe fn get_gap_close_down_C(&self, i: usize) -> Simd {
656 simd_loadu(self.pos_gap_close_C.as_ptr().add(i) as *const Simd)
657 }
658
659 #[cfg_attr(feature = "simd_sse2", target_feature(enable = "sse2"))]
660 #[cfg_attr(feature = "simd_avx2", target_feature(enable = "avx2"))]
661 #[cfg_attr(feature = "simd_wasm", target_feature(enable = "simd128"))]
662 #[cfg_attr(feature = "simd_neon", target_feature(enable = "neon"))]
663 #[inline]
664 unsafe fn get_gap_open_down_R(&self, i: usize) -> Simd {
665 simd_loadu(self.pos_gap_open_R.as_ptr().add(i) as *const Simd)
666 }
667
668 #[inline]
669 fn convert_char(c: u8) -> u8 {
670 let c = c.to_ascii_uppercase();
671 assert!(c >= b'A' && c <= Self::NULL);
672 c - b'A'
673 }
674}
675
676impl AAProfile {
677 fn set_all_core<const REV: bool>(&mut self, order: &[u8], scores: &[i8], left_shift: usize, right_shift: usize) {
678 #[repr(align(32))]
679 struct A([u8; 32]);
680 let mut o = A([Self::NULL - b'A'; 32]);
681 assert!(order.len() <= 32);
682
683 for (i, &b) in order.iter().enumerate() {
684 let b = b.to_ascii_uppercase();
685 assert!(b'A' <= b && b <= b'Z' + 1);
686 o.0[i] = b - b'A';
687 }
688 assert_eq!(scores.len() / order.len(), self.str_len);
689
690 let mut i = if REV { self.str_len } else { 1 };
691 let mut score_idx = 0;
692
693 while if REV { i >= 1 } else { i <= self.str_len } {
694 let mut j = 0;
695
696 while j < order.len() {
697 unsafe {
698 let score = ((*scores.as_ptr().add(score_idx)) << left_shift) >> right_shift;
699 let b = *o.0.as_ptr().add(j) as usize;
700 *self.pos_aa.as_mut_ptr().add(i * 32 + b) = score;
701 *self.aa_pos.as_mut_ptr().add(b * self.curr_len + i) = score as i16;
702 }
703
704 score_idx += 1;
705 j += 1;
706 }
707
708 if REV {
709 i -= 1;
710 } else {
711 i += 1;
712 }
713 }
714 }
715}