use core::arch::x86_64::*;
use crate::base16::config::Base16EncodeConfig;
use crate::base16::error::Base16Error;
#[target_feature(enable = "avx512f,avx512bw")]
#[inline]
#[allow(unsafe_op_in_unsafe_fn)]
pub(crate) unsafe fn avx512_encode_into(
config: &Base16EncodeConfig,
dst: &mut [u8],
src: &[u8],
) -> Result<usize, Base16Error> {
let alphabet =
_mm512_broadcast_i32x4(_mm_loadu_si128(config.alphabet.as_ptr() as *const __m128i));
let mask_0f = _mm512_set1_epi16(0x000F);
let interleave_shuf = _mm512_broadcast_i32x4(_mm_set_epi8(
15, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0,
));
let mut src_offset = 0usize;
let mut dst_offset = 0usize;
while src_offset + 32 <= src.len() {
let input = _mm256_loadu_si256(src.as_ptr().add(src_offset) as *const __m256i);
let wide = _mm512_cvtepu8_epi16(input);
let hi = _mm512_srli_epi16(wide, 4);
let lo = _mm512_and_si512(wide, mask_0f);
let packed = _mm512_packus_epi16(hi, lo);
let nibbles = _mm512_shuffle_epi8(packed, interleave_shuf);
let chars = _mm512_shuffle_epi8(alphabet, nibbles);
_mm512_storeu_si512(dst.as_mut_ptr().add(dst_offset) as *mut __m512i, chars);
src_offset += 32;
dst_offset += 64;
}
Ok(dst_offset)
}