diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-15 21:45:34 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-15 21:45:34 +0000 |
commit | 88278d9b77174af1205454ff00f5e20ed8e558b4 (patch) | |
tree | 0ae352b18f96fcca3ce41cc57c7dc718af0a41e2 | |
parent | c2fda04e20fda5fa0ab597ad8a8619bf5a1db7ec (diff) | |
parent | c7a0ca3f7fc2a1505551536e0b90e0d209a2a824 (diff) | |
download | slab-aml_tz3_314012070.tar.gz |
Snap for 8730993 from c7a0ca3f7fc2a1505551536e0b90e0d209a2a824 to mainline-tzdata3-releaseaml_tz3_314012070aml_tz3_314012050aml_tz3_314012010aml_tz3_313110000aml_tz3_312511020aml_tz3_312511010aml_tz3_312410020aml_tz3_312410010android12-mainline-tzdata3-releaseaml_tz3_314012010
Change-Id: I9ef4888a2b80f50581056cbdd1f8b70d10c9d91c
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | .travis.yml | 39 | ||||
-rw-r--r-- | Android.bp | 58 | ||||
-rw-r--r-- | CHANGELOG.md | 26 | ||||
-rw-r--r-- | Cargo.toml | 38 | ||||
-rw-r--r-- | Cargo.toml.orig | 31 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | README.md | 15 | ||||
-rw-r--r-- | TEST_MAPPING | 45 | ||||
-rw-r--r-- | cargo2android.json | 5 | ||||
-rw-r--r-- | patches/disable_panic_tests_on_android.patch | 13 | ||||
-rw-r--r-- | src/lib.rs | 776 | ||||
-rw-r--r-- | src/serde.rs | 101 | ||||
-rw-r--r-- | tests/serde.rs | 49 | ||||
-rw-r--r-- | tests/slab.rs | 425 |
15 files changed, 230 insertions, 1401 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 90db974..11ad1ab 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "c512385b1a70100c8597f0f519390c80e90c9529" + "sha1": "e6b8676a1526f9eed997c9f4db82386ba33e007c" } } diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..bc2955e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,39 @@ +language: rust +matrix: + include: + - rust: nightly + - rust: stable + env: RUSTFMT=1 + + # Minimum supported Rust version + - rust: 1.6.0 + script: + - cargo build + +before_script: + - if [ "$RUSTFMT" = 1 ]; then rustup component add rustfmt; fi + +script: + - if [ "$RUSTFMT" = 1 ]; then cargo fmt -- --check; fi + - cargo test + - cargo doc --no-deps + +# Deploy documentation to S3 for specific branches. At some +# point, it would be nice to also support building docs for +# a specific tag +deploy: + provider: s3 + access_key_id: AKIAIXM3KLI7WZS4ZA3Q + secret_access_key: + secure: WyYzM8PxSKC3HQ+jINE50KOu5j3taOA4chJJ9zfAhM8Eug/Z1bK8taHnm73xrCUsvh4bv1C3XWAnSTl4YO/HykYulTIVPPs6go+ssk/59PDV6dGPhheLj2tKcSrjKd4q8H668MAPiAlNt9Rvq/GkkdAW2GXG1+otPMVFBrnR+kld6WaX5EB18SjApKgl5NwSRj9wiSIPYJTBnZQhCsaM4YRMkpFbFoHUWjSjm7N9f/6A3a3jRzW7/ZtqXvMaMazMSBAlN0/LH2UMTKCuj7nywKJt1NkpEF8mA9IEUCDBCnQs+e58v6BpkDZ2nhCJ7vdm0bISuZB6jXhg+sOycZbdb7mbn5n4mPBMa1c8WnsfmVxm7bV7G3sRpcGU8HvRT35lCCuCt4bFBX1O2abuTtVqS7XgtyChBmrSG6I/z+lw+u44Dk5bYK9A2hZSOEPFr09R8f2YRe9cqAq+uI6rNPyY7DC0eATCRCX5CxjYR6DG2bDoDFfPsBlRLQJJUl/BOM5pWYdm97iaqobxlPmKaxuxTSHw1D3Z9OvuQVeB2z+4G9xMhBBTJ0N671oZhUajpBy8OW4k9c8jl+joe01W+SScfk+qPV8ivjirTPYsUYRT3gtUgO/X/XuZ+EXGcnx+Brpu6FQtW6qSKH4Q+cofM4aohoopSIAP9dZ5zpQqQTACKyE= + bucket: rust-doc + endpoint: rust-doc.s3-website-us-east-1.amazonaws.com + skip_cleanup: true + local-dir: target/doc + upload-dir: slab/${TRAVIS_BRANCH} + acl: public_read + on: + condition: $TRAVIS_RUST_VERSION == "1.3.0" && $TRAVIS_OS_NAME == "linux" + repo: carllerche/slab + branch: + - master @@ -22,43 +22,59 @@ rust_library { name: "libslab", host_supported: true, crate_name: "slab", - cargo_env_compat: true, - cargo_pkg_version: "0.4.5", srcs: ["src/lib.rs"], - edition: "2018", - features: [ - "default", - "std", - ], + edition: "2015", apex_available: [ "//apex_available:platform", - "com.android.bluetooth", "com.android.resolv", "com.android.virt", ], min_sdk_version: "29", } -rust_test { - name: "slab_test_tests_slab", - host_supported: true, +rust_defaults { + name: "slab_defaults", crate_name: "slab", - cargo_env_compat: true, - cargo_pkg_version: "0.4.5", - srcs: ["tests/slab.rs"], + srcs: ["src/lib.rs"], test_suites: ["general-tests"], auto_gen_config: true, + edition: "2015", +} + +rust_test_host { + name: "slab_host_test_src_lib", + defaults: ["slab_defaults"], test_options: { unit_test: true, }, - edition: "2018", - features: [ - "default", - "std", - ], +} + +rust_test { + name: "slab_device_test_src_lib", + defaults: ["slab_defaults"], +} + +rust_defaults { + name: "slab_defaults_slab", + crate_name: "slab", + srcs: ["tests/slab.rs"], + test_suites: ["general-tests"], + auto_gen_config: true, + edition: "2015", rustlibs: [ - "libserde", - "libserde_test", "libslab", ], } + +rust_test_host { + name: "slab_host_test_tests_slab", + defaults: ["slab_defaults_slab"], + test_options: { + unit_test: true, + }, +} + +rust_test { + name: "slab_device_test_tests_slab", + defaults: ["slab_defaults_slab"], +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 501a25c..9a222b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,29 +1,3 @@ -# 0.4.5 (October 13, 2021) - - * Add alternate debug output for listing items in the slab (#108) - * Fix typo in debug output of IntoIter (#109) - * Impl 'Clone' for 'Iter' (#110) - -# 0.4.4 (August 06, 2021) - -* Fix panic in `FromIterator` impl (#102) -* Fix compatibility with older clippy versions (#104) -* Add `try_remove` method (#89) -* Implement `ExactSizeIterator` and `FusedIterator` for iterators (#92) - -# 0.4.3 (April 20, 2021) - -* Add no_std support for Rust 1.36 and above (#71). -* Add `get2_mut` and `get2_unchecked_mut` methods (#65). -* Make `shrink_to_fit()` remove trailing vacant entries (#62). -* Implement `FromIterator<(usize, T)>` (#62). -* Implement `IntoIterator<Item = (usize, T)>` (#62). -* Provide `size_hint()` of the iterators (#62). -* Make all iterators reversible (#62). -* Add `key_of()` method (#61) -* Add `compact()` method (#60) -* Add support for serde (#85) - # 0.4.2 (January 11, 2019) * Add `Slab::drain` (#56). @@ -3,38 +3,22 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. +# to registry (e.g. crates.io) dependencies # -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) [package] -edition = "2018" name = "slab" -version = "0.4.5" +version = "0.4.2" authors = ["Carl Lerche <me@carllerche.com>"] -exclude = ["/.*"] description = "Pre-allocated storage for a uniform data type" -homepage = "https://github.com/tokio-rs/slab" -documentation = "https://docs.rs/slab" +homepage = "https://github.com/carllerche/slab" +documentation = "https://docs.rs/slab/0.4.2/slab/" readme = "README.md" -keywords = ["slab", "allocator", "no_std"] -categories = ["memory-management", "data-structures", "no-std"] +keywords = ["slab", "allocator"] +categories = ["memory-management", "data-structures"] license = "MIT" -repository = "https://github.com/tokio-rs/slab" -[dependencies.serde] -version = "1.0.95" -features = ["alloc"] -optional = true -default-features = false -[dev-dependencies.serde] -version = "1" -features = ["derive"] - -[dev-dependencies.serde_test] -version = "1" - -[features] -default = ["std"] -std = [] +repository = "https://github.com/carllerche/slab" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index bc25be8..88da41f 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -3,29 +3,20 @@ name = "slab" # When releasing to crates.io: # - Update version number +# - lib.rs: html_root_url. # - README.md # - Update CHANGELOG.md +# - Update doc URL. +# - Cargo.toml +# - README.md # - Create git tag -version = "0.4.5" -authors = ["Carl Lerche <me@carllerche.com>"] -edition = "2018" +version = "0.4.2" license = "MIT" +authors = ["Carl Lerche <me@carllerche.com>"] description = "Pre-allocated storage for a uniform data type" -documentation = "https://docs.rs/slab" -homepage = "https://github.com/tokio-rs/slab" -repository = "https://github.com/tokio-rs/slab" +documentation = "https://docs.rs/slab/0.4.2/slab/" +homepage = "https://github.com/carllerche/slab" +repository = "https://github.com/carllerche/slab" readme = "README.md" -keywords = ["slab", "allocator", "no_std"] -categories = ["memory-management", "data-structures", "no-std"] -exclude = ["/.*"] - -[features] -std = [] -default = ["std"] - -[dependencies] -serde = { version = "1.0.95", optional = true, default-features = false, features = ["alloc"] } - -[dev-dependencies] -serde = { version = "1", features = ["derive"] } -serde_test = "1" +keywords = ["slab", "allocator"] +categories = ["memory-management", "data-structures"] @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/slab/slab-0.4.5.crate" + value: "https://static.crates.io/crates/slab/slab-0.4.2.crate" } - version: "0.4.5" + version: "0.4.2" license_type: NOTICE last_upgrade_date { - year: 2022 + year: 2020 month: 3 - day: 1 + day: 17 } } @@ -2,15 +2,10 @@ Pre-allocated storage for a uniform data type. -[![Crates.io][crates-badge]][crates-url] -[![Build Status][ci-badge]][ci-url] +[![Crates.io](https://img.shields.io/crates/v/slab.svg?maxAge=2592000)](https://crates.io/crates/slab) +[![Build Status](https://travis-ci.org/carllerche/slab.svg?branch=master)](https://travis-ci.org/carllerche/slab) -[crates-badge]: https://img.shields.io/crates/v/slab -[crates-url]: https://crates.io/crates/slab -[ci-badge]: https://img.shields.io/github/workflow/status/tokio-rs/slab/CI/master -[ci-url]: https://github.com/tokio-rs/slab/actions - -[Documentation](https://docs.rs/slab) +[Documentation](https://docs.rs/slab/0.4.2/slab/) ## Usage @@ -18,12 +13,14 @@ To use `slab`, first add this to your `Cargo.toml`: ```toml [dependencies] -slab = "0.4" +slab = "0.4.2" ``` Next, add this to your crate: ```rust +extern crate slab; + use slab::Slab; let mut slab = Slab::new(); diff --git a/TEST_MAPPING b/TEST_MAPPING index 9af5cdc..3c4c00c 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -1,51 +1,14 @@ -// Generated by update_crate_tests.py for tests that depend on this crate. +// Generated by cargo2android.py for tests in Android.bp { - "imports": [ - { - "path": "external/rust/crates/anyhow" - }, - { - "path": "external/rust/crates/futures-util" - }, - { - "path": "external/rust/crates/tokio" - }, - { - "path": "external/rust/crates/tokio-test" - } - ], "presubmit": [ { - "name": "ZipFuseTest" - }, - { - "name": "authfs_device_test_src_lib" - }, - { - "name": "doh_unit_test" - }, - { - "name": "slab_test_tests_slab" - }, - { - "name": "virtualizationservice_device_test" - } - ], - "presubmit-rust": [ - { - "name": "ZipFuseTest" - }, - { - "name": "authfs_device_test_src_lib" - }, - { - "name": "doh_unit_test" + "name": "slab_device_test_src_lib" }, { - "name": "slab_test_tests_slab" + "name": "slab_device_test_tests_slab" }, { - "name": "virtualizationservice_device_test" + "name": "futures-util_device_test_src_lib" } ] } diff --git a/cargo2android.json b/cargo2android.json index 5b266a6..44e747c 100644 --- a/cargo2android.json +++ b/cargo2android.json @@ -1,13 +1,12 @@ { "apex-available": [ "//apex_available:platform", - "com.android.bluetooth", "com.android.resolv", "com.android.virt" ], + "min_sdk_version": "29", "dependencies": true, "device": true, - "min-sdk-version": "29", "run": true, "tests": true -} +}
\ No newline at end of file diff --git a/patches/disable_panic_tests_on_android.patch b/patches/disable_panic_tests_on_android.patch deleted file mode 100644 index 4333952..0000000 --- a/patches/disable_panic_tests_on_android.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/tests/slab.rs b/tests/slab.rs -index c1570fa..8ba3064 100644 ---- a/tests/slab.rs -+++ b/tests/slab.rs -@@ -580,6 +580,8 @@ fn compact_doesnt_move_if_closure_errors() { - } - - #[test] -+// Android aborts on panic and this test relies on stack unwinding. -+#[cfg(not(target_os = "android"))] - fn compact_handles_closure_panic() { - let mut slab = Slab::new(); - for i in 0..10 { @@ -1,14 +1,6 @@ -#![cfg_attr(not(feature = "std"), no_std)] -#![warn( - missing_debug_implementations, - missing_docs, - rust_2018_idioms, - unreachable_pub -)] -#![doc(test( - no_crate_inject, - attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) -))] +#![doc(html_root_url = "https://docs.rs/slab/0.4.2")] +#![deny(warnings, missing_docs, missing_debug_implementations)] +#![cfg_attr(test, deny(warnings, unreachable_pub))] //! Pre-allocated storage for a uniform data type. //! @@ -110,17 +102,10 @@ //! //! [`Slab::with_capacity`]: struct.Slab.html#with_capacity -#[cfg(not(feature = "std"))] -extern crate alloc; -#[cfg(feature = "std")] -extern crate std as alloc; - -#[cfg(feature = "serde")] -mod serde; - -use alloc::vec::{self, Vec}; -use core::iter::{self, FromIterator, FusedIterator}; -use core::{fmt, mem, ops, slice}; +use std::iter::IntoIterator; +use std::ops; +use std::vec; +use std::{fmt, mem}; /// Pre-allocated storage for a uniform data type /// @@ -169,43 +154,25 @@ impl<T> Default for Slab<T> { /// assert_eq!("hello", slab[hello].1); /// ``` #[derive(Debug)] -pub struct VacantEntry<'a, T> { +pub struct VacantEntry<'a, T: 'a> { slab: &'a mut Slab<T>, key: usize, } -/// A consuming iterator over the values stored in a `Slab` -pub struct IntoIter<T> { - entries: iter::Enumerate<vec::IntoIter<Entry<T>>>, - len: usize, -} - /// An iterator over the values stored in the `Slab` -pub struct Iter<'a, T> { - entries: iter::Enumerate<slice::Iter<'a, Entry<T>>>, - len: usize, -} - -impl<'a, T> Clone for Iter<'a, T> { - fn clone(&self) -> Self { - Self { - entries: self.entries.clone(), - len: self.len, - } - } +pub struct Iter<'a, T: 'a> { + entries: std::slice::Iter<'a, Entry<T>>, + curr: usize, } /// A mutable iterator over the values stored in the `Slab` -pub struct IterMut<'a, T> { - entries: iter::Enumerate<slice::IterMut<'a, Entry<T>>>, - len: usize, +pub struct IterMut<'a, T: 'a> { + entries: std::slice::IterMut<'a, Entry<T>>, + curr: usize, } /// A draining iterator for `Slab` -pub struct Drain<'a, T> { - inner: vec::Drain<'a, Entry<T>>, - len: usize, -} +pub struct Drain<'a, T: 'a>(vec::Drain<'a, Entry<T>>); #[derive(Clone)] enum Entry<T> { @@ -307,7 +274,7 @@ impl<T> Slab<T> { if self.capacity() - self.len >= additional { return; } - let need_add = additional - (self.entries.len() - self.len); + let need_add = self.len + additional - self.entries.len(); self.entries.reserve(need_add); } @@ -315,7 +282,7 @@ impl<T> Slab<T> { /// more values. /// /// `reserve_exact` does nothing if the slab already has sufficient capacity - /// for `additional` more values. If more capacity is required, a new segment + /// 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. @@ -341,19 +308,16 @@ impl<T> Slab<T> { if self.capacity() - self.len >= additional { return; } - let need_add = additional - (self.entries.len() - self.len); + let need_add = self.len + additional - self.entries.len(); self.entries.reserve_exact(need_add); } - /// Shrink the capacity of the slab as much as possible without invalidating keys. - /// - /// Because values cannot be moved to a different index, the slab cannot - /// shrink past any stored values. - /// It will drop down as close as possible to the length but the allocator may - /// still inform the underlying vector that there is space for a few more elements. + /// Shrink the capacity of the slab as much as possible. /// - /// This function can take O(n) time even when the capacity cannot be reduced - /// or the allocation is shrunk in place. Repeated calls run in O(1) though. + /// 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 /// @@ -365,171 +329,33 @@ impl<T> Slab<T> { /// slab.insert(i); /// } /// + /// assert_eq!(slab.capacity(), 10); /// slab.shrink_to_fit(); - /// assert!(slab.capacity() >= 3 && slab.capacity() < 10); + /// assert!(slab.capacity() >= 3); /// ``` /// - /// The slab cannot shrink past the last present value even if previous - /// values are removed: + /// 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..4 { + /// for i in 0..3 { /// slab.insert(i); /// } /// /// slab.remove(0); - /// slab.remove(3); + /// slab.remove(1); /// + /// assert_eq!(slab.capacity(), 10); /// slab.shrink_to_fit(); - /// assert!(slab.capacity() >= 3 && slab.capacity() < 10); + /// assert!(slab.capacity() >= 3); /// ``` pub fn shrink_to_fit(&mut self) { - // Remove all vacant entries after the last occupied one, so that - // the capacity can be reduced to what is actually needed. - // If the slab is empty the vector can simply be cleared, but that - // optimization would not affect time complexity when T: Drop. - let len_before = self.entries.len(); - while let Some(&Entry::Vacant(_)) = self.entries.last() { - self.entries.pop(); - } - - // Removing entries breaks the list of vacant entries, - // so it must be repaired - if self.entries.len() != len_before { - // Some vacant entries were removed, so the list now likely¹ - // either contains references to the removed entries, or has an - // invalid end marker. Fix this by recreating the list. - self.recreate_vacant_list(); - // ¹: If the removed entries formed the tail of the list, with the - // most recently popped entry being the head of them, (so that its - // index is now the end marker) the list is still valid. - // Checking for that unlikely scenario of this infrequently called - // is not worth the code complexity. - } - self.entries.shrink_to_fit(); } - /// Iterate through all entries to recreate and repair the vacant list. - /// self.len must be correct and is not modified. - fn recreate_vacant_list(&mut self) { - self.next = self.entries.len(); - // We can stop once we've found all vacant entries - let mut remaining_vacant = self.entries.len() - self.len; - // Iterate in reverse order so that lower keys are at the start of - // the vacant list. This way future shrinks are more likely to be - // able to remove vacant entries. - for (i, entry) in self.entries.iter_mut().enumerate().rev() { - if remaining_vacant == 0 { - break; - } - if let Entry::Vacant(ref mut next) = *entry { - *next = self.next; - self.next = i; - remaining_vacant -= 1; - } - } - } - - /// Reduce the capacity as much as possible, changing the key for elements when necessary. - /// - /// To allow updating references to the elements which must be moved to a new key, - /// this function takes a closure which is called before moving each element. - /// The second and third parameters to the closure are the current key and - /// new key respectively. - /// In case changing the key for one element turns out not to be possible, - /// the move can be cancelled by returning `false` from the closure. - /// In that case no further attempts at relocating elements is made. - /// If the closure unwinds, the slab will be left in a consistent state, - /// but the value that the closure panicked on might be removed. - /// - /// # Examples - /// - /// ``` - /// # use slab::*; - /// - /// let mut slab = Slab::with_capacity(10); - /// let a = slab.insert('a'); - /// slab.insert('b'); - /// slab.insert('c'); - /// slab.remove(a); - /// slab.compact(|&mut value, from, to| { - /// assert_eq!((value, from, to), ('c', 2, 0)); - /// true - /// }); - /// assert!(slab.capacity() >= 2 && slab.capacity() < 10); - /// ``` - /// - /// The value is not moved when the closure returns `Err`: - /// - /// ``` - /// # use slab::*; - /// - /// let mut slab = Slab::with_capacity(100); - /// let a = slab.insert('a'); - /// let b = slab.insert('b'); - /// slab.remove(a); - /// slab.compact(|&mut value, from, to| false); - /// assert_eq!(slab.iter().next(), Some((b, &'b'))); - /// ``` - pub fn compact<F>(&mut self, mut rekey: F) - where - F: FnMut(&mut T, usize, usize) -> bool, - { - // If the closure unwinds, we need to restore a valid list of vacant entries - struct CleanupGuard<'a, T> { - slab: &'a mut Slab<T>, - decrement: bool, - } - impl<T> Drop for CleanupGuard<'_, T> { - fn drop(&mut self) { - if self.decrement { - // Value was popped and not pushed back on - self.slab.len -= 1; - } - self.slab.recreate_vacant_list(); - } - } - let mut guard = CleanupGuard { - slab: self, - decrement: true, - }; - - let mut occupied_until = 0; - // While there are vacant entries - while guard.slab.entries.len() > guard.slab.len { - // Find a value that needs to be moved, - // by popping entries until we find an occupied one. - // (entries cannot be empty because 0 is not greater than anything) - if let Some(Entry::Occupied(mut value)) = guard.slab.entries.pop() { - // Found one, now find a vacant entry to move it to - while let Some(&Entry::Occupied(_)) = guard.slab.entries.get(occupied_until) { - occupied_until += 1; - } - // Let the caller try to update references to the key - if !rekey(&mut value, guard.slab.entries.len(), occupied_until) { - // Changing the key failed, so push the entry back on at its old index. - guard.slab.entries.push(Entry::Occupied(value)); - guard.decrement = false; - guard.slab.entries.shrink_to_fit(); - return; - // Guard drop handles cleanup - } - // Put the value in its new spot - guard.slab.entries[occupied_until] = Entry::Occupied(value); - // ... and mark it as occupied (this is optional) - occupied_until += 1; - } - } - guard.slab.next = guard.slab.len; - guard.slab.entries.shrink_to_fit(); - // Normal cleanup is not necessary - mem::forget(guard); - } - /// Clear the slab of all values. /// /// # Examples @@ -609,10 +435,10 @@ impl<T> Slab<T> { /// assert_eq!(iterator.next(), Some((2, &2))); /// assert_eq!(iterator.next(), None); /// ``` - pub fn iter(&self) -> Iter<'_, T> { + pub fn iter(&self) -> Iter<T> { Iter { - entries: self.entries.iter().enumerate(), - len: self.len, + entries: self.entries.iter(), + curr: 0, } } @@ -641,10 +467,10 @@ impl<T> Slab<T> { /// assert_eq!(slab[key1], 2); /// assert_eq!(slab[key2], 1); /// ``` - pub fn iter_mut(&mut self) -> IterMut<'_, T> { + pub fn iter_mut(&mut self) -> IterMut<T> { IterMut { - entries: self.entries.iter_mut().enumerate(), - len: self.len, + entries: self.entries.iter_mut(), + curr: 0, } } @@ -694,64 +520,11 @@ impl<T> Slab<T> { } } - /// Return two mutable references to the values associated with the two - /// given keys simultaneously. - /// - /// If any one of the given keys is not associated with a value, then `None` - /// is returned. - /// - /// This function can be used to get two mutable references out of one slab, - /// so that you can manipulate both of them at the same time, eg. swap them. - /// - /// # Examples - /// - /// ``` - /// # use slab::*; - /// use std::mem; - /// - /// let mut slab = Slab::new(); - /// let key1 = slab.insert(1); - /// let key2 = slab.insert(2); - /// let (value1, value2) = slab.get2_mut(key1, key2).unwrap(); - /// mem::swap(value1, value2); - /// assert_eq!(slab[key1], 2); - /// assert_eq!(slab[key2], 1); - /// ``` - pub fn get2_mut(&mut self, key1: usize, key2: usize) -> Option<(&mut T, &mut T)> { - assert!(key1 != key2); - - let (entry1, entry2); - - if key1 > key2 { - let (slice1, slice2) = self.entries.split_at_mut(key1); - entry1 = slice2.get_mut(0); - entry2 = slice1.get_mut(key2); - } else { - let (slice1, slice2) = self.entries.split_at_mut(key2); - entry1 = slice1.get_mut(key1); - entry2 = slice2.get_mut(0); - } - - match (entry1, entry2) { - ( - Some(&mut Entry::Occupied(ref mut val1)), - Some(&mut Entry::Occupied(ref mut val2)), - ) => Some((val1, val2)), - _ => None, - } - } - /// Return a reference to the value associated with the given key without /// performing bounds checking. /// - /// For a safe alternative see [`get`](Slab::get). - /// /// This function should be used with care. /// - /// # Safety - /// - /// The key must be within bounds. - /// /// # Examples /// /// ``` @@ -773,14 +546,8 @@ impl<T> Slab<T> { /// Return a mutable reference to the value associated with the given key /// without performing bounds checking. /// - /// For a safe alternative see [`get_mut`](Slab::get_mut). - /// /// This function should be used with care. /// - /// # Safety - /// - /// The key must be within bounds. - /// /// # Examples /// /// ``` @@ -802,95 +569,6 @@ impl<T> Slab<T> { } } - /// Return two mutable references to the values associated with the two - /// given keys simultaneously without performing bounds checking and safety - /// condition checking. - /// - /// For a safe alternative see [`get2_mut`](Slab::get2_mut). - /// - /// This function should be used with care. - /// - /// # Safety - /// - /// - Both keys must be within bounds. - /// - The condition `key1 != key2` must hold. - /// - /// # Examples - /// - /// ``` - /// # use slab::*; - /// use std::mem; - /// - /// let mut slab = Slab::new(); - /// let key1 = slab.insert(1); - /// let key2 = slab.insert(2); - /// let (value1, value2) = unsafe { slab.get2_unchecked_mut(key1, key2) }; - /// mem::swap(value1, value2); - /// assert_eq!(slab[key1], 2); - /// assert_eq!(slab[key2], 1); - /// ``` - pub unsafe fn get2_unchecked_mut(&mut self, key1: usize, key2: usize) -> (&mut T, &mut T) { - let ptr1 = self.entries.get_unchecked_mut(key1) as *mut Entry<T>; - let ptr2 = self.entries.get_unchecked_mut(key2) as *mut Entry<T>; - match (&mut *ptr1, &mut *ptr2) { - (&mut Entry::Occupied(ref mut val1), &mut Entry::Occupied(ref mut val2)) => { - (val1, val2) - } - _ => unreachable!(), - } - } - - /// Get the key for an element in the slab. - /// - /// The reference must point to an element owned by the slab. - /// Otherwise this function will panic. - /// This is a constant-time operation because the key can be calculated - /// from the reference with pointer arithmetic. - /// - /// # Panics - /// - /// This function will panic if the reference does not point to an element - /// of the slab. - /// - /// # Examples - /// - /// ``` - /// # use slab::*; - /// - /// let mut slab = Slab::new(); - /// let key = slab.insert(String::from("foo")); - /// let value = &slab[key]; - /// assert_eq!(slab.key_of(value), key); - /// ``` - /// - /// Values are not compared, so passing a reference to a different location - /// will result in a panic: - /// - /// ```should_panic - /// # use slab::*; - /// - /// let mut slab = Slab::new(); - /// let key = slab.insert(0); - /// let bad = &0; - /// slab.key_of(bad); // this will panic - /// unreachable!(); - /// ``` - pub fn key_of(&self, present_element: &T) -> usize { - let element_ptr = present_element as *const T as usize; - let base_ptr = self.entries.as_ptr() as usize; - // Use wrapping subtraction in case the reference is bad - let byte_offset = element_ptr.wrapping_sub(base_ptr); - // The division rounds away any offset of T inside Entry - // The size of Entry<T> is never zero even if T is due to Vacant(usize) - let key = byte_offset / mem::size_of::<Entry<T>>(); - // Prevent returning unspecified (but out of bounds) values - if key >= self.entries.len() { - panic!("The reference points to a value outside this slab"); - } - // The reference cannot point to a vacant entry, because then it would not be valid - key - } - /// Insert a value in the slab, returning key assigned to the value. /// /// The returned key can later be used to retrieve or remove the value using indexed @@ -940,7 +618,7 @@ impl<T> Slab<T> { /// assert_eq!(hello, slab[hello].0); /// assert_eq!("hello", slab[hello].1); /// ``` - pub fn vacant_entry(&mut self) -> VacantEntry<'_, T> { + pub fn vacant_entry(&mut self) -> VacantEntry<T> { VacantEntry { key: self.next, slab: self, @@ -954,49 +632,15 @@ impl<T> Slab<T> { self.entries.push(Entry::Occupied(val)); self.next = key + 1; } else { - self.next = match self.entries.get(key) { - Some(&Entry::Vacant(next)) => next, - _ => unreachable!(), - }; - self.entries[key] = Entry::Occupied(val); - } - } - - /// Tries to remove the value associated with the given key, - /// returning the value if the key existed. - /// - /// The key is then released and may be associated with future stored - /// values. - /// - /// # Examples - /// - /// ``` - /// # use slab::*; - /// let mut slab = Slab::new(); - /// - /// let hello = slab.insert("hello"); - /// - /// assert_eq!(slab.try_remove(hello), Some("hello")); - /// assert!(!slab.contains(hello)); - /// ``` - pub fn try_remove(&mut self, key: usize) -> Option<T> { - if let Some(entry) = self.entries.get_mut(key) { - // Swap the entry at the provided value - let prev = mem::replace(entry, Entry::Vacant(self.next)); + let prev = mem::replace(&mut self.entries[key], Entry::Occupied(val)); match prev { - Entry::Occupied(val) => { - self.len -= 1; - self.next = key; - return val.into(); - } - _ => { - // Woops, the entry is actually vacant, restore the state - *entry = prev; + Entry::Vacant(next) => { + self.next = next; } + _ => unreachable!(), } } - None } /// Remove and return the value associated with the given key. @@ -1020,7 +664,21 @@ impl<T> Slab<T> { /// assert!(!slab.contains(hello)); /// ``` pub fn remove(&mut self, key: usize) -> T { - self.try_remove(key).expect("invalid key") + // 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"); + } + } } /// Return `true` if a value is associated with the given key. @@ -1039,10 +697,13 @@ impl<T> Slab<T> { /// assert!(!slab.contains(hello)); /// ``` pub fn contains(&self, key: usize) -> bool { - match self.entries.get(key) { - Some(&Entry::Occupied(_)) => true, - _ => false, - } + self.entries + .get(key) + .map(|e| match *e { + Entry::Occupied(_) => true, + _ => false, + }) + .unwrap_or(false) } /// Retain only the elements specified by the predicate. @@ -1112,14 +773,10 @@ impl<T> Slab<T> { /// /// assert!(slab.is_empty()); /// ``` - pub fn drain(&mut self) -> Drain<'_, T> { - let old_len = self.len; + pub fn drain(&mut self) -> Drain<T> { self.len = 0; self.next = 0; - Drain { - inner: self.entries.drain(..), - len: old_len, - } + Drain(self.entries.drain(..)) } } @@ -1127,8 +784,8 @@ impl<T> ops::Index<usize> for Slab<T> { type Output = T; fn index(&self, key: usize) -> &T { - match self.entries.get(key) { - Some(&Entry::Occupied(ref v)) => v, + match self.entries[key] { + Entry::Occupied(ref v) => v, _ => panic!("invalid key"), } } @@ -1136,25 +793,13 @@ impl<T> ops::Index<usize> for Slab<T> { impl<T> ops::IndexMut<usize> for Slab<T> { fn index_mut(&mut self, key: usize) -> &mut T { - match self.entries.get_mut(key) { - Some(&mut Entry::Occupied(ref mut v)) => v, + match self.entries[key] { + Entry::Occupied(ref mut v) => v, _ => panic!("invalid key"), } } } -impl<T> IntoIterator for Slab<T> { - type Item = (usize, T); - type IntoIter = IntoIter<T>; - - fn into_iter(self) -> IntoIter<T> { - IntoIter { - entries: self.entries.into_iter().enumerate(), - len: self.len, - } - } -} - impl<'a, T> IntoIterator for &'a Slab<T> { type Item = (usize, &'a T); type IntoIter = Iter<'a, T>; @@ -1173,141 +818,46 @@ impl<'a, T> IntoIterator for &'a mut Slab<T> { } } -/// Create a slab from an iterator of key-value pairs. -/// -/// If the iterator produces duplicate keys, the previous value is replaced with the later one. -/// The keys does not need to be sorted beforehand, and this function always -/// takes O(n) time. -/// Note that the returned slab will use space proportional to the largest key, -/// so don't use `Slab` with untrusted keys. -/// -/// # Examples -/// -/// ``` -/// # use slab::*; -/// -/// let vec = vec![(2,'a'), (6,'b'), (7,'c')]; -/// let slab = vec.into_iter().collect::<Slab<char>>(); -/// assert_eq!(slab.len(), 3); -/// assert!(slab.capacity() >= 8); -/// assert_eq!(slab[2], 'a'); -/// ``` -/// -/// With duplicate and unsorted keys: -/// -/// ``` -/// # use slab::*; -/// -/// let vec = vec![(20,'a'), (10,'b'), (11,'c'), (10,'d')]; -/// let slab = vec.into_iter().collect::<Slab<char>>(); -/// assert_eq!(slab.len(), 3); -/// assert_eq!(slab[10], 'd'); -/// ``` -impl<T> FromIterator<(usize, T)> for Slab<T> { - fn from_iter<I>(iterable: I) -> Self - where - I: IntoIterator<Item = (usize, T)>, - { - let iterator = iterable.into_iter(); - let mut slab = Self::with_capacity(iterator.size_hint().0); - - let mut vacant_list_broken = false; - let mut first_vacant_index = None; - for (key, value) in iterator { - if key < slab.entries.len() { - // iterator is not sorted, might need to recreate vacant list - if let Entry::Vacant(_) = slab.entries[key] { - vacant_list_broken = true; - slab.len += 1; - } - // if an element with this key already exists, replace it. - // This is consistent with HashMap and BtreeMap - slab.entries[key] = Entry::Occupied(value); - } else { - if first_vacant_index.is_none() && slab.entries.len() < key { - first_vacant_index = Some(slab.entries.len()); - } - // insert holes as necessary - while slab.entries.len() < key { - // add the entry to the start of the vacant list - let next = slab.next; - slab.next = slab.entries.len(); - slab.entries.push(Entry::Vacant(next)); - } - slab.entries.push(Entry::Occupied(value)); - slab.len += 1; - } - } - if slab.len == slab.entries.len() { - // no vacant entries, so next might not have been updated - slab.next = slab.entries.len(); - } else if vacant_list_broken { - slab.recreate_vacant_list(); - } else if let Some(first_vacant_index) = first_vacant_index { - let next = slab.entries.len(); - match &mut slab.entries[first_vacant_index] { - Entry::Vacant(n) => *n = next, - _ => unreachable!(), - } - } else { - unreachable!() - } - - slab - } -} - impl<T> fmt::Debug for Slab<T> where T: fmt::Debug, { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - if fmt.alternate() { - fmt.debug_map().entries(self.iter()).finish() - } else { - fmt.debug_struct("Slab") - .field("len", &self.len) - .field("cap", &self.capacity()) - .finish() - } - } -} - -impl<T> fmt::Debug for IntoIter<T> -where - T: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("IntoIter") - .field("remaining", &self.len) - .finish() + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!( + fmt, + "Slab {{ len: {}, cap: {} }}", + self.len, + self.capacity() + ) } } -impl<T> fmt::Debug for Iter<'_, T> +impl<'a, T: 'a> fmt::Debug for Iter<'a, T> where T: fmt::Debug, { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Iter") - .field("remaining", &self.len) + .field("curr", &self.curr) + .field("remaining", &self.entries.len()) .finish() } } -impl<T> fmt::Debug for IterMut<'_, T> +impl<'a, T: 'a> fmt::Debug for IterMut<'a, T> where T: fmt::Debug, { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("IterMut") - .field("remaining", &self.len) + .field("curr", &self.curr) + .field("remaining", &self.entries.len()) .finish() } } -impl<T> fmt::Debug for Drain<'_, T> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { +impl<'a, T: 'a> fmt::Debug for Drain<'a, T> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Drain").finish() } } @@ -1340,8 +890,8 @@ impl<'a, T> VacantEntry<'a, T> { pub fn insert(self, val: T) -> &'a mut T { self.slab.insert_at(self.key, val); - match self.slab.entries.get_mut(self.key) { - Some(&mut Entry::Occupied(ref mut v)) => v, + match self.slab.entries[self.key] { + Entry::Occupied(ref mut v) => v, _ => unreachable!(), } } @@ -1372,178 +922,56 @@ impl<'a, T> VacantEntry<'a, T> { } } -// ===== IntoIter ===== - -impl<T> Iterator for IntoIter<T> { - type Item = (usize, T); - - fn next(&mut self) -> Option<Self::Item> { - for (key, entry) in &mut self.entries { - if let Entry::Occupied(v) = entry { - self.len -= 1; - return Some((key, v)); - } - } - - debug_assert_eq!(self.len, 0); - None - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.len, Some(self.len)) - } -} - -impl<T> DoubleEndedIterator for IntoIter<T> { - fn next_back(&mut self) -> Option<Self::Item> { - while let Some((key, entry)) = self.entries.next_back() { - if let Entry::Occupied(v) = entry { - self.len -= 1; - return Some((key, v)); - } - } - - debug_assert_eq!(self.len, 0); - None - } -} - -impl<T> ExactSizeIterator for IntoIter<T> { - fn len(&self) -> usize { - self.len - } -} - -impl<T> FusedIterator for IntoIter<T> {} - // ===== Iter ===== impl<'a, T> Iterator for Iter<'a, T> { type Item = (usize, &'a T); - fn next(&mut self) -> Option<Self::Item> { - for (key, entry) in &mut self.entries { - if let Entry::Occupied(ref v) = *entry { - self.len -= 1; - return Some((key, v)); - } - } + fn next(&mut self) -> Option<(usize, &'a T)> { + while let Some(entry) = self.entries.next() { + let curr = self.curr; + self.curr += 1; - debug_assert_eq!(self.len, 0); - None - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.len, Some(self.len)) - } -} - -impl<T> DoubleEndedIterator for Iter<'_, T> { - fn next_back(&mut self) -> Option<Self::Item> { - while let Some((key, entry)) = self.entries.next_back() { if let Entry::Occupied(ref v) = *entry { - self.len -= 1; - return Some((key, v)); + return Some((curr, v)); } } - debug_assert_eq!(self.len, 0); None } } -impl<T> ExactSizeIterator for Iter<'_, T> { - fn len(&self) -> usize { - self.len - } -} - -impl<T> FusedIterator for Iter<'_, T> {} - // ===== IterMut ===== impl<'a, T> Iterator for IterMut<'a, T> { type Item = (usize, &'a mut T); - fn next(&mut self) -> Option<Self::Item> { - for (key, entry) in &mut self.entries { - if let Entry::Occupied(ref mut v) = *entry { - self.len -= 1; - return Some((key, v)); - } - } + fn next(&mut self) -> Option<(usize, &'a mut T)> { + while let Some(entry) = self.entries.next() { + let curr = self.curr; + self.curr += 1; - debug_assert_eq!(self.len, 0); - None - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.len, Some(self.len)) - } -} - -impl<T> DoubleEndedIterator for IterMut<'_, T> { - fn next_back(&mut self) -> Option<Self::Item> { - while let Some((key, entry)) = self.entries.next_back() { if let Entry::Occupied(ref mut v) = *entry { - self.len -= 1; - return Some((key, v)); + return Some((curr, v)); } } - debug_assert_eq!(self.len, 0); None } } -impl<T> ExactSizeIterator for IterMut<'_, T> { - fn len(&self) -> usize { - self.len - } -} - -impl<T> FusedIterator for IterMut<'_, T> {} - // ===== Drain ===== -impl<T> Iterator for Drain<'_, T> { +impl<'a, T> Iterator for Drain<'a, T> { type Item = T; - fn next(&mut self) -> Option<Self::Item> { - for entry in &mut self.inner { - if let Entry::Occupied(v) = entry { - self.len -= 1; - return Some(v); - } - } - - debug_assert_eq!(self.len, 0); - None - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.len, Some(self.len)) - } -} - -impl<T> DoubleEndedIterator for Drain<'_, T> { - fn next_back(&mut self) -> Option<Self::Item> { - while let Some(entry) = self.inner.next_back() { + fn next(&mut self) -> Option<T> { + while let Some(entry) = self.0.next() { if let Entry::Occupied(v) = entry { - self.len -= 1; return Some(v); } } - debug_assert_eq!(self.len, 0); None } } - -impl<T> ExactSizeIterator for Drain<'_, T> { - fn len(&self) -> usize { - self.len - } -} - -impl<T> FusedIterator for Drain<'_, T> {} diff --git a/src/serde.rs b/src/serde.rs deleted file mode 100644 index 7ffe8e0..0000000 --- a/src/serde.rs +++ /dev/null @@ -1,101 +0,0 @@ -use core::fmt; -use core::marker::PhantomData; - -use serde::de::{Deserialize, Deserializer, MapAccess, Visitor}; -use serde::ser::{Serialize, SerializeMap, Serializer}; - -use super::{Entry, Slab}; - -impl<T> Serialize for Slab<T> -where - T: Serialize, -{ - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - let mut map_serializer = serializer.serialize_map(Some(self.len()))?; - for (key, value) in self { - map_serializer.serialize_key(&key)?; - map_serializer.serialize_value(value)?; - } - map_serializer.end() - } -} - -struct SlabVisitor<T>(PhantomData<T>); - -impl<'de, T> Visitor<'de> for SlabVisitor<T> -where - T: Deserialize<'de>, -{ - type Value = Slab<T>; - - fn expecting(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "a map") - } - - fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> - where - A: MapAccess<'de>, - { - let mut slab = Slab::with_capacity(map.size_hint().unwrap_or(0)); - - // same as FromIterator impl - let mut vacant_list_broken = false; - let mut first_vacant_index = None; - while let Some((key, value)) = map.next_entry()? { - if key < slab.entries.len() { - // iterator is not sorted, might need to recreate vacant list - if let Entry::Vacant(_) = slab.entries[key] { - vacant_list_broken = true; - slab.len += 1; - } - // if an element with this key already exists, replace it. - // This is consistent with HashMap and BtreeMap - slab.entries[key] = Entry::Occupied(value); - } else { - if first_vacant_index.is_none() && slab.entries.len() < key { - first_vacant_index = Some(slab.entries.len()); - } - // insert holes as necessary - while slab.entries.len() < key { - // add the entry to the start of the vacant list - let next = slab.next; - slab.next = slab.entries.len(); - slab.entries.push(Entry::Vacant(next)); - } - slab.entries.push(Entry::Occupied(value)); - slab.len += 1; - } - } - if slab.len == slab.entries.len() { - // no vacant entries, so next might not have been updated - slab.next = slab.entries.len(); - } else if vacant_list_broken { - slab.recreate_vacant_list(); - } else if let Some(first_vacant_index) = first_vacant_index { - let next = slab.entries.len(); - match &mut slab.entries[first_vacant_index] { - Entry::Vacant(n) => *n = next, - _ => unreachable!(), - } - } else { - unreachable!() - } - - Ok(slab) - } -} - -impl<'de, T> Deserialize<'de> for Slab<T> -where - T: Deserialize<'de>, -{ - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - deserializer.deserialize_map(SlabVisitor(PhantomData)) - } -} diff --git a/tests/serde.rs b/tests/serde.rs deleted file mode 100644 index 1d4a204..0000000 --- a/tests/serde.rs +++ /dev/null @@ -1,49 +0,0 @@ -#![cfg(feature = "serde")] -#![warn(rust_2018_idioms)] - -use serde::{Deserialize, Serialize}; -use serde_test::{assert_tokens, Token}; -use slab::Slab; - -#[derive(Debug, Serialize, Deserialize)] -#[serde(transparent)] -struct SlabPartialEq<T>(Slab<T>); - -impl<T: PartialEq> PartialEq for SlabPartialEq<T> { - fn eq(&self, other: &Self) -> bool { - self.0.len() == other.0.len() - && self - .0 - .iter() - .zip(other.0.iter()) - .all(|(this, other)| this.0 == other.0 && this.1 == other.1) - } -} - -#[test] -fn test_serde_empty() { - let slab = Slab::<usize>::new(); - assert_tokens( - &SlabPartialEq(slab), - &[Token::Map { len: Some(0) }, Token::MapEnd], - ); -} - -#[test] -fn test_serde() { - let vec = vec![(1, 2), (3, 4), (5, 6)]; - let slab: Slab<_> = vec.iter().cloned().collect(); - assert_tokens( - &SlabPartialEq(slab), - &[ - Token::Map { len: Some(3) }, - Token::U64(1), - Token::I32(2), - Token::U64(3), - Token::I32(4), - Token::U64(5), - Token::I32(6), - Token::MapEnd, - ], - ); -} diff --git a/tests/slab.rs b/tests/slab.rs index 8b03c1e..5203c95 100644 --- a/tests/slab.rs +++ b/tests/slab.rs @@ -1,9 +1,7 @@ -#![warn(rust_2018_idioms)] +extern crate slab; use slab::*; -use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; - #[test] fn insert_get_remove_one() { let mut slab = Slab::new(); @@ -84,21 +82,14 @@ fn get_vacant_entry_without_using() { } #[test] -#[should_panic(expected = "invalid key")] +#[should_panic] fn invalid_get_panics() { let slab = Slab::<usize>::with_capacity(1); - let _ = &slab[0]; -} - -#[test] -#[should_panic(expected = "invalid key")] -fn invalid_get_mut_panics() { - let mut slab = Slab::<usize>::new(); - let _ = &mut slab[0]; + slab[0]; } #[test] -#[should_panic(expected = "invalid key")] +#[should_panic] fn double_remove_panics() { let mut slab = Slab::<usize>::with_capacity(1); let key = slab.insert(123); @@ -107,7 +98,7 @@ fn double_remove_panics() { } #[test] -#[should_panic(expected = "invalid key")] +#[should_panic] fn invalid_remove_panics() { let mut slab = Slab::<usize>::with_capacity(1); slab.remove(0); @@ -126,34 +117,6 @@ fn slab_get_mut() { } #[test] -fn key_of_tagged() { - let mut slab = Slab::new(); - slab.insert(0); - assert_eq!(slab.key_of(&slab[0]), 0); -} - -#[test] -fn key_of_layout_optimizable() { - // Entry<&str> doesn't need a discriminant tag because it can use the - // nonzero-ness of ptr and store Vacant's next at the same offset as len - let mut slab = Slab::new(); - slab.insert("foo"); - slab.insert("bar"); - let third = slab.insert("baz"); - slab.insert("quux"); - assert_eq!(slab.key_of(&slab[third]), third); -} - -#[test] -fn key_of_zst() { - let mut slab = Slab::new(); - slab.insert(()); - let second = slab.insert(()); - slab.insert(()); - assert_eq!(slab.key_of(&slab[second]), second); -} - -#[test] fn reserve_does_not_allocate_if_available() { let mut slab = Slab::with_capacity(10); let mut keys = vec![]; @@ -187,27 +150,11 @@ fn reserve_exact_does_not_allocate_if_available() { assert!(slab.capacity() - slab.len() == 8); - slab.reserve_exact(8); + slab.reserve(8); assert_eq!(10, slab.capacity()); } #[test] -#[should_panic(expected = "capacity overflow")] -fn reserve_does_panic_with_capacity_overflow() { - let mut slab = Slab::with_capacity(10); - slab.insert(true); - slab.reserve(std::usize::MAX); -} - -#[test] -#[should_panic(expected = "capacity overflow")] -fn reserve_exact_does_panic_with_capacity_overflow() { - let mut slab = Slab::with_capacity(10); - slab.insert(true); - slab.reserve_exact(std::usize::MAX); -} - -#[test] fn retain() { let mut slab = Slab::with_capacity(2); @@ -238,43 +185,6 @@ fn retain() { } #[test] -fn into_iter() { - let mut slab = Slab::new(); - - for i in 0..8 { - slab.insert(i); - } - slab.remove(0); - slab.remove(4); - slab.remove(5); - slab.remove(7); - - let vals: Vec<_> = slab - .into_iter() - .inspect(|&(key, val)| assert_eq!(key, val)) - .map(|(_, val)| val) - .collect(); - assert_eq!(vals, vec![1, 2, 3, 6]); -} - -#[test] -fn into_iter_rev() { - let mut slab = Slab::new(); - - for i in 0..4 { - slab.insert(i); - } - - let mut iter = slab.into_iter(); - assert_eq!(iter.next_back(), Some((3, 3))); - assert_eq!(iter.next_back(), Some((2, 2))); - assert_eq!(iter.next(), Some((0, 0))); - assert_eq!(iter.next_back(), Some((1, 1))); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next(), None); -} - -#[test] fn iter() { let mut slab = Slab::new(); @@ -299,19 +209,6 @@ fn iter() { } #[test] -fn iter_rev() { - let mut slab = Slab::new(); - - for i in 0..4 { - slab.insert(i); - } - slab.remove(0); - - let vals = slab.iter().rev().collect::<Vec<_>>(); - assert_eq!(vals, vec![(3, &3), (2, &2), (1, &1)]); -} - -#[test] fn iter_mut() { let mut slab = Slab::new(); @@ -321,7 +218,7 @@ fn iter_mut() { for (i, (key, e)) in slab.iter_mut().enumerate() { assert_eq!(i, key); - *e += 1; + *e = *e + 1; } let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect(); @@ -330,7 +227,7 @@ fn iter_mut() { slab.remove(2); for (_, e) in slab.iter_mut() { - *e += 1; + *e = *e + 1; } let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect(); @@ -338,102 +235,6 @@ fn iter_mut() { } #[test] -fn iter_mut_rev() { - let mut slab = Slab::new(); - - for i in 0..4 { - slab.insert(i); - } - slab.remove(2); - - { - let mut iter = slab.iter_mut(); - assert_eq!(iter.next(), Some((0, &mut 0))); - let mut prev_key = !0; - for (key, e) in iter.rev() { - *e += 10; - assert!(prev_key > key); - prev_key = key; - } - } - - assert_eq!(slab[0], 0); - assert_eq!(slab[1], 11); - assert_eq!(slab[3], 13); - assert!(!slab.contains(2)); -} - -#[test] -fn from_iterator_sorted() { - let mut slab = (0..5).map(|i| (i, i)).collect::<Slab<_>>(); - assert_eq!(slab.len(), 5); - assert_eq!(slab[0], 0); - assert_eq!(slab[2], 2); - assert_eq!(slab[4], 4); - assert_eq!(slab.vacant_entry().key(), 5); -} - -#[test] -fn from_iterator_new_in_order() { - // all new keys come in increasing order, but existing keys are overwritten - let mut slab = [(0, 'a'), (1, 'a'), (1, 'b'), (0, 'b'), (9, 'a'), (0, 'c')] - .iter() - .cloned() - .collect::<Slab<_>>(); - assert_eq!(slab.len(), 3); - assert_eq!(slab[0], 'c'); - assert_eq!(slab[1], 'b'); - assert_eq!(slab[9], 'a'); - assert_eq!(slab.get(5), None); - assert_eq!(slab.vacant_entry().key(), 8); -} - -#[test] -fn from_iterator_unordered() { - let mut slab = vec![(1, "one"), (50, "fifty"), (3, "three"), (20, "twenty")] - .into_iter() - .collect::<Slab<_>>(); - assert_eq!(slab.len(), 4); - assert_eq!(slab.vacant_entry().key(), 0); - let mut iter = slab.iter(); - assert_eq!(iter.next(), Some((1, &"one"))); - assert_eq!(iter.next(), Some((3, &"three"))); - assert_eq!(iter.next(), Some((20, &"twenty"))); - assert_eq!(iter.next(), Some((50, &"fifty"))); - assert_eq!(iter.next(), None); -} - -// https://github.com/tokio-rs/slab/issues/100 -#[test] -fn from_iterator_issue_100() { - let mut slab: slab::Slab<()> = vec![(1, ())].into_iter().collect(); - assert_eq!(slab.len(), 1); - assert_eq!(slab.insert(()), 0); - assert_eq!(slab.insert(()), 2); - assert_eq!(slab.insert(()), 3); - - let mut slab: slab::Slab<()> = vec![(1, ()), (2, ())].into_iter().collect(); - assert_eq!(slab.len(), 2); - assert_eq!(slab.insert(()), 0); - assert_eq!(slab.insert(()), 3); - assert_eq!(slab.insert(()), 4); - - let mut slab: slab::Slab<()> = vec![(1, ()), (3, ())].into_iter().collect(); - assert_eq!(slab.len(), 2); - assert_eq!(slab.insert(()), 2); - assert_eq!(slab.insert(()), 0); - assert_eq!(slab.insert(()), 4); - - let mut slab: slab::Slab<()> = vec![(0, ()), (2, ()), (3, ()), (5, ())] - .into_iter() - .collect(); - assert_eq!(slab.len(), 4); - assert_eq!(slab.insert(()), 4); - assert_eq!(slab.insert(()), 1); - assert_eq!(slab.insert(()), 6); -} - -#[test] fn clear() { let mut slab = Slab::new(); @@ -443,7 +244,9 @@ fn clear() { // clear full slab.clear(); - assert!(slab.is_empty()); + + let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect(); + assert!(vals.is_empty()); assert_eq!(0, slab.len()); assert_eq!(4, slab.capacity()); @@ -457,188 +260,9 @@ fn clear() { // clear half-filled slab.clear(); - assert!(slab.is_empty()); -} - -#[test] -fn shrink_to_fit_empty() { - let mut slab = Slab::<bool>::with_capacity(20); - slab.shrink_to_fit(); - assert_eq!(slab.capacity(), 0); -} - -#[test] -fn shrink_to_fit_no_vacant() { - let mut slab = Slab::with_capacity(20); - slab.insert(String::new()); - slab.shrink_to_fit(); - assert!(slab.capacity() < 10); -} - -#[test] -fn shrink_to_fit_doesnt_move() { - let mut slab = Slab::with_capacity(8); - slab.insert("foo"); - let bar = slab.insert("bar"); - slab.insert("baz"); - let quux = slab.insert("quux"); - slab.remove(quux); - slab.remove(bar); - slab.shrink_to_fit(); - assert_eq!(slab.len(), 2); - assert!(slab.capacity() >= 3); - assert_eq!(slab.get(0), Some(&"foo")); - assert_eq!(slab.get(2), Some(&"baz")); - assert_eq!(slab.vacant_entry().key(), bar); -} - -#[test] -fn shrink_to_fit_doesnt_recreate_list_when_nothing_can_be_done() { - let mut slab = Slab::with_capacity(16); - for i in 0..4 { - slab.insert(Box::new(i)); - } - slab.remove(0); - slab.remove(2); - slab.remove(1); - assert_eq!(slab.vacant_entry().key(), 1); - slab.shrink_to_fit(); - assert_eq!(slab.len(), 1); - assert!(slab.capacity() >= 4); - assert_eq!(slab.vacant_entry().key(), 1); -} - -#[test] -fn compact_empty() { - let mut slab = Slab::new(); - slab.compact(|_, _, _| panic!()); - assert_eq!(slab.len(), 0); - assert_eq!(slab.capacity(), 0); - slab.reserve(20); - slab.compact(|_, _, _| panic!()); - assert_eq!(slab.len(), 0); - assert_eq!(slab.capacity(), 0); - slab.insert(0); - slab.insert(1); - slab.insert(2); - slab.remove(1); - slab.remove(2); - slab.remove(0); - slab.compact(|_, _, _| panic!()); - assert_eq!(slab.len(), 0); - assert_eq!(slab.capacity(), 0); -} - -#[test] -fn compact_no_moves_needed() { - let mut slab = Slab::new(); - for i in 0..10 { - slab.insert(i); - } - slab.remove(8); - slab.remove(9); - slab.remove(6); - slab.remove(7); - slab.compact(|_, _, _| panic!()); - assert_eq!(slab.len(), 6); - for ((index, &value), want) in slab.iter().zip(0..6) { - assert!(index == value); - assert_eq!(index, want); - } - assert!(slab.capacity() >= 6 && slab.capacity() < 10); -} -#[test] -fn compact_moves_successfully() { - let mut slab = Slab::with_capacity(20); - for i in 0..10 { - slab.insert(i); - } - for &i in &[0, 5, 9, 6, 3] { - slab.remove(i); - } - let mut moved = 0; - slab.compact(|&mut v, from, to| { - assert!(from > to); - assert!(from >= 5); - assert!(to < 5); - assert_eq!(from, v); - moved += 1; - true - }); - assert_eq!(slab.len(), 5); - assert_eq!(moved, 2); - assert_eq!(slab.vacant_entry().key(), 5); - assert!(slab.capacity() >= 5 && slab.capacity() < 20); - let mut iter = slab.iter(); - assert_eq!(iter.next(), Some((0, &8))); - assert_eq!(iter.next(), Some((1, &1))); - assert_eq!(iter.next(), Some((2, &2))); - assert_eq!(iter.next(), Some((3, &7))); - assert_eq!(iter.next(), Some((4, &4))); - assert_eq!(iter.next(), None); -} - -#[test] -fn compact_doesnt_move_if_closure_errors() { - let mut slab = Slab::with_capacity(20); - for i in 0..10 { - slab.insert(i); - } - for &i in &[9, 3, 1, 4, 0] { - slab.remove(i); - } - slab.compact(|&mut v, from, to| { - assert!(from > to); - assert_eq!(from, v); - v != 6 - }); - assert_eq!(slab.len(), 5); - assert!(slab.capacity() >= 7 && slab.capacity() < 20); - assert_eq!(slab.vacant_entry().key(), 3); - let mut iter = slab.iter(); - assert_eq!(iter.next(), Some((0, &8))); - assert_eq!(iter.next(), Some((1, &7))); - assert_eq!(iter.next(), Some((2, &2))); - assert_eq!(iter.next(), Some((5, &5))); - assert_eq!(iter.next(), Some((6, &6))); - assert_eq!(iter.next(), None); -} - -#[test] -// Android aborts on panic and this test relies on stack unwinding. -#[cfg(not(target_os = "android"))] -fn compact_handles_closure_panic() { - let mut slab = Slab::new(); - for i in 0..10 { - slab.insert(i); - } - for i in 1..6 { - slab.remove(i); - } - let result = catch_unwind(AssertUnwindSafe(|| { - slab.compact(|&mut v, from, to| { - assert!(from > to); - assert_eq!(from, v); - if v == 7 { - panic!("test"); - } - true - }) - })); - match result { - Err(ref payload) if payload.downcast_ref() == Some(&"test") => {} - Err(bug) => resume_unwind(bug), - Ok(()) => unreachable!(), - } - assert_eq!(slab.len(), 5 - 1); - assert_eq!(slab.vacant_entry().key(), 3); - let mut iter = slab.iter(); - assert_eq!(iter.next(), Some((0, &0))); - assert_eq!(iter.next(), Some((1, &9))); - assert_eq!(iter.next(), Some((2, &8))); - assert_eq!(iter.next(), Some((6, &6))); - assert_eq!(iter.next(), None); + let vals: Vec<_> = slab.iter().map(|(_, r)| *r).collect(); + assert!(vals.is_empty()); } #[test] @@ -675,26 +299,3 @@ fn partially_consumed_drain() { assert!(slab.is_empty()) } - -#[test] -fn drain_rev() { - let mut slab = Slab::new(); - for i in 0..10 { - slab.insert(i); - } - slab.remove(9); - - let vals: Vec<u64> = slab.drain().rev().collect(); - assert_eq!(vals, (0..9).rev().collect::<Vec<u64>>()); -} - -#[test] -fn try_remove() { - let mut slab = Slab::new(); - - let key = slab.insert(1); - - assert_eq!(slab.try_remove(key), Some(1)); - assert_eq!(slab.try_remove(key), None); - assert_eq!(slab.get(key), None); -} |