#![allow(unused_unsafe)]
use std;
use std::iter::{Enumerate, FusedIterator};
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ops::{Index, IndexMut};
use std::{fmt, ptr};
use super::{DefaultKey, Key, KeyData, Slottable};
union SlotUnion<T: Slottable> {
value: ManuallyDrop<T>,
next_free: u32,
}
struct Slot<T: Slottable> {
u: SlotUnion<T>,
version: u32, }
enum SlotContent<'a, T: 'a + Slottable> {
Occupied(&'a T),
Vacant(&'a u32),
}
enum SlotContentMut<'a, T: 'a + Slottable> {
OccupiedMut(&'a mut T),
VacantMut(&'a mut u32),
}
use self::SlotContent::{Occupied, Vacant};
use self::SlotContentMut::{OccupiedMut, VacantMut};
impl<T: Slottable> Slot<T> {
#[inline(always)]
pub fn occupied(&self) -> bool {
self.version % 2 > 0
}
pub fn get(&self) -> SlotContent<T> {
unsafe {
if self.occupied() {
Occupied(&*self.u.value)
} else {
Vacant(&self.u.next_free)
}
}
}
pub fn get_mut(&mut self) -> SlotContentMut<T> {
unsafe {
if self.occupied() {
OccupiedMut(&mut *self.u.value)
} else {
VacantMut(&mut self.u.next_free)
}
}
}
}
impl<T: Slottable> Drop for Slot<T> {
fn drop(&mut self) {
if std::mem::needs_drop::<T>() && self.occupied() {
unsafe {
ManuallyDrop::drop(&mut self.u.value);
}
}
}
}
impl<T: Clone + Slottable> Clone for Slot<T> {
fn clone(&self) -> Self {
Self {
u: match self.get() {
Occupied(value) => SlotUnion {
value: ManuallyDrop::new(value.clone()),
},
Vacant(&next_free) => SlotUnion { next_free },
},
version: self.version,
}
}
}
impl<T: fmt::Debug + Slottable> fmt::Debug for Slot<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let mut builder = fmt.debug_struct("Slot");
builder.field("version", &self.version);
match self.get() {
Occupied(value) => builder.field("value", value).finish(),
Vacant(next_free) => builder.field("next_free", next_free).finish(),
}
}
}
#[derive(Debug, Clone)]
pub struct SlotMap<K: Key, V: Slottable> {
slots: Vec<Slot<V>>,
free_head: usize,
num_elems: u32,
_k: PhantomData<fn(K) -> K>,
}
impl<V: Slottable> SlotMap<DefaultKey, V> {
pub fn new() -> Self {
Self::with_capacity_and_key(0)
}
pub fn with_capacity(capacity: usize) -> Self {
Self::with_capacity_and_key(capacity)
}
}
impl<K: Key, V: Slottable> SlotMap<K, V> {
pub fn with_key() -> Self {
Self::with_capacity_and_key(0)
}
pub fn with_capacity_and_key(capacity: usize) -> Self {
let mut slots = Vec::with_capacity(capacity + 1);
slots.push(Slot {
u: SlotUnion { next_free: 0 },
version: 0,
});
Self {
slots,
free_head: 1,
num_elems: 0,
_k: PhantomData,
}
}
pub fn len(&self) -> usize {
self.num_elems as usize
}
pub fn is_empty(&self) -> bool {
self.num_elems == 0
}
pub fn capacity(&self) -> usize {
self.slots.capacity() - 1
}
pub fn reserve(&mut self, additional: usize) {
let needed = (self.len() + additional).saturating_sub(self.slots.len() - 1);
self.slots.reserve(needed);
}
pub fn contains_key(&self, key: K) -> bool {
let key = key.into();
self.slots
.get(key.idx as usize)
.map_or(false, |slot| slot.version == key.version.get())
}
pub fn insert(&mut self, value: V) -> K {
self.insert_with_key(|_| value)
}
pub fn insert_with_key<F>(&mut self, f: F) -> K
where
F: FnOnce(K) -> V,
{
let new_num_elems = self.num_elems + 1;
if new_num_elems == std::u32::MAX {
panic!("SlotMap number of elements overflow");
}
let idx = self.free_head;
if let Some(slot) = self.slots.get_mut(idx) {
let occupied_version = slot.version | 1;
let key = KeyData::new(idx as u32, occupied_version);
let value = f(key.into());
self.free_head = unsafe { slot.u.next_free as usize };
self.num_elems = new_num_elems;
unsafe {
slot.u.value = ManuallyDrop::new(value);
}
slot.version = occupied_version;
return key.into();
}
let key = KeyData::new(idx as u32, 1);
self.slots.push(Slot {
u: SlotUnion {
value: ManuallyDrop::new(f(key.into())),
},
version: 1,
});
self.free_head = self.slots.len();
self.num_elems = new_num_elems;
key.into()
}
#[inline(always)]
unsafe fn remove_from_slot(&mut self, idx: usize) -> V {
let slot = self.slots.get_unchecked_mut(idx);
let value = ptr::read(&*slot.u.value);
slot.u.next_free = self.free_head as u32;
self.free_head = idx;
self.num_elems -= 1;
slot.version = slot.version.wrapping_add(1);
value
}
pub fn remove(&mut self, key: K) -> Option<V> {
let key = key.into();
if self.contains_key(key.into()) {
Some(unsafe { self.remove_from_slot(key.idx as usize) })
} else {
None
}
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(K, &mut V) -> bool,
{
let len = self.slots.len();
for i in 1..len {
let should_remove = {
let slot = unsafe { self.slots.get_unchecked_mut(i) };
let version = slot.version;
if let OccupiedMut(value) = slot.get_mut() {
let key = KeyData::new(i as u32, version).into();
!f(key, value)
} else {
false
}
};
if should_remove {
unsafe { self.remove_from_slot(i) };
}
}
}
pub fn clear(&mut self) {
self.drain();
}
pub fn drain(&mut self) -> Drain<K, V> {
Drain {
cur: 1,
num_left: self.len(),
sm: self,
}
}
pub fn get(&self, key: K) -> Option<&V> {
let key = key.into();
self.slots
.get(key.idx as usize)
.filter(|slot| slot.version == key.version.get())
.map(|slot| unsafe { &*slot.u.value })
}
pub unsafe fn get_unchecked(&self, key: K) -> &V {
let key = key.into();
&self.slots.get_unchecked(key.idx as usize).u.value
}
pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
let key = key.into();
self.slots
.get_mut(key.idx as usize)
.filter(|slot| slot.version == key.version.get())
.map(|slot| unsafe { &mut *slot.u.value })
}
pub unsafe fn get_unchecked_mut(&mut self, key: K) -> &mut V {
let key = key.into();
&mut self.slots.get_unchecked_mut(key.idx as usize).u.value
}
pub fn iter(&self) -> Iter<K, V> {
let mut it = self.slots.iter().enumerate();
it.next(); Iter {
slots: it,
num_left: self.len(),
_k: PhantomData,
}
}
pub fn iter_mut(&mut self) -> IterMut<K, V> {
let len = self.len();
let mut it = self.slots.iter_mut().enumerate();
it.next(); IterMut {
num_left: len,
slots: it,
_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(),
}
}
}
impl<K: Key, V: Slottable> Default for SlotMap<K, V> {
fn default() -> Self {
Self::with_key()
}
}
impl<K: Key, V: Slottable> Index<K> for SlotMap<K, V> {
type Output = V;
fn index(&self, key: K) -> &V {
match self.get(key) {
Some(r) => r,
None => panic!("invalid SlotMap key used"),
}
}
}
impl<K: Key, V: Slottable> IndexMut<K> for SlotMap<K, V> {
fn index_mut(&mut self, key: K) -> &mut V {
match self.get_mut(key) {
Some(r) => r,
None => panic!("invalid SlotMap key used"),
}
}
}
#[derive(Debug)]
pub struct Drain<'a, K: 'a + Key, V: 'a + Slottable> {
num_left: usize,
sm: &'a mut SlotMap<K, V>,
cur: usize,
}
#[derive(Debug)]
pub struct IntoIter<K: Key, V: Slottable> {
num_left: usize,
slots: Enumerate<std::vec::IntoIter<Slot<V>>>,
_k: PhantomData<fn(K) -> K>,
}
#[derive(Debug)]
pub struct Iter<'a, K: 'a + Key, V: 'a + Slottable> {
num_left: usize,
slots: Enumerate<std::slice::Iter<'a, Slot<V>>>,
_k: PhantomData<fn(K) -> K>,
}
#[derive(Debug)]
pub struct IterMut<'a, K: 'a + Key, V: 'a + Slottable> {
num_left: usize,
slots: Enumerate<std::slice::IterMut<'a, Slot<V>>>,
_k: PhantomData<fn(K) -> K>,
}
#[derive(Debug)]
pub struct Keys<'a, K: 'a + Key, V: 'a + Slottable> {
inner: Iter<'a, K, V>,
}
#[derive(Debug)]
pub struct Values<'a, K: 'a + Key, V: 'a + Slottable> {
inner: Iter<'a, K, V>,
}
#[derive(Debug)]
pub struct ValuesMut<'a, K: 'a + Key, V: 'a + Slottable> {
inner: IterMut<'a, K, V>,
}
impl<'a, K: Key, V: Slottable> Iterator for Drain<'a, K, V> {
type Item = (K, V);
fn next(&mut self) -> Option<(K, V)> {
let len = self.sm.slots.len();
while self.cur < len {
let idx = self.cur;
self.cur += 1;
unsafe {
if self.sm.slots.get_unchecked(idx).occupied() {
let key = KeyData::new(idx as u32, self.sm.slots.get_unchecked(idx).version);
self.num_left -= 1;
return Some((key.into(), self.sm.remove_from_slot(idx)));
}
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.num_left, Some(self.num_left))
}
}
impl<'a, K: Key, V: Slottable> Drop for Drain<'a, K, V> {
fn drop(&mut self) {
self.for_each(|_drop| {});
}
}
impl<K: Key, V: Slottable> 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 slot.occupied() {
let key = KeyData::new(idx as u32, slot.version);
slot.version = 0;
self.num_left -= 1;
return Some((key.into(), unsafe { ptr::read(&*slot.u.value) }));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.num_left, Some(self.num_left))
}
}
impl<'a, K: Key, V: Slottable> 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) = slot.get() {
let key = KeyData::new(idx as u32, slot.version);
self.num_left -= 1;
return Some((key.into(), value));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.num_left, Some(self.num_left))
}
}
impl<'a, K: Key, V: Slottable> 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() {
let version = slot.version;
if let OccupiedMut(value) = slot.get_mut() {
let key = KeyData::new(idx as u32, version);
self.num_left -= 1;
return Some((key.into(), value));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.num_left, Some(self.num_left))
}
}
impl<'a, K: Key, V: Slottable> 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: Slottable> 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: Slottable> 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: Slottable> IntoIterator for &'a SlotMap<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: Slottable> IntoIterator for &'a mut SlotMap<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: Slottable> IntoIterator for SlotMap<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: Slottable> FusedIterator for Iter<'a, K, V> {}
impl<'a, K: Key, V: Slottable> FusedIterator for IterMut<'a, K, V> {}
impl<'a, K: Key, V: Slottable> FusedIterator for Keys<'a, K, V> {}
impl<'a, K: Key, V: Slottable> FusedIterator for Values<'a, K, V> {}
impl<'a, K: Key, V: Slottable> FusedIterator for ValuesMut<'a, K, V> {}
impl<'a, K: Key, V: Slottable> FusedIterator for Drain<'a, K, V> {}
impl<K: Key, V: Slottable> FusedIterator for IntoIter<K, V> {}
impl<'a, K: Key, V: Slottable> ExactSizeIterator for Iter<'a, K, V> {}
impl<'a, K: Key, V: Slottable> ExactSizeIterator for IterMut<'a, K, V> {}
impl<'a, K: Key, V: Slottable> ExactSizeIterator for Keys<'a, K, V> {}
impl<'a, K: Key, V: Slottable> ExactSizeIterator for Values<'a, K, V> {}
impl<'a, K: Key, V: Slottable> ExactSizeIterator for ValuesMut<'a, K, V> {}
impl<'a, K: Key, V: Slottable> ExactSizeIterator for Drain<'a, K, V> {}
impl<K: Key, V: Slottable> ExactSizeIterator for IntoIter<K, V> {}
#[cfg(feature = "serde")]
mod serialize {
use super::*;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[derive(Serialize, Deserialize)]
struct SerdeSlot<T> {
value: Option<T>,
version: u32,
}
impl<T: Serialize + Slottable> 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.get() {
Occupied(value) => Some(value),
Vacant(_) => None,
},
};
serde_slot.serialize(serializer)
}
}
impl<'de, T> Deserialize<'de> for Slot<T>
where
T: Deserialize<'de> + Slottable,
{
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 > 0;
if occupied ^ serde_slot.value.is_some() {
return Err(de::Error::custom(&"inconsistent occupation in Slot"));
}
Ok(Self {
u: match serde_slot.value {
Some(value) => SlotUnion {
value: ManuallyDrop::new(value),
},
None => SlotUnion { next_free: 0 },
},
version: serde_slot.version,
})
}
}
impl<K: Key, V: Serialize + Slottable> Serialize for SlotMap<K, V> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.slots.serialize(serializer)
}
}
impl<'de, K, V> Deserialize<'de> for SlotMap<K, V>
where
K: Key,
V: Deserialize<'de> + Slottable,
{
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() >= (1 << 32) - 1 {
return Err(de::Error::custom(&"too many slots"));
}
if slots.get(0).map_or(true, |slot| slot.version % 2 > 0) {
return Err(de::Error::custom(&"first slot not empty"));
}
slots[0].version = 0;
slots[0].u.next_free = 0;
let mut num_elems = 0;
let mut next_free = slots.len();
for (i, slot) in slots[1..].iter_mut().enumerate() {
if slot.occupied() {
num_elems += 1;
} else {
slot.u.next_free = next_free as u32;
next_free = i + 1;
}
}
Ok(Self {
num_elems,
slots,
free_head: next_free,
_k: PhantomData,
})
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[cfg(feature = "serde")]
use serde_json;
#[cfg(feature = "unstable")]
#[test]
fn check_drops() {
let drops = std::cell::RefCell::new(0usize);
#[derive(Clone)]
struct CountDrop<'a>(&'a std::cell::RefCell<usize>);
impl<'a> Drop for CountDrop<'a> {
fn drop(&mut self) {
*self.0.borrow_mut() += 1;
}
}
{
let mut clone = {
let mut sm = SlotMap::new();
let mut sm_keys = Vec::new();
for _ in 0..1000 {
sm_keys.push(sm.insert(CountDrop(&drops)));
}
for i in (0..1000).filter(|i| i % 2 == 0) {
sm.remove(sm_keys[i]);
}
assert_eq!(*drops.borrow(), 500);
sm.clone()
};
assert_eq!(*drops.borrow(), 1000);
for _ in 0..250 {
clone.insert(CountDrop(&drops));
}
}
assert_eq!(*drops.borrow(), 1750);
}
quickcheck! {
fn qc_slotmap_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 sm_keys = Vec::new();
#[cfg(not(feature = "serde"))]
let num_ops = 3;
#[cfg(feature = "serde")]
let num_ops = 4;
for (op, val) in operations {
match op % num_ops {
0 => {
hm.insert(unique_key, val);
hm_keys.push(unique_key);
unique_key += 1;
sm_keys.push(sm.insert(val));
}
1 => {
if hm_keys.len() == 0 { continue; }
let idx = val as usize % hm_keys.len();
if hm.remove(&hm_keys[idx]) != sm.remove(sm_keys[idx]) {
return false;
}
}
2 => {
if hm_keys.len() == 0 { 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) != sm.contains_key(sm_key) ||
hm.get(hm_key) != sm.get(sm_key) {
return false;
}
}
#[cfg(feature = "serde")]
3 => {
let ser = serde_json::to_string(&sm).unwrap();
sm = serde_json::from_str(&ser).unwrap();
}
_ => unreachable!(),
}
}
let mut smv: Vec<_> = sm.values().collect();
let mut hmv: Vec<_> = hm.values().collect();
smv.sort();
hmv.sort();
smv == hmv
}
}
#[cfg(feature = "serde")]
#[test]
fn slotmap_serde() {
let mut sm = SlotMap::new();
let first = sm.insert_with_key(|k| (k, 23i32));
let second = sm.insert((first, 42));
let empties = vec![sm.insert((first, 0)), sm.insert((first, 0))];
empties.iter().for_each(|k| {
sm.remove(*k);
});
let third = sm.insert((second, 0));
sm[first].0 = third;
let ser = serde_json::to_string(&sm).unwrap();
let de: SlotMap<DefaultKey, (DefaultKey, i32)> = serde_json::from_str(&ser).unwrap();
assert_eq!(de.len(), sm.len());
let mut smkv: Vec<_> = sm.iter().collect();
let mut dekv: Vec<_> = de.iter().collect();
smkv.sort();
dekv.sort();
assert_eq!(smkv, dekv);
}
#[cfg(feature = "serde")]
#[test]
fn slotmap_serde_freelist() {
let mut sm = SlotMap::new();
let k = sm.insert(5i32);
sm.remove(k);
let ser = serde_json::to_string(&sm).unwrap();
let mut de: SlotMap<DefaultKey, i32> = serde_json::from_str(&ser).unwrap();
de.insert(0);
de.insert(1);
de.insert(2);
assert_eq!(de.len(), 3);
}
}