#[cfg(all(target_arch = "aarch64", not(feature = "nosimd")))]
mod aarch64;
#[cfg(all(target_arch = "x86_64", not(feature = "nosimd")))]
mod avx;
mod naive;
use crate::Error;
pub fn from_2bit_multi(ebuf: &[u64], n_bases: usize, dbuf: &mut Vec<u8>) -> Result<(), Error> {
#[cfg(all(target_arch = "aarch64", not(feature = "nosimd")))]
if std::arch::is_aarch64_feature_detected!("neon") {
return aarch64::fast_decode(ebuf, n_bases, dbuf);
} else {
}
#[cfg(all(target_arch = "x86_64", not(feature = "nosimd")))]
if is_x86_feature_detected!("avx2") {
return unsafe { avx::from_2bit_multi_simd(ebuf, n_bases, dbuf) };
} else {
}
let n_chunks = n_bases.div_ceil(32);
let rem = match n_bases % 32 {
0 => 32, rem => rem,
};
ebuf.iter()
.take(n_chunks - 1)
.try_for_each(|component| from_2bit(*component, 32, dbuf))?;
ebuf.get(n_chunks - 1)
.map_or(Err(Error::InvalidLength(n_bases)), |&component| {
from_2bit(component, rem, dbuf)
})?;
Ok(())
}
pub fn from_2bit(packed: u64, expected_size: usize, sequence: &mut Vec<u8>) -> Result<(), Error> {
#[cfg(all(target_arch = "aarch64", not(feature = "nosimd")))]
if std::arch::is_aarch64_feature_detected!("neon") {
unsafe { aarch64::from_2bit_simd(packed, expected_size, sequence) }
} else {
naive::from_2bit(packed, expected_size, sequence)
}
#[cfg(all(target_arch = "x86_64", not(feature = "nosimd")))]
if is_x86_feature_detected!("avx2") {
unsafe { avx::from_2bit_simd(packed, expected_size, sequence) }
} else {
naive::from_2bit(packed, expected_size, sequence)
}
#[cfg(any(
feature = "nosimd",
all(not(target_arch = "aarch64"), not(target_arch = "x86_64"),)
))]
naive::from_2bit(packed, expected_size, sequence)
}
pub fn from_2bit_alloc(packed: u64, expected_size: usize) -> Result<Vec<u8>, Error> {
let mut sequence = Vec::with_capacity(expected_size);
from_2bit(packed, expected_size, &mut sequence)?;
Ok(sequence)
}
#[cfg(test)]
mod testing {
use super::*;
#[test]
fn test_from_2bit_valid_sequence() {
let tests = vec![
(0b11100100, 4, b"ACGT"),
(0b00000000, 4, b"AAAA"),
(0b11111111, 4, b"TTTT"),
];
let mut unpacked = Vec::new();
for (input, size, expected) in tests {
from_2bit(input, size, &mut unpacked).unwrap();
assert_eq!(unpacked, expected);
unpacked.clear();
}
}
#[test]
fn test_example_case_from_2bit() {
let packed = 71620941647064936;
let slen = 28;
let expected = b"AGGCTTGAGGCCCATTCTCTGATCGTTT";
let observed = from_2bit_alloc(packed, slen).unwrap();
let obs_str = std::str::from_utf8(&observed).unwrap();
let exp_str = std::str::from_utf8(expected).unwrap();
assert_eq!(obs_str, exp_str);
assert_eq!(&observed, expected);
}
}