Browse Source

Merge #325

325: Implement assign_from_slice r=cuviper

This commit implements `assign_from_slice(..)` for `BigUint` and `BigInt`. `assig_from_slice` is for performance : it allows to reassign a value to a `BigInt` or a `BigUint` without useless reallocations. It would be useful for loops for example. I need it to implement the Toom-3 algorithm.

I also added a missing test for `BigInt::from_slice(..)`.
bors[bot] 7 years ago
parent
commit
e7df30bac4
5 changed files with 100 additions and 21 deletions
  1. 7 7
      bigint/src/algorithms.rs
  2. 21 6
      bigint/src/bigint.rs
  3. 24 8
      bigint/src/biguint.rs
  4. 33 0
      bigint/src/tests/bigint.rs
  5. 15 0
      bigint/src/tests/biguint.rs

+ 7 - 7
bigint/src/algorithms.rs

@@ -118,7 +118,7 @@ pub fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit) {
         rem = r;
         rem = r;
     }
     }
 
 
-    (a.normalize(), rem)
+    (a.normalized(), rem)
 }
 }
 
 
 // Only for the Add impl:
 // Only for the Add impl:
@@ -339,7 +339,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
         mac3(&mut p.data[..], x1, y1);
         mac3(&mut p.data[..], x1, y1);
 
 
         // Not required, but the adds go faster if we drop any unneeded 0s from the end:
         // Not required, but the adds go faster if we drop any unneeded 0s from the end:
-        p = p.normalize();
+        p.normalize();
 
 
         add2(&mut acc[b..],        &p.data[..]);
         add2(&mut acc[b..],        &p.data[..]);
         add2(&mut acc[b * 2..],    &p.data[..]);
         add2(&mut acc[b * 2..],    &p.data[..]);
@@ -350,7 +350,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
 
 
         // p0 = x0 * y0
         // p0 = x0 * y0
         mac3(&mut p.data[..], x0, y0);
         mac3(&mut p.data[..], x0, y0);
-        p = p.normalize();
+        p.normalize();
 
 
         add2(&mut acc[..],         &p.data[..]);
         add2(&mut acc[..],         &p.data[..]);
         add2(&mut acc[b..],        &p.data[..]);
         add2(&mut acc[b..],        &p.data[..]);
@@ -366,7 +366,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
                 p.data.extend(repeat(0).take(len));
                 p.data.extend(repeat(0).take(len));
 
 
                 mac3(&mut p.data[..], &j0.data[..], &j1.data[..]);
                 mac3(&mut p.data[..], &j0.data[..], &j1.data[..]);
-                p = p.normalize();
+                p.normalize();
 
 
                 sub2(&mut acc[b..], &p.data[..]);
                 sub2(&mut acc[b..], &p.data[..]);
             },
             },
@@ -383,7 +383,7 @@ pub fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint {
     let mut prod = BigUint { data: vec![0; len] };
     let mut prod = BigUint { data: vec![0; len] };
 
 
     mac3(&mut prod.data[..], x, y);
     mac3(&mut prod.data[..], x, y);
-    prod.normalize()
+    prod.normalized()
 }
 }
 
 
 pub fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit {
 pub fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit {
@@ -480,14 +480,14 @@ pub fn div_rem(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) {
 
 
         add2(&mut q.data[j..], &q0.data[..]);
         add2(&mut q.data[j..], &q0.data[..]);
         sub2(&mut a.data[j..], &prod.data[..]);
         sub2(&mut a.data[j..], &prod.data[..]);
-        a = a.normalize();
+        a.normalize();
 
 
         tmp = q0;
         tmp = q0;
     }
     }
 
 
     debug_assert!(a < b);
     debug_assert!(a < b);
 
 
-    (q.normalize(), a >> shift)
+    (q.normalized(), a >> shift)
 }
 }
 
 
 /// Find last set bit
 /// Find last set bit

+ 21 - 6
bigint/src/bigint.rs

@@ -1376,13 +1376,13 @@ impl BigInt {
     ///
     ///
     /// The digits are in little-endian base 2^32.
     /// The digits are in little-endian base 2^32.
     #[inline]
     #[inline]
-    pub fn from_biguint(sign: Sign, data: BigUint) -> BigInt {
-        if sign == NoSign || data.is_zero() {
-            return BigInt {
-                sign: NoSign,
-                data: Zero::zero(),
-            };
+    pub fn from_biguint(mut sign: Sign, mut data: BigUint) -> BigInt {
+        if sign == NoSign {
+            data.assign_from_slice(&[]);
+        } else if data.is_zero() {
+            sign = NoSign;
         }
         }
+
         BigInt {
         BigInt {
             sign: sign,
             sign: sign,
             data: data,
             data: data,
@@ -1395,6 +1395,21 @@ impl BigInt {
         BigInt::from_biguint(sign, BigUint::from_slice(slice))
         BigInt::from_biguint(sign, BigUint::from_slice(slice))
     }
     }
 
 
+    /// Reinitializes a `BigInt`.
+    #[inline]
+    pub fn assign_from_slice(&mut self, sign: Sign, slice: &[BigDigit]) {
+        if sign == NoSign {
+            self.data.assign_from_slice(&[]);
+            self.sign = NoSign;
+        } else {
+            self.data.assign_from_slice(slice);
+            self.sign = match self.data.is_zero() {
+                true => NoSign,
+                false => sign,
+            }
+        }
+    }
+
     /// Creates and initializes a `BigInt`.
     /// Creates and initializes a `BigInt`.
     ///
     ///
     /// The bytes are in big-endian byte order.
     /// The bytes are in big-endian byte order.

+ 24 - 8
bigint/src/biguint.rs

@@ -449,7 +449,7 @@ impl<'a> Sub<&'a BigUint> for BigUint {
 
 
     fn sub(mut self, other: &BigUint) -> BigUint {
     fn sub(mut self, other: &BigUint) -> BigUint {
         sub2(&mut self.data[..], &other.data[..]);
         sub2(&mut self.data[..], &other.data[..]);
-        self.normalize()
+        self.normalized()
     }
     }
 }
 }
 
 
@@ -463,7 +463,7 @@ impl<'a> Sub<BigUint> for &'a BigUint {
         }
         }
 
 
         sub2rev(&self.data[..], &mut other.data[..]);
         sub2rev(&self.data[..], &mut other.data[..]);
-        other.normalize()
+        other.normalized()
     }
     }
 }
 }
 
 
@@ -477,7 +477,7 @@ impl Sub<BigDigit> for BigUint {
     #[inline]
     #[inline]
     fn sub(mut self, other: BigDigit) -> BigUint {
     fn sub(mut self, other: BigDigit) -> BigUint {
         sub2(&mut self.data[..], &[other]);
         sub2(&mut self.data[..], &[other]);
-        self.normalize()
+        self.normalized()
     }
     }
 }
 }
 
 
@@ -491,7 +491,7 @@ impl Sub<BigUint> for BigDigit {
         }
         }
 
 
         sub2rev(&[self], &mut other.data[..]);
         sub2rev(&[self], &mut other.data[..]);
-        other.normalize()
+        other.normalized()
     }
     }
 }
 }
 
 
@@ -502,7 +502,7 @@ impl Sub<DoubleBigDigit> for BigUint {
     fn sub(mut self, other: DoubleBigDigit) -> BigUint {
     fn sub(mut self, other: DoubleBigDigit) -> BigUint {
         let (hi, lo) = big_digit::from_doublebigdigit(other);
         let (hi, lo) = big_digit::from_doublebigdigit(other);
         sub2(&mut self.data[..], &[lo, hi]);
         sub2(&mut self.data[..], &[lo, hi]);
-        self.normalize()
+        self.normalized()
     }
     }
 }
 }
 
 
@@ -517,7 +517,7 @@ impl Sub<BigUint> for DoubleBigDigit {
 
 
         let (hi, lo) = big_digit::from_doublebigdigit(self);
         let (hi, lo) = big_digit::from_doublebigdigit(self);
         sub2rev(&[lo, hi], &mut other.data[..]);
         sub2rev(&[lo, hi], &mut other.data[..]);
-        other.normalize()
+        other.normalized()
     }
     }
 }
 }
 
 
@@ -1175,7 +1175,7 @@ impl BigUint {
     /// The digits are in little-endian base 2^32.
     /// The digits are in little-endian base 2^32.
     #[inline]
     #[inline]
     pub fn new(digits: Vec<BigDigit>) -> BigUint {
     pub fn new(digits: Vec<BigDigit>) -> BigUint {
-        BigUint { data: digits }.normalize()
+        BigUint { data: digits }.normalized()
     }
     }
 
 
     /// Creates and initializes a `BigUint`.
     /// Creates and initializes a `BigUint`.
@@ -1186,6 +1186,16 @@ impl BigUint {
         BigUint::new(slice.to_vec())
         BigUint::new(slice.to_vec())
     }
     }
 
 
+    /// Assign a value to a `BigUint`.
+    ///
+    /// The digits are in little-endian base 2^32.
+    #[inline]
+    pub fn assign_from_slice(&mut self, slice: &[BigDigit]) {
+        self.data.resize(slice.len(), 0);
+        self.data.clone_from_slice(slice);
+        self.normalize();
+    }
+
     /// Creates and initializes a `BigUint`.
     /// Creates and initializes a `BigUint`.
     ///
     ///
     /// The bytes are in big-endian byte order.
     /// The bytes are in big-endian byte order.
@@ -1436,10 +1446,16 @@ impl BigUint {
     /// Strips off trailing zero bigdigits - comparisons require the last element in the vector to
     /// Strips off trailing zero bigdigits - comparisons require the last element in the vector to
     /// be nonzero.
     /// be nonzero.
     #[inline]
     #[inline]
-    fn normalize(mut self) -> BigUint {
+    fn normalize(&mut self) {
         while let Some(&0) = self.data.last() {
         while let Some(&0) = self.data.last() {
             self.data.pop();
             self.data.pop();
         }
         }
+    }
+
+    /// Returns a normalized `BigUint`.
+    #[inline]
+    fn normalized(mut self) -> BigUint {
+        self.normalize();
         self
         self
     }
     }
 }
 }

+ 33 - 0
bigint/src/tests/bigint.rs

@@ -59,6 +59,39 @@ fn test_from_biguint() {
     check(NoSign, 1, NoSign, 0);
     check(NoSign, 1, NoSign, 0);
 }
 }
 
 
+#[test]
+fn test_from_slice() {
+    fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) {
+        let inp = BigInt::from_slice(inp_s, &[inp_n]);
+        let ans = BigInt {
+            sign: ans_s,
+            data: FromPrimitive::from_u32(ans_n).unwrap(),
+        };
+        assert_eq!(inp, ans);
+    }
+    check(Plus, 1, Plus, 1);
+    check(Plus, 0, NoSign, 0);
+    check(Minus, 1, Minus, 1);
+    check(NoSign, 1, NoSign, 0);
+}
+
+#[test]
+fn test_assign_from_slice() {
+    fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) {
+        let mut inp = BigInt::from_slice(Minus, &[2627_u32, 0_u32, 9182_u32, 42_u32]);
+        inp.assign_from_slice(inp_s, &[inp_n]);
+        let ans = BigInt {
+            sign: ans_s,
+            data: FromPrimitive::from_u32(ans_n).unwrap(),
+        };
+        assert_eq!(inp, ans);
+    }
+    check(Plus, 1, Plus, 1);
+    check(Plus, 0, NoSign, 0);
+    check(Minus, 1, Minus, 1);
+    check(NoSign, 1, NoSign, 0);
+}
+
 #[test]
 #[test]
 fn test_from_bytes_be() {
 fn test_from_bytes_be() {
     fn check(s: &str, result: &str) {
     fn check(s: &str, result: &str) {

+ 15 - 0
bigint/src/tests/biguint.rs

@@ -56,6 +56,21 @@ fn test_from_slice() {
     check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]);
     check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]);
 }
 }
 
 
+#[test]
+fn test_assign_from_slice() {
+    fn check(slice: &[BigDigit], data: &[BigDigit]) {
+        let mut p = BigUint::from_slice(&[2627_u32, 0_u32, 9182_u32, 42_u32]);
+        p.assign_from_slice(slice);
+        assert!(p.data == data);
+    }
+    check(&[1], &[1]);
+    check(&[0, 0, 0], &[]);
+    check(&[1, 2, 0, 0], &[1, 2]);
+    check(&[0, 0, 1, 2], &[0, 0, 1, 2]);
+    check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]);
+    check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]);
+}
+
 #[test]
 #[test]
 fn test_from_bytes_be() {
 fn test_from_bytes_be() {
     fn check(s: &str, result: &str) {
     fn check(s: &str, result: &str) {