use serde::de::DeserializeOwned;
use serde::Serialize;
use std::arch::x86_64::_bzhi_u64;
use std::convert::TryInto;
use std::fmt;
use std::hash::Hash;
use std::io::Write;
use std::ops::{Add, BitAnd, BitOr, BitXor, Neg, Not, Shl, Shr, Sub};
use crate::error::ExecError;
#[macro_export]
macro_rules! write_bits {
($f: expr, $bits: expr, $len: expr) => {{
if $len == 4 {
write!($f, "{:x}", $bits & 0xF)?
} else if $len % 4 == 0 {
for i in (0..($len / 4)).rev() {
write!($f, "{:x}", ($bits >> (i * 4)) & 0xF)?;
}
} else {
for i in (0..$len).rev() {
write!($f, "{:b}", ($bits >> i) & 0b1)?;
}
}
Ok(())
}};
}
pub mod b129;
pub mod b64;
pub trait BV
where
Self: fmt::Debug + fmt::LowerHex + fmt::UpperHex + fmt::Display,
Self: Copy + Clone + PartialEq + Eq + Hash + Send + Sync,
Self: Serialize + DeserializeOwned,
Self: Add<Output = Self>,
Self: Sub<Output = Self>,
Self: BitAnd<Output = Self>,
Self: BitOr<Output = Self>,
Self: BitXor<Output = Self>,
Self: Not<Output = Self>,
Self: Neg<Output = Self>,
Self: Shl<Output = Self>,
Self: Shr<Output = Self>,
Self: TryInto<u64, Error = ExecError>,
{
const BIT_ONE: Self;
const BIT_ZERO: Self;
const MAX_WIDTH: u32;
fn new(value: u64, len: u32) -> Self;
fn len(self) -> u32;
fn lower_u64(self) -> u64;
fn lower_u8(self) -> u8;
fn is_zero(self) -> bool;
fn zeros(len: u32) -> Self;
fn ones(len: u32) -> Self;
fn leading_zeros(self) -> u32;
fn from_u8(value: u8) -> Self;
fn from_u16(value: u16) -> Self;
fn from_u32(value: u32) -> Self;
fn from_u64(value: u64) -> Self;
fn from_bytes(bytes: &[u8]) -> Self;
fn to_le_bytes(self) -> Vec<u8>;
fn to_be_bytes(self) -> Vec<u8>;
fn from_str(bv: &str) -> Option<Self>;
fn len_i128(self) -> i128 {
i128::from(self.len())
}
fn is_empty(self) -> bool {
self.len() == 0
}
fn add_i128(self, op: i128) -> Self;
fn sub_i128(self, op: i128) -> Self {
self.add_i128(-op)
}
fn zero_extend(self, new_len: u32) -> Self;
fn sign_extend(self, new_len: u32) -> Self;
fn unsigned(self) -> i128;
fn signed(self) -> i128;
fn append(self, suffix: Self) -> Option<Self> {
let new_len = self.len() + suffix.len();
if new_len <= Self::MAX_WIDTH {
let shift = Self::new(u64::from(suffix.len()), new_len);
Some(self.zero_extend(new_len) << shift | suffix.zero_extend(new_len))
} else {
None
}
}
fn slice(self, from: u32, len: u32) -> Option<Self>;
fn set_slice(self, n: u32, update: Self) -> Self;
fn extract(self, high: u32, low: u32) -> Option<Self> {
let len = (high - low) + 1;
if low <= high && high <= self.len() {
self.slice(low, len)
} else {
None
}
}
fn shiftr(self, shift: i128) -> Self {
if shift < 0 {
self.shiftl(shift.abs())
} else if shift >= self.len() as i128 {
Self::zeros(self.len())
} else {
self >> Self::new(shift as u64, self.len())
}
}
fn arith_shiftr(self, shift: i128) -> Self {
if shift < 0 {
self.shiftl(shift.abs())
} else if shift >= self.len() as i128 {
if self.leading_zeros() > 0 {
Self::zeros(self.len())
} else {
Self::ones(self.len())
}
} else if self.leading_zeros() > 0 {
self.shiftr(shift)
} else {
self.shiftr(shift).slice(0, self.len() - shift as u32).unwrap().sign_extend(self.len())
}
}
fn shiftl(self, shift: i128) -> Self {
if shift < 0 {
self.shiftr(shift.abs())
} else if shift >= self.len() as i128 {
Self::zeros(self.len())
} else {
self << Self::new(shift as u64, self.len())
}
}
fn truncate_lsb(self, len: i128) -> Option<Self> {
if 0 < len && len <= Self::MAX_WIDTH as i128 {
let len = len as u64;
(self >> Self::new(64 - len, self.len())).slice(0, len as u32)
} else if len == 0 {
Some(Self::new(0, 0))
} else {
None
}
}
fn replicate(self, times: i128) -> Option<Self> {
if times == 0 {
Some(Self::new(0, 0))
} else if 0 <= times && self.len() as i128 * times <= Self::MAX_WIDTH as i128 {
let mut bv = self;
for _ in 1..times {
bv = bv.append(self).unwrap()
}
Some(bv)
} else {
None
}
}
fn set_slice_int(int: i128, n: u32, update: Self) -> i128;
fn get_slice_int(len: u32, int: i128, n: u32) -> Self;
}
pub fn write_bits64(buf: &mut dyn Write, bits: u64, len: u32) -> std::io::Result<()> {
if len % 4 == 0 {
write!(buf, "#x")?
} else {
write!(buf, "#b")?
}
write_bits!(buf, bits, len)
}
#[inline(always)]
pub fn bzhi_u64(bits: u64, len: u32) -> u64 {
unsafe { _bzhi_u64(bits, len) }
}
pub fn bzhi_u128(bits: u128, len: u32) -> u128 {
bits & (std::u128::MAX >> (128 - len))
}