mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 12:56:48 +00:00
Add Bob Jenkins's hash algorithm
This commit is contained in:
parent
0d30ce0b2c
commit
783345b90b
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -71,10 +71,11 @@ name = "aster-bigtcp"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"keyable-arc",
|
||||
"jhash",
|
||||
"ostd",
|
||||
"smoltcp",
|
||||
"spin 0.9.8",
|
||||
"static_assertions",
|
||||
"takeable",
|
||||
]
|
||||
|
||||
@ -839,6 +840,10 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jhash"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "json"
|
||||
version = "0.12.4"
|
||||
|
@ -27,6 +27,7 @@ members = [
|
||||
"kernel/libs/aster-rights-proc",
|
||||
"kernel/libs/aster-util",
|
||||
"kernel/libs/aster-bigtcp",
|
||||
"kernel/libs/jhash",
|
||||
"kernel/libs/keyable-arc",
|
||||
"kernel/libs/typeflags",
|
||||
"kernel/libs/typeflags-util",
|
||||
|
1
Makefile
1
Makefile
@ -129,6 +129,7 @@ NON_OSDK_CRATES := \
|
||||
kernel/libs/int-to-c-enum/derive \
|
||||
kernel/libs/aster-rights \
|
||||
kernel/libs/aster-rights-proc \
|
||||
kernel/libs/jhash \
|
||||
kernel/libs/keyable-arc \
|
||||
kernel/libs/typeflags \
|
||||
kernel/libs/typeflags-util \
|
||||
|
6
kernel/libs/jhash/Cargo.toml
Normal file
6
kernel/libs/jhash/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "jhash"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
339
kernel/libs/jhash/src/lib.rs
Normal file
339
kernel/libs/jhash/src/lib.rs
Normal file
@ -0,0 +1,339 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! This module implements hash algorithms developed by Bob Jenkins.
|
||||
//!
|
||||
//! For further information, visit: www.burtleburtle.net/bob/hash/doobs.html
|
||||
//!
|
||||
//! The hash functions in this module facilitate the production of 32-bit values for hash table lookups.
|
||||
//! Although the [Linux kernel's jhash](https://github.com/torvalds/linux/blob/master/include/linux/jhash.h)
|
||||
//! slightly differs from the original version, this module reimplements the Linux kernel's version.
|
||||
//!
|
||||
|
||||
#![no_std]
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
/// A randomly chosen initial value
|
||||
const JHASH_INITVAL: u32 = 0xdeadbeef;
|
||||
|
||||
/// Hashes an arbitrary u8 slices.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// If you are hashing n slices, do it like this:
|
||||
/// ```rust
|
||||
/// use jhash::jhash_slice;
|
||||
///
|
||||
/// fn hash_slices(slices: &[&[u8]]) -> u32 {
|
||||
/// let mut hash: u32 = 0;
|
||||
/// for slice in slices {
|
||||
/// hash = jhash_slice(slice, hash);
|
||||
/// }
|
||||
/// hash
|
||||
/// }
|
||||
/// ```
|
||||
pub const fn jhash_slice(slice: &[u8], initval: u32) -> u32 {
|
||||
let mut length = slice.len() as u32;
|
||||
let mut index: usize = 0;
|
||||
|
||||
// Init the internal state
|
||||
let mut a: u32 = JHASH_INITVAL.wrapping_add(length).wrapping_add(initval);
|
||||
let mut b: u32 = a;
|
||||
let mut c: u32 = a;
|
||||
|
||||
// Handle the most bytes except last 12 bytes
|
||||
while length > 12 {
|
||||
// FIXME: The Linux version uses `u32::from_ne_bytes`.
|
||||
// Here, we use `from_le_bytes` to ensure consistency
|
||||
// in results across multiple runs on all machines.
|
||||
a = a.wrapping_add(u32::from_le_bytes([
|
||||
slice[index],
|
||||
slice[index + 1],
|
||||
slice[index + 2],
|
||||
slice[index + 3],
|
||||
]));
|
||||
b = b.wrapping_add(u32::from_le_bytes([
|
||||
slice[index + 4],
|
||||
slice[index + 5],
|
||||
slice[index + 6],
|
||||
slice[index + 7],
|
||||
]));
|
||||
c = c.wrapping_add(u32::from_le_bytes([
|
||||
slice[index + 8],
|
||||
slice[index + 9],
|
||||
slice[index + 10],
|
||||
slice[index + 11],
|
||||
]));
|
||||
(a, b, c) = jhash_mix(a, b, c);
|
||||
|
||||
index += 12;
|
||||
length -= 12;
|
||||
}
|
||||
|
||||
// Handle the last 12 bytes
|
||||
if length == 12 {
|
||||
c = c.wrapping_add((slice[index + 11] as u32) << 24);
|
||||
}
|
||||
|
||||
if length >= 11 {
|
||||
c = c.wrapping_add((slice[index + 10] as u32) << 16);
|
||||
}
|
||||
|
||||
if length >= 10 {
|
||||
c = c.wrapping_add((slice[index + 9] as u32) << 8);
|
||||
}
|
||||
|
||||
if length >= 9 {
|
||||
c = c.wrapping_add(slice[index + 8] as u32);
|
||||
}
|
||||
|
||||
if length >= 8 {
|
||||
b = b.wrapping_add((slice[index + 7] as u32) << 24);
|
||||
}
|
||||
|
||||
if length >= 7 {
|
||||
b = b.wrapping_add((slice[index + 6] as u32) << 16);
|
||||
}
|
||||
|
||||
if length >= 6 {
|
||||
b = b.wrapping_add((slice[index + 5] as u32) << 8);
|
||||
}
|
||||
|
||||
if length >= 5 {
|
||||
b = b.wrapping_add(slice[index + 4] as u32);
|
||||
}
|
||||
|
||||
if length >= 4 {
|
||||
a = a.wrapping_add((slice[index + 3] as u32) << 24);
|
||||
}
|
||||
|
||||
if length >= 3 {
|
||||
a = a.wrapping_add((slice[index + 2] as u32) << 16);
|
||||
}
|
||||
|
||||
if length >= 2 {
|
||||
a = a.wrapping_add((slice[index + 1] as u32) << 8);
|
||||
}
|
||||
|
||||
if length >= 1 {
|
||||
a = a.wrapping_add(slice[index] as u32);
|
||||
return jhash_final(a, b, c);
|
||||
}
|
||||
|
||||
c
|
||||
}
|
||||
|
||||
/// Hashes exactly three u32 values
|
||||
pub const fn jhash_3vals(a: u32, b: u32, c: u32, initval: u32) -> u32 {
|
||||
jhash_3vals_inner(
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
initval.wrapping_add(JHASH_INITVAL).wrapping_add(3 << 2),
|
||||
)
|
||||
}
|
||||
|
||||
/// Hashes exactly two u32 values
|
||||
pub const fn jhash_2vals(a: u32, b: u32, initval: u32) -> u32 {
|
||||
jhash_3vals_inner(
|
||||
a,
|
||||
b,
|
||||
0,
|
||||
initval.wrapping_add(JHASH_INITVAL).wrapping_add(2 << 2),
|
||||
)
|
||||
}
|
||||
|
||||
/// Hashes exactly one u32 value
|
||||
pub const fn jhash_1vals(a: u32, initval: u32) -> u32 {
|
||||
jhash_3vals_inner(
|
||||
a,
|
||||
0,
|
||||
0,
|
||||
initval.wrapping_add(JHASH_INITVAL).wrapping_add(1 << 2),
|
||||
)
|
||||
}
|
||||
|
||||
/// Hashes an array of u32 values.
|
||||
pub const fn jhash_u32_array(array: &[u32], initval: u32) -> u32 {
|
||||
let mut length = array.len() as u32;
|
||||
let mut index = 0;
|
||||
|
||||
// Initialize values a, b, and c
|
||||
let mut a: u32 = JHASH_INITVAL
|
||||
.wrapping_add(length << 2)
|
||||
.wrapping_add(initval);
|
||||
let mut b: u32 = a;
|
||||
let mut c: u32 = a;
|
||||
|
||||
// Process most values except the last three
|
||||
while length > 3 {
|
||||
a = a.wrapping_add(array[index]);
|
||||
b = b.wrapping_add(array[index + 1]);
|
||||
c = c.wrapping_add(array[index + 2]);
|
||||
(a, b, c) = jhash_mix(a, b, c);
|
||||
|
||||
length -= 3;
|
||||
index += 3;
|
||||
}
|
||||
|
||||
if length == 3 {
|
||||
c = c.wrapping_add(array[index + 2]);
|
||||
}
|
||||
|
||||
if length >= 2 {
|
||||
b = b.wrapping_add(array[index + 1]);
|
||||
}
|
||||
|
||||
if length >= 1 {
|
||||
a = a.wrapping_add(array[index]);
|
||||
return jhash_final(a, b, c);
|
||||
}
|
||||
|
||||
c
|
||||
}
|
||||
|
||||
/// An internal function that handles hashing for 3 u32 values
|
||||
const fn jhash_3vals_inner(mut a: u32, mut b: u32, mut c: u32, initval: u32) -> u32 {
|
||||
a = a.wrapping_add(initval);
|
||||
b = b.wrapping_add(initval);
|
||||
c = c.wrapping_add(initval);
|
||||
|
||||
jhash_final(a, b, c)
|
||||
}
|
||||
|
||||
/// Finalizes the mix of three 32-bit values into a single u32 value
|
||||
const fn jhash_final(mut a: u32, mut b: u32, mut c: u32) -> u32 {
|
||||
c ^= b;
|
||||
c = c.wrapping_sub(b.rotate_left(14));
|
||||
|
||||
a ^= c;
|
||||
a = a.wrapping_sub(c.rotate_left(11));
|
||||
|
||||
b ^= a;
|
||||
b = b.wrapping_sub(a.rotate_left(25));
|
||||
|
||||
c ^= b;
|
||||
c = c.wrapping_sub(b.rotate_left(16));
|
||||
|
||||
a ^= c;
|
||||
a = a.wrapping_sub(c.rotate_left(4));
|
||||
|
||||
b ^= a;
|
||||
b = b.wrapping_sub(a.rotate_left(14));
|
||||
|
||||
c ^= b;
|
||||
c.wrapping_sub(b.rotate_left(24))
|
||||
}
|
||||
|
||||
/// Mixes three 32-bit values in a reversible manner
|
||||
const fn jhash_mix(mut a: u32, mut b: u32, mut c: u32) -> (u32, u32, u32) {
|
||||
a = a.wrapping_sub(c);
|
||||
a ^= c.rotate_left(4);
|
||||
c = c.wrapping_add(b);
|
||||
|
||||
b = b.wrapping_sub(a);
|
||||
b ^= a.rotate_left(6);
|
||||
a = a.wrapping_add(c);
|
||||
|
||||
c = c.wrapping_sub(b);
|
||||
c ^= b.rotate_left(8);
|
||||
b = b.wrapping_add(a);
|
||||
|
||||
a = a.wrapping_sub(c);
|
||||
a ^= c.rotate_left(16);
|
||||
c = c.wrapping_add(b);
|
||||
|
||||
b = b.wrapping_sub(a);
|
||||
b ^= a.rotate_left(19);
|
||||
a = a.wrapping_add(c);
|
||||
|
||||
c = c.wrapping_sub(b);
|
||||
c ^= b.rotate_left(4);
|
||||
b = b.wrapping_add(a);
|
||||
|
||||
(a, b, c)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
const JHASH_INITVAL: u32 = 0;
|
||||
|
||||
#[test]
|
||||
fn test_jhash_3vals() {
|
||||
assert_eq!(jhash_3vals(1, 2, 3, JHASH_INITVAL), 2757843189);
|
||||
assert_eq!(jhash_3vals(4, 5, 6, JHASH_INITVAL), 3701334656);
|
||||
|
||||
assert_eq!(jhash_3vals(0, 0, 0, JHASH_INITVAL), 459859287);
|
||||
assert_eq!(
|
||||
jhash_3vals(u32::MAX, u32::MAX, u32::MAX, JHASH_INITVAL),
|
||||
1846109353
|
||||
);
|
||||
|
||||
assert_eq!(jhash_3vals(1, 2, 3, 10), 453614296);
|
||||
assert_eq!(jhash_3vals(10, 20, 30, 5), 1448556389);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_jhash_2vals() {
|
||||
assert_eq!(jhash_2vals(1, 2, JHASH_INITVAL), 2337044857);
|
||||
assert_eq!(jhash_2vals(3, 4, JHASH_INITVAL), 3842257880);
|
||||
assert_eq!(jhash_2vals(0, 0, JHASH_INITVAL), 1489077439);
|
||||
assert_eq!(jhash_2vals(u32::MAX, u32::MAX, JHASH_INITVAL), 1382321797);
|
||||
assert_eq!(jhash_2vals(1, 2, 10), 1474913524);
|
||||
assert_eq!(jhash_2vals(10, 20, 5), 1368945286);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_jhash_1vals() {
|
||||
assert_eq!(jhash_1vals(1, JHASH_INITVAL), 1923623579);
|
||||
assert_eq!(jhash_1vals(5, JHASH_INITVAL), 4121471414);
|
||||
assert_eq!(jhash_1vals(0, JHASH_INITVAL), 76781240);
|
||||
assert_eq!(jhash_1vals(u32::MAX, JHASH_INITVAL), 2601633627);
|
||||
assert_eq!(jhash_1vals(1, 10), 1508237099);
|
||||
assert_eq!(jhash_1vals(10, 5), 2141486731);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_jhash_u32_array() {
|
||||
assert_eq!(jhash_u32_array(&[1, 2, 3], JHASH_INITVAL), 2757843189);
|
||||
assert_eq!(jhash_u32_array(&[4, 5, 6, 7, 8], JHASH_INITVAL), 581654130);
|
||||
assert_eq!(jhash_u32_array(&[], JHASH_INITVAL), 3735928559);
|
||||
assert_eq!(jhash_u32_array(&[10], JHASH_INITVAL), 1030482289);
|
||||
assert_eq!(jhash_u32_array(&[10, 20], JHASH_INITVAL), 363923158);
|
||||
assert_eq!(
|
||||
jhash_u32_array(&[0, 1, 2, u32::MAX], JHASH_INITVAL),
|
||||
3019125658
|
||||
);
|
||||
assert_eq!(jhash_u32_array(&[1, 2, 3], 10), 453614296);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_jhash_slice() {
|
||||
assert_eq!(jhash_slice(b"hello world", JHASH_INITVAL), 1252609637);
|
||||
assert_eq!(jhash_slice(b"12345", JHASH_INITVAL), 729031446);
|
||||
assert_eq!(jhash_slice(b"\n\t\r", JHASH_INITVAL), 483925400);
|
||||
assert_eq!(jhash_slice(b"", JHASH_INITVAL), 3735928559);
|
||||
|
||||
let test_slices = &[
|
||||
b"12345".as_slice(),
|
||||
b"hello world hello world",
|
||||
b"\n",
|
||||
b"",
|
||||
b"\t\r\n",
|
||||
];
|
||||
fn hash_slices(slices: &[&[u8]]) -> u32 {
|
||||
let mut hash: u32 = 0;
|
||||
for slice in slices {
|
||||
hash = jhash_slice(slice, hash);
|
||||
}
|
||||
hash
|
||||
}
|
||||
assert_eq!(hash_slices(test_slices), 3662697720);
|
||||
assert_eq!(hash_slices(&test_slices[0..4]), 230550114);
|
||||
assert_eq!(hash_slices(&test_slices[0..3]), 789588851);
|
||||
assert_eq!(hash_slices(&test_slices[0..2]), 1101610926);
|
||||
assert_eq!(hash_slices(&test_slices[0..1]), 729031446);
|
||||
assert_eq!(hash_slices(&[]), 0);
|
||||
}
|
||||
}
|
@ -32,9 +32,9 @@ fi
|
||||
# Format the 100-line kernel demo as well
|
||||
KERNEL_DEMO_FILE="$WORKSPACE_ROOT/osdk/tests/examples_in_book/write_a_kernel_in_100_lines_templates/lib.rs"
|
||||
if [ "$CHECK_MODE" = true ]; then
|
||||
cargo fmt --check -- $KERNEL_DEMO_FILE
|
||||
rustfmt --check $KERNEL_DEMO_FILE
|
||||
else
|
||||
cargo fmt -- $KERNEL_DEMO_FILE
|
||||
rustfmt $KERNEL_DEMO_FILE
|
||||
fi
|
||||
|
||||
for CRATE in $EXCLUDED_CRATES; do
|
||||
|
Loading…
x
Reference in New Issue
Block a user