use core::{
borrow::BorrowMut,
fmt,
fmt::Debug,
hash::{Hash, Hasher},
num::NonZeroUsize,
ops::{Deref, DerefMut},
};
use awint_core::Bits;
use crate::ExtAwi;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct FPType {
pub signed: bool,
pub bw: NonZeroUsize,
pub fp: isize,
}
impl FPType {
#[must_use]
pub fn unique_min_fraction_digits(&self, radix: usize) -> Option<usize> {
if radix < 2 {
return None
}
if self.fp <= 0 {
return Some(0)
}
let mut test = ExtAwi::uone(NonZeroUsize::new(self.fp.unsigned_abs()).unwrap());
let mut digits = 0;
loop {
digits += 1;
if test.short_cin_mul(0, radix) != 0 {
break
}
}
Some(digits)
}
}
pub struct FP<B: BorrowMut<Bits>> {
signed: bool,
fp: isize,
bits: B,
}
impl<B: BorrowMut<Bits>> FP<B> {
#[inline]
pub fn new(signed: bool, bits: B, fp: isize) -> Option<Self> {
if (bits.borrow().bw() > (usize::MAX >> 2)) || (fp.unsigned_abs() > (usize::MAX >> 2)) {
None
} else {
Some(Self { signed, fp, bits })
}
}
#[inline]
pub fn into_b(self) -> B {
self.bits
}
#[inline]
pub fn b(&self) -> &B {
&self.bits
}
#[inline]
pub fn b_mut(&mut self) -> &mut B {
&mut self.bits
}
#[inline]
pub fn const_as_ref(&self) -> &Bits {
self.bits.borrow()
}
#[inline]
pub fn const_as_mut(&mut self) -> &mut Bits {
self.bits.borrow_mut()
}
#[inline]
pub fn signed(&self) -> bool {
self.signed
}
#[inline]
pub fn sign(&self) -> Option<bool> {
if self.signed() {
Some(self.const_as_ref().msb())
} else {
None
}
}
#[inline]
pub fn is_negative(&self) -> bool {
self.signed() && self.const_as_ref().msb()
}
#[inline]
pub fn nzbw(&self) -> NonZeroUsize {
self.const_as_ref().nzbw()
}
#[inline]
pub fn bw(&self) -> usize {
self.const_as_ref().bw()
}
#[inline]
pub fn ibw(&self) -> isize {
self.const_as_ref().bw() as isize
}
#[inline]
pub fn fp(&self) -> isize {
self.fp
}
#[inline]
pub fn fp_ty(&self) -> FPType {
FPType {
signed: self.signed(),
fp: self.fp(),
bw: self.nzbw(),
}
}
pub fn set_fp(&mut self, fp: isize) -> Option<()> {
if fp.unsigned_abs() > (usize::MAX >> 2) {
None
} else {
self.fp = fp;
Some(())
}
}
}
impl<B: BorrowMut<Bits>> Deref for FP<B> {
type Target = Bits;
#[inline]
fn deref(&self) -> &Self::Target {
self.const_as_ref()
}
}
impl<B: BorrowMut<Bits>> DerefMut for FP<B> {
#[inline]
fn deref_mut(&mut self) -> &mut Bits {
self.const_as_mut()
}
}
impl<B: Clone + BorrowMut<Bits>> Clone for FP<B> {
fn clone(&self) -> Self {
Self {
signed: self.signed,
fp: self.fp,
bits: self.bits.clone(),
}
}
}
impl<B: Copy + BorrowMut<Bits>> Copy for FP<B> {}
impl<B: PartialEq + BorrowMut<Bits>> PartialEq for FP<B> {
fn eq(&self, rhs: &Self) -> bool {
(self.signed == rhs.signed) && (self.fp == rhs.fp) && (self.bits == rhs.bits)
}
}
impl<B: PartialEq + Eq + BorrowMut<Bits>> Eq for FP<B> {}
macro_rules! impl_fmt {
($($ty:ident, $radix_str:expr, $radix:expr, $upper:expr);*;) => {
$(
impl<B: fmt::$ty + BorrowMut<Bits>> fmt::$ty for FP<B> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Ok((integer, fraction)) =
FP::to_str_general(self, $radix, $upper, 1, 1, 4096) {
let sign = if self.is_negative() {
"-"
} else {
""
};
let signed = if self.signed() {
'i'
} else {
'u'
};
f.write_fmt(format_args!(
"{}{}{}.{}_{}{}f{}",
sign,
$radix_str,
integer,
fraction,
signed,
self.bw(),
self.fp()
))
} else {
Ok(())
}
}
}
)*
};
}
impl_fmt!(
Debug, "", 10, false;
Display, "", 10, false;
LowerHex, "0x", 16, false;
UpperHex, "0x", 16, true;
Octal, "0o", 8, false;
Binary, "0b", 2, false;
);
impl<B: Hash + BorrowMut<Bits>> Hash for FP<B> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.signed.hash(state);
self.fp.hash(state);
self.bits.hash(state);
}
}