[no description]
the const param
| -rw-r--r-- | src/ap.rs | 198 | ||||
| -rw-r--r-- | src/lib.rs | 6 |
2 files changed, 115 insertions, 89 deletions
@@ -1,7 +1,9 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::fmt::{Debug, Display, Write}; -use std::intrinsics::{const_deallocate, const_eval_select}; +use std::intrinsics::{ + const_deallocate, const_eval_select, transmute_unchecked, +}; use std::marker::Destruct; use std::mem::{ManuallyDrop as MD, forget, replace, transmute}; use std::ops::{ @@ -12,16 +14,64 @@ use std::ops::{ mod test; use crate::xp::{self, XP}; +#[derive(core::marker::ConstParamTy, PartialEq, Eq)] +pub struct APParam { + pub sign: Sign, + pub ndigits: u32, + pub digits: &'static [u8], +} +const impl From<AP> for APParam { + fn from(value: AP) -> Self { + let AP { sign, ndigits, digits: Storage::Leaked(digits) } = + value.globalize() + else { + unreachable!() + }; + APParam { sign, ndigits, digits } + } +} +const impl From<APParam> for AP { + fn from(APParam { sign, ndigits, digits }: APParam) -> Self { + Self { sign, ndigits, digits: Storage::Leaked(digits) } + } +} + +const impl Neg for Sign { + type Output = Self; + + fn neg(self) -> Self::Output { + match self { + Self::Negative => Positive, + Self::Positive => Negative, + } + } +} +#[derive(core::marker::ConstParamTy, Copy)] +#[derive_const(PartialEq, Eq, PartialOrd, Ord, Clone)] +#[repr(i8)] +enum Sign { + Negative = -1, + Positive = 1, +} +const impl From<i128> for Sign { + fn from(value: i128) -> Self { + match value { + 0.. => Positive, + i128::MIN..0 => Negative, + } + } +} +use Sign::*; #[repr(C)] /// Arbitratry precision integer, usable in const pub struct AP { - // -1 | +1 - sign: i8, + // Negative | +1 + sign: Sign, ndigits: u32, - digits: MD<Storage>, + digits: Storage, } -impl const Eq for AP {} -impl const PartialEq for AP { +const impl Eq for AP {} +const impl PartialEq for AP { fn eq(&self, other: &Self) -> bool { self.sign == other.sign && self.ndigits == other.ndigits @@ -30,25 +80,7 @@ impl const PartialEq for AP { } } -impl const Drop for Storage { - fn drop(&mut self) { - const fn drop_c(x: &mut MD<Vec<u8>>) { - unsafe { const_deallocate(x.as_mut_ptr(), x.capacity(), 0) }; - } - fn drop_r(x: &mut MD<Vec<u8>>) { - unsafe { MD::drop(x) }; - } - - match self { - Self::V(x) => { - const_eval_select((x,), drop_c, drop_r); - } - _ => {} - } - } -} - -impl const DerefMut for Storage { +const impl DerefMut for Storage { fn deref_mut(&mut self) -> &mut Self::Target { match self { Self::V(x) => x.as_mut_slice(), @@ -58,14 +90,14 @@ impl const DerefMut for Storage { while i < items.len() { v.push(items[i]); } - *self = Storage::V(MD::new(v)); + *self = Storage::V(v); &mut *self } } } } -impl const Deref for Storage { +const impl Deref for Storage { type Target = [u8]; fn deref(&self) -> &Self::Target { match self { @@ -75,22 +107,22 @@ impl const Deref for Storage { } } -impl const Clone for AP { +const impl Clone for AP { fn clone(&self) -> Self { Self { - sign: self.sign.clone(), + sign: self.sign, ndigits: self.ndigits.clone(), - digits: MD::new((&*self.digits).clone()), + digits: self.digits.clone(), } } } #[derive(Debug)] pub enum Storage { - V(MD<Vec<u8>>), + V(Vec<u8>), Leaked(&'static [u8]), } -impl const Clone for Storage { +const impl Clone for Storage { fn clone(&self) -> Self { match self { Self::V(x) => { @@ -100,25 +132,21 @@ impl const Clone for Storage { v.push(x.as_slice()[i]); i += 1; } - Self::V(MD::new(v)) + Self::V(v) } Self::Leaked(x) => Self::Leaked(x), } } } -impl const Default for AP { +const impl Default for AP { fn default() -> Self { - Self { - sign: 1, - ndigits: 1, - digits: MD::new(Storage::Leaked(&[0])), - } + Self { sign: Positive, ndigits: 1, digits: Storage::Leaked(&[0]) } } } impl Debug for AP { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.sign == -1 { + if self.sign == Negative { f.write_char('-')?; } let mut x = Vec::with_capacity(1024); @@ -134,7 +162,7 @@ impl Debug for AP { } impl Display for AP { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.sign == -1 { + if self.sign == Negative { f.write_char('-')?; } let mut x = Vec::with_capacity(1024); @@ -167,7 +195,7 @@ impl AP { pub const fn to_int(&self) -> i128 { let u = xp::to_int(self.ndigits, self.dgr()) % (i128::MAX as u128 + 1); - if self.sign == -1 { -(u as i128) } else { u as i128 } + if self.sign == Negative { -(u as i128) } else { u as i128 } } pub const fn set(&mut self, n: i128) { if (n == i128::MIN) { @@ -176,9 +204,8 @@ impl AP { xp::from_int(self.sz(), self.dg(), (-n) as _); } else { xp::from_int(self.sz(), self.dg(), (n) as _); - self.sign = if n < 0 { -1 } else { 1 }; } - self.sign = if n < 0 { -1 } else { 1 }; + self.sign = n.into(); self.normalize(self.sz()); } const fn normalize(&mut self, n: u32) { @@ -196,11 +223,7 @@ impl AP { i += 1; } - Self { - sign: 1, - ndigits: 1, - digits: MD::new(Storage::V(MD::new(v))), - } + Self { sign: Positive, ndigits: 1, digits: Storage::V(v) } } const fn add(z: &mut Self, x: &Self, y: &Self) { let mut n = y.ndigits; @@ -248,7 +271,7 @@ impl AP { } } const fn smsn(x: &Self, y: &Self) -> bool { - (x.sign ^ y.sign) == 0 + (x.sign == y.sign) } pub const fn divmod(x: &Self, y: &Self) -> (AP, AP) { assert!(!y.iszero()); @@ -265,7 +288,8 @@ impl AP { ); q.normalize(q.sz()); r.normalize(r.sz()); - q.sign = if q.iszero() || AP::smsn(x, y) { 1 } else { -1 }; + q.sign = + if q.iszero() || AP::smsn(x, y) { Positive } else { Negative }; if !AP::smsn(x, y) && !r.iszero() { let carry = unsafe { xp::sum_p(q.sz(), q.dg().as_mut_ptr(), q.dgr().as_ptr(), 1) @@ -296,7 +320,7 @@ impl AP { &xy % p } pub const fn pow(&self, y: &Self) -> AP { - assert!(y.sign == 1); + assert!(y.sign == Positive); if self.iszero() { return AP::new(0); } @@ -318,8 +342,10 @@ impl AP { z } pub const fn pow_mod(&self, y: &Self, modulo: &Self) -> Self { - assert!(y.sign == 1); - assert!(modulo.sign == 1 && !modulo.iszero() && !modulo.isone()); + assert!(y.sign == Positive); + assert!( + modulo.sign == Positive && !modulo.iszero() && !modulo.isone() + ); if self.iszero() { return AP::new(0); } @@ -349,49 +375,45 @@ impl AP { } /// call before storing. pub const fn globalize(mut self) -> Self { - match &mut *self.digits { + match self.digits { Storage::V(x) => - self.digits = MD::new(Storage::Leaked( - unsafe { MD::take(x) }.const_make_global(), - )), + self.digits = Storage::Leaked(x.const_make_global()), _ => {} }; self } } -impl const Drop for AP { - fn drop(&mut self) { - unsafe { MD::drop(&mut self.digits) }; - } -} - -impl const Neg for AP { +const impl Neg for AP { type Output = AP; fn neg(mut self) -> Self::Output { - self.sign = if self.iszero() { 1 } else { -self.sign }; + self.sign = if self.iszero() { Positive } else { -self.sign }; self } } -impl const Mul for &AP { +const impl Mul for &AP { type Output = AP; fn mul(self, rhs: Self) -> Self::Output { let mut z = AP::alloc(self.ndigits + rhs.ndigits); xp::mul(z.dg(), self.ndigits, self.dgr(), rhs.ndigits, rhs.dgr()); z.normalize(z.sz()); - z.sign = if z.iszero() || AP::smsn(self, rhs) { 1 } else { -1 }; + z.sign = if z.iszero() || AP::smsn(self, rhs) { + Positive + } else { + Negative + }; z } } -impl const MulAssign<&AP> for AP { +const impl MulAssign<&AP> for AP { fn mul_assign(&mut self, rhs: &Self) { *self = &*self * rhs; } } -impl const Add for &AP { +const impl Add for &AP { type Output = AP; fn add(self, rhs: Self) -> Self::Output { @@ -399,21 +421,21 @@ impl const Add for &AP { if AP::smsn(&self, &rhs) { z = AP::alloc(self.ndigits.max(rhs.ndigits) + 1); AP::add(&mut z, &self, &rhs); - z.sign = if z.iszero() { 1 } else { self.sign }; + z.sign = if z.iszero() { Positive } else { self.sign }; } else if AP::cmp(self, rhs).is_gt() { z = AP::alloc(self.ndigits); AP::sub(&mut z, self, rhs); - z.sign = if z.iszero() { 1 } else { self.sign }; + z.sign = if z.iszero() { Positive } else { self.sign }; } else { // lesser ? z = AP::alloc(rhs.ndigits); AP::sub(&mut z, rhs, self); - z.sign = if z.iszero() { 1 } else { -self.sign }; + z.sign = if z.iszero() { Positive } else { -self.sign }; } z } } -impl const Sub for &AP { +const impl Sub for &AP { type Output = AP; fn sub(self, rhs: Self) -> Self::Output { @@ -422,42 +444,42 @@ impl const Sub for &AP { z = AP::alloc(self.ndigits.max(rhs.ndigits) + 1); AP::add(&mut z, self, rhs); - z.sign = if z.iszero() { 1 } else { self.sign }; + z.sign = if z.iszero() { Positive } else { self.sign }; } else if AP::cmp(self, rhs).is_gt() { z = AP::alloc(self.ndigits); AP::sub(&mut z, self, rhs); - z.sign = if z.iszero() { 1 } else { self.sign }; + z.sign = if z.iszero() { Positive } else { self.sign }; } else { z = AP::alloc(rhs.ndigits); AP::sub(&mut z, rhs, self); - z.sign = if z.iszero() { 1 } else { -self.sign }; + z.sign = if z.iszero() { Positive } else { -self.sign }; } z } } -impl const SubAssign<&AP> for AP { +const impl SubAssign<&AP> for AP { fn sub_assign(&mut self, rhs: &AP) { *self = &*self - rhs; } } -impl const AddAssign<&AP> for AP { +const impl AddAssign<&AP> for AP { fn add_assign(&mut self, rhs: &AP) { *self = &*self + rhs; } } -impl const Div for &AP { +const impl Div for &AP { type Output = AP; fn div(self, rhs: Self) -> Self::Output { AP::divmod(self, rhs).0 } } -impl const DivAssign<&AP> for AP { +const impl DivAssign<&AP> for AP { fn div_assign(&mut self, rhs: &AP) { *self = &*self / rhs; } } -impl const Rem for &AP { +const impl Rem for &AP { type Output = AP; fn rem(self, rhs: Self) -> Self::Output { @@ -465,7 +487,7 @@ impl const Rem for &AP { } } -impl const Shl<u32> for &AP { +const impl Shl<u32> for &AP { type Output = AP; fn shl(self, s: u32) -> Self::Output { @@ -476,7 +498,7 @@ impl const Shl<u32> for &AP { z } } -impl const Shr<u32> for &AP { +const impl Shr<u32> for &AP { type Output = AP; /// this is a truncating, not flooring, shr. @@ -488,7 +510,7 @@ impl const Shr<u32> for &AP { let mut z = AP::alloc(self.ndigits - (s / 8)); let c = xp::shr(z.sz(), z.dg(), self.ndigits, self.dgr(), s, 0); - z.sign = if z.iszero() { 1 } else { self.sign }; + z.sign = if z.iszero() { Positive } else { self.sign }; z.normalize(z.sz()); z } @@ -537,16 +559,16 @@ fni!(Div, div => u64 u32 u16 u8 i128 i64 i32 i16 i8); fni!(Sub, sub => u64 u32 u16 u8 i128 i64 i32 i16 i8); fni!(Rem, rem => u64 u32 u16 u8 i128 i64 i32 i16 i8); -impl const PartialOrd for AP { +const impl PartialOrd for AP { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } } -impl const Ord for AP { +const impl Ord for AP { fn cmp(&self, other: &Self) -> Ordering { if !AP::smsn(self, other) { unsafe { transmute(self.sign) } - } else if self.sign == 1 { + } else if self.sign == Positive { AP::cmp_(self, other) } else { AP::cmp_(other, self) @@ -1,9 +1,12 @@ //! provides bigints, but const. #![feature( + min_adt_const_params, const_drop_in_place, generic_const_exprs, const_eval_select, const_manually_drop_take, + unsized_const_params, + adt_const_params, exact_div, exact_bitshifts, const_default, @@ -17,7 +20,8 @@ const_convert, const_result_trait_fn, derive_const, - const_clone + const_clone, + rustc_attrs )] #![allow(warnings)] |