Add documentation example and add Borrow stuff for easier contains_key

This commit is contained in:
Gwilym Inzani 2023-04-23 18:37:30 +01:00
parent d594e9e078
commit 150b1a3078

View file

@ -20,6 +20,7 @@ extern crate alloc;
use alloc::{alloc::Global, vec::Vec}; use alloc::{alloc::Global, vec::Vec};
use core::{ use core::{
alloc::Allocator, alloc::Allocator,
borrow::Borrow,
hash::{BuildHasher, BuildHasherDefault, Hash, Hasher}, hash::{BuildHasher, BuildHasherDefault, Hash, Hasher},
iter::FromIterator, iter::FromIterator,
mem::{self, MaybeUninit}, mem::{self, MaybeUninit},
@ -99,6 +100,38 @@ type HashType = u32;
/// ///
/// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html
/// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html
///
/// # Example
/// ```
/// use agb_hashmap::HashMap;
///
/// // Type inference lets you omit the type signature (which would be HashMap<String, String> in this example)
/// let mut game_reviews = HashMap::new();
///
/// // Review some games
/// game_reviews.insert(
/// "Pokemon Emerald".to_string(),
/// "Best post-game battle experience of any generation.".to_string(),
/// );
/// game_reviews.insert(
/// "Golden Sun".to_string(),
/// "Some of the best music on the console".to_string(),
/// );
/// game_reviews.insert(
/// "Super Dodge Ball Advance".to_string(),
/// "Really great launch title".to_string(),
/// );
///
/// // Check for a specific entry
/// if !game_reviews.contains_key("Legend of Zelda: The Minish Cap") {
/// println!("We've got {} reviews, but The Minish Cap ain't one", game_reviews.len());
/// }
///
/// // Iterate over everything
/// for (game, review) in &game_reviews {
/// println!("{game}: \"{review}\"");
/// }
/// ```
pub struct HashMap<K, V, ALLOCATOR: Allocator = Global> { pub struct HashMap<K, V, ALLOCATOR: Allocator = Global> {
nodes: NodeStorage<K, V, ALLOCATOR>, nodes: NodeStorage<K, V, ALLOCATOR>,
@ -299,7 +332,11 @@ where
} }
/// Returns `true` if the map contains a value for the specified key. /// Returns `true` if the map contains a value for the specified key.
pub fn contains_key(&self, k: &K) -> bool { pub fn contains_key<Q>(&self, k: &Q) -> bool
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash(k); let hash = self.hash(k);
self.nodes.location(k, hash).is_some() self.nodes.location(k, hash).is_some()
} }
@ -346,7 +383,11 @@ impl<K, V, ALLOCATOR: ClonableAllocator> HashMap<K, V, ALLOCATOR>
where where
K: Hash, K: Hash,
{ {
fn hash(&self, key: &K) -> HashType { fn hash<Q>(&self, key: &Q) -> HashType
where
K: Borrow<Q>,
Q: Hash + ?Sized,
{
let mut hasher = self.hasher.build_hasher(); let mut hasher = self.hasher.build_hasher();
key.hash(&mut hasher); key.hash(&mut hasher);
hasher.finish() as HashType hasher.finish() as HashType
@ -828,9 +869,10 @@ impl<K, V, ALLOCATOR: ClonableAllocator> NodeStorage<K, V, ALLOCATOR> {
} }
} }
fn location(&self, key: &K, hash: HashType) -> Option<usize> fn location<Q>(&self, key: &Q, hash: HashType) -> Option<usize>
where where
K: Eq, K: Borrow<Q>,
Q: Eq + ?Sized,
{ {
for distance_to_initial_bucket in 0..(self.max_distance_to_initial_bucket + 1) { for distance_to_initial_bucket in 0..(self.max_distance_to_initial_bucket + 1) {
let location = fast_mod( let location = fast_mod(
@ -840,7 +882,7 @@ impl<K, V, ALLOCATOR: ClonableAllocator> NodeStorage<K, V, ALLOCATOR> {
let node = &self.nodes[location]; let node = &self.nodes[location];
if let Some(node_key_ref) = node.key_ref() { if let Some(node_key_ref) = node.key_ref() {
if node_key_ref == key { if node_key_ref.borrow() == key {
return Some(location); return Some(location);
} }
} else { } else {