├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── benches ├── bench_web2dict.rs ├── pseudo-random-data.bin └── sample-dict ├── src ├── farmhashcc_shared.rs ├── farmhashmk.rs ├── farmhashmk_shared.rs ├── farmhashna.rs ├── farmhashna_shared.rs ├── farmhashuo.rs ├── farmhashxo.rs ├── lib.rs └── platform.rs └── tests ├── test_hash32.rs └── test_hash64.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "farmhash" 3 | version = "1.1.5" 4 | authors = ["Seif Lotfy "] 5 | 6 | # A short blurb about the package. This is not rendered in any format when 7 | # uploaded to crates.io (aka this is not markdown) 8 | description = "Farmhash is a successor to Cityhash (also from Google). Farmhash, like Cityhash before it, use ideas from Austin Appleby's MurmurHash." 9 | 10 | # These URLs point to more information about the repository 11 | homepage = "http://seif.codes" 12 | repository = "https://github.com/seiflotfy/rust-farmhash" 13 | 14 | # This points to a file in the repository (relative to this Cargo.toml). The 15 | # contents of this file are stored and indexed in the registry. 16 | readme = "./README.md" 17 | 18 | # This is a small list of keywords used to categorize and search for this 19 | # package. 20 | keywords = ["farmhash", "hashing"] 21 | 22 | # This is a string description of the license for this package. Currently 23 | # crates.io will validate the license provided against a whitelist of known 24 | # license identifiers from http://spdx.org/licenses/. Multiple licenses can 25 | # be separated with a `/` 26 | license = "MIT" 27 | 28 | [dev-dependencies] 29 | fnv = "1.0.0" 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Seif Lotfy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-farmhash 2 | 3 | Port of Google's Farmhash version 1.1 to pure Rust 4 | 5 | For more on Farmhash see https://code.google.com/p/farmhash/ 6 | 7 | Farmhash is a successor to Cityhash (also from Google). Farmhash, like Cityhash 8 | before it, use ideas from Austin Appleby's MurmurHash. 9 | 10 | 11 | ## Example usage 12 | 13 | ```rust 14 | extern crate farmhash; 15 | 16 | ... 17 | 18 | let value: &str = "hello world"; 19 | let res32 = farmhash::hash32(&value.as_bytes()); 20 | // res32 ==> 430397466 21 | let res64 = farmhash::hash64(&value.as_bytes()); 22 | // res64 ==> 6381520714923946011 23 | ``` 24 | 25 | ## Benchmarks 26 | 27 | Tested on /usr/share/dict/web2 on Mac OSX 28 | 29 | ``` 30 | farmhash: required 0.06485s with 0/235887 collisions 31 | fnv: required 0.12042s with 1/235887 collisions 32 | siphash: required 0.23546s with 0/235887 collisions 33 | ``` 34 | 35 | ### Note 36 | 37 | Since FarmHash is not a streaming hash. It is recommended to use the function hash64 or hash32 directly. 38 | Using the hasher interface will give you a different result if you write the same bytearray in chunks before calling finish. 39 | 40 | -------------------------------------------------------------------------------- /benches/bench_web2dict.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | extern crate farmhash; 4 | extern crate fnv; 5 | 6 | use self::farmhash::*; 7 | use self::test::Bencher; 8 | use std::fs::File; 9 | use std::io::prelude::*; 10 | use std::path::Path; 11 | use std::error::Error; 12 | use std::hash::{Hash, SipHasher, Hasher}; 13 | use test::black_box; 14 | 15 | // Macros to insert into other macros to test with Hash trait or with a direct 16 | // function 17 | macro_rules! hash_hashing { 18 | ($data:ident, $hasher:expr) => {{ 19 | let mut hasher = $hasher; 20 | $data.hash(&mut hasher); 21 | black_box(hasher.finish()); 22 | }} 23 | } 24 | 25 | macro_rules! direct_hashing_str { 26 | ($data:ident, $hasher:expr) => {{ 27 | black_box($hasher(&$data.as_bytes())); 28 | }} 29 | } 30 | 31 | macro_rules! direct_hashing_u8 { 32 | ($data:ident, $hasher:expr) => {{ 33 | black_box($hasher($data)); 34 | }} 35 | } 36 | 37 | // Dictonary benchmark 38 | macro_rules! dict_bench { 39 | ($fun:ident, $hashing:ident, $hasher:expr) => { 40 | #[bench] 41 | fn $fun(b: &mut Bencher) { 42 | let path = Path::new("benches/sample-dict"); 43 | let display = path.display(); 44 | 45 | // Open file in read-only mode 46 | let mut file = match File::open(&path) { 47 | Err(e) => panic!("Couldn't open '{}': {}", display, e), 48 | Ok(file) => file, 49 | }; 50 | 51 | // Read all contents to string 52 | let mut dict = String::new(); 53 | if let Err(e) = file.read_to_string(&mut dict) { 54 | panic!("Couldn't read '{}': {}", display, e); 55 | } 56 | 57 | b.iter(|| { 58 | for s in dict.split('\n') { 59 | $hashing!(s, $hasher) 60 | } 61 | }); 62 | } 63 | } 64 | } 65 | 66 | dict_bench!(bench_dict_sip, hash_hashing, SipHasher::default()); 67 | dict_bench!(bench_dict_fnv, hash_hashing, fnv::FnvHasher::default()); 68 | dict_bench!(bench_dict_farm, hash_hashing, farmhash::FarmHasher::default()); 69 | dict_bench!(bench_dict_farm_direct, direct_hashing_str, farmhash::hash64); 70 | 71 | 72 | // Lorem Ipsum benchmark 73 | macro_rules! lorem_bench { 74 | ($fun:ident, $hashing:ident, $hasher:expr) => { 75 | #[bench] 76 | fn $fun(b: &mut Bencher) { 77 | let data = ["Lorem", "ipsum", "dolor", "sit", "amet,", "consetetur", 78 | "sadipscing", "elitr,", "sed", "diam", "nonumy", 79 | "eirmod", "tempor", "invidunt", "ut", "labore", "et", 80 | "dolore", "magna", "aliquyam", "erat,", "sed", "diam", 81 | "voluptua."]; 82 | 83 | b.iter(|| { 84 | for s in &data { 85 | $hashing!(s, $hasher) 86 | } 87 | }); 88 | } 89 | } 90 | } 91 | 92 | lorem_bench!(bench_lorem_sip, hash_hashing, SipHasher::default()); 93 | lorem_bench!(bench_lorem_fnv, hash_hashing, fnv::FnvHasher::default()); 94 | lorem_bench!(bench_lorem_farm, hash_hashing, farmhash::FarmHasher::default()); 95 | lorem_bench!(bench_lorem_farm_direct, direct_hashing_str, farmhash::hash64); 96 | 97 | 98 | // Pseudo random data benchmark 99 | macro_rules! lorem_bench { 100 | ($fun:ident, $chunk:expr, $hashing:ident, $hasher:expr) => { 101 | #[bench] 102 | fn $fun(b: &mut Bencher) { 103 | let path = Path::new("benches/pseudo-random-data.bin"); 104 | let display = path.display(); 105 | 106 | // Open file in read-only mode 107 | let mut file = match File::open(&path) { 108 | Err(e) => panic!("Couldn't open '{}': {}", display, e), 109 | Ok(file) => file, 110 | }; 111 | 112 | // Read all contents to string 113 | let mut data = Vec::new(); 114 | if let Err(e) = file.read_to_end(&mut data) { 115 | panic!("Couldn't read '{}': {}", display, e); 116 | } 117 | 118 | b.iter(|| { 119 | for s in data.chunks($chunk) { 120 | $hashing!(s, $hasher) 121 | } 122 | }); 123 | } 124 | } 125 | } 126 | 127 | lorem_bench!(bench_pseurand_big_sip, 512, hash_hashing, SipHasher::default()); 128 | lorem_bench!(bench_pseurand_big_fnv, 512, hash_hashing, fnv::FnvHasher::default()); 129 | lorem_bench!(bench_pseurand_big_farm, 512, hash_hashing, farmhash::FarmHasher::default()); 130 | lorem_bench!(bench_pseurand_big_farm_direct, 512, direct_hashing_u8, farmhash::hash64); 131 | 132 | lorem_bench!(bench_pseurand_small_sip, 4, hash_hashing, SipHasher::default()); 133 | lorem_bench!(bench_pseurand_small_fnv, 4, hash_hashing, fnv::FnvHasher::default()); 134 | lorem_bench!(bench_pseurand_small_farm, 4, hash_hashing, farmhash::FarmHasher::default()); 135 | lorem_bench!(bench_pseurand_small_farm_direct, 4, direct_hashing_u8, farmhash::hash64); 136 | -------------------------------------------------------------------------------- /benches/pseudo-random-data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seiflotfy/rust-farmhash/a2374a78c15bd949e7140954f278c1867c66e84e/benches/pseudo-random-data.bin -------------------------------------------------------------------------------- /src/farmhashcc_shared.rs: -------------------------------------------------------------------------------- 1 | // Based on the original C++ farmhashcc.cc 2 | 3 | // This file provides a 32-bit hash equivalent to CityHash32 (v1.1.1) 4 | // and a 128-bit hash equivalent to CityHash128 (v1.1.1). It also provides 5 | // a seeded 32-bit hash function similar to CityHash32. 6 | 7 | use platform::*; 8 | use std::mem; 9 | 10 | fn hash32_len_13_to_24(s: &[u8]) -> u32 { 11 | let len = s.len() as usize; 12 | let a = fetch32(&s[(len>>1 as u64) - 4..]); 13 | let b = fetch32(&s[4..]); 14 | let c = fetch32(&s[len-8..]); 15 | let d = fetch32(&s[len>>1..]); 16 | let e = fetch32(&s[0..]); 17 | let f = fetch32(&s[len-4..]); 18 | let h = len as u32; 19 | return fmix(mur(f, mur(e, mur(d, mur(c, mur(b, mur(a, h))))))); 20 | } 21 | 22 | fn hash32_len_0_to_4(s: &[u8]) -> u32 { 23 | let len = s.len() as usize; 24 | let mut b: u32 = 0; 25 | let mut c: u32 = 9; 26 | for i in 0..len { 27 | let v: u8 = s[i]; 28 | b = b.wrapping_mul(C1) + v as u32; 29 | c ^= b; 30 | } 31 | return fmix(mur(b, mur(len as u32, c))); 32 | } 33 | 34 | fn hash32_len_5_to_12(s: &[u8]) -> u32 { 35 | let len = s.len() as usize; 36 | let mut a = len as u32; 37 | let mut b = len as u32 * 5; 38 | let mut c: u32 = 9; 39 | let d: u32 = b; 40 | 41 | a += fetch32(&s[0..]); 42 | b += fetch32(&s[len-4..]); 43 | c += fetch32(&s[((len >> 1) & 4)..]); 44 | return fmix(mur(c, mur(b, mur(a, d)))); 45 | } 46 | 47 | 48 | pub fn hash32(mut s: &[u8]) -> u32 { 49 | let len = s.len() as usize; 50 | if len <= 24 { 51 | if len <= 12 { 52 | if len <= 4 { 53 | return hash32_len_0_to_4(s) 54 | } 55 | return hash32_len_5_to_12(s) 56 | } 57 | return hash32_len_13_to_24(s) 58 | } 59 | 60 | // len > 24 61 | let mut h = len as u32; 62 | let mut g = (len as u32).wrapping_mul(C1); 63 | let mut f = g; 64 | let a0 = rotate32(fetch32(&s[(len-4)..]).wrapping_mul(C1), 17) * C2; 65 | let a1 = rotate32(fetch32(&s[(len-8)..]).wrapping_mul(C1), 17) * C2; 66 | let a2 = rotate32(fetch32(&s[(len-16)..]).wrapping_mul(C1), 17) * C2; 67 | let a3 = rotate32(fetch32(&s[(len-12)..]).wrapping_mul(C1), 17) * C2; 68 | let a4 = rotate32(fetch32(&s[(len-20)..]).wrapping_mul(C1), 17) * C2; 69 | h ^= a0; 70 | h = rotate32(h, 19); 71 | h = (h*5).wrapping_add(0xe6546b64); 72 | h ^= a2; 73 | h = rotate32(h, 19); 74 | h = (h*5).wrapping_add(0xe6546b64); 75 | g ^= a1; 76 | g = rotate32(g, 19); 77 | g = (g*5).wrapping_add(0xe6546b64); 78 | g ^= a3; 79 | g = rotate32(g, 19); 80 | g = (g*5).wrapping_add(0xe6546b64); 81 | f += a4; 82 | f = rotate32(f, 19); 83 | f = (f*5).wrapping_add(0xe6546b64); 84 | 85 | let mut iters = ((len - 1) / 20) as u64; 86 | while iters > 0{ 87 | let a0 = rotate32(fetch32(&s[..]).wrapping_mul(C1), 17).wrapping_mul(C2); 88 | let a1 = fetch32(&s[4..]); 89 | let a2 = rotate32(fetch32(&s[8..]).wrapping_mul(C1), 17).wrapping_mul(C2); 90 | let a3 = rotate32(fetch32(&s[12..]).wrapping_mul(C1), 17).wrapping_mul(C2); 91 | let a4 = fetch32(&s[16..]); 92 | h ^= a0; 93 | h = rotate32(h, 18); 94 | h = (h*5).wrapping_add(0xe6546b64); 95 | f += a1; 96 | f = rotate32(f, 19); 97 | f = f.wrapping_mul(C1); 98 | g += a2; 99 | g = rotate32(g, 18); 100 | g = (g*5).wrapping_add(0xe6546b64); 101 | h ^= a3 + a1; 102 | h = rotate32(h, 19); 103 | h = (h*5).wrapping_add(0xe6546b64); 104 | g ^= a4; 105 | g = bswap32(g) * 5; 106 | h += a4 * 5; 107 | h = bswap32(h); 108 | f += a0; 109 | //PERMUTE3(f, h, g) - swap(a,b);swap(b,c) 110 | mem::swap(&mut h, &mut f); 111 | 112 | mem::swap(&mut g, &mut f); 113 | s = &s[20..]; 114 | iters-=1; 115 | } 116 | g = rotate32(g, 11).wrapping_mul(C1); 117 | g = rotate32(g, 17).wrapping_mul(C1); 118 | f = rotate32(f, 11).wrapping_mul(C1); 119 | f = rotate32(f, 17).wrapping_mul(C1); 120 | h = rotate32(h+g, 19); 121 | h = h*5 + 0xe6546b64; 122 | h = rotate32(h, 17).wrapping_mul(C1); 123 | h = rotate32(h+f, 19); 124 | h = h*5 + 0xe6546b64; 125 | h = rotate32(h, 17).wrapping_mul(C1); 126 | return h 127 | } 128 | 129 | // Return a 16-byte hash for 48 bytes. Quick and dirty. 130 | // Callers do best to use "random-looking" values for a and b. 131 | // Note: C++ returned pair 132 | pub fn weak_hash_len_32_with_seeds(w: u64, x: u64, y:u64, z:u64, mut a:u64, mut b:u64) -> Uint128 { 133 | a = a.wrapping_add(w); 134 | b = rotate64(b.wrapping_add(a).wrapping_add(z), 21); 135 | let c = a; 136 | a = a.wrapping_add(x); 137 | a = a.wrapping_add(y); 138 | b = b.wrapping_add(rotate64(a, 44)); 139 | return Uint128{first: a.wrapping_add(z), second:b.wrapping_add(c)}; 140 | } 141 | 142 | // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. 143 | // Note: original C++ returned a pair 144 | pub fn weak_hash_len_32_with_seeds_bytes(s: &[u8], a:u64, b:u64) -> Uint128 { 145 | return weak_hash_len_32_with_seeds(fetch64(&s[0..8]), 146 | fetch64(&s[8..16]), 147 | fetch64(&s[16..24]), 148 | fetch64(&s[24..32]), 149 | a, 150 | b); 151 | } 152 | -------------------------------------------------------------------------------- /src/farmhashmk.rs: -------------------------------------------------------------------------------- 1 | // Based on the original C++ farmhashmk.cc 2 | 3 | // Note: These functions clashed with the versions in farmhashcc 4 | // Some only differ by taking a seed but others are quite different 5 | // To avoid clashes I've added mk to the start of these names 6 | 7 | use platform::*; 8 | use farmhashcc_shared; 9 | use farmhashmk_shared::*; 10 | 11 | pub fn mk_hash32_with_seed(s: &[u8], seed: u32) -> u32 { 12 | let len = s.len() as usize; 13 | if len <= 24 { 14 | if len >= 13 { 15 | return mk_hask32_len_13_to_24(s, seed.wrapping_mul(C1)) 16 | } else if len >= 5 { 17 | return mk_hash32_len_5_to_12(s, seed) 18 | } else { 19 | return mk_hash32_len_0_to_4(s, seed) 20 | } 21 | } 22 | let h = mk_hask32_len_13_to_24(&s[0 .. 24], seed^(len as u32)); 23 | return mur(farmhashcc_shared::hash32(&s[24..])+seed, h) 24 | } 25 | 26 | pub fn mk_hash32(mut s: &[u8]) -> u32{ 27 | let len = s.len() as usize; 28 | if len <= 24 { 29 | if len <= 12 { 30 | if len <= 4 { 31 | return mk_hash32_len_0_to_4(s, 0) 32 | } 33 | return mk_hash32_len_5_to_12(s, 0) 34 | } 35 | return mk_hask32_len_13_to_24(s, 0) 36 | } 37 | 38 | // len > 24 39 | //var h, g, f uint32 40 | let mut h = len as u32; 41 | let mut g = (len as u32).wrapping_mul(C1); 42 | let mut f: u32 = g; 43 | let a0 = rotate32(fetch32(&s[len-4..]).wrapping_mul(C1), 17).wrapping_mul(C2); 44 | let a1 = rotate32(fetch32(&s[len-8..]).wrapping_mul(C1), 17).wrapping_mul(C2); 45 | let a2 = rotate32(fetch32(&s[len-16..]).wrapping_mul(C1), 17).wrapping_mul(C2); 46 | let a3 = rotate32(fetch32(&s[len-12..]).wrapping_mul(C1), 17).wrapping_mul(C2); 47 | let a4 = rotate32(fetch32(&s[len-20..]).wrapping_mul(C1), 17).wrapping_mul(C2); 48 | h ^= a0; 49 | h = rotate32(h, 19); 50 | h = h.wrapping_mul(5).wrapping_add(0xe6546b64); 51 | h ^= a2; 52 | h = rotate32(h, 19); 53 | h = h.wrapping_mul(5).wrapping_add(0xe6546b64); 54 | g ^= a1; 55 | g = rotate32(g, 19); 56 | g = g.wrapping_mul(5).wrapping_add(0xe6546b64); 57 | g ^= a3; 58 | g = rotate32(g, 19); 59 | g = g.wrapping_mul(5).wrapping_add(0xe6546b64); 60 | f = f.wrapping_add(a4); 61 | f = rotate32(f, 19).wrapping_add(113); 62 | let mut iters = ((len - 1) / 20) as u64; 63 | while iters > 0 { 64 | let a = fetch32(&s); 65 | let b = fetch32(&s[4..]); 66 | let c = fetch32(&s[8..]); 67 | let d = fetch32(&s[12..]); 68 | let e = fetch32(&s[16..]); 69 | h = h.wrapping_add(a); 70 | g = g.wrapping_add(b); 71 | f = f.wrapping_add(c); 72 | h = mur(d, h).wrapping_add(e); 73 | g = mur(c, g).wrapping_add(a); 74 | f = mur(b.wrapping_add(e.wrapping_mul(C1)), f).wrapping_add(d); 75 | f = f.wrapping_add(g); 76 | g = g.wrapping_add(f); 77 | s = &s[20..]; 78 | iters-=1; 79 | } 80 | g = rotate32(g, 11).wrapping_mul(C1); 81 | g = rotate32(g, 17).wrapping_mul(C1); 82 | f = rotate32(f, 11).wrapping_mul(C1); 83 | f = rotate32(f, 17).wrapping_mul(C1); 84 | h = rotate32(h.wrapping_add(g), 19); 85 | h = h.wrapping_mul(5).wrapping_add(0xe6546b64); 86 | h = rotate32(h, 17).wrapping_mul(C1); 87 | h = rotate32(h.wrapping_add(f), 19); 88 | h = h.wrapping_mul(5).wrapping_add(0xe6546b64); 89 | h = rotate32(h, 17).wrapping_mul(C1); 90 | return h 91 | } 92 | -------------------------------------------------------------------------------- /src/farmhashmk_shared.rs: -------------------------------------------------------------------------------- 1 | // Based on the original C++ farmhashmk.cc 2 | 3 | // Note: These functions clashed with the versions in farmhashcc 4 | // Some only differ by taking a seed but others are quite different 5 | // To avoid clashes I've added mk to the start of these names 6 | 7 | use platform::*; 8 | 9 | pub fn mk_hask32_len_13_to_24 (s: &[u8], seed: u32) -> u32 { 10 | let len = s.len() as usize; 11 | let mut a = fetch32(&s[(len>>1)-4..]); 12 | let b = fetch32(&s[4..]); 13 | let c = fetch32(&s[len-8..]); 14 | let d = fetch32(&s[len>>1..]); 15 | let e = fetch32(&s); 16 | let f = fetch32(&s[len-4..]); 17 | let mut h = d.wrapping_mul(C1) + (len as u32) + seed; 18 | a = rotate32(a, 12).wrapping_add(f); 19 | h = mur(c, h).wrapping_add(a); 20 | a = rotate32(a, 3).wrapping_add(c); 21 | h = mur(e, h).wrapping_add(a); 22 | a = rotate32(a.wrapping_add(f), 12).wrapping_add(d); 23 | h = mur(b^seed, h).wrapping_add(a); 24 | return fmix(h); 25 | } 26 | 27 | pub fn mk_hash32_len_0_to_4 (s: &[u8], seed: u32) -> u32 { 28 | let len = s.len() as usize; 29 | let mut b = seed; 30 | let mut c: u32 = 9; 31 | for i in 0..len{ 32 | let v = s[i] as u8; 33 | b = b.wrapping_mul(C1).wrapping_add(v as u32); 34 | c ^= b; 35 | } 36 | return fmix(mur(b, mur((len as u32), c))) 37 | } 38 | 39 | pub fn mk_hash32_len_5_to_12 (s: &[u8], seed: u32) -> u32 { 40 | let len = s.len() as usize; 41 | let mut a = len as u32; 42 | let mut b =(len as u32) * 5; 43 | let mut c: u32 = 9; 44 | let d: u32 = b + seed; 45 | a += fetch32(&s); 46 | b += fetch32(&s[len-4..]); 47 | c += fetch32(&s[(len>>1)&4..]); 48 | return fmix(seed ^ mur(c, mur(b, mur(a, d)))) 49 | } -------------------------------------------------------------------------------- /src/farmhashna.rs: -------------------------------------------------------------------------------- 1 | // Based on the original C++ farmhashna.cc 2 | use platform::*; 3 | use farmhashna_shared::*; 4 | use farmhashcc_shared; 5 | use std::mem; 6 | 7 | // renamed from hash64 to make it clearer elsewhere which is being called 8 | pub fn na_hash64(mut s: &[u8]) -> u64 { 9 | let len = s.len() as usize; 10 | const SEED: u64 = 81; 11 | if len <= 32 { 12 | if len <= 16 { 13 | return hash_len_0_to_16(s); 14 | } else { 15 | return hash_len_17_to_32(s); 16 | } 17 | } else if len <= 64{ 18 | return hash_len_33_to_64(s); 19 | } 20 | // For strings over 64 bytes we loop. Internal state consists of 21 | // 56 bytes: v, w, x, y, and z. 22 | let mut x = SEED; 23 | let mut y: u64 = 2480279821605975764; // y := (seed*k1) + 113 24 | let mut z = shift_mix(y.wrapping_mul(K2).wrapping_add(113)).wrapping_mul(K2); 25 | let mut v = Uint128 {first:0, second:0}; 26 | let mut w = Uint128 {first:0, second:0}; 27 | 28 | x = x.wrapping_mul(K2).wrapping_add(fetch64(s)); 29 | 30 | let last64 = &s[len - 64..]; 31 | while { 32 | x = rotate64(x.wrapping_add(y).wrapping_add(v.first).wrapping_add(fetch64(&s[8..])), 37).wrapping_mul(K1); 33 | y = rotate64(y.wrapping_add(v.second).wrapping_add(fetch64(&s[48..])), 42).wrapping_mul(K1); 34 | x ^= w.second; 35 | y = y.wrapping_add(v.first).wrapping_add(fetch64(&s[40..])); 36 | z = rotate64(z.wrapping_add(w.first), 33).wrapping_mul(K1); 37 | v = farmhashcc_shared::weak_hash_len_32_with_seeds_bytes(&s,v.second.wrapping_mul(K1), x.wrapping_add(w.first)); 38 | w = farmhashcc_shared::weak_hash_len_32_with_seeds_bytes(&s[32..],z.wrapping_add(w.second), y.wrapping_add(fetch64(&s[16..]))); 39 | 40 | mem::swap(&mut z, &mut x); 41 | s = &s[64..]; 42 | s.len() >= 64 43 | } {} 44 | 45 | let mul = K1 + ((z & 0xff) << 1); 46 | 47 | // Make s point to the last 64 bytes of input. 48 | s = last64; 49 | w.first = w.first.wrapping_add(((len as u64 - 1) & 63)); 50 | v.first = v.first.wrapping_add(w.first); 51 | w.first = w.first.wrapping_add(v.first); 52 | x = rotate64(x.wrapping_add(y) 53 | .wrapping_add(v.first.wrapping_add(fetch64(&s[8..]))), 37).wrapping_mul(mul); 54 | y = rotate64(y.wrapping_add(v.second).wrapping_add(fetch64(&s[48..])), 42).wrapping_mul(mul); 55 | x ^= w.second.wrapping_mul(9); 56 | y = y.wrapping_add(v.first.wrapping_mul(9).wrapping_add(fetch64(&s[40..]))); 57 | z = rotate64(z.wrapping_add(w.first), 33).wrapping_mul(mul); 58 | v = farmhashcc_shared::weak_hash_len_32_with_seeds_bytes(&s, v.second.wrapping_mul(mul), 59 | x.wrapping_add(w.first)); 60 | w = farmhashcc_shared::weak_hash_len_32_with_seeds_bytes(&s[32..], z.wrapping_add(w.second), 61 | y.wrapping_add(fetch64(&s[16..]))); 62 | mem::swap(&mut z, &mut x); 63 | return hash_len_16_mul(hash_len_16_mul(v.first, w.first, mul).wrapping_add(shift_mix(y).wrapping_mul(K0).wrapping_add(z)), 64 | hash_len_16_mul(v.second, w.second, mul).wrapping_add(x), 65 | mul) 66 | } 67 | 68 | pub fn na_hash64_with_seed(s: &[u8], seed: u64) -> u64 { 69 | return na_hash64_with_seeds(s, K2, seed) 70 | } 71 | 72 | pub fn na_hash64_with_seeds(s: &[u8], seed0: u64, seed1: u64) -> u64 { 73 | return hash_len_16(na_hash64(s).wrapping_sub(seed0), seed1) 74 | } 75 | -------------------------------------------------------------------------------- /src/farmhashna_shared.rs: -------------------------------------------------------------------------------- 1 | use platform::*; 2 | 3 | pub fn shift_mix(val: u64) -> u64 { 4 | val ^ (val >> 47) 5 | } 6 | // Note: the C++ original was overloaded hashLen16() 7 | pub fn hash_len_16_mul(u: u64, v: u64, mul: u64) -> u64 { 8 | let mut a = (u ^ v).wrapping_mul(mul); 9 | a ^= a >> 47; 10 | let mut b = (v ^ a).wrapping_mul(mul); 11 | b ^= b >> 47; 12 | b = b.wrapping_mul(mul); 13 | return b; 14 | } 15 | 16 | pub fn hash_len_16(u: u64, v: u64) -> u64{ 17 | hash128to64(Uint128{first: u, second: v}) 18 | } 19 | 20 | pub fn hash_len_0_to_16(s: &[u8]) -> u64 { 21 | let len = s.len() as usize; 22 | if len >= 8 { 23 | let mul = K2.wrapping_add(len as u64 *2); 24 | let a = fetch64(s).wrapping_add(K2); 25 | let b = fetch64(&s[len - 8 ..]); 26 | let c = rotate64(b, 37).wrapping_mul(mul).wrapping_add(a); 27 | let d = rotate64(a, 25).wrapping_add(b).wrapping_mul(mul); 28 | return hash_len_16_mul(c, d, mul); 29 | } 30 | if len >= 4 { 31 | let mul = K2 + len as u64 * 2; 32 | let a = fetch32(s); 33 | return hash_len_16_mul(len as u64 + ((a as u64) << 3), fetch32(&s[len-4..]) as u64, mul); 34 | } 35 | if len > 0 { 36 | let a = s[0]; 37 | let b = if len >= 2 { s[1] } else { a }; // s[len / 2] 38 | let c = s[len - 1]; 39 | let y = a as u32 + ((b as u32) << 8); 40 | let z = len as u64 + ((c as u64) << 2); 41 | return shift_mix((y as u64).wrapping_mul(K2) ^ z.wrapping_mul(K0)).wrapping_mul(K2); 42 | } 43 | return K2; 44 | } 45 | 46 | // This probably works well for 16-byte strings as well, but it may be overkill 47 | // in that case. 48 | pub fn hash_len_17_to_32(s: &[u8]) -> u64 { 49 | let len = s.len() as usize; 50 | let mul = K2.wrapping_add((len as u64)*2); 51 | let a = fetch64(&s).wrapping_mul(K1); 52 | let b = fetch64(&s[8..]); 53 | let c = fetch64(&s[len-8..]).wrapping_mul(mul); 54 | let d = fetch64(&s[len-16..]).wrapping_mul(K2); 55 | return hash_len_16_mul(rotate64(a.wrapping_add(b), 43).wrapping_add(rotate64(c, 30)).wrapping_add(d), 56 | (a.wrapping_add(rotate64(b.wrapping_add(K2), 18))).wrapping_add(c), mul); 57 | } 58 | 59 | // Return an 8-byte hash for 33 to 64 bytes. 60 | pub fn hash_len_33_to_64(s: &[u8]) -> u64 { 61 | let len = s.len() as usize; 62 | let mul = K2.wrapping_add((len as u64) * 2); 63 | let a = fetch64(&s).wrapping_mul(K2); 64 | let b = fetch64(&s[8..]); 65 | let c = fetch64(&s[len-8..]).wrapping_mul(mul); 66 | let d = fetch64(&s[len-16..]).wrapping_mul(K2); 67 | let y = rotate64(a.wrapping_add(b), 43).wrapping_add(rotate64(c, 30)).wrapping_add(d); 68 | let z = hash_len_16_mul(y, a.wrapping_add(rotate64(b.wrapping_add(K2), 18)).wrapping_add(c), mul); 69 | let e = fetch64(&s[16..]).wrapping_mul(mul); 70 | let f = fetch64(&s[24..]); 71 | let g = (y.wrapping_add(fetch64(&s[len-32..]))).wrapping_mul(mul); 72 | let h = (z.wrapping_add(fetch64(&s[len-24..]))).wrapping_mul(mul); 73 | return hash_len_16_mul(rotate64(e.wrapping_add(f), 43).wrapping_add(rotate64(g, 30).wrapping_add(h)), 74 | e.wrapping_add(rotate64(f.wrapping_add(a), 18).wrapping_add(g)), mul); 75 | } 76 | -------------------------------------------------------------------------------- /src/farmhashuo.rs: -------------------------------------------------------------------------------- 1 | use platform::*; 2 | use farmhashna::*; 3 | use farmhashna_shared::*; 4 | use farmhashcc_shared::weak_hash_len_32_with_seeds_bytes; 5 | use std::mem; 6 | 7 | fn uo_h(x: u64, y: u64, mul: u64, r: u64) -> u64 { 8 | let mut a = (x ^ y).wrapping_mul(mul); 9 | a ^= a >> 47; 10 | let b = (y ^ a).wrapping_mul(mul); 11 | return rotate64(b, r).wrapping_mul(mul); 12 | } 13 | 14 | pub fn uo_hash64_with_seeds(mut s: &[u8], seed0: u64, seed1: u64) -> u64 { 15 | let len = s.len() as usize; 16 | if len <= 64 { 17 | return na_hash64_with_seeds(s, seed0, seed1) 18 | } 19 | 20 | // For strings over 64 bytes we loop. Internal state consists of 21 | // 64 bytes: u, v, w, x, y, and z. 22 | let mut x = seed0; 23 | let mut y = seed1.wrapping_mul(K1).wrapping_add(113); 24 | let mut z = shift_mix(y.wrapping_mul(K2)).wrapping_mul(K2); 25 | let mut v = Uint128{first: seed0, second: seed1}; 26 | let mut w = Uint128{first: 0, second: 0}; 27 | let mut u = x.wrapping_sub(z); 28 | x = x.wrapping_mul(K2); 29 | let mul = K2.wrapping_add(u & 0x82); 30 | 31 | // Process the input in blocks of 64 bytes 32 | let last64 = &s[len - 64..]; 33 | 34 | while s.len() >= 64 { 35 | // The `s.len() >= 64` should allow the boundary checks to be elided. 36 | let a0 = fetch64(&s[0..8]); 37 | let a1 = fetch64(&s[8..16]); 38 | let a2 = fetch64(&s[16..24]); 39 | let a3 = fetch64(&s[24..32]); 40 | let a4 = fetch64(&s[32..40]); 41 | let a5 = fetch64(&s[40..48]); 42 | let a6 = fetch64(&s[48..56]); 43 | let a7 = fetch64(&s[56..64]); 44 | x = x.wrapping_add(a0).wrapping_add(a1); 45 | y = y.wrapping_add(a2); 46 | z = z.wrapping_add(a3); 47 | v.first = v.first.wrapping_add(a4); 48 | v.second = v.second.wrapping_add(a5).wrapping_add(a1); 49 | w.first = w.first.wrapping_add(a6); 50 | w.second = w.second.wrapping_add(a7); 51 | 52 | x = rotate64(x, 26); 53 | x = x.wrapping_mul(9); 54 | y = rotate64(y, 29); 55 | z = z.wrapping_mul(mul); 56 | 57 | v.first = rotate64(v.first, 33); 58 | v.second = rotate64(v.second, 30); 59 | w.first ^= x; 60 | w.first = w.first.wrapping_mul(9); 61 | z = rotate64(z, 32); 62 | z = z.wrapping_add(w.second); 63 | w.second = w.second.wrapping_add(z); 64 | z = z.wrapping_mul(9); 65 | 66 | mem::swap(&mut u, &mut y); 67 | 68 | z = z.wrapping_add(a0).wrapping_add(a6); 69 | v.first = v.first.wrapping_add(a2); 70 | v.second = v.second.wrapping_add(a3); 71 | w.first = w.first.wrapping_add(a4); 72 | w.second = w.second.wrapping_add(a5).wrapping_add(a6); 73 | x = x.wrapping_add(a1); 74 | y = y.wrapping_add(a7); 75 | 76 | y = y.wrapping_add(v.first); 77 | v.first = v.first.wrapping_add(x).wrapping_sub(y); 78 | v.second = v.second.wrapping_add(w.first); 79 | w.first = w.first.wrapping_add(v.second); 80 | w.second = w.second.wrapping_add(x).wrapping_sub(y); 81 | x = x.wrapping_add(w.second); 82 | w.second = rotate64(w.second, 34); 83 | 84 | mem::swap(&mut u, &mut z); 85 | s = &s[64..]; 86 | } 87 | // Make s point to the last 64 bytes of input. 88 | s = last64; 89 | u = u.wrapping_mul(9); 90 | v.second = rotate64(v.second, 28); 91 | v.first = rotate64(v.first, 20); 92 | w.first = w.first.wrapping_add((len-1) as u64 & 63); 93 | u = u.wrapping_add(y); 94 | y = y.wrapping_add(u); 95 | x = rotate64(y.wrapping_sub(x).wrapping_add(v.first).wrapping_add(fetch64(&s[8..])), 37).wrapping_mul(mul); 96 | y = rotate64(y^v.second^fetch64(&s[48..]), 42).wrapping_mul(mul); 97 | 98 | x ^= w.second.wrapping_mul(9); 99 | y = y.wrapping_add(v.first).wrapping_add(fetch64(&s[40..])); 100 | z = rotate64(z.wrapping_add(w.first), 33).wrapping_mul(mul); 101 | 102 | v = weak_hash_len_32_with_seeds_bytes(s, v.second.wrapping_mul(mul), x.wrapping_add(w.first)); 103 | w = weak_hash_len_32_with_seeds_bytes(&s[32..], z.wrapping_add(w.second), y.wrapping_add(fetch64(&s[16..]))); 104 | return uo_h(hash_len_16_mul(v.first.wrapping_add(x), w.first^y, mul).wrapping_add(z).wrapping_sub(u), 105 | uo_h(v.second.wrapping_add(y), w.second.wrapping_add(z), K2, 30)^x, 106 | K2, 107 | 31); 108 | } 109 | 110 | pub fn uo_hash64_with_seed(s: &[u8], seed: u64) -> u64 { 111 | if s.len() <= 64 { 112 | return na_hash64_with_seed(s, seed) 113 | } 114 | return uo_hash64_with_seeds(s, 0, seed) 115 | } 116 | 117 | pub fn uo_hash64(s: &[u8]) -> u64 { 118 | if s.len() <= 64 { 119 | return na_hash64(s) 120 | } 121 | return uo_hash64_with_seeds(s, 81, 0) 122 | } 123 | -------------------------------------------------------------------------------- /src/farmhashxo.rs: -------------------------------------------------------------------------------- 1 | use platform::*; 2 | use farmhashna::*; 3 | use farmhashuo::*; 4 | use farmhashna_shared::*; 5 | 6 | fn xo_h32(s: &[u8], len: usize, mul: u64, seed0: u64, seed1: u64) -> u64 { 7 | let mut a = fetch64(s).wrapping_mul(K1); 8 | let mut b = fetch64(&s[8..]); 9 | let c = fetch64(&s[len - 8..]).wrapping_mul(mul); 10 | let d = fetch64(&s[len - 16 ..]).wrapping_mul(K2); 11 | let u = rotate64(a.wrapping_add(b), 43) .wrapping_add(rotate64(c, 30)) .wrapping_add(d) .wrapping_add(seed0); 12 | let v = a.wrapping_add(rotate64(b.wrapping_add(K2), 18).wrapping_add(c).wrapping_add(seed1)); 13 | a = shift_mix((u ^ v).wrapping_mul(mul)); 14 | b = shift_mix((v ^ a).wrapping_mul(mul)); 15 | 16 | b 17 | } 18 | 19 | // Return an 8-byte hash for 33 to 64 bytes. 20 | fn xo_hash_len_33_to_64(s: &[u8], len: usize) -> u64 { 21 | let mul0 = K2.wrapping_sub(30); 22 | let mul1 = K2.wrapping_sub(30).wrapping_add(2 * len as u64); 23 | let h0 = xo_h32(s, 32, mul0, 0, 0); 24 | let h1 = xo_h32(&s[s.len() - 32..], 32, mul1, 0, 0); 25 | 26 | ((h1.wrapping_mul(mul1)).wrapping_add(h0)).wrapping_mul(mul1) 27 | } 28 | 29 | // Return an 8-byte hash for 65 to 96 bytes. 30 | fn xo_hash_len_65_to_96(s: &[u8], len: usize) -> u64 { 31 | let mul0 = K2.wrapping_sub(114); 32 | let mul1 = K2.wrapping_sub(114).wrapping_add(2 * len as u64); 33 | let h0 = xo_h32(s, 32, mul0, 0, 0); 34 | let h1 = xo_h32(&s[32..], 32, mul1, 0, 0); 35 | let h2 = xo_h32(&s[s.len() - 32..], 32, mul1, h0, h1); 36 | 37 | (h2 .wrapping_mul(9) 38 | .wrapping_add(h0 >> 17) 39 | .wrapping_add(h1 >> 21)).wrapping_mul(mul1) 40 | } 41 | 42 | pub fn xo_hash64(s: &[u8]) -> u64 { 43 | match s.len() { 44 | 0 ...16 => hash_len_0_to_16(s), 45 | 17...32 => hash_len_17_to_32(s), 46 | 33...64 => xo_hash_len_33_to_64(s, s.len()), 47 | 65...96 => xo_hash_len_65_to_96(s, s.len()), 48 | 97...256 => na_hash64(s), 49 | _ => uo_hash64(s), 50 | } 51 | } 52 | 53 | pub fn xo_hash64_with_seeds(s: &[u8], seed0: u64, seed1: u64) -> u64 { 54 | uo_hash64_with_seeds(s, seed0, seed1) 55 | } 56 | 57 | pub fn xo_hash64_with_seed(s: &[u8], seed: u64) -> u64 { 58 | uo_hash64_with_seed(s, seed) 59 | } 60 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod platform; 2 | mod farmhashna; 3 | mod farmhashmk; 4 | mod farmhashuo; 5 | mod farmhashxo; 6 | mod farmhashna_shared; 7 | mod farmhashcc_shared; 8 | mod farmhashmk_shared; 9 | 10 | use farmhashna::na_hash64; 11 | use farmhashmk::mk_hash32; 12 | use farmhashmk::mk_hash32_with_seed; 13 | use farmhashxo::xo_hash64; 14 | use farmhashxo::xo_hash64_with_seed; 15 | use farmhashxo::xo_hash64_with_seeds; 16 | use std::hash::Hasher; 17 | 18 | /// Create a new farmhash based u32 for an array of bytes. Hash value may vary 19 | /// with library version and platform. 20 | /// 21 | /// # Examples 22 | /// 23 | /// ``` 24 | /// let value: &str = "hello world"; 25 | /// let res32 = farmhash::hash32(&value.as_bytes()); 26 | /// //res32 ==> 430397466 27 | /// ``` 28 | pub fn hash32(s: &[u8]) -> u32 { 29 | mk_hash32(s) 30 | } 31 | 32 | /// Create a new farmhash based u32 for an array of bytes with a given seed. 33 | /// Hash value may vary with library version and platform. 34 | pub fn hash32_with_seed(s: &[u8], seed: u32) -> u32 { 35 | mk_hash32_with_seed(s, seed) 36 | } 37 | 38 | /// Create a new farmhash based u64 for an array of bytes. Hash value may 39 | /// vary with library version and platform. 40 | /// 41 | /// # Examples 42 | /// 43 | /// ``` 44 | /// let value: &str = "hello world"; 45 | /// let res64 = farmhash::hash64(&value.as_bytes()); 46 | /// //res64 ==> 6381520714923946011 47 | /// ``` 48 | pub fn hash64(s: &[u8]) -> u64 { 49 | xo_hash64(s) 50 | } 51 | 52 | /// Create a new farmhash based u64 for an array of bytes with a given seed. 53 | /// Hash value may vary with library version and platform. 54 | pub fn hash64_with_seed(s: &[u8], seed: u64) -> u64 { 55 | xo_hash64_with_seed(s, seed) 56 | } 57 | 58 | /// Create a new farmhash based u64 for an array of bytes with 2 given seeds. 59 | /// Hash value may vary with library version and platform. 60 | pub fn hash64_with_seeds(s: &[u8], seed0: u64, seed1: u64) -> u64 { 61 | xo_hash64_with_seeds(s, seed0, seed1) 62 | } 63 | 64 | /// Create a new farmhash based u32 for an array of bytes. Fingerprint value 65 | /// should be portable and stable across library versions and platforms. 66 | /// 67 | /// # Examples 68 | /// 69 | /// ``` 70 | /// let value: &str = "hello world"; 71 | /// let res32 = farmhash::fingerprint32(&value.as_bytes()); 72 | /// //res32 ==> 430397466 73 | /// ``` 74 | pub fn fingerprint32(s: &[u8]) -> u32 { 75 | mk_hash32(s) 76 | } 77 | 78 | /// Create a stable farmhash based u64 for an array of bytes. Fingerprint value 79 | /// should be portable and stable across library versions and platforms. 80 | /// 81 | /// # Examples 82 | /// 83 | /// ``` 84 | /// let value: &str = "hello world"; 85 | /// let res64 = farmhash::fingerprint64(&value.as_bytes()); 86 | /// //res64 ==> 6381520714923946011 87 | /// ``` 88 | pub fn fingerprint64(s: &[u8]) -> u64 { 89 | na_hash64(s) 90 | } 91 | 92 | pub struct FarmHasher { 93 | bytes: Vec 94 | } 95 | 96 | impl Default for FarmHasher { 97 | #[inline] 98 | fn default() -> FarmHasher { FarmHasher{bytes: Vec::with_capacity(20)} } 99 | } 100 | 101 | impl Hasher for FarmHasher { 102 | #[inline] 103 | fn finish(&self) -> u64 { 104 | hash64(&self.bytes[..]) 105 | } 106 | #[inline] 107 | fn write(&mut self, bytes: &[u8]) { 108 | self.bytes.extend(bytes.iter().cloned()); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/platform.rs: -------------------------------------------------------------------------------- 1 | // Based on the original C++ platform.cc 2 | 3 | // A small optimisation I switched from binary.LittleEndian.Uint32/64 to 4 | // hand coded. The benchmark, on my system, went from 5 | // around 64ns/op to around 51ns/op 6 | 7 | // Note: I used to call binary.LittleEndian.Uint32 and Uint64 inline but it 8 | // made comparing the code to the original much trickier 9 | 10 | use std::mem; 11 | use std::ptr; 12 | 13 | #[inline] 14 | pub fn fetch32(p: &[u8]) -> u32 { 15 | assert!(p.len() >= 4); 16 | let mut result = 0u32; 17 | unsafe { 18 | ptr::copy_nonoverlapping(p.as_ptr(), &mut result as *mut _ as *mut u8, mem::size_of::()); 19 | } 20 | result.to_le() 21 | } 22 | 23 | #[inline] 24 | pub fn fetch64(p: &[u8]) -> u64 { 25 | assert!(p.len() >= 8); 26 | let mut result = 0u64; 27 | unsafe { 28 | ptr::copy_nonoverlapping(p.as_ptr(), &mut result as *mut _ as *mut u8, mem::size_of::()); 29 | } 30 | result.to_le() 31 | } 32 | 33 | // rotate32 is a bitwise rotate 34 | pub fn rotate32(val: u32, shift: u32) -> u32 { 35 | if shift == 0 { 36 | return val; 37 | } 38 | return val >> shift | val << (32 - shift) 39 | } 40 | 41 | // rotate64 is a bitwise rotate 42 | pub fn rotate64(val: u64, shift: u64) -> u64 { 43 | if shift == 0 { 44 | return val; 45 | } 46 | return val >> shift | val << (64 - shift) 47 | } 48 | 49 | 50 | // Some primes between 2^63 and 2^64 for various uses. 51 | pub const K0: u64 = 0xc3a5c85c97cb3127; 52 | pub const K1: u64 = 0xb492b66fbe98f273; 53 | pub const K2: u64 = 0x9ae16a3b2f90404f; 54 | 55 | // Magic numbers for 32-bit hashing. Copied from Murmur3. 56 | pub const C1: u32 = 0xcc9e2d51; 57 | pub const C2: u32 = 0x1b873593; 58 | 59 | // fmix is a 32-bit to 32-bit integer hash copied from Murmur3. 60 | pub fn fmix(mut h: u32) -> u32 { 61 | h ^= h >> 16; 62 | h = h.wrapping_mul(0x85ebca6b); 63 | h ^= h >> 13; 64 | h = h.wrapping_mul(0xc2b2ae35); 65 | h ^= h >> 16; 66 | return h; 67 | } 68 | 69 | // Mur is a helper from Murmur3 for combining two 32-bit values. 70 | pub fn mur(mut a: u32, mut h: u32) -> u32 { 71 | a = a.wrapping_mul(C1); 72 | a = rotate32(a, 17); 73 | a = a.wrapping_mul(C2); 74 | h ^= a; 75 | h = rotate32(h, 19); 76 | return h.wrapping_mul(5).wrapping_add(0xe6546b64); 77 | } 78 | 79 | pub fn bswap32(x: u32) -> u32 { 80 | return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | 81 | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000) 82 | } 83 | 84 | pub struct Uint128 { 85 | pub first: u64, 86 | pub second: u64, 87 | } 88 | 89 | // hash128to64 is from farmhash.h it is intended to be a reasonably good hash function. 90 | pub fn hash128to64(x: Uint128) -> u64 { 91 | // Murmur-inspired hashing. 92 | const KMUL: u64 = 0x9ddfea08eb382d69; 93 | let mut a = (x.first ^ x.second).wrapping_mul(KMUL); 94 | a ^= a >> 47; 95 | let mut b = (x.second ^ a).wrapping_mul(KMUL); 96 | b ^= b >> 47; 97 | b = b.wrapping_mul(KMUL); 98 | return b; 99 | } 100 | 101 | 102 | #[cfg(test)] 103 | struct NumIn2Out { 104 | in1: u32, 105 | in2: u32, 106 | out: u32 107 | } 108 | 109 | 110 | #[cfg(test)] 111 | struct NumInOut { 112 | in1: u32, 113 | out: u32 114 | } 115 | 116 | #[test] 117 | fn test_mur() { 118 | let i = mur(12, 1); 119 | assert_eq!(i, 4253658843); 120 | } 121 | 122 | #[test] 123 | fn test_bswap32() { 124 | let i = bswap32(12); 125 | assert_eq!(i, 201326592); 126 | } 127 | #[test] 128 | fn test_hash128to64() { 129 | let j = hash128to64(Uint128{first:12, second:1}); 130 | assert_eq!(j, 463069014307918310); 131 | } 132 | 133 | #[test] 134 | fn test_rotate64() { 135 | let rots = vec![ 136 | NumIn2Out{in1: 0, in2: 0, out: 0}, 137 | // Rotate32 138 | NumIn2Out{in1: 100, in2: 0, out: 100}, 139 | NumIn2Out{in1: 100, in2: 1, out: 50}, 140 | NumIn2Out{in1: 100, in2: 2, out: 25}, 141 | NumIn2Out{in1: 100, in2: 3, out: 2147483660}, 142 | NumIn2Out{in1: 100, in2: 4, out: 1073741830}, 143 | NumIn2Out{in1: 100, in2: 5, out: 536870915}, 144 | NumIn2Out{in1: 100, in2: 6, out: 2415919105}, 145 | NumIn2Out{in1: 100, in2: 7, out: 3355443200}, 146 | NumIn2Out{in1: 100, in2: 8, out: 1677721600}, 147 | NumIn2Out{in1: 100, in2: 9, out: 838860800}, 148 | NumIn2Out{in1: 100, in2: 10, out: 419430400}, 149 | NumIn2Out{in1: 100, in2: 11, out: 209715200}, 150 | NumIn2Out{in1: 100, in2: 12, out: 104857600}, 151 | NumIn2Out{in1: 100, in2: 13, out: 52428800}, 152 | NumIn2Out{in1: 100, in2: 14, out: 26214400}, 153 | NumIn2Out{in1: 100, in2: 15, out: 13107200}, 154 | NumIn2Out{in1: 100, in2: 16, out: 6553600}, 155 | NumIn2Out{in1: 100, in2: 17, out: 3276800}, 156 | NumIn2Out{in1: 100, in2: 18, out: 1638400}, 157 | NumIn2Out{in1: 100, in2: 19, out: 819200}, 158 | NumIn2Out{in1: 100, in2: 20, out: 409600}, 159 | NumIn2Out{in1: 100, in2: 21, out: 204800}, 160 | NumIn2Out{in1: 100, in2: 22, out: 102400}, 161 | NumIn2Out{in1: 100, in2: 23, out: 51200}, 162 | NumIn2Out{in1: 100, in2: 24, out: 25600}, 163 | NumIn2Out{in1: 100, in2: 25, out: 12800}, 164 | NumIn2Out{in1: 100, in2: 26, out: 6400}, 165 | NumIn2Out{in1: 100, in2: 27, out: 3200}, 166 | NumIn2Out{in1: 100, in2: 28, out: 1600}, 167 | NumIn2Out{in1: 100, in2: 29, out: 800}, 168 | NumIn2Out{in1: 100, in2: 30, out: 400}, 169 | NumIn2Out{in1: 100, in2: 31, out: 200}, 170 | NumIn2Out{in1: 1000, in2: 0, out: 1000}, 171 | NumIn2Out{in1: 1000, in2: 1, out: 500}, 172 | NumIn2Out{in1: 1000, in2: 2, out: 250}, 173 | NumIn2Out{in1: 1000, in2: 3, out: 125}, 174 | NumIn2Out{in1: 1000, in2: 4, out: 2147483710}, 175 | NumIn2Out{in1: 1000, in2: 5, out: 1073741855}, 176 | NumIn2Out{in1: 1000, in2: 6, out: 2684354575}, 177 | NumIn2Out{in1: 1000, in2: 7, out: 3489660935}, 178 | NumIn2Out{in1: 1000, in2: 8, out: 3892314115}, 179 | NumIn2Out{in1: 1000, in2: 9, out: 4093640705}, 180 | NumIn2Out{in1: 1000, in2: 10, out: 4194304000}, 181 | NumIn2Out{in1: 1000, in2: 11, out: 2097152000}, 182 | NumIn2Out{in1: 1000, in2: 12, out: 1048576000}, 183 | NumIn2Out{in1: 1000, in2: 13, out: 524288000}, 184 | NumIn2Out{in1: 1000, in2: 14, out: 262144000}, 185 | NumIn2Out{in1: 1000, in2: 15, out: 131072000}, 186 | NumIn2Out{in1: 1000, in2: 16, out: 65536000}, 187 | NumIn2Out{in1: 1000, in2: 17, out: 32768000}, 188 | NumIn2Out{in1: 1000, in2: 18, out: 16384000}, 189 | NumIn2Out{in1: 1000, in2: 19, out: 8192000}, 190 | NumIn2Out{in1: 1000, in2: 20, out: 4096000}, 191 | NumIn2Out{in1: 1000, in2: 21, out: 2048000}, 192 | NumIn2Out{in1: 1000, in2: 22, out: 1024000}, 193 | NumIn2Out{in1: 1000, in2: 23, out: 512000}, 194 | NumIn2Out{in1: 1000, in2: 24, out: 256000}, 195 | NumIn2Out{in1: 1000, in2: 25, out: 128000}, 196 | NumIn2Out{in1: 1000, in2: 26, out: 64000}, 197 | NumIn2Out{in1: 1000, in2: 27, out: 32000}, 198 | NumIn2Out{in1: 1000, in2: 28, out: 16000}, 199 | NumIn2Out{in1: 1000, in2: 29, out: 8000}, 200 | NumIn2Out{in1: 1000, in2: 30, out: 4000}, 201 | NumIn2Out{in1: 1000, in2: 31, out: 2000}, 202 | NumIn2Out{in1: 100000, in2: 0, out: 100000}, 203 | NumIn2Out{in1: 100000, in2: 1, out: 50000}, 204 | NumIn2Out{in1: 100000, in2: 2, out: 25000}, 205 | NumIn2Out{in1: 100000, in2: 3, out: 12500}, 206 | NumIn2Out{in1: 100000, in2: 4, out: 6250}, 207 | NumIn2Out{in1: 100000, in2: 5, out: 3125}, 208 | NumIn2Out{in1: 100000, in2: 6, out: 2147485210}, 209 | NumIn2Out{in1: 100000, in2: 7, out: 1073742605}, 210 | NumIn2Out{in1: 100000, in2: 8, out: 2684354950}, 211 | NumIn2Out{in1: 100000, in2: 9, out: 1342177475}, 212 | NumIn2Out{in1: 100000, in2: 10, out: 2818572385}, 213 | NumIn2Out{in1: 100000, in2: 11, out: 3556769840}, 214 | NumIn2Out{in1: 100000, in2: 12, out: 1778384920}, 215 | NumIn2Out{in1: 100000, in2: 13, out: 889192460}, 216 | NumIn2Out{in1: 100000, in2: 14, out: 444596230}, 217 | NumIn2Out{in1: 100000, in2: 15, out: 222298115}, 218 | NumIn2Out{in1: 100000, in2: 16, out: 2258632705}, 219 | NumIn2Out{in1: 100000, in2: 17, out: 3276800000}, 220 | NumIn2Out{in1: 100000, in2: 18, out: 1638400000}, 221 | NumIn2Out{in1: 100000, in2: 19, out: 819200000}, 222 | NumIn2Out{in1: 100000, in2: 20, out: 409600000}, 223 | NumIn2Out{in1: 100000, in2: 21, out: 204800000}, 224 | NumIn2Out{in1: 100000, in2: 22, out: 102400000}, 225 | NumIn2Out{in1: 100000, in2: 23, out: 51200000}, 226 | NumIn2Out{in1: 100000, in2: 24, out: 25600000}, 227 | NumIn2Out{in1: 100000, in2: 25, out: 12800000}, 228 | NumIn2Out{in1: 100000, in2: 26, out: 6400000}, 229 | NumIn2Out{in1: 100000, in2: 27, out: 3200000}, 230 | NumIn2Out{in1: 100000, in2: 28, out: 1600000}, 231 | NumIn2Out{in1: 100000, in2: 29, out: 800000}, 232 | NumIn2Out{in1: 100000, in2: 30, out: 400000}, 233 | NumIn2Out{in1: 100000, in2: 31, out: 200000}, 234 | NumIn2Out{in1: 1000000, in2: 0, out: 1000000}, 235 | NumIn2Out{in1: 1000000, in2: 1, out: 500000}, 236 | NumIn2Out{in1: 1000000, in2: 2, out: 250000}, 237 | NumIn2Out{in1: 1000000, in2: 3, out: 125000}, 238 | NumIn2Out{in1: 1000000, in2: 4, out: 62500}, 239 | NumIn2Out{in1: 1000000, in2: 5, out: 31250}, 240 | NumIn2Out{in1: 1000000, in2: 6, out: 15625}, 241 | NumIn2Out{in1: 1000000, in2: 7, out: 2147491460}, 242 | NumIn2Out{in1: 1000000, in2: 8, out: 1073745730}, 243 | NumIn2Out{in1: 1000000, in2: 9, out: 536872865}, 244 | NumIn2Out{in1: 1000000, in2: 10, out: 2415920080}, 245 | NumIn2Out{in1: 1000000, in2: 11, out: 1207960040}, 246 | NumIn2Out{in1: 1000000, in2: 12, out: 603980020}, 247 | NumIn2Out{in1: 1000000, in2: 13, out: 301990010}, 248 | NumIn2Out{in1: 1000000, in2: 14, out: 150995005}, 249 | NumIn2Out{in1: 1000000, in2: 15, out: 2222981150}, 250 | NumIn2Out{in1: 1000000, in2: 16, out: 1111490575}, 251 | NumIn2Out{in1: 1000000, in2: 17, out: 2703228935}, 252 | NumIn2Out{in1: 1000000, in2: 18, out: 3499098115}, 253 | NumIn2Out{in1: 1000000, in2: 19, out: 3897032705}, 254 | NumIn2Out{in1: 1000000, in2: 20, out: 4096000000}, 255 | NumIn2Out{in1: 1000000, in2: 21, out: 2048000000}, 256 | NumIn2Out{in1: 1000000, in2: 22, out: 1024000000}, 257 | NumIn2Out{in1: 1000000, in2: 23, out: 512000000}, 258 | NumIn2Out{in1: 1000000, in2: 24, out: 256000000}, 259 | NumIn2Out{in1: 1000000, in2: 25, out: 128000000}, 260 | NumIn2Out{in1: 1000000, in2: 26, out: 64000000}, 261 | NumIn2Out{in1: 1000000, in2: 27, out: 32000000}, 262 | NumIn2Out{in1: 1000000, in2: 28, out: 16000000}, 263 | NumIn2Out{in1: 1000000, in2: 29, out: 8000000}, 264 | NumIn2Out{in1: 1000000, in2: 30, out: 4000000}, 265 | NumIn2Out{in1: 1000000, in2: 31, out: 2000000}, 266 | NumIn2Out{in1: 10000000, in2: 0, out: 10000000}, 267 | NumIn2Out{in1: 10000000, in2: 1, out: 5000000}, 268 | NumIn2Out{in1: 10000000, in2: 2, out: 2500000}, 269 | NumIn2Out{in1: 10000000, in2: 3, out: 1250000}, 270 | NumIn2Out{in1: 10000000, in2: 4, out: 625000}, 271 | NumIn2Out{in1: 10000000, in2: 5, out: 312500}, 272 | NumIn2Out{in1: 10000000, in2: 6, out: 156250}, 273 | NumIn2Out{in1: 10000000, in2: 7, out: 78125}, 274 | NumIn2Out{in1: 10000000, in2: 8, out: 2147522710}, 275 | NumIn2Out{in1: 10000000, in2: 9, out: 1073761355}, 276 | NumIn2Out{in1: 10000000, in2: 10, out: 2684364325}, 277 | NumIn2Out{in1: 10000000, in2: 11, out: 3489665810}, 278 | NumIn2Out{in1: 10000000, in2: 12, out: 1744832905}, 279 | NumIn2Out{in1: 10000000, in2: 13, out: 3019900100}, 280 | NumIn2Out{in1: 10000000, in2: 14, out: 1509950050}, 281 | NumIn2Out{in1: 10000000, in2: 15, out: 754975025}, 282 | NumIn2Out{in1: 10000000, in2: 16, out: 2524971160}, 283 | NumIn2Out{in1: 10000000, in2: 17, out: 1262485580}, 284 | NumIn2Out{in1: 10000000, in2: 18, out: 631242790}, 285 | NumIn2Out{in1: 10000000, in2: 19, out: 315621395}, 286 | NumIn2Out{in1: 10000000, in2: 20, out: 2305294345}, 287 | NumIn2Out{in1: 10000000, in2: 21, out: 3300130820}, 288 | NumIn2Out{in1: 10000000, in2: 22, out: 1650065410}, 289 | NumIn2Out{in1: 10000000, in2: 23, out: 825032705}, 290 | NumIn2Out{in1: 10000000, in2: 24, out: 2560000000}, 291 | NumIn2Out{in1: 10000000, in2: 25, out: 1280000000}, 292 | NumIn2Out{in1: 10000000, in2: 26, out: 640000000}, 293 | NumIn2Out{in1: 10000000, in2: 27, out: 320000000}, 294 | NumIn2Out{in1: 10000000, in2: 28, out: 160000000}, 295 | NumIn2Out{in1: 10000000, in2: 29, out: 80000000}, 296 | NumIn2Out{in1: 10000000, in2: 30, out: 40000000}, 297 | NumIn2Out{in1: 10000000, in2: 31, out: 20000000}, 298 | NumIn2Out{in1: 100000000, in2: 0, out: 100000000}, 299 | NumIn2Out{in1: 100000000, in2: 1, out: 50000000}, 300 | NumIn2Out{in1: 100000000, in2: 2, out: 25000000}, 301 | NumIn2Out{in1: 100000000, in2: 3, out: 12500000}, 302 | NumIn2Out{in1: 100000000, in2: 4, out: 6250000}, 303 | NumIn2Out{in1: 100000000, in2: 5, out: 3125000}, 304 | NumIn2Out{in1: 100000000, in2: 6, out: 1562500}, 305 | NumIn2Out{in1: 100000000, in2: 7, out: 781250}, 306 | NumIn2Out{in1: 100000000, in2: 8, out: 390625}, 307 | NumIn2Out{in1: 100000000, in2: 9, out: 2147678960}, 308 | NumIn2Out{in1: 100000000, in2: 10, out: 1073839480}, 309 | NumIn2Out{in1: 100000000, in2: 11, out: 536919740}, 310 | NumIn2Out{in1: 100000000, in2: 12, out: 268459870}, 311 | NumIn2Out{in1: 100000000, in2: 13, out: 134229935}, 312 | NumIn2Out{in1: 100000000, in2: 14, out: 2214598615}, 313 | NumIn2Out{in1: 100000000, in2: 15, out: 3254782955}, 314 | NumIn2Out{in1: 100000000, in2: 16, out: 3774875125}, 315 | NumIn2Out{in1: 100000000, in2: 17, out: 4034921210}, 316 | NumIn2Out{in1: 100000000, in2: 18, out: 2017460605}, 317 | NumIn2Out{in1: 100000000, in2: 19, out: 3156213950}, 318 | NumIn2Out{in1: 100000000, in2: 20, out: 1578106975}, 319 | NumIn2Out{in1: 100000000, in2: 21, out: 2936537135}, 320 | NumIn2Out{in1: 100000000, in2: 22, out: 3615752215}, 321 | NumIn2Out{in1: 100000000, in2: 23, out: 3955359755}, 322 | NumIn2Out{in1: 100000000, in2: 24, out: 4125163525}, 323 | NumIn2Out{in1: 100000000, in2: 25, out: 4210065410}, 324 | NumIn2Out{in1: 100000000, in2: 26, out: 2105032705}, 325 | NumIn2Out{in1: 100000000, in2: 27, out: 3200000000}, 326 | NumIn2Out{in1: 100000000, in2: 28, out: 1600000000}, 327 | NumIn2Out{in1: 100000000, in2: 29, out: 800000000}, 328 | NumIn2Out{in1: 100000000, in2: 30, out: 400000000}, 329 | NumIn2Out{in1: 100000000, in2: 31, out: 200000000}, 330 | NumIn2Out{in1: 1000000000, in2: 0, out: 1000000000}, 331 | NumIn2Out{in1: 1000000000, in2: 1, out: 500000000}, 332 | NumIn2Out{in1: 1000000000, in2: 2, out: 250000000}, 333 | NumIn2Out{in1: 1000000000, in2: 3, out: 125000000}, 334 | NumIn2Out{in1: 1000000000, in2: 4, out: 62500000}, 335 | NumIn2Out{in1: 1000000000, in2: 5, out: 31250000}, 336 | NumIn2Out{in1: 1000000000, in2: 6, out: 15625000}, 337 | NumIn2Out{in1: 1000000000, in2: 7, out: 7812500}, 338 | NumIn2Out{in1: 1000000000, in2: 8, out: 3906250}, 339 | NumIn2Out{in1: 1000000000, in2: 9, out: 1953125}, 340 | NumIn2Out{in1: 1000000000, in2: 10, out: 2148460210}, 341 | NumIn2Out{in1: 1000000000, in2: 11, out: 1074230105}, 342 | NumIn2Out{in1: 1000000000, in2: 12, out: 2684598700}, 343 | NumIn2Out{in1: 1000000000, in2: 13, out: 1342299350}, 344 | NumIn2Out{in1: 1000000000, in2: 14, out: 671149675}, 345 | NumIn2Out{in1: 1000000000, in2: 15, out: 2483058485}, 346 | NumIn2Out{in1: 1000000000, in2: 16, out: 3389012890}, 347 | NumIn2Out{in1: 1000000000, in2: 17, out: 1694506445}, 348 | NumIn2Out{in1: 1000000000, in2: 18, out: 2994736870}, 349 | NumIn2Out{in1: 1000000000, in2: 19, out: 1497368435}, 350 | NumIn2Out{in1: 1000000000, in2: 20, out: 2896167865}, 351 | NumIn2Out{in1: 1000000000, in2: 21, out: 3595567580}, 352 | NumIn2Out{in1: 1000000000, in2: 22, out: 1797783790}, 353 | NumIn2Out{in1: 1000000000, in2: 23, out: 898891895}, 354 | NumIn2Out{in1: 1000000000, in2: 24, out: 2596929595}, 355 | NumIn2Out{in1: 1000000000, in2: 25, out: 3445948445}, 356 | NumIn2Out{in1: 1000000000, in2: 26, out: 3870457870}, 357 | NumIn2Out{in1: 1000000000, in2: 27, out: 1935228935}, 358 | NumIn2Out{in1: 1000000000, in2: 28, out: 3115098115}, 359 | NumIn2Out{in1: 1000000000, in2: 29, out: 3705032705}, 360 | NumIn2Out{in1: 1000000000, in2: 30, out: 4000000000}, 361 | NumIn2Out{in1: 1000000000, in2: 31, out: 2000000000} 362 | ]; 363 | for f in rots { 364 | let u = rotate32(f.in1 as u32, f.in2 as u32); 365 | assert_eq!(u, f.out); 366 | } 367 | } 368 | 369 | #[test] 370 | fn test_mux() { 371 | let murs = vec![ 372 | // Mur 373 | NumIn2Out{in1: 100, in2: 100, out: 296331858}, 374 | NumIn2Out{in1: 100, in2: 1000, out: 322382418}, 375 | NumIn2Out{in1: 100, in2: 100000, out: 3309578834}, 376 | NumIn2Out{in1: 100, in2: 1000000, out: 2332043863}, 377 | NumIn2Out{in1: 100, in2: 10000000, out: 1532504573}, 378 | NumIn2Out{in1: 100, in2: 100000000, out: 109586476}, 379 | NumIn2Out{in1: 100, in2: 1000000000, out: 4129826525}, 380 | NumIn2Out{in1: 1000, in2: 100, out: 904209336}, 381 | NumIn2Out{in1: 1000, in2: 1000, out: 909616056}, 382 | NumIn2Out{in1: 1000, in2: 100000, out: 2222629816}, 383 | NumIn2Out{in1: 1000, in2: 1000000, out: 4010714045}, 384 | NumIn2Out{in1: 1000, in2: 10000000, out: 3999704087}, 385 | NumIn2Out{in1: 1000, in2: 100000000, out: 3377899334}, 386 | NumIn2Out{in1: 1000, in2: 1000000000, out: 2218174583}, 387 | NumIn2Out{in1: 100000, in2: 100, out: 193992030}, 388 | NumIn2Out{in1: 100000, in2: 1000, out: 157783390}, 389 | NumIn2Out{in1: 100000, in2: 100000, out: 4239037790}, 390 | NumIn2Out{in1: 100000, in2: 1000000, out: 2456196451}, 391 | NumIn2Out{in1: 100000, in2: 10000000, out: 1388221705}, 392 | NumIn2Out{in1: 100000, in2: 100000000, out: 2402195232}, 393 | NumIn2Out{in1: 100000, in2: 1000000000, out: 3180234409}, 394 | NumIn2Out{in1: 1000000, in2: 100, out: 3909538526}, 395 | NumIn2Out{in1: 1000000, in2: 1000, out: 3946730206}, 396 | NumIn2Out{in1: 1000000, in2: 100000, out: 3622916830}, 397 | NumIn2Out{in1: 1000000, in2: 1000000, out: 1918718691}, 398 | NumIn2Out{in1: 1000000, in2: 10000000, out: 1107645065}, 399 | NumIn2Out{in1: 1000000, in2: 100000000, out: 2509590432}, 400 | NumIn2Out{in1: 1000000, in2: 1000000000, out: 2805288489}, 401 | NumIn2Out{in1: 10000000, in2: 100, out: 1497840043}, 402 | NumIn2Out{in1: 10000000, in2: 1000, out: 1471134123}, 403 | NumIn2Out{in1: 10000000, in2: 100000, out: 1794947499}, 404 | NumIn2Out{in1: 10000000, in2: 1000000, out: 3491281318}, 405 | NumIn2Out{in1: 10000000, in2: 10000000, out: 353417548}, 406 | NumIn2Out{in1: 10000000, in2: 100000000, out: 2900408157}, 407 | NumIn2Out{in1: 10000000, in2: 1000000000, out: 2604713900}, 408 | NumIn2Out{in1: 100000000, in2: 100, out: 3858265169}, 409 | NumIn2Out{in1: 100000000, in2: 1000, out: 3843028049}, 410 | NumIn2Out{in1: 100000000, in2: 100000, out: 2534601809}, 411 | NumIn2Out{in1: 100000000, in2: 1000000, out: 2896622668}, 412 | NumIn2Out{in1: 100000000, in2: 10000000, out: 754906278}, 413 | NumIn2Out{in1: 100000000, in2: 100000000, out: 716108471}, 414 | NumIn2Out{in1: 100000000, in2: 1000000000, out: 567217414}, 415 | NumIn2Out{in1: 1000000000, in2: 100, out: 4215452687}, 416 | NumIn2Out{in1: 1000000000, in2: 1000, out: 4179244047}, 417 | NumIn2Out{in1: 1000000000, in2: 100000, out: 1192047631}, 418 | NumIn2Out{in1: 1000000000, in2: 1000000, out: 32584714}, 419 | NumIn2Out{in1: 1000000000, in2: 10000000, out: 2969121872}, 420 | NumIn2Out{in1: 1000000000, in2: 100000000, out: 107557113}, 421 | NumIn2Out{in1: 1000000000, in2: 1000000000, out: 2529766768} 422 | ]; 423 | for m in murs { 424 | let u = mur(m.in1 as u32, m.in2 as u32); 425 | assert_eq!(u, m.out); 426 | } 427 | } 428 | 429 | #[test] 430 | fn test_fmix() { 431 | let fmix_in_out = vec![ 432 | NumInOut{in1: 0, out: 0}, 433 | NumInOut{in1: 100, out: 4258159850}, 434 | NumInOut{in1: 1000, out: 1718167128}, 435 | NumInOut{in1: 100000, out: 1391155934}, 436 | NumInOut{in1: 1000000, out: 37787785}, 437 | NumInOut{in1: 10000000, out: 3568206535}, 438 | NumInOut{in1: 100000000, out: 701900797}, 439 | NumInOut{in1: 1000000000, out: 4234498180} 440 | ]; 441 | 442 | for f in fmix_in_out { 443 | let u = fmix(f.in1 as u32); 444 | assert_eq!(u, f.out); 445 | } 446 | } 447 | -------------------------------------------------------------------------------- /tests/test_hash32.rs: -------------------------------------------------------------------------------- 1 | extern crate farmhash; 2 | 3 | use self::farmhash::*; 4 | 5 | #[cfg(test)] 6 | struct StrToHash32<'a> { 7 | value: &'a str, 8 | expected: u32 9 | } 10 | 11 | #[test] 12 | fn test_hash32_len_0_to_4() { 13 | let str_to_hash32 = vec![ 14 | // Hash32 15 | StrToHash32{expected: 0xdc56d17a, value: ""}, 16 | StrToHash32{expected: 0x3c973d4d, value: "a"}, 17 | StrToHash32{expected: 0x417330fd, value: "ab"}, 18 | StrToHash32{expected: 0x2f635ec7, value: "abc"}, 19 | StrToHash32{expected: 0x98b51e95, value: "abcd"}, 20 | StrToHash32{expected: 0xf2311502, value: "hi"}, 21 | ]; 22 | for s in str_to_hash32 { 23 | let hash = hash32((&s.value).as_bytes()); 24 | if hash != s.expected { 25 | println!("{}", s.value); 26 | } 27 | assert_eq!(hash, s.expected); 28 | } 29 | } 30 | 31 | 32 | #[test] 33 | fn test_hash32_len_5_to_12() { 34 | let str_to_hash32 = vec![ 35 | // Hash32 36 | StrToHash32{expected: 0xa3f366ac, value: "abcde"}, 37 | StrToHash32{expected: 0x0f813aa4, value: "abcdef"}, 38 | StrToHash32{expected: 0x21deb6d7, value: "abcdefg"}, 39 | StrToHash32{expected: 0xfd7ec8b9, value: "abcdefgh"}, 40 | StrToHash32{expected: 0x6f98dc86, value: "abcdefghi"}, 41 | StrToHash32{expected: 0xf2669361, value: "abcdefghij"}, 42 | StrToHash32{expected: 0x19a7581a, value: "hello world"}, 43 | ]; 44 | for s in str_to_hash32 { 45 | let hash = hash32((&s.value).as_bytes()); 46 | if hash != s.expected { 47 | println!("{}", s.value); 48 | } 49 | assert_eq!(hash, s.expected); 50 | } 51 | } 52 | 53 | #[test] 54 | fn test_hash32_len_13_to_24() { 55 | let str_to_hash32 = vec![ 56 | // Hash32 57 | StrToHash32{expected: 0x7acdc357, value: "fred@example.com"}, 58 | StrToHash32{expected: 0xaf0a30fe, value: "lee@lmmrtech.com"}, 59 | StrToHash32{expected: 0x5d8cdbf4, value: "docklandsman@gmail.com"}, 60 | StrToHash32{expected: 0xc6246b8d, value: "size: a.out: bad magic"}, 61 | ]; 62 | for s in str_to_hash32 { 63 | let hash = hash32((&s.value).as_bytes()); 64 | if hash != s.expected { 65 | println!("{}", s.value); 66 | } 67 | assert_eq!(hash, s.expected); 68 | } 69 | } 70 | 71 | 72 | #[test] 73 | fn test_hash32_else() { 74 | let str_to_hash32 = vec![ 75 | // Hash32 76 | StrToHash32{expected: 0x9c8f96f3, value: "Go is a tool for managing Go source code.Usage: go command [arguments]The commands are: build compile packages and dependencies clean remove object files env print Go environment information fix run go tool fix on packages fmt run gofmt on package sources generate generate Go files by processing source get download and install packages and dependencies install compile and install packages and dependencies list list packages run compile and run Go program test test packages tool run specified go tool version print Go version vet run go tool vet on packagesUse go help [command] for more information about a command.Additional help topics: c calling between Go and C filetype file types gopath GOPATH environment variable importpath import path syntax packages description of package lists testflag description of testing flags testfunc description of testing functionsUse go help [topic] for more information about that topic."}, 77 | StrToHash32{expected: 0xe273108f, value: "Discard medicine more than two years old."}, 78 | StrToHash32{expected: 0xf585dfc4, value: "He who has a shady past knows that nice guys finish last."}, 79 | StrToHash32{expected: 0x363394d1, value: "I wouldn't marry him with a ten foot pole."}, 80 | StrToHash32{expected: 0x7613810f, value: "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, 81 | StrToHash32{expected: 0x2cc30bb7, value: "The days of the digital watch are numbered. -Tom Stoppard"}, 82 | StrToHash32{expected: 0x322984d9, value: "Nepal premier won't resign."}, 83 | StrToHash32{expected: 0xa5812ac8, value: "For every action there is an equal and opposite government program."}, 84 | StrToHash32{expected: 0x1090d244, value: "His money is twice tainted: 'taint yours and 'taint mine."}, 85 | StrToHash32{expected: 0xff16c9e6, value: "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, 86 | StrToHash32{expected: 0xcc3d0ff2, value: "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, 87 | StrToHash32{expected: 0xd225e92e, value: "The major problem is with sendmail. -Mark Horton"}, 88 | StrToHash32{expected: 0x1b8db5d0, value: "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, 89 | StrToHash32{expected: 0x4fda5f07, value: "If the enemy is within range, then so are you."}, 90 | StrToHash32{expected: 0x2e18e880, value: "It's well we cannot hear the screams/That we create in others' dreams."}, 91 | StrToHash32{expected: 0xd07de88f, value: "You remind me of a TV show, but that's all right: I watch it anyway."}, 92 | StrToHash32{expected: 0x221694e4, value: "C is as portable as Stonehedge!!"}, 93 | StrToHash32{expected: 0xe2053c2c, value: "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, 94 | StrToHash32{expected: 0x11c493bb, value: "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, 95 | StrToHash32{expected: 0x0819a4e8, value: "How can you write a big system without C++? -Paul Glick"} 96 | ]; 97 | for s in str_to_hash32 { 98 | let hash = hash32((&s.value).as_bytes()); 99 | if hash != s.expected { 100 | println!("{}", s.value); 101 | } 102 | assert_eq!(hash, s.expected); 103 | } 104 | } -------------------------------------------------------------------------------- /tests/test_hash64.rs: -------------------------------------------------------------------------------- 1 | extern crate farmhash; 2 | 3 | use self::farmhash::*; 4 | use std::hash::Hasher; 5 | 6 | #[cfg(test)] 7 | struct StrToHash64<'a> { 8 | value: &'a str, 9 | expected: u64 10 | } 11 | 12 | #[test] 13 | fn test_hash64_0_to_16() { 14 | let str_to_hash64 = vec![ 15 | // Hash32 16 | StrToHash64{expected: 0x9ae16a3b2f90404f, value: ""}, 17 | StrToHash64{expected: 0xb3454265b6df75e3, value: "a"}, 18 | StrToHash64{expected: 0xaa8d6e5242ada51e, value: "ab"}, 19 | StrToHash64{expected: 0x24a5b3a074e7f369, value: "abc"}, 20 | StrToHash64{expected: 0x1a5502de4a1f8101, value: "abcd"}, 21 | StrToHash64{expected: 0xc22f4663e54e04d4, value: "abcde"}, 22 | StrToHash64{expected: 0xc329379e6a03c2cd, value: "abcdef"}, 23 | StrToHash64{expected: 0x3c40c92b1ccb7355, value: "abcdefg"}, 24 | StrToHash64{expected: 0xfee9d22990c82909, value: "abcdefgh"}, 25 | StrToHash64{expected: 0x332c8ed4dae5ba42, value: "abcdefghi"}, 26 | StrToHash64{expected: 0x8a3abb6a5f3fb7fb, value: "abcdefghij"}, 27 | StrToHash64{expected: 0x6a5d2fba44f012f8, value: "hi"}, 28 | StrToHash64{expected: 0x588fb7478bd6b01b, value: "hello world"}, 29 | StrToHash64{expected: 0x61bec68db00fa2ff, value: "lee@lmmrtech.com"}, 30 | StrToHash64{expected: 0x7fbbcd6191d8dce0, value: "fred@example.com"}, 31 | StrToHash64{expected: 0x80d73b843ba57db8, value: "size: a.out: bad magic"}, 32 | ]; 33 | for s in str_to_hash64 { 34 | let hash = hash64((&s.value).as_bytes()); 35 | if hash != s.expected { 36 | println!("{}", s.value); 37 | } 38 | assert_eq!(hash, s.expected); 39 | 40 | let mut hasher = FarmHasher::default(); 41 | hasher.write((&s.value).as_bytes()); 42 | let hash = hasher.finish(); 43 | if hash != s.expected { 44 | println!("{}", s.value); 45 | } 46 | assert_eq!(hash, s.expected); 47 | } 48 | } 49 | 50 | #[test] 51 | fn test_hash64_17_to_32() { 52 | let str_to_hash64 = vec![ 53 | // Hash32 54 | StrToHash64{expected: 0xb678cf3842309f40, value: "docklandsman@gmail.com"}, 55 | StrToHash64{expected: 0x8eb3808d1ccfc779, value: "Nepal premier won't resign."}, 56 | StrToHash64{expected: 0xb944f8a16261e414, value: "C is as portable as Stonehedge!!"} 57 | ]; 58 | for s in str_to_hash64 { 59 | let hash = hash64((&s.value).as_bytes()); 60 | if hash != s.expected { 61 | println!("{}", s.value); 62 | } 63 | assert_eq!(hash, s.expected); 64 | 65 | let mut hasher = FarmHasher::default(); 66 | hasher.write((&s.value).as_bytes()); 67 | let hash = hasher.finish(); 68 | assert_eq!(hash, s.expected); 69 | } 70 | } 71 | 72 | #[test] 73 | fn test_hash64_33_to_64() { 74 | let str_to_hash64 = vec![ 75 | // Hash32 76 | StrToHash64{expected: 0x2d072041b535155d, value: "Discard medicine more than two years old."}, //41 77 | StrToHash64{expected: 0x9f9e3cdeb570f926, value: "He who has a shady past knows that nice guys finish last."}, 78 | StrToHash64{expected: 0x361b79df08615cd6, value: "I wouldn't marry him with a ten foot pole."}, 79 | StrToHash64{expected: 0xdcfb73d4de1111c6, value: "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, 80 | StrToHash64{expected: 0xd71bdfedb6182a5d, value: "The days of the digital watch are numbered. -Tom Stoppard"}, 81 | StrToHash64{expected: 0x3df4b8e109629602, value: "His money is twice tainted: 'taint yours and 'taint mine."}, 82 | StrToHash64{expected: 0x1da6c1dfec23a597, value: "The major problem is with sendmail. -Mark Horton"}, 83 | StrToHash64{expected: 0x1f232f3375914f0a, value: "If the enemy is within range, then so are you."}, 84 | StrToHash64{expected: 0xa29944470950e8e4, value: "How can you write a big system without C++? -Paul Glick"} 85 | ]; 86 | for s in str_to_hash64 { 87 | let hash = hash64((&s.value).as_bytes()); 88 | if hash != s.expected { 89 | println!("{}", s.value); 90 | } 91 | assert_eq!(hash, s.expected); 92 | 93 | let mut hasher = FarmHasher::default(); 94 | hasher.write((&s.value).as_bytes()); 95 | let hash = hasher.finish(); 96 | assert_eq!(hash, s.expected); 97 | } 98 | } 99 | 100 | #[test] 101 | fn test_hash64_else() { 102 | let str_to_hash64 = vec![ 103 | // Hash32 104 | StrToHash64{expected: 0x8452fbb0c8f98c4f, value: "For every action there is an equal and opposite government program."}, 105 | StrToHash64{expected: 0x7fee06e367562d44, value: "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, 106 | StrToHash64{expected: 0x889b024bab17bf54, value: "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, 107 | StrToHash64{expected: 0xb8e2918a4398348d, value: "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, 108 | StrToHash64{expected: 0x796229f1faacec7e, value: "It's well we cannot hear the screams/That we create in others' dreams."}, 109 | StrToHash64{expected: 0x98d2fbd5131a5860, value: "You remind me of a TV show, but that's all right: I watch it anyway."}, 110 | StrToHash64{expected: 0x4c349a4ff7ac0c89, value: "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, 111 | StrToHash64{expected: 0x98eff6958c5e91a, value: "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, 112 | StrToHash64{expected: 0x21609f6764c635ed, value: "Go is a tool for managing Go source code.Usage: go command [arguments]The commands are: build compile packages and dependencies clean remove object files env print Go environment information fix run go tool fix on packages fmt run gofmt on package sources generate generate Go files by processing source get download and install packages and dependencies install compile and install packages and dependencies list list packages run compile and run Go program test test packages tool run specified go tool version print Go version vet run go tool vet on packagesUse go help [command] for more information about a command.Additional help topics: c calling between Go and C filetype file types gopath GOPATH environment variable importpath import path syntax packages description of package lists testflag description of testing flags testfunc description of testing functionsUse go help [topic] for more information about that topic."}, 113 | ]; 114 | 115 | for s in str_to_hash64 { 116 | let hash = hash64((&s.value).as_bytes()); 117 | if hash != s.expected { 118 | println!("{}", s.value); 119 | } 120 | assert_eq!(hash, s.expected); 121 | 122 | let mut hasher = FarmHasher::default(); 123 | hasher.write((&s.value).as_bytes()); 124 | let hash = hasher.finish(); 125 | assert_eq!(hash, s.expected); 126 | } 127 | } 128 | --------------------------------------------------------------------------------