Skip to content

Commit

Permalink
crate-visible IntDigits trait for common BigUint and BigInt access
Browse files Browse the repository at this point in the history
  • Loading branch information
tspiteri committed Mar 4, 2018
1 parent e005dcc commit 008d2f0
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 64 deletions.
102 changes: 56 additions & 46 deletions src/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use super::ParseBigIntError;
use super::big_digit::{self, BigDigit, DoubleBigDigit};
use biguint;
use biguint::to_str_radix_reversed;
use biguint::BigUint;
use biguint::{BigUint, IntDigits};

use UsizePromotion;
use IsizePromotion;
Expand Down Expand Up @@ -204,13 +204,6 @@ fn negate_carry(a: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit {
lo
}

fn normalize(i: &mut BigInt) {
biguint::normalize(&mut i.data);
if i.data.is_zero() {
i.sign = NoSign;
}
}

// !-2 = !...f fe = ...0 01 = +1
// !-1 = !...f ff = ...0 00 = 0
// ! 0 = !...0 00 = ...f ff = -1
Expand Down Expand Up @@ -240,7 +233,7 @@ impl Not for BigInt {
// + 1 & -ff = ...0 01 & ...f 01 = ...0 01 = + 1
// +ff & - 1 = ...0 ff & ...f ff = ...0 ff = +ff
// answer is pos, has length of a
fn bitand_pos_neg(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
fn bitand_pos_neg(a: &mut Vec<BigDigit>, b: &[BigDigit]) {
let mut carry_b = 1;
for (ai, &bi) in a.iter_mut().zip(b.iter()) {
let twos_b = negate_carry(bi, &mut carry_b);
Expand All @@ -252,7 +245,7 @@ fn bitand_pos_neg(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
// - 1 & +ff = ...f ff & ...0 ff = ...0 ff = +ff
// -ff & + 1 = ...f 01 & ...0 01 = ...0 01 = + 1
// answer is pos, has length of b
fn bitand_neg_pos(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
fn bitand_neg_pos(a: &mut Vec<BigDigit>, b: &[BigDigit]) {
let mut carry_a = 1;
for (ai, &bi) in a.iter_mut().zip(b.iter()) {
let twos_a = negate_carry(*ai, &mut carry_a);
Expand All @@ -271,7 +264,7 @@ fn bitand_neg_pos(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
// -ff & - 1 = ...f 01 & ...f ff = ...f 01 = - ff
// -ff & -fe = ...f 01 & ...f 02 = ...f 00 = -100
// answer is neg, has length of longest with a possible carry
fn bitand_neg_neg(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
fn bitand_neg_neg(a: &mut Vec<BigDigit>, b: &[BigDigit]) {
let mut carry_a = 1;
let mut carry_b = 1;
let mut carry_and = 1;
Expand Down Expand Up @@ -322,20 +315,17 @@ impl<'a> BitAndAssign<&'a BigInt> for BigInt {
}
}
(Plus, Minus) => {
bitand_pos_neg(biguint::digits_mut(&mut self.data),
biguint::digits(&other.data));
normalize(self);
bitand_pos_neg(self.data.digits_mut(), other.data.digits());
self.normalize();
}
(Minus, Plus) => {
bitand_neg_pos(biguint::digits_mut(&mut self.data),
biguint::digits(&other.data));
bitand_neg_pos(self.data.digits_mut(), other.data.digits());
self.sign = Plus;
normalize(self);
self.normalize();
}
(Minus, Minus) => {
bitand_neg_neg(biguint::digits_mut(&mut self.data),
biguint::digits(&other.data));
normalize(self);
bitand_neg_neg(self.data.digits_mut(), other.digits());
self.normalize();
}
}
}
Expand All @@ -344,7 +334,7 @@ impl<'a> BitAndAssign<&'a BigInt> for BigInt {
// + 1 | -ff = ...0 01 | ...f 01 = ...f 01 = -ff
// +ff | - 1 = ...0 ff | ...f ff = ...f ff = - 1
// answer is neg, has length of b
fn bitor_pos_neg(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
fn bitor_pos_neg(a: &mut Vec<BigDigit>, b: &[BigDigit]) {
let mut carry_b = 1;
let mut carry_or = 1;
for (ai, &bi) in a.iter_mut().zip(b.iter()) {
Expand All @@ -369,7 +359,7 @@ fn bitor_pos_neg(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
// - 1 | +ff = ...f ff | ...0 ff = ...f ff = - 1
// -ff | + 1 = ...f 01 | ...0 01 = ...f 01 = -ff
// answer is neg, has length of a
fn bitor_neg_pos(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
fn bitor_neg_pos(a: &mut Vec<BigDigit>, b: &[BigDigit]) {
let mut carry_a = 1;
let mut carry_or = 1;
for (ai, &bi) in a.iter_mut().zip(b.iter()) {
Expand All @@ -391,7 +381,7 @@ fn bitor_neg_pos(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
// - 1 | -ff = ...f ff | ...f 01 = ...f ff = -1
// -ff | - 1 = ...f 01 | ...f ff = ...f ff = -1
// answer is neg, has length of shortest
fn bitor_neg_neg(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
fn bitor_neg_neg(a: &mut Vec<BigDigit>, b: &[BigDigit]) {
let mut carry_a = 1;
let mut carry_b = 1;
let mut carry_or = 1;
Expand Down Expand Up @@ -422,23 +412,20 @@ impl<'a> BitOrAssign<&'a BigInt> for BigInt {
fn bitor_assign(&mut self, other: &BigInt) {
match (self.sign, other.sign) {
(_, NoSign) => {}
(NoSign, _) => self.assign_from_slice(other.sign, biguint::digits(&other.data)),
(NoSign, _) => self.assign_from_slice(other.sign, other.data.digits()),
(Plus, Plus) => self.data |= &other.data,
(Plus, Minus) => {
bitor_pos_neg(biguint::digits_mut(&mut self.data),
biguint::digits(&other.data));
bitor_pos_neg(self.data.digits_mut(), other.data.digits());
self.sign = Minus;
normalize(self);
self.normalize();
}
(Minus, Plus) => {
bitor_neg_pos(biguint::digits_mut(&mut self.data),
biguint::digits(&other.data));
normalize(self);
bitor_neg_pos(self.data.digits_mut(), other.data.digits());
self.normalize();
}
(Minus, Minus) => {
bitor_neg_neg(biguint::digits_mut(&mut self.data),
biguint::digits(&other.data));
normalize(self);
bitor_neg_neg(self.data.digits_mut(), other.data.digits());
self.normalize();
}
}
}
Expand All @@ -447,7 +434,7 @@ impl<'a> BitOrAssign<&'a BigInt> for BigInt {
// + 1 ^ -ff = ...0 01 ^ ...f 01 = ...f 00 = -100
// +ff ^ - 1 = ...0 ff ^ ...f ff = ...f 00 = -100
// answer is neg, has length of longest with a possible carry
fn bitxor_pos_neg(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
fn bitxor_pos_neg(a: &mut Vec<BigDigit>, b: &[BigDigit]) {
let mut carry_b = 1;
let mut carry_xor = 1;
for (ai, &bi) in a.iter_mut().zip(b.iter()) {
Expand Down Expand Up @@ -476,7 +463,7 @@ fn bitxor_pos_neg(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
// - 1 ^ +ff = ...f ff ^ ...0 ff = ...f 00 = -100
// -ff ^ + 1 = ...f 01 ^ ...0 01 = ...f 00 = -100
// answer is neg, has length of longest with a possible carry
fn bitxor_neg_pos(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
fn bitxor_neg_pos(a: &mut Vec<BigDigit>, b: &[BigDigit]) {
let mut carry_a = 1;
let mut carry_xor = 1;
for (ai, &bi) in a.iter_mut().zip(b.iter()) {
Expand Down Expand Up @@ -505,7 +492,7 @@ fn bitxor_neg_pos(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
// - 1 ^ -ff = ...f ff ^ ...f 01 = ...0 fe = +fe
// -ff & - 1 = ...f 01 ^ ...f ff = ...0 fe = +fe
// answer is pos, has length of longest
fn bitxor_neg_neg(a: &mut Vec<BigDigit>, b: &Vec<BigDigit>) {
fn bitxor_neg_neg(a: &mut Vec<BigDigit>, b: &[BigDigit]) {
let mut carry_a = 1;
let mut carry_b = 1;
for (ai, &bi) in a.iter_mut().zip(b.iter()) {
Expand Down Expand Up @@ -546,29 +533,26 @@ impl<'a> BitXorAssign<&'a BigInt> for BigInt {
fn bitxor_assign(&mut self, other: &BigInt) {
match (self.sign, other.sign) {
(_, NoSign) => {}
(NoSign, _) => self.assign_from_slice(other.sign, biguint::digits(&other.data)),
(NoSign, _) => self.assign_from_slice(other.sign, other.data.digits()),
(Plus, Plus) => {
self.data ^= &other.data;
if self.data.is_zero() {
self.sign = NoSign;
}
}
(Plus, Minus) => {
bitxor_pos_neg(biguint::digits_mut(&mut self.data),
biguint::digits(&other.data));
bitxor_pos_neg(self.data.digits_mut(), other.data.digits());
self.sign = Minus;
normalize(self);
self.normalize();
}
(Minus, Plus) => {
bitxor_neg_pos(biguint::digits_mut(&mut self.data),
biguint::digits(&other.data));
normalize(self);
bitxor_neg_pos(self.data.digits_mut(), other.data.digits());
self.normalize();
}
(Minus, Minus) => {
bitxor_neg_neg(biguint::digits_mut(&mut self.data),
biguint::digits(&other.data));
bitxor_neg_neg(self.data.digits_mut(), other.data.digits());
self.sign = Plus;
normalize(self);
self.normalize();
}
}
}
Expand Down Expand Up @@ -1609,6 +1593,32 @@ impl From<BigUint> for BigInt {
}
}

impl IntDigits for BigInt {
#[inline]
fn digits(&self) -> &[BigDigit] {
self.data.digits()
}
#[inline]
fn digits_mut(&mut self) -> &mut Vec<BigDigit> {
self.data.digits_mut()
}
#[inline]
fn normalize(&mut self) {
self.data.normalize();
if self.data.is_zero() {
self.sign = NoSign;
}
}
#[inline]
fn capacity(&self) -> usize {
self.data.capacity()
}
#[inline]
fn len(&self) -> usize {
self.data.len()
}
}

#[cfg(feature = "serde")]
impl serde::Serialize for BigInt {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
Expand Down
45 changes: 29 additions & 16 deletions src/biguint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1717,27 +1717,40 @@ pub fn trailing_zeros(u: &BigUint) -> Option<usize> {
.map(|(i, digit)| i * big_digit::BITS + digit.trailing_zeros() as usize)
}

// needed since we cannot set visibility of `BigUint::data` to `pub(crate)`
#[inline]
pub fn digits(u: &BigUint) -> &Vec<BigDigit> {
&u.data
}
impl_sum_iter_type!(BigUint);
impl_product_iter_type!(BigUint);

// needed since we cannot set visibility of `BigUint::data` to `pub(crate)`
#[inline]
pub fn digits_mut(u: &mut BigUint) -> &mut Vec<BigDigit> {
&mut u.data
pub trait IntDigits {
fn digits(&self) -> &[BigDigit];
fn digits_mut(&mut self) -> &mut Vec<BigDigit>;
fn normalize(&mut self);
fn capacity(&self) -> usize;
fn len(&self) -> usize;
}

// needed since we cannot set visibility of `BigUint::normalize` to `pub(crate)`
#[inline]
pub fn normalize(u: &mut BigUint) {
u.normalize()
impl IntDigits for BigUint {
#[inline]
fn digits(&self) -> &[BigDigit] {
&self.data
}
#[inline]
fn digits_mut(&mut self) -> &mut Vec<BigDigit> {
&mut self.data
}
#[inline]
fn normalize(&mut self) {
self.normalize();
}
#[inline]
fn capacity(&self) -> usize {
self.data.capacity()
}
#[inline]
fn len(&self) -> usize {
self.data.len()
}
}

impl_sum_iter_type!(BigUint);
impl_product_iter_type!(BigUint);

#[cfg(feature = "serde")]
impl serde::Serialize for BigUint {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
Expand Down
4 changes: 2 additions & 2 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ macro_rules! forward_val_val_binop_commutative {
#[inline]
fn $method(self, other: $res) -> $res {
// forward to val-ref, with the larger capacity as val
if self.data.capacity() >= other.data.capacity() {
if self.capacity() >= other.capacity() {
$imp::$method(self, &other)
} else {
$imp::$method(other, &self)
Expand Down Expand Up @@ -97,7 +97,7 @@ macro_rules! forward_ref_ref_binop_commutative {
#[inline]
fn $method(self, other: &$res) -> $res {
// forward to val-ref, choosing the larger to clone
if self.data.len() >= other.data.len() {
if self.len() >= other.len() {
$imp::$method(self.clone(), other)
} else {
$imp::$method(other.clone(), self)
Expand Down

0 comments on commit 008d2f0

Please sign in to comment.