From af82adce751ec8bc983478ad201d148502bb4a69 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Sun, 17 Aug 2014 11:15:07 -0400 Subject: [PATCH] Make BigUint and BigInt Hash, fixes #16551 --- src/libnum/bigint.rs | 55 +++++++++++++++++++++++++++++++++++++++++++- src/libnum/lib.rs | 1 + 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/libnum/bigint.rs b/src/libnum/bigint.rs index 3a5f7649201..48fc9fb4a38 100644 --- a/src/libnum/bigint.rs +++ b/src/libnum/bigint.rs @@ -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 hash::Hash 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 @@ impl fmt::Show for BigInt { } } +impl hash::Hash 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 { @@ -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 @@ mod biguint_tests { } } + #[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 @@ mod bigint_tests { } } + #[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) { diff --git a/src/libnum/lib.rs b/src/libnum/lib.rs index 5cc2eee7da7..f12279b20e8 100644 --- a/src/libnum/lib.rs +++ b/src/libnum/lib.rs @@ -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]