use crate::{
hashiter::{Iter, IterMut, OwnedIter},
make_hash,
util::{allocate, deallocate, round_to_pow2, AllocationKind},
Value,
};
use core::{
borrow::Borrow,
default::Default,
hash::{BuildHasher, BuildHasherDefault, Hash},
};
#[cfg(feature = "stable_alloc")]
use allocator_api2::alloc::{Allocator, Global};
#[cfg(not(feature = "stable_alloc"))]
use core::alloc::Allocator;
#[cfg(not(feature = "stable_alloc"))]
use std::alloc::Global;
pub use crate::hashentry::{Entry, OccupiedEntry, VacantEntry};
pub(crate) type DefaultHash = std::collections::hash_map::DefaultHasher;
pub struct HashMap<K, V, H = BuildHasherDefault<DefaultHash>, A: Allocator = Global> {
table: *mut Table<K, V>,
hash_builder: H,
allocator: A,
size: usize,
}
impl<'a, K, V, H, A: Allocator> HashMap<K, V, H, A> {
pub fn capacity(&self) -> usize {
self.get_table().size()
}
fn get_table(&self) -> &'a Table<K, V> {
unsafe { &*self.table }
}
fn get_table_mut(&self) -> &'a mut Table<K, V> {
unsafe { &mut *self.table }
}
fn is_allocated(&self) -> bool {
!self.table.is_null()
}
}
impl<K, V> HashMap<K, V, BuildHasherDefault<DefaultHash>, Global>
where
K: Eq + Hash + Clone,
V: Value,
{
pub fn new() -> HashMap<K, V, BuildHasherDefault<DefaultHash>, Global> {
Self::new_in(Global)
}
pub fn with_capacity(
capacity: usize,
) -> HashMap<K, V, BuildHasherDefault<DefaultHash>, Global> {
Self::with_capacity_and_hasher_in(
capacity,
BuildHasherDefault::<DefaultHash>::default(),
Global,
)
}
}
impl<K, V, H> HashMap<K, V, H, Global>
where
K: Eq + Hash + Clone,
V: Value,
H: BuildHasher + Default,
{
pub fn with_capacity_and_hasher(capacity: usize, builder: H) -> HashMap<K, V, H, Global> {
Self::with_capacity_and_hasher_in(capacity, builder, Global)
}
}
impl<'a, K, V, H, A> HashMap<K, V, H, A>
where
K: Eq + Hash + Clone + 'a,
V: Value + 'a,
H: BuildHasher + Default,
A: Allocator,
{
const INITIAL_SIZE: usize = 8;
const LINEAR_SEARCH_LIMIT: usize = 128;
const CELLS_IN_USE: usize = Self::LINEAR_SEARCH_LIMIT >> 1;
pub fn new_in(allocator: A) -> HashMap<K, V, H, A> {
Self::with_capacity_and_hasher_in(Self::INITIAL_SIZE, H::default(), allocator)
}
pub fn with_capacity_and_hasher_in(
capacity: usize,
builder: H,
allocator: A,
) -> HashMap<K, V, H, A> {
let capacity = round_to_pow2(capacity.max(Self::INITIAL_SIZE));
let table = Self::allocate_and_init_table(&allocator, capacity);
HashMap {
table,
hash_builder: builder,
allocator,
size: 0,
}
}
pub fn hash_usize<Q>(&self, key: &Q) -> usize
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
make_hash::<Q, H>(&self.hash_builder, key) as usize
}
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
let hash = self.hash_builder.hash_one(&key);
debug_assert!(hash != null_hash());
loop {
let size_mask = self.get_table().size_mask;
let buckets = self.get_table_mut().bucket_slice_mut();
match Self::insert_or_find(hash, &key, value, buckets, size_mask) {
InsertResult::Overflow(overflow_index) => {
self.move_to_new_buckets(overflow_index);
}
InsertResult::Found(old_value) => {
return Some(old_value);
}
InsertResult::NewInsert => {
self.size += 1;
return None;
}
}
}
}
pub fn get<Q>(&'a self, key: &Q) -> Option<&'a V>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.find(make_hash::<Q, H>(&self.hash_builder, key), key)
.and_then(|(_k, v)| if v.is_null() { None } else { Some(v) })
}
pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&'a mut V>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
let table = self.get_table_mut();
let size_mask = table.size_mask;
let buckets = table.bucket_slice_mut();
let hash = make_hash::<Q, H>(&self.hash_builder, key);
Self::find_mut(buckets, hash, key, size_mask).and_then(|old| {
if old.is_null() {
None
} else {
Some(old)
}
})
}
pub fn get_key_value<Q>(&self, key: &Q) -> Option<(&K, &V)>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.find(make_hash::<Q, H>(&self.hash_builder, key), key)
}
pub fn entry(&mut self, key: K) -> Entry<'_, K, V, H, A> {
if let Some(v_ref) = self.get_mut(&key) {
Entry::Occupied(OccupiedEntry {
map: self,
key,
value: v_ref,
})
} else {
Entry::Vacant(VacantEntry { map: self, key })
}
}
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.get(key).is_some()
}
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
if let Some(v) = self.get_mut(key) {
let old_value = *v;
if old_value.is_null() {
return None;
}
*v = V::null();
self.size -= 1;
Some(old_value)
} else {
None
}
}
pub fn iter(&'a self) -> Iter<'a, K, V, H, A> {
Iter::new(self)
}
pub fn iter_mut(&'a mut self) -> IterMut<'a, K, V, H, A> {
IterMut::new(self)
}
pub fn len(&self) -> usize {
self.size
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
fn insert_or_find(
hash: HashedKey,
key: &K,
value: V,
buckets: &mut [Bucket<K, V>],
size_mask: usize,
) -> InsertResult<V> {
let mut index = hash as usize;
{
let cell = Self::get_cell_mut(buckets, index, size_mask);
if cell.hash == hash && cell.key == *key {
let old_value = cell.value;
cell.value = value;
return InsertResult::Found(old_value);
} else if cell.hash == null_hash() {
cell.key = key.clone();
cell.hash = hash;
cell.value = value;
return InsertResult::NewInsert;
}
}
let mut delta = Self::get_first_delta(buckets, index, size_mask);
let first_delta = delta == 0;
while delta != 0 {
index += delta as usize;
delta = Self::get_second_delta(buckets, index, size_mask);
let cell = Self::get_cell_mut(buckets, index, size_mask);
if hash == cell.hash && cell.key == *key {
let old_value = cell.value;
cell.value = value;
return InsertResult::Found(old_value);
}
}
let max_index = index + size_mask;
debug_assert!(max_index as i64 - index as i64 >= 0);
let prev_link_index = index;
let mut probes_remaining = Self::LINEAR_SEARCH_LIMIT.min(max_index - index);
while probes_remaining > 0 {
index += 1;
let cell = Self::get_cell_mut(buckets, index, size_mask);
if cell.hash == null_hash() {
cell.hash = hash;
cell.key = key.clone();
cell.value = value;
let offset = (index - prev_link_index) as u8;
if first_delta {
*Self::get_first_delta_mut(buckets, prev_link_index, size_mask) = offset;
} else {
*Self::get_second_delta_mut(buckets, prev_link_index, size_mask) = offset;
}
return InsertResult::NewInsert;
}
debug_assert!(cell.key != *key);
probes_remaining -= 1;
}
InsertResult::Overflow(index + 1)
}
fn find<Q: ?Sized + Eq>(&self, hash: HashedKey, key: &Q) -> Option<(&K, &V)>
where
K: Borrow<Q>,
{
debug_assert!(hash != null_hash());
let buckets = self.get_table().bucket_slice();
let size_mask = self.get_table().size_mask;
let mut index = hash as usize;
let cell = Self::get_cell(buckets, index, size_mask);
if cell.hash == hash && key.eq(cell.key.borrow()) {
return Some((&cell.key, &cell.value));
}
let mut delta = Self::get_first_delta(buckets, index, size_mask);
while delta != 0 {
index += delta as usize;
let cell = Self::get_cell(buckets, index, size_mask);
if cell.hash == hash && key.eq(cell.key.borrow()) {
return Some((&cell.key, &cell.value));
}
delta = Self::get_second_delta(buckets, index, size_mask);
}
None
}
fn find_mut<Q: ?Sized + Eq>(
buckets: &'a mut [Bucket<K, V>],
hash: HashedKey,
key: &Q,
size_mask: usize,
) -> Option<&'a mut V>
where
K: Borrow<Q>,
{
debug_assert!(hash != null_hash());
let mut index = hash as usize;
let mut delta = 0u8;
let mut found = false;
let cell = Self::get_cell(buckets, index, size_mask);
if cell.hash == hash && key.eq(cell.key.borrow()) {
found = true;
} else {
delta = Self::get_first_delta(buckets, index, size_mask);
}
while !found && delta != 0 {
index += delta as usize;
let cell = Self::get_cell(buckets, index, size_mask);
if cell.hash == hash && key.eq(cell.key.borrow()) {
found = true;
break;
}
delta = Self::get_second_delta(buckets, index, size_mask);
}
if found {
Some(&mut Self::get_cell_mut(buckets, index, size_mask).value)
} else {
None
}
}
fn move_to_new_buckets(&mut self, overflow_index: usize) {
let mut index = overflow_index - Self::CELLS_IN_USE;
let mut cells_in_use = 0;
let buckets = self.get_table().bucket_slice();
let size_mask = self.get_table().size_mask;
for _ in 0..Self::CELLS_IN_USE {
let cell = Self::get_cell(buckets, index, size_mask);
if !cell.value.is_null() {
cells_in_use += 1;
}
index += 1;
}
let ratio = cells_in_use as f32 / Self::CELLS_IN_USE as f32;
let in_use_estimated = (size_mask + 1) as f32 * ratio;
let estimated = round_to_pow2((in_use_estimated * 2.0) as usize);
let mut new_table_size = estimated.max(Self::INITIAL_SIZE);
loop {
if self.try_move_to_new_buckets(new_table_size) {
return; }
new_table_size *= 2;
}
}
fn try_move_to_new_buckets(&mut self, size: usize) -> bool {
let source_buckets = self.get_table().bucket_slice();
let source_size_mask = self.get_table().size_mask;
let source_size = source_size_mask + 1;
let dst_table_ptr = Self::allocate_and_init_table(&self.allocator, size);
let dst_table = unsafe { &mut *dst_table_ptr };
let dst_size_mask = dst_table.size_mask;
let dst_buckets = dst_table.bucket_slice_mut();
for source_index in 0..source_size {
let cell = Self::get_cell(source_buckets, source_index, source_size_mask);
if !cell.value.is_null() {
match Self::insert_or_find(
cell.hash,
&cell.key,
cell.value,
dst_buckets,
dst_size_mask,
) {
InsertResult::Overflow(_) => {
Self::deallocate_table(&self.allocator, dst_table_ptr);
return false;
}
InsertResult::Found(_) => {
debug_assert!(false);
}
InsertResult::NewInsert => {
}
}
}
}
Self::deallocate_table(&self.allocator, self.table);
self.table = dst_table_ptr;
true
}
fn allocate_and_init_table(allocator: &A, cells: usize) -> *mut Table<K, V> {
assert!(cells >= 4 && (cells % 2 == 0));
let bucket_count = cells >> 2;
let bucket_ptr =
allocate::<Bucket<K, V>, A>(allocator, bucket_count, AllocationKind::Uninitialized);
let buckets = unsafe { std::slice::from_raw_parts_mut(bucket_ptr, bucket_count) };
for bucket in buckets.iter_mut().take(bucket_count) {
unsafe {
let bucket_deltas = &mut bucket.deltas as *mut u8;
std::ptr::write_bytes(bucket_deltas, 0, 8);
};
for cell in 0..4 {
unsafe {
let cell_hash: *mut HashedKey = &mut bucket.cells[cell].hash;
std::ptr::write_bytes(cell_hash, 0, 1);
};
let cell_value = &mut bucket.cells[cell].value;
*cell_value = V::null();
}
}
let table_ptr = allocate::<Table<K, V>, A>(allocator, 1, AllocationKind::Uninitialized);
let table = unsafe { &mut *table_ptr };
table.buckets = bucket_ptr;
table.size_mask = cells - 1;
table_ptr
}
fn deallocate_table(allocator: &A, table_ptr: *mut Table<K, V>) {
let table = unsafe { &mut *table_ptr };
let bucket_ptr = table.buckets;
let bucket_count = table.size() >> 2;
deallocate::<Bucket<K, V>, A>(allocator, bucket_ptr, bucket_count);
deallocate::<Table<K, V>, A>(allocator, table_ptr, 1);
}
pub(crate) fn get_cell_at_index(&self, index: usize) -> Option<&Cell<K, V>> {
let table = self.get_table();
if index >= table.size() {
return None;
}
let buckets = table.bucket_slice();
Some(Self::get_cell(buckets, index, table.size_mask))
}
pub(crate) fn get_cell_at_index_mut(&self, index: usize) -> Option<&'a mut Cell<K, V>> {
let table = self.get_table_mut();
if index >= table.size() {
return None;
}
let size_mask = table.size_mask;
let buckets = table.bucket_slice_mut();
Some(Self::get_cell_mut(buckets, index, size_mask))
}
#[inline]
fn get_cell(buckets: &[Bucket<K, V>], index: usize, size_mask: usize) -> &Cell<K, V> {
let bucket_index = Self::get_bucket_index(index, size_mask);
let cell_index = Self::get_cell_index(index);
&buckets[bucket_index].cells[cell_index]
}
#[inline]
fn get_cell_mut(
buckets: &mut [Bucket<K, V>],
index: usize,
size_mask: usize,
) -> &mut Cell<K, V> {
let bucket_index = Self::get_bucket_index(index, size_mask);
let cell_index = Self::get_cell_index(index);
&mut buckets[bucket_index].cells[cell_index]
}
#[inline]
fn get_first_delta(buckets: &[Bucket<K, V>], index: usize, size_mask: usize) -> u8 {
let bucket_index = Self::get_bucket_index(index, size_mask);
let cell_index = Self::get_cell_index(index);
buckets[bucket_index].deltas[cell_index]
}
#[inline]
fn get_first_delta_mut(
buckets: &mut [Bucket<K, V>],
index: usize,
size_mask: usize,
) -> &mut u8 {
let bucket_index = Self::get_bucket_index(index, size_mask);
let cell_index = Self::get_cell_index(index);
&mut buckets[bucket_index].deltas[cell_index]
}
#[inline]
fn get_second_delta(buckets: &[Bucket<K, V>], index: usize, size_mask: usize) -> u8 {
let bucket_index = Self::get_bucket_index(index, size_mask);
let cell_index = Self::get_cell_index(index);
buckets[bucket_index].deltas[cell_index + 4]
}
#[inline]
fn get_second_delta_mut(
buckets: &mut [Bucket<K, V>],
index: usize,
size_mask: usize,
) -> &mut u8 {
let bucket_index = Self::get_bucket_index(index, size_mask);
let cell_index = Self::get_cell_index(index);
&mut buckets[bucket_index].deltas[cell_index + 4]
}
#[inline]
const fn get_bucket_index(index: usize, size_mask: usize) -> usize {
(index & size_mask) >> 2
}
#[inline]
const fn get_cell_index(index: usize) -> usize {
index & 3
}
}
unsafe impl<K, V, H, A> Send for HashMap<K, V, H, A>
where
H: BuildHasher + Send,
A: Allocator + Send,
{
}
impl<K, V> Default for HashMap<K, V, BuildHasherDefault<DefaultHash>, Global>
where
K: Eq + Hash + Clone,
V: Value,
{
fn default() -> Self {
Self::new_in(Global)
}
}
impl<K, V, H, A> Clone for HashMap<K, V, H, A>
where
K: Eq + Hash + Clone,
V: Value,
H: BuildHasher + Default,
A: Allocator + Clone,
{
fn clone(&self) -> Self {
let capacity = self.capacity();
let builder = H::default();
let mut new_map =
Self::with_capacity_and_hasher_in(capacity, builder, self.allocator.clone());
for (key, value) in self.into_iter() {
let _old = new_map.insert(key.clone(), *value);
}
new_map
}
}
impl<K, V, H, A: Allocator> Drop for HashMap<K, V, H, A> {
fn drop(&mut self) {
if !self.is_allocated() {
return;
}
let table = self.get_table_mut();
let bucket_ptr = table.buckets;
let bucket_count = table.size() >> 2;
deallocate::<Bucket<K, V>, A>(&self.allocator, bucket_ptr, bucket_count);
let table_ptr = self.table;
deallocate::<Table<K, V>, A>(&self.allocator, table_ptr, 1);
}
}
impl<K, V, H, A> IntoIterator for HashMap<K, V, H, A>
where
K: Eq + Hash + Clone,
V: Value,
H: BuildHasher + Default,
A: Allocator,
{
type Item = (K, V);
type IntoIter = OwnedIter<K, V, H, A>;
fn into_iter(self) -> Self::IntoIter {
OwnedIter::new(self)
}
}
impl<'a, K, V, H, A> IntoIterator for &'a HashMap<K, V, H, A>
where
K: Eq + Hash + Clone,
V: Value,
H: BuildHasher + Default + 'a,
A: Allocator + 'a,
{
type Item = (&'a K, &'a V);
type IntoIter = Iter<'a, K, V, H, A>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[inline]
pub(crate) const fn null_hash() -> HashedKey {
0_u64
}
pub(crate) type HashedKey = u64;
pub(crate) struct Cell<K, V> {
hash: HashedKey,
pub(crate) key: K,
pub(crate) value: V,
}
impl<K, V> Cell<K, V> {
pub(super) fn is_empty(&self) -> bool {
self.hash == null_hash()
}
}
struct Table<K, V> {
buckets: *mut Bucket<K, V>,
size_mask: usize,
}
impl<K, V> Table<K, V> {
fn bucket_slice_mut(&mut self) -> &mut [Bucket<K, V>] {
unsafe { std::slice::from_raw_parts_mut(self.buckets, self.size()) }
}
fn bucket_slice(&self) -> &[Bucket<K, V>] {
unsafe { std::slice::from_raw_parts(self.buckets, self.size()) }
}
fn size(&self) -> usize {
self.size_mask + 1
}
}
struct Bucket<K, V> {
deltas: [u8; 8],
cells: [Cell<K, V>; 4],
_key: std::marker::PhantomData<K>,
}
enum InsertResult<V> {
Found(V),
NewInsert,
Overflow(usize),
}