#[cfg(feature = "aligned-vec")]
use aligned_vec::{avec, AVec, ConstAlign};
use super::*;
mod ags_scalar;
pub(crate) use ags_scalar::*;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ags_128_ssse3;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub(crate) use ags_128_ssse3::*;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ags_128_avx2;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub(crate) use ags_128_avx2::*;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ags_64_ssse3;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub(crate) use ags_64_ssse3::*;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ags_64_avx2;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub(crate) use ags_64_avx2::*;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ags_32_ssse3;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub(crate) use ags_32_ssse3::*;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ags_32_avx2;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub(crate) use ags_32_avx2::*;
#[cfg(feature = "aligned-vec")]
#[derive(Debug)]
pub(crate) struct AsciiGraphicSet {
binmap: AVec<u8, ConstAlign<64>>,
a128map: AVec<u8, ConstAlign<128>>,
}
#[cfg(not(feature = "aligned-vec"))]
#[derive(Debug)]
pub(crate) struct AsciiGraphicSet {
binmap: Vec<u8>,
a128map: Vec<u8>,
}
impl AsciiGraphicSet {
#[allow(dead_code)]
#[inline]
pub fn with_str(a: &str) -> Self {
Self::with_slice(a.as_bytes())
}
#[cfg(not(feature = "aligned-vec"))]
#[allow(dead_code)]
pub fn with_slice(a: &[u8]) -> Self {
assert!(a.len() <= 64);
assert_eq!(a.iter().position(|&x| !x.is_ascii_graphic()), None);
let binmap = a.to_vec();
let mut a128map: Vec<u8> = vec![0xFF; 128];
for (idx, &a) in binmap.iter().enumerate() {
a128map[a as usize] = idx as u8;
}
Self { binmap, a128map }
}
#[cfg(feature = "aligned-vec")]
#[allow(dead_code)]
pub fn with_slice(a: &[u8]) -> Self {
assert!(a.len() <= 64);
assert_eq!(a.iter().position(|&x| !x.is_ascii_graphic()), None);
let mut binmap = avec!([64]| 0x00; a.len());
binmap[0..a.len()].copy_from_slice(a);
let mut a128map = avec!([128]| 0xFF; 128);
for (idx, &a) in binmap.iter().enumerate() {
a128map[a as usize] = idx as u8;
}
Self { binmap, a128map }
}
#[allow(dead_code)]
#[inline]
pub fn len(&self) -> usize {
self.binmap.len()
}
#[inline(always)]
pub fn position(&self, byte: u8) -> Option<u8> {
if let Some(&idx) = self.a128map.get(byte as usize) {
if idx != 0xFF {
return Some(idx);
}
}
None
}
#[inline(always)]
pub fn get(&self, index: u8) -> Option<u8> {
self.binmap.get(index as usize).copied()
}
}
impl AsciiGraphicSet {
#[inline(always)]
pub fn posq(&self, ascii: u8) -> Result<u8, DecodeError> {
if let Some(&binary) = self.a128map.get(ascii as usize) {
if binary != 0xFF {
return Ok(binary);
}
}
Err(DecodeError::InvalidByte(ascii))
}
#[inline(always)]
pub fn getq(&self, binary: u8) -> Result<u8, EncodeError> {
if let Some(&ascii) = self.binmap.get(binary as usize) {
return Ok(ascii);
}
Err(EncodeError::InvalidIndex(binary))
}
#[allow(dead_code)]
#[inline(always)]
pub fn binary_to_ascii(&self, buf: &mut [u8]) -> Result<(), EncodeError> {
x86_dispatch!(
avx2 => {
if self.len() == 64 {
unsafe { _binary_to_ascii_64_avx2(&self.binmap, buf) }
} else if self.len() == 32 {
unsafe { _binary_to_ascii_32_avx2(&self.binmap, buf) }
} else {
_binary_to_ascii_scalar(&self.binmap, buf)
}
},
ssse3 => {
if self.len() == 64 {
unsafe { _binary_to_ascii_64_ssse3(&self.binmap, buf) }
} else if self.len() == 32 {
unsafe { _binary_to_ascii_32_ssse3(&self.binmap, buf) }
} else {
_binary_to_ascii_scalar(&self.binmap, buf)
}
},
fallback => {
_binary_to_ascii_scalar(&self.binmap, buf)
}
)
}
#[allow(dead_code)]
#[inline(always)]
pub fn ascii_to_binary(&self, buf: &mut [u8]) -> Result<(), DecodeError> {
x86_dispatch!(
avx2 => {
unsafe { _ascii_to_binary_128_avx2(&self.a128map, buf) }
},
ssse3 => {
unsafe { _ascii_to_binary_128_ssse3(&self.a128map, buf) }
},
fallback => {
_ascii_to_binary_scalar(&self.a128map, buf)
}
)
}
#[cfg(target_feature = "sse2")]
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn binary_to_ascii_64_ssse3(&self, buf: &mut [u64; 2]) -> Result<(), EncodeError> {
assert!(self.len() == 64);
unsafe { _binary_to_ascii_64_ssse3_c16(&self.binmap, buf) }
}
#[cfg(target_feature = "sse2")]
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn ascii_to_binary_64_ssse3(&self, buf: &mut [u64; 2]) -> Result<(), DecodeError> {
assert!(self.len() == 64);
unsafe { _ascii_to_binary_128_ssse3_c16(&self.a128map, buf) }
}
#[cfg(target_feature = "sse2")]
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn binary_to_ascii_64_avx2(&self, buf: &mut [u64; 4]) -> Result<(), EncodeError> {
assert!(self.len() == 64);
unsafe { _binary_to_ascii_64_avx2_c32(&self.binmap, buf) }
}
#[cfg(target_feature = "sse2")]
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn ascii_to_binary_64_avx2(&self, buf: &mut [u64; 4]) -> Result<(), DecodeError> {
assert!(self.len() == 64);
unsafe { _ascii_to_binary_128_avx2_c32(&self.a128map, buf) }
}
#[cfg(target_feature = "sse2")]
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn binary_to_ascii_32_ssse3(&self, buf: &mut [u64; 2]) -> Result<(), EncodeError> {
assert!(self.len() == 32);
unsafe { _binary_to_ascii_32_ssse3_c16(&self.binmap, buf) }
}
#[cfg(target_feature = "sse2")]
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn ascii_to_binary_32_ssse3(&self, buf: &mut [u64; 2]) -> Result<(), DecodeError> {
assert!(self.len() == 32);
unsafe { _ascii_to_binary_128_ssse3_c16(&self.a128map, buf) }
}
#[cfg(target_feature = "sse2")]
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn binary_to_ascii_32_avx2(&self, buf: &mut [u64; 4]) -> Result<(), EncodeError> {
assert!(self.len() == 32);
unsafe { _binary_to_ascii_32_avx2_c32(&self.binmap, buf) }
}
#[cfg(target_feature = "sse2")]
#[allow(dead_code)]
#[inline(always)]
pub(crate) fn ascii_to_binary_32_avx2(&self, buf: &mut [u64; 4]) -> Result<(), DecodeError> {
assert!(self.len() == 32);
unsafe { _ascii_to_binary_128_avx2_c32(&self.a128map, buf) }
}
}
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use super::super::*;
#[allow(unused_imports)]
use super::*;
#[test]
fn test_ascii_graphic_set_1() {
let ags = AsciiGraphicSet::with_slice(&test_utils::_CMAP64);
assert_eq!(ags.len(), 64);
assert_eq!(ags.get(0), Some(b'A'));
assert_eq!(ags.get(1), Some(b'B'));
assert_eq!(ags.get(26), Some(b'a'));
assert_eq!(ags.get(27), Some(b'b'));
assert_eq!(ags.get(52), Some(b'0'));
assert_eq!(ags.get(53), Some(b'1'));
assert_eq!(ags.get(62), Some(b'+'));
assert_eq!(ags.get(63), Some(b'/'));
assert_eq!(ags.position(b'A'), Some(0));
assert_eq!(ags.position(b'B'), Some(1));
assert_eq!(ags.position(b'a'), Some(26));
assert_eq!(ags.position(b'b'), Some(27));
assert_eq!(ags.position(b'0'), Some(52));
assert_eq!(ags.position(b'1'), Some(53));
assert_eq!(ags.position(b'+'), Some(62));
assert_eq!(ags.position(b'/'), Some(63));
}
#[test]
fn test_ascii_graphic_set_binary_to_ascii() {
let ags = AsciiGraphicSet::with_slice(&test_utils::_CMAP64);
let mut buf = Vec::<u8>::with_capacity(64);
for i in 0..64 {
buf.push(i);
}
let r = ags.binary_to_ascii(&mut buf);
assert!(r.is_ok());
assert_eq!(buf, &test_utils::_CMAP64);
}
#[test]
fn test_ascii_graphic_set_ascii_to_binary() {
let ags = AsciiGraphicSet::with_slice(&test_utils::_CMAP64);
let mut valid = Vec::<u8>::with_capacity(64);
for i in 0..64 {
valid.push(i);
}
let mut buf = Vec::<u8>::with_capacity(64);
for i in 0..64 {
buf.push(test_utils::_CMAP64[i]);
}
let r = ags.ascii_to_binary(&mut buf);
assert!(r.is_ok());
assert_eq!(buf, valid);
}
}