]> git.lizzy.rs Git - rust.git/commitdiff
Make BigUint and BigInt Hash, fixes #16551
authorAlexis Beingessner <a.beingessner@gmail.com>
Sun, 17 Aug 2014 15:15:07 +0000 (11:15 -0400)
committerAlexis Beingessner <a.beingessner@gmail.com>
Sun, 17 Aug 2014 16:26:33 +0000 (12:26 -0400)
src/libnum/bigint.rs
src/libnum/lib.rs

index 3a5f7649201cb6ce0f50493aef765f05b785a400..48fc9fb4a38c6d0e4387f03e7c5bc3a00ac57985 100644 (file)
@@ -59,7 +59,7 @@
 use Integer;
 use rand::Rng;
 
-use std::{cmp, fmt};
+use std::{cmp, fmt, hash};
 use std::default::Default;
 use std::from_str::FromStr;
 use std::num::CheckedDiv;
@@ -150,6 +150,22 @@ impl Default for BigUint {
     fn default() -> BigUint { Zero::zero() }
 }
 
+impl<S: hash::Writer> hash::Hash<S> for BigUint {
+    fn hash(&self, state: &mut S) {
+        // hash 0 in case it's all 0's
+        0u32.hash(state);
+
+        let mut found_first_value = false;
+        for elem in self.data.iter().rev() {
+            // don't hash any leading 0's, they shouldn't affect the hash
+            if found_first_value || *elem != 0 {
+                found_first_value = true;
+                elem.hash(state);
+            }
+        }
+    }
+}
+
 impl fmt::Show for BigUint {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}", self.to_str_radix(10))
@@ -881,6 +897,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
+impl<S: hash::Writer> hash::Hash<S> for BigInt {
+    fn hash(&self, state: &mut S) {
+        (self.sign == Plus).hash(state);
+        self.data.hash(state);
+    }
+}
+
 impl FromStr for BigInt {
     #[inline]
     fn from_str(s: &str) -> Option<BigInt> {
@@ -1409,6 +1432,7 @@ mod biguint_tests {
     use std::num::CheckedDiv;
     use std::rand::task_rng;
     use std::u64;
+    use std::hash::hash;
 
     #[test]
     fn test_from_slice() {
@@ -1460,6 +1484,19 @@ fn test_cmp() {
         }
     }
 
+    #[test]
+    fn test_hash() {
+        let a = BigUint::new(vec!());
+        let b = BigUint::new(vec!(0));
+        let c = BigUint::new(vec!(1));
+        let d = BigUint::new(vec!(1,0,0,0,0,0));
+        let e = BigUint::new(vec!(0,0,0,0,0,1));
+        assert!(hash(&a) == hash(&b));
+        assert!(hash(&b) != hash(&c));
+        assert!(hash(&c) == hash(&d));
+        assert!(hash(&d) != hash(&e));
+    }
+
     #[test]
     fn test_bitand() {
         fn check(left: &[BigDigit],
@@ -2257,6 +2294,7 @@ mod bigint_tests {
     use std::num::{ToPrimitive, FromPrimitive};
     use std::rand::task_rng;
     use std::u64;
+    use std::hash::hash;
 
     #[test]
     fn test_from_biguint() {
@@ -2314,6 +2352,21 @@ fn test_cmp() {
         }
     }
 
+    #[test]
+    fn test_hash() {
+        let a = BigInt::new(Zero, vec!());
+        let b = BigInt::new(Zero, vec!(0));
+        let c = BigInt::new(Plus, vec!(1));
+        let d = BigInt::new(Plus, vec!(1,0,0,0,0,0));
+        let e = BigInt::new(Plus, vec!(0,0,0,0,0,1));
+        let f = BigInt::new(Minus, vec!(1));
+        assert!(hash(&a) == hash(&b));
+        assert!(hash(&b) != hash(&c));
+        assert!(hash(&c) == hash(&d));
+        assert!(hash(&d) != hash(&e));
+        assert!(hash(&c) != hash(&f));
+    }
+
     #[test]
     fn test_convert_i64() {
         fn check(b1: BigInt, i: i64) {
index 5cc2eee7da75c2743695c41c1f414621f661e8b4..f12279b20e8ef5eae82e46f5c4686ae24020cecb 100644 (file)
@@ -43,6 +43,7 @@
 //! [newt]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
 
 #![feature(macro_rules)]
+#![feature(default_type_params)]
 
 #![crate_name = "num"]
 #![experimental]