use std::borrow::Borrow;
use std::collections;
use std::collections::hash_map::RandomState;
use std::fmt::{Debug, Error, Formatter};
use std::hash::{BuildHasher, Hash};
use std::iter::{FromIterator, FusedIterator, Sum};
use std::mem;
use std::ops::{Add, Index, IndexMut};
use archery::{SharedPointer, SharedPointerKind};
use crate::nodes::hamt::{
hash_key, Drain as NodeDrain, HashBits, HashValue, Iter as NodeIter, IterMut as NodeIterMut,
Node,
};
use crate::shared_ptr::DefaultSharedPtr;
#[macro_export]
macro_rules! hashmap {
() => { $crate::hashmap::HashMap::new() };
( $( $key:expr => $value:expr ),* ) => {{
let mut map = $crate::hashmap::HashMap::new();
$({
map.insert($key, $value);
})*;
map
}};
( $( $key:expr => $value:expr ,)* ) => {{
let mut map = $crate::hashmap::HashMap::new();
$({
map.insert($key, $value);
})*;
map
}};
}
pub type HashMap<K, V> = GenericHashMap<K, V, RandomState, DefaultSharedPtr>;
pub struct GenericHashMap<K, V, S, P: SharedPointerKind> {
size: usize,
root: Option<SharedPointer<Node<(K, V), P>, P>>,
hasher: S,
}
impl<K, V> HashValue for (K, V)
where
K: Eq,
{
type Key = K;
fn extract_key(&self) -> &Self::Key {
&self.0
}
fn ptr_eq(&self, _other: &Self) -> bool {
false
}
}
impl<K, V, P> GenericHashMap<K, V, RandomState, P>
where
K: Hash + Eq + Clone,
V: Clone,
P: SharedPointerKind,
{
#[inline]
#[must_use]
pub fn unit(k: K, v: V) -> GenericHashMap<K, V, RandomState, P> {
GenericHashMap::new().update(k, v)
}
}
impl<K, V, S, P: SharedPointerKind> GenericHashMap<K, V, S, P> {
#[inline]
#[must_use]
pub fn new() -> Self
where
S: Default,
{
Self::default()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.size
}
pub fn ptr_eq(&self, other: &Self) -> bool {
match (&self.root, &other.root) {
(Some(a), Some(b)) => SharedPointer::ptr_eq(a, b),
(None, None) => true,
_ => false,
}
}
#[inline]
#[must_use]
pub fn with_hasher(hasher: S) -> Self {
GenericHashMap {
size: 0,
hasher,
root: None,
}
}
#[must_use]
pub fn hasher(&self) -> &S {
&self.hasher
}
#[inline]
#[must_use]
pub fn new_from<K1, V1>(&self) -> GenericHashMap<K1, V1, S, P>
where
K1: Hash + Eq + Clone,
V1: Clone,
S: Clone,
{
GenericHashMap {
size: 0,
root: None,
hasher: self.hasher.clone(),
}
}
#[inline]
#[must_use]
pub fn iter(&self) -> Iter<'_, K, V, P> {
Iter {
it: NodeIter::new(self.root.as_deref(), self.size),
}
}
#[inline]
#[must_use]
pub fn keys(&self) -> Keys<'_, K, V, P> {
Keys {
it: NodeIter::new(self.root.as_deref(), self.size),
}
}
#[inline]
#[must_use]
pub fn values(&self) -> Values<'_, K, V, P> {
Values {
it: NodeIter::new(self.root.as_deref(), self.size),
}
}
pub fn clear(&mut self) {
self.root = None;
self.size = 0;
}
#[cfg(test)]
pub fn print_structure_summary(&self) {
use crate::nodes::hamt::Entry as NodeEntry;
use std::collections::VecDeque;
println!("HashMap Structure Summary:");
#[derive(Default, Debug)]
struct LevelStats {
node_count: usize,
value_count: usize,
collision_count: usize,
collision_entry_sum: usize,
child_node_count: usize,
small_simd_node_count: usize,
large_simd_node_count: usize,
small_simd_entry_sum: usize,
large_simd_entry_sum: usize,
total_entries: usize,
}
if self.root.is_none() {
println!(" Empty HashMap (no root node)");
println!(" Total entries: 0");
return;
}
let mut level_stats: Vec<LevelStats> = Vec::new();
let mut queue: VecDeque<(usize, SharedPointer<Node<(K, V), P>, P>)> = VecDeque::new();
let mut max_depth = 0;
if let Some(ref root) = self.root {
queue.push_back((0, root.clone()));
}
while let Some((level, node)) = queue.pop_front() {
while level_stats.len() <= level {
level_stats.push(LevelStats::default());
}
let stats = &mut level_stats[level];
stats.node_count += 1;
node.analyze_structure(|entry| {
stats.total_entries += 1;
match entry {
NodeEntry::Value(_, _) => {
stats.value_count += 1;
max_depth = max_depth.max(level);
}
NodeEntry::Collision(_coll) => {
stats.collision_count += 1;
max_depth = max_depth.max(level);
}
NodeEntry::HamtNode(child_node) => {
stats.child_node_count += 1;
queue.push_back((level + 1, child_node.clone()));
}
NodeEntry::SmallSimdNode(small_node) => {
stats.small_simd_node_count += 1;
stats.small_simd_entry_sum += small_node.len();
max_depth = max_depth.max(level + 1);
}
NodeEntry::LargeSimdNode(large_node) => {
stats.large_simd_node_count += 1;
stats.large_simd_entry_sum += large_node.len();
max_depth = max_depth.max(level + 1);
}
}
})
}
println!(
" Hash level size (bits): {}",
crate::config::HASH_LEVEL_SIZE
);
println!(
" Branching factor: {}",
2_usize.pow(crate::config::HASH_LEVEL_SIZE as u32)
);
println!(" Total entries: {}", self.size);
println!(" Tree depth: {} levels", max_depth + 1);
println!();
for (level, stats) in level_stats.iter().enumerate() {
println!(" Level {}:", level);
println!(" Nodes: {}", stats.node_count);
if stats.total_entries > 0 {
let avg_entries = stats.total_entries as f64 / stats.node_count as f64;
println!(" Average entries per node: {:.2}", avg_entries);
println!(" Entry types:");
println!(
" Values: {} ({:.1}%)",
stats.value_count,
(stats.value_count as f64 / stats.total_entries as f64) * 100.0
);
println!(
" Collisions: {} (avg len: {:.1}) ({:.1}%)",
stats.collision_count,
if stats.collision_count > 0 {
stats.collision_entry_sum as f64 / stats.collision_count as f64
} else {
0.0
},
(stats.collision_count as f64 / stats.total_entries as f64) * 100.0
);
println!(
" Child HAMT nodes: {} ({:.1}%)",
stats.child_node_count,
(stats.child_node_count as f64 / stats.total_entries as f64) * 100.0
);
if stats.small_simd_node_count > 0 {
println!(
" Small SIMD leaf nodes: {} ({:.1}%) [total values: {}]",
stats.small_simd_node_count,
(stats.small_simd_node_count as f64 / stats.total_entries as f64) * 100.0,
stats.small_simd_entry_sum
);
println!(
" → Avg values per small SIMD node: {:.1}",
stats.small_simd_entry_sum as f64 / stats.small_simd_node_count as f64
);
}
if stats.large_simd_node_count > 0 {
println!(
" Large SIMD leaf nodes: {} ({:.1}%) [total values: {}]",
stats.large_simd_node_count,
(stats.large_simd_node_count as f64 / stats.total_entries as f64) * 100.0,
stats.large_simd_entry_sum
);
println!(
" → Avg values per large SIMD node: {:.1}",
stats.large_simd_entry_sum as f64 / stats.large_simd_node_count as f64
);
}
}
println!();
}
}
}
impl<K, V, S, P> GenericHashMap<K, V, S, P>
where
K: Hash + Eq,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
fn test_eq<S2: BuildHasher + Clone, P2: SharedPointerKind>(
&self,
other: &GenericHashMap<K, V, S2, P2>,
) -> bool
where
V: PartialEq,
{
if self.len() != other.len() {
return false;
}
let mut seen = collections::HashSet::new();
for (key, value) in self.iter() {
if Some(value) != other.get(key) {
return false;
}
seen.insert(key);
}
for key in other.keys() {
if !seen.contains(&key) {
return false;
}
}
true
}
#[must_use]
pub fn get<BK>(&self, key: &BK) -> Option<&V>
where
BK: Hash + Eq + ?Sized,
K: Borrow<BK>,
{
if let Some(root) = &self.root {
root.get(hash_key(&self.hasher, key), 0, key)
.map(|(_, v)| v)
} else {
None
}
}
#[must_use]
pub fn get_key_value<BK>(&self, key: &BK) -> Option<(&K, &V)>
where
BK: Hash + Eq + ?Sized,
K: Borrow<BK>,
{
if let Some(root) = &self.root {
root.get(hash_key(&self.hasher, key), 0, key)
.map(|(k, v)| (k, v))
} else {
None
}
}
#[inline]
#[must_use]
pub fn contains_key<BK>(&self, k: &BK) -> bool
where
BK: Hash + Eq + ?Sized,
K: Borrow<BK>,
{
self.get(k).is_some()
}
#[must_use]
pub fn is_submap_by<B, RM, F, P2: SharedPointerKind>(&self, other: RM, mut cmp: F) -> bool
where
F: FnMut(&V, &B) -> bool,
RM: Borrow<GenericHashMap<K, B, S, P2>>,
{
self.iter()
.all(|(k, v)| other.borrow().get(k).map(|ov| cmp(v, ov)).unwrap_or(false))
}
#[must_use]
pub fn is_proper_submap_by<B, RM, F, P2: SharedPointerKind>(&self, other: RM, cmp: F) -> bool
where
F: FnMut(&V, &B) -> bool,
RM: Borrow<GenericHashMap<K, B, S, P2>>,
{
self.len() != other.borrow().len() && self.is_submap_by(other, cmp)
}
#[inline]
#[must_use]
pub fn is_submap<RM>(&self, other: RM) -> bool
where
V: PartialEq,
RM: Borrow<Self>,
{
self.is_submap_by(other.borrow(), PartialEq::eq)
}
#[inline]
#[must_use]
pub fn is_proper_submap<RM>(&self, other: RM) -> bool
where
V: PartialEq,
RM: Borrow<Self>,
{
self.is_proper_submap_by(other.borrow(), PartialEq::eq)
}
}
impl<K, V, S, P> GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
#[inline]
#[must_use]
pub fn iter_mut(&mut self) -> IterMut<'_, K, V, P> {
let root = self.root.as_mut().map(|r| SharedPointer::make_mut(r));
IterMut {
it: NodeIterMut::new(root, self.size),
}
}
#[must_use]
pub fn get_mut<BK>(&mut self, key: &BK) -> Option<&mut V>
where
BK: Hash + Eq + ?Sized,
K: Borrow<BK>,
{
self.get_key_value_mut(key).map(|(_, v)| v)
}
#[must_use]
pub fn get_key_value_mut<BK>(&mut self, key: &BK) -> Option<(&K, &mut V)>
where
BK: Hash + Eq + ?Sized,
K: Borrow<BK>,
{
let Some(root) = self.root.as_mut() else {
return None;
};
match SharedPointer::make_mut(root).get_mut(hash_key(&self.hasher, key), 0, key) {
None => None,
Some((key, value)) => Some((key, value)),
}
}
#[inline]
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
let hash = hash_key(&self.hasher, &k);
let root = SharedPointer::make_mut(self.root.get_or_insert_with(SharedPointer::default));
let result = root.insert(hash, 0, (k, v));
if result.is_none() {
self.size += 1;
}
result.map(|(_, v)| v)
}
pub fn remove<BK>(&mut self, k: &BK) -> Option<V>
where
BK: Hash + Eq + ?Sized,
K: Borrow<BK>,
{
self.remove_with_key(k).map(|(_, v)| v)
}
pub fn remove_with_key<BK>(&mut self, k: &BK) -> Option<(K, V)>
where
BK: Hash + Eq + ?Sized,
K: Borrow<BK>,
{
let Some(root) = &mut self.root else {
return None;
};
let result = SharedPointer::make_mut(root).remove(hash_key(&self.hasher, k), 0, k);
if result.is_some() {
self.size -= 1;
}
result
}
#[must_use]
pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S, P> {
let hash = hash_key(&self.hasher, &key);
if self
.root
.as_ref()
.and_then(|r| r.get(hash, 0, &key))
.is_some()
{
Entry::Occupied(OccupiedEntry {
map: self,
hash,
key,
})
} else {
Entry::Vacant(VacantEntry {
map: self,
hash,
key,
})
}
}
#[inline]
#[must_use]
pub fn update(&self, k: K, v: V) -> Self {
let mut out = self.clone();
out.insert(k, v);
out
}
#[must_use]
pub fn update_with<F>(&self, k: K, v: V, f: F) -> Self
where
F: FnOnce(V, V) -> V,
{
match self.extract_with_key(&k) {
None => self.update(k, v),
Some((_, v2, m)) => m.update(k, f(v2, v)),
}
}
#[must_use]
pub fn update_with_key<F>(&self, k: K, v: V, f: F) -> Self
where
F: FnOnce(&K, V, V) -> V,
{
match self.extract_with_key(&k) {
None => self.update(k, v),
Some((_, v2, m)) => {
let out_v = f(&k, v2, v);
m.update(k, out_v)
}
}
}
#[must_use]
pub fn update_lookup_with_key<F>(&self, k: K, v: V, f: F) -> (Option<V>, Self)
where
F: FnOnce(&K, &V, V) -> V,
{
match self.extract_with_key(&k) {
None => (None, self.update(k, v)),
Some((_, v2, m)) => {
let out_v = f(&k, &v2, v);
(Some(v2), m.update(k, out_v))
}
}
}
#[must_use]
pub fn alter<F>(&self, f: F, k: K) -> Self
where
F: FnOnce(Option<V>) -> Option<V>,
{
let pop = self.extract_with_key(&k);
match (f(pop.as_ref().map(|(_, v, _)| v.clone())), pop) {
(None, None) => self.clone(),
(Some(v), None) => self.update(k, v),
(None, Some((_, _, m))) => m,
(Some(v), Some((_, _, m))) => m.update(k, v),
}
}
#[must_use]
pub fn without<BK>(&self, k: &BK) -> Self
where
BK: Hash + Eq + ?Sized,
K: Borrow<BK>,
{
match self.extract_with_key(k) {
None => self.clone(),
Some((_, _, map)) => map,
}
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&K, &V) -> bool,
{
let Some(root) = &mut self.root else {
return;
};
let old_root = root.clone();
let root = SharedPointer::make_mut(root);
for ((key, value), hash) in NodeIter::new(Some(&old_root), self.size) {
if !f(key, value) && root.remove(hash, 0, key).is_some() {
self.size -= 1;
}
}
}
#[must_use]
pub fn extract<BK>(&self, k: &BK) -> Option<(V, Self)>
where
BK: Hash + Eq + ?Sized,
K: Borrow<BK>,
{
self.extract_with_key(k).map(|(_, v, m)| (v, m))
}
#[must_use]
pub fn extract_with_key<BK>(&self, k: &BK) -> Option<(K, V, Self)>
where
BK: Hash + Eq + ?Sized,
K: Borrow<BK>,
{
let mut out = self.clone();
out.remove_with_key(k).map(|(k, v)| (k, v, out))
}
#[must_use]
pub fn union(self, other: Self) -> Self {
let (mut to_mutate, to_consume, use_to_consume) = if self.len() >= other.len() {
(self, other, false)
} else {
(other, self, true)
};
for (k, v) in to_consume {
match to_mutate.entry(k) {
Entry::Occupied(mut e) if use_to_consume => {
e.insert(v);
}
Entry::Vacant(e) => {
e.insert(v);
}
_ => {}
}
}
to_mutate
}
#[inline]
#[must_use]
pub fn union_with<F>(self, other: Self, mut f: F) -> Self
where
F: FnMut(V, V) -> V,
{
self.union_with_key(other, |_, v1, v2| f(v1, v2))
}
#[must_use]
pub fn union_with_key<F>(self, other: Self, mut f: F) -> Self
where
F: FnMut(&K, V, V) -> V,
{
if self.len() >= other.len() {
self.union_with_key_inner(other, f)
} else {
other.union_with_key_inner(self, |key, other_value, self_value| {
f(key, self_value, other_value)
})
}
}
fn union_with_key_inner<F>(mut self, other: Self, mut f: F) -> Self
where
F: FnMut(&K, V, V) -> V,
{
for (key, right_value) in other {
match self.remove(&key) {
None => {
self.insert(key, right_value);
}
Some(left_value) => {
let final_value = f(&key, left_value, right_value);
self.insert(key, final_value);
}
}
}
self
}
#[must_use]
pub fn unions<I>(i: I) -> Self
where
S: Default,
I: IntoIterator<Item = Self>,
{
i.into_iter().fold(Self::default(), Self::union)
}
#[must_use]
pub fn unions_with<I, F>(i: I, f: F) -> Self
where
S: Default,
I: IntoIterator<Item = Self>,
F: Fn(V, V) -> V,
{
i.into_iter()
.fold(Self::default(), |a, b| a.union_with(b, &f))
}
#[must_use]
pub fn unions_with_key<I, F>(i: I, f: F) -> Self
where
S: Default,
I: IntoIterator<Item = Self>,
F: Fn(&K, V, V) -> V,
{
i.into_iter()
.fold(Self::default(), |a, b| a.union_with_key(b, &f))
}
#[deprecated(
since = "2.0.1",
note = "to avoid conflicting behaviors between std and imbl, the `difference` alias for `symmetric_difference` will be removed."
)]
#[inline]
#[must_use]
pub fn difference(self, other: Self) -> Self {
self.symmetric_difference(other)
}
#[inline]
#[must_use]
pub fn symmetric_difference(self, other: Self) -> Self {
self.symmetric_difference_with_key(other, |_, _, _| None)
}
#[deprecated(
since = "2.0.1",
note = "to avoid conflicting behaviors between std and imbl, the `difference_with` alias for `symmetric_difference_with` will be removed."
)]
#[inline]
#[must_use]
pub fn difference_with<F>(self, other: Self, f: F) -> Self
where
F: FnMut(V, V) -> Option<V>,
{
self.symmetric_difference_with(other, f)
}
#[inline]
#[must_use]
pub fn symmetric_difference_with<F>(self, other: Self, mut f: F) -> Self
where
F: FnMut(V, V) -> Option<V>,
{
self.symmetric_difference_with_key(other, |_, a, b| f(a, b))
}
#[deprecated(
since = "2.0.1",
note = "to avoid conflicting behaviors between std and imbl, the `difference_with_key` alias for `symmetric_difference_with_key` will be removed."
)]
#[must_use]
pub fn difference_with_key<F>(self, other: Self, f: F) -> Self
where
F: FnMut(&K, V, V) -> Option<V>,
{
self.symmetric_difference_with_key(other, f)
}
#[must_use]
pub fn symmetric_difference_with_key<F>(mut self, other: Self, mut f: F) -> Self
where
F: FnMut(&K, V, V) -> Option<V>,
{
let mut out = self.new_from();
for (key, right_value) in other {
match self.remove(&key) {
None => {
out.insert(key, right_value);
}
Some(left_value) => {
if let Some(final_value) = f(&key, left_value, right_value) {
out.insert(key, final_value);
}
}
}
}
out.union(self)
}
#[inline]
#[must_use]
pub fn relative_complement(mut self, other: Self) -> Self {
for (key, _) in other {
let _ = self.remove(&key);
}
self
}
#[inline]
#[must_use]
pub fn intersection(self, other: Self) -> Self {
self.intersection_with_key(other, |_, v, _| v)
}
#[inline]
#[must_use]
pub fn intersection_with<B, C, F>(
self,
other: GenericHashMap<K, B, S, P>,
mut f: F,
) -> GenericHashMap<K, C, S, P>
where
B: Clone,
C: Clone,
F: FnMut(V, B) -> C,
{
self.intersection_with_key(other, |_, v1, v2| f(v1, v2))
}
#[must_use]
pub fn intersection_with_key<B, C, F>(
mut self,
other: GenericHashMap<K, B, S, P>,
mut f: F,
) -> GenericHashMap<K, C, S, P>
where
B: Clone,
C: Clone,
F: FnMut(&K, V, B) -> C,
{
let mut out = self.new_from();
for (key, right_value) in other {
match self.remove(&key) {
None => (),
Some(left_value) => {
let result = f(&key, left_value, right_value);
out.insert(key, result);
}
}
}
out
}
}
pub enum Entry<'a, K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
Occupied(OccupiedEntry<'a, K, V, S, P>),
Vacant(VacantEntry<'a, K, V, S, P>),
}
impl<'a, K, V, S, P> Entry<'a, K, V, S, P>
where
K: 'a + Hash + Eq + Clone,
V: 'a + Clone,
S: 'a + BuildHasher + Clone,
P: SharedPointerKind,
{
pub fn or_insert(self, default: V) -> &'a mut V {
self.or_insert_with(|| default)
}
pub fn or_insert_with<F>(self, default: F) -> &'a mut V
where
F: FnOnce() -> V,
{
match self {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => entry.insert(default()),
}
}
pub fn or_default(self) -> &'a mut V
where
V: Default,
{
#[allow(clippy::unwrap_or_default)]
self.or_insert_with(Default::default)
}
#[must_use]
pub fn key(&self) -> &K {
match self {
Entry::Occupied(entry) => entry.key(),
Entry::Vacant(entry) => entry.key(),
}
}
pub fn and_modify<F>(mut self, f: F) -> Self
where
F: FnOnce(&mut V),
{
match &mut self {
Entry::Occupied(ref mut entry) => f(entry.get_mut()),
Entry::Vacant(_) => (),
}
self
}
}
pub struct OccupiedEntry<'a, K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
map: &'a mut GenericHashMap<K, V, S, P>,
hash: HashBits,
key: K,
}
impl<'a, K, V, S, P> OccupiedEntry<'a, K, V, S, P>
where
K: 'a + Hash + Eq + Clone,
V: 'a + Clone,
S: 'a + BuildHasher + Clone,
P: SharedPointerKind,
{
#[must_use]
pub fn key(&self) -> &K {
&self.key
}
pub fn remove_entry(self) -> (K, V) {
let root = SharedPointer::make_mut(self.map.root.as_mut().unwrap());
let result = root.remove(self.hash, 0, &self.key);
self.map.size -= 1;
result.unwrap()
}
#[must_use]
pub fn get(&self) -> &V {
&self
.map
.root
.as_ref()
.unwrap()
.get(self.hash, 0, &self.key)
.unwrap()
.1
}
#[must_use]
pub fn get_mut(&mut self) -> &mut V {
let root = SharedPointer::make_mut(self.map.root.as_mut().unwrap());
&mut root.get_mut(self.hash, 0, &self.key).unwrap().1
}
#[must_use]
pub fn into_mut(self) -> &'a mut V {
let root = SharedPointer::make_mut(self.map.root.as_mut().unwrap());
&mut root.get_mut(self.hash, 0, &self.key).unwrap().1
}
pub fn insert(&mut self, value: V) -> V {
mem::replace(self.get_mut(), value)
}
pub fn remove(self) -> V {
self.remove_entry().1
}
}
pub struct VacantEntry<'a, K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
map: &'a mut GenericHashMap<K, V, S, P>,
hash: HashBits,
key: K,
}
impl<'a, K, V, S, P> VacantEntry<'a, K, V, S, P>
where
K: 'a + Hash + Eq + Clone,
V: 'a + Clone,
S: 'a + BuildHasher + Clone,
P: SharedPointerKind,
{
#[must_use]
pub fn key(&self) -> &K {
&self.key
}
#[must_use]
pub fn into_key(self) -> K {
self.key
}
pub fn insert(self, value: V) -> &'a mut V {
let root =
SharedPointer::make_mut(self.map.root.get_or_insert_with(SharedPointer::default));
if root
.insert(self.hash, 0, (self.key.clone(), value))
.is_none()
{
self.map.size += 1;
}
&mut root.get_mut(self.hash, 0, &self.key).unwrap().1
}
}
impl<K, V, S, P> Clone for GenericHashMap<K, V, S, P>
where
K: Clone,
V: Clone,
S: Clone,
P: SharedPointerKind,
{
#[inline]
fn clone(&self) -> Self {
GenericHashMap {
root: self.root.clone(),
size: self.size,
hasher: self.hasher.clone(),
}
}
}
impl<K, V, S1, S2, P1, P2> PartialEq<GenericHashMap<K, V, S2, P2>> for GenericHashMap<K, V, S1, P1>
where
K: Hash + Eq,
V: PartialEq,
S1: BuildHasher + Clone,
S2: BuildHasher + Clone,
P1: SharedPointerKind,
P2: SharedPointerKind,
{
fn eq(&self, other: &GenericHashMap<K, V, S2, P2>) -> bool {
self.test_eq(other)
}
}
impl<K, V, S, P> Eq for GenericHashMap<K, V, S, P>
where
K: Hash + Eq,
V: Eq,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
}
impl<K, V, S, P> Default for GenericHashMap<K, V, S, P>
where
S: Default,
P: SharedPointerKind,
{
#[inline]
fn default() -> Self {
GenericHashMap {
size: 0,
root: None,
hasher: Default::default(),
}
}
}
impl<K, V, S, P> Add for GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
type Output = GenericHashMap<K, V, S, P>;
fn add(self, other: Self) -> Self::Output {
self.union(other)
}
}
impl<K, V, S, P> Add for &GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
type Output = GenericHashMap<K, V, S, P>;
fn add(self, other: Self) -> Self::Output {
self.clone().union(other.clone())
}
}
impl<K, V, S, P> Sum for GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn sum<I>(it: I) -> Self
where
I: Iterator<Item = Self>,
{
it.fold(Self::default(), |a, b| a + b)
}
}
impl<K, V, S, RK, RV, P> Extend<(RK, RV)> for GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone + From<RK>,
V: Clone + From<RV>,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (RK, RV)>,
{
for (key, value) in iter {
self.insert(From::from(key), From::from(value));
}
}
}
impl<BK, K, V, S, P> Index<&BK> for GenericHashMap<K, V, S, P>
where
BK: Hash + Eq + ?Sized,
K: Hash + Eq + Borrow<BK>,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
type Output = V;
fn index(&self, key: &BK) -> &Self::Output {
match self.get(key) {
None => panic!("HashMap::index: invalid key"),
Some(value) => value,
}
}
}
impl<BK, K, V, S, P> IndexMut<&BK> for GenericHashMap<K, V, S, P>
where
BK: Hash + Eq + ?Sized,
K: Hash + Eq + Clone + Borrow<BK>,
V: Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
fn index_mut(&mut self, key: &BK) -> &mut Self::Output {
match self.get_mut(key) {
None => panic!("HashMap::index_mut: invalid key"),
Some(value) => value,
}
}
}
impl<K, V, S, P> Debug for GenericHashMap<K, V, S, P>
where
K: Debug,
V: Debug,
P: SharedPointerKind,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
let mut d = f.debug_map();
for (k, v) in self {
d.entry(k, v);
}
d.finish()
}
}
pub struct Iter<'a, K, V, P: SharedPointerKind> {
it: NodeIter<'a, (K, V), P>,
}
impl<'a, K, V, P: SharedPointerKind> Clone for Iter<'a, K, V, P> {
fn clone(&self) -> Self {
Iter {
it: self.it.clone(),
}
}
}
impl<'a, K, V, P: SharedPointerKind> Iterator for Iter<'a, K, V, P> {
type Item = (&'a K, &'a V);
fn next(&mut self) -> Option<Self::Item> {
self.it.next().map(|((k, v), _)| (k, v))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
}
impl<'a, K, V, P: SharedPointerKind> ExactSizeIterator for Iter<'a, K, V, P> {}
impl<'a, K, V, P: SharedPointerKind> FusedIterator for Iter<'a, K, V, P> {}
pub struct IterMut<'a, K, V, P>
where
K: Clone,
V: Clone,
P: SharedPointerKind,
{
it: NodeIterMut<'a, (K, V), P>,
}
impl<'a, K, V, P> Iterator for IterMut<'a, K, V, P>
where
K: Clone,
V: Clone,
P: SharedPointerKind,
{
type Item = (&'a K, &'a mut V);
fn next(&mut self) -> Option<Self::Item> {
self.it.next().map(|((k, v), _)| (&*k, v))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
}
impl<'a, K, V, P> ExactSizeIterator for IterMut<'a, K, V, P>
where
K: Clone,
V: Clone,
P: SharedPointerKind,
{
}
impl<'a, K, V, P> FusedIterator for IterMut<'a, K, V, P>
where
K: Clone,
V: Clone,
P: SharedPointerKind,
{
}
pub struct ConsumingIter<A: HashValue, P: SharedPointerKind> {
it: NodeDrain<A, P>,
}
impl<A, P: SharedPointerKind> Iterator for ConsumingIter<A, P>
where
A: HashValue + Clone,
{
type Item = A;
fn next(&mut self) -> Option<Self::Item> {
self.it.next().map(|(p, _)| p)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
}
impl<A, P> ExactSizeIterator for ConsumingIter<A, P>
where
A: HashValue + Clone,
P: SharedPointerKind,
{
}
impl<A, P> FusedIterator for ConsumingIter<A, P>
where
A: HashValue + Clone,
P: SharedPointerKind,
{
}
pub struct Keys<'a, K, V, P: SharedPointerKind> {
it: NodeIter<'a, (K, V), P>,
}
impl<'a, K, V, P: SharedPointerKind> Iterator for Keys<'a, K, V, P> {
type Item = &'a K;
fn next(&mut self) -> Option<Self::Item> {
self.it.next().map(|((k, _), _)| k)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
}
impl<'a, K, V, P: SharedPointerKind> ExactSizeIterator for Keys<'a, K, V, P> {}
impl<'a, K, V, P: SharedPointerKind> FusedIterator for Keys<'a, K, V, P> {}
pub struct Values<'a, K, V, P: SharedPointerKind> {
it: NodeIter<'a, (K, V), P>,
}
impl<'a, K, V, P: SharedPointerKind> Iterator for Values<'a, K, V, P> {
type Item = &'a V;
fn next(&mut self) -> Option<Self::Item> {
self.it.next().map(|((_, v), _)| v)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
}
impl<'a, K, V, P: SharedPointerKind> ExactSizeIterator for Values<'a, K, V, P> {}
impl<'a, K, V, P: SharedPointerKind> FusedIterator for Values<'a, K, V, P> {}
impl<'a, K, V, S, P: SharedPointerKind> IntoIterator for &'a GenericHashMap<K, V, S, P> {
type Item = (&'a K, &'a V);
type IntoIter = Iter<'a, K, V, P>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<K, V, S, P> IntoIterator for GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Clone,
P: SharedPointerKind,
{
type Item = (K, V);
type IntoIter = ConsumingIter<(K, V), P>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
ConsumingIter {
it: NodeDrain::new(self.root, self.size),
}
}
}
impl<K, V, S, P> FromIterator<(K, V)> for GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from_iter<T>(i: T) -> Self
where
T: IntoIterator<Item = (K, V)>,
{
let mut map = Self::default();
for (k, v) in i {
map.insert(k, v);
}
map
}
}
impl<K, V, S, P: SharedPointerKind> AsRef<GenericHashMap<K, V, S, P>>
for GenericHashMap<K, V, S, P>
{
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl<K, V, OK, OV, SA, SB, P1, P2> From<&GenericHashMap<&K, &V, SA, P1>>
for GenericHashMap<OK, OV, SB, P2>
where
K: Hash + Eq + ToOwned<Owned = OK> + ?Sized,
V: ToOwned<Owned = OV> + ?Sized,
OK: Hash + Eq + Clone + Borrow<K>,
OV: Borrow<V> + Clone,
SA: BuildHasher + Clone,
SB: BuildHasher + Default + Clone,
P1: SharedPointerKind,
P2: SharedPointerKind,
{
fn from(m: &GenericHashMap<&K, &V, SA, P1>) -> Self {
m.iter()
.map(|(k, v)| ((*k).to_owned(), (*v).to_owned()))
.collect()
}
}
impl<'a, K, V, S, P> From<&'a [(K, V)]> for GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(m: &'a [(K, V)]) -> Self {
m.iter().cloned().collect()
}
}
impl<K, V, S, P> From<Vec<(K, V)>> for GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(m: Vec<(K, V)>) -> Self {
m.into_iter().collect()
}
}
impl<'a, K, V, S, P> From<&'a Vec<(K, V)>> for GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(m: &'a Vec<(K, V)>) -> Self {
m.iter().cloned().collect()
}
}
impl<K, V, S1, S2, P> From<collections::HashMap<K, V, S2>> for GenericHashMap<K, V, S1, P>
where
K: Hash + Eq + Clone,
V: Clone,
S1: BuildHasher + Default + Clone,
S2: BuildHasher,
P: SharedPointerKind,
{
fn from(m: collections::HashMap<K, V, S2>) -> Self {
m.into_iter().collect()
}
}
impl<'a, K, V, S1, S2, P> From<&'a collections::HashMap<K, V, S2>> for GenericHashMap<K, V, S1, P>
where
K: Hash + Eq + Clone,
V: Clone,
S1: BuildHasher + Default + Clone,
S2: BuildHasher,
P: SharedPointerKind,
{
fn from(m: &'a collections::HashMap<K, V, S2>) -> Self {
m.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
}
}
impl<K, V, S, P> From<collections::BTreeMap<K, V>> for GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(m: collections::BTreeMap<K, V>) -> Self {
m.into_iter().collect()
}
}
impl<'a, K, V, S, P> From<&'a collections::BTreeMap<K, V>> for GenericHashMap<K, V, S, P>
where
K: Hash + Eq + Clone,
V: Clone,
S: BuildHasher + Default + Clone,
P: SharedPointerKind,
{
fn from(m: &'a collections::BTreeMap<K, V>) -> Self {
m.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
}
}
#[cfg(any(test, feature = "proptest"))]
#[doc(hidden)]
pub mod proptest {
#[deprecated(
since = "14.3.0",
note = "proptest strategies have moved to imbl::proptest"
)]
pub use crate::proptest::hash_map;
}
#[cfg(test)]
mod test {
use super::*;
use crate::test::LolHasher;
#[rustfmt::skip]
use ::proptest::{collection, num::{i16, usize}, proptest};
use static_assertions::{assert_impl_all, assert_not_impl_any};
use std::hash::BuildHasherDefault;
assert_impl_all!(HashMap<i32, i32>: Send, Sync);
assert_not_impl_any!(HashMap<i32, *const i32>: Send, Sync);
assert_not_impl_any!(HashMap<*const i32, i32>: Send, Sync);
assert_covariant!(HashMap<T, i32> in T);
assert_covariant!(HashMap<i32, T> in T);
#[test]
fn safe_mutation() {
let v1: HashMap<usize, usize> = GenericHashMap::from_iter((0..131_072).map(|i| (i, i)));
let mut v2 = v1.clone();
v2.insert(131_000, 23);
assert_eq!(Some(&23), v2.get(&131_000));
assert_eq!(Some(&131_000), v1.get(&131_000));
}
#[test]
fn index_operator() {
let mut map: HashMap<usize, usize> = hashmap![1 => 2, 3 => 4, 5 => 6];
assert_eq!(4, map[&3]);
map[&3] = 8;
let target_map: HashMap<usize, usize> = hashmap![1 => 2, 3 => 8, 5 => 6];
assert_eq!(target_map, map);
}
#[test]
fn proper_formatting() {
let map: HashMap<usize, usize> = hashmap![1 => 2];
assert_eq!("{1: 2}", format!("{:?}", map));
assert_eq!("{}", format!("{:?}", HashMap::<(), ()>::new()));
}
#[test]
fn remove_failing() {
let pairs = [(1469, 0), (-67, 0)];
let mut m: collections::HashMap<i16, i16, _> =
collections::HashMap::with_hasher(BuildHasherDefault::<LolHasher>::default());
for (k, v) in &pairs {
m.insert(*k, *v);
}
let mut map: GenericHashMap<i16, i16, _, DefaultSharedPtr> =
GenericHashMap::with_hasher(BuildHasherDefault::<LolHasher>::default());
for (k, v) in &m {
map = map.update(*k, *v);
}
for k in m.keys() {
let l = map.len();
assert_eq!(m.get(k).cloned(), map.get(k).cloned());
map = map.without(k);
assert_eq!(None, map.get(k));
assert_eq!(l - 1, map.len());
}
}
#[test]
fn match_string_keys_with_string_slices() {
let tmp_map: HashMap<&str, &i32> = hashmap! { "foo" => &1, "bar" => &2, "baz" => &3 };
let mut map: HashMap<String, i32> = From::from(&tmp_map);
assert_eq!(Some(&1), map.get("foo"));
map = map.without("foo");
assert_eq!(Some(3), map.remove("baz"));
map["bar"] = 8;
assert_eq!(8, map["bar"]);
}
#[test]
fn macro_allows_trailing_comma() {
let map1: HashMap<&str, i32> = hashmap! {"x" => 1, "y" => 2};
let map2: HashMap<&str, i32> = hashmap! {
"x" => 1,
"y" => 2,
};
assert_eq!(map1, map2);
}
#[test]
fn remove_top_level_collisions() {
let pairs = vec![9, 2569, 27145];
let mut map: GenericHashMap<i16, i16, BuildHasherDefault<LolHasher>, DefaultSharedPtr> =
Default::default();
for k in pairs.clone() {
map.insert(k, k);
}
assert_eq!(pairs.len(), map.len());
let keys: Vec<_> = map.keys().cloned().collect();
for k in keys {
let l = map.len();
assert_eq!(Some(&k), map.get(&k));
map.remove(&k);
assert_eq!(None, map.get(&k));
assert_eq!(l - 1, map.len());
}
}
#[test]
fn entry_api() {
let mut map: HashMap<&str, i32> = hashmap! {"bar" => 5};
map.entry("foo").and_modify(|v| *v += 5).or_insert(1);
assert_eq!(1, map[&"foo"]);
map.entry("foo").and_modify(|v| *v += 5).or_insert(1);
assert_eq!(6, map[&"foo"]);
map.entry("bar").and_modify(|v| *v += 5).or_insert(1);
assert_eq!(10, map[&"bar"]);
assert_eq!(
10,
match map.entry("bar") {
Entry::Occupied(entry) => entry.remove(),
_ => panic!(),
}
);
assert!(!map.contains_key(&"bar"));
}
#[test]
fn refpool_crash() {
let _map = HashMap::<u128, usize>::new();
}
#[test]
fn large_map() {
let mut map = HashMap::<_, _>::new();
let size = 32769;
for i in 0..size {
map.insert(i, i);
}
assert_eq!(size, map.len());
for i in 0..size {
assert_eq!(Some(&i), map.get(&i));
}
}
struct PanicOnClone;
impl Clone for PanicOnClone {
fn clone(&self) -> Self {
panic!("PanicOnClone::clone called")
}
}
#[test]
fn into_iter_no_clone() {
let mut map = HashMap::new();
for i in 0..10_000 {
map.insert(i, PanicOnClone);
}
let _ = map.into_iter().collect::<Vec<_>>();
}
#[test]
fn iter_mut_no_clone() {
let mut map = HashMap::new();
for i in 0..10_000 {
map.insert(i, PanicOnClone);
}
let _ = map.iter_mut().collect::<Vec<_>>();
}
#[test]
fn iter_no_clone() {
let mut map = HashMap::new();
for i in 0..10_000 {
map.insert(i, PanicOnClone);
}
let _ = map.iter().collect::<Vec<_>>();
}
proptest! {
#[test]
fn update_and_length(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) {
let mut map: GenericHashMap<i16, i16, BuildHasherDefault<LolHasher>, DefaultSharedPtr> = Default::default();
for (index, (k, v)) in m.iter().enumerate() {
map = map.update(*k, *v);
assert_eq!(Some(v), map.get(k));
assert_eq!(index + 1, map.len());
}
}
#[test]
fn from_iterator(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) {
let map: HashMap<i16, i16> =
FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v)));
assert_eq!(m.len(), map.len());
}
#[test]
fn iterate_over(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) {
let map: HashMap<i16, i16> = FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v)));
assert_eq!(m.len(), map.iter().count());
}
#[test]
fn equality(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) {
let map1: HashMap<i16, i16> = FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v)));
let map2: HashMap<i16, i16> = FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v)));
assert_eq!(map1, map2);
}
#[test]
fn lookup(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) {
let map: HashMap<i16, i16> = FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v)));
for (k, v) in m {
assert_eq!(Some(*v), map.get(k).cloned(), "{k} not found in map {map:?}");
}
}
#[test]
fn without(ref pairs in collection::vec((i16::ANY, i16::ANY), 0..100)) {
let mut m: collections::HashMap<i16, i16, _> =
collections::HashMap::with_hasher(BuildHasherDefault::<LolHasher>::default());
for (k, v) in pairs {
m.insert(*k, *v);
}
let mut map: GenericHashMap<i16, i16, _, DefaultSharedPtr> = GenericHashMap::with_hasher(BuildHasherDefault::<LolHasher>::default());
for (k, v) in &m {
map = map.update(*k, *v);
}
for k in m.keys() {
let l = map.len();
assert_eq!(m.get(k).cloned(), map.get(k).cloned());
map = map.without(k);
assert_eq!(None, map.get(k));
assert_eq!(l - 1, map.len());
}
}
#[test]
fn insert(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) {
let mut mut_map: GenericHashMap<i16, i16, BuildHasherDefault<LolHasher>, DefaultSharedPtr> = Default::default();
let mut map: GenericHashMap<i16, i16, BuildHasherDefault<LolHasher>, DefaultSharedPtr> = Default::default();
for (count, (k, v)) in m.iter().enumerate() {
map = map.update(*k, *v);
mut_map.insert(*k, *v);
assert_eq!(count + 1, map.len());
assert_eq!(count + 1, mut_map.len());
}
for (k, v) in m {
assert_eq!(Some(v), map.get(k));
assert_eq!(Some(v), mut_map.get(k));
}
assert_eq!(map, mut_map);
}
#[test]
fn remove(ref pairs in collection::vec((i16::ANY, i16::ANY), 0..100)) {
let mut m: collections::HashMap<i16, i16, _> =
collections::HashMap::with_hasher(BuildHasherDefault::<LolHasher>::default());
for (k, v) in pairs {
m.insert(*k, *v);
}
let mut map: GenericHashMap<i16, i16, _, DefaultSharedPtr> = GenericHashMap::with_hasher(BuildHasherDefault::<LolHasher>::default());
for (k, v) in &m {
map.insert(*k, *v);
}
for k in m.keys() {
let l = map.len();
assert_eq!(m.get(k).cloned(), map.get(k).cloned());
map.remove(k);
assert_eq!(None, map.get(k));
assert_eq!(l - 1, map.len());
}
}
#[test]
fn delete_and_reinsert(
ref input in collection::hash_map(i16::ANY, i16::ANY, 1..1000),
index_rand in usize::ANY
) {
let index = *input.keys().nth(index_rand % input.len()).unwrap();
let map1: HashMap<_, _> = HashMap::from_iter(input.clone());
let (val, map2) = map1.extract(&index).unwrap();
let map3 = map2.update(index, val);
for key in map2.keys() {
assert!(*key != index);
}
assert_eq!(map1.len(), map2.len() + 1);
assert_eq!(map1, map3);
}
#[test]
fn proptest_works(ref m in proptest::hash_map(0..9999, ".*", 10..100)) {
assert!(m.len() < 100);
assert!(m.len() >= 10);
}
#[test]
fn exact_size_iterator(ref m in proptest::hash_map(i16::ANY, i16::ANY, 0..100)) {
let mut should_be = m.len();
let mut it = m.iter();
loop {
assert_eq!(should_be, it.len());
match it.next() {
None => break,
Some(_) => should_be -= 1,
}
}
assert_eq!(0, it.len());
}
#[test]
fn union(ref m1 in collection::hash_map(i16::ANY, i16::ANY, 0..100),
ref m2 in collection::hash_map(i16::ANY, i16::ANY, 0..100)) {
let map1: HashMap<i16, i16> = FromIterator::from_iter(m1.iter().map(|(k, v)| (*k, *v)));
let map2: HashMap<i16, i16> = FromIterator::from_iter(m2.iter().map(|(k, v)| (*k, *v)));
let union_map = map1.union(map2);
for k in m1.keys() {
assert!(union_map.contains_key(k));
}
for k in m2.keys() {
assert!(union_map.contains_key(k));
}
for (k, v) in union_map.iter() {
assert_eq!(v, m1.get(k).or_else(|| m2.get(k)).unwrap());
}
}
}
#[test]
fn test_structure_summary() {
let sizes = vec![10, 100, 1_000, 10_000, 100_000];
for size in sizes {
println!("\n=== Testing with {} entries ===", size);
let mut map = HashMap::new();
for i in 0..size {
map.insert(i, i * 2);
}
map.print_structure_summary();
}
}
}