use alloc::collections::TryReserveError;
use alloc::vec::Vec;
use core::hint::unreachable_unchecked;
use core::iter::{Enumerate, Extend, FromIterator, FusedIterator};
use core::marker::PhantomData;
use core::mem::{replace, MaybeUninit};
use core::num::NonZeroU32;
use core::ops::{Index, IndexMut};
use super::{Key, KeyData};
use crate::util::is_older_version;
#[derive(Debug, Clone)]
enum Slot<T> {
Occupied { value: T, version: NonZeroU32 },
Vacant,
}
use self::Slot::{Occupied, Vacant};
impl<T> Slot<T> {
pub fn new_occupied(version: u32, value: T) -> Self {
Occupied {
value,
version: unsafe { NonZeroU32::new_unchecked(version | 1u32) },
}
}
pub fn new_vacant() -> Self {
Vacant
}
#[inline(always)]
pub fn occupied(&self) -> bool {
match self {
Occupied { .. } => true,
Vacant => false,
}
}
#[inline(always)]
pub fn version(&self) -> u32 {
match self {
Occupied { version, .. } => version.get(),
Vacant => 0,
}
}
pub unsafe fn get_unchecked(&self) -> &T {
match self {
Occupied { value, .. } => value,
Vacant => unreachable_unchecked(),
}
}
pub unsafe fn get_unchecked_mut(&mut self) -> &mut T {
match self {
Occupied { value, .. } => value,
Vacant => unreachable_unchecked(),
}
}
pub fn into_option(self) -> Option<T> {
match self {
Occupied { value, .. } => Some(value),
Vacant => None,
}
}
}
#[derive(Debug, Clone)]
pub struct SecondaryMap<K: Key, V> {
slots: Vec<Slot<V>>,
num_elems: usize,
_k: PhantomData<fn(K) -> K>,
}
impl<K: Key, V> SecondaryMap<K, V> {
pub fn new() -> Self {
Self::with_capacity(0)
}
pub fn with_capacity(capacity: usize) -> Self {
let mut slots = Vec::with_capacity(capacity + 1); slots.push(Slot::new_vacant());
Self {
slots,
num_elems: 0,
_k: PhantomData,
}
}
pub fn len(&self) -> usize {
self.num_elems
}
pub fn is_empty(&self) -> bool {
self.num_elems == 0
}
pub fn capacity(&self) -> usize {
self.slots.capacity() - 1 }
pub fn set_capacity(&mut self, new_capacity: usize) {
let new_capacity = new_capacity + 1; if new_capacity > self.slots.capacity() {
let needed = new_capacity - self.slots.len();
self.slots.reserve(needed);
}
}
pub fn try_set_capacity(&mut self, new_capacity: usize) -> Result<(), TryReserveError> {
let new_capacity = new_capacity + 1; if new_capacity > self.slots.capacity() {
let needed = new_capacity - self.slots.len();
self.slots.try_reserve(needed)
} else {
Ok(())
}
}
pub fn contains_key(&self, key: K) -> bool {
let kd = key.data();
self.slots
.get(kd.idx as usize)
.map_or(false, |slot| slot.version() == kd.version.get())
}
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
if key.is_null() {
return None;
}
let kd = key.data();
self.slots
.extend((self.slots.len()..=kd.idx as usize).map(|_| Slot::new_vacant()));
let slot = &mut self.slots[kd.idx as usize];
if slot.version() == kd.version.get() {
return Some(replace(unsafe { slot.get_unchecked_mut() }, value));
}
if slot.occupied() {
if is_older_version(kd.version.get(), slot.version()) {
return None;
}
} else {
self.num_elems += 1;
}
*slot = Slot::new_occupied(kd.version.get(), value);
None
}
pub fn remove(&mut self, key: K) -> Option<V> {
let kd = key.data();
if let Some(slot) = self.slots.get_mut(kd.idx as usize) {
if slot.version() == kd.version.get() {
self.num_elems -= 1;
return replace(slot, Slot::new_vacant()).into_option();
}
}
None
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(K, &mut V) -> bool,
{
for (i, slot) in self.slots.iter_mut().enumerate() {
if let Occupied { value, version } = slot {
let key = KeyData::new(i as u32, version.get()).into();
if !f(key, value) {
self.num_elems -= 1;
*slot = Slot::new_vacant();
}
}
}
}
pub fn clear(&mut self) {
self.drain();
}
pub fn drain(&mut self) -> Drain<'_, K, V> {
Drain { cur: 1, sm: self }
}
pub fn get(&self, key: K) -> Option<&V> {
let kd = key.data();
self.slots
.get(kd.idx as usize)
.filter(|slot| slot.version() == kd.version.get())
.map(|slot| unsafe { slot.get_unchecked() })
}
pub unsafe fn get_unchecked(&self, key: K) -> &V {
debug_assert!(self.contains_key(key));
let slot = self.slots.get_unchecked(key.data().idx as usize);
slot.get_unchecked()
}
pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
let kd = key.data();
self.slots
.get_mut(kd.idx as usize)
.filter(|slot| slot.version() == kd.version.get())
.map(|slot| unsafe { slot.get_unchecked_mut() })
}
pub unsafe fn get_unchecked_mut(&mut self, key: K) -> &mut V {
debug_assert!(self.contains_key(key));
let slot = self.slots.get_unchecked_mut(key.data().idx as usize);
slot.get_unchecked_mut()
}
pub fn get_disjoint_mut<const N: usize>(&mut self, keys: [K; N]) -> Option<[&mut V; N]> {
let mut slot_versions: [MaybeUninit<u32>; N] = [(); N].map(|_| MaybeUninit::uninit());
let mut i = 0;
while i < N {
let kd = keys[i].data();
match self.slots.get_mut(kd.idx as usize) {
Some(Occupied { version, .. }) if *version == kd.version => {
slot_versions[i] = MaybeUninit::new(version.get());
*version = NonZeroU32::new(2).unwrap();
},
_ => break,
}
i += 1;
}
let mut ptrs: [MaybeUninit<*mut V>; N] = [(); N].map(|_| MaybeUninit::uninit());
let slots_ptr = self.slots.as_mut_ptr();
for j in 0..i {
unsafe {
let idx = keys[j].data().idx as usize;
let slot = &mut *slots_ptr.add(idx);
match slot {
Occupied { version, value } => {
ptrs[j] = MaybeUninit::new(value);
*version = NonZeroU32::new_unchecked(slot_versions[j].assume_init());
},
_ => unreachable_unchecked(),
}
}
}
if i == N {
Some(ptrs.map(|p| unsafe { &mut *p.assume_init() }))
} else {
None
}
}
pub unsafe fn get_disjoint_unchecked_mut<const N: usize>(
&mut self,
keys: [K; N],
) -> [&mut V; N] {
let slots_ptr = self.slots.as_mut_ptr();
keys.map(|k| unsafe {
let slot = &mut *slots_ptr.add(k.data().idx as usize);
slot.get_unchecked_mut()
})
}
pub fn iter(&self) -> Iter<'_, K, V> {
Iter {
num_left: self.num_elems,
slots: self.slots.iter().enumerate(),
_k: PhantomData,
}
}
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut {
num_left: self.num_elems,
slots: self.slots.iter_mut().enumerate(),
_k: PhantomData,
}
}
pub fn keys(&self) -> Keys<'_, K, V> {
Keys { inner: self.iter() }
}
pub fn values(&self) -> Values<'_, K, V> {
Values { inner: self.iter() }
}
pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
ValuesMut {
inner: self.iter_mut(),
}
}
pub fn entry(&mut self, key: K) -> Option<Entry<'_, K, V>> {
if key.is_null() {
return None;
}
let kd = key.data();
self.slots
.extend((self.slots.len()..=kd.idx as usize).map(|_| Slot::new_vacant()));
let slot = unsafe { self.slots.get_unchecked(kd.idx as usize) };
if kd.version.get() == slot.version() {
Some(Entry::Occupied(OccupiedEntry {
map: self,
kd,
_k: PhantomData,
}))
} else if is_older_version(kd.version.get(), slot.version()) {
None
} else {
Some(Entry::Vacant(VacantEntry {
map: self,
kd,
_k: PhantomData,
}))
}
}
}
impl<K: Key, V> Default for SecondaryMap<K, V> {
fn default() -> Self {
Self::new()
}
}
impl<K: Key, V> Index<K> for SecondaryMap<K, V> {
type Output = V;
fn index(&self, key: K) -> &V {
match self.get(key) {
Some(r) => r,
None => panic!("invalid SecondaryMap key used"),
}
}
}
impl<K: Key, V> IndexMut<K> for SecondaryMap<K, V> {
fn index_mut(&mut self, key: K) -> &mut V {
match self.get_mut(key) {
Some(r) => r,
None => panic!("invalid SecondaryMap key used"),
}
}
}
impl<K: Key, V: PartialEq> PartialEq for SecondaryMap<K, V> {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
self.iter().all(|(key, value)| {
other
.get(key)
.map_or(false, |other_value| *value == *other_value)
})
}
}
impl<K: Key, V: Eq> Eq for SecondaryMap<K, V> {}
impl<K: Key, V> FromIterator<(K, V)> for SecondaryMap<K, V> {
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let mut sec = Self::new();
sec.extend(iter);
sec
}
}
impl<K: Key, V> Extend<(K, V)> for SecondaryMap<K, V> {
fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
let iter = iter.into_iter();
for (k, v) in iter {
self.insert(k, v);
}
}
}
impl<'a, K: Key, V: 'a + Copy> Extend<(K, &'a V)> for SecondaryMap<K, V> {
fn extend<I: IntoIterator<Item = (K, &'a V)>>(&mut self, iter: I) {
let iter = iter.into_iter();
for (k, v) in iter {
self.insert(k, *v);
}
}
}
#[derive(Debug)]
pub struct OccupiedEntry<'a, K: Key, V> {
map: &'a mut SecondaryMap<K, V>,
kd: KeyData,
_k: PhantomData<fn(K) -> K>,
}
#[derive(Debug)]
pub struct VacantEntry<'a, K: Key, V> {
map: &'a mut SecondaryMap<K, V>,
kd: KeyData,
_k: PhantomData<fn(K) -> K>,
}
#[derive(Debug)]
pub enum Entry<'a, K: Key, V> {
Occupied(OccupiedEntry<'a, K, V>),
Vacant(VacantEntry<'a, K, V>),
}
impl<'a, K: Key, V> Entry<'a, K, V> {
pub fn or_insert(self, default: V) -> &'a mut V {
self.or_insert_with(|| default)
}
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
match self {
Entry::Occupied(x) => x.into_mut(),
Entry::Vacant(x) => x.insert(default()),
}
}
pub fn key(&self) -> K {
match self {
Entry::Occupied(entry) => entry.kd.into(),
Entry::Vacant(entry) => entry.kd.into(),
}
}
pub fn and_modify<F>(self, f: F) -> Self
where
F: FnOnce(&mut V),
{
match self {
Entry::Occupied(mut entry) => {
f(entry.get_mut());
Entry::Occupied(entry)
},
Entry::Vacant(entry) => Entry::Vacant(entry),
}
}
}
impl<'a, K: Key, V: Default> Entry<'a, K, V> {
pub fn or_default(self) -> &'a mut V {
self.or_insert_with(Default::default)
}
}
impl<'a, K: Key, V> OccupiedEntry<'a, K, V> {
pub fn key(&self) -> K {
self.kd.into()
}
pub fn remove_entry(self) -> (K, V) {
(self.kd.into(), self.remove())
}
pub fn get(&self) -> &V {
unsafe { self.map.get_unchecked(self.kd.into()) }
}
pub fn get_mut(&mut self) -> &mut V {
unsafe { self.map.get_unchecked_mut(self.kd.into()) }
}
pub fn into_mut(self) -> &'a mut V {
unsafe { self.map.get_unchecked_mut(self.kd.into()) }
}
pub fn insert(&mut self, value: V) -> V {
replace(self.get_mut(), value)
}
pub fn remove(self) -> V {
let slot = unsafe { self.map.slots.get_unchecked_mut(self.kd.idx as usize) };
self.map.num_elems -= 1;
match replace(slot, Slot::new_vacant()) {
Occupied { value, .. } => value,
Vacant => unsafe { unreachable_unchecked() },
}
}
}
impl<'a, K: Key, V> VacantEntry<'a, K, V> {
pub fn key(&self) -> K {
self.kd.into()
}
pub fn insert(self, value: V) -> &'a mut V {
let slot = unsafe { self.map.slots.get_unchecked_mut(self.kd.idx as usize) };
match replace(slot, Slot::new_occupied(self.kd.version.get(), value)) {
Occupied { .. } => {},
Vacant => self.map.num_elems += 1,
}
unsafe { slot.get_unchecked_mut() }
}
}
#[derive(Debug)]
pub struct Drain<'a, K: Key + 'a, V: 'a> {
sm: &'a mut SecondaryMap<K, V>,
cur: usize,
}
#[derive(Debug)]
pub struct IntoIter<K: Key, V> {
num_left: usize,
slots: Enumerate<alloc::vec::IntoIter<Slot<V>>>,
_k: PhantomData<fn(K) -> K>,
}
#[derive(Debug)]
pub struct Iter<'a, K: Key + 'a, V: 'a> {
num_left: usize,
slots: Enumerate<core::slice::Iter<'a, Slot<V>>>,
_k: PhantomData<fn(K) -> K>,
}
impl<'a, K: 'a + Key, V: 'a> Clone for Iter<'a, K, V> {
fn clone(&self) -> Self {
Iter {
num_left: self.num_left,
slots: self.slots.clone(),
_k: self._k,
}
}
}
#[derive(Debug)]
pub struct IterMut<'a, K: Key + 'a, V: 'a> {
num_left: usize,
slots: Enumerate<core::slice::IterMut<'a, Slot<V>>>,
_k: PhantomData<fn(K) -> K>,
}
#[derive(Debug)]
pub struct Keys<'a, K: Key + 'a, V: 'a> {
inner: Iter<'a, K, V>,
}
impl<'a, K: 'a + Key, V: 'a> Clone for Keys<'a, K, V> {
fn clone(&self) -> Self {
Keys {
inner: self.inner.clone(),
}
}
}
#[derive(Debug)]
pub struct Values<'a, K: Key + 'a, V: 'a> {
inner: Iter<'a, K, V>,
}
impl<'a, K: 'a + Key, V: 'a> Clone for Values<'a, K, V> {
fn clone(&self) -> Self {
Values {
inner: self.inner.clone(),
}
}
}
#[derive(Debug)]
pub struct ValuesMut<'a, K: Key + 'a, V: 'a> {
inner: IterMut<'a, K, V>,
}
impl<'a, K: Key, V> Iterator for Drain<'a, K, V> {
type Item = (K, V);
fn next(&mut self) -> Option<(K, V)> {
while let Some(slot) = self.sm.slots.get_mut(self.cur) {
let idx = self.cur;
self.cur += 1;
if let Occupied { value, version } = replace(slot, Slot::new_vacant()) {
self.sm.num_elems -= 1;
let key = KeyData::new(idx as u32, version.get()).into();
return Some((key, value));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.sm.len(), Some(self.sm.len()))
}
}
impl<'a, K: Key, V> Drop for Drain<'a, K, V> {
fn drop(&mut self) {
self.for_each(|_drop| {});
}
}
impl<K: Key, V> Iterator for IntoIter<K, V> {
type Item = (K, V);
fn next(&mut self) -> Option<(K, V)> {
while let Some((idx, mut slot)) = self.slots.next() {
if let Occupied { value, version } = replace(&mut slot, Slot::new_vacant()) {
self.num_left -= 1;
let key = KeyData::new(idx as u32, version.get()).into();
return Some((key, value));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.num_left, Some(self.num_left))
}
}
impl<'a, K: Key, V> Iterator for Iter<'a, K, V> {
type Item = (K, &'a V);
fn next(&mut self) -> Option<(K, &'a V)> {
while let Some((idx, slot)) = self.slots.next() {
if let Occupied { value, version } = slot {
self.num_left -= 1;
let key = KeyData::new(idx as u32, version.get()).into();
return Some((key, value));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.num_left, Some(self.num_left))
}
}
impl<'a, K: Key, V> Iterator for IterMut<'a, K, V> {
type Item = (K, &'a mut V);
fn next(&mut self) -> Option<(K, &'a mut V)> {
while let Some((idx, slot)) = self.slots.next() {
if let Occupied { value, version } = slot {
let key = KeyData::new(idx as u32, version.get()).into();
self.num_left -= 1;
return Some((key, value));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.num_left, Some(self.num_left))
}
}
impl<'a, K: Key, V> Iterator for Keys<'a, K, V> {
type Item = K;
fn next(&mut self) -> Option<K> {
self.inner.next().map(|(key, _)| key)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<'a, K: Key, V> Iterator for Values<'a, K, V> {
type Item = &'a V;
fn next(&mut self) -> Option<&'a V> {
self.inner.next().map(|(_, value)| value)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<'a, K: Key, V> Iterator for ValuesMut<'a, K, V> {
type Item = &'a mut V;
fn next(&mut self) -> Option<&'a mut V> {
self.inner.next().map(|(_, value)| value)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<'a, K: Key, V> IntoIterator for &'a SecondaryMap<K, V> {
type Item = (K, &'a V);
type IntoIter = Iter<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, K: Key, V> IntoIterator for &'a mut SecondaryMap<K, V> {
type Item = (K, &'a mut V);
type IntoIter = IterMut<'a, K, V>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<K: Key, V> IntoIterator for SecondaryMap<K, V> {
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
fn into_iter(self) -> Self::IntoIter {
let len = self.len();
let mut it = self.slots.into_iter().enumerate();
it.next(); IntoIter {
num_left: len,
slots: it,
_k: PhantomData,
}
}
}
impl<'a, K: Key, V> FusedIterator for Iter<'a, K, V> {}
impl<'a, K: Key, V> FusedIterator for IterMut<'a, K, V> {}
impl<'a, K: Key, V> FusedIterator for Keys<'a, K, V> {}
impl<'a, K: Key, V> FusedIterator for Values<'a, K, V> {}
impl<'a, K: Key, V> FusedIterator for ValuesMut<'a, K, V> {}
impl<'a, K: Key, V> FusedIterator for Drain<'a, K, V> {}
impl<K: Key, V> FusedIterator for IntoIter<K, V> {}
impl<'a, K: Key, V> ExactSizeIterator for Iter<'a, K, V> {}
impl<'a, K: Key, V> ExactSizeIterator for IterMut<'a, K, V> {}
impl<'a, K: Key, V> ExactSizeIterator for Keys<'a, K, V> {}
impl<'a, K: Key, V> ExactSizeIterator for Values<'a, K, V> {}
impl<'a, K: Key, V> ExactSizeIterator for ValuesMut<'a, K, V> {}
impl<'a, K: Key, V> ExactSizeIterator for Drain<'a, K, V> {}
impl<K: Key, V> ExactSizeIterator for IntoIter<K, V> {}
#[cfg(feature = "serde")]
mod serialize {
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use super::*;
#[derive(Serialize, Deserialize)]
struct SerdeSlot<T> {
value: Option<T>,
version: u32,
}
impl<T: Serialize> Serialize for Slot<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let serde_slot = SerdeSlot {
version: self.version(),
value: match self {
Occupied { value, .. } => Some(value),
Vacant => None,
},
};
serde_slot.serialize(serializer)
}
}
impl<'de, T> Deserialize<'de> for Slot<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let serde_slot: SerdeSlot<T> = Deserialize::deserialize(deserializer)?;
let occupied = serde_slot.version % 2 == 1;
if occupied ^ serde_slot.value.is_some() {
return Err(de::Error::custom("inconsistent occupation in Slot"));
}
Ok(match serde_slot.value {
Some(value) => Self::new_occupied(serde_slot.version, value),
None => Self::new_vacant(),
})
}
}
impl<K: Key, V: Serialize> Serialize for SecondaryMap<K, V> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.slots.serialize(serializer)
}
}
impl<'de, K: Key, V: Deserialize<'de>> Deserialize<'de> for SecondaryMap<K, V> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let mut slots: Vec<Slot<V>> = Deserialize::deserialize(deserializer)?;
if slots.len() >= (u32::MAX - 1) as usize {
return Err(de::Error::custom("too many slots"));
}
if slots.first().map_or(true, |slot| slot.occupied()) {
return Err(de::Error::custom("first slot not empty"));
}
slots[0] = Slot::new_vacant();
let num_elems = slots.iter().map(|s| s.occupied() as usize).sum();
Ok(Self {
num_elems,
slots,
_k: PhantomData,
})
}
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use quickcheck::quickcheck;
use crate::*;
#[test]
fn disjoint() {
let mut sm = SlotMap::new();
let mut sec = SecondaryMap::new();
for i in 0..20usize {
sm.insert(i);
}
sm.retain(|_, i| *i % 2 == 0);
for (i, k) in sm.keys().enumerate() {
sec.insert(k, i);
}
let keys: Vec<_> = sm.keys().collect();
for i in 0..keys.len() {
for j in 0..keys.len() {
if let Some([r0, r1]) = sec.get_disjoint_mut([keys[i], keys[j]]) {
*r0 ^= *r1;
*r1 = r1.wrapping_add(*r0);
} else {
assert!(i == j);
}
}
}
for i in 0..keys.len() {
for j in 0..keys.len() {
for k in 0..keys.len() {
if let Some([r0, r1, r2]) = sec.get_disjoint_mut([keys[i], keys[j], keys[k]]) {
*r0 ^= *r1;
*r0 = r0.wrapping_add(*r2);
*r1 ^= *r0;
*r1 = r1.wrapping_add(*r2);
*r2 ^= *r0;
*r2 = r2.wrapping_add(*r1);
} else {
assert!(i == j || j == k || i == k);
}
}
}
}
}
quickcheck! {
fn qc_secmap_equiv_hashmap(operations: Vec<(u8, u32)>) -> bool {
let mut hm = HashMap::new();
let mut hm_keys = Vec::new();
let mut unique_key = 0u32;
let mut sm = SlotMap::new();
let mut sec = SecondaryMap::new();
let mut sm_keys = Vec::new();
#[cfg(not(feature = "serde"))]
let num_ops = 4;
#[cfg(feature = "serde")]
let num_ops = 5;
for (op, val) in operations {
match op % num_ops {
0 => {
hm.insert(unique_key, val);
hm_keys.push(unique_key);
unique_key += 1;
let k = sm.insert(val);
sec.insert(k, val);
sm_keys.push(k);
}
1 => {
if hm_keys.is_empty() { continue; }
let idx = val as usize % hm_keys.len();
sm.remove(sm_keys[idx]);
if hm.remove(&hm_keys[idx]) != sec.remove(sm_keys[idx]) {
return false;
}
}
2 => {
if hm_keys.is_empty() { continue; }
let idx = val as usize % hm_keys.len();
let (hm_key, sm_key) = (&hm_keys[idx], sm_keys[idx]);
if hm.contains_key(hm_key) != sec.contains_key(sm_key) ||
hm.get(hm_key) != sec.get(sm_key) {
return false;
}
}
3 => {
sec = sec.clone();
}
#[cfg(feature = "serde")]
4 => {
let ser = serde_json::to_string(&sec).unwrap();
sec = serde_json::from_str(&ser).unwrap();
}
_ => unreachable!(),
}
}
let mut secv: Vec<_> = sec.values().collect();
let mut hmv: Vec<_> = hm.values().collect();
secv.sort();
hmv.sort();
secv == hmv
}
}
}