Skip to content

Commit af82adc

Browse files
committed
Make BigUint and BigInt Hash, fixes #16551
1 parent 02f9fd8 commit af82adc

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

src/libnum/bigint.rs

+54-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
use Integer;
6060
use rand::Rng;
6161

62-
use std::{cmp, fmt};
62+
use std::{cmp, fmt, hash};
6363
use std::default::Default;
6464
use std::from_str::FromStr;
6565
use std::num::CheckedDiv;
@@ -150,6 +150,22 @@ impl Default for BigUint {
150150
fn default() -> BigUint { Zero::zero() }
151151
}
152152

153+
impl<S: hash::Writer> hash::Hash<S> for BigUint {
154+
fn hash(&self, state: &mut S) {
155+
// hash 0 in case it's all 0's
156+
0u32.hash(state);
157+
158+
let mut found_first_value = false;
159+
for elem in self.data.iter().rev() {
160+
// don't hash any leading 0's, they shouldn't affect the hash
161+
if found_first_value || *elem != 0 {
162+
found_first_value = true;
163+
elem.hash(state);
164+
}
165+
}
166+
}
167+
}
168+
153169
impl fmt::Show for BigUint {
154170
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155171
write!(f, "{}", self.to_str_radix(10))
@@ -881,6 +897,13 @@ impl fmt::Show for BigInt {
881897
}
882898
}
883899

900+
impl<S: hash::Writer> hash::Hash<S> for BigInt {
901+
fn hash(&self, state: &mut S) {
902+
(self.sign == Plus).hash(state);
903+
self.data.hash(state);
904+
}
905+
}
906+
884907
impl FromStr for BigInt {
885908
#[inline]
886909
fn from_str(s: &str) -> Option<BigInt> {
@@ -1409,6 +1432,7 @@ mod biguint_tests {
14091432
use std::num::CheckedDiv;
14101433
use std::rand::task_rng;
14111434
use std::u64;
1435+
use std::hash::hash;
14121436

14131437
#[test]
14141438
fn test_from_slice() {
@@ -1460,6 +1484,19 @@ mod biguint_tests {
14601484
}
14611485
}
14621486

1487+
#[test]
1488+
fn test_hash() {
1489+
let a = BigUint::new(vec!());
1490+
let b = BigUint::new(vec!(0));
1491+
let c = BigUint::new(vec!(1));
1492+
let d = BigUint::new(vec!(1,0,0,0,0,0));
1493+
let e = BigUint::new(vec!(0,0,0,0,0,1));
1494+
assert!(hash(&a) == hash(&b));
1495+
assert!(hash(&b) != hash(&c));
1496+
assert!(hash(&c) == hash(&d));
1497+
assert!(hash(&d) != hash(&e));
1498+
}
1499+
14631500
#[test]
14641501
fn test_bitand() {
14651502
fn check(left: &[BigDigit],
@@ -2257,6 +2294,7 @@ mod bigint_tests {
22572294
use std::num::{ToPrimitive, FromPrimitive};
22582295
use std::rand::task_rng;
22592296
use std::u64;
2297+
use std::hash::hash;
22602298

22612299
#[test]
22622300
fn test_from_biguint() {
@@ -2314,6 +2352,21 @@ mod bigint_tests {
23142352
}
23152353
}
23162354

2355+
#[test]
2356+
fn test_hash() {
2357+
let a = BigInt::new(Zero, vec!());
2358+
let b = BigInt::new(Zero, vec!(0));
2359+
let c = BigInt::new(Plus, vec!(1));
2360+
let d = BigInt::new(Plus, vec!(1,0,0,0,0,0));
2361+
let e = BigInt::new(Plus, vec!(0,0,0,0,0,1));
2362+
let f = BigInt::new(Minus, vec!(1));
2363+
assert!(hash(&a) == hash(&b));
2364+
assert!(hash(&b) != hash(&c));
2365+
assert!(hash(&c) == hash(&d));
2366+
assert!(hash(&d) != hash(&e));
2367+
assert!(hash(&c) != hash(&f));
2368+
}
2369+
23172370
#[test]
23182371
fn test_convert_i64() {
23192372
fn check(b1: BigInt, i: i64) {

src/libnum/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
//! [newt]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
4444
4545
#![feature(macro_rules)]
46+
#![feature(default_type_params)]
4647

4748
#![crate_name = "num"]
4849
#![experimental]

0 commit comments

Comments
 (0)