Skip to content

Commit c49eb0f

Browse files
PackedNSeqVec::push_from_ascii_and_quality
1 parent afec41c commit c49eb0f

1 file changed

Lines changed: 32 additions & 0 deletions

File tree

src/packed_n_seq.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,36 @@ impl PackedNSeqVec {
102102
ambiguous,
103103
}
104104
}
105+
106+
/// Create a mask that is 1 for all non-ACGT bases and for all low-quality bases with quality `<threshold`.
107+
pub fn push_from_ascii_and_quality(&mut self, seq: &[u8], quality: &[u8], threshold: usize) {
108+
let r = self.seq.push_ascii(seq);
109+
let r2 = self.ambiguous.push_ascii(seq);
110+
assert_eq!(r, r2);
111+
112+
assert_eq!(seq.len(), quality.len());
113+
114+
// Low-quality bases are also ambiguous.
115+
let t = b'!' + threshold as u8;
116+
let t_simd = i8x32::splat(t as i8);
117+
118+
let mut idx = r2.start;
119+
let mut i = 0;
120+
while idx % 8 != 0 {
121+
self.ambiguous.seq[idx / 8] |= ((quality[i] < t) as u8) << (idx % 8);
122+
idx += 1;
123+
i += 1;
124+
}
125+
let quality = &quality[i..];
126+
127+
let ambiguous = self.ambiguous.seq[idx / 8..].as_chunks_mut::<4>().0;
128+
for i in (0..quality.len()).step_by(32) {
129+
let chunk =
130+
i8x32::from(unsafe { std::mem::transmute::<_, i8x32>(read_slice_32(quality, i)) });
131+
132+
let mask = t_simd.cmp_lt(chunk).move_mask() as u32;
133+
let ambi = &mut ambiguous[i / 32];
134+
*ambi = (u32::from_ne_bytes(*ambi) | mask).to_ne_bytes();
135+
}
136+
}
105137
}

0 commit comments

Comments
 (0)