Skip to content

Commit a1af9ad

Browse files
committed
Support 32-bit MUM
1 parent fb138f8 commit a1af9ad

File tree

15 files changed

+163
-50
lines changed

15 files changed

+163
-50
lines changed

.github/workflows/build.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,13 @@ jobs:
173173
command: test
174174
args: --target=${{ matrix.TARGET }} --workspace
175175

176+
- name: Test 32-bit mum
177+
if: matrix.rust != '1.36.0' && matrix.TARGET != 'x86_64-unknown-linux-musl' # musl-gcc is not installed
178+
uses: actions-rs/cargo@v1
179+
with:
180+
command: test
181+
args: --target=${{ matrix.TARGET }} --workspace --features comparison/mum32bit
182+
176183
- name: Test MSRV
177184
if: matrix.rust == '1.36.0' || matrix.TARGET == 'x86_64-unknown-linux-musl'
178185
uses: actions-rs/cargo@v1
@@ -186,6 +193,12 @@ jobs:
186193
run: |
187194
cargo test --target=${{ matrix.TARGET }}
188195
196+
- name: Test MSRV comparison 32-bit mum
197+
if: matrix.rust == '1.36.0' && matrix.TARGET != 'x86_64-unknown-linux-musl' # musl-gcc is not installed
198+
working-directory: ./comparison
199+
run: |
200+
cargo test --target=${{ matrix.TARGET }} --features mum32bit
201+
189202
- name: Build examples
190203
uses: actions-rs/cargo@v1
191204
if: contains(matrix.TARGET, 'x86_64')
@@ -224,7 +237,7 @@ jobs:
224237
- name: Run cargo-tarpaulin
225238
uses: actions-rs/[email protected]
226239
with:
227-
args: '--workspace --out Lcov -- --test-threads 1'
240+
args: '--workspace -- --test-threads 1'
228241

229242
- name: upload to Coveralls
230243
uses: coverallsapp/github-action@master

.tarpaulin.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[default_coverage]
2+
features = ""
3+
4+
[mum32bit_coverage]
5+
features = "comparison/mum32bit"
6+
7+
[report]
8+
out = ["Lcov"]

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
99

1010
### Added
1111
- Ported `final3` algorithm version.
12+
- Enable better performance on 32-bit systems via the `mum32bit` feature.
1213
- Benchmarks.
1314

1415
### Changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ metrohash = "1"
2828
fnv = "1"
2929
twox-hash = "1"
3030

31+
[features]
32+
mum32bit = []
33+
3134
[workspace]
3235
members = ["comparison"]
3336

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,14 @@ used in `no_std` environments) and has no dependencies (except the traits from `
1717
The generated hashes are equal (see tests) as of the version stated [here][original-version]
1818
although the speed varies ([PRs are welcome][issue-tracker]).
1919

20-
### Usage
20+
## Crate features
21+
22+
By default this crate uses 128-bit integer multiplications.
23+
To restrict that to 64 bits you can enable the feature `mum32bit`. This offers better
24+
performance on 32-bit architectures.
25+
Beware that this feature produces different results.
26+
27+
## Usage
2128

2229
This crate provides free functions as well as implementations of the `Hasher`, `Rng` and
2330
`SeedableRng` traits.

comparison/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ twox-hash = "1"
1919
cc = "1"
2020
cmake = "0.1"
2121

22+
[features]
23+
mum32bit = ["wyhash/mum32bit"]
24+
2225
[[bench]]
2326
name = "bench"
2427
harness = false

comparison/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ fn main() {
77
println!("cargo:rustc-link-search=native={}", dst.display());
88
println!("cargo:rustc-link-lib=static=original_v1");
99
println!("cargo:rustc-link-lib=static=original_final3");
10+
println!("cargo:rustc-link-lib=static=original_final3_32bit_mum");
1011
}

comparison/original/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,9 @@ add_library(original_final3
2323
${CMAKE_CURRENT_SOURCE_DIR}/lib_final3.c
2424
${CMAKE_CURRENT_BINARY_DIR}/wyhash_final3.h)
2525

26-
install(TARGETS original_v1 original_final3 DESTINATION .)
26+
add_library(original_final3_32bit_mum
27+
${CMAKE_CURRENT_SOURCE_DIR}/lib_final3_32bit_mum.c
28+
${CMAKE_CURRENT_BINARY_DIR}/wyhash_final3.h)
29+
30+
install(TARGETS original_v1 original_final3 original_final3_32bit_mum DESTINATION .)
2731

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#define WYHASH_32BIT_MUM 1
2+
#include "wyhash_final3.h"
3+
4+
uint64_t c_wyhash_final3_32bit_mum(const void* key, size_t len, uint64_t seed,
5+
const uint64_t* secret) {
6+
return wyhash(key, len, seed, secret);
7+
}
8+
9+
uint64_t c_wyrng_final3_32bit_mum(uint64_t *s) {
10+
return wyrand(s);
11+
}

comparison/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,14 @@ pub mod ffi {
1919
) -> c_ulonglong;
2020

2121
pub fn c_wyrng_final3(seed: *mut c_ulonglong) -> c_ulonglong;
22+
23+
pub fn c_wyhash_final3_32bit_mum(
24+
data: *const c_void,
25+
length: c_ulonglong,
26+
seed: c_ulonglong,
27+
secret: *const c_ulonglong,
28+
) -> c_ulonglong;
29+
30+
pub fn c_wyrng_final3_32bit_mum(seed: *mut c_ulonglong) -> c_ulonglong;
2231
}
2332
}

comparison/tests/back_to_back_hash.rs

Lines changed: 51 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use comparison::ffi::{c_wyhash_final3, c_wyhash_v1};
1+
#[cfg(not(feature = "mum32bit"))]
2+
use comparison::ffi::c_wyhash_final3;
3+
#[cfg(feature = "mum32bit")]
4+
use comparison::ffi::c_wyhash_final3_32bit_mum;
5+
use comparison::ffi::c_wyhash_v1;
26
use core::hash::Hasher;
37
use libc::{c_ulonglong, c_void};
48
use wyhash::{final3, v1};
@@ -31,44 +35,53 @@ mod v1_tests {
3135
}
3236
}
3337

34-
mod final3_tests {
35-
use super::*;
36-
37-
#[test]
38-
fn function_test() {
39-
let secret = final3::make_secret(0);
40-
let mut data = [0; 256];
41-
for i in 0..data.len() {
42-
data[i] = i as u8;
43-
let original = unsafe {
44-
c_wyhash_final3(
45-
data.as_ptr() as *const c_void,
46-
i as u64,
47-
i as u64,
48-
secret.as_ptr() as *const c_ulonglong,
49-
)
50-
};
51-
assert_eq!(original, final3::wyhash(&data[..i], i as u64, secret));
38+
macro_rules! final3_tests {
39+
($c_function: ident) => {
40+
#[test]
41+
fn function_test() {
42+
let secret = final3::make_secret(0);
43+
let mut data = [0; 256];
44+
for i in 0..data.len() {
45+
data[i] = i as u8;
46+
let original = unsafe {
47+
$c_function(
48+
data.as_ptr() as *const c_void,
49+
i as u64,
50+
i as u64,
51+
secret.as_ptr() as *const c_ulonglong,
52+
)
53+
};
54+
assert_eq!(original, final3::wyhash(&data[..i], i as u64, secret));
55+
}
5256
}
53-
}
5457

55-
#[test]
56-
fn core_hasher() {
57-
let secret = final3::make_secret(0);
58-
let mut data = [0; 256];
59-
for i in 0..data.len() {
60-
data[i] = i as u8;
61-
let mut hasher = final3::WyHash::new(i as u64, secret);
62-
hasher.write(&data[..i]);
63-
let original = unsafe {
64-
c_wyhash_final3(
65-
data.as_ptr() as *const c_void,
66-
i as u64,
67-
i as u64,
68-
secret.as_ptr() as *const c_ulonglong,
69-
)
70-
};
71-
assert_eq!(original, hasher.finish());
58+
#[test]
59+
fn core_hasher() {
60+
let secret = final3::make_secret(0);
61+
let mut data = [0; 256];
62+
for i in 0..data.len() {
63+
data[i] = i as u8;
64+
let mut hasher = final3::WyHash::new(i as u64, secret);
65+
hasher.write(&data[..i]);
66+
let original = unsafe {
67+
$c_function(
68+
data.as_ptr() as *const c_void,
69+
i as u64,
70+
i as u64,
71+
secret.as_ptr() as *const c_ulonglong,
72+
)
73+
};
74+
assert_eq!(original, hasher.finish());
75+
}
7276
}
73-
}
77+
};
78+
}
79+
80+
mod final3_tests {
81+
use super::*;
82+
#[cfg(not(feature = "mum32bit"))]
83+
final3_tests!(c_wyhash_final3);
84+
85+
#[cfg(feature = "mum32bit")]
86+
final3_tests!(c_wyhash_final3_32bit_mum);
7487
}

comparison/tests/back_to_back_prng.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use comparison::ffi::{c_wyrng_final3, c_wyrng_v1};
1+
#[cfg(not(feature = "mum32bit"))]
2+
use comparison::ffi::c_wyrng_final3;
3+
#[cfg(feature = "mum32bit")]
4+
use comparison::ffi::c_wyrng_final3_32bit_mum;
5+
use comparison::ffi::c_wyrng_v1;
26
use rand::{RngCore, SeedableRng};
37
use wyhash::v1::wyrng as wyrng_v1;
48
use wyhash::v1::WyRng as WyRngV1;
@@ -103,4 +107,9 @@ macro_rules! impl_tests {
103107
}
104108

105109
impl_tests!(v1, WyRngV1, wyrng_v1, c_wyrng_v1);
110+
111+
#[cfg(not(feature = "mum32bit"))]
106112
impl_tests!(final3, WyRng, wyrng, c_wyrng_final3);
113+
114+
#[cfg(feature = "mum32bit")]
115+
impl_tests!(final3, WyRng, wyrng, c_wyrng_final3_32bit_mum);

src/final3/functions.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,25 @@
11
use crate::v1::functions::{read32, read64, P0, P1};
22
use core::cmp::Ordering;
33

4+
#[cfg(feature = "mum32bit")]
5+
#[inline]
6+
fn wyrotate(x: u64) -> u64 {
7+
(x >> 32) | (x << 32)
8+
}
9+
10+
#[cfg(feature = "mum32bit")]
11+
#[inline]
12+
fn wymum(a: u64, b: u64) -> u64 {
13+
let hh = (a >> 32) * (b >> 32);
14+
let hl = (a >> 32) * (b & 0xFFFF_FFFF);
15+
let lh = (a & 0xFFFF_FFFF) * (b >> 32);
16+
let ll = (a & 0xFFFF_FFFF) * (b & 0xFFFF_FFFF);
17+
let a = wyrotate(hl) ^ hh;
18+
let b = wyrotate(lh) ^ ll;
19+
a ^ b
20+
}
21+
22+
#[cfg(not(feature = "mum32bit"))]
423
#[inline]
524
fn wymum(a: u64, b: u64) -> u64 {
625
let r = u128::from(a) * u128::from(b);

src/lib.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
//! [original]: https://github.com/wangyi-fudan/wyhash
1919
//! [original-version]: https://github.com/eldruin/wyhash-rs/blob/master/comparison/original/CMakeLists.txt
2020
//!
21+
//! ## Crate features
22+
//!
23+
//! By default this crate uses 128-bit integer multiplications.
24+
//! To restrict that to 64 bits you can enable the feature `mum32bit`. This offers better
25+
//! performance on 32-bit architectures.
26+
//! Beware that this feature produces different the results.
27+
//!
2128
//! ## Usage (see also examples folder)
2229
//!
2330
//! For the hashing function you can use either the free function or the
@@ -32,7 +39,7 @@
3239
//! let seed = 3;
3340
//! let hash = wyhash(&data, seed, make_secret(seed));
3441
//!
35-
//! assert_eq!(0xebd4_9a0a_d010_78ce, hash);
42+
//! println!("{:x}", hash); // prints ebd49a0ad01078ce
3643
//! ```
3744
//!
3845
//! ### `Hasher` trait usage
@@ -47,7 +54,7 @@
4754
//! let mut hasher = WyHash::new(4, secret);
4855
//! hasher.write(&[0, 1, 2]);
4956
//!
50-
//! assert_eq!(0x8301_42a2_4404_5ff4, hasher.finish());
57+
//! println!("{:x}", hasher.finish()); // prints 830142a244045ff4
5158
//! ```
5259
//!
5360
//! ### `wyrng` function usage
@@ -61,8 +68,8 @@
6168
//! let mut seed = 3;
6269
//! let random_number = wyrng(&mut seed);
6370
//!
64-
//! assert_eq!(0x3e9_9a77_2750_dcbe, random_number);
65-
//! assert_eq!(0xa0761d6478bd6432, seed);
71+
//! println!("{:x}", random_number); // prints 3e99a772750dcbe
72+
//! println!("{:x}", seed); //prints a0761d6478bd6432
6673
//! ```
6774
//!
6875
//! ### `RngCore` trait usage
@@ -74,7 +81,7 @@
7481
//! use wyhash::WyRng;
7582
//!
7683
//! let mut rng = WyRng::default();
77-
//! assert_eq!(0x111c_b3a7_8f59_a58e, rng.next_u64());
84+
//! println!("{:x}", rng.next_u64()); // prints 111cb3a78f59a58e
7885
//! ```
7986
//!
8087
//! ### `SeedableRng` trait usage
@@ -88,11 +95,11 @@
8895
//! // Seeds are 8-byte long.
8996
//! let seed = [0, 1, 2, 3, 4, 5, 6, 7];
9097
//! let mut rng1 = WyRng::from_seed(seed);
91-
//! assert_eq!(0xd730_1357_74c6_ae31, rng1.next_u64());
98+
//! println!("{:x}", rng1.next_u64()); // prints d730135774c6ae31
9299
//!
93100
//! // Alternatively you can also use this convenience method:
94101
//! let mut rng2 = WyRng::seed_from_u64(3);
95-
//! assert_eq!(0x3e9_9a77_2750_dcbe, rng2.next_u64());
102+
//! println!("{:x}", rng2.next_u64()); // prints 3e99a772750dcbe
96103
//! ```
97104
98105
#![doc(html_root_url = "https://docs.rs/wyhash/0.5.0")]

tests/integration.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ fn v1_default_constructed() {
1212

1313
#[test]
1414
fn final3_default_constructed() {
15+
#[cfg(not(feature = "mum32bit"))]
16+
let expected = 0x22a2_d5db_3856_770f;
17+
#[cfg(feature = "mum32bit")]
18+
let expected = 0x6a2c_d506_62d4_cdf1;
19+
1520
let mut hasher = final3::WyHash::default();
1621
hasher.write(&[0]);
17-
assert_eq!(0x22a2_d5db_3856_770f, hasher.finish());
22+
assert_eq!(expected, hasher.finish());
1823
}

0 commit comments

Comments
 (0)