use std::borrow::Borrow;
use std::fmt::Debug;
use std::hash::{BuildHasher, Hash, Hasher};
use std::iter::{FromIterator, FusedIterator};
use std::marker::PhantomData;
use std::mem::{ManuallyDrop, MaybeUninit};
use std::ops::Index;
use crate::pair::Pair;
use crate::alloc::{Allocator, Layout, XLangAlloc};
use crate::hash::{BuildHasherDefault, XLangHasher};
use crate::ptr::Unique;
#[repr(C)]
struct HashMapSlot<K, V> {
ecount: usize,
entries: [MaybeUninit<Pair<K, V>>; 16],
}
#[repr(C)]
pub struct HashMap<
K,
V,
H: BuildHasher = BuildHasherDefault<XLangHasher>,
A: Allocator = XLangAlloc,
> {
htab: Unique<HashMapSlot<K, V>>,
buckets: usize,
hash: H,
alloc: A,
}
impl<K, V, H: BuildHasher, A: Allocator> Drop for HashMap<K, V, H, A> {
fn drop(&mut self) {
for i in 0..self.buckets {
let bucket = unsafe { &mut *self.htab.as_ptr().add(i) };
for i in 0..bucket.ecount {
unsafe { core::ptr::drop_in_place(bucket.entries[i].as_mut_ptr()) }
}
}
if self.buckets != 0 {
unsafe {
self.alloc.deallocate(
self.htab.as_nonnull().cast(),
Layout::array::<HashMapSlot<K, V>>(self.buckets).unwrap(),
);
}
}
}
}
impl<K, V, H: BuildHasher + Default, A: Allocator + Default> HashMap<K, V, H, A> {
#[must_use]
pub fn new() -> Self {
Self {
htab: Unique::dangling(),
buckets: 0,
hash: Default::default(),
alloc: Default::default(),
}
}
}
impl<K, V, H: BuildHasher + Default, A: Allocator + Default> Default for HashMap<K, V, H, A> {
fn default() -> Self {
Self::new()
}
}
impl<K, V, H: BuildHasher + Default, A: Allocator> HashMap<K, V, H, A> {
pub fn new_in(alloc: A) -> Self {
Self {
htab: Unique::dangling(),
buckets: 0,
hash: Default::default(),
alloc,
}
}
}
impl<K, V, H: BuildHasher, A: Allocator + Default> HashMap<K, V, H, A> {
pub fn with_hasher(hash: H) -> Self {
Self {
htab: Unique::dangling(),
buckets: 0,
hash,
alloc: Default::default(),
}
}
}
impl<K, V, H: BuildHasher, A: Allocator> HashMap<K, V, H, A> {
pub fn with_hasher_in(hash: H, alloc: A) -> Self {
Self {
htab: Unique::dangling(),
buckets: 0,
hash,
alloc,
}
}
pub fn iter(&self) -> Iter<'_, K, V> {
Iter(
unsafe { core::slice::from_raw_parts(self.htab.as_ptr(), self.buckets) }.iter(),
None,
)
}
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
let begin = self.htab.as_ptr();
let end = unsafe { begin.add(self.buckets) };
IterMut {
buckets: begin,
buckets_end: end,
bucket_position: 0,
phantom: PhantomData,
}
}
pub fn values(&self) -> Values<'_, K, V> {
Values(self.iter())
}
pub fn keys(&self) -> Keys<'_, K, V> {
Keys(self.iter())
}
}
impl<K: Eq + Hash, V, H: BuildHasher, A: Allocator> HashMap<K, V, H, A> {
#[allow(clippy::similar_names)]
fn rehash(&mut self) {
let ocount = self.buckets;
let ncount = self.buckets * 2;
assert!(
ncount <= (std::isize::MAX as usize),
"We have too many buckets, bail before we maybe cause UB"
);
let ptr = self
.alloc
.allocate_zeroed(Layout::array::<HashMapSlot<K, V>>(ncount).unwrap())
.unwrap_or_else(|| {
crate::alloc::handle_alloc_error(Layout::array::<HashMapSlot<K, V>>(16).unwrap())
});
let ptr = core::mem::replace(&mut self.htab, unsafe {
Unique::new_nonnull_unchecked(ptr.cast())
});
self.buckets = ncount;
for i in 0..self.buckets {
let bucket = unsafe { &mut *ptr.as_ptr().add(i) };
for i in 0..bucket.ecount {
let Pair(key, value) = unsafe { bucket.entries[i].as_ptr().read() };
self.insert(key, value).unwrap();
}
}
unsafe {
self.alloc.deallocate(
ptr.as_nonnull().cast(),
Layout::array::<HashMapSlot<K, V>>(ocount).unwrap(),
);
}
}
#[allow(clippy::cast_possible_truncation, clippy::missing_panics_doc)]
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
if self.buckets == 0 {
let ptr = self
.alloc
.allocate_zeroed(Layout::array::<HashMapSlot<K, V>>(16).unwrap())
.unwrap_or_else(|| {
crate::alloc::handle_alloc_error(
Layout::array::<HashMapSlot<K, V>>(16).unwrap(),
)
});
self.htab = unsafe { Unique::new_nonnull_unchecked(ptr.cast()) };
self.buckets = 16;
}
loop {
let mut hasher = self.hash.build_hasher();
key.hash(&mut hasher);
let hash = hasher.finish() as usize % self.buckets;
let bucket = unsafe { &mut *self.htab.as_ptr().add(hash) };
for i in 0..bucket.ecount {
let key_val = unsafe { &mut *bucket.entries.get_unchecked_mut(i).as_mut_ptr() };
if key_val.0.eq(&key) {
return Some(core::mem::replace(&mut key_val.1, value));
}
}
if bucket.ecount == 16 {
self.rehash();
continue;
}
unsafe {
bucket.entries[bucket.ecount]
.as_mut_ptr()
.write(Pair(key, value));
}
bucket.ecount += 1;
return None;
}
}
#[allow(clippy::cast_possible_truncation, clippy::missing_panics_doc)]
pub fn get_or_insert_mut(&mut self, key: K, value: V) -> &mut V {
if self.buckets == 0 {
let ptr = self
.alloc
.allocate_zeroed(Layout::array::<HashMapSlot<K, V>>(16).unwrap())
.unwrap_or_else(|| {
crate::alloc::handle_alloc_error(
Layout::array::<HashMapSlot<K, V>>(16).unwrap(),
)
});
self.htab = unsafe { Unique::new_nonnull_unchecked(ptr.cast()) };
self.buckets = 16;
}
loop {
let mut hasher = self.hash.build_hasher();
key.hash(&mut hasher);
let hash = hasher.finish() as usize % self.buckets;
let bucket = unsafe { &mut *self.htab.as_ptr().add(hash) };
for i in 0..bucket.ecount {
let key_val = unsafe { &mut *bucket.entries.get_unchecked_mut(i).as_mut_ptr() };
if key_val.0.eq(&key) {
return &mut key_val.1;
}
}
if bucket.ecount == 16 {
self.rehash();
continue;
}
unsafe {
bucket.entries[bucket.ecount]
.as_mut_ptr()
.write(Pair(key, value));
}
bucket.ecount += 1;
return &mut unsafe { &mut *bucket.entries[bucket.ecount - 1].as_mut_ptr() }.1;
}
}
#[allow(clippy::cast_possible_truncation, clippy::missing_panics_doc)]
pub fn get_or_insert_with_mut<F: FnOnce(&K) -> V>(&mut self, key: K, value: F) -> &mut V {
if self.buckets == 0 {
let ptr = self
.alloc
.allocate_zeroed(Layout::array::<HashMapSlot<K, V>>(16).unwrap()) .unwrap_or_else(|| {
crate::alloc::handle_alloc_error(
Layout::array::<HashMapSlot<K, V>>(16).unwrap(),
)
});
self.htab = unsafe { Unique::new_nonnull_unchecked(ptr.cast()) };
self.buckets = 16;
}
loop {
let mut hasher = self.hash.build_hasher();
key.hash(&mut hasher);
let hash = hasher.finish() as usize % self.buckets;
let bucket = unsafe { &mut *self.htab.as_ptr().add(hash) };
for i in 0..bucket.ecount {
let key_val = unsafe { &mut *bucket.entries.get_unchecked_mut(i).as_mut_ptr() };
if key_val.0.eq(&key) {
return &mut key_val.1;
}
}
if bucket.ecount == 16 {
self.rehash();
continue;
}
let value = value(&key);
unsafe {
bucket.entries[bucket.ecount]
.as_mut_ptr()
.write(Pair(key, value));
}
bucket.ecount += 1;
return &mut unsafe { &mut *bucket.entries[bucket.ecount - 1].as_mut_ptr() }.1;
}
}
#[allow(clippy::cast_possible_truncation)]
pub fn get<Q: ?Sized + Hash + Eq>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
{
if self.buckets == 0 {
return None;
}
let mut hasher = self.hash.build_hasher();
key.hash(&mut hasher);
let hash = hasher.finish() as usize % self.buckets;
let bucket = unsafe { &mut *self.htab.as_ptr().add(hash) };
for i in 0..bucket.ecount {
let key_val = unsafe { &*bucket.entries.get_unchecked_mut(i).as_mut_ptr() };
if key_val.0.borrow().eq(key) {
return Some(&key_val.1);
}
}
None
}
#[allow(clippy::cast_possible_truncation)]
pub fn get_mut<Q: ?Sized + Hash + Eq>(&mut self, key: &Q) -> Option<&mut V>
where
K: Borrow<Q>,
{
if self.buckets == 0 {
return None;
}
let mut hasher = self.hash.build_hasher();
key.hash(&mut hasher);
let hash = hasher.finish() as usize % self.buckets;
let bucket = unsafe { &mut *self.htab.as_ptr().add(hash) };
for i in 0..bucket.ecount {
let key_val = unsafe { &mut *bucket.entries.get_unchecked_mut(i).as_mut_ptr() };
if key_val.0.borrow().eq(key) {
return Some(&mut key_val.1);
}
}
None
}
#[allow(clippy::cast_possible_truncation)]
pub fn remove<Q: ?Sized + Hash + Eq>(&mut self, key: &Q) -> Option<Pair<K, V>>
where
K: Borrow<Q>,
{
if self.buckets == 0 {
return None;
}
let mut hasher = self.hash.build_hasher();
key.hash(&mut hasher);
let hash = hasher.finish() as usize % self.buckets;
let bucket = unsafe { &mut *self.htab.as_ptr().add(hash) };
for i in 0..bucket.ecount {
let key_val = unsafe { &mut *bucket.entries.get_unchecked_mut(i).as_mut_ptr() };
if key_val.0.borrow().eq(key) {
let val = unsafe { core::ptr::read(key_val) };
bucket.ecount -= 1;
for j in i..bucket.ecount {
unsafe {
core::ptr::write(
bucket.entries.as_mut_ptr().add(j),
core::ptr::read(bucket.entries.as_mut_ptr().add(j + 1)),
);
}
}
return Some(val);
}
}
None
}
}
impl<K: Clone, V: Clone, H: BuildHasher + Clone, A: Allocator + Clone> Clone
for HashMap<K, V, H, A>
{
#[allow(clippy::similar_names)]
fn clone(&self) -> Self {
let buckets = self.buckets;
let hash = self.hash.clone();
let alloc = self.alloc.clone();
let htab = alloc
.allocate_zeroed(Layout::array::<HashMapSlot<K, V>>(buckets).unwrap())
.unwrap()
.cast::<HashMapSlot<K, V>>();
let ptr = htab.as_ptr();
for i in 0..buckets {
let bucket = unsafe { &mut *ptr.add(i) };
let obucket = unsafe { &*self.htab.as_ptr().add(i) };
for j in 0..obucket.ecount {
unsafe {
bucket.entries[j]
.as_mut_ptr()
.write((&*obucket.entries[j].as_ptr()).clone());
}
}
bucket.ecount = obucket.ecount;
}
Self {
htab: unsafe { Unique::new_nonnull_unchecked(htab) },
buckets,
hash,
alloc,
}
}
}
impl<K, V, A: Allocator, H: BuildHasher> IntoIterator for HashMap<K, V, H, A> {
type Item = Pair<K, V>;
type IntoIter = IntoIter<K, V, A>;
fn into_iter(self) -> Self::IntoIter {
let mut this = ManuallyDrop::new(self);
let htab = unsafe { core::ptr::read(core::ptr::addr_of!(this.htab)) };
let buckets = this.buckets;
let alloc = unsafe { core::ptr::read(core::ptr::addr_of!(this.alloc)) };
unsafe { core::ptr::drop_in_place(core::ptr::addr_of_mut!(this.hash)) };
IntoIter {
htab,
buckets,
alloc,
pos: (0, 0),
}
}
}
pub struct IntoIter<K, V, A: Allocator> {
htab: Unique<HashMapSlot<K, V>>,
buckets: usize,
alloc: A,
pos: (usize, usize),
}
impl<K, V, A: Allocator> Drop for IntoIter<K, V, A> {
fn drop(&mut self) {
if core::mem::needs_drop::<Pair<K, V>>() {
for i in &mut *self {
core::mem::drop(i);
}
}
unsafe {
self.alloc.deallocate(
self.htab.as_nonnull().cast(),
Layout::array::<HashMapSlot<K, V>>(self.buckets).unwrap(),
);
}
}
}
impl<K, V, A: Allocator> Iterator for IntoIter<K, V, A> {
type Item = Pair<K, V>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let (bucket, pos) = self.pos;
if bucket >= self.buckets {
break None;
}
let slot = unsafe { &mut *self.htab.as_ptr().add(bucket) };
if pos >= slot.ecount {
self.pos = (bucket + 1, 0);
continue;
}
self.pos = (bucket, pos + 1);
break Some(unsafe { core::ptr::read(slot.entries.as_ptr().add(pos).cast()) });
}
}
}
pub struct Iter<'a, K, V>(
core::slice::Iter<'a, HashMapSlot<K, V>>,
Option<(&'a HashMapSlot<K, V>, usize)>,
);
impl<'a, K, V> Iter<'a, K, V> {
fn current_slot(&mut self) -> std::option::Option<(&'a HashMapSlot<K, V>, usize)> {
if let Some((slot, offset)) = self.1 {
Some((slot, offset))
} else {
let x = self.0.next()?;
self.1 = Some((x, 0));
Some((x, 0))
}
}
}
#[allow(clippy::borrow_as_ptr)]
impl<'a, K, V> Iterator for Iter<'a, K, V> {
type Item = &'a Pair<K, V>;
fn next(&mut self) -> Option<Self::Item> {
let (mut slot, mut offset) = self.current_slot()?;
while offset == slot.ecount {
slot = self.0.next()?;
offset = 0;
self.1 = Some((slot, 0));
}
self.1.as_mut().unwrap().1 += 1;
Some(unsafe {
&*(&slot.entries[offset] as *const MaybeUninit<Pair<K, V>>).cast::<Pair<K, V>>()
})
}
}
pub struct Values<'a, K, V>(Iter<'a, K, V>);
impl<'a, K, V> Iterator for Values<'a, K, V> {
type Item = &'a V;
fn next(&mut self) -> Option<Self::Item> {
match self.0.next() {
Some(Pair(_, v)) => Some(v),
None => None,
}
}
}
pub struct Keys<'a, K, V>(Iter<'a, K, V>);
impl<'a, K, V> Iterator for Keys<'a, K, V> {
type Item = &'a K;
fn next(&mut self) -> Option<Self::Item> {
match self.0.next() {
Some(Pair(k, _)) => Some(k),
None => None,
}
}
}
impl<'a, K, V, H: BuildHasher, A: Allocator> IntoIterator for &'a HashMap<K, V, H, A> {
type Item = &'a Pair<K, V>;
type IntoIter = Iter<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, K, V, H: BuildHasher, A: Allocator> IntoIterator for &'a mut HashMap<K, V, H, A> {
type Item = Pair<&'a K, &'a mut V>;
type IntoIter = IterMut<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<K: Hash, V: Hash, H: BuildHasher, A: Allocator> Hash for HashMap<K, V, H, A> {
fn hash<P: Hasher>(&self, state: &mut P) {
for i in self {
i.hash(state);
}
}
}
impl<K: Debug, V: Debug, H: BuildHasher, A: Allocator> Debug for HashMap<K, V, H, A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_map()
.entries(self.iter().map(|Pair(k, v)| (k, v)))
.finish()
}
}
impl<'a, K: Eq + Hash, V, Q: Eq + Hash + 'a, H: BuildHasher, A: Allocator> Index<&'a Q>
for HashMap<K, V, H, A>
where
K: Borrow<Q>,
{
type Output = V;
fn index(&self, idx: &'a Q) -> &V {
self.get(idx).unwrap()
}
}
impl<K: Eq + Hash, V: PartialEq, H: BuildHasher, A: Allocator> PartialEq for HashMap<K, V, H, A> {
fn eq(&self, other: &Self) -> bool {
if core::ptr::eq(self, other) {
return true;
}
for Pair(k, v) in self {
if other.get(k).map_or(false, |v2| v.eq(v2)) {
return false;
}
}
for Pair(k, v) in other {
if self.get(k).map_or(false, |v2| v.eq(v2)) {
return false;
}
}
true
}
}
impl<K: Eq + Hash, V: Eq, H: BuildHasher, A: Allocator> Eq for HashMap<K, V, H, A> {}
impl<K: Eq + Hash, V, H: BuildHasher + Default, A: Allocator + Default> FromIterator<Pair<K, V>>
for HashMap<K, V, H, A>
{
fn from_iter<I>(it: I) -> Self
where
I: IntoIterator<Item = Pair<K, V>>,
{
let mut ret = Self::new();
for Pair(k, v) in it {
ret.insert(k, v);
}
ret
}
}
impl<K: Eq + Hash, V, H: BuildHasher, A: Allocator> Extend<Pair<K, V>> for HashMap<K, V, H, A> {
fn extend<I>(&mut self, it: I)
where
I: IntoIterator<Item = Pair<K, V>>,
{
for Pair(k, v) in it {
self.insert(k, v);
}
}
}
impl<K: Eq + Hash, V, H: BuildHasher + Default, A: Allocator + Default> FromIterator<(K, V)>
for HashMap<K, V, H, A>
{
fn from_iter<I>(it: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
{
let mut ret = Self::new();
for (k, v) in it {
ret.insert(k, v);
}
ret
}
}
impl<K: Eq + Hash, V, H: BuildHasher, A: Allocator> Extend<(K, V)> for HashMap<K, V, H, A> {
fn extend<I>(&mut self, it: I)
where
I: IntoIterator<Item = (K, V)>,
{
for (k, v) in it {
self.insert(k, v);
}
}
}
pub struct IterMut<'a, K, V> {
buckets: *mut HashMapSlot<K, V>,
buckets_end: *mut HashMapSlot<K, V>,
bucket_position: usize,
phantom: PhantomData<&'a mut [HashMapSlot<K, V>]>,
}
impl<'a, K, V> IterMut<'a, K, V> {
fn next_item(&mut self) -> Option<&'a mut Pair<K, V>> {
if self.buckets == self.buckets_end {
None
} else {
let mut ecount = unsafe { (*self.buckets).ecount };
let mut entries =
unsafe { core::ptr::addr_of_mut!((*self.buckets).entries) }.cast::<Pair<K, V>>();
while self.bucket_position >= ecount {
self.bucket_position = 0;
self.buckets = unsafe { self.buckets.offset(1) };
if self.buckets == self.buckets_end {
return None;
}
ecount = unsafe { (*self.buckets).ecount };
entries = unsafe { core::ptr::addr_of_mut!((*self.buckets).entries) }
.cast::<Pair<K, V>>();
}
let ret = unsafe { entries.add(self.bucket_position) };
self.bucket_position += 1;
Some(unsafe { &mut *ret })
}
}
}
impl<'a, K, V> Iterator for IterMut<'a, K, V> {
type Item = Pair<&'a K, &'a mut V>;
fn next(&mut self) -> Option<Self::Item> {
self.next_item().map(|Pair(k, v)| Pair(k as &K, v))
}
}
impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
pub struct ValuesMut<'a, K, V>(IterMut<'a, K, V>);
impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
type Item = &'a mut V;
fn next(&mut self) -> Option<&'a mut V> {
self.0.next().map(|Pair(_, v)| v)
}
}
#[derive(
Clone, Debug /* may not be good to derive(Debug) here. Maybe should provide impl instead */,
)]
pub struct HashSet<K, H: BuildHasher = BuildHasherDefault<XLangHasher>, A: Allocator = XLangAlloc> {
inner: HashMap<K, (), H, A>,
}
impl<K: Eq + Hash, H: BuildHasher, A: Allocator> PartialEq for HashSet<K, H, A> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<K: Eq + Hash, H: BuildHasher, A: Allocator> Eq for HashSet<K, H, A> {}
impl<K: Eq + Hash, H: BuildHasher, A: Allocator> Hash for HashSet<K, H, A> {
fn hash<Hash: Hasher>(&self, hasher: &mut Hash) {
self.inner.hash(hasher);
}
}
impl<K, H: BuildHasher + Default, A: Allocator + Default> HashSet<K, H, A> {
#[must_use]
pub fn new() -> Self {
Self {
inner: HashMap::new(),
}
}
}
impl<K, H: BuildHasher + Default, A: Allocator + Default> Default for HashSet<K, H, A> {
fn default() -> Self {
Self::new()
}
}
impl<K, H: BuildHasher, A: Allocator + Default> HashSet<K, H, A> {
#[must_use]
pub fn with_hasher(hasher: H) -> Self {
Self {
inner: HashMap::with_hasher(hasher),
}
}
}
impl<K, H: BuildHasher + Default, A: Allocator> HashSet<K, H, A> {
#[must_use]
pub fn new_in(alloc: A) -> Self {
Self {
inner: HashMap::new_in(alloc),
}
}
}
impl<K, H: BuildHasher, A: Allocator> HashSet<K, H, A> {
#[must_use]
pub fn with_hasher_in(hasher: H, alloc: A) -> Self {
Self {
inner: HashMap::with_hasher_in(hasher, alloc),
}
}
pub fn iter(&self) -> SetIter<'_, K> {
SetIter(self.inner.keys())
}
}
impl<K: Eq + Hash, H: BuildHasher, A: Allocator> HashSet<K, H, A> {
pub fn contains<Q: ?Sized + Hash + Eq>(&self, val: &Q) -> bool
where
K: Borrow<Q>,
{
self.inner.get(val).is_some()
}
#[allow(clippy::missing_errors_doc)] pub fn insert(&mut self, val: K) -> Result<(), K> {
if self.inner.get(&val).is_some() {
Err(val)
} else {
self.inner.insert(val, ());
Ok(())
}
}
pub fn remove<Q: ?Sized + Hash + Eq>(&mut self, val: &Q) -> Option<K>
where
K: Borrow<Q>,
{
self.inner.remove(val).map(|Pair(k, _)| k)
}
}
impl<K: Eq + Hash, H: BuildHasher + Default, A: Allocator + Default> FromIterator<K>
for HashSet<K, H, A>
{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = K>,
{
let mut out = Self::new();
for item in iter {
drop(out.insert(item));
}
out
}
}
impl<K: Eq + Hash, H: BuildHasher + Default, A: Allocator + Default> Extend<K>
for HashSet<K, H, A>
{
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = K>,
{
for item in iter {
drop(self.insert(item));
}
}
}
#[macro_export]
macro_rules! set{
{$($expr:expr),*} => {{
let __array = [$($expr),*];
$crate::collection::HashSet::from_iter(::core::iter::IntoIterator::into_iter(__array))
}}
}
pub struct SetIter<'a, K>(Keys<'a, K, ()>);
impl<'a, K> Iterator for SetIter<'a, K> {
type Item = &'a K;
fn next(&mut self) -> Option<&'a K> {
self.0.next()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_hash_map_get() {
let mut map = HashMap::<&str, i32>::new();
map.insert("Hi", 0);
assert_eq!(map.get("Hi"), Some(&0));
}
#[test]
fn test_hash_map_missing() {
let mut map = HashMap::<&str, i32>::new();
map.insert("Hi", 0);
assert_eq!(map.get("Bye"), None);
}
#[test]
fn test_hash_map_iter_count() {
let mut map = HashMap::<&str, i32>::new();
map.insert("Hi", 0);
map.insert("Hello", 1);
assert_eq!(map.iter().count(), 2);
}
#[test]
fn test_hash_map_iter_mut_count() {
let mut map = HashMap::<&str, i32>::new();
map.insert("Hi", 0);
map.insert("Hello", 1);
assert_eq!(map.iter_mut().count(), 2);
}
#[test]
fn test_hash_map_iter_mut_count1() {
let mut map = HashMap::<&str, i32>::new();
map.insert("Hi", 0);
assert_eq!(map.iter_mut().count(), 1);
}
#[test]
fn test_hash_map_iter_present() {
let mut map = HashMap::<&str, i32>::new();
map.insert("Hi", 0);
map.insert("Hello", 1);
let mut iter = map.iter();
assert!(iter.any(|Pair(s, _)| *s == "Hi"));
assert!(!iter.any(|Pair(s, _)| *s == "Hi"));
}
#[test]
fn test_hash_map_iter_present2() {
let mut map = HashMap::<&str, i32>::new();
map.insert("Hi", 0);
map.insert("Hello", 1);
let mut iter = map.iter();
assert!(iter.any(|Pair(s, _)| *s == "Hello"));
assert!(!iter.any(|Pair(s, _)| *s == "Hello"));
}
#[test]
fn test_hash_map_clone() {
let mut map = HashMap::<&str, i32>::new();
map.insert("Hi", 0);
map.insert("Hello", 1);
let map2 = map.clone();
let mut iter = map2.iter();
assert!(iter.any(|Pair(s, _)| *s == "Hello"));
assert!(!iter.any(|Pair(s, _)| *s == "Hello"));
}
#[test]
fn test_hash_map_into_iter_count() {
let mut map = HashMap::<&str, i32>::new();
map.insert("Hi", 0);
map.insert("Hello", 1);
let iter = map.into_iter();
assert_eq!(iter.count(), 2);
}
#[test]
fn test_hash_map_into_iter() {
let mut map = HashMap::<&str, i32>::new();
map.insert("Hi", 0);
map.insert("Hello", 1);
let mut iter = map.into_iter();
assert!(iter.any(|Pair(s, _)| s == "Hello"));
}
#[test]
fn test_hash_map_remove() {
let mut map = HashMap::<String, String>::new();
map.insert("Hello".to_string(), "World".to_string());
assert!(map.remove("Hello").unwrap() == Pair("Hello", "World"));
}
#[test]
fn test_hash_map_remove_and_drop() {
let mut map = HashMap::<String, String>::new();
map.insert("Hello".to_string(), "World".to_string());
map.insert("Goodbye".to_string(), "Universe".to_string());
assert!(map.remove("Hello").unwrap() == Pair("Hello", "World"));
}
#[test]
fn test_hash_map_add_a_whole_hecking_lot_of_random_data() {
let mut map = HashMap::<u8, u8>::new();
let mut vals = Vec::<u8>::new();
for i in 0u8..=255 {
let val = i.wrapping_mul(37);
vals.push(val);
map.insert(i, val);
}
for i in 0..=255 {
assert!(map[&i] == vals[i as usize]);
}
}
}