use crate::{decode, encode, CheckCase};
#[derive(Clone, Copy)]
enum Kind {
Scalar,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Sse41,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Avx2,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Avx512,
#[cfg(target_arch = "aarch64")]
Neon,
}
#[derive(Clone, Copy)]
pub struct Backend(Kind);
pub fn backends() -> impl Iterator<Item = Backend> {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
let (sse41, avx2, avx512) = {
#[cfg(test)]
{
let avx2 = std::arch::is_x86_feature_detected!("avx2");
(
std::arch::is_x86_feature_detected!("sse4.1"),
avx2,
avx2 && std::arch::is_x86_feature_detected!("avx512f")
&& std::arch::is_x86_feature_detected!("avx512bw"),
)
}
#[cfg(not(test))]
{
use crate::Vectorization::{AVX2, AVX512, SSE41};
let kind = crate::vectorization_support();
(
matches!(kind, SSE41 | AVX2 | AVX512),
matches!(kind, AVX2 | AVX512),
kind == AVX512,
)
}
};
IntoIterator::into_iter([
Some(Backend(Kind::Scalar)),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
sse41.then_some(Backend(Kind::Sse41)),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
avx2.then_some(Backend(Kind::Avx2)),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
avx512.then_some(Backend(Kind::Avx512)),
#[cfg(target_arch = "aarch64")]
(crate::vectorization_support() == crate::Vectorization::Neon)
.then_some(Backend(Kind::Neon)),
])
.flatten()
}
impl Backend {
pub fn name(self) -> &'static str {
match self.0 {
Kind::Scalar => "scalar",
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Sse41 => "sse41",
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Avx2 => "avx2",
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Avx512 => "avx512",
#[cfg(target_arch = "aarch64")]
Kind::Neon => "neon",
}
}
pub fn encode(self, src: &[u8], dst: &mut [u8], upper: bool) {
assert_eq!(src.len().checked_mul(2), Some(dst.len()));
unsafe {
let dst = core::slice::from_raw_parts_mut(dst.as_mut_ptr().cast(), dst.len());
match self.0 {
Kind::Scalar => encode::hex_encode_custom_case_fallback(src, dst, upper),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Sse41 => encode::hex_encode_sse41(src, dst, upper),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Avx2 | Kind::Avx512 => encode::hex_encode_avx2(src, dst, upper),
#[cfg(target_arch = "aarch64")]
Kind::Neon => encode::hex_encode_neon(src, dst, upper),
}
}
}
pub fn check(self, src: &[u8], case: CheckCase) -> bool {
#[allow(unused_unsafe)] unsafe {
match self.0 {
Kind::Scalar => decode::hex_check_fallback_with_case(src, case),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Sse41 => decode::x86::hex_check_sse_with_case(src, case),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Avx2 => decode::x86::hex_check_avx2_with_case(src, case),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Avx512 => decode::x86::hex_check_avx512_with_case(src, case),
#[cfg(target_arch = "aarch64")]
Kind::Neon => decode::aarch64::hex_check_neon_with_case(src, case),
}
}
}
pub fn decode(self, src: &[u8], dst: &mut [u8], case: CheckCase) -> bool {
assert_eq!(dst.len().checked_mul(2), Some(src.len()));
if src.len() < 16 {
return decode::hex_decode_short_scalar(src, dst, case).is_ok();
}
#[allow(unused_unsafe)] unsafe {
match self.0 {
Kind::Scalar => {
if !decode::hex_check_fallback_with_case(src, case) {
return false;
}
decode::hex_decode_fallback(src, dst);
true
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Sse41 => decode::x86::hex_decode_sse41_checked(src, dst, case).is_ok(),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Avx2 => decode::x86::hex_decode_avx2_checked(src, dst, case).is_ok(),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Avx512 => decode::x86::hex_decode_avx512_checked(src, dst, case).is_ok(),
#[cfg(target_arch = "aarch64")]
Kind::Neon => decode::decode_checked(src, dst, case).is_ok(),
}
}
}
pub fn decode_owned(self, src: &[u8], dst: &mut [u8], case: CheckCase) -> bool {
assert_eq!(dst.len().checked_mul(2), Some(src.len()));
#[allow(unused_unsafe)] unsafe {
match self.0 {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Avx2 => decode::x86::hex_decode_avx2_owned(src, dst, case).is_ok(),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Kind::Avx512 => decode::x86::hex_decode_avx512_owned(src, dst, case).is_ok(),
#[cfg(target_arch = "aarch64")]
Kind::Neon => decode::aarch64::hex_decode_neon_owned(src, dst, case).is_ok(),
_ => self.decode(src, dst, case),
}
}
}
}