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()); +}