Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inital naive implementation of HashMap #143

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions apps/memtest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
extern crate axstd as std;

use rand::{rngs::SmallRng, RngCore, SeedableRng};
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::vec::Vec;

fn test_vec(rng: &mut impl RngCore) {
Expand All @@ -22,9 +22,9 @@ fn test_vec(rng: &mut impl RngCore) {
println!("test_vec() OK!");
}

fn test_btree_map(rng: &mut impl RngCore) {
fn test_hashmap_map(rng: &mut impl RngCore) {
const N: usize = 50_000;
let mut m = BTreeMap::new();
let mut m = HashMap::new();
for _ in 0..N {
let value = rng.next_u32();
let key = format!("key_{value}");
Expand All @@ -35,7 +35,7 @@ fn test_btree_map(rng: &mut impl RngCore) {
assert_eq!(k.parse::<u32>().unwrap(), *v);
}
}
println!("test_btree_map() OK!");
println!("test_hashmap_map() OK!");
}

#[cfg_attr(feature = "axstd", no_mangle)]
Expand All @@ -44,7 +44,7 @@ fn main() {

let mut rng = SmallRng::seed_from_u64(0xdead_beef);
test_vec(&mut rng);
test_btree_map(&mut rng);
test_hashmap_map(&mut rng);

println!("Memory tests run OK!");
}
102 changes: 102 additions & 0 deletions ulib/axstd/src/collections/hashmap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
extern crate alloc;

const N: usize = 128;

struct Entry<K, V> {
key: K,
value: V,
}

// As a Rust newbie, I found it's very hard to me to port the hash map implementation from std library which contains too many things
// I generated the initial code by ChatGPT, and fixed the code issues with the help of ChatGPT prompts and compiler hints
// I am glad to pass the unit tests in the end
pub struct HashMap<K, V> {
storage: [Option<Entry<K, V>>; N],
}

pub struct HashMapIter<'a, K, V> {
hashmap: &'a HashMap<K, V>,
index: usize,
}

impl<K, V> HashMap<K, V>
where
K: PartialEq,
{
const ARRAY_REPEAT_VALUE: Option<Entry<K, V>> = None;

pub fn new() -> Self {
HashMap {
storage: [Self::ARRAY_REPEAT_VALUE; N],
}
}

pub fn insert(&mut self, key: K, value: V) -> Option<V> {
let index = self.hash(&key) % N;
for i in 0..N {
let idx = (index + i) % N;
match self.storage[idx] {
Some(ref entry) if entry.key == key => {
let old_value =
core::mem::replace(&mut self.storage[idx].as_mut().unwrap().value, value);
return Some(old_value);
}
None => {
self.storage[idx] = Some(Entry { key, value });
return None;
}
_ => continue,
}
}
None
}

pub fn get(&self, key: K) -> Option<&V> {
let index = self.hash(&key) % N;
for i in 0..N {
let idx = (index + i) % N;
match self.storage[idx] {
Some(ref entry) if entry.key == key => return Some(&entry.value),
None => return None,
_ => continue,
}
}
None
}

// A very simple hash function for demonstration purposes.
// You should use a better hash function for real applications.
fn hash(&self, key: &K) -> usize {
let key_ptr = key as *const K as usize;
key_ptr % N
}

pub fn iter(&self) -> HashMapIter<K, V> {
HashMapIter {
hashmap: self,
index: 0,
}
}
}

impl<'a, K, V> Iterator for HashMapIter<'a, K, V>
where
K: PartialEq,
{
type Item = (&'a K, &'a V);

fn next(&mut self) -> Option<Self::Item> {
while self.index < N {
match self.hashmap.storage[self.index] {
Some(ref entry) => {
self.index += 1; // Move to the next index for the next call to next()
return Some((&entry.key, &entry.value));
}
None => {
self.index += 1; // Current index is empty, move to the next one
}
}
}
None // All entries have been traversed
}
}
2 changes: 2 additions & 0 deletions ulib/axstd/src/collections/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod hashmap;
pub use self::hashmap::HashMap;
3 changes: 2 additions & 1 deletion ulib/axstd/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,15 @@ extern crate alloc;

#[cfg(feature = "alloc")]
#[doc(no_inline)]
pub use alloc::{boxed, collections, format, string, vec};
pub use alloc::{boxed, format, string, vec};

#[doc(no_inline)]
pub use core::{arch, cell, cmp, hint, marker, mem, ops, ptr, slice, str};

#[macro_use]
mod macros;

pub mod collections;
pub mod env;
pub mod io;
pub mod os;
Expand Down