diff --git a/Cargo.toml b/Cargo.toml index 08ef4ca..57eb269 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "fchashmap" -version = "0.1.3" +version = "0.2.0" authors = ["Simsys "] -edition = "2018" +edition = "2024" license = "MIT OR Apache-2.0" description = "A fixed capacity no_std hashmap" repository = "https://github.com/Simsys/fchashmap" @@ -11,15 +11,10 @@ keywords = ["no-std", "static", "no-heap", "embedded"] categories = ["no-std", "embedded", "data-structures"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -hash32 = "0.2.1" - -[dependencies.arrayvec] -version = "0.7.0" -default-features = false +arrayvec = { version = "0.7.8", default-features = false } +hash32 = "1.0.0" [dev-dependencies] -hash32-derive = "0.1.0" rand_xorshift = "0.3.0" rand_core = "0.6.2" diff --git a/src/lib.rs b/src/lib.rs index 1cbf05e..36c944a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,8 +14,8 @@ mod map; use map::{Iter, IterMut, Map}; //use std::{fmt::Display}; +use core::hash::Hash; use core::{borrow::Borrow, fmt, iter::FromIterator, ops}; -use hash32::Hash; /// A fixed capacity no_std hashmap. /// @@ -34,8 +34,7 @@ use hash32::Hash; /// /// ``` /// use fchashmap::FcHashMap; -/// use hash32_derive::Hash32; -/// use hash32::Hash; +/// use core::hash::Hash; /// /// #[derive(Debug)] /// struct Reading { @@ -43,7 +42,7 @@ use hash32::Hash; /// humidy: f32, /// } /// -/// #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash32)] +/// #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] /// struct DeviceId([u8; 8]); /// /// impl DeviceId { @@ -73,11 +72,11 @@ use hash32::Hash; /// /// assert!(fc_hash_map.get(&dev3).is_none()); /// ``` -/// +/// /// ## Performance /// /// The following diagram shows the timing behavior on a Cortex M4f system (STM32F3) at 72 MHz. It -/// can be seen that the performance of the hashmap decreases significantly from a fill margin of +/// can be seen that the performance of the hashmap decreases significantly from a fill margin of /// about 80%. /// /// ![Image](https://raw.githubusercontent.com/Simsys/fchashmap/master/benches/cm4_performance/fchashmap.png) @@ -85,8 +84,7 @@ pub struct FcHashMap { map: Map, } -impl FcHashMap -{ +impl FcHashMap { // pub fn show(&self) { self.map.show() } /// Creates an empty HashMap. diff --git a/src/map.rs b/src/map.rs index 93399a5..eb02513 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1,7 +1,8 @@ #![allow(dead_code)] use arrayvec::ArrayVec; +use core::hash::{BuildHasher, BuildHasherDefault, Hash}; use core::{borrow::Borrow, mem, slice}; -use hash32::{BuildHasher, BuildHasherDefault, FnvHasher, Hash, Hasher}; +use hash32::{Hasher, Murmur3Hasher}; #[derive(Clone, Copy, PartialEq)] struct HashValue(u16); @@ -37,7 +38,10 @@ struct HashIndex { impl HashIndex { // Create a nuew hash index from given parameters fn new(hash: HashValue, b_idx: usize) -> Self { - Self { hash, b_idx: b_idx as u16 } + Self { + hash, + b_idx: b_idx as u16, + } } // Clear actual hash index an mark it as empty @@ -61,11 +65,10 @@ pub struct Bucket { pub struct Map { pub buckets: ArrayVec, CAP>, hash_table: [HashIndex; CAP], - build_hasher: BuildHasherDefault, + build_hasher: BuildHasherDefault, } -impl Map -{ +impl Map { // Create a new map pub fn new() -> Self { debug_assert!((Self::capacity() as u32) < u32::MAX); @@ -98,7 +101,7 @@ impl Map { let mut h = self.build_hasher.build_hasher(); key.hash(&mut h); - HashValue::new(h.finish()) + HashValue::new(h.finish32()) } // Inserts a key-value pair into the map. @@ -142,7 +145,7 @@ impl Map if next_hash_index.is_empty() { // We found the right place: store and return *next_hash_index = hash_index; - unsafe { self.buckets.push_unchecked( Bucket { key, value, hash }) } + unsafe { self.buckets.push_unchecked(Bucket { key, value, hash }) } return Ok(None); } else { // Replace HashIndexs and continue shifting and searching for a vacancy diff --git a/tests/monte_carlo.rs b/tests/monte_carlo.rs index e65ab69..ab68510 100644 --- a/tests/monte_carlo.rs +++ b/tests/monte_carlo.rs @@ -1,18 +1,16 @@ use fchashmap::FcHashMap; -use rand_xorshift::XorShiftRng; use rand_core::{RngCore, SeedableRng}; +use rand_xorshift::XorShiftRng; use std::collections::HashMap; - struct MonteCarlo { - fc_hashmap: FcHashMap::, - std_hashmap: HashMap::, + fc_hashmap: FcHashMap, + std_hashmap: HashMap, } const MAP_SIZE: usize = 16384; const SEED: u64 = 1234567890987654321; - impl MonteCarlo { fn new() -> Self { Self { @@ -30,14 +28,28 @@ impl MonteCarlo { match r_fc { Ok(r_v) => { if r_v != r_std { - println!("Error 1, len {}, key {}, value {}, r_v{:?}, r_std {:?}", self.fc_hashmap.len(), key, value, r_v, r_std); + println!( + "Error 1, len {}, key {}, value {}, r_v{:?}, r_std {:?}", + self.fc_hashmap.len(), + key, + value, + r_v, + r_std + ); }; assert_eq!(r_v, r_std); - }, + } Err(e) => { - println!("Error 2, len {}, key {}, value {}, e{:?}, r_std {:?}", self.fc_hashmap.len(), key, value, e, r_std); + println!( + "Error 2, len {}, key {}, value {}, e{:?}, r_std {:?}", + self.fc_hashmap.len(), + key, + value, + e, + r_std + ); assert!(false); - }, + } } } @@ -48,7 +60,13 @@ impl MonteCarlo { let r_std = self.std_hashmap.remove(&key); if r_fc != r_std { - println!("Error 3, len {}, key {}, r_fc{:?}, r_std {:?}", self.fc_hashmap.len(), key, r_fc, r_std); + println!( + "Error 3, len {}, key {}, r_fc{:?}, r_std {:?}", + self.fc_hashmap.len(), + key, + r_fc, + r_std + ); }; assert_eq!(r_fc, r_std); } @@ -60,7 +78,13 @@ impl MonteCarlo { let r_std = self.std_hashmap.get(&key); if r_fc != r_std { - println!("Error 4, len {}, key {}, r_fc{:?}, r_std {:?}", self.fc_hashmap.len(), key, r_fc, r_std); + println!( + "Error 4, len {}, key {}, r_fc{:?}, r_std {:?}", + self.fc_hashmap.len(), + key, + r_fc, + r_std + ); }; assert_eq!(r_fc, r_std); } @@ -103,7 +127,7 @@ impl MonteCarlo { // First, we fill the map at 50% let mut rng = XorShiftRng::seed_from_u64(SEED); loop { - if self.fc_hashmap.len() >= MAP_SIZE/2 { + if self.fc_hashmap.len() >= MAP_SIZE / 2 { break; } self.insert(&mut rng); @@ -117,7 +141,13 @@ impl MonteCarlo { let r_std = self.std_hashmap.get(&key); if r_fc != r_std { - println!("Error 6, len {}, key {}, r_fc{:?}, r_std {:?}", self.fc_hashmap.len(), key, r_fc, r_std); + println!( + "Error 6, len {}, key {}, r_fc{:?}, r_std {:?}", + self.fc_hashmap.len(), + key, + r_fc, + r_std + ); }; assert_eq!(r_fc, r_std); } @@ -125,7 +155,7 @@ impl MonteCarlo { } #[test] -fn monte_carlo () { +fn monte_carlo() { let mut m = MonteCarlo::new(); m.test_1(); m.test_2();