use alloc::vec::Vec;
use core::{
borrow::Borrow,
cell::Cell,
fmt,
fmt::Formatter,
hash::{BuildHasher, Hash, Hasher},
iter::FromIterator,
mem,
num::NonZeroUsize,
ops::{Index, IndexMut},
};
use crate::{FromIndex, Idx, IntoIndex, Key, NewIndex};
mod hasher;
use hasher::LuaBuildHasher;
mod iter;
pub use iter::{IntoIter, Iter, IterMut, Keys, Values, ValuesMut};
macro_rules! cp {
($T:ty => $U:ty, $v:ident => $field:ident) => {
match $v {
ref cell => {
let cell: &Cell<$T> = cell;
let ptr: *mut $T = cell.as_ptr();
let member_ptr: *mut $U = unsafe { ::core::ptr::addr_of_mut!((*ptr).$field) };
let cell_ptr: *mut Cell<$U> = member_ptr.cast();
unsafe { &*cell_ptr }
}
}
};
}
mod node;
use node::Node;
mod entry;
pub use entry::{Entry, OccupiedEntry, VacantEntry};
#[inline]
const fn round_pow_2(x: usize) -> usize {
if x == 0 {
0
} else {
x.next_power_of_two()
}
}
#[inline]
const fn round_down_pow_2(x: usize) -> usize {
if x.is_power_of_two() {
x
} else {
x.next_power_of_two() >> 1
}
}
#[inline]
const fn ceil_log_2(x: NonZeroUsize) -> usize {
(usize::BITS - (x.get() - 1).leading_zeros()) as usize
}
const NUMS_LEN: usize = usize::BITS as usize;
type Nums = [usize; NUMS_LEN];
#[derive(Clone)]
pub struct Ham<K, V> {
array: Vec<Option<V>>,
hash: Vec<Node<K, V>>,
len: usize,
last_free: usize,
hash_builder: LuaBuildHasher,
}
#[cfg(feature = "imm_gc")]
unsafe impl<K: imm_gc::Trace, V: imm_gc::Trace> imm_gc::Trace for Ham<K, V> {
imm_gc::unsafe_field_trace! {
array: Vec<Option<V>>,
hash: Vec<Node<K, V>>,
}
}
#[cfg(feature = "bacon_rajan_cc")]
impl<K: bacon_rajan_cc::Trace, V: bacon_rajan_cc::Trace> bacon_rajan_cc::Trace for Ham<K, V> {
fn trace(&self, t: &mut bacon_rajan_cc::Tracer) {
self.array.trace(t);
self.hash.trace(t);
}
}
impl<K: FromIndex + fmt::Debug, V: fmt::Debug> fmt::Debug for Ham<K, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
#[cfg(feature = "std")]
impl<K, V> Default for Ham<K, V> {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "std")]
impl<K, V> Ham<K, V> {
#[must_use]
pub fn new() -> Self {
Self {
array: Vec::new(),
len: 0,
hash: Vec::new(),
last_free: 0,
hash_builder: LuaBuildHasher::new(),
}
}
#[must_use]
pub fn with_capacity(array_part: usize, hash_part: usize) -> Self {
let mut array = Vec::with_capacity(array_part);
array.resize_with(array_part, Option::default);
let hash_part = round_pow_2(hash_part);
let mut hash = Vec::with_capacity(hash_part);
hash.resize_with(hash_part, Node::default);
Self {
array,
len: 0,
hash,
last_free: hash_part,
hash_builder: LuaBuildHasher::new(),
}
}
}
impl<K, V> Ham<K, V> {
#[must_use]
pub const fn with_seed(seed: u64) -> Self {
Self {
array: Vec::new(),
len: 0,
hash: Vec::new(),
last_free: 0,
hash_builder: LuaBuildHasher::with_seed(seed),
}
}
#[must_use]
pub fn with_capacity_and_seed(array_part: usize, hash_part: usize, seed: u64) -> Self {
let mut array = Vec::with_capacity(array_part);
array.resize_with(array_part, Option::default);
let hash_part = round_pow_2(hash_part);
let mut hash = Vec::with_capacity(hash_part);
hash.resize_with(hash_part, Node::default);
Self {
array,
len: 0,
hash,
last_free: hash_part,
hash_builder: LuaBuildHasher::with_seed(seed),
}
}
#[must_use]
pub const fn len(&self) -> usize {
self.len
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
#[must_use]
pub fn capacity(&self) -> (usize, usize) {
(self.array.len(), self.hash.len())
}
pub fn clear(&mut self) {
self.len = 0;
for item in &mut self.array {
*item = None;
}
for item in &mut self.hash {
item.take();
item.next = 0;
}
self.last_free = self.hash.len();
}
#[must_use]
pub fn is_in_array<Q: ?Sized + IntoIndex>(&self, key: &Q) -> bool {
self.get_array(key).is_some()
}
#[must_use]
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: IntoIndex + Hash + Eq,
{
if let Some(v) = self.get_array(key) {
v.as_ref()
} else {
self.get_hash(key)
.and_then(|v| v.value().as_ref().map(|p| &p.1))
}
}
#[must_use]
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: IntoIndex + Hash + Eq,
{
self.get(key).is_some()
}
#[must_use]
pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
Q: IntoIndex + Hash + Eq,
{
if let Some(idx) = self.get_array_idx_only(key) {
unsafe { self.array.get_unchecked_mut(idx) }.as_mut()
} else {
self.get_hash_mut(key)
.and_then(|v| v.value_mut().as_mut().map(|p| &mut p.1))
}
}
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: IntoIndex + Hash + Eq,
{
let v = self
.get_array_take(key)
.or_else(|| self.get_hash_take(key).map(|v| v.1));
if v.is_some() {
self.len -= 1;
}
v
}
}
impl<K: FromIndex, V> Ham<K, V> {
pub fn iter(&self) -> Iter<'_, K, V> {
Iter {
array: self.array.iter().enumerate(),
hash: self.hash.iter(),
len: self.len,
}
}
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut {
array: self.array.iter_mut().enumerate(),
hash: self.hash.iter_mut(),
len: self.len,
}
}
pub fn keys(&self) -> Keys<'_, K, V> {
Keys { inner: self.iter() }
}
pub fn values(&self) -> Values<'_, K, V> {
Values {
array: self.array.iter(),
hash: self.hash.iter(),
len: self.len,
}
}
pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
ValuesMut {
array: self.array.iter_mut(),
hash: self.hash.iter_mut(),
len: self.len,
}
}
}
impl<K: FromIndex + Hash + Eq, V> Ham<K, V> {
#[must_use]
pub fn get_key_value<Q: ?Sized>(&self, key: &Q) -> Option<(Key<'_, K>, &V)>
where
K: Borrow<Q>,
Q: IntoIndex + Hash + Eq,
{
if let Some((idx, v)) = self.get_array_idx(key) {
v.as_ref()
.map(|v| (Key::Owned(idx.cast_safe().into_value()), v))
} else {
self.get_hash(key)
.and_then(|v| v.value().as_ref().map(|(k, v)| (Key::Borrowed(k), v)))
}
}
#[must_use]
pub fn remove_entry<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
where
K: Borrow<Q>,
Q: IntoIndex + Hash + Eq,
{
let v = if let Some((idx, v)) = self.get_array_idx_mut(key) {
v.take().map(|v| (idx.cast_safe().into_value(), v))
} else {
self.get_hash_take(key)
};
if v.is_some() {
self.len -= 1;
}
v
}
}
impl<K: NewIndex + Hash + Eq, V> Ham<K, V> {
pub fn get_n(&self) -> Option<usize> {
fn binary_search(
mut min: usize,
mut max: usize,
is_empty: impl Fn(usize) -> Option<bool>,
) -> Option<usize> {
while max - min > 1 {
let mid = min + (max - min) / 2;
if is_empty(mid)? {
max = mid;
} else {
min = mid;
}
}
Some(min)
}
let array_len = self.array.len();
if let Some(&None) = self.array.last() {
binary_search(0, array_len, |i| Some(self.array[i].is_none()))
} else if self.array.is_empty() {
None
} else if self.hash.is_empty() {
Some(array_len)
} else {
let min = array_len;
let mut max = array_len + 1;
while self
.get_hash(&Idx::try_new_usize(max)?.into_value())
.is_some()
{
if max == usize::MAX {
return Some(usize::MAX);
}
max = max.saturating_mul(2);
}
binary_search(min, max, |i| {
Some(
self.get_hash(&Idx::try_new_usize(i)?.into_value())
.is_some(),
)
})
}
}
}
impl<K: IntoIndex + FromIndex + Hash + Eq, V> Ham<K, V> {
#[must_use]
pub fn entry(&mut self, k: K) -> Entry<'_, K, V> {
Entry::make_new(self, k) }
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
if let Some(slot) = self.get_array_mut(&key) {
let v = mem::replace(slot, Some(value));
if v.is_none() {
self.len += 1;
}
v
} else if let Some(node) = self.get_hash_mut(&key) {
if let Some((_, ref mut v)) = *node.value_mut() {
Some(mem::replace(v, value))
} else {
*node.value_mut() = Some((key, value));
self.len += 1;
None
}
} else {
self.new_key(key, value);
None
}
}
pub fn shrink_to_fit(&mut self) {
self.do_rehash(None, true);
}
pub fn force_rehash(&mut self) {
self.do_rehash(None, false);
}
}
impl<K: IntoIndex + FromIndex + Hash + Eq, V> Ham<K, V> {
fn insert_and_get_mut(&mut self, key: K, value: V) -> &mut V {
if let Some(idx) = self.get_array_idx_only(&key) {
let slot = &mut self.array[idx];
if slot.is_none() {
self.len += 1;
}
slot.insert(value)
} else if let Some(idx) = self.get_hash_idx_only(&key) {
let node = &mut self.hash[idx];
let entry = node.value_mut().take();
if entry.is_none() {
self.len += 1;
}
let key = if let Some((key, _)) = entry { key } else { key };
&mut node.value_mut().insert((key, value)).1
} else {
self.new_key(key, value)
}
}
fn new_key(&mut self, key: K, value: V) -> &mut V {
if self.hash.is_empty() {
self.do_rehash(Some(&key), false);
return self.insert_and_get_mut(key, value);
}
let main_pos = Self::main_position_cell(self as *mut _, &key);
let mut emplaced = main_pos;
if let Some((ref colliding_key, _)) = *unsafe { &*main_pos.as_ptr() }.value() {
if let Some(free) = Self::get_free_pos_cell(self as *mut _) {
debug_assert_eq!(Node::next(free) as *const _, free as *const _);
let mut other_main_pos = Self::main_position_cell(self as *mut _, colliding_key);
if main_pos as *const _ != other_main_pos {
while main_pos as *const _ != Node::next(other_main_pos) {
other_main_pos = Node::next(other_main_pos);
}
Node::set_next(other_main_pos, free);
let next = Node::next(main_pos);
free.set(main_pos.replace(Node {
inner: Some((key, value)),
next: 0,
}));
if next as *const _ != main_pos {
Node::set_next(free, next);
}
} else {
if Node::next(main_pos) as *const _ != main_pos {
Node::set_next(free, Node::next(main_pos));
}
Node::set_next(main_pos, free);
*unsafe { &mut *free.as_ptr() }.value_mut() = Some((key, value));
emplaced = free;
}
} else {
self.do_rehash(Some(&key), false);
return self.insert_and_get_mut(key, value);
}
} else {
*unsafe { &mut *main_pos.as_ptr() }.value_mut() = Some((key, value));
}
self.len += 1;
&mut unsafe {
(&mut *emplaced.as_ptr())
.value_mut()
.as_mut()
.unwrap_unchecked()
}
.1
}
fn count_int(key: &K, nums: &mut Nums) -> bool {
key.into_index()
.map(|v| nums[ceil_log_2(v.get())] += 1)
.is_some()
}
fn num_use_hash(&self, nums: &mut Nums) -> (usize, usize) {
let mut total = 0;
let mut a_use = 0;
for v in &self.hash {
if let Some((key, _)) = v.value().as_ref() {
if Self::count_int(key, nums) {
a_use += 1;
}
total += 1;
}
}
(total, a_use)
}
fn num_use_array(&self, nums: &mut Nums) -> usize {
let mut a_use: usize = 0;
let mut i = 0;
for (lg, num) in nums.iter_mut().enumerate() {
let ttlg = 1 << lg;
let limit = core::cmp::min(ttlg, self.array.len());
if i >= limit {
break;
}
let count = self.array[i..limit]
.iter()
.filter_map(Option::as_ref)
.count();
i = limit;
*num += count;
a_use += count;
}
a_use
}
fn do_rehash(&mut self, key: Option<&K>, shrink: bool) {
let mut nums: Nums = [0; NUMS_LEN];
let mut na = self.num_use_array(&mut nums);
let mut total_use = na;
{
let (total_add, na_add) = self.num_use_hash(&mut nums);
total_use += total_add;
na += na_add;
}
if let Some(key) = key {
if Self::count_int(key, &mut nums) {
na += 1;
}
total_use += 1;
}
let (asize, na) = compute_sizes(&nums, na);
fn compute_sizes(nums: &Nums, pna: usize) -> (usize, usize) {
let mut a = 0;
let mut na = 0;
let mut optimal = 0;
for (two_to_i, num) in nums
.iter()
.copied()
.enumerate()
.map(|(i, num)| (1 << i, num))
{
if pna <= two_to_i / 2 {
break;
}
a += num;
if a > two_to_i / 2 {
optimal = two_to_i; na = a; }
}
debug_assert!(
(optimal == 0 || optimal / 2 < na) && na <= optimal,
"optimal = {optimal}; na = {na}",
optimal = optimal,
na = na,
);
(optimal, na)
}
self.resize(asize, total_use - na, shrink);
}
fn resize(&mut self, array_part: usize, hash_part: usize, shrink: bool) {
let mut hash_part = round_pow_2(hash_part);
let old_hash = mem::replace(&mut self.hash, {
let mut v = Vec::with_capacity(hash_part);
let c = round_down_pow_2(v.capacity());
if c > hash_part {
hash_part = c;
}
v.resize_with(hash_part, Node::default);
v
});
let hash_part = hash_part;
self.last_free = hash_part;
let mut array_part = array_part;
let array_grew = if array_part > self.array.len() {
self.array.resize_with(array_part, Option::default);
let c = round_down_pow_2(self.array.capacity());
if c > array_part {
array_part = c;
self.array.resize_with(array_part, Option::default);
}
true
} else {
false
};
let array_part = array_part;
let len = self.len;
if array_part < self.array.len() {
let mut array = mem::take(&mut self.array);
for (i, item) in array.drain(array_part..).enumerate() {
if let Some(item) = item {
self.new_key(
K::from_index(unsafe { Idx::new_unchecked(array_part + i + 1) }),
item,
); }
}
if shrink {
array.shrink_to_fit();
}
self.array = array;
}
for node in old_hash {
if let Some((k, v)) = node.into_inner() {
if array_grew {
self.insert(k, v);
} else {
self.new_key(k, v);
}
}
}
self.len = len; }
}
impl<K, V> Ham<K, V> {
fn get_array_idx_only<Q: ?Sized + IntoIndex>(&self, key: &Q) -> Option<usize> {
let v = key.into_index()?.get().get() - 1;
self.array.get(v).map(|_| v)
}
fn get_array_idx<Q: ?Sized + IntoIndex>(&self, key: &Q) -> Option<(Idx<Q>, &Option<V>)> {
key.into_index()
.and_then(|v| Some((v.clone(), self.array.get(v.get().get() - 1)?)))
}
fn get_array_idx_mut<Q: ?Sized + IntoIndex>(
&mut self,
key: &Q,
) -> Option<(Idx<Q>, &mut Option<V>)> {
key.into_index()
.and_then(move |v| Some((v.clone(), self.array.get_mut(v.get().get() - 1)?)))
}
fn get_array<Q: ?Sized + IntoIndex>(&self, key: &Q) -> Option<&Option<V>> {
key.into_index()
.and_then(|v| self.array.get(v.get().get() - 1))
}
fn get_array_mut<Q: ?Sized + IntoIndex>(&mut self, key: &Q) -> Option<&mut Option<V>> {
key.into_index()
.and_then(move |v| self.array.get_mut(v.get().get() - 1))
}
fn get_array_take<Q: ?Sized + IntoIndex>(&mut self, key: &Q) -> Option<V> {
self.get_array_mut(key).and_then(Option::take)
}
fn get_hash_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut Node<K, V>>
where
Q: Hash + Eq,
K: Borrow<Q>,
{
if self.hash.is_empty() {
None
} else {
let mut v = Self::main_position_cell(self as *mut _, key);
while !Node::matches(v, key) {
let new_v = Node::next(v);
if new_v as *const _ == v {
return None; }
v = new_v;
}
Some(unsafe { &mut *v.as_ptr() })
}
}
fn get_hash_mut_for_take<Q: ?Sized>(&mut self, key: &Q) -> Option<(&mut Node<K, V>, bool)>
where
Q: Hash + Eq,
K: Borrow<Q>,
{
if self.hash.is_empty() {
None
} else {
let mut v = Self::main_position_cell(self as *mut _, key);
let mut prev_v = None;
while !Node::matches(v, key) {
let new_v = Node::next(v);
if new_v as *const _ == v {
return None; }
prev_v = Some(v);
v = new_v;
}
Some(if let Some(prev) = prev_v {
(unsafe { &mut *prev.as_ptr() }, true)
} else {
(unsafe { &mut *v.as_ptr() }, false)
})
}
}
fn get_hash_take<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
where
Q: Hash + Eq,
K: Borrow<Q>,
{
if self.hash.is_empty() {
None
} else {
let mut v = Self::main_position_cell(self as *mut _, key);
let mut prev_v = None;
while !Node::matches(v, key) {
let new_v = Node::next(v);
if new_v as *const _ == v {
return None; }
prev_v = Some(v);
v = new_v;
}
let v_next = Node::next(v);
{
#[allow(clippy::cast_sign_loss)]
let num = unsafe { v.as_ptr().offset_from(self.hash.as_ptr()) } as usize;
if num > self.last_free {
self.last_free = num;
}
}
let out = if let Some(prev_v) = prev_v {
if v_next as *const _ == v {
Node::set_next(prev_v, prev_v);
} else {
Node::set_next(prev_v, v_next);
}
unsafe { &mut *v.as_ptr() }.value_mut().take()
} else if v_next as *const _ != v {
let v_next_next = Node::next(v_next);
let v_next_value = v_next.replace(Node::default());
let v_value = v.replace(v_next_value);
if v_next_next as *const _ != v_next {
Node::set_next(v, v_next_next);
}
v_value.into_inner()
} else {
unsafe { &mut *v.as_ptr() }.value_mut().take()
};
Node::set_next(v, v);
out
}
}
fn get_hash<Q: ?Sized>(&self, key: &Q) -> Option<&Node<K, V>>
where
Q: Hash + Eq,
K: Borrow<Q>,
{
if self.hash.is_empty() {
None
} else {
let mut v = self.main_position(key);
while !v.matches_ref(key) {
let new_v = v.next_ref();
if new_v as *const _ == v {
return None; }
v = new_v;
}
Some(v)
}
}
fn get_hash_idx_only<Q: ?Sized>(&self, key: &Q) -> Option<usize>
where
Q: Hash + Eq,
K: Borrow<Q>,
{
self.get_hash_idx(key).map(|v| v.0)
}
fn get_hash_idx<Q: ?Sized>(&self, key: &Q) -> Option<(usize, &Node<K, V>)>
where
Q: Hash + Eq,
K: Borrow<Q>,
{
if self.hash.is_empty() {
None
} else {
let mut v = self.main_position(key);
while !v.matches_ref(key) {
let new_v = v.next_ref();
if new_v as *const _ == v {
return None; }
v = new_v;
}
#[allow(clippy::cast_sign_loss)]
Some((
unsafe { (v as *const Node<K, V>).offset_from(self.hash.as_ptr()) } as usize,
v,
))
}
}
fn main_position<Q: ?Sized + Hash>(&self, key: &Q) -> &Node<K, V> {
let mut hasher = self.hash_builder.build_hasher();
key.hash(&mut hasher);
debug_assert!(self.hash.len().is_power_of_two());
let idx = (hasher.finish() as usize) % self.hash.len();
&self.hash[idx]
}
fn main_position_cell<'a, Q: ?Sized + Hash>(this: *mut Self, key: &Q) -> &'a Cell<Node<K, V>> {
let mut hasher = unsafe { (*this).hash_builder }.build_hasher();
key.hash(&mut hasher);
let h = unsafe { &mut (*this).hash };
let idx = (hasher.finish() as usize) % h.len();
unsafe { &*h.as_mut_ptr().add(idx).cast::<Cell<Node<K, V>>>() }
}
fn get_free_pos_cell<'a>(this: *mut Self) -> Option<&'a Cell<Node<K, V>>> {
for i in (0..unsafe { (*this).last_free }).rev() {
let node = unsafe { &*(*this).hash.as_mut_ptr().add(i).cast::<Cell<Node<K, V>>>() };
if unsafe { &*node.as_ptr() }.value().is_none() {
unsafe {
(*this).last_free = i;
} return Some(node);
}
}
None
}
}
impl<K, Q: ?Sized, V> Index<&Q> for Ham<K, V>
where
K: Hash + Eq + Borrow<Q>,
Q: IntoIndex + Hash + Eq,
{
type Output = V;
fn index(&self, key: &Q) -> &V {
self.get(key).expect("no entry found for key")
}
}
impl<K, Q: ?Sized, V> IndexMut<&Q> for Ham<K, V>
where
K: Hash + Eq + Borrow<Q>,
Q: IntoIndex + Hash + Eq,
{
fn index_mut(&mut self, key: &Q) -> &mut V {
self.get_mut(key).expect("no entry found for key")
}
}
#[cfg(feature = "std")]
impl<K, V> FromIterator<(K, V)> for Ham<K, V>
where
K: IntoIndex + FromIndex + Hash + Eq,
{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
{
let mut map = Self::new();
map.extend(iter);
map
}
}
impl<K, V> Extend<(K, V)> for Ham<K, V>
where
K: IntoIndex + FromIndex + Hash + Eq,
{
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (K, V)>,
{
for (k, v) in iter {
self.insert(k, v);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const SIZE: usize = 1000;
#[test]
fn test_insert() {
let mut hash_map = Ham::with_seed(0);
for i in 0..SIZE {
hash_map.insert(i, i);
}
}
#[test]
fn test_insert_remove() {
let mut hash_map = Ham::with_seed(0);
for i in 0..SIZE {
hash_map.insert(i, i);
}
for i in 0..SIZE {
hash_map.insert(i + SIZE, i);
hash_map.remove(&i);
hash_map.shrink_to_fit();
}
}
#[test]
fn test_insert_remove_2() {
let mut hash_map = Ham::with_seed(0);
for i in 0..100 {
hash_map.insert(i, i);
}
for i in 0..100 {
hash_map.insert(i + 100, i);
hash_map.remove(&i);
}
}
}