From 3292bdf2d5f91210f1dffe0bdc6b6cd6357be86e Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Mon, 24 Jul 2017 14:33:28 -0700 Subject: [PATCH] Rewrite slab making it more idiomatic (#35) The goal of the rewrite is to make the APIs more idiomatic and more in line with other types in the Rust std. Also, any existing function that wasn't necessary has been removed in favor of a smaller API surface. --- .travis.yml | 2 +- Cargo.toml | 13 +- LICENSE-APACHE | 201 +++++++ LICENSE-MIT | 25 + README.md | 47 +- src/lib.rs | 1491 +++++++++++++++++++++++++----------------------- tests/slab.rs | 258 +++++++++ 7 files changed, 1296 insertions(+), 741 deletions(-) create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 tests/slab.rs diff --git a/.travis.yml b/.travis.yml index 5dd073a..407e1f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: rust rust: - nightly - stable - - 1.3.0 + - 1.6.0 script: - cargo test diff --git a/Cargo.toml b/Cargo.toml index 48e772f..547b0f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,13 @@ [package] name = "slab" -version = "0.3.0" +version = "0.4.0" license = "MIT" authors = ["Carl Lerche "] -description = "Simple slab allocator" -documentation = "https://docs.rs/slab/0.3.0/slab/" +description = "Pre-allocated storage for a uniform data type" +documentation = "https://docs.rs/slab" homepage = "https://github.com/carllerche/slab" repository = "https://github.com/carllerche/slab" readme = "README.md" keywords = ["slab", "allocator"] -categories = ["memory-management"] -exclude = [ - ".gitignore", - ".travis.yml", - "test/**/*", -] +categories = ["memory-management", "data-structures"] diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..87d73e7 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2017 Carl Lerche + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..6c296be --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 Carl Lerche + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 8e4b462..c57fa93 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,46 @@ -Slab Allocator for Rust +# Slab -Preallocate memory for values of a given type. +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) + +[Documentation](https://docs.rs/slab) + +## Usage + +To use `slab`, first add this to your `Cargo.toml`: + +```toml +[dependencies] +slab = "0.4" +``` + +Next, add this to your crate: + +```rust +extern crate slab; + +use slab::Slab; + +let mut slab = Slab::new(); + +let hello = slab.insert("hello"); +let world = slab.insert("world"); + +assert_eq!(slab[hello], "hello"); +assert_eq!(slab[world], "world"); + +slab[world] = "earth"; +assert_eq!(slab[world], "earth"); +``` + +See [documentation](https://docs.rs/slab) for more details. + +# License + +`slab` is primarily distributed under the terms of both the MIT license and the +Apache License (Version 2.0), with portions covered by various BSD-like +licenses. + +See LICENSE-APACHE, and LICENSE-MIT for details. diff --git a/src/lib.rs b/src/lib.rs index dc2105f..94c4fcf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,121 @@ -use std::{fmt, mem, usize}; +//! Pre-allocated storage for a uniform data type. +//! +//! `Slab` provides pre-allocated storage for a single data type. If many values +//! of a single type are being allocated, it can be more efficient to +//! pre-allocate the necessary storage. Since the size of the type is uniform, +//! memory fragmentation can be avoided. Storing, clearing, and lookup +//! operations become very cheap. +//! +//! While `Slab` may look like other Rust collections, it is not intended to be +//! used as a general purpose collection. The primary difference between `Slab` +//! and `Vec` is that `Slab` returns the key when storing the value. +//! +//! It is important to note that keys may be reused. In other words, once a +//! value associated with a given key is removed from a slab, that key may be +//! returned from future calls to `insert`. +//! +//! # Examples +//! +//! Basic storing and retrieval. +//! +//! ``` +//! # use slab::*; +//! let mut slab = Slab::new(); +//! +//! let hello = slab.insert("hello"); +//! let world = slab.insert("world"); +//! +//! assert_eq!(slab[hello], "hello"); +//! assert_eq!(slab[world], "world"); +//! +//! slab[world] = "earth"; +//! assert_eq!(slab[world], "earth"); +//! ``` +//! +//! Sometimes it is useful to be able to associate the key with the value being +//! inserted in the slab. This can be done with the `vacant_entry` API as such: +//! +//! ``` +//! # use slab::*; +//! let mut slab = Slab::new(); +//! +//! let hello = { +//! let entry = slab.vacant_entry(); +//! let key = entry.key(); +//! +//! entry.insert((key, "hello")); +//! key +//! }; +//! +//! assert_eq!(hello, slab[hello].0); +//! assert_eq!("hello", slab[hello].1); +//! ``` +//! +//! It is generally a good idea to specify the desired capacity of a slab at +//! creation time. Note that `Slab` will grow the internal capacity when +//! attempting to insert a new value once the existing capacity has been reached. +//! To avoid this, add a check. +//! +//! ``` +//! # use slab::*; +//! let mut slab = Slab::with_capacity(1024); +//! +//! // ... use the slab +//! +//! if slab.len() == slab.capacity() { +//! panic!("slab full"); +//! } +//! +//! slab.insert("the slab is not at capacity yet"); +//! ``` +//! +//! # Capacity and reallocation +//! +//! The capacity of a slab is the amount of space allocated for any future +//! values that will be inserted in the slab. This is not to be confused with +//! the *length* of the slab, which specifies the number of actual values +//! currently being inserted. If a slab's length is equal to its capacity, the +//! next value inserted into the slab will require growing the slab by +//! reallocating. +//! +//! For example, a slab with capacity 10 and length 0 would be an empty slab +//! with space for 10 more stored values. Storing 10 or fewer elements into the +//! slab will not change its capacity or cause reallocation to occur. However, +//! if the slab length is increased to 11 (due to another `insert`), it will +//! have to reallocate, which can be slow. For this reason, it is recommended to +//! use [`Slab::with_capacity`] whenever possible to specify how many values the +//! slab is expected to store. +//! +//! # Implementation +//! +//! `Slab` is backed by a `Vec` of slots. Each slot is either occupied or +//! vacant. `Slab` maintains a stack of vacant slots using a linked list. To +//! find a vacant slot, the stack is popped. When a slot is released, it is +//! pushed onto the stack. +//! +//! If there are no more available slots in the stack, then `Vec::reserve(1)` is +//! called and a new slot is created. +//! +//! [`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")] +#![crate_name = "slab"] + +use std::{fmt, mem}; use std::iter::IntoIterator; use std::ops; use std::marker::PhantomData; -/// A preallocated chunk of memory for storing objects of the same type. -pub struct Slab { +/// Pre-allocated storage for a uniform data type +/// +/// See [module documentation] for more details. +/// +/// [module documentation]: index.html +#[derive(Clone)] +pub struct Slab { // Chunk of memory - entries: Vec>, + entries: Vec>, // Number of Filled elements currently in the slab len: usize, @@ -14,860 +123,784 @@ pub struct Slab { // Offset of the next available slot in the slab. Set to the slab's // capacity when the slab is full. next: usize, - - _marker: PhantomData, -} - -/// A handle to an occupied slot in the `Slab` -pub struct Entry<'a, T: 'a, I: 'a> { - slab: &'a mut Slab, - idx: usize, } -/// A handle to a vacant slot in the `Slab` -pub struct VacantEntry<'a, T: 'a, I: 'a> { - slab: &'a mut Slab, - idx: usize, +/// A handle to an vacant entry in a `Slab`. +/// +/// `VacantEntry` allows constructing values with the key that they will be +/// assigned to. +/// +/// # Examples +/// +/// ``` +/// # use slab::*; +/// let mut slab = Slab::new(); +/// +/// let hello = { +/// let entry = slab.vacant_entry(); +/// let key = entry.key(); +/// +/// entry.insert((key, "hello")); +/// key +/// }; +/// +/// assert_eq!(hello, slab[hello].0); +/// assert_eq!("hello", slab[hello].1); +/// ``` +#[derive(Debug)] +pub struct VacantEntry<'a, T: 'a> { + slab: &'a mut Slab, + key: usize, } /// An iterator over the values stored in the `Slab` -pub struct Iter<'a, T: 'a, I: 'a> { - slab: &'a Slab, - cur_idx: usize, - yielded: usize, +#[derive(Debug)] +pub struct Iter<'a, T: 'a> { + slab: &'a Slab, + curr: usize, } /// A mutable iterator over the values stored in the `Slab` -pub struct IterMut<'a, T: 'a, I: 'a> { - slab: *mut Slab, - cur_idx: usize, - yielded: usize, +pub struct IterMut<'a, T: 'a> { + slab: *mut Slab, + curr: usize, _marker: PhantomData<&'a mut ()>, } -enum Slot { - Empty(usize), - Filled(T), - Invalid, -} - -unsafe impl Send for Slab where T: Send {} - -macro_rules! some { - ($expr:expr) => (match $expr { - Some(val) => val, - None => return None, - }) +#[derive(Clone)] +enum Entry { + Vacant(usize), + Occupied(T), } -impl Slab { - /// Returns an empty `Slab` with the requested capacity - pub fn with_capacity(capacity: usize) -> Slab { - let entries = (1..capacity + 1) - .map(Slot::Empty) - .collect::>(); +impl Slab { + /// Construct a new, empty `Slab`. + /// + /// The function does not allocate and the returned slab will have no + /// capacity until `insert` is called or capacity is explicitly reserved. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let slab: Slab = Slab::new(); + /// ``` + pub fn new() -> Slab { + Slab::with_capacity(0) + } + /// Construct a new, empty `Slab` with the specified capacity. + /// + /// The returned slab will be able to store exactly `capacity` without + /// reallocating. If `capacity` is 0, the slab will not allocate. + /// + /// It is important to note that this function does not specify the *length* + /// of the returned slab, but only the capacity. For an explanation of the + /// difference between length and capacity, see [Capacity and + /// reallocation](index.html#capacity-and-reallocation). + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::with_capacity(10); + /// + /// // The slab contains no values, even though it has capacity for more + /// assert_eq!(slab.len(), 0); + /// + /// // These are all done without reallocating... + /// for i in 0..10 { + /// slab.insert(i); + /// } + /// + /// // ...but this may make the slab reallocate + /// slab.insert(11); + /// ``` + pub fn with_capacity(capacity: usize) -> Slab { Slab { - entries: entries, + entries: Vec::with_capacity(capacity), next: 0, len: 0, - _marker: PhantomData, } } - /// Returns the number of values stored by the `Slab` - pub fn len(&self) -> usize { - self.len - } - - /// Returns the total capacity of the `Slab` + /// Returns the number of values the slab can store without reallocating. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let slab: Slab = Slab::with_capacity(10); + /// assert_eq!(slab.capacity(), 10); + /// ``` pub fn capacity(&self) -> usize { - self.entries.len() - } - - /// Returns true if the `Slab` is storing no values - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - /// Returns the number of available slots remaining in the `Slab` - pub fn available(&self) -> usize { - self.entries.len() - self.len - } - - /// Returns true if the `Slab` has available slots - pub fn has_available(&self) -> bool { - self.available() > 0 - } -} - -impl + From> Slab { - /// Returns true if the `Slab` contains a value for the given token - pub fn contains(&self, idx: I) -> bool { - self.get(idx).is_some() + self.entries.capacity() } - /// Get a reference to the value associated with the given token - pub fn get(&self, idx: I) -> Option<&T> { - let idx = some!(self.local_index(idx)); + /// Reserves capacity for at least `additional` more values to be stored + /// without allocating. + /// + /// `reserve` does nothing if the slab already has sufficient capcity for + /// `additional` more values. If more capacity is required, a new segment of + /// memory will be allocated and all existing values will be copied into it. + /// As such, if the slab is already very large, a call to `reserve` can end + /// up being expensive. + /// + /// The slab may reserve more than `additional` extra space in order to + /// avoid frequent reallocations. Use `reserve_exact` instead to guarantee + /// that only the requested space is allocated. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// slab.insert("hello"); + /// slab.reserve(10); + /// assert!(slab.capacity() >= 11); + /// ``` + pub fn reserve(&mut self, additional: usize) { + let available = self.entries.len() - self.len; - match self.entries[idx] { - Slot::Filled(ref val) => Some(val), - Slot::Empty(_) => None, - Slot::Invalid => panic!("Slab corrupt"), + if available >= additional { + return; } - } - - /// Get a mutable reference to the value associated with the given token - pub fn get_mut(&mut self, idx: I) -> Option<&mut T> { - let idx = some!(self.local_index(idx)); - match self.entries[idx] { - Slot::Filled(ref mut v) => Some(v), - _ => None, - } + self.entries.reserve(additional - available); } - /// Get a reference to the value associated with the given token + /// Reserves the minimum capacity required to store exactly `additional` + /// more values. /// - /// # Safety + /// `reserve_exact` does nothing if the slab already has sufficient capacity + /// for `additional` more valus. If more capacity is required, a new segment + /// of memory will be allocated and all existing values will be copied into + /// it. As such, if the slab is already very large, a call to `reserve` can + /// end up being expensive. /// - /// This is unsafe due to ignored runtime checks - pub unsafe fn get_unchecked(&self, idx: I) -> &T { - let idx: usize = idx.into(); - - match *self.entries.get_unchecked(idx) { - Slot::Filled(ref val) => val, - _ => panic!("Invalid slot"), - } - } - - /// Get a mutable reference to the value associated with the given token + /// Note that the allocator may give the slab more space than it requests. + /// Therefore capacity can not be relied upon to be precisely minimal. + /// Prefer `reserve` if future insertions are expected. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. /// - /// # Safety + /// # Examples /// - /// This is unsafe due to ignored runtime checks - pub unsafe fn get_unchecked_mut(&mut self, idx: I) -> &mut T { - let idx: usize = idx.into(); + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// slab.insert("hello"); + /// slab.reserve_exact(10); + /// assert!(slab.capacity() >= 11); + /// ``` + pub fn reserve_exact(&mut self, additional: usize) { + let available = self.entries.len() - self.len; - match *self.entries.get_unchecked_mut(idx) { - Slot::Filled(ref mut v) => v, - _ => panic!("Invalid slot"), + if available >= additional { + return; } - } - /// Insert a value into the slab, returning the associated token - pub fn insert(&mut self, val: T) -> Result { - match self.vacant_entry() { - Some(entry) => Ok(entry.insert(val).index()), - None => Err(val), - } + self.entries.reserve_exact(additional - available); } - /// Returns a handle to an entry. + /// Shrinks the capacity of the slab as much as possible. /// - /// This allows more advanced manipulation of the value stored at the given - /// index. - pub fn entry(&mut self, idx: I) -> Option> { - let idx = some!(self.local_index(idx)); - - match self.entries[idx] { - Slot::Filled(_) => { - Some(Entry { - slab: self, - idx: idx, - }) - } - Slot::Empty(_) => None, - Slot::Invalid => panic!("Slab corrupt"), - } + /// 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. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::with_capacity(10); + /// + /// for i in 0..3 { + /// slab.insert(i); + /// } + /// + /// assert_eq!(slab.capacity(), 10); + /// slab.shrink_to_fit(); + /// assert!(slab.capacity() >= 3); + /// ``` + /// + /// In this case, even though two values are removed, the slab cannot shrink + /// past the last value. + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::with_capacity(10); + /// + /// for i in 0..3 { + /// slab.insert(i); + /// } + /// + /// slab.remove(0); + /// slab.remove(1); + /// + /// assert_eq!(slab.capacity(), 10); + /// slab.shrink_to_fit(); + /// assert!(slab.capacity() >= 3); + /// ``` + pub fn shrink_to_fit(&mut self) { + self.entries.shrink_to_fit(); } - /// Returns a handle to a vacant entry. + /// Clear the slab of all values /// - /// This allows optionally inserting a value that is constructed with the - /// index. - pub fn vacant_entry(&mut self) -> Option> { - let idx = self.next; - - if idx >= self.entries.len() { - return None; - } - - Some(VacantEntry { - slab: self, - idx: idx, - }) + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// + /// for i in 0..3 { + /// slab.insert(i); + /// } + /// + /// slab.clear(); + /// assert!(slab.is_empty()); + /// ``` + pub fn clear(&mut self) { + self.entries.clear(); + self.len = 0; + self.next = 0; } - /// Releases the given slot - pub fn remove(&mut self, idx: I) -> Option { - self.entry(idx).map(Entry::remove) + /// Returns the number of stored values + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// + /// for i in 0..3 { + /// slab.insert(i); + /// } + /// + /// assert_eq!(3, slab.len()); + /// ``` + pub fn len(&self) -> usize { + self.len } - /// Retain only the elements specified by the predicate. + /// Returns `true` if no values are stored in the slab /// - /// In other words, remove all elements `e` such that `f(&e)` returns false. - /// This method operates in place and preserves the order of the retained - /// elements. - pub fn retain(&mut self, mut f: F) - where F: FnMut(&T) -> bool - { - for i in 0..self.entries.len() { - if let Some(e) = self.entry(I::from(i)) { - if !f(e.get()) { - e.remove(); - } - } - } + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// assert!(slab.is_empty()); + /// + /// slab.insert(1); + /// assert!(!slab.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.len == 0 } - /// An iterator for visiting all elements stored in the `Slab` - pub fn iter(&self) -> Iter { + /// Returns an iterator over the slab + /// + /// This function should generally be **avoided** as it is not efficient. + /// Iterators must iterate over every slot in the slab even if it is + /// vaccant. As such, a slab with a capacity of 1 million but only one + /// stored value must still iterate the million slots. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// + /// for i in 0..3 { + /// slab.insert(i); + /// } + /// + /// let mut iterator = slab.iter(); + /// + /// assert_eq!(iterator.next(), Some((0, &0))); + /// assert_eq!(iterator.next(), Some((1, &1))); + /// assert_eq!(iterator.next(), Some((2, &2))); + /// assert_eq!(iterator.next(), None); + /// ``` + pub fn iter(&self) -> Iter { Iter { slab: self, - cur_idx: 0, - yielded: 0, + curr: 0, } } - /// A mutable iterator for visiting all elements stored in the `Slab` - pub fn iter_mut(&mut self) -> IterMut { + /// Returns an iterator that allows modifying each value. + /// + /// This function should generally be **avoided** as it is not efficient. + /// Iterators must iterate over every slot in the slab even if it is + /// vaccant. As such, a slab with a capacity of 1 million but only one + /// stored value must still iterate the million slots. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// + /// let key1 = slab.insert(0); + /// let key2 = slab.insert(1); + /// + /// for (key, val) in slab.iter_mut() { + /// if key == key1 { + /// *val += 2; + /// } + /// } + /// + /// assert_eq!(slab[key1], 2); + /// assert_eq!(slab[key2], 1); + /// ``` + pub fn iter_mut(&mut self) -> IterMut { IterMut { - slab: self as *mut Slab, - cur_idx: 0, - yielded: 0, + slab: self as *mut Slab, + curr: 0, _marker: PhantomData, } } - /// Empty the slab, by freeing all entries - pub fn clear(&mut self) { - for (i, e) in self.entries.iter_mut().enumerate() { - *e = Slot::Empty(i + 1) + /// Returns a reference to the value associated with the given key + /// + /// If the given key is not associated with a value, then `None` is + /// returned. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// let key = slab.insert("hello"); + /// + /// assert_eq!(slab.get(key), Some(&"hello")); + /// assert_eq!(slab.get(123), None); + /// ``` + pub fn get(&self, key: usize) -> Option<&T> { + match self.entries.get(key) { + Some(&Entry::Occupied(ref val)) => Some(val), + _ => None, } - self.next = 0; - self.len = 0; } - /// Reserves the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `Slab`. Does nothing if the capacity is - /// already sufficient. - pub fn reserve_exact(&mut self, additional: usize) { - let prev_len = self.entries.len(); - - // Ensure `entries_num` isn't too big - assert!(additional < usize::MAX - prev_len, "capacity too large"); - - let prev_len_next = prev_len + 1; - self.entries.extend((prev_len_next..(prev_len_next + additional)).map(Slot::Empty)); - - debug_assert_eq!(self.entries.len(), prev_len + additional); - } - - fn insert_at(&mut self, idx: usize, value: T) -> I { - self.next = match self.entries[idx] { - Slot::Empty(next) => next, - Slot::Filled(_) => panic!("Index already contains value"), - Slot::Invalid => panic!("Slab corrupt"), - }; - - self.entries[idx] = Slot::Filled(value); - self.len += 1; - - I::from(idx) - } - - fn replace(&mut self, idx: usize, e: Slot) -> Option { - if let Slot::Filled(val) = mem::replace(&mut self.entries[idx], e) { - self.next = idx; - return Some(val); + /// Returns a mutable reference to the value associated with the given key + /// + /// If the given key is not associated with a value, then `None` is + /// returned. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// let key = slab.insert("hello"); + /// + /// *slab.get_mut(key).unwrap() = "world"; + /// + /// assert_eq!(slab[key], "world"); + /// assert_eq!(slab.get_mut(123), None); + /// ``` + pub fn get_mut(&mut self, key: usize) -> Option<&mut T> { + match self.entries.get_mut(key) { + Some(&mut Entry::Occupied(ref mut val)) => Some(val), + _ => None, } - - None } - fn local_index(&self, idx: I) -> Option { - let idx: usize = idx.into(); - - if idx >= self.entries.len() { - return None; + /// Returns a reference to the value associated with the given key without + /// performing bounds checking. + /// + /// This function should be used with care. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// let key = slab.insert(2); + /// + /// unsafe { + /// assert_eq!(slab.get_unchecked(key), &2); + /// } + /// ``` + pub unsafe fn get_unchecked(&self, key: usize) -> &T { + match *self.entries.get_unchecked(key) { + Entry::Occupied(ref val) => val, + _ => unreachable!(), } - - Some(idx) - } -} - -impl + Into> ops::Index for Slab { - type Output = T; - - fn index(&self, index: I) -> &T { - self.get(index).expect("invalid index") - } -} - -impl + Into> ops::IndexMut for Slab { - fn index_mut(&mut self, index: I) -> &mut T { - self.get_mut(index).expect("invalid index") - } -} - -impl fmt::Debug for Slab - where T: fmt::Debug, - I: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, - "Slab {{ len: {}, cap: {} }}", - self.len, - self.capacity()) - } -} - -impl<'a, T, I: From + Into> IntoIterator for &'a Slab { - type Item = &'a T; - type IntoIter = Iter<'a, T, I>; - - fn into_iter(self) -> Iter<'a, T, I> { - self.iter() } -} -impl<'a, T, I: From + Into> IntoIterator for &'a mut Slab { - type Item = &'a mut T; - type IntoIter = IterMut<'a, T, I>; - - fn into_iter(self) -> IterMut<'a, T, I> { - self.iter_mut() - } -} - -/* - * - * ===== Entry ===== - * - */ - -impl<'a, T, I: From + Into> Entry<'a, T, I> { - - /// Replace the value stored in the entry - pub fn replace(&mut self, val: T) -> T { - match mem::replace(&mut self.slab.entries[self.idx], Slot::Filled(val)) { - Slot::Filled(v) => v, - _ => panic!("Slab corrupt"), + /// Returns a mutable reference to the value associated with the given key + /// without performing bounds checking. + /// + /// This function should be used with care. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// let key = slab.insert(2); + /// + /// unsafe { + /// let val = slab.get_unchecked_mut(key); + /// *val = 13; + /// } + /// + /// assert_eq!(slab[key], 13); + /// ``` + pub unsafe fn get_unchecked_mut(&mut self, key: usize) -> &mut T { + match *self.entries.get_unchecked_mut(key) { + Entry::Occupied(ref mut val) => val, + _ => unreachable!(), } } - /// Apply the function to the current value, replacing it with the result - /// of the function. - pub fn replace_with(&mut self, f: F) - where F: FnOnce(T) -> T - { - let idx = self.idx; + /// 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 + /// lookup and `remove`. Additional capacity is allocated if needed. See + /// [Capacity and reallocation](index.html#capacity-and-reallocation). + /// + /// # Panics + /// + /// Panics if the number of elements in the vector overflows a `usize`. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// let key = slab.insert("hello"); + /// assert_eq!(slab[key], "hello"); + /// ``` + pub fn insert(&mut self, val: T) -> usize { + let key = self.next; - // Take the value out of the entry, temporarily setting it to Invalid - let val = match mem::replace(&mut self.slab.entries[idx], Slot::Invalid) { - Slot::Filled(v) => f(v), - _ => panic!("Slab corrupt"), - }; + self.insert_at(key, val); - self.slab.entries[idx] = Slot::Filled(val); + key } - /// Remove and return the value stored in the entry - pub fn remove(self) -> T { - let next = self.slab.next; - - if let Some(v) = self.slab.replace(self.idx, Slot::Empty(next)) { - self.slab.len -= 1; - v - } else { - panic!("Slab corrupt"); + /// Returns a handle to a vacant entry allowing for further manipulation. + /// + /// This function is useful when creating values that must contain their + /// slab key. The returned `VaccantEntry` reserves a slot in the slab and is + /// able to query the associated key. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// + /// let hello = { + /// let entry = slab.vacant_entry(); + /// let key = entry.key(); + /// + /// entry.insert((key, "hello")); + /// key + /// }; + /// + /// assert_eq!(hello, slab[hello].0); + /// assert_eq!("hello", slab[hello].1); + /// ``` + pub fn vacant_entry(&mut self) -> VacantEntry { + VacantEntry { + key: self.next, + slab: self, } } - /// Get a reference to the value stored in the entry - pub fn get(&self) -> &T { - let idx = self.index(); - self.slab - .get(idx) - .expect("Filled slot in Entry") - } - - /// Get a mutable reference to the value stored in the entry - pub fn get_mut(&mut self) -> &mut T { - let idx = self.index(); - self.slab - .get_mut(idx) - .expect("Filled slot in Entry") - } - - /// Convert the entry handle to a mutable reference - pub fn into_mut(self) -> &'a mut T { - let idx = self.index(); - self.slab - .get_mut(idx) - .expect("Filled slot in Entry") - } - - /// Return the entry index - pub fn index(&self) -> I { - I::from(self.idx) - } -} - -/* - * - * ===== VacantEntry ===== - * - */ - -impl<'a, T, I: From + Into> VacantEntry<'a, T, I> { - /// Insert a value into the entry - pub fn insert(self, val: T) -> Entry<'a, T, I> { - self.slab.insert_at(self.idx, val); - - Entry { - slab: self.slab, - idx: self.idx, - } - } + fn insert_at(&mut self, key: usize, val: T) { + self.len += 1; - /// Returns the entry index - pub fn index(&self) -> I { - I::from(self.idx) - } -} + if key == self.entries.len() { + self.entries.push(Entry::Occupied(val)); + self.next = key + 1; + } else { + let prev = mem::replace( + &mut self.entries[key], + Entry::Occupied(val)); -/* - * - * ===== Iter ===== - * - */ - -impl<'a, T, I> Iterator for Iter<'a, T, I> { - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - while self.yielded < self.slab.len { - match self.slab.entries[self.cur_idx] { - Slot::Filled(ref v) => { - self.cur_idx += 1; - self.yielded += 1; - return Some(v); - } - Slot::Empty(_) => { - self.cur_idx += 1; - } - Slot::Invalid => { - panic!("Slab corrupt"); + match prev { + Entry::Vacant(next) => { + self.next = next; } + _ => unreachable!(), } } - - None } -} - -/* - * - * ===== IterMut ===== - * - */ - -impl<'a, T, I> Iterator for IterMut<'a, T, I> { - type Item = &'a mut T; - fn next(&mut self) -> Option<&'a mut T> { - unsafe { - while self.yielded < (*self.slab).len { - let idx = self.cur_idx; - - match (*self.slab).entries[idx] { - Slot::Filled(ref mut v) => { - self.cur_idx += 1; - self.yielded += 1; - return Some(v); - } - Slot::Empty(_) => { - self.cur_idx += 1; - } - Slot::Invalid => { - panic!("Slab corrupt"); - } - } + /// Removes and returns the value associated with the given key. + /// + /// The key is then released and may be associated with future stored + /// values. + /// + /// # Panics + /// + /// Panics if `key` is not associated with a value. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// + /// let hello = slab.insert("hello"); + /// + /// assert_eq!(slab.remove(hello), "hello"); + /// 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)); + + 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"); } - - None - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct MyIndex(pub usize); - - impl From for MyIndex { - fn from(i: usize) -> MyIndex { - MyIndex(i) - } - } - - impl Into for MyIndex { - fn into(self) -> usize { - self.0 } } - #[test] - fn test_index_trait() { - let mut slab = Slab::::with_capacity(1); - let idx = slab.insert(10).ok().expect("Failed to insert"); - assert_eq!(idx, MyIndex(0)); - assert_eq!(slab[idx], 10); - } - - #[test] - fn test_insertion() { - let mut slab = Slab::::with_capacity(1); - assert_eq!(slab.is_empty(), true); - assert_eq!(slab.has_available(), true); - assert_eq!(slab.available(), 1); - let idx = slab.insert(10).ok().expect("Failed to insert"); - assert_eq!(slab[idx], 10); - assert_eq!(slab.is_empty(), false); - assert_eq!(slab.has_available(), false); - assert_eq!(slab.available(), 0); + /// Returns `true` if a value is associated with the given key. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// + /// let hello = slab.insert("hello"); + /// assert!(slab.contains(hello)); + /// + /// slab.remove(hello); + /// + /// 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) } - #[test] - fn test_insert_with() { - let mut slab = Slab::::with_capacity(1); + /// Retain only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(usize, &mut e)` + /// returns false. This method operates in place and preserves the key + /// associated with the retained values. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// + /// let k1 = slab.insert(0); + /// let k2 = slab.insert(1); + /// let k3 = slab.insert(2); + /// + /// slab.retain(|key, val| key == k1 || *val == 1); + /// + /// assert!(slab.contains(k1)); + /// assert!(slab.contains(k2)); + /// assert!(!slab.contains(k3)); + /// + /// assert_eq!(2, slab.len()); + /// ``` + pub fn retain(&mut self, mut f: F) + where F: FnMut(usize, &mut T) -> bool + { + for i in 0..self.entries.len() { + let keep = match self.entries[i] { + Entry::Occupied(ref mut v) => f(i, v), + _ => true, + }; - { - let e = slab.vacant_entry().unwrap(); - assert_eq!(e.index(), 0); - let e = e.insert(5); - assert_eq!(5, *e.get()); + if !keep { + self.remove(i); + } } - - assert_eq!(Some(&5), slab.get(0)); } +} - #[test] - fn test_repeated_insertion() { - let mut slab = Slab::::with_capacity(10); +impl ops::Index for Slab { + type Output = T; - for i in 0..10 { - let idx = slab.insert(i + 10).ok().expect("Failed to insert"); - assert_eq!(slab[idx], i + 10); + fn index(&self, key: usize) -> &T { + match self.entries[key] { + Entry::Occupied(ref v) => v, + _ => panic!("invalid key"), } - - slab.insert(20).err().expect("Inserted when full"); } +} - #[test] - fn test_repeated_insertion_and_removal() { - let mut slab = Slab::::with_capacity(10); - let mut indices = vec![]; - - for i in 0..10 { - let idx = slab.insert(i + 10).ok().expect("Failed to insert"); - indices.push(idx); - assert_eq!(slab[idx], i + 10); - } - - for &i in indices.iter() { - slab.remove(i); +impl ops::IndexMut for Slab { + fn index_mut(&mut self, key: usize) -> &mut T { + match self.entries[key] { + Entry::Occupied(ref mut v) => v, + _ => panic!("invalid key"), } - - slab.insert(20).ok().expect("Failed to insert in newly empty slab"); - } - - #[test] - fn test_insertion_when_full() { - let mut slab = Slab::::with_capacity(1); - slab.insert(10).ok().expect("Failed to insert"); - slab.insert(10).err().expect("Inserted into a full slab"); - } - - #[test] - fn test_removal_at_boundries() { - let mut slab = Slab::::with_capacity(1); - assert_eq!(slab.remove(0), None); - assert_eq!(slab.remove(1), None); - } - - #[test] - fn test_removal_is_successful() { - let mut slab = Slab::::with_capacity(1); - let t1 = slab.insert(10).ok().expect("Failed to insert"); - slab.remove(t1); - let t2 = slab.insert(20).ok().expect("Failed to insert"); - assert_eq!(slab[t2], 20); - } - - #[test] - fn test_remove_empty_entry() { - let mut s = Slab::<(), usize>::with_capacity(3); - let t1 = s.insert(()).unwrap(); - assert!(s.remove(t1).is_some()); - assert!(s.remove(t1).is_none()); - assert!(s.insert(()).is_ok()); - assert!(s.insert(()).is_ok()); - } - - #[test] - fn test_mut_retrieval() { - let mut slab = Slab::<_, usize>::with_capacity(1); - let t1 = slab.insert("foo".to_string()).ok().expect("Failed to insert"); - - slab[t1].push_str("bar"); - - assert_eq!(&slab[t1][..], "foobar"); } +} - #[test] - #[should_panic] - fn test_reusing_slots_1() { - let mut slab = Slab::::with_capacity(16); - - let t0 = slab.insert(123).unwrap(); - let t1 = slab.insert(456).unwrap(); - - assert!(slab.len() == 2); - assert!(slab.available() == 14); - - slab.remove(t0); - - assert!(slab.len() == 1, "actual={}", slab.len()); - assert!(slab.available() == 15); - - slab.remove(t1); - - assert!(slab.len() == 0); - assert!(slab.available() == 16); +impl<'a, T> IntoIterator for &'a Slab { + type Item = (usize, &'a T); + type IntoIter = Iter<'a, T>; - let _ = slab[t1]; + fn into_iter(self) -> Iter<'a, T> { + self.iter() } +} - #[test] - fn test_reusing_slots_2() { - let mut slab = Slab::::with_capacity(16); - - let t0 = slab.insert(123).unwrap(); - - assert!(slab[t0] == 123); - assert!(slab.remove(t0) == Some(123)); - - let t0 = slab.insert(456).unwrap(); - - assert!(slab[t0] == 456); - - let t1 = slab.insert(789).unwrap(); - - assert!(slab[t0] == 456); - assert!(slab[t1] == 789); - - assert!(slab.remove(t0).unwrap() == 456); - assert!(slab.remove(t1).unwrap() == 789); - - assert!(slab.len() == 0); - } +impl<'a, T> IntoIterator for &'a mut Slab { + type Item = (usize, &'a mut T); + type IntoIter = IterMut<'a, T>; - #[test] - #[should_panic] - fn test_accessing_out_of_bounds() { - let slab = Slab::::with_capacity(16); - slab[0]; + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() } +} - #[test] - #[should_panic] - fn test_capacity_too_large1() { - use std::usize; - Slab::::with_capacity(usize::MAX); +impl fmt::Debug for Slab where T: fmt::Debug { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, + "Slab {{ len: {}, cap: {} }}", + self.len, + self.capacity()) } +} - #[test] - #[should_panic] - fn test_capacity_too_large_in_reserve_exact() { - use std::usize; - let mut slab = Slab::::with_capacity(100); - slab.reserve_exact(usize::MAX - 100); +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("slab", unsafe { &*self.slab }) + .field("curr", &self.curr) + .finish() } +} - #[test] - fn test_contains() { - let mut slab = Slab::with_capacity(16); - assert!(!slab.contains(0)); +// ===== VacantEntry ===== - let idx = slab.insert(111).unwrap(); - assert!(slab.contains(idx)); - } +impl<'a, T> VacantEntry<'a, T> { + /// Insert a value in the entry, returning a mutable reference to the value. + /// + /// To get the key associated with the value, use `key` prior to calling + /// `insert`. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// + /// let hello = { + /// let entry = slab.vacant_entry(); + /// let key = entry.key(); + /// + /// entry.insert((key, "hello")); + /// key + /// }; + /// + /// assert_eq!(hello, slab[hello].0); + /// assert_eq!("hello", slab[hello].1); + /// ``` + pub fn insert(self, val: T) -> &'a mut T { + self.slab.insert_at(self.key, val); - #[test] - fn test_get() { - let mut slab = Slab::::with_capacity(16); - let tok = slab.insert(5).unwrap(); - assert_eq!(slab.get(tok), Some(&5)); - assert_eq!(slab.get(1), None); - assert_eq!(slab.get(23), None); - unsafe { - assert_eq!(*slab.get_unchecked(tok), 5); + match self.slab.entries[self.key] { + Entry::Occupied(ref mut v) => v, + _ => unreachable!(), } } - #[test] - fn test_get_mut() { - let mut slab = Slab::::with_capacity(16); - let tok = slab.insert(5u32).unwrap(); - { - let mut_ref = slab.get_mut(tok).unwrap(); - assert_eq!(*mut_ref, 5); - *mut_ref = 12; - } - assert_eq!(slab[tok], 12); - assert_eq!(slab.get_mut(1), None); - assert_eq!(slab.get_mut(23), None); - unsafe { - assert_eq!(*slab.get_unchecked_mut(tok), 12); - *slab.get_unchecked_mut(tok) = 13; - assert_eq!(*slab.get_unchecked_mut(tok), 13); - } - } - - #[test] - fn test_replace() { - let mut slab = Slab::::with_capacity(16); - let tok = slab.insert(5).unwrap(); - - slab.entry(tok).unwrap().replace(6); - assert!(slab.entry(tok + 1).is_none()); - - assert_eq!(slab[tok], 6); - assert_eq!(slab.len(), 1); - } - - #[test] - fn test_replace_again() { - let mut slab = Slab::::with_capacity(16); - let tok = slab.insert(5).unwrap(); - - slab.entry(tok).unwrap().replace(6); - slab.entry(tok).unwrap().replace(7); - slab.entry(tok).unwrap().replace(8); - assert_eq!(slab[tok], 8); - } - - #[test] - fn test_replace_with() { - let mut slab = Slab::::with_capacity(16); - let tok = slab.insert(5u32).unwrap(); - slab.entry(tok).unwrap().replace_with(|x| x + 1); - assert_eq!(slab[tok], 6); - } - - #[test] - fn test_retain() { - let mut slab = Slab::::with_capacity(2); - let tok1 = slab.insert(0).unwrap(); - let tok2 = slab.insert(1).unwrap(); - slab.retain(|x| x % 2 == 0); - assert_eq!(slab.len(), 1); - assert_eq!(slab[tok1], 0); - assert_eq!(slab.contains(tok2), false); + /// Return the key associated with this entry. + /// + /// A value stored in this entry will be associated with this key. + /// + /// # Examples + /// + /// ``` + /// # use slab::*; + /// let mut slab = Slab::new(); + /// + /// let hello = { + /// let entry = slab.vacant_entry(); + /// let key = entry.key(); + /// + /// entry.insert((key, "hello")); + /// key + /// }; + /// + /// assert_eq!(hello, slab[hello].0); + /// assert_eq!("hello", slab[hello].1); + /// ``` + pub fn key(&self) -> usize { + self.key } +} - #[test] - fn test_iter() { - let mut slab = Slab::::with_capacity(4); - for i in 0..4 { - slab.insert(i).unwrap(); - } - - let vals: Vec = slab.iter().map(|r| *r).collect(); - assert_eq!(vals, vec![0, 1, 2, 3]); - - slab.remove(1); - - let vals: Vec = slab.iter().map(|r| *r).collect(); - assert_eq!(vals, vec![0, 2, 3]); - } +// ===== Iter ===== - #[test] - fn test_iter_mut() { - let mut slab = Slab::::with_capacity(4); - for i in 0..4 { - slab.insert(i).unwrap(); - } - for e in slab.iter_mut() { - *e = *e + 1; - } +impl<'a, T> Iterator for Iter<'a, T> { + type Item = (usize, &'a T); - let vals: Vec = slab.iter().map(|r| *r).collect(); - assert_eq!(vals, vec![1, 2, 3, 4]); + fn next(&mut self) -> Option<(usize, &'a T)> { + while self.curr < self.slab.entries.len() { + let curr = self.curr; + self.curr += 1; - slab.remove(2); - for e in slab.iter_mut() { - *e = *e + 1; + if let Entry::Occupied(ref v) = self.slab.entries[curr] { + return Some((curr, v)); + } } - let vals: Vec = slab.iter().map(|r| *r).collect(); - assert_eq!(vals, vec![2, 3, 5]); + None } +} - #[test] - fn test_reserve_exact() { - let mut slab = Slab::::with_capacity(4); - for i in 0..4 { - slab.insert(i).unwrap(); - } - - assert!(slab.insert(0).is_err()); - - slab.reserve_exact(3); - - let vals: Vec = slab.iter().map(|r| *r).collect(); - assert_eq!(vals, vec![0, 1, 2, 3]); - - for i in 0..3 { - slab.insert(i).unwrap(); - } - assert!(slab.insert(0).is_err()); - - let vals: Vec = slab.iter().map(|r| *r).collect(); - assert_eq!(vals, vec![0, 1, 2, 3, 0, 1, 2]); - } +// ===== IterMut ===== - #[test] - fn test_clear() { - let mut slab = Slab::::with_capacity(4); - for i in 0..4 { - slab.insert(i).unwrap(); - } +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = (usize, &'a mut T); - // clear full - slab.clear(); + fn next(&mut self) -> Option<(usize, &'a mut T)> { + unsafe { + while self.curr < (*self.slab).entries.len() { + let curr = self.curr; + self.curr += 1; - let vals: Vec = slab.iter().map(|r| *r).collect(); - assert_eq!(vals, vec![]); + if let Entry::Occupied(ref mut v) = (*self.slab).entries[curr] { + return Some((curr, v)); + } + } - for i in 0..2 { - slab.insert(i).unwrap(); + None } - - let vals: Vec = slab.iter().map(|r| *r).collect(); - assert_eq!(vals, vec![0, 1]); - - - // clear half-filled - slab.clear(); - - let vals: Vec = slab.iter().map(|r| *r).collect(); - assert_eq!(vals, vec![]); } } diff --git a/tests/slab.rs b/tests/slab.rs new file mode 100644 index 0000000..645a14b --- /dev/null +++ b/tests/slab.rs @@ -0,0 +1,258 @@ +extern crate slab; + +use slab::*; + +#[test] +fn insert_get_remove_one() { + let mut slab = Slab::new(); + assert!(slab.is_empty()); + + let key = slab.insert(10); + + assert_eq!(slab[key], 10); + assert_eq!(slab.get(key), Some(&10)); + assert!(!slab.is_empty()); + assert!(slab.contains(key)); + + assert_eq!(slab.remove(key), 10); + assert!(!slab.contains(key)); + assert!(slab.get(key).is_none()); +} + +#[test] +fn insert_get_many() { + let mut slab = Slab::with_capacity(10); + + for i in 0..10 { + let key = slab.insert(i + 10); + assert_eq!(slab[key], i + 10); + } + + assert_eq!(slab.capacity(), 10); + + // Storing another one grows the slab + let key = slab.insert(20); + assert_eq!(slab[key], 20); + + // Capacity grows by 2x + assert_eq!(slab.capacity(), 20); +} + +#[test] +fn insert_get_remove_many() { + let mut slab = Slab::with_capacity(10); + let mut keys = vec![]; + + for i in 0..10 { + for j in 0..10 { + let val = (i * 10) + j; + + let key = slab.insert(val); + keys.push((key, val)); + assert_eq!(slab[key], val); + } + + for (key, val) in keys.drain(..) { + assert_eq!(val, slab.remove(key)); + } + } + + assert_eq!(10, slab.capacity()); +} + +#[test] +fn insert_with_vacant_entry() { + let mut slab = Slab::with_capacity(1); + let key; + + { + let entry = slab.vacant_entry(); + key = entry.key(); + entry.insert(123); + } + + assert_eq!(123, slab[key]); +} + +#[test] +fn get_vacant_entry_without_using() { + let mut slab = Slab::::with_capacity(1); + let key = slab.vacant_entry().key(); + assert_eq!(key, slab.vacant_entry().key()); +} + +#[test] +#[should_panic] +fn invalid_get_panics() { + let slab = Slab::::with_capacity(1); + slab[0]; +} + +#[test] +#[should_panic] +fn double_remove_panics() { + let mut slab = Slab::::with_capacity(1); + let key = slab.insert(123); + slab.remove(key); + slab.remove(key); +} + +#[test] +#[should_panic] +fn invalid_remove_panics() { + let mut slab = Slab::::with_capacity(1); + slab.remove(0); +} + +#[test] +fn slab_get_mut() { + let mut slab = Slab::new(); + let key = slab.insert(1); + + slab[key] = 2; + assert_eq!(slab[key], 2); + + *slab.get_mut(key).unwrap() = 3; + assert_eq!(slab[key], 3); +} + +#[test] +fn reserve_does_not_allocate_if_available() { + let mut slab = Slab::with_capacity(10); + let mut keys = vec![]; + + for i in 0..10 { + keys.push(slab.insert(i)); + } + + for key in keys { + slab.remove(key); + } + + slab.reserve(10); + assert_eq!(10, slab.capacity()); +} + +#[test] +fn reserve_exact_does_not_allocate_if_available() { + let mut slab = Slab::with_capacity(10); + let mut keys = vec![]; + + for i in 0..10 { + keys.push(slab.insert(i)); + } + + for key in keys { + slab.remove(key); + } + + slab.reserve_exact(10); + assert_eq!(10, slab.capacity()); +} + +#[test] +fn retain() { + let mut slab = Slab::with_capacity(2); + + let key1 = slab.insert(0); + let key2 = slab.insert(1); + + slab.retain(|key, x| { + assert_eq!(key, *x); + *x % 2 == 0 + }); + + assert_eq!(slab.len(), 1); + assert_eq!(slab[key1], 0); + assert!(!slab.contains(key2)); + + // Ensure consistency is retained + let key = slab.insert(123); + assert_eq!(key, key2); + + assert_eq!(2, slab.len()); + assert_eq!(2, slab.capacity()); + + // Inserting another element grows + let key = slab.insert(345); + assert_eq!(key, 2); + + assert_eq!(4, slab.capacity()); +} + +#[test] +fn iter() { + let mut slab = Slab::new(); + + for i in 0..4 { + slab.insert(i); + } + + 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); + + let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect(); + assert_eq!(vals, vec![0, 2, 3]); +} + +#[test] +fn iter_mut() { + let mut slab = Slab::new(); + + for i in 0..4 { + slab.insert(i); + } + + for (i, (key, e)) in slab.iter_mut().enumerate() { + assert_eq!(i, key); + *e = *e + 1; + } + + let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect(); + assert_eq!(vals, vec![1, 2, 3, 4]); + + slab.remove(2); + + for (_, e) in slab.iter_mut() { + *e = *e + 1; + } + + let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect(); + assert_eq!(vals, vec![2, 3, 5]); +} + +#[test] +fn clear() { + let mut slab = Slab::new(); + + for i in 0..4 { + slab.insert(i); + } + + // clear full + slab.clear(); + + let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect(); + assert!(vals.is_empty()); + + assert_eq!(0, slab.len()); + assert_eq!(4, slab.capacity()); + + for i in 0..2 { + slab.insert(i); + } + + let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect(); + assert_eq!(vals, vec![0, 1]); + + // clear half-filled + slab.clear(); + + let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect(); + assert!(vals.is_empty()); +}