use std::mem::MaybeUninit;
const MIN_CAPACITY: usize = 8;
const LOAD_FACTOR_NUM: usize = 3;
const LOAD_FACTOR_DEN: usize = 4;
const SHRINK_DIVISOR: usize = 4;
const MIN_SHRINK_CAPACITY: usize = 64;
const EMPTY: i64 = i64::MIN;
#[cold]
#[inline(never)]
fn assert_valid_key(key: i64) {
if key == EMPTY {
panic!("i64::MIN cannot be used as a key in I64Map (reserved as empty sentinel)");
}
}
#[inline(always)]
fn check_key(key: i64) {
if key == EMPTY {
assert_valid_key(key);
}
}
#[repr(C)]
struct Slot<V> {
key: i64,
value: MaybeUninit<V>,
}
pub struct I64Map<V> {
slots: Box<[Slot<V>]>,
len: usize,
mask: usize,
}
impl<V: Clone> Clone for I64Map<V> {
fn clone(&self) -> Self {
let mut new_map = Self::with_capacity(self.len);
for (key, value) in self.iter() {
new_map.insert(key, value.clone());
}
new_map
}
}
impl<V> Default for I64Map<V> {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl<V> I64Map<V> {
#[inline(always)]
pub fn new() -> Self {
Self::with_capacity(0)
}
pub fn with_capacity(capacity: usize) -> Self {
let cap = if capacity == 0 {
MIN_CAPACITY
} else {
capacity
.saturating_mul(LOAD_FACTOR_DEN)
.saturating_div(LOAD_FACTOR_NUM)
.next_power_of_two()
.max(MIN_CAPACITY)
};
let slots: Vec<Slot<V>> = (0..cap)
.map(|_| Slot {
key: EMPTY,
value: MaybeUninit::uninit(),
})
.collect();
Self {
slots: slots.into_boxed_slice(),
len: 0,
mask: cap - 1,
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.len
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline(always)]
pub fn capacity(&self) -> usize {
self.slots.len()
}
pub fn reserve(&mut self, additional: usize) {
let target_len = self.len + additional;
let target_cap = if target_len == 0 {
MIN_CAPACITY
} else {
target_len
.saturating_mul(LOAD_FACTOR_DEN)
.saturating_div(LOAD_FACTOR_NUM)
.next_power_of_two()
.max(MIN_CAPACITY)
};
if target_cap <= self.slots.len() {
return;
}
let new_cap = target_cap;
let new_mask = new_cap - 1;
let new_slots: Vec<Slot<V>> = (0..new_cap)
.map(|_| Slot {
key: EMPTY,
value: MaybeUninit::uninit(),
})
.collect();
let old_slots = std::mem::replace(&mut self.slots, new_slots.into_boxed_slice());
let old_len = self.len;
self.len = 0;
self.mask = new_mask;
for slot in old_slots.iter() {
if slot.key != EMPTY {
let value = unsafe { slot.value.as_ptr().read() };
self.insert(slot.key, value);
}
}
debug_assert_eq!(self.len, old_len);
}
#[inline(always)]
fn hash(key: i64) -> usize {
let k = key as u64;
let k = k ^ (k >> 16); k.wrapping_mul(0x517cc1b727220a95) as usize
}
#[inline(always)]
pub fn insert(&mut self, key: i64, value: V) -> Option<V> {
check_key(key);
if self.len * LOAD_FACTOR_DEN >= self.slots.len() * LOAD_FACTOR_NUM {
self.grow();
}
let mask = self.mask;
let mut idx = Self::hash(key) & mask;
loop {
let slot = unsafe { self.slots.get_unchecked_mut(idx) };
if slot.key == EMPTY {
slot.key = key;
slot.value.write(value);
self.len += 1;
return None;
}
if slot.key == key {
let old = unsafe { slot.value.as_ptr().read() };
slot.value.write(value);
return Some(old);
}
idx = (idx + 1) & mask;
}
}
#[inline(always)]
pub fn get(&self, key: i64) -> Option<&V> {
check_key(key);
let mask = self.mask;
let mut idx = Self::hash(key) & mask;
loop {
let slot = unsafe { self.slots.get_unchecked(idx) };
if slot.key == EMPTY {
return None;
}
if slot.key == key {
return Some(unsafe { slot.value.assume_init_ref() });
}
idx = (idx + 1) & mask;
}
}
#[inline(always)]
pub fn get_mut(&mut self, key: i64) -> Option<&mut V> {
check_key(key);
let mask = self.mask;
let mut idx = Self::hash(key) & mask;
let found_idx = loop {
let slot = unsafe { self.slots.get_unchecked(idx) };
if slot.key == EMPTY {
return None;
}
if slot.key == key {
break idx;
}
idx = (idx + 1) & mask;
};
Some(unsafe {
self.slots
.get_unchecked_mut(found_idx)
.value
.assume_init_mut()
})
}
#[inline(always)]
pub fn contains_key(&self, key: i64) -> bool {
self.get(key).is_some()
}
#[inline(always)]
pub fn remove(&mut self, key: i64) -> Option<V> {
check_key(key);
let mask = self.mask;
let mut idx = Self::hash(key) & mask;
loop {
let slot = unsafe { self.slots.get_unchecked(idx) };
if slot.key == EMPTY {
return None;
}
if slot.key == key {
break;
}
idx = (idx + 1) & mask;
}
let value = unsafe { self.slots.get_unchecked(idx).value.as_ptr().read() };
self.len -= 1;
let mut empty_idx = idx;
let mut next_idx = (idx + 1) & mask;
loop {
let next_slot = unsafe { self.slots.get_unchecked(next_idx) };
if next_slot.key == EMPTY {
break;
}
let next_home = Self::hash(next_slot.key) & mask;
let can_move = if next_home <= next_idx {
empty_idx >= next_home && empty_idx < next_idx
} else {
empty_idx >= next_home || empty_idx < next_idx
};
if can_move {
unsafe {
let base = self.slots.as_mut_ptr();
let src = base.add(next_idx);
let dst = base.add(empty_idx);
(*dst).key = (*src).key;
std::ptr::copy_nonoverlapping(
(*src).value.as_ptr(),
(*dst).value.as_mut_ptr(),
1,
);
}
empty_idx = next_idx;
}
next_idx = (next_idx + 1) & mask;
}
unsafe {
self.slots.get_unchecked_mut(empty_idx).key = EMPTY;
}
if self.should_shrink() {
self.shrink();
}
Some(value)
}
fn grow(&mut self) {
let new_cap = (self.slots.len() * 2).max(MIN_CAPACITY);
let new_mask = new_cap - 1;
let new_slots: Vec<Slot<V>> = (0..new_cap)
.map(|_| Slot {
key: EMPTY,
value: MaybeUninit::uninit(),
})
.collect();
let old_slots = std::mem::replace(&mut self.slots, new_slots.into_boxed_slice());
let old_len = self.len;
self.len = 0;
self.mask = new_mask;
for slot in Vec::from(old_slots) {
if slot.key != EMPTY {
let value = unsafe { slot.value.assume_init() };
self.insert(slot.key, value);
}
}
debug_assert_eq!(self.len, old_len);
}
#[inline]
fn should_shrink(&self) -> bool {
let cap = self.slots.len();
cap > MIN_SHRINK_CAPACITY && self.len < cap / SHRINK_DIVISOR
}
fn shrink(&mut self) {
let new_cap = if self.len == 0 {
MIN_CAPACITY
} else {
self.len
.saturating_mul(LOAD_FACTOR_DEN)
.saturating_div(LOAD_FACTOR_NUM)
.next_power_of_two()
.max(MIN_CAPACITY)
};
if new_cap >= self.slots.len() {
return; }
let new_mask = new_cap - 1;
let new_slots: Vec<Slot<V>> = (0..new_cap)
.map(|_| Slot {
key: EMPTY,
value: MaybeUninit::uninit(),
})
.collect();
let old_slots = std::mem::replace(&mut self.slots, new_slots.into_boxed_slice());
let old_len = self.len;
self.len = 0;
self.mask = new_mask;
for slot in Vec::from(old_slots) {
if slot.key != EMPTY {
let value = unsafe { slot.value.assume_init() };
self.insert(slot.key, value);
}
}
debug_assert_eq!(self.len, old_len);
}
pub fn shrink_to_fit(&mut self) {
self.shrink();
}
pub fn clear(&mut self) {
for slot in self.slots.iter_mut() {
if slot.key != EMPTY {
unsafe {
std::ptr::drop_in_place(slot.value.as_mut_ptr());
}
slot.key = EMPTY;
}
}
self.len = 0;
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (i64, &V)> {
self.slots.iter().filter_map(|slot| {
if slot.key != EMPTY {
Some((slot.key, unsafe { slot.value.assume_init_ref() }))
} else {
None
}
})
}
#[inline]
pub fn keys(&self) -> impl Iterator<Item = i64> + '_ {
self.slots
.iter()
.filter_map(|s| if s.key != EMPTY { Some(s.key) } else { None })
}
#[inline]
pub fn values(&self) -> impl Iterator<Item = &V> {
self.slots.iter().filter_map(|slot| {
if slot.key != EMPTY {
Some(unsafe { slot.value.assume_init_ref() })
} else {
None
}
})
}
#[inline]
pub fn iter_mut(&mut self) -> impl Iterator<Item = (i64, &mut V)> {
self.slots.iter_mut().filter_map(|slot| {
if slot.key != EMPTY {
Some((slot.key, unsafe { slot.value.assume_init_mut() }))
} else {
None
}
})
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(i64, &mut V) -> bool,
{
let keys_to_remove: Vec<i64> = self
.slots
.iter_mut()
.filter_map(|slot| {
if slot.key != EMPTY {
let value = unsafe { slot.value.assume_init_mut() };
if f(slot.key, value) {
None } else {
Some(slot.key) }
} else {
None
}
})
.collect();
for key in keys_to_remove {
self.remove(key);
}
}
#[inline]
pub fn drain(&mut self) -> Drain<V> {
let old_slots = std::mem::replace(
&mut self.slots,
(0..MIN_CAPACITY)
.map(|_| Slot {
key: EMPTY,
value: MaybeUninit::uninit(),
})
.collect::<Vec<_>>()
.into_boxed_slice(),
);
self.len = 0;
self.mask = MIN_CAPACITY - 1;
Drain {
slots: old_slots,
pos: 0,
}
}
#[inline(always)]
pub fn entry(&mut self, key: i64) -> Entry<'_, V> {
check_key(key);
let mask = self.mask;
let mut idx = Self::hash(key) & mask;
loop {
let slot = unsafe { self.slots.get_unchecked(idx) };
if slot.key == EMPTY {
if self.len * LOAD_FACTOR_DEN >= self.slots.len() * LOAD_FACTOR_NUM {
self.grow();
let new_mask = self.mask;
let mut new_idx = Self::hash(key) & new_mask;
loop {
let slot = unsafe { self.slots.get_unchecked(new_idx) };
if slot.key == EMPTY {
return Entry::Vacant(VacantEntry {
map: self,
key,
idx: new_idx,
});
}
new_idx = (new_idx + 1) & new_mask;
}
}
return Entry::Vacant(VacantEntry {
map: self,
key,
idx,
});
}
if slot.key == key {
return Entry::Occupied(OccupiedEntry { map: self, idx });
}
idx = (idx + 1) & mask;
}
}
}
impl<V> Drop for I64Map<V> {
fn drop(&mut self) {
for slot in self.slots.iter_mut() {
if slot.key != EMPTY {
unsafe {
std::ptr::drop_in_place(slot.value.as_mut_ptr());
}
}
}
}
}
pub enum Entry<'a, V> {
Occupied(OccupiedEntry<'a, V>),
Vacant(VacantEntry<'a, V>),
}
impl<'a, V> Entry<'a, V> {
#[inline(always)]
pub fn or_insert(self, default: V) -> &'a mut V {
match self {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => e.insert(default),
}
}
#[inline(always)]
pub fn or_insert_with<F: FnOnce() -> V>(self, f: F) -> &'a mut V {
match self {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => e.insert(f()),
}
}
#[inline(always)]
pub fn or_default(self) -> &'a mut V
where
V: Default,
{
match self {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => e.insert(V::default()),
}
}
#[inline(always)]
pub fn and_modify<F: FnOnce(&mut V)>(self, f: F) -> Self {
match self {
Entry::Occupied(mut e) => {
f(e.get_mut());
Entry::Occupied(e)
}
Entry::Vacant(e) => Entry::Vacant(e),
}
}
}
pub struct OccupiedEntry<'a, V> {
map: &'a mut I64Map<V>,
idx: usize,
}
impl<'a, V> OccupiedEntry<'a, V> {
#[inline(always)]
pub fn get(&self) -> &V {
unsafe {
self.map
.slots
.get_unchecked(self.idx)
.value
.assume_init_ref()
}
}
#[inline(always)]
pub fn get_mut(&mut self) -> &mut V {
unsafe {
self.map
.slots
.get_unchecked_mut(self.idx)
.value
.assume_init_mut()
}
}
#[inline(always)]
pub fn into_mut(self) -> &'a mut V {
unsafe {
self.map
.slots
.get_unchecked_mut(self.idx)
.value
.assume_init_mut()
}
}
#[inline(always)]
pub fn insert(&mut self, value: V) -> V {
let slot = unsafe { self.map.slots.get_unchecked_mut(self.idx) };
let old = unsafe { slot.value.as_ptr().read() };
slot.value.write(value);
old
}
#[inline(always)]
pub fn remove(self) -> V {
let key = unsafe { self.map.slots.get_unchecked(self.idx).key };
let value = unsafe { self.map.slots.get_unchecked(self.idx).value.as_ptr().read() };
self.map.len -= 1;
let mask = self.map.mask;
let mut empty_idx = self.idx;
let mut next_idx = (self.idx + 1) & mask;
loop {
let next_slot = unsafe { self.map.slots.get_unchecked(next_idx) };
if next_slot.key == EMPTY {
break;
}
let next_home = I64Map::<V>::hash(next_slot.key) & mask;
let can_move = if next_home <= next_idx {
empty_idx >= next_home && empty_idx < next_idx
} else {
empty_idx >= next_home || empty_idx < next_idx
};
if can_move {
unsafe {
let base = self.map.slots.as_mut_ptr();
let src = base.add(next_idx);
let dst = base.add(empty_idx);
(*dst).key = (*src).key;
std::ptr::copy_nonoverlapping(
(*src).value.as_ptr(),
(*dst).value.as_mut_ptr(),
1,
);
}
empty_idx = next_idx;
}
next_idx = (next_idx + 1) & mask;
}
unsafe {
self.map.slots.get_unchecked_mut(empty_idx).key = EMPTY;
}
let _ = key;
value
}
}
pub struct VacantEntry<'a, V> {
map: &'a mut I64Map<V>,
key: i64,
idx: usize,
}
impl<'a, V> VacantEntry<'a, V> {
#[inline(always)]
pub fn key(&self) -> i64 {
self.key
}
#[inline(always)]
pub fn insert(self, value: V) -> &'a mut V {
let slot = unsafe { self.map.slots.get_unchecked_mut(self.idx) };
slot.key = self.key;
slot.value.write(value);
self.map.len += 1;
unsafe { slot.value.assume_init_mut() }
}
}
pub struct IntoIter<V> {
slots: Box<[Slot<V>]>,
pos: usize,
}
impl<V> Iterator for IntoIter<V> {
type Item = (i64, V);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
while self.pos < self.slots.len() {
let slot = &mut self.slots[self.pos];
self.pos += 1;
if slot.key != EMPTY {
let key = slot.key;
let value = unsafe { slot.value.as_ptr().read() };
slot.key = EMPTY; return Some((key, value));
}
}
None
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.slots.len() - self.pos))
}
}
impl<V> Drop for IntoIter<V> {
fn drop(&mut self) {
while self.pos < self.slots.len() {
let slot = &mut self.slots[self.pos];
self.pos += 1;
if slot.key != EMPTY {
unsafe {
std::ptr::drop_in_place(slot.value.as_mut_ptr());
}
slot.key = EMPTY; }
}
}
}
impl<V> IntoIterator for I64Map<V> {
type Item = (i64, V);
type IntoIter = IntoIter<V>;
fn into_iter(mut self) -> Self::IntoIter {
let slots = std::mem::take(&mut self.slots);
self.len = 0; IntoIter { slots, pos: 0 }
}
}
pub struct Drain<V> {
slots: Box<[Slot<V>]>,
pos: usize,
}
pub struct I64Set {
slots: Box<[i64]>,
len: usize,
mask: usize,
}
impl Clone for I64Set {
fn clone(&self) -> Self {
let mut new_set = Self::with_capacity(self.len);
for key in self.iter() {
new_set.insert(key);
}
new_set
}
}
impl std::fmt::Debug for I64Set {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_set().entries(self.iter()).finish()
}
}
impl Default for I64Set {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl I64Set {
#[inline(always)]
pub fn new() -> Self {
Self::with_capacity(0)
}
pub fn with_capacity(capacity: usize) -> Self {
let cap = if capacity == 0 {
MIN_CAPACITY
} else {
capacity
.saturating_mul(LOAD_FACTOR_DEN)
.saturating_div(LOAD_FACTOR_NUM)
.next_power_of_two()
.max(MIN_CAPACITY)
};
let slots: Vec<i64> = vec![EMPTY; cap];
Self {
slots: slots.into_boxed_slice(),
len: 0,
mask: cap - 1,
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.len
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline(always)]
pub fn capacity(&self) -> usize {
self.slots.len()
}
pub fn reserve(&mut self, additional: usize) {
let target_len = self.len + additional;
let target_cap = if target_len == 0 {
MIN_CAPACITY
} else {
target_len
.saturating_mul(LOAD_FACTOR_DEN)
.saturating_div(LOAD_FACTOR_NUM)
.next_power_of_two()
.max(MIN_CAPACITY)
};
if target_cap <= self.slots.len() {
return;
}
let new_cap = target_cap;
let new_mask = new_cap - 1;
let new_slots: Vec<i64> = vec![EMPTY; new_cap];
let old_slots = std::mem::replace(&mut self.slots, new_slots.into_boxed_slice());
let old_len = self.len;
self.len = 0;
self.mask = new_mask;
for slot in old_slots.iter() {
if *slot != EMPTY {
self.insert(*slot);
}
}
debug_assert_eq!(self.len, old_len);
}
#[inline(always)]
fn hash(key: i64) -> usize {
let k = key as u64;
let k = k ^ (k >> 16);
k.wrapping_mul(0x517cc1b727220a95) as usize
}
#[inline(always)]
pub fn insert(&mut self, key: i64) -> bool {
check_key(key);
if self.len * LOAD_FACTOR_DEN >= self.slots.len() * LOAD_FACTOR_NUM {
self.grow();
}
let mask = self.mask;
let mut idx = Self::hash(key) & mask;
loop {
let slot = unsafe { *self.slots.get_unchecked(idx) };
if slot == EMPTY {
unsafe { *self.slots.get_unchecked_mut(idx) = key };
self.len += 1;
return true;
}
if slot == key {
return false; }
idx = (idx + 1) & mask;
}
}
#[inline(always)]
pub fn contains(&self, key: i64) -> bool {
check_key(key);
let mask = self.mask;
let mut idx = Self::hash(key) & mask;
loop {
let slot = unsafe { *self.slots.get_unchecked(idx) };
if slot == EMPTY {
return false;
}
if slot == key {
return true;
}
idx = (idx + 1) & mask;
}
}
#[inline(always)]
pub fn remove(&mut self, key: i64) -> bool {
check_key(key);
let mask = self.mask;
let mut idx = Self::hash(key) & mask;
loop {
let slot = unsafe { *self.slots.get_unchecked(idx) };
if slot == EMPTY {
return false;
}
if slot == key {
break;
}
idx = (idx + 1) & mask;
}
self.len -= 1;
let mut empty_idx = idx;
let mut next_idx = (idx + 1) & mask;
loop {
let next_slot = unsafe { *self.slots.get_unchecked(next_idx) };
if next_slot == EMPTY {
break;
}
let next_home = Self::hash(next_slot) & mask;
let can_move = if next_home <= next_idx {
empty_idx >= next_home && empty_idx < next_idx
} else {
empty_idx >= next_home || empty_idx < next_idx
};
if can_move {
unsafe {
*self.slots.get_unchecked_mut(empty_idx) = next_slot;
}
empty_idx = next_idx;
}
next_idx = (next_idx + 1) & mask;
}
unsafe {
*self.slots.get_unchecked_mut(empty_idx) = EMPTY;
}
if self.should_shrink() {
self.shrink();
}
true
}
fn grow(&mut self) {
let new_cap = (self.slots.len() * 2).max(MIN_CAPACITY);
let new_mask = new_cap - 1;
let new_slots: Vec<i64> = vec![EMPTY; new_cap];
let old_slots = std::mem::replace(&mut self.slots, new_slots.into_boxed_slice());
let old_len = self.len;
self.len = 0;
self.mask = new_mask;
for slot in old_slots.iter() {
if *slot != EMPTY {
self.insert(*slot);
}
}
debug_assert_eq!(self.len, old_len);
}
#[inline]
fn should_shrink(&self) -> bool {
let cap = self.slots.len();
cap > MIN_SHRINK_CAPACITY && self.len < cap / SHRINK_DIVISOR
}
fn shrink(&mut self) {
let new_cap = if self.len == 0 {
MIN_CAPACITY
} else {
self.len
.saturating_mul(LOAD_FACTOR_DEN)
.saturating_div(LOAD_FACTOR_NUM)
.next_power_of_two()
.max(MIN_CAPACITY)
};
if new_cap >= self.slots.len() {
return; }
let new_mask = new_cap - 1;
let new_slots: Vec<i64> = vec![EMPTY; new_cap];
let old_slots = std::mem::replace(&mut self.slots, new_slots.into_boxed_slice());
let old_len = self.len;
self.len = 0;
self.mask = new_mask;
for slot in old_slots.iter() {
if *slot != EMPTY {
self.insert(*slot);
}
}
debug_assert_eq!(self.len, old_len);
}
pub fn shrink_to_fit(&mut self) {
self.shrink();
}
pub fn clear(&mut self) {
for slot in self.slots.iter_mut() {
*slot = EMPTY;
}
self.len = 0;
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = i64> + '_ {
self.slots
.iter()
.filter_map(|&slot| if slot != EMPTY { Some(slot) } else { None })
}
#[inline]
pub fn drain(&mut self) -> impl Iterator<Item = i64> + '_ {
let len = self.len;
self.len = 0;
self.slots
.iter_mut()
.filter_map(move |slot| {
if *slot != EMPTY {
let val = *slot;
*slot = EMPTY;
Some(val)
} else {
None
}
})
.take(len)
}
}
impl IntoIterator for I64Set {
type Item = i64;
type IntoIter = I64SetIntoIter;
fn into_iter(self) -> Self::IntoIter {
I64SetIntoIter {
slots: self.slots,
pos: 0,
}
}
}
pub struct I64SetIntoIter {
slots: Box<[i64]>,
pos: usize,
}
impl Iterator for I64SetIntoIter {
type Item = i64;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
while self.pos < self.slots.len() {
let slot = self.slots[self.pos];
self.pos += 1;
if slot != EMPTY {
return Some(slot);
}
}
None
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.slots.len() - self.pos))
}
}
impl std::iter::FromIterator<i64> for I64Set {
fn from_iter<T: IntoIterator<Item = i64>>(iter: T) -> Self {
let iter = iter.into_iter();
let (lower, _) = iter.size_hint();
let mut set = I64Set::with_capacity(lower);
for key in iter {
set.insert(key);
}
set
}
}
impl Extend<i64> for I64Set {
fn extend<T: IntoIterator<Item = i64>>(&mut self, iter: T) {
for key in iter {
self.insert(key);
}
}
}
impl<V> Iterator for Drain<V> {
type Item = (i64, V);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
while self.pos < self.slots.len() {
let slot = &mut self.slots[self.pos];
self.pos += 1;
if slot.key != EMPTY {
let key = slot.key;
let value = unsafe { slot.value.as_ptr().read() };
slot.key = EMPTY; return Some((key, value));
}
}
None
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.slots.len() - self.pos))
}
}
impl<V> Drop for Drain<V> {
fn drop(&mut self) {
for _ in self.by_ref() {}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
use std::rc::Rc;
struct DropTracker {
count: Rc<RefCell<usize>>,
}
impl DropTracker {
fn new(count: Rc<RefCell<usize>>) -> Self {
Self { count }
}
}
impl Drop for DropTracker {
fn drop(&mut self) {
*self.count.borrow_mut() += 1;
}
}
#[test]
fn test_into_iter_partial_consume_drops_remaining() {
let drop_count = Rc::new(RefCell::new(0));
let mut map = I64Map::new();
map.insert(1, DropTracker::new(Rc::clone(&drop_count)));
map.insert(2, DropTracker::new(Rc::clone(&drop_count)));
map.insert(3, DropTracker::new(Rc::clone(&drop_count)));
let mut iter = map.into_iter();
let _ = iter.next();
assert_eq!(*drop_count.borrow(), 1);
drop(iter);
assert_eq!(
*drop_count.borrow(),
3,
"Memory leak detected! Only {} items dropped",
*drop_count.borrow()
);
}
#[test]
fn test_into_iter_no_consume_drops_all() {
let drop_count = Rc::new(RefCell::new(0));
let mut map = I64Map::new();
map.insert(1, DropTracker::new(Rc::clone(&drop_count)));
map.insert(2, DropTracker::new(Rc::clone(&drop_count)));
map.insert(3, DropTracker::new(Rc::clone(&drop_count)));
let iter = map.into_iter();
drop(iter);
assert_eq!(
*drop_count.borrow(),
3,
"Memory leak detected! Only {} items dropped",
*drop_count.borrow()
);
}
#[test]
fn test_into_iter_full_consume() {
let drop_count = Rc::new(RefCell::new(0));
let mut map = I64Map::new();
map.insert(1, DropTracker::new(Rc::clone(&drop_count)));
map.insert(2, DropTracker::new(Rc::clone(&drop_count)));
map.insert(3, DropTracker::new(Rc::clone(&drop_count)));
for _ in map.into_iter() {}
assert_eq!(*drop_count.borrow(), 3);
}
#[test]
fn test_drain_partial_consume_drops_remaining() {
let drop_count = Rc::new(RefCell::new(0));
let mut map = I64Map::new();
map.insert(1, DropTracker::new(Rc::clone(&drop_count)));
map.insert(2, DropTracker::new(Rc::clone(&drop_count)));
map.insert(3, DropTracker::new(Rc::clone(&drop_count)));
let mut drain = map.drain();
let _ = drain.next();
assert_eq!(*drop_count.borrow(), 1);
drop(drain);
assert_eq!(*drop_count.borrow(), 3);
}
#[test]
fn test_basic_operations() {
let mut map = I64Map::new();
assert!(map.insert(1, "one").is_none());
assert!(map.insert(2, "two").is_none());
assert!(map.insert(3, "three").is_none());
assert_eq!(map.len(), 3);
assert_eq!(map.get(1), Some(&"one"));
assert_eq!(map.get(2), Some(&"two"));
assert_eq!(map.get(3), Some(&"three"));
assert_eq!(map.get(4), None);
assert_eq!(map.insert(2, "TWO"), Some("two"));
assert_eq!(map.get(2), Some(&"TWO"));
assert_eq!(map.remove(2), Some("TWO"));
assert_eq!(map.get(2), None);
assert_eq!(map.len(), 2);
}
#[test]
fn test_entry_api() {
let mut map = I64Map::new();
*map.entry(1).or_insert(10) += 5;
assert_eq!(map.get(1), Some(&15));
*map.entry(1).or_insert(100) += 5;
assert_eq!(map.get(1), Some(&20));
map.entry(2).or_insert_with(|| 42);
assert_eq!(map.get(2), Some(&42));
let v: &mut i32 = map.entry(3).or_default();
*v = 99;
assert_eq!(map.get(3), Some(&99));
}
#[test]
fn test_grow() {
let mut map = I64Map::new();
for i in 0..1000 {
map.insert(i, i * 2);
}
assert_eq!(map.len(), 1000);
for i in 0..1000 {
assert_eq!(map.get(i), Some(&(i * 2)));
}
}
#[test]
fn test_edge_values() {
let mut map = I64Map::new();
map.insert(i64::MIN + 1, "near_min");
map.insert(i64::MAX, "max");
map.insert(0, "zero");
map.insert(-1, "neg one");
map.insert(1, "one");
assert_eq!(map.get(i64::MIN + 1), Some(&"near_min"));
assert_eq!(map.get(i64::MAX), Some(&"max"));
assert_eq!(map.get(0), Some(&"zero"));
assert_eq!(map.get(-1), Some(&"neg one"));
assert_eq!(map.get(1), Some(&"one"));
}
#[test]
fn test_deletion() {
let mut map = I64Map::with_capacity(16);
for i in 0..10 {
map.insert(i, i);
}
map.remove(5);
assert!(!map.contains_key(5));
for i in 0..10 {
if i != 5 {
assert_eq!(map.get(i), Some(&i));
}
}
map.insert(5, 55);
assert_eq!(map.get(5), Some(&55));
}
#[test]
fn test_clear() {
let mut map = I64Map::new();
for i in 0..100 {
map.insert(i, i);
}
map.clear();
assert!(map.is_empty());
for i in 0..100 {
assert!(!map.contains_key(i));
}
}
#[test]
fn test_iterators() {
let mut map = I64Map::new();
map.insert(1, 10);
map.insert(2, 20);
map.insert(3, 30);
let mut keys: Vec<_> = map.keys().collect();
keys.sort();
assert_eq!(keys, vec![1, 2, 3]);
let mut values: Vec<_> = map.values().copied().collect();
values.sort();
assert_eq!(values, vec![10, 20, 30]);
}
#[test]
fn test_drain() {
let mut map = I64Map::new();
map.insert(1, 10);
map.insert(2, 20);
map.insert(3, 30);
let mut drained: Vec<_> = map.drain().collect();
drained.sort_by_key(|(k, _)| *k);
assert_eq!(drained, vec![(1, 10), (2, 20), (3, 30)]);
assert!(map.is_empty());
map.insert(4, 40);
assert_eq!(map.get(4), Some(&40));
}
#[test]
fn test_shrink_after_delete() {
let mut map = I64Map::new();
for i in 0..1000 {
map.insert(i, i * 2);
}
let capacity_after_insert = map.capacity();
assert!(capacity_after_insert >= 1000);
for i in 10..1000 {
map.remove(i);
}
assert_eq!(map.len(), 10);
let capacity_after_remove = map.capacity();
assert!(
capacity_after_remove < capacity_after_insert,
"capacity should shrink: {} < {}",
capacity_after_remove,
capacity_after_insert
);
for i in 0..10 {
assert_eq!(map.get(i), Some(&(i * 2)));
}
}
#[test]
fn test_shrink_to_fit() {
let mut map: I64Map<i64> = I64Map::with_capacity(1000);
for i in 0..10 {
map.insert(i, i);
}
let initial_capacity = map.capacity();
assert!(initial_capacity >= 1000);
map.shrink_to_fit();
let after_shrink = map.capacity();
assert!(
after_shrink < initial_capacity,
"capacity should shrink: {} < {}",
after_shrink,
initial_capacity
);
for i in 0..10 {
assert_eq!(map.get(i), Some(&i));
}
}
#[test]
fn test_strided_keys_no_collision_catastrophe() {
let mut map = I64Map::with_capacity(10000);
let stride = 1024;
for i in 0..10000i64 {
map.insert(i * stride, i);
}
assert_eq!(map.len(), 10000);
for i in 0..10000i64 {
assert_eq!(map.get(i * stride), Some(&i), "Missing key {}", i * stride);
}
for i in (0..10000i64).step_by(2) {
assert_eq!(map.remove(i * stride), Some(i));
}
assert_eq!(map.len(), 5000);
for i in (1..10000i64).step_by(2) {
assert_eq!(map.get(i * stride), Some(&i));
}
}
#[test]
#[should_panic(expected = "i64::MIN cannot be used as a key")]
fn test_i64_min_panics_on_insert() {
let mut map = I64Map::<i64>::new();
map.insert(i64::MIN, 42);
}
#[test]
#[should_panic(expected = "i64::MIN cannot be used as a key")]
fn test_i64_min_panics_on_get() {
let map = I64Map::<i64>::new();
let _ = map.get(i64::MIN);
}
#[test]
#[should_panic(expected = "i64::MIN cannot be used as a key")]
fn test_i64_min_panics_on_entry() {
let mut map = I64Map::<i64>::new();
let _ = map.entry(i64::MIN);
}
#[test]
fn test_i64set_basic_operations() {
let mut set = I64Set::new();
assert!(set.insert(1));
assert!(set.insert(2));
assert!(set.insert(3));
assert_eq!(set.len(), 3);
assert!(set.contains(1));
assert!(set.contains(2));
assert!(set.contains(3));
assert!(!set.contains(4));
assert!(!set.insert(2));
assert_eq!(set.len(), 3);
assert!(set.remove(2));
assert!(!set.contains(2));
assert_eq!(set.len(), 2);
assert!(!set.remove(2));
}
#[test]
fn test_i64set_grow() {
let mut set = I64Set::new();
for i in 0..1000 {
set.insert(i);
}
assert_eq!(set.len(), 1000);
for i in 0..1000 {
assert!(set.contains(i), "Missing key {}", i);
}
}
#[test]
fn test_i64set_edge_values() {
let mut set = I64Set::new();
set.insert(i64::MIN + 1);
set.insert(i64::MAX);
set.insert(0);
set.insert(-1);
set.insert(1);
assert!(set.contains(i64::MIN + 1));
assert!(set.contains(i64::MAX));
assert!(set.contains(0));
assert!(set.contains(-1));
assert!(set.contains(1));
}
#[test]
fn test_i64set_into_iter() {
let mut set = I64Set::new();
set.insert(1);
set.insert(2);
set.insert(3);
let mut values: Vec<i64> = set.into_iter().collect();
values.sort();
assert_eq!(values, vec![1, 2, 3]);
}
#[test]
fn test_i64set_from_iter() {
let set: I64Set = vec![1, 2, 3, 2, 1].into_iter().collect();
assert_eq!(set.len(), 3);
assert!(set.contains(1));
assert!(set.contains(2));
assert!(set.contains(3));
}
#[test]
fn test_i64set_shrink_after_delete() {
let mut set = I64Set::new();
for i in 0..1000 {
set.insert(i);
}
let capacity_after_insert = set.capacity();
assert!(capacity_after_insert >= 1000);
for i in 10..1000 {
set.remove(i);
}
assert_eq!(set.len(), 10);
let capacity_after_remove = set.capacity();
assert!(
capacity_after_remove < capacity_after_insert,
"capacity should shrink: {} < {}",
capacity_after_remove,
capacity_after_insert
);
for i in 0..10 {
assert!(set.contains(i));
}
}
#[test]
fn test_i64set_shrink_to_fit() {
let mut set = I64Set::with_capacity(1000);
for i in 0..10 {
set.insert(i);
}
let initial_capacity = set.capacity();
assert!(initial_capacity >= 1000);
set.shrink_to_fit();
let after_shrink = set.capacity();
assert!(
after_shrink < initial_capacity,
"capacity should shrink: {} < {}",
after_shrink,
initial_capacity
);
for i in 0..10 {
assert!(set.contains(i));
}
}
#[test]
fn test_i64set_strided_keys() {
let mut set = I64Set::with_capacity(10000);
let stride = 1024;
for i in 0..10000i64 {
set.insert(i * stride);
}
assert_eq!(set.len(), 10000);
for i in 0..10000i64 {
assert!(set.contains(i * stride), "Missing key {}", i * stride);
}
}
#[test]
#[should_panic(expected = "i64::MIN cannot be used as a key")]
fn test_i64set_min_panics_on_insert() {
let mut set = I64Set::new();
set.insert(i64::MIN);
}
#[test]
#[should_panic(expected = "i64::MIN cannot be used as a key")]
fn test_i64set_min_panics_on_contains() {
let set = I64Set::new();
let _ = set.contains(i64::MIN);
}
}