[no description]
the const param
bendn 6 weeks ago
parent dd1dd24 · commit 3491491
-rw-r--r--src/ap.rs198
-rw-r--r--src/lib.rs6
2 files changed, 115 insertions, 89 deletions
diff --git a/src/ap.rs b/src/ap.rs
index 8379fb3..6e441b6 100644
--- a/src/ap.rs
+++ b/src/ap.rs
@@ -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)
diff --git a/src/lib.rs b/src/lib.rs
index 1595c63..2d540a5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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)]