зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1716518 - Upgrade slab to v0.4.3.
Differential Revision: https://phabricator.services.mozilla.com/D117861 Depends on D117860
This commit is contained in:
Родитель
44e5a3d825
Коммит
4c2c284417
|
@ -4675,9 +4675,9 @@ version = "0.0.1"
|
|||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.1"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d"
|
||||
checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
|
||||
|
||||
[[package]]
|
||||
name = "smallbitvec"
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"CHANGELOG.md":"a3e1912aae6f72659729ba4b2e303aa46bfbe1110fe9133386ac3ac3b1c5a1ea","Cargo.toml":"f07494b6213d2ad4b56d1ea9d6579305175de381c1016fa169fc9e84e5ffab9d","LICENSE":"45f522cacecb1023856e46df79ca625dfc550c94910078bd8aec6e02880b3d42","README.md":"ba0e174bd812dba6f93c38595c44187083dfafa408b308492b652182513218f6","src/lib.rs":"4736c1ce76fe28644d70dcc097404d19423578d0c85ae0b47d71c3a79e9c0649","tests/slab.rs":"c166c080b2534ffd5a5de4317f40072603678b2ca996a694c583eafadeb99a8c"},"package":"5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d"}
|
||||
{"files":{"CHANGELOG.md":"4d27de4c0d2c80d7a82af217a2759d14ac08a554c928a334924ca840455d0cd9","Cargo.toml":"0afd491c025731bfbc992ff89fb4e520c8efb84829a5713684c0934cbd948db9","LICENSE":"8ce0830173fdac609dfb4ea603fdc002c2f4af0dc9b1a005653f5da9cf534b18","README.md":"3a9d020510c4ba182d34d459ae2eea9354435964f7014d12ca99cd6334f79cba","src/lib.rs":"ea971740ac2b424da695b4eac6aee81ce6471f40e3186e8f5993bcd31a7f64d2","src/serde.rs":"ecdee6b2e7794746415391efe4687534b1e12b2f27eb02b873efdc030cc669b6","tests/serde.rs":"4e7e737e2a1845a01410b1ad288067de14accd941d72db172b31564623aa587f","tests/slab.rs":"daf451850527c1faf98b7745eab3eb39f18733f36815b01fd82b998127323124"},"package":"f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"}
|
|
@ -1,3 +1,20 @@
|
|||
# 0.4.3 (February 6, 2021)
|
||||
|
||||
* Add no_std support for Rust 1.36 and above (#71).
|
||||
* Add `get2_mut` and `get2_unchecked_mut` methods (#65).
|
||||
* Make `shrink_to_fit()` remove trailing vacant entries (#62).
|
||||
* Implement `FromIterator<(usize, T)>` (#62).
|
||||
* Implement `IntoIterator<Item = (usize, T)>` (#62).
|
||||
* Provide `size_hint()` of the iterators (#62).
|
||||
* Make all iterators reversible (#62).
|
||||
* Add `key_of()` method (#61)
|
||||
* Add `compact()` method (#60)
|
||||
* Add support for serde (#85)
|
||||
|
||||
# 0.4.2 (January 11, 2019)
|
||||
|
||||
* Add `Slab::drain` (#56).
|
||||
|
||||
# 0.4.1 (July 15, 2018)
|
||||
|
||||
* Improve `reserve` and `reserve_exact` (#37).
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g. crates.io) dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
|
@ -12,13 +12,28 @@
|
|||
|
||||
[package]
|
||||
name = "slab"
|
||||
version = "0.4.1"
|
||||
version = "0.4.3"
|
||||
authors = ["Carl Lerche <me@carllerche.com>"]
|
||||
description = "Pre-allocated storage for a uniform data type"
|
||||
homepage = "https://github.com/carllerche/slab"
|
||||
documentation = "https://docs.rs/slab"
|
||||
homepage = "https://github.com/tokio-rs/slab"
|
||||
documentation = "https://docs.rs/slab/0.4.3/slab/"
|
||||
readme = "README.md"
|
||||
keywords = ["slab", "allocator"]
|
||||
categories = ["memory-management", "data-structures"]
|
||||
keywords = ["slab", "allocator", "no_std"]
|
||||
categories = ["memory-management", "data-structures", "no-std"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/carllerche/slab"
|
||||
repository = "https://github.com/tokio-rs/slab"
|
||||
[dependencies.serde]
|
||||
version = "1.0.95"
|
||||
features = ["alloc"]
|
||||
optional = true
|
||||
default-features = false
|
||||
[dev-dependencies.serde]
|
||||
version = "1"
|
||||
features = ["derive"]
|
||||
|
||||
[dev-dependencies.serde_test]
|
||||
version = "1"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2018 Carl Lerche
|
||||
Copyright (c) 2019 Carl Lerche
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
|
|
|
@ -2,10 +2,15 @@
|
|||
|
||||
Pre-allocated storage for a uniform data type.
|
||||
|
||||
[![Crates.io](https://img.shields.io/crates/v/slab.svg?maxAge=2592000)](https://crates.io/crates/slab)
|
||||
[![Build Status](https://travis-ci.org/carllerche/slab.svg?branch=master)](https://travis-ci.org/carllerche/slab)
|
||||
[![Crates.io][crates-badge]][crates-url]
|
||||
[![Build Status][ci-badge]][ci-url]
|
||||
|
||||
[Documentation](https://docs.rs/slab)
|
||||
[crates-badge]: https://img.shields.io/crates/v/slab
|
||||
[crates-url]: https://crates.io/crates/slab
|
||||
[ci-badge]: https://img.shields.io/github/workflow/status/tokio-rs/slab/CI/master
|
||||
[ci-url]: https://github.com/tokio-rs/slab/actions
|
||||
|
||||
[Documentation](https://docs.rs/slab/0.4.3/slab/)
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -13,7 +18,7 @@ To use `slab`, first add this to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
slab = "0.4"
|
||||
slab = "0.4.3"
|
||||
```
|
||||
|
||||
Next, add this to your crate:
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
#![warn(missing_docs, missing_debug_implementations)]
|
||||
#![cfg_attr(test, warn(unreachable_pub))]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
//! Pre-allocated storage for a uniform data type.
|
||||
//!
|
||||
//! `Slab` provides pre-allocated storage for a single data type. If many values
|
||||
|
@ -98,13 +102,26 @@
|
|||
//!
|
||||
//! [`Slab::with_capacity`]: struct.Slab.html#with_capacity
|
||||
|
||||
#![deny(warnings, missing_docs, missing_debug_implementations)]
|
||||
#![doc(html_root_url = "https://docs.rs/slab/0.4.1")]
|
||||
#![crate_name = "slab"]
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate alloc;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate core;
|
||||
|
||||
use std::{fmt, mem};
|
||||
use std::iter::IntoIterator;
|
||||
use std::ops;
|
||||
#[cfg(feature = "serde")]
|
||||
mod serde;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::vec;
|
||||
|
||||
use core::iter::FromIterator;
|
||||
|
||||
use core::{fmt, mem, ops, slice};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::vec;
|
||||
|
||||
/// Pre-allocated storage for a uniform data type
|
||||
///
|
||||
|
@ -158,18 +175,27 @@ pub struct VacantEntry<'a, T: 'a> {
|
|||
key: usize,
|
||||
}
|
||||
|
||||
/// A consuming iterator over the values stored in a `Slab`
|
||||
pub struct IntoIter<T> {
|
||||
entries: vec::IntoIter<Entry<T>>,
|
||||
curr: usize,
|
||||
}
|
||||
|
||||
/// An iterator over the values stored in the `Slab`
|
||||
pub struct Iter<'a, T: 'a> {
|
||||
entries: std::slice::Iter<'a, Entry<T>>,
|
||||
entries: slice::Iter<'a, Entry<T>>,
|
||||
curr: usize,
|
||||
}
|
||||
|
||||
/// A mutable iterator over the values stored in the `Slab`
|
||||
pub struct IterMut<'a, T: 'a> {
|
||||
entries: std::slice::IterMut<'a, Entry<T>>,
|
||||
entries: slice::IterMut<'a, Entry<T>>,
|
||||
curr: usize,
|
||||
}
|
||||
|
||||
/// A draining iterator for `Slab`
|
||||
pub struct Drain<'a, T: 'a>(vec::Drain<'a, Entry<T>>);
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Entry<T> {
|
||||
Vacant(usize),
|
||||
|
@ -270,7 +296,7 @@ impl<T> Slab<T> {
|
|||
if self.capacity() - self.len >= additional {
|
||||
return;
|
||||
}
|
||||
let need_add = self.len + additional - self.entries.len();
|
||||
let need_add = additional - (self.entries.len() - self.len);
|
||||
self.entries.reserve(need_add);
|
||||
}
|
||||
|
||||
|
@ -304,16 +330,19 @@ impl<T> Slab<T> {
|
|||
if self.capacity() - self.len >= additional {
|
||||
return;
|
||||
}
|
||||
let need_add = self.len + additional - self.entries.len();
|
||||
let need_add = additional - (self.entries.len() - self.len);
|
||||
self.entries.reserve_exact(need_add);
|
||||
}
|
||||
|
||||
/// Shrink the capacity of the slab as much as possible.
|
||||
/// Shrink the capacity of the slab as much as possible without invalidating keys.
|
||||
///
|
||||
/// It will drop down as close as possible to the length but the allocator
|
||||
/// may still inform the vector that there is space for a few more elements.
|
||||
/// Also, since values are not moved, the slab cannot shrink past any stored
|
||||
/// values.
|
||||
/// Because values cannot be moved to a different index, the slab cannot
|
||||
/// shrink past any stored values.
|
||||
/// It will drop down as close as possible to the length but the allocator may
|
||||
/// still inform the underlying vector that there is space for a few more elements.
|
||||
///
|
||||
/// This function can take O(n) time even when the capacity cannot be reduced
|
||||
/// or the allocation is shrunk in place. Repeated calls run in O(1) though.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -325,33 +354,171 @@ impl<T> Slab<T> {
|
|||
/// slab.insert(i);
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(slab.capacity(), 10);
|
||||
/// slab.shrink_to_fit();
|
||||
/// assert!(slab.capacity() >= 3);
|
||||
/// assert!(slab.capacity() >= 3 && slab.capacity() < 10);
|
||||
/// ```
|
||||
///
|
||||
/// In this case, even though two values are removed, the slab cannot shrink
|
||||
/// past the last value.
|
||||
/// The slab cannot shrink past the last present value even if previous
|
||||
/// values are removed:
|
||||
///
|
||||
/// ```
|
||||
/// # use slab::*;
|
||||
/// let mut slab = Slab::with_capacity(10);
|
||||
///
|
||||
/// for i in 0..3 {
|
||||
/// for i in 0..4 {
|
||||
/// slab.insert(i);
|
||||
/// }
|
||||
///
|
||||
/// slab.remove(0);
|
||||
/// slab.remove(1);
|
||||
/// slab.remove(3);
|
||||
///
|
||||
/// assert_eq!(slab.capacity(), 10);
|
||||
/// slab.shrink_to_fit();
|
||||
/// assert!(slab.capacity() >= 3);
|
||||
/// assert!(slab.capacity() >= 3 && slab.capacity() < 10);
|
||||
/// ```
|
||||
pub fn shrink_to_fit(&mut self) {
|
||||
// Remove all vacant entries after the last occupied one, so that
|
||||
// the capacity can be reduced to what is actually needed.
|
||||
// If the slab is empty the vector can simply be cleared, but that
|
||||
// optimization would not affect time complexity when T: Drop.
|
||||
let len_before = self.entries.len();
|
||||
while let Some(&Entry::Vacant(_)) = self.entries.last() {
|
||||
self.entries.pop();
|
||||
}
|
||||
|
||||
// Removing entries breaks the list of vacant entries,
|
||||
// so it must be repaired
|
||||
if self.entries.len() != len_before {
|
||||
// Some vacant entries were removed, so the list now likely¹
|
||||
// either contains references to the removed entries, or has an
|
||||
// invalid end marker. Fix this by recreating the list.
|
||||
self.recreate_vacant_list();
|
||||
// ¹: If the removed entries formed the tail of the list, with the
|
||||
// most recently popped entry being the head of them, (so that its
|
||||
// index is now the end marker) the list is still valid.
|
||||
// Checking for that unlikely scenario of this infrequently called
|
||||
// is not worth the code complexity.
|
||||
}
|
||||
|
||||
self.entries.shrink_to_fit();
|
||||
}
|
||||
|
||||
/// Iterate through all entries to recreate and repair the vacant list.
|
||||
/// self.len must be correct and is not modified.
|
||||
fn recreate_vacant_list(&mut self) {
|
||||
self.next = self.entries.len();
|
||||
// We can stop once we've found all vacant entries
|
||||
let mut remaining_vacant = self.entries.len() - self.len;
|
||||
// Iterate in reverse order so that lower keys are at the start of
|
||||
// the vacant list. This way future shrinks are more likely to be
|
||||
// able to remove vacant entries.
|
||||
for (i, entry) in self.entries.iter_mut().enumerate().rev() {
|
||||
if remaining_vacant == 0 {
|
||||
break;
|
||||
}
|
||||
if let Entry::Vacant(ref mut next) = *entry {
|
||||
*next = self.next;
|
||||
self.next = i;
|
||||
remaining_vacant -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reduce the capacity as much as possible, changing the key for elements when necessary.
|
||||
///
|
||||
/// To allow updating references to the elements which must be moved to a new key,
|
||||
/// this function takes a closure which is called before moving each element.
|
||||
/// The second and third parameters to the closure are the current key and
|
||||
/// new key respectively.
|
||||
/// In case changing the key for one element turns out not to be possible,
|
||||
/// the move can be cancelled by returning `false` from the closure.
|
||||
/// In that case no further attempts at relocating elements is made.
|
||||
/// If the closure unwinds, the slab will be left in a consistent state,
|
||||
/// but the value that the closure panicked on might be removed.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use slab::*;
|
||||
///
|
||||
/// let mut slab = Slab::with_capacity(10);
|
||||
/// let a = slab.insert('a');
|
||||
/// slab.insert('b');
|
||||
/// slab.insert('c');
|
||||
/// slab.remove(a);
|
||||
/// slab.compact(|&mut value, from, to| {
|
||||
/// assert_eq!((value, from, to), ('c', 2, 0));
|
||||
/// true
|
||||
/// });
|
||||
/// assert!(slab.capacity() >= 2 && slab.capacity() < 10);
|
||||
/// ```
|
||||
///
|
||||
/// The value is not moved when the closure returns `Err`:
|
||||
///
|
||||
/// ```
|
||||
/// # use slab::*;
|
||||
///
|
||||
/// let mut slab = Slab::with_capacity(100);
|
||||
/// let a = slab.insert('a');
|
||||
/// let b = slab.insert('b');
|
||||
/// slab.remove(a);
|
||||
/// slab.compact(|&mut value, from, to| false);
|
||||
/// assert_eq!(slab.iter().next(), Some((b, &'b')));
|
||||
/// ```
|
||||
pub fn compact<F>(&mut self, mut rekey: F)
|
||||
where
|
||||
F: FnMut(&mut T, usize, usize) -> bool,
|
||||
{
|
||||
// If the closure unwinds, we need to restore a valid list of vacant entries
|
||||
struct CleanupGuard<'a, T: 'a> {
|
||||
slab: &'a mut Slab<T>,
|
||||
decrement: bool,
|
||||
}
|
||||
impl<'a, T: 'a> Drop for CleanupGuard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
if self.decrement {
|
||||
// Value was popped and not pushed back on
|
||||
self.slab.len -= 1;
|
||||
}
|
||||
self.slab.recreate_vacant_list();
|
||||
}
|
||||
}
|
||||
let mut guard = CleanupGuard {
|
||||
slab: self,
|
||||
decrement: true,
|
||||
};
|
||||
|
||||
let mut occupied_until = 0;
|
||||
// While there are vacant entries
|
||||
while guard.slab.entries.len() > guard.slab.len {
|
||||
// Find a value that needs to be moved,
|
||||
// by popping entries until we find an occopied one.
|
||||
// (entries cannot be empty because 0 is not greater than anything)
|
||||
if let Some(Entry::Occupied(mut value)) = guard.slab.entries.pop() {
|
||||
// Found one, now find a vacant entry to move it to
|
||||
while let Some(&Entry::Occupied(_)) = guard.slab.entries.get(occupied_until) {
|
||||
occupied_until += 1;
|
||||
}
|
||||
// Let the caller try to update references to the key
|
||||
if !rekey(&mut value, guard.slab.entries.len(), occupied_until) {
|
||||
// Changing the key failed, so push the entry back on at its old index.
|
||||
guard.slab.entries.push(Entry::Occupied(value));
|
||||
guard.decrement = false;
|
||||
guard.slab.entries.shrink_to_fit();
|
||||
return;
|
||||
// Guard drop handles cleanup
|
||||
}
|
||||
// Put the value in its new spot
|
||||
guard.slab.entries[occupied_until] = Entry::Occupied(value);
|
||||
// ... and mark it as occupied (this is optional)
|
||||
occupied_until += 1;
|
||||
}
|
||||
}
|
||||
guard.slab.next = guard.slab.len;
|
||||
guard.slab.entries.shrink_to_fit();
|
||||
// Normal cleanup is not necessary
|
||||
mem::forget(guard);
|
||||
}
|
||||
|
||||
/// Clear the slab of all values.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -516,11 +683,62 @@ impl<T> Slab<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return two mutable references to the values associated with the two
|
||||
/// given keys simultaneously.
|
||||
///
|
||||
/// If any one of the given keys is not associated with a value, then `None`
|
||||
/// is returned.
|
||||
///
|
||||
/// This function can be used to get two mutable references out of one slab,
|
||||
/// so that you can manipulate both of them at the same time, eg. swap them.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use slab::*;
|
||||
/// use std::mem;
|
||||
///
|
||||
/// let mut slab = Slab::new();
|
||||
/// let key1 = slab.insert(1);
|
||||
/// let key2 = slab.insert(2);
|
||||
/// let (value1, value2) = slab.get2_mut(key1, key2).unwrap();
|
||||
/// mem::swap(value1, value2);
|
||||
/// assert_eq!(slab[key1], 2);
|
||||
/// assert_eq!(slab[key2], 1);
|
||||
/// ```
|
||||
pub fn get2_mut(&mut self, key1: usize, key2: usize) -> Option<(&mut T, &mut T)> {
|
||||
assert!(key1 != key2);
|
||||
|
||||
let (entry1, entry2);
|
||||
|
||||
if key1 > key2 {
|
||||
let (slice1, slice2) = self.entries.split_at_mut(key1);
|
||||
entry1 = slice2.get_mut(0);
|
||||
entry2 = slice1.get_mut(key2);
|
||||
} else {
|
||||
let (slice1, slice2) = self.entries.split_at_mut(key2);
|
||||
entry1 = slice1.get_mut(key1);
|
||||
entry2 = slice2.get_mut(0);
|
||||
}
|
||||
|
||||
match (entry1, entry2) {
|
||||
(
|
||||
Some(&mut Entry::Occupied(ref mut val1)),
|
||||
Some(&mut Entry::Occupied(ref mut val2)),
|
||||
) => Some((val1, val2)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a reference to the value associated with the given key without
|
||||
/// performing bounds checking.
|
||||
///
|
||||
/// This function should be used with care.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The key must be within bounds.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
@ -544,6 +762,10 @@ impl<T> Slab<T> {
|
|||
///
|
||||
/// This function should be used with care.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The key must be within bounds.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
@ -565,6 +787,93 @@ impl<T> Slab<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return two mutable references to the values associated with the two
|
||||
/// given keys simultaneously without performing bounds checking and safety
|
||||
/// condition checking.
|
||||
///
|
||||
/// This function should be used with care.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Both keys must be within bounds.
|
||||
/// - The condition `key1 != key2` must hold.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use slab::*;
|
||||
/// use std::mem;
|
||||
///
|
||||
/// let mut slab = Slab::new();
|
||||
/// let key1 = slab.insert(1);
|
||||
/// let key2 = slab.insert(2);
|
||||
/// let (value1, value2) = unsafe { slab.get2_unchecked_mut(key1, key2) };
|
||||
/// mem::swap(value1, value2);
|
||||
/// assert_eq!(slab[key1], 2);
|
||||
/// assert_eq!(slab[key2], 1);
|
||||
/// ```
|
||||
pub unsafe fn get2_unchecked_mut(&mut self, key1: usize, key2: usize) -> (&mut T, &mut T) {
|
||||
let ptr1 = self.entries.get_unchecked_mut(key1) as *mut Entry<T>;
|
||||
let ptr2 = self.entries.get_unchecked_mut(key2) as *mut Entry<T>;
|
||||
match (&mut *ptr1, &mut *ptr2) {
|
||||
(&mut Entry::Occupied(ref mut val1), &mut Entry::Occupied(ref mut val2)) => {
|
||||
(val1, val2)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the key for an element in the slab.
|
||||
///
|
||||
/// The reference must point to an element owned by the slab.
|
||||
/// Otherwise this function will panic.
|
||||
/// This is a constant-time operation because the key can be calculated
|
||||
/// from the reference with pointer arithmetic.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if the reference does not point to an element
|
||||
/// of the slab.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use slab::*;
|
||||
///
|
||||
/// let mut slab = Slab::new();
|
||||
/// let key = slab.insert(String::from("foo"));
|
||||
/// let value = &slab[key];
|
||||
/// assert_eq!(slab.key_of(value), key);
|
||||
/// ```
|
||||
///
|
||||
/// Values are not compared, so passing a reference to a different locaton
|
||||
/// will result in a panic:
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use slab::*;
|
||||
///
|
||||
/// let mut slab = Slab::new();
|
||||
/// let key = slab.insert(0);
|
||||
/// let bad = &0;
|
||||
/// slab.key_of(bad); // this will panic
|
||||
/// unreachable!();
|
||||
/// ```
|
||||
pub fn key_of(&self, present_element: &T) -> usize {
|
||||
let element_ptr = present_element as *const T as usize;
|
||||
let base_ptr = self.entries.as_ptr() as usize;
|
||||
// Use wrapping subtraction in case the reference is bad
|
||||
let byte_offset = element_ptr.wrapping_sub(base_ptr);
|
||||
// The division rounds away any offset of T inside Entry
|
||||
// The size of Entry<T> is never zero even if T is due to Vacant(usize)
|
||||
let key = byte_offset / mem::size_of::<Entry<T>>();
|
||||
// Prevent returning unspecified (but out of bounds) values
|
||||
if key >= self.entries.len() {
|
||||
panic!("The reference points to a value outside this slab");
|
||||
}
|
||||
// The reference cannot point to a vacant entry, because then it would not be valid
|
||||
key
|
||||
}
|
||||
|
||||
/// Insert a value in the slab, returning key assigned to the value.
|
||||
///
|
||||
/// The returned key can later be used to retrieve or remove the value using indexed
|
||||
|
@ -628,16 +937,11 @@ impl<T> Slab<T> {
|
|||
self.entries.push(Entry::Occupied(val));
|
||||
self.next = key + 1;
|
||||
} else {
|
||||
let prev = mem::replace(
|
||||
&mut self.entries[key],
|
||||
Entry::Occupied(val));
|
||||
|
||||
match prev {
|
||||
Entry::Vacant(next) => {
|
||||
self.next = next;
|
||||
}
|
||||
self.next = match self.entries.get(key) {
|
||||
Some(&Entry::Vacant(next)) => next,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
self.entries[key] = Entry::Occupied(val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -662,23 +966,23 @@ impl<T> Slab<T> {
|
|||
/// assert!(!slab.contains(hello));
|
||||
/// ```
|
||||
pub fn remove(&mut self, key: usize) -> T {
|
||||
// Swap the entry at the provided value
|
||||
let prev = mem::replace(
|
||||
&mut self.entries[key],
|
||||
Entry::Vacant(self.next));
|
||||
if let Some(entry) = self.entries.get_mut(key) {
|
||||
// Swap the entry at the provided value
|
||||
let prev = mem::replace(entry, Entry::Vacant(self.next));
|
||||
|
||||
match prev {
|
||||
Entry::Occupied(val) => {
|
||||
self.len -= 1;
|
||||
self.next = key;
|
||||
val
|
||||
}
|
||||
_ => {
|
||||
// Woops, the entry is actually vacant, restore the state
|
||||
self.entries[key] = prev;
|
||||
panic!("invalid key");
|
||||
match prev {
|
||||
Entry::Occupied(val) => {
|
||||
self.len -= 1;
|
||||
self.next = key;
|
||||
return val;
|
||||
}
|
||||
_ => {
|
||||
// Woops, the entry is actually vacant, restore the state
|
||||
*entry = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
panic!("invalid key");
|
||||
}
|
||||
|
||||
/// Return `true` if a value is associated with the given key.
|
||||
|
@ -697,14 +1001,10 @@ impl<T> Slab<T> {
|
|||
/// assert!(!slab.contains(hello));
|
||||
/// ```
|
||||
pub fn contains(&self, key: usize) -> bool {
|
||||
self.entries.get(key)
|
||||
.map(|e| {
|
||||
match *e {
|
||||
Entry::Occupied(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
.unwrap_or(false)
|
||||
match self.entries.get(key) {
|
||||
Some(&Entry::Occupied(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Retain only the elements specified by the predicate.
|
||||
|
@ -732,7 +1032,8 @@ impl<T> Slab<T> {
|
|||
/// assert_eq!(2, slab.len());
|
||||
/// ```
|
||||
pub fn retain<F>(&mut self, mut f: F)
|
||||
where F: FnMut(usize, &mut T) -> bool
|
||||
where
|
||||
F: FnMut(usize, &mut T) -> bool,
|
||||
{
|
||||
for i in 0..self.entries.len() {
|
||||
let keep = match self.entries[i] {
|
||||
|
@ -745,14 +1046,47 @@ impl<T> Slab<T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a draining iterator that removes all elements from the slab and
|
||||
/// yields the removed items.
|
||||
///
|
||||
/// Note: Elements are removed even if the iterator is only partially
|
||||
/// consumed or not consumed at all.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use slab::*;
|
||||
/// let mut slab = Slab::new();
|
||||
///
|
||||
/// let _ = slab.insert(0);
|
||||
/// let _ = slab.insert(1);
|
||||
/// let _ = slab.insert(2);
|
||||
///
|
||||
/// {
|
||||
/// let mut drain = slab.drain();
|
||||
///
|
||||
/// assert_eq!(Some(0), drain.next());
|
||||
/// assert_eq!(Some(1), drain.next());
|
||||
/// assert_eq!(Some(2), drain.next());
|
||||
/// assert_eq!(None, drain.next());
|
||||
/// }
|
||||
///
|
||||
/// assert!(slab.is_empty());
|
||||
/// ```
|
||||
pub fn drain(&mut self) -> Drain<T> {
|
||||
self.len = 0;
|
||||
self.next = 0;
|
||||
Drain(self.entries.drain(..))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::Index<usize> for Slab<T> {
|
||||
type Output = T;
|
||||
|
||||
fn index(&self, key: usize) -> &T {
|
||||
match self.entries[key] {
|
||||
Entry::Occupied(ref v) => v,
|
||||
match self.entries.get(key) {
|
||||
Some(&Entry::Occupied(ref v)) => v,
|
||||
_ => panic!("invalid key"),
|
||||
}
|
||||
}
|
||||
|
@ -760,13 +1094,25 @@ impl<T> ops::Index<usize> for Slab<T> {
|
|||
|
||||
impl<T> ops::IndexMut<usize> for Slab<T> {
|
||||
fn index_mut(&mut self, key: usize) -> &mut T {
|
||||
match self.entries[key] {
|
||||
Entry::Occupied(ref mut v) => v,
|
||||
match self.entries.get_mut(key) {
|
||||
Some(&mut Entry::Occupied(ref mut v)) => v,
|
||||
_ => panic!("invalid key"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoIterator for Slab<T> {
|
||||
type Item = (usize, T);
|
||||
type IntoIter = IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> IntoIter<T> {
|
||||
IntoIter {
|
||||
entries: self.entries.into_iter(),
|
||||
curr: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> IntoIterator for &'a Slab<T> {
|
||||
type Item = (usize, &'a T);
|
||||
type IntoIter = Iter<'a, T>;
|
||||
|
@ -785,16 +1131,93 @@ impl<'a, T> IntoIterator for &'a mut Slab<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Slab<T> where T: fmt::Debug {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt,
|
||||
"Slab {{ len: {}, cap: {} }}",
|
||||
self.len,
|
||||
self.capacity())
|
||||
/// Create a slab from an iterator of key-value pairs.
|
||||
///
|
||||
/// If the iterator produces duplicate keys, the previous value is replaced with the later one.
|
||||
/// The keys does not need to be sorted beforehand, and this function always
|
||||
/// takes O(n) time.
|
||||
/// Note that the returned slab will use space proportional to the largest key,
|
||||
/// so don't use `Slab` with untrusted keys.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use slab::*;
|
||||
///
|
||||
/// let vec = vec![(2,'a'), (6,'b'), (7,'c')];
|
||||
/// let slab = vec.into_iter().collect::<Slab<char>>();
|
||||
/// assert_eq!(slab.len(), 3);
|
||||
/// assert!(slab.capacity() >= 8);
|
||||
/// assert_eq!(slab[2], 'a');
|
||||
/// ```
|
||||
///
|
||||
/// With duplicate and unsorted keys:
|
||||
///
|
||||
/// ```
|
||||
/// # use slab::*;
|
||||
///
|
||||
/// let vec = vec![(20,'a'), (10,'b'), (11,'c'), (10,'d')];
|
||||
/// let slab = vec.into_iter().collect::<Slab<char>>();
|
||||
/// assert_eq!(slab.len(), 3);
|
||||
/// assert_eq!(slab[10], 'd');
|
||||
/// ```
|
||||
impl<T> FromIterator<(usize, T)> for Slab<T> {
|
||||
fn from_iter<I>(iterable: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = (usize, T)>,
|
||||
{
|
||||
let iterator = iterable.into_iter();
|
||||
let mut slab = Self::with_capacity(iterator.size_hint().0);
|
||||
|
||||
let mut vacant_list_broken = false;
|
||||
for (key, value) in iterator {
|
||||
if key < slab.entries.len() {
|
||||
// iterator is not sorted, might need to recreate vacant list
|
||||
if let Entry::Vacant(_) = slab.entries[key] {
|
||||
vacant_list_broken = true;
|
||||
slab.len += 1;
|
||||
}
|
||||
// if an element with this key already exists, replace it.
|
||||
// This is consisent with HashMap and BtreeMap
|
||||
slab.entries[key] = Entry::Occupied(value);
|
||||
} else {
|
||||
// insert holes as necessary
|
||||
while slab.entries.len() < key {
|
||||
// add the entry to the start of the vacant list
|
||||
let next = slab.next;
|
||||
slab.next = slab.entries.len();
|
||||
slab.entries.push(Entry::Vacant(next));
|
||||
}
|
||||
slab.entries.push(Entry::Occupied(value));
|
||||
slab.len += 1;
|
||||
}
|
||||
}
|
||||
if slab.len == slab.entries.len() {
|
||||
// no vacant enries, so next might not have been updated
|
||||
slab.next = slab.entries.len();
|
||||
} else if vacant_list_broken {
|
||||
slab.recreate_vacant_list();
|
||||
}
|
||||
slab
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> fmt::Debug for Iter<'a, T> where T: fmt::Debug {
|
||||
impl<T> fmt::Debug for Slab<T>
|
||||
where
|
||||
T: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("Slab")
|
||||
.field("len", &self.len)
|
||||
.field("cap", &self.capacity())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for IntoIter<T>
|
||||
where
|
||||
T: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("Iter")
|
||||
.field("curr", &self.curr)
|
||||
|
@ -803,7 +1226,22 @@ impl<'a, T: 'a> fmt::Debug for Iter<'a, T> where T: fmt::Debug {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> fmt::Debug for IterMut<'a, T> where T: fmt::Debug {
|
||||
impl<'a, T: 'a> fmt::Debug for Iter<'a, T>
|
||||
where
|
||||
T: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("Iter")
|
||||
.field("curr", &self.curr)
|
||||
.field("remaining", &self.entries.len())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> fmt::Debug for IterMut<'a, T>
|
||||
where
|
||||
T: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("IterMut")
|
||||
.field("curr", &self.curr)
|
||||
|
@ -812,6 +1250,12 @@ impl<'a, T: 'a> fmt::Debug for IterMut<'a, T> where T: fmt::Debug {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> fmt::Debug for Drain<'a, T> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("Drain").finish()
|
||||
}
|
||||
}
|
||||
|
||||
// ===== VacantEntry =====
|
||||
|
||||
impl<'a, T> VacantEntry<'a, T> {
|
||||
|
@ -840,8 +1284,8 @@ impl<'a, T> VacantEntry<'a, T> {
|
|||
pub fn insert(self, val: T) -> &'a mut T {
|
||||
self.slab.insert_at(self.key, val);
|
||||
|
||||
match self.slab.entries[self.key] {
|
||||
Entry::Occupied(ref mut v) => v,
|
||||
match self.slab.entries.get_mut(self.key) {
|
||||
Some(&mut Entry::Occupied(ref mut v)) => v,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -872,6 +1316,42 @@ impl<'a, T> VacantEntry<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
// ===== IntoIter =====
|
||||
|
||||
impl<T> Iterator for IntoIter<T> {
|
||||
type Item = (usize, T);
|
||||
|
||||
fn next(&mut self) -> Option<(usize, T)> {
|
||||
while let Some(entry) = self.entries.next() {
|
||||
let curr = self.curr;
|
||||
self.curr += 1;
|
||||
|
||||
if let Entry::Occupied(v) = entry {
|
||||
return Some((curr, v));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(0, Some(self.entries.len()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DoubleEndedIterator for IntoIter<T> {
|
||||
fn next_back(&mut self) -> Option<(usize, T)> {
|
||||
while let Some(entry) = self.entries.next_back() {
|
||||
if let Entry::Occupied(v) = entry {
|
||||
let key = self.curr + self.entries.len();
|
||||
return Some((key, v));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Iter =====
|
||||
|
||||
impl<'a, T> Iterator for Iter<'a, T> {
|
||||
|
@ -889,6 +1369,23 @@ impl<'a, T> Iterator for Iter<'a, T> {
|
|||
|
||||
None
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(0, Some(self.entries.len()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
|
||||
fn next_back(&mut self) -> Option<(usize, &'a T)> {
|
||||
while let Some(entry) = self.entries.next_back() {
|
||||
if let Entry::Occupied(ref v) = *entry {
|
||||
let key = self.curr + self.entries.len();
|
||||
return Some((key, v));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// ===== IterMut =====
|
||||
|
@ -908,4 +1405,53 @@ impl<'a, T> Iterator for IterMut<'a, T> {
|
|||
|
||||
None
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(0, Some(self.entries.len()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
|
||||
fn next_back(&mut self) -> Option<(usize, &'a mut T)> {
|
||||
while let Some(entry) = self.entries.next_back() {
|
||||
if let Entry::Occupied(ref mut v) = *entry {
|
||||
let key = self.curr + self.entries.len();
|
||||
return Some((key, v));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Drain =====
|
||||
|
||||
impl<'a, T> Iterator for Drain<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
while let Some(entry) = self.0.next() {
|
||||
if let Entry::Occupied(v) = entry {
|
||||
return Some(v);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(0, Some(self.0.len()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
while let Some(entry) = self.0.next_back() {
|
||||
if let Entry::Occupied(v) = entry {
|
||||
return Some(v);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
extern crate serde;
|
||||
|
||||
use core::fmt;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use self::serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
|
||||
use self::serde::ser::{Serialize, SerializeMap, Serializer};
|
||||
|
||||
use super::{Entry, Slab};
|
||||
|
||||
impl<T> Serialize for Slab<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut map_serializer = serializer.serialize_map(Some(self.len()))?;
|
||||
for (key, value) in self {
|
||||
map_serializer.serialize_key(&key)?;
|
||||
map_serializer.serialize_value(value)?;
|
||||
}
|
||||
map_serializer.end()
|
||||
}
|
||||
}
|
||||
|
||||
struct SlabVisitor<T>(PhantomData<T>);
|
||||
|
||||
impl<'de, T> Visitor<'de> for SlabVisitor<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
type Value = Slab<T>;
|
||||
|
||||
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "a map")
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: MapAccess<'de>,
|
||||
{
|
||||
let mut slab = Slab::with_capacity(map.size_hint().unwrap_or(0));
|
||||
|
||||
// same as FromIterator impl
|
||||
let mut vacant_list_broken = false;
|
||||
while let Some((key, value)) = map.next_entry()? {
|
||||
if key < slab.entries.len() {
|
||||
// iterator is not sorted, might need to recreate vacant list
|
||||
if let Entry::Vacant(_) = slab.entries[key] {
|
||||
vacant_list_broken = true;
|
||||
slab.len += 1;
|
||||
}
|
||||
// if an element with this key already exists, replace it.
|
||||
// This is consisent with HashMap and BtreeMap
|
||||
slab.entries[key] = Entry::Occupied(value);
|
||||
} else {
|
||||
// insert holes as necessary
|
||||
while slab.entries.len() < key {
|
||||
// add the entry to the start of the vacant list
|
||||
let next = slab.next;
|
||||
slab.next = slab.entries.len();
|
||||
slab.entries.push(Entry::Vacant(next));
|
||||
}
|
||||
slab.entries.push(Entry::Occupied(value));
|
||||
slab.len += 1;
|
||||
}
|
||||
}
|
||||
if slab.len == slab.entries.len() {
|
||||
// no vacant enries, so next might not have been updated
|
||||
slab.next = slab.entries.len();
|
||||
} else if vacant_list_broken {
|
||||
slab.recreate_vacant_list();
|
||||
}
|
||||
|
||||
Ok(slab)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> Deserialize<'de> for Slab<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_map(SlabVisitor(PhantomData))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#![cfg(feature = "serde")]
|
||||
|
||||
extern crate serde;
|
||||
extern crate serde_test;
|
||||
extern crate slab;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_test::{assert_tokens, Token};
|
||||
use slab::Slab;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
struct SlabPartialEq<T>(Slab<T>);
|
||||
|
||||
impl<T: PartialEq> PartialEq for SlabPartialEq<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0
|
||||
.iter()
|
||||
.zip(other.0.iter())
|
||||
.all(|(this, other)| this.0 == other.0 && this.1 == other.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_empty() {
|
||||
let slab = Slab::<usize>::new();
|
||||
assert_tokens(
|
||||
&SlabPartialEq(slab),
|
||||
&[Token::Map { len: Some(0) }, Token::MapEnd],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde() {
|
||||
let vec = vec![(1, 2), (3, 4), (5, 6)];
|
||||
let slab: Slab<_> = vec.iter().cloned().collect();
|
||||
assert_tokens(
|
||||
&SlabPartialEq(slab),
|
||||
&[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::U64(1),
|
||||
Token::I32(2),
|
||||
Token::U64(3),
|
||||
Token::I32(4),
|
||||
Token::U64(5),
|
||||
Token::I32(6),
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
}
|
|
@ -2,6 +2,8 @@ extern crate slab;
|
|||
|
||||
use slab::*;
|
||||
|
||||
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
|
||||
|
||||
#[test]
|
||||
fn insert_get_remove_one() {
|
||||
let mut slab = Slab::new();
|
||||
|
@ -82,14 +84,21 @@ fn get_vacant_entry_without_using() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[should_panic(expected = "invalid key")]
|
||||
fn invalid_get_panics() {
|
||||
let slab = Slab::<usize>::with_capacity(1);
|
||||
slab[0];
|
||||
let _ = &slab[0];
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[should_panic(expected = "invalid key")]
|
||||
fn invalid_get_mut_panics() {
|
||||
let mut slab = Slab::<usize>::new();
|
||||
let _ = &mut slab[0];
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "invalid key")]
|
||||
fn double_remove_panics() {
|
||||
let mut slab = Slab::<usize>::with_capacity(1);
|
||||
let key = slab.insert(123);
|
||||
|
@ -98,7 +107,7 @@ fn double_remove_panics() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
#[should_panic(expected = "invalid key")]
|
||||
fn invalid_remove_panics() {
|
||||
let mut slab = Slab::<usize>::with_capacity(1);
|
||||
slab.remove(0);
|
||||
|
@ -116,6 +125,34 @@ fn slab_get_mut() {
|
|||
assert_eq!(slab[key], 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_of_tagged() {
|
||||
let mut slab = Slab::new();
|
||||
slab.insert(0);
|
||||
assert_eq!(slab.key_of(&slab[0]), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_of_layout_optimizable() {
|
||||
// Entry<&str> doesn't need a discriminant tag because it can use the
|
||||
// nonzero-ness of ptr and store Vacant's next at the same offset as len
|
||||
let mut slab = Slab::new();
|
||||
slab.insert("foo");
|
||||
slab.insert("bar");
|
||||
let third = slab.insert("baz");
|
||||
slab.insert("quux");
|
||||
assert_eq!(slab.key_of(&slab[third]), third);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_of_zst() {
|
||||
let mut slab = Slab::new();
|
||||
slab.insert(());
|
||||
let second = slab.insert(());
|
||||
slab.insert(());
|
||||
assert_eq!(slab.key_of(&slab[second]), second);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reserve_does_not_allocate_if_available() {
|
||||
let mut slab = Slab::with_capacity(10);
|
||||
|
@ -150,10 +187,26 @@ fn reserve_exact_does_not_allocate_if_available() {
|
|||
|
||||
assert!(slab.capacity() - slab.len() == 8);
|
||||
|
||||
slab.reserve(8);
|
||||
slab.reserve_exact(8);
|
||||
assert_eq!(10, slab.capacity());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "capacity overflow")]
|
||||
fn reserve_does_panic_with_capacity_overflow() {
|
||||
let mut slab = Slab::with_capacity(10);
|
||||
slab.insert(true);
|
||||
slab.reserve(std::usize::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "capacity overflow")]
|
||||
fn reserve_exact_does_panic_with_capacity_overflow() {
|
||||
let mut slab = Slab::with_capacity(10);
|
||||
slab.insert(true);
|
||||
slab.reserve_exact(std::usize::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retain() {
|
||||
let mut slab = Slab::with_capacity(2);
|
||||
|
@ -184,6 +237,43 @@ fn retain() {
|
|||
assert_eq!(4, slab.capacity());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_iter() {
|
||||
let mut slab = Slab::new();
|
||||
|
||||
for i in 0..8 {
|
||||
slab.insert(i);
|
||||
}
|
||||
slab.remove(0);
|
||||
slab.remove(4);
|
||||
slab.remove(5);
|
||||
slab.remove(7);
|
||||
|
||||
let vals: Vec<_> = slab
|
||||
.into_iter()
|
||||
.inspect(|&(key, val)| assert_eq!(key, val))
|
||||
.map(|(_, val)| val)
|
||||
.collect();
|
||||
assert_eq!(vals, vec![1, 2, 3, 6]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_iter_rev() {
|
||||
let mut slab = Slab::new();
|
||||
|
||||
for i in 0..4 {
|
||||
slab.insert(i);
|
||||
}
|
||||
|
||||
let mut iter = slab.into_iter();
|
||||
assert_eq!(iter.next_back(), Some((3, 3)));
|
||||
assert_eq!(iter.next_back(), Some((2, 2)));
|
||||
assert_eq!(iter.next(), Some((0, 0)));
|
||||
assert_eq!(iter.next_back(), Some((1, 1)));
|
||||
assert_eq!(iter.next_back(), None);
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iter() {
|
||||
let mut slab = Slab::new();
|
||||
|
@ -192,10 +282,14 @@ fn iter() {
|
|||
slab.insert(i);
|
||||
}
|
||||
|
||||
let vals: Vec<_> = slab.iter().enumerate().map(|(i, (key, val))| {
|
||||
assert_eq!(i, key);
|
||||
*val
|
||||
}).collect();
|
||||
let vals: Vec<_> = slab
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, (key, val))| {
|
||||
assert_eq!(i, key);
|
||||
*val
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(vals, vec![0, 1, 2, 3]);
|
||||
|
||||
slab.remove(1);
|
||||
|
@ -204,6 +298,19 @@ fn iter() {
|
|||
assert_eq!(vals, vec![0, 2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iter_rev() {
|
||||
let mut slab = Slab::new();
|
||||
|
||||
for i in 0..4 {
|
||||
slab.insert(i);
|
||||
}
|
||||
slab.remove(0);
|
||||
|
||||
let vals = slab.iter().rev().collect::<Vec<_>>();
|
||||
assert_eq!(vals, vec![(3, &3), (2, &2), (1, &1)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iter_mut() {
|
||||
let mut slab = Slab::new();
|
||||
|
@ -214,7 +321,7 @@ fn iter_mut() {
|
|||
|
||||
for (i, (key, e)) in slab.iter_mut().enumerate() {
|
||||
assert_eq!(i, key);
|
||||
*e = *e + 1;
|
||||
*e += 1;
|
||||
}
|
||||
|
||||
let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect();
|
||||
|
@ -223,13 +330,79 @@ fn iter_mut() {
|
|||
slab.remove(2);
|
||||
|
||||
for (_, e) in slab.iter_mut() {
|
||||
*e = *e + 1;
|
||||
*e += 1;
|
||||
}
|
||||
|
||||
let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect();
|
||||
assert_eq!(vals, vec![2, 3, 5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iter_mut_rev() {
|
||||
let mut slab = Slab::new();
|
||||
|
||||
for i in 0..4 {
|
||||
slab.insert(i);
|
||||
}
|
||||
slab.remove(2);
|
||||
|
||||
{
|
||||
let mut iter = slab.iter_mut();
|
||||
assert_eq!(iter.next(), Some((0, &mut 0)));
|
||||
let mut prev_key = !0;
|
||||
for (key, e) in iter.rev() {
|
||||
*e += 10;
|
||||
assert!(prev_key > key);
|
||||
prev_key = key;
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(slab[0], 0);
|
||||
assert_eq!(slab[1], 11);
|
||||
assert_eq!(slab[3], 13);
|
||||
assert!(!slab.contains(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_iterator_sorted() {
|
||||
let mut slab = (0..5).map(|i| (i, i)).collect::<Slab<_>>();
|
||||
assert_eq!(slab.len(), 5);
|
||||
assert_eq!(slab[0], 0);
|
||||
assert_eq!(slab[2], 2);
|
||||
assert_eq!(slab[4], 4);
|
||||
assert_eq!(slab.vacant_entry().key(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_iterator_new_in_order() {
|
||||
// all new keys come in increasing order, but existing keys are overwritten
|
||||
let mut slab = [(0, 'a'), (1, 'a'), (1, 'b'), (0, 'b'), (9, 'a'), (0, 'c')]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Slab<_>>();
|
||||
assert_eq!(slab.len(), 3);
|
||||
assert_eq!(slab[0], 'c');
|
||||
assert_eq!(slab[1], 'b');
|
||||
assert_eq!(slab[9], 'a');
|
||||
assert_eq!(slab.get(5), None);
|
||||
assert_eq!(slab.vacant_entry().key(), 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_iterator_unordered() {
|
||||
let mut slab = vec![(1, "one"), (50, "fifty"), (3, "three"), (20, "twenty")]
|
||||
.into_iter()
|
||||
.collect::<Slab<_>>();
|
||||
assert_eq!(slab.len(), 4);
|
||||
assert_eq!(slab.vacant_entry().key(), 0);
|
||||
let mut iter = slab.iter();
|
||||
assert_eq!(iter.next(), Some((1, &"one")));
|
||||
assert_eq!(iter.next(), Some((3, &"three")));
|
||||
assert_eq!(iter.next(), Some((20, &"twenty")));
|
||||
assert_eq!(iter.next(), Some((50, &"fifty")));
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clear() {
|
||||
let mut slab = Slab::new();
|
||||
|
@ -260,3 +433,229 @@ fn clear() {
|
|||
let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect();
|
||||
assert!(vals.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shrink_to_fit_empty() {
|
||||
let mut slab = Slab::<bool>::with_capacity(20);
|
||||
slab.shrink_to_fit();
|
||||
assert_eq!(slab.capacity(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shrink_to_fit_no_vacant() {
|
||||
let mut slab = Slab::with_capacity(20);
|
||||
slab.insert(String::new());
|
||||
slab.shrink_to_fit();
|
||||
assert!(slab.capacity() < 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shrink_to_fit_doesnt_move() {
|
||||
let mut slab = Slab::with_capacity(8);
|
||||
slab.insert("foo");
|
||||
let bar = slab.insert("bar");
|
||||
slab.insert("baz");
|
||||
let quux = slab.insert("quux");
|
||||
slab.remove(quux);
|
||||
slab.remove(bar);
|
||||
slab.shrink_to_fit();
|
||||
assert_eq!(slab.len(), 2);
|
||||
assert!(slab.capacity() >= 3);
|
||||
assert_eq!(slab.get(0), Some(&"foo"));
|
||||
assert_eq!(slab.get(2), Some(&"baz"));
|
||||
assert_eq!(slab.vacant_entry().key(), bar);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shrink_to_fit_doesnt_recreate_list_when_nothing_can_be_done() {
|
||||
let mut slab = Slab::with_capacity(16);
|
||||
for i in 0..4 {
|
||||
slab.insert(Box::new(i));
|
||||
}
|
||||
slab.remove(0);
|
||||
slab.remove(2);
|
||||
slab.remove(1);
|
||||
assert_eq!(slab.vacant_entry().key(), 1);
|
||||
slab.shrink_to_fit();
|
||||
assert_eq!(slab.len(), 1);
|
||||
assert!(slab.capacity() >= 4);
|
||||
assert_eq!(slab.vacant_entry().key(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compact_empty() {
|
||||
let mut slab = Slab::new();
|
||||
slab.compact(|_, _, _| panic!());
|
||||
assert_eq!(slab.len(), 0);
|
||||
assert_eq!(slab.capacity(), 0);
|
||||
slab.reserve(20);
|
||||
slab.compact(|_, _, _| panic!());
|
||||
assert_eq!(slab.len(), 0);
|
||||
assert_eq!(slab.capacity(), 0);
|
||||
slab.insert(0);
|
||||
slab.insert(1);
|
||||
slab.insert(2);
|
||||
slab.remove(1);
|
||||
slab.remove(2);
|
||||
slab.remove(0);
|
||||
slab.compact(|_, _, _| panic!());
|
||||
assert_eq!(slab.len(), 0);
|
||||
assert_eq!(slab.capacity(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compact_no_moves_needed() {
|
||||
let mut slab = Slab::new();
|
||||
for i in 0..10 {
|
||||
slab.insert(i);
|
||||
}
|
||||
slab.remove(8);
|
||||
slab.remove(9);
|
||||
slab.remove(6);
|
||||
slab.remove(7);
|
||||
slab.compact(|_, _, _| panic!());
|
||||
assert_eq!(slab.len(), 6);
|
||||
for ((index, &value), want) in slab.iter().zip(0..6) {
|
||||
assert!(index == value);
|
||||
assert_eq!(index, want);
|
||||
}
|
||||
assert!(slab.capacity() >= 6 && slab.capacity() < 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compact_moves_successfully() {
|
||||
let mut slab = Slab::with_capacity(20);
|
||||
for i in 0..10 {
|
||||
slab.insert(i);
|
||||
}
|
||||
for &i in &[0, 5, 9, 6, 3] {
|
||||
slab.remove(i);
|
||||
}
|
||||
let mut moved = 0;
|
||||
slab.compact(|&mut v, from, to| {
|
||||
assert!(from > to);
|
||||
assert!(from >= 5);
|
||||
assert!(to < 5);
|
||||
assert_eq!(from, v);
|
||||
moved += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(slab.len(), 5);
|
||||
assert_eq!(moved, 2);
|
||||
assert_eq!(slab.vacant_entry().key(), 5);
|
||||
assert!(slab.capacity() >= 5 && slab.capacity() < 20);
|
||||
let mut iter = slab.iter();
|
||||
assert_eq!(iter.next(), Some((0, &8)));
|
||||
assert_eq!(iter.next(), Some((1, &1)));
|
||||
assert_eq!(iter.next(), Some((2, &2)));
|
||||
assert_eq!(iter.next(), Some((3, &7)));
|
||||
assert_eq!(iter.next(), Some((4, &4)));
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compact_doesnt_move_if_closure_errors() {
|
||||
let mut slab = Slab::with_capacity(20);
|
||||
for i in 0..10 {
|
||||
slab.insert(i);
|
||||
}
|
||||
for &i in &[9, 3, 1, 4, 0] {
|
||||
slab.remove(i);
|
||||
}
|
||||
slab.compact(|&mut v, from, to| {
|
||||
assert!(from > to);
|
||||
assert_eq!(from, v);
|
||||
v != 6
|
||||
});
|
||||
assert_eq!(slab.len(), 5);
|
||||
assert!(slab.capacity() >= 7 && slab.capacity() < 20);
|
||||
assert_eq!(slab.vacant_entry().key(), 3);
|
||||
let mut iter = slab.iter();
|
||||
assert_eq!(iter.next(), Some((0, &8)));
|
||||
assert_eq!(iter.next(), Some((1, &7)));
|
||||
assert_eq!(iter.next(), Some((2, &2)));
|
||||
assert_eq!(iter.next(), Some((5, &5)));
|
||||
assert_eq!(iter.next(), Some((6, &6)));
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compact_handles_closure_panic() {
|
||||
let mut slab = Slab::new();
|
||||
for i in 0..10 {
|
||||
slab.insert(i);
|
||||
}
|
||||
for i in 1..6 {
|
||||
slab.remove(i);
|
||||
}
|
||||
let result = catch_unwind(AssertUnwindSafe(|| {
|
||||
slab.compact(|&mut v, from, to| {
|
||||
assert!(from > to);
|
||||
assert_eq!(from, v);
|
||||
if v == 7 {
|
||||
panic!("test");
|
||||
}
|
||||
true
|
||||
})
|
||||
}));
|
||||
match result {
|
||||
Err(ref payload) if payload.downcast_ref() == Some(&"test") => {}
|
||||
Err(bug) => resume_unwind(bug),
|
||||
Ok(()) => unreachable!(),
|
||||
}
|
||||
assert_eq!(slab.len(), 5 - 1);
|
||||
assert_eq!(slab.vacant_entry().key(), 3);
|
||||
let mut iter = slab.iter();
|
||||
assert_eq!(iter.next(), Some((0, &0)));
|
||||
assert_eq!(iter.next(), Some((1, &9)));
|
||||
assert_eq!(iter.next(), Some((2, &8)));
|
||||
assert_eq!(iter.next(), Some((6, &6)));
|
||||
assert_eq!(iter.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fully_consumed_drain() {
|
||||
let mut slab = Slab::new();
|
||||
|
||||
for i in 0..3 {
|
||||
slab.insert(i);
|
||||
}
|
||||
|
||||
{
|
||||
let mut drain = slab.drain();
|
||||
assert_eq!(Some(0), drain.next());
|
||||
assert_eq!(Some(1), drain.next());
|
||||
assert_eq!(Some(2), drain.next());
|
||||
assert_eq!(None, drain.next());
|
||||
}
|
||||
|
||||
assert!(slab.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partially_consumed_drain() {
|
||||
let mut slab = Slab::new();
|
||||
|
||||
for i in 0..3 {
|
||||
slab.insert(i);
|
||||
}
|
||||
|
||||
{
|
||||
let mut drain = slab.drain();
|
||||
assert_eq!(Some(0), drain.next());
|
||||
}
|
||||
|
||||
assert!(slab.is_empty())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drain_rev() {
|
||||
let mut slab = Slab::new();
|
||||
for i in 0..10 {
|
||||
slab.insert(i);
|
||||
}
|
||||
slab.remove(9);
|
||||
|
||||
let vals: Vec<u64> = slab.drain().rev().collect();
|
||||
assert_eq!(vals, (0..9).rev().collect::<Vec<u64>>());
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче