use core::{
borrow::Borrow,
fmt,
hash::{BuildHasher, Hash},
iter::FusedIterator,
mem,
num::NonZeroU32,
ops, slice,
};
#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
use hash32::{BuildHasherDefault, FnvHasher};
use crate::Vec;
pub type FnvIndexMap<K, V, const N: usize> = IndexMap<K, V, BuildHasherDefault<FnvHasher>, N>;
#[derive(Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "zeroize", derive(Zeroize))]
struct HashValue(u16);
impl HashValue {
fn desired_pos(&self, mask: usize) -> usize {
usize::from(self.0) & mask
}
fn probe_distance(&self, mask: usize, current: usize) -> usize {
current.wrapping_sub(self.desired_pos(mask)) & mask
}
}
#[doc(hidden)]
#[derive(Clone)]
#[cfg_attr(feature = "zeroize", derive(Zeroize))]
pub struct Bucket<K, V> {
hash: HashValue,
key: K,
value: V,
}
#[doc(hidden)]
#[derive(Clone, Copy, PartialEq)]
#[cfg_attr(feature = "zeroize", derive(Zeroize))]
pub struct Pos {
nz: NonZeroU32,
}
impl Pos {
fn new(index: usize, hash: HashValue) -> Self {
Self {
nz: unsafe {
NonZeroU32::new_unchecked(
((u32::from(hash.0) << 16) + index as u32).wrapping_add(1),
)
},
}
}
fn hash(&self) -> HashValue {
HashValue((self.nz.get().wrapping_sub(1) >> 16) as u16)
}
fn index(&self) -> usize {
self.nz.get().wrapping_sub(1) as u16 as usize
}
}
enum Insert<K, V> {
Success(Inserted<V>),
Full((K, V)),
}
struct Inserted<V> {
index: usize,
old_value: Option<V>,
}
macro_rules! probe_loop {
($probe_var: ident < $len: expr, $body: expr) => {
loop {
if $probe_var < $len {
$body
$probe_var += 1;
} else {
$probe_var = 0;
}
}
}
}
#[cfg_attr(
feature = "zeroize",
derive(Zeroize),
zeroize(bound = "K: Zeroize, V: Zeroize")
)]
struct CoreMap<K, V, const N: usize> {
entries: Vec<Bucket<K, V>, N, usize>,
indices: [Option<Pos>; N],
}
impl<K, V, const N: usize> CoreMap<K, V, N> {
const fn new() -> Self {
const INIT: Option<Pos> = None;
Self {
entries: Vec::new(),
indices: [INIT; N],
}
}
}
impl<K, V, const N: usize> CoreMap<K, V, N>
where
K: Eq + Hash,
{
fn capacity() -> usize {
N
}
fn mask() -> usize {
Self::capacity() - 1
}
fn find<Q>(&self, hash: HashValue, query: &Q) -> Option<(usize, usize)>
where
K: Borrow<Q>,
Q: ?Sized + Eq,
{
let mut probe = hash.desired_pos(Self::mask());
let mut dist = 0;
probe_loop!(probe < self.indices.len(), {
if let Some(pos) = self.indices[probe] {
let entry_hash = pos.hash();
let i = pos.index();
debug_assert!(i < self.entries.len());
if dist > entry_hash.probe_distance(Self::mask(), probe) {
return None;
} else if entry_hash == hash
&& unsafe { self.entries.get_unchecked(i).key.borrow() == query }
{
return Some((probe, i));
}
} else {
return None;
}
dist += 1;
});
}
fn insert(&mut self, hash: HashValue, key: K, value: V) -> Insert<K, V> {
let mut probe = hash.desired_pos(Self::mask());
let mut dist = 0;
probe_loop!(probe < self.indices.len(), {
let pos = &mut self.indices[probe];
if let Some(pos) = *pos {
let entry_hash = pos.hash();
let i = pos.index();
debug_assert!(i < self.entries.len());
let their_dist = entry_hash.probe_distance(Self::mask(), probe);
if their_dist < dist {
if self.entries.is_full() {
return Insert::Full((key, value));
}
let index = self.entries.len();
unsafe { self.entries.push_unchecked(Bucket { hash, key, value }) };
Self::insert_phase_2(&mut self.indices, probe, Pos::new(index, hash));
return Insert::Success(Inserted {
index,
old_value: None,
});
} else if entry_hash == hash && unsafe { self.entries.get_unchecked(i).key == key }
{
return Insert::Success(Inserted {
index: i,
old_value: Some(mem::replace(
unsafe { &mut self.entries.get_unchecked_mut(i).value },
value,
)),
});
}
} else {
if self.entries.is_full() {
return Insert::Full((key, value));
}
let index = self.entries.len();
*pos = Some(Pos::new(index, hash));
unsafe { self.entries.push_unchecked(Bucket { hash, key, value }) };
return Insert::Success(Inserted {
index,
old_value: None,
});
}
dist += 1;
});
}
fn insert_phase_2(indices: &mut [Option<Pos>; N], mut probe: usize, mut old_pos: Pos) -> usize {
probe_loop!(probe < indices.len(), {
let pos = unsafe { indices.get_unchecked_mut(probe) };
let mut is_none = true; if let Some(pos) = pos.as_mut() {
old_pos = mem::replace(pos, old_pos);
is_none = false;
}
if is_none {
*pos = Some(old_pos);
return probe;
}
});
}
fn remove_found(&mut self, probe: usize, found: usize) -> (K, V) {
self.indices[probe] = None;
let entry = unsafe { self.entries.swap_remove_unchecked(found) };
if let Some(entry) = self.entries.get(found) {
let mut probe = entry.hash.desired_pos(Self::mask());
probe_loop!(probe < self.indices.len(), {
if let Some(pos) = self.indices[probe] {
if pos.index() >= self.entries.len() {
self.indices[probe] = Some(Pos::new(found, entry.hash));
break;
}
}
});
}
self.backward_shift_after_removal(probe);
(entry.key, entry.value)
}
fn retain_in_order<F>(&mut self, mut keep: F)
where
F: FnMut(&mut K, &mut V) -> bool,
{
const INIT: Option<Pos> = None;
self.entries
.retain_mut(|entry| keep(&mut entry.key, &mut entry.value));
if self.entries.len() < self.indices.len() {
for index in self.indices.iter_mut() {
*index = INIT;
}
for (index, entry) in self.entries.iter().enumerate() {
let mut probe = entry.hash.desired_pos(Self::mask());
let mut dist = 0;
probe_loop!(probe < self.indices.len(), {
let pos = &mut self.indices[probe];
if let Some(pos) = *pos {
let entry_hash = pos.hash();
let their_dist = entry_hash.probe_distance(Self::mask(), probe);
if their_dist < dist {
Self::insert_phase_2(
&mut self.indices,
probe,
Pos::new(index, entry.hash),
);
break;
}
} else {
*pos = Some(Pos::new(index, entry.hash));
break;
}
dist += 1;
});
}
}
}
fn backward_shift_after_removal(&mut self, probe_at_remove: usize) {
let mut last_probe = probe_at_remove;
let mut probe = probe_at_remove + 1;
probe_loop!(probe < self.indices.len(), {
if let Some(pos) = self.indices[probe] {
let entry_hash = pos.hash();
if entry_hash.probe_distance(Self::mask(), probe) > 0 {
unsafe { *self.indices.get_unchecked_mut(last_probe) = self.indices[probe] }
self.indices[probe] = None;
} else {
break;
}
} else {
break;
}
last_probe = probe;
});
}
}
impl<K, V, const N: usize> Clone for CoreMap<K, V, N>
where
K: Clone,
V: Clone,
{
fn clone(&self) -> Self {
Self {
entries: self.entries.clone(),
indices: self.indices,
}
}
}
pub enum Entry<'a, K, V, const N: usize> {
Occupied(OccupiedEntry<'a, K, V, N>),
Vacant(VacantEntry<'a, K, V, N>),
}
impl<'a, K, V, const N: usize> Entry<'a, K, V, N>
where
K: Eq + Hash,
{
pub fn or_insert(self, default: V) -> Result<&'a mut V, V> {
match self {
Self::Occupied(entry) => Ok(entry.into_mut()),
Self::Vacant(entry) => entry.insert(default),
}
}
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> Result<&'a mut V, V> {
match self {
Self::Occupied(entry) => Ok(entry.into_mut()),
Self::Vacant(entry) => entry.insert(default()),
}
}
pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> Result<&'a mut V, V> {
match self {
Self::Occupied(entry) => Ok(entry.into_mut()),
Self::Vacant(entry) => {
let value = default(entry.key());
entry.insert(value)
}
}
}
pub fn key(&self) -> &K {
match *self {
Self::Occupied(ref entry) => entry.key(),
Self::Vacant(ref entry) => entry.key(),
}
}
pub fn and_modify<F>(self, f: F) -> Self
where
F: FnOnce(&mut V),
{
match self {
Self::Occupied(mut entry) => {
f(entry.get_mut());
Self::Occupied(entry)
}
Self::Vacant(entry) => Self::Vacant(entry),
}
}
}
impl<'a, K, V, const N: usize> Entry<'a, K, V, N>
where
K: Eq + Hash,
V: Default,
{
#[inline]
pub fn or_default(self) -> Result<&'a mut V, V> {
match self {
Self::Occupied(entry) => Ok(entry.into_mut()),
Self::Vacant(entry) => entry.insert(Default::default()),
}
}
}
pub struct OccupiedEntry<'a, K, V, const N: usize> {
key: K,
probe: usize,
pos: usize,
core: &'a mut CoreMap<K, V, N>,
}
impl<'a, K, V, const N: usize> OccupiedEntry<'a, K, V, N>
where
K: Eq + Hash,
{
pub fn key(&self) -> &K {
&self.key
}
pub fn remove_entry(self) -> (K, V) {
self.core.remove_found(self.probe, self.pos)
}
pub fn get(&self) -> &V {
unsafe { &self.core.entries.get_unchecked(self.pos).value }
}
pub fn get_mut(&mut self) -> &mut V {
unsafe { &mut self.core.entries.get_unchecked_mut(self.pos).value }
}
pub fn into_mut(self) -> &'a mut V {
unsafe { &mut self.core.entries.get_unchecked_mut(self.pos).value }
}
pub fn insert(self, value: V) -> V {
unsafe {
mem::replace(
&mut self.core.entries.get_unchecked_mut(self.pos).value,
value,
)
}
}
pub fn remove(self) -> V {
self.remove_entry().1
}
}
pub struct VacantEntry<'a, K, V, const N: usize> {
key: K,
hash_val: HashValue,
core: &'a mut CoreMap<K, V, N>,
}
impl<'a, K, V, const N: usize> VacantEntry<'a, K, V, N>
where
K: Eq + Hash,
{
pub fn key(&self) -> &K {
&self.key
}
pub fn into_key(self) -> K {
self.key
}
pub fn insert(self, value: V) -> Result<&'a mut V, V> {
if self.core.entries.is_full() {
Err(value)
} else {
match self.core.insert(self.hash_val, self.key, value) {
Insert::Success(inserted) => {
unsafe {
Ok(&mut (*self.core.entries.as_mut_ptr().add(inserted.index)).value)
}
}
Insert::Full((_, v)) => Err(v),
}
}
}
}
#[cfg_attr(
feature = "zeroize",
derive(Zeroize),
zeroize(bound = "K: Zeroize, V: Zeroize")
)]
pub struct IndexMap<K, V, S, const N: usize> {
core: CoreMap<K, V, N>,
#[cfg_attr(feature = "zeroize", zeroize(skip))]
build_hasher: S,
}
impl<K, V, S, const N: usize> IndexMap<K, V, BuildHasherDefault<S>, N> {
pub const fn new() -> Self {
const {
assert!(N > 1);
assert!(N.is_power_of_two());
}
Self {
build_hasher: BuildHasherDefault::new(),
core: CoreMap::new(),
}
}
}
impl<K, V, S, const N: usize> IndexMap<K, V, S, N> {
pub fn capacity(&self) -> usize {
N
}
pub fn keys(&self) -> Keys<'_, K, V> {
Keys {
iter: self.core.entries.iter(),
}
}
pub fn values(&self) -> Values<'_, K, V> {
Values {
iter: self.core.entries.iter(),
}
}
pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
ValuesMut {
iter: self.core.entries.iter_mut(),
}
}
pub fn iter(&self) -> Iter<'_, K, V> {
Iter {
iter: self.core.entries.iter(),
}
}
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut {
iter: self.core.entries.iter_mut(),
}
}
pub fn first(&self) -> Option<(&K, &V)> {
self.core
.entries
.first()
.map(|bucket| (&bucket.key, &bucket.value))
}
pub fn first_mut(&mut self) -> Option<(&K, &mut V)> {
self.core
.entries
.first_mut()
.map(|bucket| (&bucket.key, &mut bucket.value))
}
pub fn last(&self) -> Option<(&K, &V)> {
self.core
.entries
.last()
.map(|bucket| (&bucket.key, &bucket.value))
}
pub fn last_mut(&mut self) -> Option<(&K, &mut V)> {
self.core
.entries
.last_mut()
.map(|bucket| (&bucket.key, &mut bucket.value))
}
pub fn len(&self) -> usize {
self.core.entries.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn is_full(&self) -> bool {
self.len() == self.capacity()
}
pub fn clear(&mut self) {
self.core.entries.clear();
for pos in self.core.indices.iter_mut() {
*pos = None;
}
}
}
impl<K, V, S, const N: usize> IndexMap<K, V, S, N>
where
K: Eq + Hash,
S: BuildHasher,
{
pub fn entry(&mut self, key: K) -> Entry<'_, K, V, N> {
let hash_val = hash_with(&key, &self.build_hasher);
if let Some((probe, pos)) = self.core.find(hash_val, &key) {
Entry::Occupied(OccupiedEntry {
key,
probe,
pos,
core: &mut self.core,
})
} else {
Entry::Vacant(VacantEntry {
key,
hash_val,
core: &mut self.core,
})
}
}
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.find(key)
.map(|(_, found)| unsafe { &self.core.entries.get_unchecked(found).value })
}
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q>,
Q: ?Sized + Eq + Hash,
{
self.find(key).is_some()
}
pub fn get_mut<'v, Q>(&'v mut self, key: &Q) -> Option<&'v mut V>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
if let Some((_, found)) = self.find(key) {
Some(unsafe { &mut self.core.entries.get_unchecked_mut(found).value })
} else {
None
}
}
pub fn get_index(&self, index: usize) -> Option<(&K, &V)> {
self.core
.entries
.get(index)
.map(|entry| (&entry.key, &entry.value))
}
pub fn get_index_mut(&mut self, index: usize) -> Option<(&K, &mut V)> {
self.core
.entries
.get_mut(index)
.map(|entry| (&entry.key, &mut entry.value))
}
pub fn get_index_of<Q>(&self, key: &Q) -> Option<usize>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.find(key).map(|(_, found)| found)
}
pub fn insert(&mut self, key: K, value: V) -> Result<Option<V>, (K, V)> {
let hash = hash_with(&key, &self.build_hasher);
match self.core.insert(hash, key, value) {
Insert::Success(inserted) => Ok(inserted.old_value),
Insert::Full((k, v)) => Err((k, v)),
}
}
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.swap_remove(key)
}
pub fn swap_remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.find(key)
.map(|(probe, found)| self.core.remove_found(probe, found).1)
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&K, &mut V) -> bool,
{
self.core.retain_in_order(move |k, v| f(k, v));
}
pub fn truncate(&mut self, len: usize) {
self.core.entries.truncate(len);
if self.core.indices.len() > self.core.entries.len() {
for index in self.core.indices.iter_mut() {
match index {
Some(pos) if pos.index() >= len => *index = None,
_ => (),
}
}
}
}
fn find<Q>(&self, key: &Q) -> Option<(usize, usize)>
where
K: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
if self.is_empty() {
return None;
}
let h = hash_with(key, &self.build_hasher);
self.core.find(h, key)
}
}
impl<K, Q, V, S, const N: usize> ops::Index<&Q> for IndexMap<K, V, S, N>
where
K: Eq + Hash + Borrow<Q>,
Q: ?Sized + Eq + Hash,
S: BuildHasher,
{
type Output = V;
fn index(&self, key: &Q) -> &V {
self.get(key).expect("key not found")
}
}
impl<K, Q, V, S, const N: usize> ops::IndexMut<&Q> for IndexMap<K, V, S, N>
where
K: Eq + Hash + Borrow<Q>,
Q: ?Sized + Eq + Hash,
S: BuildHasher,
{
fn index_mut(&mut self, key: &Q) -> &mut V {
self.get_mut(key).expect("key not found")
}
}
impl<K, V, S, const N: usize> Clone for IndexMap<K, V, S, N>
where
K: Clone,
V: Clone,
S: Clone,
{
fn clone(&self) -> Self {
Self {
core: self.core.clone(),
build_hasher: self.build_hasher.clone(),
}
}
}
impl<K, V, S, const N: usize> fmt::Debug for IndexMap<K, V, S, N>
where
K: fmt::Debug,
V: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
impl<K, V, S, const N: usize> Default for IndexMap<K, V, S, N>
where
S: Default,
{
fn default() -> Self {
const {
assert!(N > 1);
assert!(N.is_power_of_two());
}
Self {
build_hasher: <_>::default(),
core: CoreMap::new(),
}
}
}
impl<K, V1, V2, S1, S2, const N1: usize, const N2: usize> PartialEq<IndexMap<K, V2, S2, N2>>
for IndexMap<K, V1, S1, N1>
where
K: Eq + Hash,
V1: PartialEq<V2>,
S1: BuildHasher,
S2: BuildHasher,
{
fn eq(&self, other: &IndexMap<K, V2, S2, N2>) -> bool {
self.len() == other.len()
&& self
.iter()
.all(|(key, value)| other.get(key).is_some_and(|v| *value == *v))
}
}
impl<K, V, S, const N: usize> Eq for IndexMap<K, V, S, N>
where
K: Eq + Hash,
V: Eq,
S: BuildHasher,
{
}
impl<K, V, S, const N: usize> Extend<(K, V)> for IndexMap<K, V, S, N>
where
K: Eq + Hash,
S: BuildHasher,
{
fn extend<I>(&mut self, iterable: I)
where
I: IntoIterator<Item = (K, V)>,
{
for (k, v) in iterable {
self.insert(k, v).ok().unwrap();
}
}
}
impl<'a, K, V, S, const N: usize> Extend<(&'a K, &'a V)> for IndexMap<K, V, S, N>
where
K: Eq + Hash + Copy,
V: Copy,
S: BuildHasher,
{
fn extend<I>(&mut self, iterable: I)
where
I: IntoIterator<Item = (&'a K, &'a V)>,
{
self.extend(iterable.into_iter().map(|(&key, &value)| (key, value)));
}
}
impl<K, V, S, const N: usize> FromIterator<(K, V)> for IndexMap<K, V, S, N>
where
K: Eq + Hash,
S: BuildHasher + Default,
{
fn from_iter<I>(iterable: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
{
let mut map = Self::default();
map.extend(iterable);
map
}
}
#[derive(Clone)]
pub struct IntoIter<K, V, const N: usize> {
entries: Vec<Bucket<K, V>, N, usize>,
}
impl<K, V, const N: usize> Iterator for IntoIter<K, V, N> {
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
self.entries.pop().map(|bucket| (bucket.key, bucket.value))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl<K, V, const N: usize> FusedIterator for IntoIter<K, V, N> {}
impl<K, V, const N: usize> ExactSizeIterator for IntoIter<K, V, N> {
fn len(&self) -> usize {
self.entries.len()
}
}
impl<K, V, S, const N: usize> IntoIterator for IndexMap<K, V, S, N> {
type Item = (K, V);
type IntoIter = IntoIter<K, V, N>;
fn into_iter(self) -> Self::IntoIter {
IntoIter {
entries: self.core.entries,
}
}
}
impl<'a, K, V, S, const N: usize> IntoIterator for &'a IndexMap<K, V, S, N> {
type Item = (&'a K, &'a V);
type IntoIter = Iter<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, K, V, S, const N: usize> IntoIterator for &'a mut IndexMap<K, V, S, N> {
type Item = (&'a K, &'a mut V);
type IntoIter = IterMut<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
pub struct Iter<'a, K, V> {
iter: slice::Iter<'a, Bucket<K, V>>,
}
impl<'a, K, V> Iterator for Iter<'a, K, V> {
type Item = (&'a K, &'a V);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|bucket| (&bucket.key, &bucket.value))
}
}
impl<K, V> Clone for Iter<'_, K, V> {
fn clone(&self) -> Self {
Self {
iter: self.iter.clone(),
}
}
}
pub struct IterMut<'a, K, V> {
iter: slice::IterMut<'a, Bucket<K, V>>,
}
impl<'a, K, V> Iterator for IterMut<'a, K, V> {
type Item = (&'a K, &'a mut V);
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|bucket| (&bucket.key, &mut bucket.value))
}
}
pub struct Keys<'a, K, V> {
iter: slice::Iter<'a, Bucket<K, V>>,
}
impl<'a, K, V> Iterator for Keys<'a, K, V> {
type Item = &'a K;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|bucket| &bucket.key)
}
}
pub struct Values<'a, K, V> {
iter: slice::Iter<'a, Bucket<K, V>>,
}
impl<'a, K, V> Iterator for Values<'a, K, V> {
type Item = &'a V;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|bucket| &bucket.value)
}
}
pub struct ValuesMut<'a, K, V> {
iter: slice::IterMut<'a, Bucket<K, V>>,
}
impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
type Item = &'a mut V;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|bucket| &mut bucket.value)
}
}
fn hash_with<K, S>(key: &K, build_hasher: &S) -> HashValue
where
K: ?Sized + Hash,
S: BuildHasher,
{
HashValue(build_hasher.hash_one(key) as u16)
}
#[cfg(test)]
mod tests {
use core::mem;
use static_assertions::assert_not_impl_any;
use super::{BuildHasherDefault, Entry, FnvIndexMap, IndexMap};
assert_not_impl_any!(IndexMap<*const (), (), BuildHasherDefault<()>, 4>: Send);
assert_not_impl_any!(IndexMap<(), *const (), BuildHasherDefault<()>, 4>: Send);
#[test]
fn size() {
const CAP: usize = 4;
assert_eq!(
mem::size_of::<FnvIndexMap<i16, u16, CAP>>(),
CAP * mem::size_of::<u32>() + CAP * (mem::size_of::<i16>() + mem::size_of::<u16>() + mem::size_of::<u16>() ) + mem::size_of::<usize>() );
}
#[test]
fn partial_eq() {
{
let mut a: FnvIndexMap<_, _, 4> = FnvIndexMap::new();
a.insert("k1", "v1").unwrap();
let mut b: FnvIndexMap<_, _, 4> = FnvIndexMap::new();
b.insert("k1", "v1").unwrap();
assert!(a == b);
b.insert("k2", "v2").unwrap();
assert!(a != b);
}
{
let mut a: FnvIndexMap<_, _, 4> = FnvIndexMap::new();
a.insert("k1", "v1").unwrap();
a.insert("k2", "v2").unwrap();
let mut b: FnvIndexMap<_, _, 4> = FnvIndexMap::new();
b.insert("k2", "v2").unwrap();
b.insert("k1", "v1").unwrap();
assert!(a == b);
}
}
#[test]
fn entry_or_insert() {
let mut a: FnvIndexMap<_, _, 2> = FnvIndexMap::new();
a.entry("k1").or_insert("v1").unwrap();
assert_eq!(a["k1"], "v1");
a.entry("k2").or_insert("v2").unwrap();
assert_eq!(a["k2"], "v2");
let result = a.entry("k3").or_insert("v3");
assert_eq!(result, Err("v3"));
}
#[test]
fn entry_or_insert_with() {
let mut a: FnvIndexMap<_, _, 2> = FnvIndexMap::new();
a.entry("k1").or_insert_with(|| "v1").unwrap();
assert_eq!(a["k1"], "v1");
a.entry("k2").or_insert_with(|| "v2").unwrap();
assert_eq!(a["k2"], "v2");
let result = a.entry("k3").or_insert_with(|| "v3");
assert_eq!(result, Err("v3"));
}
#[test]
fn entry_or_insert_with_key() {
let mut a: FnvIndexMap<_, _, 2> = FnvIndexMap::new();
a.entry("k1")
.or_insert_with_key(|key| key.chars().count())
.unwrap();
assert_eq!(a["k1"], 2);
a.entry("k22")
.or_insert_with_key(|key| key.chars().count())
.unwrap();
assert_eq!(a["k22"], 3);
let result = a.entry("k3").or_insert_with_key(|key| key.chars().count());
assert_eq!(result, Err(2));
}
#[test]
fn entry_key() {
let mut a: FnvIndexMap<&str, &str, 2> = FnvIndexMap::new();
assert_eq!(a.entry("k1").key(), &"k1");
}
#[test]
fn entry_and_modify() {
let mut a: FnvIndexMap<_, _, 2> = FnvIndexMap::new();
a.insert("k1", "v1").unwrap();
a.entry("k1").and_modify(|e| *e = "modified v1");
assert_eq!(a["k1"], "modified v1");
a.entry("k2")
.and_modify(|e| *e = "v2")
.or_insert("default v2")
.unwrap();
assert_eq!(a["k2"], "default v2");
}
#[test]
fn entry_or_default() {
let mut a: FnvIndexMap<&str, Option<u32>, 2> = FnvIndexMap::new();
a.entry("k1").or_default().unwrap();
assert_eq!(a["k1"], None);
let mut b: FnvIndexMap<&str, u8, 2> = FnvIndexMap::new();
b.entry("k2").or_default().unwrap();
assert_eq!(b["k2"], 0);
}
#[test]
fn into_iter() {
let mut src: FnvIndexMap<_, _, 4> = FnvIndexMap::new();
src.insert("k1", "v1").unwrap();
src.insert("k2", "v2").unwrap();
src.insert("k3", "v3").unwrap();
src.insert("k4", "v4").unwrap();
let clone = src.clone();
for (k, v) in clone.into_iter() {
assert_eq!(v, src.remove(k).unwrap());
}
assert!(src.is_empty());
}
#[test]
fn into_iter_len() {
let mut src: FnvIndexMap<_, _, 2> = FnvIndexMap::new();
src.insert("k1", "v1").unwrap();
src.insert("k2", "v2").unwrap();
let mut items = src.into_iter();
assert_eq!(items.len(), 2);
let _ = items.next();
assert_eq!(items.len(), 1);
let _ = items.next();
assert_eq!(items.len(), 0);
}
#[test]
fn insert_replaces_on_full_map() {
let mut a: FnvIndexMap<_, _, 2> = FnvIndexMap::new();
a.insert("k1", "v1").unwrap();
a.insert("k2", "v2").unwrap();
a.insert("k1", "v2").unwrap();
assert_eq!(a.get("k1"), a.get("k2"));
}
#[cfg(not(any(miri, target_os = "vxworks")))]
const MAP_SLOTS: usize = 4096;
#[cfg(target_os = "vxworks")]
const MAP_SLOTS: usize = 1024;
#[cfg(miri)]
const MAP_SLOTS: usize = 64;
fn almost_filled_map() -> FnvIndexMap<usize, usize, MAP_SLOTS> {
let mut almost_filled = FnvIndexMap::new();
for i in 1..MAP_SLOTS {
almost_filled.insert(i, i).unwrap();
}
almost_filled
}
#[test]
fn entry_find() {
let key = 0;
let value = 0;
let mut src = almost_filled_map();
let entry = src.entry(key);
match entry {
Entry::Occupied(_) => {
panic!("Found entry without inserting");
}
Entry::Vacant(v) => {
assert_eq!(&key, v.key());
assert_eq!(key, v.into_key());
}
}
src.insert(key, value).unwrap();
let entry = src.entry(key);
match entry {
Entry::Occupied(mut o) => {
assert_eq!(&key, o.key());
assert_eq!(&value, o.get());
assert_eq!(&value, o.get_mut());
assert_eq!(&value, o.into_mut());
}
Entry::Vacant(_) => {
panic!("Entry not found");
}
}
}
#[test]
fn entry_vacant_insert() {
let key = 0;
let value = 0;
let mut src = almost_filled_map();
assert_eq!(MAP_SLOTS - 1, src.len());
let entry = src.entry(key);
match entry {
Entry::Occupied(_) => {
panic!("Entry found when empty");
}
Entry::Vacant(v) => {
assert_eq!(value, *v.insert(value).unwrap());
}
};
assert_eq!(value, *src.get(&key).unwrap());
}
#[test]
fn entry_occupied_insert() {
let key = 0;
let value = 0;
let value2 = 5;
let mut src = almost_filled_map();
assert_eq!(MAP_SLOTS - 1, src.len());
src.insert(key, value).unwrap();
let entry = src.entry(key);
match entry {
Entry::Occupied(o) => {
assert_eq!(value, o.insert(value2));
}
Entry::Vacant(_) => {
panic!("Entry not found");
}
};
assert_eq!(value2, *src.get(&key).unwrap());
}
#[test]
fn entry_remove_entry() {
let key = 0;
let value = 0;
let mut src = almost_filled_map();
src.insert(key, value).unwrap();
assert_eq!(MAP_SLOTS, src.len());
let entry = src.entry(key);
match entry {
Entry::Occupied(o) => {
assert_eq!((key, value), o.remove_entry());
}
Entry::Vacant(_) => {
panic!("Entry not found")
}
};
assert_eq!(MAP_SLOTS - 1, src.len());
}
#[test]
fn entry_remove() {
let key = 0;
let value = 0;
let mut src = almost_filled_map();
src.insert(key, value).unwrap();
assert_eq!(MAP_SLOTS, src.len());
let entry = src.entry(key);
match entry {
Entry::Occupied(o) => {
assert_eq!(value, o.remove());
}
Entry::Vacant(_) => {
panic!("Entry not found");
}
};
assert_eq!(MAP_SLOTS - 1, src.len());
}
#[test]
fn retain() {
let mut none = almost_filled_map();
none.retain(|_, _| false);
assert!(none.is_empty());
let mut all = almost_filled_map();
all.retain(|_, _| true);
assert_eq!(all.len(), MAP_SLOTS - 1);
let mut even = almost_filled_map();
even.retain(|_, &mut v| v.is_multiple_of(2));
assert_eq!(even.len(), (MAP_SLOTS - 1) / 2);
for &v in even.values() {
assert_eq!(v % 2, 0);
}
let mut odd = almost_filled_map();
odd.retain(|_, &mut v| !v.is_multiple_of(2));
assert_eq!(odd.len(), MAP_SLOTS / 2);
for &v in odd.values() {
assert_ne!(v % 2, 0);
}
assert_eq!(odd.insert(2, 2), Ok(None));
assert_eq!(odd.len(), (MAP_SLOTS / 2) + 1);
}
#[test]
fn entry_roll_through_all() {
let mut src: FnvIndexMap<usize, usize, MAP_SLOTS> = FnvIndexMap::new();
for i in 0..MAP_SLOTS {
match src.entry(i) {
Entry::Occupied(_) => {
panic!("Entry found before insert");
}
Entry::Vacant(v) => {
assert_eq!(i, *v.insert(i).unwrap());
}
}
}
let add_mod = 99;
for i in 0..MAP_SLOTS {
match src.entry(i) {
Entry::Occupied(o) => {
assert_eq!(i, o.insert(i + add_mod));
}
Entry::Vacant(_) => {
panic!("Entry not found after insert");
}
}
}
for i in 0..MAP_SLOTS {
match src.entry(i) {
Entry::Occupied(o) => {
assert_eq!((i, i + add_mod), o.remove_entry());
}
Entry::Vacant(_) => {
panic!("Entry not found after insert");
}
}
}
for i in 0..MAP_SLOTS {
assert!(matches!(src.entry(i), Entry::Vacant(_)));
}
assert!(src.is_empty());
}
#[test]
fn first_last() {
let mut map = FnvIndexMap::<_, _, 4>::new();
assert_eq!(None, map.first());
assert_eq!(None, map.last());
map.insert(0, 0).unwrap();
map.insert(2, 2).unwrap();
assert_eq!(Some((&0, &0)), map.first());
assert_eq!(Some((&2, &2)), map.last());
map.insert(1, 1).unwrap();
assert_eq!(Some((&1, &1)), map.last());
*map.first_mut().unwrap().1 += 1;
*map.last_mut().unwrap().1 += 1;
assert_eq!(Some((&0, &1)), map.first());
assert_eq!(Some((&1, &2)), map.last());
}
#[test]
fn keys_iter() {
let map = almost_filled_map();
for (&key, i) in map.keys().zip(1..MAP_SLOTS) {
assert_eq!(key, i);
}
}
#[test]
fn values_iter() {
let map = almost_filled_map();
for (&value, i) in map.values().zip(1..MAP_SLOTS) {
assert_eq!(value, i);
}
}
#[test]
fn values_mut_iter() {
let mut map = almost_filled_map();
for value in map.values_mut() {
*value += 1;
}
for (&value, i) in map.values().zip(1..MAP_SLOTS) {
assert_eq!(value, i + 1);
}
}
#[test]
fn partial_eq_floats() {
let map: FnvIndexMap<usize, f32, 4> = Default::default();
assert_eq!(map, map);
}
#[test]
#[cfg(feature = "zeroize")]
fn test_index_map_zeroize() {
use zeroize::Zeroize;
let mut map: FnvIndexMap<u8, u8, 8> = FnvIndexMap::new();
for i in 1..=8 {
map.insert(i, i * 10).unwrap();
}
assert_eq!(map.len(), 8);
assert!(!map.is_empty());
map.zeroize();
assert_eq!(map.len(), 0);
assert!(map.is_empty());
map.insert(1, 10).unwrap();
assert_eq!(map.len(), 1);
assert_eq!(map.get(&1), Some(&10));
}
}