slotmap-1.0.7/.cargo_vcs_info.json0000644000000001360000000000100125200ustar { "git": { "sha1": "c905b6ced490551476cb7c37778eb8128bdea7ba" }, "path_in_vcs": "" }slotmap-1.0.7/.gitignore000064400000000000000000000000600072674642500133240ustar 00000000000000/target **/*.rs.bk .vscode Cargo.lock tags slotmap-1.0.7/Cargo.lock0000644000000156440000000000100105050ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" dependencies = [ "memchr", ] [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "env_logger" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ "log", "regex", ] [[package]] name = "fxhash" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" dependencies = [ "byteorder", ] [[package]] name = "getrandom" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if 1.0.0", "libc", "wasi", ] [[package]] name = "itoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" [[package]] name = "log" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ "cfg-if 0.1.10", ] [[package]] name = "memchr" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "ppv-lite86" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] [[package]] name = "quickcheck" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f" dependencies = [ "env_logger", "log", "rand", "rand_core", ] [[package]] name = "quote" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom", "libc", "rand_chacha", "rand_core", "rand_hc", ] [[package]] name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ "getrandom", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ "rand_core", ] [[package]] name = "regex" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" dependencies = [ "aho-corasick", "memchr", "regex-syntax", "thread_local", ] [[package]] name = "regex-syntax" version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "serde" version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "slotmap" version = "1.0.7" dependencies = [ "fxhash", "quickcheck", "serde", "serde_derive", "serde_json", "version_check", ] [[package]] name = "syn" version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "thread_local" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" dependencies = [ "lazy_static", ] [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "version_check" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" slotmap-1.0.7/Cargo.toml0000644000000024640000000000100105240ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # 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. # # 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. [package] edition = "2018" name = "slotmap" version = "1.0.7" authors = ["Orson Peters "] description = "Slotmap data structure" readme = "README.md" keywords = [ "slotmap", "storage", "allocator", "arena", "reference", ] categories = [ "data-structures", "memory-management", "caching", ] license = "Zlib" repository = "https://github.com/orlp/slotmap" [dependencies.serde] version = "1.0" features = [ "derive", "alloc", ] optional = true default-features = false [dev-dependencies.fxhash] version = "0.2.1" [dev-dependencies.quickcheck] version = "0.9" [dev-dependencies.serde] version = "1.0" [dev-dependencies.serde_derive] version = "1.0" [dev-dependencies.serde_json] version = "1.0" [build-dependencies.version_check] version = "0.9" [features] default = ["std"] std = [] unstable = [] slotmap-1.0.7/Cargo.toml.orig000064400000000000000000000014110072674642500142240ustar 00000000000000[package] name = "slotmap" version = "1.0.7" # Remember to grep and update version everywhere. edition = "2018" authors = ["Orson Peters "] description = "Slotmap data structure" license = "Zlib" repository = "https://github.com/orlp/slotmap" readme = "README.md" keywords = ["slotmap", "storage", "allocator", "arena", "reference"] categories = ["data-structures", "memory-management", "caching"] [features] default = ["std"] unstable = [] std = [] [dependencies] serde = { version = "1.0", optional = true, default-features = false, features = ["derive", "alloc"] } [dev-dependencies] fxhash = "0.2.1" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" quickcheck = "0.9" [build-dependencies] version_check = "0.9" slotmap-1.0.7/LICENSE000064400000000000000000000016070072674642500123510ustar 00000000000000Copyright (c) 2021 Orson Peters This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. slotmap-1.0.7/README.md000064400000000000000000000032020072674642500126140ustar 00000000000000# slotmap A Rust library providing three containers with persistent unique keys to access stored values, `SlotMap`, `HopSlotMap` and `DenseSlotMap`. Upon insertion a key is returned that can be used to later access or remove the values. Insertion, deletion and access all take O(1) time with low overhead. Great for storing collections of objects that need stable, safe references but have no clear ownership otherwise, such as game entities or graph nodes. Two secondary maps, `SecondaryMap` and `SparseSecondaryMap` are also provided that allow you to map further objects to the keys created by one of the slot maps. Please refer to [**the documentation**](https://docs.rs/slotmap) for more information. The minimum required stable Rust version for `slotmap` is 1.49. To start using `slotmap` add the following to your `Cargo.toml`: ```toml [dependencies] slotmap = "1.0" ``` # Example A short example: ```rust use slotmap::{SlotMap, SecondaryMap}; let mut sm = SlotMap::new(); let foo = sm.insert("foo"); // Key generated on insert. let bar = sm.insert("bar"); assert_eq!(sm[foo], "foo"); assert_eq!(sm[bar], "bar"); sm.remove(bar); let reuse = sm.insert("reuse"); // Space from bar reused. assert_eq!(sm.contains_key(bar), false); // After deletion a key stays invalid. let mut sec = SecondaryMap::new(); sec.insert(foo, "noun"); // We provide the key for secondary maps. sec.insert(reuse, "verb"); for (key, val) in sm { println!("{} is a {}", val, sec[key]); } ``` # License `slotmap` is released under the Zlib license, a permissive license. It is OSI and FSF approved and GPL compatible. slotmap-1.0.7/RELEASES.md000064400000000000000000000111010072674642500130570ustar 00000000000000Version 1.0.7 ============= - Added `clone_from` implementations for all slot maps. - Added `try_insert_with_key` methods that accept a fallible closure. - Improved performance of insertion and key hashing. - Made `new_key_type` resistant to shadowing. - Made iterators clonable regardless of item type clonability. Version 1.0.6 ============= - Made `Key` trait unsafe, as it was erroneously safe to implement. Version 1.0.5 ============= - Added fuzzing for extra testing. - Fixed an issue that could cause a segfault when using `HopSlotMap::retain` that had the same underlying cause as the fix in 1.0.4 but was missed. Version 1.0.4 ============= - Fixed an issue that could cause a segfault when using `HopSlotMap::drain`. All versions 0.3+ are affected, and thus yanked. Version 1.0.3 ============= - Made `get_disjoint_mut` available on stable Rust 1.51 and up. - Added unchecked variants for the getters on `SparseSecondaryMap`. Version 1.0.2 ============= - Fixed the `new_key_type!` macro, it assumed the `Key` trait was in scope. - Updated code base with more stringent (clippy) warnings, and many small code quality and documentation changes. - Documented the minimum required stable Rust version, which is 1.49. Version 1.0.1 ============= - Fixed an instance where an uninitialized `[u32; N]` was created. The uninitialized values were never read - the code always initialized them before reading - but simply having the variable be uninitialized (despite all bit patterns being valid) is technically undefined behavior. Version 1.0.0 ============= - Removed all `Copy` trait restrictions of value types stable Rust! There are no longer any restrictions on the types you can store in any of the slot maps. For that reason `Slottable` was deprecated as well. - `no_std` support was added, use it by opting out of the default feature `std`. - Added `sm.get_disjoint_mut([k1, k2, ...])` which allows you to get mutable references from multiple disjoint keys at the same time. This requires `min-const-generics` to be stabilized, so until Rust 1.51 comes out this is only available on nightly by setting the `unstable` feature. - Added an `Entry` API to the secondary maps. - Added `derive(Clone)` for iterators where possible. - Replaced `Into` with `Key::data()`. - `SecondaryMap` now uses minimal space overhead. Each slot now uses `max(sizeof(T), 4)` bytes. - Moved `SlotMap` to the `basic` module. Version 0.4.1 ============= - Backport of fix made in 1.0.4. Version 0.4.0 ============= - Codebase moved to 2018 Edition. - Reintroduce `DenseSlotMap` - an overzealous removal in 0.3.0. - Added support for `try_reserve`. - Added support for custom hashers in `SparseSecondaryMap`. - `SparseSecondaryMap` and `SecondaryMap` can now be cloned. - Keys have a more terse debug output. - Fixed a bug that caused an overflowing left shift on 32-bit targets. Version 0.3.0 ============= - Massive rework, with a focus on secondary maps and custom keys to prevent cross-slotmap key usage. - Removed `DenseSlotMap` in favour of `HopSlotMap` as the latter performs better when secondary maps are in use. - Unfortunately due to the redesign the first slot in a slot map must now always be empty. This means some deserializations of slot maps serialized with a version before 0.3.0 can fail. - Added `SecondaryMap` and `SparseSecondaryMap`, which allows you to associate extra data with keys given by a slot map. - Added `DefaultKey`, custom key types, and support for them on all slot maps and secondary maps. You must now always specify the key type you're using with a slot map, so `SlotMap` would be `SlotMap`. It is recommended to make a custom key type with `new_key_type!` for any slot map you create, as this entirely prevents using the wrong key on the wrong slot map. - `KeyData` now has `as_ffi` and `from_ffi` functions that convert the data that makes up a key to/from an `u64`. This allows you to use slot map keys as opaque handles in FFI code. Version 0.2.1 ============= - Fixed a potential uninitialized memory vulnerability. No uninitialized memory was read or used directly, but Rust's assumptions could lead to it. Yanked all previous versions as they were all vulnerable. - Made a `Key` member non-zero so that `Option` is optimized. Version 0.2.0 ============= Start of version history. slotmap-1.0.7/build.rs000064400000000000000000000010540072674642500130050ustar 00000000000000fn main() { let is_nightly = version_check::is_feature_flaggable() == Some(true); let is_at_least_1_49 = version_check::is_min_version("1.49.0").unwrap_or(false); let is_at_least_1_51 = version_check::is_min_version("1.51.0").unwrap_or(false); if !is_at_least_1_49 { println!("cargo:warning=slotmap requires rustc => 1.49.0"); } if is_at_least_1_51 || is_nightly { println!("cargo:rustc-cfg=has_min_const_generics"); } if is_nightly { println!("cargo:rustc-cfg=nightly"); } } slotmap-1.0.7/examples/doubly_linked_list.rs000064400000000000000000000063030072674642500174050ustar 00000000000000// A simple doubly linked list example using slotmap. use slotmap::{new_key_type, Key, SlotMap}; new_key_type! { pub struct ListKey; } #[derive(Copy, Clone)] struct Node { value: T, prev: ListKey, next: ListKey, } pub struct List { sm: SlotMap>, head: ListKey, tail: ListKey, } impl List { pub fn new() -> Self { Self { sm: SlotMap::with_key(), head: ListKey::null(), tail: ListKey::null(), } } pub fn len(&self) -> usize { self.sm.len() } pub fn push_head(&mut self, value: T) -> ListKey { let k = self.sm.insert(Node { value, prev: ListKey::null(), next: self.head, }); if let Some(old_head) = self.sm.get_mut(self.head) { old_head.prev = k; } else { self.tail = k; } self.head = k; k } pub fn push_tail(&mut self, value: T) -> ListKey { let k = self.sm.insert(Node { value, prev: self.tail, next: ListKey::null(), }); if let Some(old_tail) = self.sm.get_mut(self.tail) { old_tail.next = k; } else { self.head = k; } self.tail = k; k } pub fn pop_head(&mut self) -> Option { self.sm.remove(self.head).map(|old_head| { self.head = old_head.next; old_head.value }) } pub fn pop_tail(&mut self) -> Option { self.sm.remove(self.tail).map(|old_tail| { self.tail = old_tail.prev; old_tail.value }) } pub fn remove(&mut self, key: ListKey) -> Option { self.sm.remove(key).map(|node| { if let Some(prev_node) = self.sm.get_mut(node.prev) { prev_node.next = node.next; } else { self.head = node.next; } if let Some(next_node) = self.sm.get_mut(node.next) { next_node.prev = node.prev; } else { self.tail = node.prev; } node.value }) } pub fn head(&self) -> ListKey { self.head } pub fn tail(&self) -> ListKey { self.tail } pub fn get(&self, key: ListKey) -> Option<&T> { self.sm.get(key).map(|node| &node.value) } pub fn get_mut(&mut self, key: ListKey) -> Option<&mut T> { self.sm.get_mut(key).map(|node| &mut node.value) } } fn main() { let mut dll = List::new(); dll.push_head(5); dll.push_tail(6); let k = dll.push_head(3); dll.push_tail(7); dll.push_head(4); assert_eq!(dll.len(), 4); assert_eq!(dll.pop_head(), Some(4)); assert_eq!(dll.pop_head(), Some(5)); assert_eq!(dll.head(), k); dll.push_head(10); assert_eq!(dll.remove(k), Some(3)); assert_eq!(dll.pop_tail(), Some(7)); assert_eq!(dll.pop_tail(), Some(6)); assert_eq!(dll.pop_head(), Some(10)); assert_eq!(dll.pop_head(), None); assert_eq!(dll.pop_tail(), None); } slotmap-1.0.7/examples/rand_meld_heap.rs000064400000000000000000000113210072674642500164440ustar 00000000000000// Randomized meldable heap. // https://en.wikipedia.org/wiki/Randomized_meldable_heap use slotmap::{new_key_type, Key, SlotMap}; new_key_type! { struct HeapKey; } #[derive(Copy, Clone)] struct NodeHandle(HeapKey); #[derive(Copy, Clone)] struct Node { value: T, children: [HeapKey; 2], parent: HeapKey, } struct RandMeldHeap { sm: SlotMap>, rng: std::num::Wrapping, root: HeapKey, } impl RandMeldHeap { pub fn new() -> Self { Self { sm: SlotMap::with_key(), rng: std::num::Wrapping(0xdead_beef), root: HeapKey::null(), } } pub fn coinflip(&mut self) -> bool { // Simple LCG for top speed - random quality barely matters. self.rng += (self.rng << 8) + std::num::Wrapping(1); self.rng >> 31 > std::num::Wrapping(0) } pub fn insert(&mut self, value: T) -> NodeHandle { let k = self.sm.insert(Node { value, children: [HeapKey::null(), HeapKey::null()], parent: HeapKey::null(), }); let root = self.root; self.root = self.meld(k, root); NodeHandle(k) } pub fn pop(&mut self) -> Option { self.sm.remove(self.root).map(|root| { self.root = self.meld(root.children[0], root.children[1]); if let Some(new_root) = self.sm.get_mut(self.root) { new_root.parent = HeapKey::null(); } root.value }) } pub fn remove_key(&mut self, node: NodeHandle) -> T { let node = node.0; self.unlink_node(node); self.sm.remove(node).unwrap().value } pub fn update_key(&mut self, node: NodeHandle, value: T) { let node = node.0; // Unlink and re-insert. self.unlink_node(node); self.sm[node] = Node { value, children: [HeapKey::null(), HeapKey::null()], parent: HeapKey::null(), }; let root = self.root; self.root = self.meld(node, root); } fn unlink_node(&mut self, node: HeapKey) { // Remove node from heap by merging children and placing them where // node used to be. let children = self.sm[node].children; let parent_key = self.sm[node].parent; let melded_children = self.meld(children[0], children[1]); if let Some(mc) = self.sm.get_mut(melded_children) { mc.parent = parent_key; } if let Some(parent) = self.sm.get_mut(parent_key) { if parent.children[0] == node { parent.children[0] = melded_children; } else { parent.children[1] = melded_children; } } else { self.root = melded_children; } } fn meld(&mut self, mut a: HeapKey, mut b: HeapKey) -> HeapKey { if a.is_null() { return b; } if b.is_null() { return a; } if self.sm[a].value > self.sm[b].value { std::mem::swap(&mut a, &mut b); } let ret = a; // From this point parent and trickle are assumed to be valid keys. let mut parent = a; let mut trickle = b; loop { // If a child spot is free, put our trickle there. let children = self.sm[parent].children; if children[0].is_null() { self.sm[parent].children[0] = trickle; self.sm[trickle].parent = parent; break; } else if children[1].is_null() { self.sm[parent].children[1] = trickle; self.sm[trickle].parent = parent; break; } // No spot free, choose a random child. let c = self.coinflip() as usize; let child = children[c]; if self.sm[child].value > self.sm[trickle].value { self.sm[parent].children[c] = trickle; self.sm[trickle].parent = parent; parent = trickle; trickle = child; } else { parent = child; } } ret } pub fn len(&self) -> usize { self.sm.len() } } fn main() { let mut rhm = RandMeldHeap::new(); let the_answer = rhm.insert(-2); let big = rhm.insert(999); for k in (0..10).rev() { rhm.insert(k * k); } rhm.update_key(the_answer, 42); rhm.remove_key(big); while rhm.len() > 0 { println!("{}", rhm.pop().unwrap()); } } slotmap-1.0.7/src/basic.rs000064400000000000000000001347300072674642500135660ustar 00000000000000// Needed because assigning to non-Copy union is unsafe in stable but not in nightly. #![allow(unused_unsafe)] //! Contains the slot map implementation. #[cfg(all(nightly, any(doc, feature = "unstable")))] use alloc::collections::TryReserveError; use alloc::vec::Vec; use core::fmt; use core::iter::{Enumerate, FusedIterator}; use core::marker::PhantomData; #[allow(unused_imports)] // MaybeUninit is only used on nightly at the moment. use core::mem::{ManuallyDrop, MaybeUninit}; use core::ops::{Index, IndexMut}; use crate::util::{Never, UnwrapUnchecked}; use crate::{DefaultKey, Key, KeyData}; // Storage inside a slot or metadata for the freelist when vacant. union SlotUnion { value: ManuallyDrop, next_free: u32, } // A slot, which represents storage for a value and a current version. // Can be occupied or vacant. struct Slot { u: SlotUnion, version: u32, // Even = vacant, odd = occupied. } // Safe API to read a slot. enum SlotContent<'a, T: 'a> { Occupied(&'a T), Vacant(&'a u32), } enum SlotContentMut<'a, T: 'a> { OccupiedMut(&'a mut T), VacantMut(&'a mut u32), } use self::SlotContent::{Occupied, Vacant}; use self::SlotContentMut::{OccupiedMut, VacantMut}; impl Slot { // Is this slot occupied? #[inline(always)] pub fn occupied(&self) -> bool { self.version % 2 > 0 } pub fn get(&self) -> SlotContent { unsafe { if self.occupied() { Occupied(&*self.u.value) } else { Vacant(&self.u.next_free) } } } pub fn get_mut(&mut self) -> SlotContentMut { unsafe { if self.occupied() { OccupiedMut(&mut *self.u.value) } else { VacantMut(&mut self.u.next_free) } } } } impl Drop for Slot { fn drop(&mut self) { if core::mem::needs_drop::() && self.occupied() { // This is safe because we checked that we're occupied. unsafe { ManuallyDrop::drop(&mut self.u.value); } } } } impl Clone for Slot { fn clone(&self) -> Self { Self { u: match self.get() { Occupied(value) => SlotUnion { value: ManuallyDrop::new(value.clone()), }, Vacant(&next_free) => SlotUnion { next_free }, }, version: self.version, } } fn clone_from(&mut self, source: &Self) { match (self.get_mut(), source.get()) { (OccupiedMut(self_val), Occupied(source_val)) => self_val.clone_from(source_val), (VacantMut(self_next_free), Vacant(&source_next_free)) => { *self_next_free = source_next_free }, (_, Occupied(value)) => { self.u = SlotUnion { value: ManuallyDrop::new(value.clone()), } }, (_, Vacant(&next_free)) => self.u = SlotUnion { next_free }, } self.version = source.version; } } impl fmt::Debug for Slot { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("Slot"); builder.field("version", &self.version); match self.get() { Occupied(value) => builder.field("value", value).finish(), Vacant(next_free) => builder.field("next_free", next_free).finish(), } } } /// Slot map, storage with stable unique keys. /// /// See [crate documentation](crate) for more details. #[derive(Debug)] pub struct SlotMap { slots: Vec>, free_head: u32, num_elems: u32, _k: PhantomData K>, } impl SlotMap { /// Constructs a new, empty [`SlotMap`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm: SlotMap<_, i32> = SlotMap::new(); /// ``` pub fn new() -> Self { Self::with_capacity_and_key(0) } /// Creates an empty [`SlotMap`] with the given capacity. /// /// The slot map will not reallocate until it holds at least `capacity` /// elements. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm: SlotMap<_, i32> = SlotMap::with_capacity(10); /// ``` pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_and_key(capacity) } } impl SlotMap { /// Constructs a new, empty [`SlotMap`] with a custom key type. /// /// # Examples /// /// ``` /// # use slotmap::*; /// new_key_type! { /// struct PositionKey; /// } /// let mut positions: SlotMap = SlotMap::with_key(); /// ``` pub fn with_key() -> Self { Self::with_capacity_and_key(0) } /// Creates an empty [`SlotMap`] with the given capacity and a custom key /// type. /// /// The slot map will not reallocate until it holds at least `capacity` /// elements. /// /// # Examples /// /// ``` /// # use slotmap::*; /// new_key_type! { /// struct MessageKey; /// } /// let mut messages = SlotMap::with_capacity_and_key(3); /// let welcome: MessageKey = messages.insert("Welcome"); /// let good_day = messages.insert("Good day"); /// let hello = messages.insert("Hello"); /// ``` pub fn with_capacity_and_key(capacity: usize) -> Self { // Create slots with a sentinel at index 0. // We don't actually use the sentinel for anything currently, but // HopSlotMap does, and if we want keys to remain valid through // conversion we have to have one as well. let mut slots = Vec::with_capacity(capacity + 1); slots.push(Slot { u: SlotUnion { next_free: 0 }, version: 0, }); Self { slots, free_head: 1, num_elems: 0, _k: PhantomData, } } /// Returns the number of elements in the slot map. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::with_capacity(10); /// sm.insert("len() counts actual elements, not capacity"); /// let key = sm.insert("removed elements don't count either"); /// sm.remove(key); /// assert_eq!(sm.len(), 1); /// ``` pub fn len(&self) -> usize { self.num_elems as usize } /// Returns if the slot map is empty. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("dummy"); /// assert_eq!(sm.is_empty(), false); /// sm.remove(key); /// assert_eq!(sm.is_empty(), true); /// ``` pub fn is_empty(&self) -> bool { self.num_elems == 0 } /// Returns the number of elements the [`SlotMap`] can hold without /// reallocating. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let sm: SlotMap<_, f64> = SlotMap::with_capacity(10); /// assert_eq!(sm.capacity(), 10); /// ``` pub fn capacity(&self) -> usize { // One slot is reserved for the sentinel. self.slots.capacity() - 1 } /// Reserves capacity for at least `additional` more elements to be inserted /// in the [`SlotMap`]. The collection may reserve more space to avoid /// frequent reallocations. /// /// # Panics /// /// Panics if the new allocation size overflows [`usize`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// sm.insert("foo"); /// sm.reserve(32); /// assert!(sm.capacity() >= 33); /// ``` pub fn reserve(&mut self, additional: usize) { // One slot is reserved for the sentinel. let needed = (self.len() + additional).saturating_sub(self.slots.len() - 1); self.slots.reserve(needed); } /// Tries to reserve capacity for at least `additional` more elements to be /// inserted in the [`SlotMap`]. The collection may reserve more space to /// avoid frequent reallocations. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// sm.insert("foo"); /// sm.try_reserve(32).unwrap(); /// assert!(sm.capacity() >= 33); /// ``` #[cfg(all(nightly, any(doc, feature = "unstable")))] #[cfg_attr(all(nightly, doc), doc(cfg(feature = "unstable")))] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { // One slot is reserved for the sentinel. let needed = (self.len() + additional).saturating_sub(self.slots.len() - 1); self.slots.try_reserve(needed) } /// Returns [`true`] if the slot map contains `key`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert(42); /// assert_eq!(sm.contains_key(key), true); /// sm.remove(key); /// assert_eq!(sm.contains_key(key), false); /// ``` pub fn contains_key(&self, key: K) -> bool { let kd = key.data(); self.slots .get(kd.idx as usize) .map_or(false, |slot| slot.version == kd.version.get()) } /// Inserts a value into the slot map. Returns a unique key that can be used /// to access this value. /// /// # Panics /// /// Panics if the number of elements in the slot map equals /// 232 - 2. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert(42); /// assert_eq!(sm[key], 42); /// ``` #[inline(always)] pub fn insert(&mut self, value: V) -> K { unsafe { self.try_insert_with_key::<_, Never>(move |_| Ok(value)).unwrap_unchecked_() } } /// Inserts a value given by `f` into the slot map. The key where the /// value will be stored is passed into `f`. This is useful to store values /// that contain their own key. /// /// # Panics /// /// Panics if the number of elements in the slot map equals /// 232 - 2. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert_with_key(|k| (k, 20)); /// assert_eq!(sm[key], (key, 20)); /// ``` #[inline(always)] pub fn insert_with_key(&mut self, f: F) -> K where F: FnOnce(K) -> V, { unsafe { self.try_insert_with_key::<_, Never>(move |k| Ok(f(k))).unwrap_unchecked_() } } /// Inserts a value given by `f` into the slot map. The key where the /// value will be stored is passed into `f`. This is useful to store values /// that contain their own key. /// /// If `f` returns `Err`, this method returns the error. The slotmap is untouched. /// /// # Panics /// /// Panics if the number of elements in the slot map equals /// 232 - 2. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.try_insert_with_key::<_, ()>(|k| Ok((k, 20))).unwrap(); /// assert_eq!(sm[key], (key, 20)); /// /// sm.try_insert_with_key::<_, ()>(|k| Err(())).unwrap_err(); /// ``` pub fn try_insert_with_key(&mut self, f: F) -> Result where F: FnOnce(K) -> Result, { // In case f panics, we don't make any changes until we have the value. let new_num_elems = self.num_elems + 1; if new_num_elems == core::u32::MAX { panic!("SlotMap number of elements overflow"); } if let Some(slot) = self.slots.get_mut(self.free_head as usize) { let occupied_version = slot.version | 1; let kd = KeyData::new(self.free_head, occupied_version); // Get value first in case f panics or returns an error. let value = f(kd.into())?; // Update. unsafe { self.free_head = slot.u.next_free; slot.u.value = ManuallyDrop::new(value); slot.version = occupied_version; } self.num_elems = new_num_elems; return Ok(kd.into()); } let version = 1; let kd = KeyData::new(self.slots.len() as u32, version); // Create new slot before adjusting freelist in case f or the allocation panics or errors. self.slots.push(Slot { u: SlotUnion { value: ManuallyDrop::new(f(kd.into())?), }, version, }); self.free_head = kd.idx + 1; self.num_elems = new_num_elems; Ok(kd.into()) } // Helper function to remove a value from a slot. Safe iff the slot is // occupied. Returns the value removed. #[inline(always)] unsafe fn remove_from_slot(&mut self, idx: usize) -> V { // Remove value from slot before overwriting union. let slot = self.slots.get_unchecked_mut(idx); let value = ManuallyDrop::take(&mut slot.u.value); // Maintain freelist. slot.u.next_free = self.free_head; self.free_head = idx as u32; self.num_elems -= 1; slot.version = slot.version.wrapping_add(1); value } /// Removes a key from the slot map, returning the value at the key if the /// key was not previously removed. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert(42); /// assert_eq!(sm.remove(key), Some(42)); /// assert_eq!(sm.remove(key), None); /// ``` pub fn remove(&mut self, key: K) -> Option { let kd = key.data(); if self.contains_key(key) { // This is safe because we know that the slot is occupied. Some(unsafe { self.remove_from_slot(kd.idx as usize) }) } else { None } } /// Retains only the elements specified by the predicate. /// /// In other words, remove all key-value pairs `(k, v)` such that /// `f(k, &mut v)` returns false. This method invalidates any removed keys. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// /// let k1 = sm.insert(0); /// let k2 = sm.insert(1); /// let k3 = sm.insert(2); /// /// sm.retain(|key, val| key == k1 || *val == 1); /// /// assert!(sm.contains_key(k1)); /// assert!(sm.contains_key(k2)); /// assert!(!sm.contains_key(k3)); /// /// assert_eq!(2, sm.len()); /// ``` pub fn retain(&mut self, mut f: F) where F: FnMut(K, &mut V) -> bool, { for i in 1..self.slots.len() { // This is safe because removing elements does not shrink slots. let slot = unsafe { self.slots.get_unchecked_mut(i) }; let version = slot.version; let should_remove = if let OccupiedMut(value) = slot.get_mut() { let key = KeyData::new(i as u32, version).into(); !f(key, value) } else { false }; if should_remove { // This is safe because we know that the slot was occupied. unsafe { self.remove_from_slot(i) }; } } } /// Clears the slot map. Keeps the allocated memory for reuse. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// for i in 0..10 { /// sm.insert(i); /// } /// assert_eq!(sm.len(), 10); /// sm.clear(); /// assert_eq!(sm.len(), 0); /// ``` pub fn clear(&mut self) { self.drain(); } /// Clears the slot map, returning all key-value pairs in arbitrary order as /// an iterator. Keeps the allocated memory for reuse. /// /// When the iterator is dropped all elements in the slot map are removed, /// even if the iterator was not fully consumed. If the iterator is not /// dropped (using e.g. [`std::mem::forget`]), only the elements that were /// iterated over are removed. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let k = sm.insert(0); /// let v: Vec<_> = sm.drain().collect(); /// assert_eq!(sm.len(), 0); /// assert_eq!(v, vec![(k, 0)]); /// ``` pub fn drain(&mut self) -> Drain { Drain { cur: 1, sm: self } } /// Returns a reference to the value corresponding to the key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("bar"); /// assert_eq!(sm.get(key), Some(&"bar")); /// sm.remove(key); /// assert_eq!(sm.get(key), None); /// ``` pub fn get(&self, key: K) -> Option<&V> { let kd = key.data(); self.slots .get(kd.idx as usize) .filter(|slot| slot.version == kd.version.get()) .map(|slot| unsafe { &*slot.u.value }) } /// Returns a reference to the value corresponding to the key without /// version or bounds checking. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true. Otherwise it is /// potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("bar"); /// assert_eq!(unsafe { sm.get_unchecked(key) }, &"bar"); /// sm.remove(key); /// // sm.get_unchecked(key) is now dangerous! /// ``` pub unsafe fn get_unchecked(&self, key: K) -> &V { debug_assert!(self.contains_key(key)); &self.slots.get_unchecked(key.data().idx as usize).u.value } /// Returns a mutable reference to the value corresponding to the key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert(3.5); /// if let Some(x) = sm.get_mut(key) { /// *x += 3.0; /// } /// assert_eq!(sm[key], 6.5); /// ``` pub fn get_mut(&mut self, key: K) -> Option<&mut V> { let kd = key.data(); self.slots .get_mut(kd.idx as usize) .filter(|slot| slot.version == kd.version.get()) .map(|slot| unsafe { &mut *slot.u.value }) } /// Returns a mutable reference to the value corresponding to the key /// without version or bounds checking. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true. Otherwise it is /// potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("foo"); /// unsafe { *sm.get_unchecked_mut(key) = "bar" }; /// assert_eq!(sm[key], "bar"); /// sm.remove(key); /// // sm.get_unchecked_mut(key) is now dangerous! /// ``` pub unsafe fn get_unchecked_mut(&mut self, key: K) -> &mut V { debug_assert!(self.contains_key(key)); &mut self.slots.get_unchecked_mut(key.data().idx as usize).u.value } /// Returns mutable references to the values corresponding to the given /// keys. All keys must be valid and disjoint, otherwise None is returned. /// /// Requires at least stable Rust version 1.51. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let ka = sm.insert("butter"); /// let kb = sm.insert("apples"); /// let kc = sm.insert("charlie"); /// sm.remove(kc); // Make key c invalid. /// assert_eq!(sm.get_disjoint_mut([ka, kb, kc]), None); // Has invalid key. /// assert_eq!(sm.get_disjoint_mut([ka, ka]), None); // Not disjoint. /// let [a, b] = sm.get_disjoint_mut([ka, kb]).unwrap(); /// std::mem::swap(a, b); /// assert_eq!(sm[ka], "apples"); /// assert_eq!(sm[kb], "butter"); /// ``` #[cfg(has_min_const_generics)] pub fn get_disjoint_mut(&mut self, keys: [K; N]) -> Option<[&mut V; N]> { // Create an uninitialized array of `MaybeUninit`. The `assume_init` is // safe because the type we are claiming to have initialized here is a // bunch of `MaybeUninit`s, which do not require initialization. let mut ptrs: [MaybeUninit<*mut V>; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut i = 0; while i < N { let kd = keys[i].data(); if !self.contains_key(kd.into()) { break; } // This key is valid, and thus the slot is occupied. Temporarily // mark it as unoccupied so duplicate keys would show up as invalid. // This gives us a linear time disjointness check. unsafe { let slot = self.slots.get_unchecked_mut(kd.idx as usize); slot.version ^= 1; ptrs[i] = MaybeUninit::new(&mut *slot.u.value); } i += 1; } // Undo temporary unoccupied markings. for k in &keys[..i] { let idx = k.data().idx as usize; unsafe { self.slots.get_unchecked_mut(idx).version ^= 1; } } if i == N { // All were valid and disjoint. Some(unsafe { core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs) }) } else { None } } /// Returns mutable references to the values corresponding to the given /// keys. All keys must be valid and disjoint. /// /// Requires at least stable Rust version 1.51. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true for every given /// key and no two keys are equal. Otherwise it is potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let ka = sm.insert("butter"); /// let kb = sm.insert("apples"); /// let [a, b] = unsafe { sm.get_disjoint_unchecked_mut([ka, kb]) }; /// std::mem::swap(a, b); /// assert_eq!(sm[ka], "apples"); /// assert_eq!(sm[kb], "butter"); /// ``` #[cfg(has_min_const_generics)] pub unsafe fn get_disjoint_unchecked_mut( &mut self, keys: [K; N], ) -> [&mut V; N] { // Safe, see get_disjoint_mut. let mut ptrs: [MaybeUninit<*mut V>; N] = MaybeUninit::uninit().assume_init(); for i in 0..N { ptrs[i] = MaybeUninit::new(self.get_unchecked_mut(keys[i])); } core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs) } /// An iterator visiting all key-value pairs in arbitrary order. The /// iterator element type is `(K, &'a V)`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let k0 = sm.insert(0); /// let k1 = sm.insert(1); /// let k2 = sm.insert(2); /// /// for (k, v) in sm.iter() { /// println!("key: {:?}, val: {}", k, v); /// } /// ``` pub fn iter(&self) -> Iter { let mut it = self.slots.iter().enumerate(); it.next(); // Skip sentinel. Iter { slots: it, num_left: self.len(), _k: PhantomData, } } /// An iterator visiting all key-value pairs in arbitrary order, with /// mutable references to the values. The iterator element type is /// `(K, &'a mut V)`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let k0 = sm.insert(10); /// let k1 = sm.insert(20); /// let k2 = sm.insert(30); /// /// for (k, v) in sm.iter_mut() { /// if k != k1 { /// *v *= -1; /// } /// } /// /// assert_eq!(sm[k0], -10); /// assert_eq!(sm[k1], 20); /// assert_eq!(sm[k2], -30); /// ``` pub fn iter_mut(&mut self) -> IterMut { let len = self.len(); let mut it = self.slots.iter_mut().enumerate(); it.next(); // Skip sentinel. IterMut { num_left: len, slots: it, _k: PhantomData, } } /// An iterator visiting all keys in arbitrary order. The iterator element /// type is `K`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = SlotMap::new(); /// let k0 = sm.insert(10); /// let k1 = sm.insert(20); /// let k2 = sm.insert(30); /// let keys: HashSet<_> = sm.keys().collect(); /// let check: HashSet<_> = vec![k0, k1, k2].into_iter().collect(); /// assert_eq!(keys, check); /// ``` pub fn keys(&self) -> Keys { Keys { inner: self.iter() } } /// An iterator visiting all values in arbitrary order. The iterator element /// type is `&'a V`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = SlotMap::new(); /// let k0 = sm.insert(10); /// let k1 = sm.insert(20); /// let k2 = sm.insert(30); /// let values: HashSet<_> = sm.values().collect(); /// let check: HashSet<_> = vec![&10, &20, &30].into_iter().collect(); /// assert_eq!(values, check); /// ``` pub fn values(&self) -> Values { Values { inner: self.iter() } } /// An iterator visiting all values mutably in arbitrary order. The iterator /// element type is `&'a mut V`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = SlotMap::new(); /// sm.insert(1); /// sm.insert(2); /// sm.insert(3); /// sm.values_mut().for_each(|n| { *n *= 3 }); /// let values: HashSet<_> = sm.into_iter().map(|(_k, v)| v).collect(); /// let check: HashSet<_> = vec![3, 6, 9].into_iter().collect(); /// assert_eq!(values, check); /// ``` pub fn values_mut(&mut self) -> ValuesMut { ValuesMut { inner: self.iter_mut(), } } } impl Clone for SlotMap where V: Clone, { fn clone(&self) -> Self { Self { slots: self.slots.clone(), ..*self } } fn clone_from(&mut self, source: &Self) { self.slots.clone_from(&source.slots); self.free_head = source.free_head; self.num_elems = source.num_elems; } } impl Default for SlotMap { fn default() -> Self { Self::with_key() } } impl Index for SlotMap { type Output = V; fn index(&self, key: K) -> &V { match self.get(key) { Some(r) => r, None => panic!("invalid SlotMap key used"), } } } impl IndexMut for SlotMap { fn index_mut(&mut self, key: K) -> &mut V { match self.get_mut(key) { Some(r) => r, None => panic!("invalid SlotMap key used"), } } } // Iterators. /// A draining iterator for [`SlotMap`]. /// /// This iterator is created by [`SlotMap::drain`]. #[derive(Debug)] pub struct Drain<'a, K: 'a + Key, V: 'a> { sm: &'a mut SlotMap, cur: usize, } /// An iterator that moves key-value pairs out of a [`SlotMap`]. /// /// This iterator is created by calling the `into_iter` method on [`SlotMap`], /// provided by the [`IntoIterator`] trait. #[derive(Debug, Clone)] pub struct IntoIter { num_left: usize, slots: Enumerate>>, _k: PhantomData K>, } /// An iterator over the key-value pairs in a [`SlotMap`]. /// /// This iterator is created by [`SlotMap::iter`]. #[derive(Debug)] pub struct Iter<'a, K: 'a + Key, V: 'a> { num_left: usize, slots: Enumerate>>, _k: PhantomData K>, } impl<'a, K: 'a + Key, V: 'a> Clone for Iter<'a, K, V> { fn clone(&self) -> Self { Iter { num_left: self.num_left, slots: self.slots.clone(), _k: self._k, } } } /// A mutable iterator over the key-value pairs in a [`SlotMap`]. /// /// This iterator is created by [`SlotMap::iter_mut`]. #[derive(Debug)] pub struct IterMut<'a, K: 'a + Key, V: 'a> { num_left: usize, slots: Enumerate>>, _k: PhantomData K>, } /// An iterator over the keys in a [`SlotMap`]. /// /// This iterator is created by [`SlotMap::keys`]. #[derive(Debug)] pub struct Keys<'a, K: 'a + Key, V: 'a> { inner: Iter<'a, K, V>, } impl<'a, K: 'a + Key, V: 'a> Clone for Keys<'a, K, V> { fn clone(&self) -> Self { Keys { inner: self.inner.clone(), } } } /// An iterator over the values in a [`SlotMap`]. /// /// This iterator is created by [`SlotMap::values`]. #[derive(Debug)] pub struct Values<'a, K: 'a + Key, V: 'a> { inner: Iter<'a, K, V>, } impl<'a, K: 'a + Key, V: 'a> Clone for Values<'a, K, V> { fn clone(&self) -> Self { Values { inner: self.inner.clone(), } } } /// A mutable iterator over the values in a [`SlotMap`]. /// /// This iterator is created by [`SlotMap::values_mut`]. #[derive(Debug)] pub struct ValuesMut<'a, K: 'a + Key, V: 'a> { inner: IterMut<'a, K, V>, } impl<'a, K: Key, V> Iterator for Drain<'a, K, V> { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { let len = self.sm.slots.len(); while self.cur < len { let idx = self.cur; self.cur += 1; // This is safe because removing doesn't shrink slots. unsafe { let slot = self.sm.slots.get_unchecked(idx); if slot.occupied() { let kd = KeyData::new(idx as u32, slot.version); return Some((kd.into(), self.sm.remove_from_slot(idx))); } } } None } fn size_hint(&self) -> (usize, Option) { (self.sm.len(), Some(self.sm.len())) } } impl<'a, K: Key, V> Drop for Drain<'a, K, V> { fn drop(&mut self) { self.for_each(|_drop| {}); } } impl Iterator for IntoIter { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { while let Some((idx, mut slot)) = self.slots.next() { if slot.occupied() { let kd = KeyData::new(idx as u32, slot.version); // Prevent dropping after extracting the value. slot.version = 0; // This is safe because we know the slot was occupied. let value = unsafe { ManuallyDrop::take(&mut slot.u.value) }; self.num_left -= 1; return Some((kd.into(), value)); } } None } fn size_hint(&self) -> (usize, Option) { (self.num_left, Some(self.num_left)) } } impl<'a, K: Key, V> Iterator for Iter<'a, K, V> { type Item = (K, &'a V); fn next(&mut self) -> Option<(K, &'a V)> { while let Some((idx, slot)) = self.slots.next() { if let Occupied(value) = slot.get() { let kd = KeyData::new(idx as u32, slot.version); self.num_left -= 1; return Some((kd.into(), value)); } } None } fn size_hint(&self) -> (usize, Option) { (self.num_left, Some(self.num_left)) } } impl<'a, K: Key, V> Iterator for IterMut<'a, K, V> { type Item = (K, &'a mut V); fn next(&mut self) -> Option<(K, &'a mut V)> { while let Some((idx, slot)) = self.slots.next() { let version = slot.version; if let OccupiedMut(value) = slot.get_mut() { let kd = KeyData::new(idx as u32, version); self.num_left -= 1; return Some((kd.into(), value)); } } None } fn size_hint(&self) -> (usize, Option) { (self.num_left, Some(self.num_left)) } } impl<'a, K: Key, V> Iterator for Keys<'a, K, V> { type Item = K; fn next(&mut self) -> Option { self.inner.next().map(|(key, _)| key) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Iterator for Values<'a, K, V> { type Item = &'a V; fn next(&mut self) -> Option<&'a V> { self.inner.next().map(|(_, value)| value) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; fn next(&mut self) -> Option<&'a mut V> { self.inner.next().map(|(_, value)| value) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> IntoIterator for &'a SlotMap { type Item = (K, &'a V); type IntoIter = Iter<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, K: Key, V> IntoIterator for &'a mut SlotMap { type Item = (K, &'a mut V); type IntoIter = IterMut<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl IntoIterator for SlotMap { type Item = (K, V); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { let len = self.len(); let mut it = self.slots.into_iter().enumerate(); it.next(); // Skip sentinel. IntoIter { num_left: len, slots: it, _k: PhantomData, } } } impl<'a, K: Key, V> FusedIterator for Iter<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for IterMut<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Keys<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Values<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for ValuesMut<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Drain<'a, K, V> {} impl FusedIterator for IntoIter {} impl<'a, K: Key, V> ExactSizeIterator for Iter<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for IterMut<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Keys<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Values<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for ValuesMut<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Drain<'a, K, V> {} impl ExactSizeIterator for IntoIter {} // Serialization with serde. #[cfg(feature = "serde")] mod serialize { use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use super::*; #[derive(Serialize, Deserialize)] struct SerdeSlot { value: Option, version: u32, } impl Serialize for Slot { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let serde_slot = SerdeSlot { version: self.version, value: match self.get() { Occupied(value) => Some(value), Vacant(_) => None, }, }; serde_slot.serialize(serializer) } } impl<'de, T> Deserialize<'de> for Slot where T: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let serde_slot: SerdeSlot = Deserialize::deserialize(deserializer)?; let occupied = serde_slot.version % 2 == 1; if occupied ^ serde_slot.value.is_some() { return Err(de::Error::custom(&"inconsistent occupation in Slot")); } Ok(Self { u: match serde_slot.value { Some(value) => SlotUnion { value: ManuallyDrop::new(value), }, None => SlotUnion { next_free: 0 }, }, version: serde_slot.version, }) } } impl Serialize for SlotMap { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.slots.serialize(serializer) } } impl<'de, K, V> Deserialize<'de> for SlotMap where K: Key, V: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let mut slots: Vec> = Deserialize::deserialize(deserializer)?; if slots.len() >= u32::max_value() as usize { return Err(de::Error::custom(&"too many slots")); } // Ensure the first slot exists and is empty for the sentinel. if slots.get(0).map_or(true, |slot| slot.version % 2 == 1) { return Err(de::Error::custom(&"first slot not empty")); } slots[0].version = 0; slots[0].u.next_free = 0; // We have our slots, rebuild freelist. let mut num_elems = 0; let mut next_free = slots.len(); for (i, slot) in slots[1..].iter_mut().enumerate() { if slot.occupied() { num_elems += 1; } else { slot.u.next_free = next_free as u32; next_free = i + 1; } } Ok(Self { num_elems, slots, free_head: next_free as u32, _k: PhantomData, }) } } } #[cfg(test)] mod tests { use std::collections::{HashMap, HashSet}; use quickcheck::quickcheck; use super::*; #[derive(Clone)] struct CountDrop<'a>(&'a std::cell::RefCell); impl<'a> Drop for CountDrop<'a> { fn drop(&mut self) { *self.0.borrow_mut() += 1; } } #[cfg(all(nightly, feature = "unstable"))] #[test] fn check_drops() { let drops = std::cell::RefCell::new(0usize); { let mut clone = { // Insert 1000 items. let mut sm = SlotMap::new(); let mut sm_keys = Vec::new(); for _ in 0..1000 { sm_keys.push(sm.insert(CountDrop(&drops))); } // Remove even keys. for i in (0..1000).filter(|i| i % 2 == 0) { sm.remove(sm_keys[i]); } // Should only have dropped 500 so far. assert_eq!(*drops.borrow(), 500); // Let's clone ourselves and then die. sm.clone() }; // Now all original items should have been dropped exactly once. assert_eq!(*drops.borrow(), 1000); // Reuse some empty slots. for _ in 0..250 { clone.insert(CountDrop(&drops)); } } // 1000 + 750 drops in total should have happened. assert_eq!(*drops.borrow(), 1750); } #[cfg(all(nightly, feature = "unstable"))] #[test] fn disjoint() { // Intended to be run with miri to find any potential UB. let mut sm = SlotMap::new(); // Some churn. for i in 0..20usize { sm.insert(i); } sm.retain(|_, i| *i % 2 == 0); let keys: Vec<_> = sm.keys().collect(); for i in 0..keys.len() { for j in 0..keys.len() { if let Some([r0, r1]) = sm.get_disjoint_mut([keys[i], keys[j]]) { *r0 ^= *r1; *r1 = r1.wrapping_add(*r0); } else { assert!(i == j); } } } for i in 0..keys.len() { for j in 0..keys.len() { for k in 0..keys.len() { if let Some([r0, r1, r2]) = sm.get_disjoint_mut([keys[i], keys[j], keys[k]]) { *r0 ^= *r1; *r0 = r0.wrapping_add(*r2); *r1 ^= *r0; *r1 = r1.wrapping_add(*r2); *r2 ^= *r0; *r2 = r2.wrapping_add(*r1); } else { assert!(i == j || j == k || i == k); } } } } } quickcheck! { fn qc_slotmap_equiv_hashmap(operations: Vec<(u8, u32)>) -> bool { let mut hm = HashMap::new(); let mut hm_keys = Vec::new(); let mut unique_key = 0u32; let mut sm = SlotMap::new(); let mut sm_keys = Vec::new(); #[cfg(not(feature = "serde"))] let num_ops = 3; #[cfg(feature = "serde")] let num_ops = 4; for (op, val) in operations { match op % num_ops { // Insert. 0 => { hm.insert(unique_key, val); hm_keys.push(unique_key); unique_key += 1; sm_keys.push(sm.insert(val)); } // Delete. 1 => { // 10% of the time test clear. if val % 10 == 0 { let hmvals: HashSet<_> = hm.drain().map(|(_, v)| v).collect(); let smvals: HashSet<_> = sm.drain().map(|(_, v)| v).collect(); if hmvals != smvals { return false; } } if hm_keys.is_empty() { continue; } let idx = val as usize % hm_keys.len(); if hm.remove(&hm_keys[idx]) != sm.remove(sm_keys[idx]) { return false; } } // Access. 2 => { if hm_keys.is_empty() { continue; } let idx = val as usize % hm_keys.len(); let (hm_key, sm_key) = (&hm_keys[idx], sm_keys[idx]); if hm.contains_key(hm_key) != sm.contains_key(sm_key) || hm.get(hm_key) != sm.get(sm_key) { return false; } } // Serde round-trip. #[cfg(feature = "serde")] 3 => { let ser = serde_json::to_string(&sm).unwrap(); sm = serde_json::from_str(&ser).unwrap(); } _ => unreachable!(), } } let mut smv: Vec<_> = sm.values().collect(); let mut hmv: Vec<_> = hm.values().collect(); smv.sort(); hmv.sort(); smv == hmv } } #[cfg(feature = "serde")] #[test] fn slotmap_serde() { let mut sm = SlotMap::new(); // Self-referential structure. let first = sm.insert_with_key(|k| (k, 23i32)); let second = sm.insert((first, 42)); // Make some empty slots. let empties = vec![sm.insert((first, 0)), sm.insert((first, 0))]; empties.iter().for_each(|k| { sm.remove(*k); }); let third = sm.insert((second, 0)); sm[first].0 = third; let ser = serde_json::to_string(&sm).unwrap(); let de: SlotMap = serde_json::from_str(&ser).unwrap(); assert_eq!(de.len(), sm.len()); let mut smkv: Vec<_> = sm.iter().collect(); let mut dekv: Vec<_> = de.iter().collect(); smkv.sort(); dekv.sort(); assert_eq!(smkv, dekv); } #[cfg(feature = "serde")] #[test] fn slotmap_serde_freelist() { let mut sm = SlotMap::new(); let k = sm.insert(5i32); sm.remove(k); let ser = serde_json::to_string(&sm).unwrap(); let mut de: SlotMap = serde_json::from_str(&ser).unwrap(); de.insert(0); de.insert(1); de.insert(2); assert_eq!(de.len(), 3); } } slotmap-1.0.7/src/dense.rs000064400000000000000000001261020072674642500135750ustar 00000000000000//! Contains the dense slot map implementation. // There is quite a lot of unsafe code in this implementation. To prevent the // same explanation over and over again, care must be taken that indices in // slots and keys from key-value pairs **that are stored inside the slot map** // are valid. Keys that are received from the user are not trusted (as they // might have come from a different slot map or malicious serde deseralization). #[cfg(all(nightly, any(doc, feature = "unstable")))] use alloc::collections::TryReserveError; use alloc::vec::Vec; use core::iter::FusedIterator; #[allow(unused_imports)] // MaybeUninit is only used on nightly at the moment. use core::mem::MaybeUninit; use core::ops::{Index, IndexMut}; use crate::util::{Never, UnwrapUnchecked}; use crate::{DefaultKey, Key, KeyData}; // A slot, which represents storage for an index and a current version. // Can be occupied or vacant. #[derive(Debug, Clone)] struct Slot { // Even = vacant, odd = occupied. version: u32, // An index when occupied, the next free slot otherwise. idx_or_free: u32, } /// Dense slot map, storage with stable unique keys. /// /// See [crate documentation](crate) for more details. #[derive(Debug)] pub struct DenseSlotMap { keys: Vec, values: Vec, slots: Vec, free_head: u32, } impl DenseSlotMap { /// Construct a new, empty [`DenseSlotMap`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm: DenseSlotMap<_, i32> = DenseSlotMap::new(); /// ``` pub fn new() -> Self { Self::with_capacity_and_key(0) } /// Creates an empty [`DenseSlotMap`] with the given capacity. /// /// The slot map will not reallocate until it holds at least `capacity` /// elements. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm: DenseSlotMap<_, i32> = DenseSlotMap::with_capacity(10); /// ``` pub fn with_capacity(capacity: usize) -> DenseSlotMap { Self::with_capacity_and_key(capacity) } } impl DenseSlotMap { /// Constructs a new, empty [`DenseSlotMap`] with a custom key type. /// /// # Examples /// /// ``` /// # use slotmap::*; /// new_key_type! { /// struct PositionKey; /// } /// let mut positions: DenseSlotMap = DenseSlotMap::with_key(); /// ``` pub fn with_key() -> Self { Self::with_capacity_and_key(0) } /// Creates an empty [`DenseSlotMap`] with the given capacity and a custom key /// type. /// /// The slot map will not reallocate until it holds at least `capacity` /// elements. /// /// # Examples /// /// ``` /// # use slotmap::*; /// new_key_type! { /// struct MessageKey; /// } /// let mut messages = DenseSlotMap::with_capacity_and_key(3); /// let welcome: MessageKey = messages.insert("Welcome"); /// let good_day = messages.insert("Good day"); /// let hello = messages.insert("Hello"); /// ``` pub fn with_capacity_and_key(capacity: usize) -> Self { // Create slots with a sentinel at index 0. // We don't actually use the sentinel for anything currently, but // HopSlotMap does, and if we want keys to remain valid through // conversion we have to have one as well. let mut slots = Vec::with_capacity(capacity + 1); slots.push(Slot { idx_or_free: 0, version: 0, }); DenseSlotMap { keys: Vec::with_capacity(capacity), values: Vec::with_capacity(capacity), slots, free_head: 1, } } /// Returns the number of elements in the slot map. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::with_capacity(10); /// sm.insert("len() counts actual elements, not capacity"); /// let key = sm.insert("removed elements don't count either"); /// sm.remove(key); /// assert_eq!(sm.len(), 1); /// ``` pub fn len(&self) -> usize { self.keys.len() } /// Returns if the slot map is empty. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let key = sm.insert("dummy"); /// assert_eq!(sm.is_empty(), false); /// sm.remove(key); /// assert_eq!(sm.is_empty(), true); /// ``` pub fn is_empty(&self) -> bool { self.keys.is_empty() } /// Returns the number of elements the [`DenseSlotMap`] can hold without /// reallocating. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let sm: DenseSlotMap<_, f64> = DenseSlotMap::with_capacity(10); /// assert_eq!(sm.capacity(), 10); /// ``` pub fn capacity(&self) -> usize { self.keys.capacity() } /// Reserves capacity for at least `additional` more elements to be inserted /// in the [`DenseSlotMap`]. The collection may reserve more space to /// avoid frequent reallocations. /// /// # Panics /// /// Panics if the new allocation size overflows [`usize`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// sm.insert("foo"); /// sm.reserve(32); /// assert!(sm.capacity() >= 33); /// ``` pub fn reserve(&mut self, additional: usize) { self.keys.reserve(additional); self.values.reserve(additional); // One slot is reserved for the sentinel. let needed = (self.len() + additional).saturating_sub(self.slots.len() - 1); self.slots.reserve(needed); } /// Tries to reserve capacity for at least `additional` more elements to be /// inserted in the [`DenseSlotMap`]. The collection may reserve more space to /// avoid frequent reallocations. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// sm.insert("foo"); /// sm.try_reserve(32).unwrap(); /// assert!(sm.capacity() >= 33); /// ``` #[cfg(all(nightly, any(doc, feature = "unstable")))] #[cfg_attr(all(nightly, doc), doc(cfg(feature = "unstable")))] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.keys.try_reserve(additional)?; self.values.try_reserve(additional)?; // One slot is reserved for the sentinel. let needed = (self.len() + additional).saturating_sub(self.slots.len() - 1); self.slots.try_reserve(needed) } /// Returns [`true`] if the slot map contains `key`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let key = sm.insert(42); /// assert_eq!(sm.contains_key(key), true); /// sm.remove(key); /// assert_eq!(sm.contains_key(key), false); /// ``` pub fn contains_key(&self, key: K) -> bool { let kd = key.data(); self.slots .get(kd.idx as usize) .map_or(false, |slot| slot.version == kd.version.get()) } /// Inserts a value into the slot map. Returns a unique key that can be used /// to access this value. /// /// # Panics /// /// Panics if the number of elements in the slot map equals /// 232 - 2. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let key = sm.insert(42); /// assert_eq!(sm[key], 42); /// ``` #[inline(always)] pub fn insert(&mut self, value: V) -> K { unsafe { self.try_insert_with_key::<_, Never>(move |_| Ok(value)).unwrap_unchecked_() } } /// Inserts a value given by `f` into the slot map. The key where the /// value will be stored is passed into `f`. This is useful to store values /// that contain their own key. /// /// # Panics /// /// Panics if the number of elements in the slot map equals /// 232 - 2. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let key = sm.insert_with_key(|k| (k, 20)); /// assert_eq!(sm[key], (key, 20)); /// ``` #[inline(always)] pub fn insert_with_key(&mut self, f: F) -> K where F: FnOnce(K) -> V, { unsafe { self.try_insert_with_key::<_, Never>(move |k| Ok(f(k))).unwrap_unchecked_() } } /// Inserts a value given by `f` into the slot map. The key where the /// value will be stored is passed into `f`. This is useful to store values /// that contain their own key. /// /// If `f` returns `Err`, this method returns the error. The slotmap is untouched. /// /// # Panics /// /// Panics if the number of elements in the slot map equals /// 232 - 2. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let key = sm.try_insert_with_key::<_, ()>(|k| Ok((k, 20))).unwrap(); /// assert_eq!(sm[key], (key, 20)); /// /// sm.try_insert_with_key::<_, ()>(|k| Err(())).unwrap_err(); /// ``` pub fn try_insert_with_key(&mut self, f: F) -> Result where F: FnOnce(K) -> Result, { if self.len() >= (core::u32::MAX - 1) as usize { panic!("DenseSlotMap number of elements overflow"); } let idx = self.free_head; if let Some(slot) = self.slots.get_mut(idx as usize) { let occupied_version = slot.version | 1; let key = KeyData::new(idx, occupied_version).into(); // Push value before adjusting slots/freelist in case f panics or returns an error. self.values.push(f(key)?); self.keys.push(key); self.free_head = slot.idx_or_free; slot.idx_or_free = self.keys.len() as u32 - 1; slot.version = occupied_version; return Ok(key); } // Push value before adjusting slots/freelist in case f panics or returns an error. let key = KeyData::new(idx, 1).into(); self.values.push(f(key)?); self.keys.push(key); self.slots.push(Slot { version: 1, idx_or_free: self.keys.len() as u32 - 1, }); self.free_head = self.slots.len() as u32; Ok(key) } // Helper function to add a slot to the freelist. Returns the index that // was stored in the slot. #[inline(always)] fn free_slot(&mut self, slot_idx: usize) -> u32 { let slot = &mut self.slots[slot_idx]; let value_idx = slot.idx_or_free; slot.version = slot.version.wrapping_add(1); slot.idx_or_free = self.free_head; self.free_head = slot_idx as u32; value_idx } // Helper function to remove a value from a slot and make the slot free. // Returns the value removed. #[inline(always)] fn remove_from_slot(&mut self, slot_idx: usize) -> V { let value_idx = self.free_slot(slot_idx); // Remove values/slot_indices by swapping to end. let _ = self.keys.swap_remove(value_idx as usize); let value = self.values.swap_remove(value_idx as usize); // Did something take our place? Update its slot to new position. if let Some(k) = self.keys.get(value_idx as usize) { self.slots[k.data().idx as usize].idx_or_free = value_idx; } value } /// Removes a key from the slot map, returning the value at the key if the /// key was not previously removed. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let key = sm.insert(42); /// assert_eq!(sm.remove(key), Some(42)); /// assert_eq!(sm.remove(key), None); /// ``` pub fn remove(&mut self, key: K) -> Option { let kd = key.data(); if self.contains_key(kd.into()) { Some(self.remove_from_slot(kd.idx as usize)) } else { None } } /// Retains only the elements specified by the predicate. /// /// In other words, remove all key-value pairs `(k, v)` such that /// `f(k, &mut v)` returns false. This method invalidates any removed keys. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// /// let k3 = sm.insert(2); /// let k1 = sm.insert(0); /// let k2 = sm.insert(1); /// /// sm.retain(|key, val| key == k1 || *val == 1); /// /// assert!(sm.contains_key(k1)); /// assert!(sm.contains_key(k2)); /// assert!(!sm.contains_key(k3)); /// /// assert_eq!(2, sm.len()); /// ``` pub fn retain(&mut self, mut f: F) where F: FnMut(K, &mut V) -> bool, { let mut i = 0; while i < self.keys.len() { let (should_keep, slot_idx) = { let (kd, mut value) = (self.keys[i].data(), &mut self.values[i]); (f(kd.into(), &mut value), kd.idx as usize) }; if should_keep { i += 1; } else { // We do not increment i here intentionally. This index has just // been replaced with a new value. self.remove_from_slot(slot_idx); } } } /// Clears the slot map. Keeps the allocated memory for reuse. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// for i in 0..10 { /// sm.insert(i); /// } /// assert_eq!(sm.len(), 10); /// sm.clear(); /// assert_eq!(sm.len(), 0); /// ``` pub fn clear(&mut self) { self.drain(); } /// Clears the slot map, returning all key-value pairs in arbitrary order /// as an iterator. Keeps the allocated memory for reuse. /// /// When the iterator is dropped all elements in the slot map are removed, /// even if the iterator was not fully consumed. If the iterator is not /// dropped (using e.g. [`std::mem::forget`]), only the elements that were /// iterated over are removed. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let k = sm.insert(0); /// let v: Vec<_> = sm.drain().collect(); /// assert_eq!(sm.len(), 0); /// assert_eq!(v, vec![(k, 0)]); /// ``` pub fn drain(&mut self) -> Drain { Drain { sm: self } } /// Returns a reference to the value corresponding to the key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let key = sm.insert("bar"); /// assert_eq!(sm.get(key), Some(&"bar")); /// sm.remove(key); /// assert_eq!(sm.get(key), None); /// ``` pub fn get(&self, key: K) -> Option<&V> { let kd = key.data(); self.slots .get(kd.idx as usize) .filter(|slot| slot.version == kd.version.get()) .map(|slot| unsafe { // This is safe because we only store valid indices. let idx = slot.idx_or_free as usize; self.values.get_unchecked(idx) }) } /// Returns a reference to the value corresponding to the key without /// version or bounds checking. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true. Otherwise it is /// potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let key = sm.insert("bar"); /// assert_eq!(unsafe { sm.get_unchecked(key) }, &"bar"); /// sm.remove(key); /// // sm.get_unchecked(key) is now dangerous! /// ``` pub unsafe fn get_unchecked(&self, key: K) -> &V { debug_assert!(self.contains_key(key)); let idx = self.slots.get_unchecked(key.data().idx as usize).idx_or_free; &self.values.get_unchecked(idx as usize) } /// Returns a mutable reference to the value corresponding to the key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let key = sm.insert(3.5); /// if let Some(x) = sm.get_mut(key) { /// *x += 3.0; /// } /// assert_eq!(sm[key], 6.5); /// ``` pub fn get_mut(&mut self, key: K) -> Option<&mut V> { let kd = key.data(); self.slots .get(kd.idx as usize) .filter(|slot| slot.version == kd.version.get()) .map(|slot| slot.idx_or_free as usize) .map(move |idx| unsafe { // This is safe because we only store valid indices. self.values.get_unchecked_mut(idx) }) } /// Returns a mutable reference to the value corresponding to the key /// without version or bounds checking. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true. Otherwise it is /// potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let key = sm.insert("foo"); /// unsafe { *sm.get_unchecked_mut(key) = "bar" }; /// assert_eq!(sm[key], "bar"); /// sm.remove(key); /// // sm.get_unchecked_mut(key) is now dangerous! /// ``` pub unsafe fn get_unchecked_mut(&mut self, key: K) -> &mut V { debug_assert!(self.contains_key(key)); let idx = self.slots.get_unchecked(key.data().idx as usize).idx_or_free; self.values.get_unchecked_mut(idx as usize) } /// Returns mutable references to the values corresponding to the given /// keys. All keys must be valid and disjoint, otherwise [`None`] is /// returned. /// /// Requires at least stable Rust version 1.51. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let ka = sm.insert("butter"); /// let kb = sm.insert("apples"); /// let kc = sm.insert("charlie"); /// sm.remove(kc); // Make key c invalid. /// assert_eq!(sm.get_disjoint_mut([ka, kb, kc]), None); // Has invalid key. /// assert_eq!(sm.get_disjoint_mut([ka, ka]), None); // Not disjoint. /// let [a, b] = sm.get_disjoint_mut([ka, kb]).unwrap(); /// std::mem::swap(a, b); /// assert_eq!(sm[ka], "apples"); /// assert_eq!(sm[kb], "butter"); /// ``` #[cfg(has_min_const_generics)] pub fn get_disjoint_mut(&mut self, keys: [K; N]) -> Option<[&mut V; N]> { // Create an uninitialized array of `MaybeUninit`. The `assume_init` is // safe because the type we are claiming to have initialized here is a // bunch of `MaybeUninit`s, which do not require initialization. let mut ptrs: [MaybeUninit<*mut V>; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut i = 0; while i < N { // We can avoid this clone after min_const_generics and array_map. let kd = keys[i].data(); if !self.contains_key(kd.into()) { break; } // This key is valid, and thus the slot is occupied. Temporarily // mark it as unoccupied so duplicate keys would show up as invalid. // This gives us a linear time disjointness check. unsafe { let slot = self.slots.get_unchecked_mut(kd.idx as usize); slot.version ^= 1; let ptr = self.values.get_unchecked_mut(slot.idx_or_free as usize); ptrs[i] = MaybeUninit::new(ptr); } i += 1; } // Undo temporary unoccupied markings. for k in &keys[..i] { let idx = k.data().idx as usize; unsafe { self.slots.get_unchecked_mut(idx).version ^= 1; } } if i == N { // All were valid and disjoint. Some(unsafe { core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs) }) } else { None } } /// Returns mutable references to the values corresponding to the given /// keys. All keys must be valid and disjoint. /// /// Requires at least stable Rust version 1.51. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true for every given /// key and no two keys are equal. Otherwise it is potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let ka = sm.insert("butter"); /// let kb = sm.insert("apples"); /// let [a, b] = unsafe { sm.get_disjoint_unchecked_mut([ka, kb]) }; /// std::mem::swap(a, b); /// assert_eq!(sm[ka], "apples"); /// assert_eq!(sm[kb], "butter"); /// ``` #[cfg(has_min_const_generics)] pub unsafe fn get_disjoint_unchecked_mut( &mut self, keys: [K; N], ) -> [&mut V; N] { // Safe, see get_disjoint_mut. let mut ptrs: [MaybeUninit<*mut V>; N] = MaybeUninit::uninit().assume_init(); for i in 0..N { ptrs[i] = MaybeUninit::new(self.get_unchecked_mut(keys[i])); } core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs) } /// An iterator visiting all key-value pairs in arbitrary order. The /// iterator element type is `(K, &'a V)`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let k0 = sm.insert(0); /// let k1 = sm.insert(1); /// let k2 = sm.insert(2); /// /// let mut it = sm.iter(); /// for (k, v) in sm.iter() { /// println!("key: {:?}, val: {}", k, v); /// } /// ``` pub fn iter(&self) -> Iter { Iter { inner_keys: self.keys.iter(), inner_values: self.values.iter(), } } /// An iterator visiting all key-value pairs in arbitrary order, with /// mutable references to the values. The iterator element type is /// `(K, &'a mut V)`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = DenseSlotMap::new(); /// let k0 = sm.insert(10); /// let k1 = sm.insert(20); /// let k2 = sm.insert(30); /// /// for (k, v) in sm.iter_mut() { /// if k != k1 { /// *v *= -1; /// } /// } /// /// assert_eq!(sm[k0], -10); /// assert_eq!(sm[k1], 20); /// assert_eq!(sm[k2], -30); /// ``` pub fn iter_mut(&mut self) -> IterMut { IterMut { inner_keys: self.keys.iter(), inner_values: self.values.iter_mut(), } } /// An iterator visiting all keys in arbitrary order. The iterator element /// type is K. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = DenseSlotMap::new(); /// let k0 = sm.insert(10); /// let k1 = sm.insert(20); /// let k2 = sm.insert(30); /// let keys: HashSet<_> = sm.keys().collect(); /// let check: HashSet<_> = vec![k0, k1, k2].into_iter().collect(); /// assert_eq!(keys, check); /// ``` pub fn keys(&self) -> Keys { Keys { inner: self.iter() } } /// An iterator visiting all values in arbitrary order. The iterator element /// type is `&'a V`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = DenseSlotMap::new(); /// let k0 = sm.insert(10); /// let k1 = sm.insert(20); /// let k2 = sm.insert(30); /// let values: HashSet<_> = sm.values().collect(); /// let check: HashSet<_> = vec![&10, &20, &30].into_iter().collect(); /// assert_eq!(values, check); /// ``` pub fn values(&self) -> Values { Values { inner: self.iter() } } /// An iterator visiting all values mutably in arbitrary order. The iterator /// element type is `&'a mut V`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = DenseSlotMap::new(); /// sm.insert(1); /// sm.insert(2); /// sm.insert(3); /// sm.values_mut().for_each(|n| { *n *= 3 }); /// let values: HashSet<_> = sm.into_iter().map(|(_k, v)| v).collect(); /// let check: HashSet<_> = vec![3, 6, 9].into_iter().collect(); /// assert_eq!(values, check); /// ``` pub fn values_mut(&mut self) -> ValuesMut { ValuesMut { inner: self.iter_mut(), } } } impl Clone for DenseSlotMap where V: Clone, { fn clone(&self) -> Self { Self { keys: self.keys.clone(), values: self.values.clone(), slots: self.slots.clone(), ..*self } } fn clone_from(&mut self, source: &Self) { self.keys.clone_from(&source.keys); self.values.clone_from(&source.values); self.slots.clone_from(&source.slots); self.free_head = source.free_head; } } impl Default for DenseSlotMap { fn default() -> Self { Self::with_key() } } impl Index for DenseSlotMap { type Output = V; fn index(&self, key: K) -> &V { match self.get(key) { Some(r) => r, None => panic!("invalid DenseSlotMap key used"), } } } impl IndexMut for DenseSlotMap { fn index_mut(&mut self, key: K) -> &mut V { match self.get_mut(key) { Some(r) => r, None => panic!("invalid DenseSlotMap key used"), } } } // Iterators. /// A draining iterator for [`DenseSlotMap`]. /// /// This iterator is created by [`DenseSlotMap::drain`]. #[derive(Debug)] pub struct Drain<'a, K: 'a + Key, V: 'a> { sm: &'a mut DenseSlotMap, } /// An iterator that moves key-value pairs out of a [`DenseSlotMap`]. /// /// This iterator is created by calling the `into_iter` method on [`DenseSlotMap`], /// provided by the [`IntoIterator`] trait. #[derive(Debug, Clone)] pub struct IntoIter { inner_keys: alloc::vec::IntoIter, inner_values: alloc::vec::IntoIter, } /// An iterator over the key-value pairs in a [`DenseSlotMap`]. /// /// This iterator is created by [`DenseSlotMap::iter`]. #[derive(Debug)] pub struct Iter<'a, K: 'a + Key, V: 'a> { inner_keys: core::slice::Iter<'a, K>, inner_values: core::slice::Iter<'a, V>, } impl<'a, K: 'a + Key, V: 'a> Clone for Iter<'a, K, V> { fn clone(&self) -> Self { Iter { inner_keys: self.inner_keys.clone(), inner_values: self.inner_values.clone(), } } } /// A mutable iterator over the key-value pairs in a [`DenseSlotMap`]. /// /// This iterator is created by [`DenseSlotMap::iter_mut`]. #[derive(Debug)] pub struct IterMut<'a, K: 'a + Key, V: 'a> { inner_keys: core::slice::Iter<'a, K>, inner_values: core::slice::IterMut<'a, V>, } /// An iterator over the keys in a [`DenseSlotMap`]. /// /// This iterator is created by [`DenseSlotMap::keys`]. #[derive(Debug)] pub struct Keys<'a, K: 'a + Key, V> { inner: Iter<'a, K, V>, } impl<'a, K: 'a + Key, V: 'a> Clone for Keys<'a, K, V> { fn clone(&self) -> Self { Keys { inner: self.inner.clone(), } } } /// An iterator over the values in a [`DenseSlotMap`]. /// /// This iterator is created by [`DenseSlotMap::values`]. #[derive(Debug)] pub struct Values<'a, K: 'a + Key, V> { inner: Iter<'a, K, V>, } impl<'a, K: 'a + Key, V: 'a> Clone for Values<'a, K, V> { fn clone(&self) -> Self { Values { inner: self.inner.clone(), } } } /// A mutable iterator over the values in a [`DenseSlotMap`]. /// /// This iterator is created by [`DenseSlotMap::values_mut`]. #[derive(Debug)] pub struct ValuesMut<'a, K: 'a + Key, V: 'a> { inner: IterMut<'a, K, V>, } impl<'a, K: Key, V> Iterator for Drain<'a, K, V> { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { // We make no iteration order guarantees, so we just repeatedly pop. let key = self.sm.keys.pop(); let value = self.sm.values.pop(); if let (Some(k), Some(v)) = (key, value) { self.sm.free_slot(k.data().idx as usize); Some((k, v)) } else { None } } fn size_hint(&self) -> (usize, Option) { let len = self.sm.keys.len(); (len, Some(len)) } } impl<'a, K: Key, V> Drop for Drain<'a, K, V> { fn drop(&mut self) { self.for_each(|_drop| {}); } } impl Iterator for IntoIter { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { let key = self.inner_keys.next(); let value = self.inner_values.next(); if let (Some(k), Some(v)) = (key, value) { Some((k, v)) } else { None } } fn size_hint(&self) -> (usize, Option) { self.inner_keys.size_hint() } } impl<'a, K: 'a + Key, V> Iterator for Iter<'a, K, V> { type Item = (K, &'a V); fn next(&mut self) -> Option<(K, &'a V)> { let key = self.inner_keys.next(); let value = self.inner_values.next(); if let (Some(k), Some(v)) = (key, value) { Some((*k, v)) } else { None } } fn size_hint(&self) -> (usize, Option) { self.inner_keys.size_hint() } } impl<'a, K: 'a + Key, V> Iterator for IterMut<'a, K, V> { type Item = (K, &'a mut V); fn next(&mut self) -> Option<(K, &'a mut V)> { let key = self.inner_keys.next(); let value = self.inner_values.next(); if let (Some(k), Some(v)) = (key, value) { Some((*k, v)) } else { None } } fn size_hint(&self) -> (usize, Option) { self.inner_keys.size_hint() } } impl<'a, K: 'a + Key, V> Iterator for Keys<'a, K, V> { type Item = K; fn next(&mut self) -> Option { self.inner.next().map(|(key, _)| key) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: 'a + Key, V> Iterator for Values<'a, K, V> { type Item = &'a V; fn next(&mut self) -> Option<&'a V> { self.inner.next().map(|(_, value)| value) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: 'a + Key, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; fn next(&mut self) -> Option<&'a mut V> { self.inner.next().map(|(_, value)| value) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: 'a + Key, V> IntoIterator for &'a DenseSlotMap { type Item = (K, &'a V); type IntoIter = Iter<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, K: 'a + Key, V> IntoIterator for &'a mut DenseSlotMap { type Item = (K, &'a mut V); type IntoIter = IterMut<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl IntoIterator for DenseSlotMap { type Item = (K, V); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { inner_keys: self.keys.into_iter(), inner_values: self.values.into_iter(), } } } impl<'a, K: 'a + Key, V> FusedIterator for Iter<'a, K, V> {} impl<'a, K: 'a + Key, V> FusedIterator for IterMut<'a, K, V> {} impl<'a, K: 'a + Key, V> FusedIterator for Keys<'a, K, V> {} impl<'a, K: 'a + Key, V> FusedIterator for Values<'a, K, V> {} impl<'a, K: 'a + Key, V> FusedIterator for ValuesMut<'a, K, V> {} impl<'a, K: 'a + Key, V> FusedIterator for Drain<'a, K, V> {} impl FusedIterator for IntoIter {} impl<'a, K: 'a + Key, V> ExactSizeIterator for Iter<'a, K, V> {} impl<'a, K: 'a + Key, V> ExactSizeIterator for IterMut<'a, K, V> {} impl<'a, K: 'a + Key, V> ExactSizeIterator for Keys<'a, K, V> {} impl<'a, K: 'a + Key, V> ExactSizeIterator for Values<'a, K, V> {} impl<'a, K: 'a + Key, V> ExactSizeIterator for ValuesMut<'a, K, V> {} impl<'a, K: 'a + Key, V> ExactSizeIterator for Drain<'a, K, V> {} impl ExactSizeIterator for IntoIter {} // Serialization with serde. #[cfg(feature = "serde")] mod serialize { use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use super::*; #[derive(Serialize, Deserialize)] struct SerdeSlot { value: Option, version: u32, } impl Serialize for DenseSlotMap { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let serde_slots: Vec<_> = self .slots .iter() .map(|slot| SerdeSlot { value: if slot.version % 2 == 1 { self.values.get(slot.idx_or_free as usize) } else { None }, version: slot.version, }) .collect(); serde_slots.serialize(serializer) } } impl<'de, K: Key, V: Deserialize<'de>> Deserialize<'de> for DenseSlotMap { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let serde_slots: Vec> = Deserialize::deserialize(deserializer)?; if serde_slots.len() >= u32::max_value() as usize { return Err(de::Error::custom(&"too many slots")); } // Ensure the first slot exists and is empty for the sentinel. if serde_slots.get(0).map_or(true, |slot| slot.version % 2 == 1) { return Err(de::Error::custom(&"first slot not empty")); } // Rebuild slots, key and values. let mut keys = Vec::new(); let mut values = Vec::new(); let mut slots = Vec::new(); slots.push(Slot { idx_or_free: 0, version: 0, }); let mut next_free = serde_slots.len(); for (i, serde_slot) in serde_slots.into_iter().enumerate().skip(1) { let occupied = serde_slot.version % 2 == 1; if occupied ^ serde_slot.value.is_some() { return Err(de::Error::custom(&"inconsistent occupation in Slot")); } if let Some(value) = serde_slot.value { let kd = KeyData::new(i as u32, serde_slot.version); keys.push(kd.into()); values.push(value); slots.push(Slot { version: serde_slot.version, idx_or_free: (keys.len() - 1) as u32, }); } else { slots.push(Slot { version: serde_slot.version, idx_or_free: next_free as u32, }); next_free = i; } } Ok(DenseSlotMap { keys, values, slots, free_head: next_free as u32, }) } } } #[cfg(test)] mod tests { use std::collections::{HashMap, HashSet}; use quickcheck::quickcheck; use super::*; #[derive(Clone)] struct CountDrop<'a>(&'a core::cell::RefCell); impl<'a> Drop for CountDrop<'a> { fn drop(&mut self) { *self.0.borrow_mut() += 1; } } #[test] fn check_drops() { let drops = core::cell::RefCell::new(0usize); { let mut clone = { // Insert 1000 items. let mut sm = DenseSlotMap::new(); let mut sm_keys = Vec::new(); for _ in 0..1000 { sm_keys.push(sm.insert(CountDrop(&drops))); } // Remove even keys. for i in (0..1000).filter(|i| i % 2 == 0) { sm.remove(sm_keys[i]); } // Should only have dropped 500 so far. assert_eq!(*drops.borrow(), 500); // Let's clone ourselves and then die. sm.clone() }; // Now all original items should have been dropped exactly once. assert_eq!(*drops.borrow(), 1000); // Re-use some empty slots. for _ in 0..250 { clone.insert(CountDrop(&drops)); } } // 1000 + 750 drops in total should have happened. assert_eq!(*drops.borrow(), 1750); } #[cfg(all(nightly, feature = "unstable"))] #[test] fn disjoint() { // Intended to be run with miri to find any potential UB. let mut sm = DenseSlotMap::new(); // Some churn. for i in 0..20usize { sm.insert(i); } sm.retain(|_, i| *i % 2 == 0); let keys: Vec<_> = sm.keys().collect(); for i in 0..keys.len() { for j in 0..keys.len() { if let Some([r0, r1]) = sm.get_disjoint_mut([keys[i], keys[j]]) { *r0 ^= *r1; *r1 = r1.wrapping_add(*r0); } else { assert!(i == j); } } } for i in 0..keys.len() { for j in 0..keys.len() { for k in 0..keys.len() { if let Some([r0, r1, r2]) = sm.get_disjoint_mut([keys[i], keys[j], keys[k]]) { *r0 ^= *r1; *r0 = r0.wrapping_add(*r2); *r1 ^= *r0; *r1 = r1.wrapping_add(*r2); *r2 ^= *r0; *r2 = r2.wrapping_add(*r1); } else { assert!(i == j || j == k || i == k); } } } } } quickcheck! { fn qc_slotmap_equiv_hashmap(operations: Vec<(u8, u32)>) -> bool { let mut hm = HashMap::new(); let mut hm_keys = Vec::new(); let mut unique_key = 0u32; let mut sm = DenseSlotMap::new(); let mut sm_keys = Vec::new(); #[cfg(not(feature = "serde"))] let num_ops = 3; #[cfg(feature = "serde")] let num_ops = 4; for (op, val) in operations { match op % num_ops { // Insert. 0 => { hm.insert(unique_key, val); hm_keys.push(unique_key); unique_key += 1; sm_keys.push(sm.insert(val)); } // Delete. 1 => { // 10% of the time test clear. if val % 10 == 0 { let hmvals: HashSet<_> = hm.drain().map(|(_, v)| v).collect(); let smvals: HashSet<_> = sm.drain().map(|(_, v)| v).collect(); if hmvals != smvals { return false; } } if hm_keys.is_empty() { continue; } let idx = val as usize % hm_keys.len(); if hm.remove(&hm_keys[idx]) != sm.remove(sm_keys[idx]) { return false; } } // Access. 2 => { if hm_keys.is_empty() { continue; } let idx = val as usize % hm_keys.len(); let (hm_key, sm_key) = (&hm_keys[idx], sm_keys[idx]); if hm.contains_key(hm_key) != sm.contains_key(sm_key) || hm.get(hm_key) != sm.get(sm_key) { return false; } } // Serde round-trip. #[cfg(feature = "serde")] 3 => { let ser = serde_json::to_string(&sm).unwrap(); sm = serde_json::from_str(&ser).unwrap(); } _ => unreachable!(), } } let mut smv: Vec<_> = sm.values().collect(); let mut hmv: Vec<_> = hm.values().collect(); smv.sort(); hmv.sort(); smv == hmv } } #[cfg(feature = "serde")] #[test] fn slotmap_serde() { let mut sm = DenseSlotMap::new(); // Self-referential structure. let first = sm.insert_with_key(|k| (k, 23i32)); let second = sm.insert((first, 42)); // Make some empty slots. let empties = vec![sm.insert((first, 0)), sm.insert((first, 0))]; empties.iter().for_each(|k| { sm.remove(*k); }); let third = sm.insert((second, 0)); sm[first].0 = third; let ser = serde_json::to_string(&sm).unwrap(); let de: DenseSlotMap = serde_json::from_str(&ser).unwrap(); assert_eq!(de.len(), sm.len()); let mut smkv: Vec<_> = sm.iter().collect(); let mut dekv: Vec<_> = de.iter().collect(); smkv.sort(); dekv.sort(); assert_eq!(smkv, dekv); } #[cfg(feature = "serde")] #[test] fn slotmap_serde_freelist() { let mut sm = DenseSlotMap::new(); let k0 = sm.insert(5i32); let k1 = sm.insert(5i32); sm.remove(k0); sm.remove(k1); let ser = serde_json::to_string(&sm).unwrap(); let mut de: DenseSlotMap = serde_json::from_str(&ser).unwrap(); de.insert(0); de.insert(1); de.insert(2); assert_eq!(de.len(), 3); } } slotmap-1.0.7/src/hop.rs000064400000000000000000001504160072674642500132720ustar 00000000000000// Needed because assigning to non-Copy union is unsafe in stable but not in nightly. #![allow(unused_unsafe)] //! Contains the faster iteration, slower insertion/removal slot map //! implementation. //! //! This data structure is essentially the same as a regular [`SlotMap`], but //! maintains extra information when inserting/removing elements that allows it //! to 'hop over' vacant slots during iteration, making it potentially much //! faster for iteration. //! //! The trade-off is that compared to a regular [`SlotMap`] insertion/removal is //! roughly twice as slow. Random indexing has identical performance for both. //! //! [`SlotMap`]: crate::SlotMap #[cfg(all(nightly, any(doc, feature = "unstable")))] use alloc::collections::TryReserveError; use alloc::vec::Vec; use core::fmt; use core::iter::FusedIterator; use core::marker::PhantomData; use core::mem::ManuallyDrop; #[allow(unused_imports)] // MaybeUninit is only used on nightly at the moment. use core::mem::MaybeUninit; use core::ops::{Index, IndexMut}; use crate::util::{Never, UnwrapUnchecked}; use crate::{DefaultKey, Key, KeyData}; // Metadata to maintain the freelist. #[derive(Clone, Copy, Debug)] struct FreeListEntry { next: u32, prev: u32, other_end: u32, } // Storage inside a slot or metadata for the freelist when vacant. union SlotUnion { value: ManuallyDrop, free: FreeListEntry, } // A slot, which represents storage for a value and a current version. // Can be occupied or vacant. struct Slot { u: SlotUnion, version: u32, // Even = vacant, odd = occupied. } // Safe API to read a slot. enum SlotContent<'a, T: 'a> { Occupied(&'a T), Vacant(&'a FreeListEntry), } enum SlotContentMut<'a, T: 'a> { OccupiedMut(&'a mut T), VacantMut(&'a mut FreeListEntry), } use self::SlotContent::{Occupied, Vacant}; use self::SlotContentMut::{OccupiedMut, VacantMut}; impl Slot { // Is this slot occupied? #[inline(always)] pub fn occupied(&self) -> bool { self.version % 2 == 1 } pub fn get(&self) -> SlotContent { unsafe { if self.occupied() { Occupied(&*self.u.value) } else { Vacant(&self.u.free) } } } pub fn get_mut(&mut self) -> SlotContentMut { unsafe { if self.occupied() { OccupiedMut(&mut *self.u.value) } else { VacantMut(&mut self.u.free) } } } } impl Drop for Slot { fn drop(&mut self) { if core::mem::needs_drop::() && self.occupied() { // This is safe because we checked that we're occupied. unsafe { ManuallyDrop::drop(&mut self.u.value); } } } } impl Clone for Slot { fn clone(&self) -> Self { Self { u: match self.get() { Occupied(value) => SlotUnion { value: ManuallyDrop::new(value.clone()), }, Vacant(&free) => SlotUnion { free }, }, version: self.version, } } fn clone_from(&mut self, source: &Self) { match (self.get_mut(), source.get()) { (OccupiedMut(self_val), Occupied(source_val)) => self_val.clone_from(source_val), (VacantMut(self_free), Vacant(&source_free)) => *self_free = source_free, (_, Occupied(value)) => { self.u = SlotUnion { value: ManuallyDrop::new(value.clone()), } }, (_, Vacant(&free)) => self.u = SlotUnion { free }, } self.version = source.version; } } impl fmt::Debug for Slot { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("Slot"); builder.field("version", &self.version); match self.get() { Occupied(value) => builder.field("value", value).finish(), Vacant(free) => builder.field("free", free).finish(), } } } /// Hop slot map, storage with stable unique keys. /// /// See [crate documentation](crate) for more details. #[derive(Debug)] pub struct HopSlotMap { slots: Vec>, num_elems: u32, _k: PhantomData K>, } impl HopSlotMap { /// Constructs a new, empty [`HopSlotMap`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm: HopSlotMap<_, i32> = HopSlotMap::new(); /// ``` pub fn new() -> Self { Self::with_capacity_and_key(0) } /// Creates an empty [`HopSlotMap`] with the given capacity. /// /// The slot map will not reallocate until it holds at least `capacity` /// elements. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm: HopSlotMap<_, i32> = HopSlotMap::with_capacity(10); /// ``` pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_and_key(capacity) } } impl HopSlotMap { /// Constructs a new, empty [`HopSlotMap`] with a custom key type. /// /// # Examples /// /// ``` /// # use slotmap::*; /// new_key_type! { /// struct PositionKey; /// } /// let mut positions: HopSlotMap = HopSlotMap::with_key(); /// ``` pub fn with_key() -> Self { Self::with_capacity_and_key(0) } /// Creates an empty [`HopSlotMap`] with the given capacity and a custom key /// type. /// /// The slot map will not reallocate until it holds at least `capacity` /// elements. /// /// # Examples /// /// ``` /// # use slotmap::*; /// new_key_type! { /// struct MessageKey; /// } /// let mut messages = HopSlotMap::with_capacity_and_key(3); /// let welcome: MessageKey = messages.insert("Welcome"); /// let good_day = messages.insert("Good day"); /// let hello = messages.insert("Hello"); /// ``` pub fn with_capacity_and_key(capacity: usize) -> Self { // Create slots with sentinel at index 0. let mut slots = Vec::with_capacity(capacity + 1); slots.push(Slot { u: SlotUnion { free: FreeListEntry { next: 0, prev: 0, other_end: 0, }, }, version: 0, }); Self { slots, num_elems: 0, _k: PhantomData, } } /// Returns the number of elements in the slot map. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::with_capacity(10); /// sm.insert("len() counts actual elements, not capacity"); /// let key = sm.insert("removed elements don't count either"); /// sm.remove(key); /// assert_eq!(sm.len(), 1); /// ``` pub fn len(&self) -> usize { self.num_elems as usize } /// Returns if the slot map is empty. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let key = sm.insert("dummy"); /// assert_eq!(sm.is_empty(), false); /// sm.remove(key); /// assert_eq!(sm.is_empty(), true); /// ``` pub fn is_empty(&self) -> bool { self.num_elems == 0 } /// Returns the number of elements the [`HopSlotMap`] can hold without /// reallocating. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let sm: HopSlotMap<_, f64> = HopSlotMap::with_capacity(10); /// assert_eq!(sm.capacity(), 10); /// ``` pub fn capacity(&self) -> usize { // One slot is reserved for the freelist sentinel. self.slots.capacity() - 1 } /// Reserves capacity for at least `additional` more elements to be inserted /// in the [`HopSlotMap`]. The collection may reserve more space to /// avoid frequent reallocations. /// /// # Panics /// /// Panics if the new allocation size overflows [`usize`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// sm.insert("foo"); /// sm.reserve(32); /// assert!(sm.capacity() >= 33); /// ``` pub fn reserve(&mut self, additional: usize) { // One slot is reserved for the freelist sentinel. let needed = (self.len() + additional).saturating_sub(self.slots.len() - 1); self.slots.reserve(needed); } /// Tries to reserve capacity for at least `additional` more elements to be /// inserted in the [`HopSlotMap`]. The collection may reserve more space to /// avoid frequent reallocations. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// sm.insert("foo"); /// sm.try_reserve(32).unwrap(); /// assert!(sm.capacity() >= 33); /// ``` #[cfg(all(nightly, any(doc, feature = "unstable")))] #[cfg_attr(all(nightly, doc), doc(cfg(feature = "unstable")))] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { // One slot is reserved for the freelist sentinel. let needed = (self.len() + additional).saturating_sub(self.slots.len() - 1); self.slots.try_reserve(needed) } /// Returns [`true`] if the slot map contains `key`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let key = sm.insert(42); /// assert_eq!(sm.contains_key(key), true); /// sm.remove(key); /// assert_eq!(sm.contains_key(key), false); /// ``` pub fn contains_key(&self, key: K) -> bool { let kd = key.data(); self.slots .get(kd.idx as usize) .map_or(false, |slot| slot.version == kd.version.get()) } /// Inserts a value into the slot map. Returns a unique key that can be /// used to access this value. /// /// # Panics /// /// Panics if the number of elements in the slot map equals /// 232 - 2. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let key = sm.insert(42); /// assert_eq!(sm[key], 42); /// ``` #[inline(always)] pub fn insert(&mut self, value: V) -> K { unsafe { self.try_insert_with_key::<_, Never>(move |_| Ok(value)).unwrap_unchecked_() } } // Helper function to make using the freelist painless. // For that same ergonomy it uses u32, not usize as index. // Safe iff idx is a valid index and the slot at that index is vacant. unsafe fn freelist(&mut self, idx: u32) -> &mut FreeListEntry { &mut self.slots.get_unchecked_mut(idx as usize).u.free } /// Inserts a value given by `f` into the slot map. The key where the /// value will be stored is passed into `f`. This is useful to store values /// that contain their own key. /// /// # Panics /// /// Panics if the number of elements in the slot map equals /// 232 - 2. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let key = sm.insert_with_key(|k| (k, 20)); /// assert_eq!(sm[key], (key, 20)); /// ``` #[inline(always)] pub fn insert_with_key(&mut self, f: F) -> K where F: FnOnce(K) -> V, { unsafe { self.try_insert_with_key::<_, Never>(move |k| Ok(f(k))).unwrap_unchecked_() } } /// Inserts a value given by `f` into the slot map. The key where the /// value will be stored is passed into `f`. This is useful to store values /// that contain their own key. /// /// If `f` returns `Err`, this method returns the error. The slotmap is untouched. /// /// # Panics /// /// Panics if the number of elements in the slot map equals /// 232 - 2. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let key = sm.try_insert_with_key::<_, ()>(|k| Ok((k, 20))).unwrap(); /// assert_eq!(sm[key], (key, 20)); /// /// sm.try_insert_with_key::<_, ()>(|k| Err(())).unwrap_err(); /// ``` pub fn try_insert_with_key(&mut self, f: F) -> Result where F: FnOnce(K) -> Result, { // In case f panics, we don't make any changes until we have the value. let new_num_elems = self.num_elems + 1; if new_num_elems == core::u32::MAX { panic!("HopSlotMap number of elements overflow"); } // All unsafe accesses here are safe due to the invariants of the slot // map freelist. unsafe { let head = self.freelist(0).next; // We have a contiguous block of vacant slots starting at head. // Put our new element at the back slot. let front = head; let back = self.freelist(front).other_end; let slot_idx = back as usize; // Freelist is empty. if slot_idx == 0 { let version = 1; let key = KeyData::new(self.slots.len() as u32, version).into(); self.slots.push(Slot { u: SlotUnion { value: ManuallyDrop::new(f(key)?), }, version, }); self.num_elems = new_num_elems; return Ok(key); } // Compute value first in case f panics or returns an error. let occupied_version = self.slots[slot_idx].version | 1; let key = KeyData::new(slot_idx as u32, occupied_version).into(); let value = f(key)?; // Update freelist. if front == back { // Used last slot in this block, move next one to head. let new_head = self.freelist(front).next; self.freelist(0).next = new_head; self.freelist(new_head).prev = 0; } else { // Continue using this block, only need to update other_ends. let new_back = back - 1; self.freelist(new_back).other_end = front; self.freelist(front).other_end = new_back; } // And finally insert the value. let slot = &mut self.slots[slot_idx]; slot.version = occupied_version; slot.u.value = ManuallyDrop::new(value); self.num_elems = new_num_elems; Ok(key) } } // Helper function to remove a value from a slot. Safe iff the slot is // occupied. Returns the value removed. #[inline(always)] unsafe fn remove_from_slot(&mut self, idx: usize) -> V { // Remove value from slot. let slot = self.slots.get_unchecked_mut(idx); slot.version = slot.version.wrapping_add(1); let value = ManuallyDrop::take(&mut slot.u.value); // This is safe and can't underflow because of the sentinel element at // the start. let left_vacant = !self.slots.get_unchecked(idx - 1).occupied(); let right_vacant = self.slots.get(idx + 1).map_or(false, |s| !s.occupied()); // Maintain freelist by either appending/prepending this slot to a // contiguous block to the left or right, merging the two blocks to the // left and right or inserting a new block. let i = idx as u32; match (left_vacant, right_vacant) { (false, false) => { // New block, insert it at the tail. let old_tail = self.freelist(0).prev; self.freelist(0).prev = i; self.freelist(old_tail).next = i; *self.freelist(i) = FreeListEntry { other_end: i, next: 0, prev: old_tail, }; }, (false, true) => { // Prepend to vacant block on right. let front_data = *self.freelist(i + 1); // Since the start of this block moved we must update the pointers to it. self.freelist(front_data.other_end).other_end = i; self.freelist(front_data.prev).next = i; self.freelist(front_data.next).prev = i; *self.freelist(i) = front_data; }, (true, false) => { // Append to vacant block on left. let front = self.freelist(i - 1).other_end; self.freelist(i).other_end = front; self.freelist(front).other_end = i; }, (true, true) => { // We must merge left and right. // First snip right out of the freelist. let right = *self.freelist(i + 1); self.freelist(right.prev).next = right.next; self.freelist(right.next).prev = right.prev; // Now update endpoints. let front = self.freelist(i - 1).other_end; let back = right.other_end; self.freelist(front).other_end = back; self.freelist(back).other_end = front; }, } self.num_elems -= 1; value } /// Removes a key from the slot map, returning the value at the key if the /// key was not previously removed. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let key = sm.insert(42); /// assert_eq!(sm.remove(key), Some(42)); /// assert_eq!(sm.remove(key), None); /// ``` pub fn remove(&mut self, key: K) -> Option { let kd = key.data(); if self.contains_key(key) { // This is safe because we know that the slot is occupied. Some(unsafe { self.remove_from_slot(kd.idx as usize) }) } else { None } } /// Retains only the elements specified by the predicate. /// /// In other words, remove all key-value pairs `(k, v)` such that /// `f(k, &mut v)` returns false. This method invalidates any removed keys. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// /// let k1 = sm.insert(0); /// let k2 = sm.insert(1); /// let k3 = sm.insert(2); /// /// sm.retain(|key, val| key == k1 || *val == 1); /// /// assert!(sm.contains_key(k1)); /// assert!(sm.contains_key(k2)); /// assert!(!sm.contains_key(k3)); /// /// assert_eq!(2, sm.len()); /// ``` pub fn retain(&mut self, mut f: F) where F: FnMut(K, &mut V) -> bool, { let mut elems_left_to_scan = self.len(); let mut cur = unsafe { self.slots.get_unchecked(0).u.free.other_end as usize + 1 }; while elems_left_to_scan > 0 { // This is safe because removing elements does not shrink slots, cur always // points to an occupied slot. let idx = cur; let slot = unsafe { self.slots.get_unchecked_mut(cur) }; let version = slot.version; let key = KeyData::new(cur as u32, version).into(); let should_remove = !f(key, unsafe { &mut *slot.u.value }); cur = match self.slots.get(cur + 1).map(|s| s.get()) { Some(Occupied(_)) => cur + 1, Some(Vacant(free)) => free.other_end as usize + 1, None => 0, }; if should_remove { // This must happen after getting the next index. unsafe { self.remove_from_slot(idx) }; } elems_left_to_scan -= 1; } } /// Clears the slot map. Keeps the allocated memory for reuse. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// for i in 0..10 { /// sm.insert(i); /// } /// assert_eq!(sm.len(), 10); /// sm.clear(); /// assert_eq!(sm.len(), 0); /// ``` pub fn clear(&mut self) { self.drain(); } /// Clears the slot map, returning all key-value pairs in arbitrary order as /// an iterator. Keeps the allocated memory for reuse. /// /// When the iterator is dropped all elements in the slot map are removed, /// even if the iterator was not fully consumed. If the iterator is not /// dropped (using e.g. [`std::mem::forget`]), only the elements that were /// iterated over are removed. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let k = sm.insert(0); /// let v: Vec<_> = sm.drain().collect(); /// assert_eq!(sm.len(), 0); /// assert_eq!(v, vec![(k, 0)]); /// ``` pub fn drain(&mut self) -> Drain { Drain { cur: unsafe { self.slots.get_unchecked(0).u.free.other_end as usize + 1 }, sm: self, } } /// Returns a reference to the value corresponding to the key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let key = sm.insert("bar"); /// assert_eq!(sm.get(key), Some(&"bar")); /// sm.remove(key); /// assert_eq!(sm.get(key), None); /// ``` pub fn get(&self, key: K) -> Option<&V> { let kd = key.data(); // This is safe because we check version first and a key always contains // an odd version, thus we are occupied. self.slots .get(kd.idx as usize) .filter(|slot| slot.version == kd.version.get()) .map(|slot| unsafe { &*slot.u.value }) } /// Returns a reference to the value corresponding to the key without /// version or bounds checking. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true. Otherwise it is /// dangerous undefined behavior. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let key = sm.insert("bar"); /// assert_eq!(unsafe { sm.get_unchecked(key) }, &"bar"); /// sm.remove(key); /// // sm.get_unchecked(key) is now dangerous! /// ``` pub unsafe fn get_unchecked(&self, key: K) -> &V { debug_assert!(self.contains_key(key)); &self.slots.get_unchecked(key.data().idx as usize).u.value } /// Returns a mutable reference to the value corresponding to the key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let key = sm.insert(3.5); /// if let Some(x) = sm.get_mut(key) { /// *x += 3.0; /// } /// assert_eq!(sm[key], 6.5); /// ``` pub fn get_mut(&mut self, key: K) -> Option<&mut V> { let kd = key.data(); // This is safe because we check version first and a key always contains // an odd version, thus we are occupied. self.slots .get_mut(kd.idx as usize) .filter(|slot| slot.version == kd.version.get()) .map(|slot| unsafe { &mut *slot.u.value }) } /// Returns a mutable reference to the value corresponding to the key /// without version or bounds checking. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true. Otherwise it is /// dangerous undefined behavior. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let key = sm.insert("foo"); /// unsafe { *sm.get_unchecked_mut(key) = "bar" }; /// assert_eq!(sm[key], "bar"); /// sm.remove(key); /// // sm.get_unchecked_mut(key) is now dangerous! /// ``` pub unsafe fn get_unchecked_mut(&mut self, key: K) -> &mut V { debug_assert!(self.contains_key(key)); &mut self.slots.get_unchecked_mut(key.data().idx as usize).u.value } /// Returns mutable references to the values corresponding to the given /// keys. All keys must be valid and disjoint, otherwise [`None`] is /// returned. /// /// Requires at least stable Rust version 1.51. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let ka = sm.insert("butter"); /// let kb = sm.insert("apples"); /// let kc = sm.insert("charlie"); /// sm.remove(kc); // Make key c invalid. /// assert_eq!(sm.get_disjoint_mut([ka, kb, kc]), None); // Has invalid key. /// assert_eq!(sm.get_disjoint_mut([ka, ka]), None); // Not disjoint. /// let [a, b] = sm.get_disjoint_mut([ka, kb]).unwrap(); /// std::mem::swap(a, b); /// assert_eq!(sm[ka], "apples"); /// assert_eq!(sm[kb], "butter"); /// ``` #[cfg(has_min_const_generics)] pub fn get_disjoint_mut(&mut self, keys: [K; N]) -> Option<[&mut V; N]> { // Create an uninitialized array of `MaybeUninit`. The `assume_init` is // safe because the type we are claiming to have initialized here is a // bunch of `MaybeUninit`s, which do not require initialization. let mut ptrs: [MaybeUninit<*mut V>; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut i = 0; while i < N { // We can avoid this clone after min_const_generics and array_map. let kd = keys[i].data(); if !self.contains_key(kd.into()) { break; } // This key is valid, and thus the slot is occupied. Temporarily // mark it as unoccupied so duplicate keys would show up as invalid. // This gives us a linear time disjointness check. unsafe { let slot = self.slots.get_unchecked_mut(kd.idx as usize); slot.version ^= 1; ptrs[i] = MaybeUninit::new(&mut *slot.u.value); } i += 1; } // Undo temporary unoccupied markings. for k in &keys[..i] { let idx = k.data().idx as usize; unsafe { self.slots.get_unchecked_mut(idx).version ^= 1; } } if i == N { // All were valid and disjoint. Some(unsafe { core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs) }) } else { None } } /// Returns mutable references to the values corresponding to the given /// keys. All keys must be valid and disjoint. /// /// Requires at least stable Rust version 1.51. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true for every given /// key and no two keys are equal. Otherwise it is potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let ka = sm.insert("butter"); /// let kb = sm.insert("apples"); /// let [a, b] = unsafe { sm.get_disjoint_unchecked_mut([ka, kb]) }; /// std::mem::swap(a, b); /// assert_eq!(sm[ka], "apples"); /// assert_eq!(sm[kb], "butter"); /// ``` #[cfg(has_min_const_generics)] pub unsafe fn get_disjoint_unchecked_mut( &mut self, keys: [K; N], ) -> [&mut V; N] { // Safe, see get_disjoint_mut. let mut ptrs: [MaybeUninit<*mut V>; N] = MaybeUninit::uninit().assume_init(); for i in 0..N { ptrs[i] = MaybeUninit::new(self.get_unchecked_mut(keys[i])); } core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs) } /// An iterator visiting all key-value pairs in arbitrary order. The /// iterator element type is `(K, &'a V)`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let k0 = sm.insert(0); /// let k1 = sm.insert(1); /// let k2 = sm.insert(2); /// /// for (k, v) in sm.iter() { /// println!("key: {:?}, val: {}", k, v); /// } /// ``` pub fn iter(&self) -> Iter { Iter { cur: unsafe { self.slots.get_unchecked(0).u.free.other_end as usize + 1 }, num_left: self.len(), slots: &self.slots[..], _k: PhantomData, } } /// An iterator visiting all key-value pairs in arbitrary order, with /// mutable references to the values. The iterator element type is /// `(K, &'a mut V)`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = HopSlotMap::new(); /// let k0 = sm.insert(10); /// let k1 = sm.insert(20); /// let k2 = sm.insert(30); /// /// for (k, v) in sm.iter_mut() { /// if k != k1 { /// *v *= -1; /// } /// } /// /// assert_eq!(sm[k0], -10); /// assert_eq!(sm[k1], 20); /// assert_eq!(sm[k2], -30); /// ``` pub fn iter_mut(&mut self) -> IterMut { IterMut { cur: 0, num_left: self.len(), slots: &mut self.slots[..], _k: PhantomData, } } /// An iterator visiting all keys in arbitrary order. The iterator element /// type is `K`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = HopSlotMap::new(); /// let k0 = sm.insert(10); /// let k1 = sm.insert(20); /// let k2 = sm.insert(30); /// let keys: HashSet<_> = sm.keys().collect(); /// let check: HashSet<_> = vec![k0, k1, k2].into_iter().collect(); /// assert_eq!(keys, check); /// ``` pub fn keys(&self) -> Keys { Keys { inner: self.iter() } } /// An iterator visiting all values in arbitrary order. The iterator element /// type is `&'a V`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = HopSlotMap::new(); /// let k0 = sm.insert(10); /// let k1 = sm.insert(20); /// let k2 = sm.insert(30); /// let values: HashSet<_> = sm.values().collect(); /// let check: HashSet<_> = vec![&10, &20, &30].into_iter().collect(); /// assert_eq!(values, check); /// ``` pub fn values(&self) -> Values { Values { inner: self.iter() } } /// An iterator visiting all values mutably in arbitrary order. The iterator /// element type is `&'a mut V`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = HopSlotMap::new(); /// sm.insert(1); /// sm.insert(2); /// sm.insert(3); /// sm.values_mut().for_each(|n| { *n *= 3 }); /// let values: HashSet<_> = sm.into_iter().map(|(_k, v)| v).collect(); /// let check: HashSet<_> = vec![3, 6, 9].into_iter().collect(); /// assert_eq!(values, check); /// ``` pub fn values_mut(&mut self) -> ValuesMut { ValuesMut { inner: self.iter_mut(), } } } impl Clone for HopSlotMap where V: Clone, { fn clone(&self) -> Self { Self { slots: self.slots.clone(), ..*self } } fn clone_from(&mut self, source: &Self) { self.slots.clone_from(&source.slots); self.num_elems = source.num_elems; } } impl Default for HopSlotMap { fn default() -> Self { Self::with_key() } } impl Index for HopSlotMap { type Output = V; fn index(&self, key: K) -> &V { match self.get(key) { Some(r) => r, None => panic!("invalid HopSlotMap key used"), } } } impl IndexMut for HopSlotMap { fn index_mut(&mut self, key: K) -> &mut V { match self.get_mut(key) { Some(r) => r, None => panic!("invalid HopSlotMap key used"), } } } // Iterators. /// A draining iterator for [`HopSlotMap`]. /// /// This iterator is created by [`HopSlotMap::drain`]. #[derive(Debug)] pub struct Drain<'a, K: Key + 'a, V: 'a> { cur: usize, sm: &'a mut HopSlotMap, } /// An iterator that moves key-value pairs out of a [`HopSlotMap`]. /// /// This iterator is created by calling the `into_iter` method on [`HopSlotMap`], /// provided by the [`IntoIterator`] trait. #[derive(Debug, Clone)] pub struct IntoIter { cur: usize, num_left: usize, slots: Vec>, _k: PhantomData K>, } /// An iterator over the key-value pairs in a [`HopSlotMap`]. /// /// This iterator is created by [`HopSlotMap::iter`]. #[derive(Debug)] pub struct Iter<'a, K: Key + 'a, V: 'a> { cur: usize, num_left: usize, slots: &'a [Slot], _k: PhantomData K>, } impl<'a, K: 'a + Key, V: 'a> Clone for Iter<'a, K, V> { fn clone(&self) -> Self { Iter { cur: self.cur, num_left: self.num_left, slots: self.slots, _k: self._k.clone(), } } } /// A mutable iterator over the key-value pairs in a [`HopSlotMap`]. /// /// This iterator is created by [`HopSlotMap::iter_mut`]. #[derive(Debug)] pub struct IterMut<'a, K: Key + 'a, V: 'a> { cur: usize, num_left: usize, slots: &'a mut [Slot], _k: PhantomData K>, } /// An iterator over the keys in a [`HopSlotMap`]. /// /// This iterator is created by [`HopSlotMap::keys`]. #[derive(Debug)] pub struct Keys<'a, K: Key + 'a, V: 'a> { inner: Iter<'a, K, V>, } impl<'a, K: 'a + Key, V: 'a> Clone for Keys<'a, K, V> { fn clone(&self) -> Self { Keys { inner: self.inner.clone(), } } } /// An iterator over the values in a [`HopSlotMap`]. /// /// This iterator is created by [`HopSlotMap::values`]. #[derive(Debug)] pub struct Values<'a, K: Key + 'a, V: 'a> { inner: Iter<'a, K, V>, } impl<'a, K: 'a + Key, V: 'a> Clone for Values<'a, K, V> { fn clone(&self) -> Self { Values { inner: self.inner.clone(), } } } /// A mutable iterator over the values in a [`HopSlotMap`]. /// /// This iterator is created by [`HopSlotMap::values_mut`]. #[derive(Debug)] pub struct ValuesMut<'a, K: Key + 'a, V: 'a> { inner: IterMut<'a, K, V>, } impl<'a, K: Key, V> Iterator for Drain<'a, K, V> { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { // All unchecked indices are safe due to the invariants of the freelist // and that self.sm.len() guarantees there is another element. if self.sm.len() == 0 { return None; } // Skip ahead to next element. Must do this before removing. let idx = self.cur; self.cur = match self.sm.slots.get(idx + 1).map(|s| s.get()) { Some(Occupied(_)) => idx + 1, Some(Vacant(free)) => free.other_end as usize + 1, None => 0, }; let key = KeyData::new(idx as u32, unsafe { self.sm.slots.get_unchecked(idx).version }); Some((key.into(), unsafe { self.sm.remove_from_slot(idx) })) } fn size_hint(&self) -> (usize, Option) { (self.sm.len(), Some(self.sm.len())) } } impl<'a, K: Key, V> Drop for Drain<'a, K, V> { fn drop(&mut self) { self.for_each(|_drop| {}); } } impl Iterator for IntoIter { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { if self.cur >= self.slots.len() { return None; } let idx = match self.slots[self.cur].get() { Occupied(_) => self.cur, Vacant(free) => { // Skip block of contiguous vacant slots. let idx = free.other_end as usize + 1; if idx >= self.slots.len() { return None; } idx }, }; self.cur = idx + 1; self.num_left -= 1; let slot = &mut self.slots[idx]; let key = KeyData::new(idx as u32, slot.version).into(); slot.version = 0; // Prevent dropping after extracting the value. Some((key, unsafe { ManuallyDrop::take(&mut slot.u.value) })) } fn size_hint(&self) -> (usize, Option) { (self.num_left, Some(self.num_left)) } } impl<'a, K: Key, V> Iterator for Iter<'a, K, V> { type Item = (K, &'a V); fn next(&mut self) -> Option<(K, &'a V)> { // All unchecked indices are safe due to the invariants of the freelist // and that num_left guarantees there is another element. if self.num_left == 0 { return None; } self.num_left -= 1; let idx = match unsafe { self.slots.get_unchecked(self.cur).get() } { Occupied(_) => self.cur, Vacant(free) => free.other_end as usize + 1, }; self.cur = idx + 1; let slot = unsafe { self.slots.get_unchecked(idx) }; let key = KeyData::new(idx as u32, slot.version).into(); Some((key, unsafe { &*slot.u.value })) } fn size_hint(&self) -> (usize, Option) { (self.num_left, Some(self.num_left)) } } impl<'a, K: Key, V> Iterator for IterMut<'a, K, V> { type Item = (K, &'a mut V); fn next(&mut self) -> Option<(K, &'a mut V)> { if self.cur >= self.slots.len() { return None; } let idx = match self.slots[self.cur].get() { Occupied(_) => self.cur, Vacant(free) => { // Skip block of contiguous vacant slots. let idx = free.other_end as usize + 1; if idx >= self.slots.len() { return None; } idx }, }; self.cur = idx + 1; self.num_left -= 1; // Unsafe necessary because Rust can't deduce that we won't // return multiple references to the same value. let slot = &mut self.slots[idx]; let version = slot.version; let value_ref = unsafe { let ptr: *mut V = &mut *slot.u.value; &mut *ptr }; Some((KeyData::new(idx as u32, version).into(), value_ref)) } fn size_hint(&self) -> (usize, Option) { (self.num_left, Some(self.num_left)) } } impl<'a, K: Key, V> Iterator for Keys<'a, K, V> { type Item = K; fn next(&mut self) -> Option { self.inner.next().map(|(key, _)| key) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Iterator for Values<'a, K, V> { type Item = &'a V; fn next(&mut self) -> Option<&'a V> { self.inner.next().map(|(_, value)| value) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; fn next(&mut self) -> Option<&'a mut V> { self.inner.next().map(|(_, value)| value) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> IntoIterator for &'a HopSlotMap { type Item = (K, &'a V); type IntoIter = Iter<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, K: Key, V> IntoIterator for &'a mut HopSlotMap { type Item = (K, &'a mut V); type IntoIter = IterMut<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl IntoIterator for HopSlotMap { type Item = (K, V); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { cur: 0, num_left: self.len(), slots: self.slots, _k: PhantomData, } } } impl<'a, K: Key, V> FusedIterator for Iter<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for IterMut<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Keys<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Values<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for ValuesMut<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Drain<'a, K, V> {} impl FusedIterator for IntoIter {} impl<'a, K: Key, V> ExactSizeIterator for Iter<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for IterMut<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Keys<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Values<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for ValuesMut<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Drain<'a, K, V> {} impl ExactSizeIterator for IntoIter {} // Serialization with serde. #[cfg(feature = "serde")] mod serialize { use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use super::*; #[derive(Serialize, Deserialize)] struct SerdeSlot { value: Option, version: u32, } impl Serialize for Slot { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let serde_slot = SerdeSlot { version: self.version, value: match self.get() { Occupied(value) => Some(value), Vacant(_) => None, }, }; serde_slot.serialize(serializer) } } impl<'de, T> Deserialize<'de> for Slot where T: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let serde_slot: SerdeSlot = Deserialize::deserialize(deserializer)?; let occupied = serde_slot.version % 2 == 1; if occupied ^ serde_slot.value.is_some() { return Err(de::Error::custom(&"inconsistent occupation in Slot")); } Ok(Self { u: match serde_slot.value { Some(value) => SlotUnion { value: ManuallyDrop::new(value), }, None => SlotUnion { free: FreeListEntry { next: 0, prev: 0, other_end: 0, }, }, }, version: serde_slot.version, }) } } impl Serialize for HopSlotMap { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.slots.serialize(serializer) } } impl<'de, K: Key, V: Deserialize<'de>> Deserialize<'de> for HopSlotMap { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let mut slots: Vec> = Deserialize::deserialize(deserializer)?; if slots.len() >= u32::max_value() as usize { return Err(de::Error::custom(&"too many slots")); } // Ensure the first slot exists and is empty for the sentinel. if slots.get(0).map_or(true, |slot| slot.version % 2 == 1) { return Err(de::Error::custom(&"first slot not empty")); } slots[0].u.free = FreeListEntry { next: 0, prev: 0, other_end: 0, }; // We have our slots, rebuild freelist. let mut num_elems = 0; let mut prev = 0; let mut i = 0; while i < slots.len() { // i is the start of a contiguous block of vacant slots. let front = i; while i < slots.len() && !slots[i].occupied() { i += 1; } let back = i - 1; // Update freelist. unsafe { slots[back].u.free.other_end = front as u32; slots[prev].u.free.next = front as u32; slots[front].u.free = FreeListEntry { next: 0, prev: prev as u32, other_end: back as u32, }; } prev = front; // Skip occupied slots. while i < slots.len() && slots[i].occupied() { num_elems += 1; i += 1; } } Ok(Self { num_elems, slots, _k: PhantomData, }) } } } #[cfg(test)] mod tests { use std::collections::{HashMap, HashSet}; use quickcheck::quickcheck; use super::*; #[derive(Clone)] struct CountDrop<'a>(&'a std::cell::RefCell); impl<'a> Drop for CountDrop<'a> { fn drop(&mut self) { *self.0.borrow_mut() += 1; } } #[cfg(all(nightly, feature = "unstable"))] #[test] fn check_drops() { let drops = std::cell::RefCell::new(0usize); { let mut clone = { // Insert 1000 items. let mut sm = HopSlotMap::new(); let mut sm_keys = Vec::new(); for _ in 0..1000 { sm_keys.push(sm.insert(CountDrop(&drops))); } // Remove even keys. for i in (0..1000).filter(|i| i % 2 == 0) { sm.remove(sm_keys[i]); } // Should only have dropped 500 so far. assert_eq!(*drops.borrow(), 500); // Let's clone ourselves and then die. sm.clone() }; // Now all original items should have been dropped exactly once. assert_eq!(*drops.borrow(), 1000); // Reuse some empty slots. for _ in 0..250 { clone.insert(CountDrop(&drops)); } } // 1000 + 750 drops in total should have happened. assert_eq!(*drops.borrow(), 1750); } #[cfg(all(nightly, feature = "unstable"))] #[test] fn disjoint() { // Intended to be run with miri to find any potential UB. let mut sm = HopSlotMap::new(); // Some churn. for i in 0..20usize { sm.insert(i); } sm.retain(|_, i| *i % 2 == 0); let keys: Vec<_> = sm.keys().collect(); for i in 0..keys.len() { for j in 0..keys.len() { if let Some([r0, r1]) = sm.get_disjoint_mut([keys[i], keys[j]]) { *r0 ^= *r1; *r1 = r1.wrapping_add(*r0); } else { assert!(i == j); } } } for i in 0..keys.len() { for j in 0..keys.len() { for k in 0..keys.len() { if let Some([r0, r1, r2]) = sm.get_disjoint_mut([keys[i], keys[j], keys[k]]) { *r0 ^= *r1; *r0 = r0.wrapping_add(*r2); *r1 ^= *r0; *r1 = r1.wrapping_add(*r2); *r2 ^= *r0; *r2 = r2.wrapping_add(*r1); } else { assert!(i == j || j == k || i == k); } } } } } quickcheck! { fn qc_slotmap_equiv_hashmap(operations: Vec<(u8, u32)>) -> bool { let mut hm = HashMap::new(); let mut hm_keys = Vec::new(); let mut unique_key = 0u32; let mut sm = HopSlotMap::new(); let mut sm_keys = Vec::new(); #[cfg(not(feature = "serde"))] let num_ops = 3; #[cfg(feature = "serde")] let num_ops = 4; for (op, val) in operations { match op % num_ops { // Insert. 0 => { hm.insert(unique_key, val); hm_keys.push(unique_key); unique_key += 1; sm_keys.push(sm.insert(val)); } // Delete. 1 => { // 10% of the time test clear. if val % 10 == 0 { let hmvals: HashSet<_> = hm.drain().map(|(_, v)| v).collect(); let smvals: HashSet<_> = sm.drain().map(|(_, v)| v).collect(); if hmvals != smvals { return false; } } if hm_keys.is_empty() { continue; } let idx = val as usize % hm_keys.len(); if hm.remove(&hm_keys[idx]) != sm.remove(sm_keys[idx]) { return false; } } // Access. 2 => { if hm_keys.is_empty() { continue; } let idx = val as usize % hm_keys.len(); let (hm_key, sm_key) = (&hm_keys[idx], sm_keys[idx]); if hm.contains_key(hm_key) != sm.contains_key(sm_key) || hm.get(hm_key) != sm.get(sm_key) { return false; } } // Serde round-trip. #[cfg(feature = "serde")] 3 => { let ser = serde_json::to_string(&sm).unwrap(); sm = serde_json::from_str(&ser).unwrap(); } _ => unreachable!(), } } let mut smv: Vec<_> = sm.values().collect(); let mut hmv: Vec<_> = hm.values().collect(); smv.sort(); hmv.sort(); smv == hmv } } #[cfg(feature = "serde")] #[test] fn slotmap_serde() { let mut sm = HopSlotMap::new(); // Self-referential structure. let first = sm.insert_with_key(|k| (k, 23i32)); let second = sm.insert((first, 42)); // Make some empty slots. let empties = vec![sm.insert((first, 0)), sm.insert((first, 0))]; empties.iter().for_each(|k| { sm.remove(*k); }); let third = sm.insert((second, 0)); sm[first].0 = third; let ser = serde_json::to_string(&sm).unwrap(); let de: HopSlotMap = serde_json::from_str(&ser).unwrap(); assert_eq!(de.len(), sm.len()); let mut smkv: Vec<_> = sm.iter().collect(); let mut dekv: Vec<_> = de.iter().collect(); smkv.sort(); dekv.sort(); assert_eq!(smkv, dekv); } #[cfg(feature = "serde")] #[test] fn slotmap_serde_freelist() { let mut sm = HopSlotMap::new(); let k = sm.insert(5i32); sm.remove(k); let ser = serde_json::to_string(&sm).unwrap(); let mut de: HopSlotMap = serde_json::from_str(&ser).unwrap(); de.insert(0); de.insert(1); de.insert(2); assert_eq!(de.len(), 3); } } slotmap-1.0.7/src/lib.rs000064400000000000000000000552410072674642500132520ustar 00000000000000#![doc(html_root_url = "https://docs.rs/slotmap/1.0.7")] #![crate_name = "slotmap"] #![cfg_attr(all(nightly, feature = "unstable"), feature(try_reserve))] #![cfg_attr(all(not(test), not(feature = "std")), no_std)] #![cfg_attr(all(nightly, doc), feature(doc_cfg))] #![warn( missing_debug_implementations, trivial_casts, trivial_numeric_casts, unused_lifetimes, unused_import_braces )] #![deny(missing_docs, unaligned_references)] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] #![cfg_attr( feature = "cargo-clippy", allow( // Style differences. module_name_repetitions, redundant_closure_for_method_calls, unseparated_literal_suffix, // I know what I'm doing and want these. wildcard_imports, inline_always, cast_possible_truncation, needless_pass_by_value, // Very noisy. missing_errors_doc, must_use_candidate ))] //! # slotmap //! //! This library provides a container with persistent unique keys to access //! stored values, [`SlotMap`]. Upon insertion a key is returned that can be //! used to later access or remove the values. Insertion, removal and access all //! take O(1) time with low overhead. Great for storing collections of objects //! that need stable, safe references but have no clear ownership otherwise, //! such as game entities or graph nodes. //! //! The difference between a [`BTreeMap`] or [`HashMap`] and a slot map is //! that the slot map generates and returns the key when inserting a value. A //! key is always unique and will only refer to the value that was inserted. //! A slot map's main purpose is to simply own things in a safe and efficient //! manner. //! //! You can also create (multiple) secondary maps that can map the keys returned //! by [`SlotMap`] to other values, to associate arbitrary data with objects //! stored in slot maps, without hashing required - it's direct indexing under //! the hood. //! //! The minimum required stable Rust version for this crate is 1.49. //! //! # Examples //! //! ``` //! # use slotmap::*; //! let mut sm = SlotMap::new(); //! let foo = sm.insert("foo"); // Key generated on insert. //! let bar = sm.insert("bar"); //! assert_eq!(sm[foo], "foo"); //! assert_eq!(sm[bar], "bar"); //! //! sm.remove(bar); //! let reuse = sm.insert("reuse"); // Space from bar reused. //! assert_eq!(sm.contains_key(bar), false); // After deletion a key stays invalid. //! //! let mut sec = SecondaryMap::new(); //! sec.insert(foo, "noun"); // We provide the key for secondary maps. //! sec.insert(reuse, "verb"); //! //! for (key, val) in sm { //! println!("{} is a {}", val, sec[key]); //! } //! ``` //! //! # Serialization through [`serde`], [`no_std`] support and unstable features //! //! Both keys and the slot maps have full (de)seralization support through //! the [`serde`] library. A key remains valid for a slot map even after one or //! both have been serialized and deserialized! This makes storing or //! transferring complicated referential structures and graphs a breeze. Care has //! been taken such that deserializing keys and slot maps from untrusted sources //! is safe. If you wish to use these features you must enable the `serde` //! feature flag for `slotmap` in your `Cargo.toml`. //! //! ```text //! slotmap = { version = "1.0", features = ["serde"] } //! ``` //! //! This crate also supports [`no_std`] environments, but does require the //! [`alloc`] crate to be available. To enable this you have to disable the //! `std` feature that is enabled by default: //! //! ```text //! slotmap = { version = "1.0", default-features = false } //! ``` //! //! Unfortunately [`SparseSecondaryMap`] is not available in [`no_std`], because //! it relies on [`HashMap`]. Finally the `unstable` feature can be defined to //! enable the parts of `slotmap` that only work on nightly Rust. //! //! # Why not index a [`Vec`], or use [`slab`], [`stable-vec`], etc? //! //! Those solutions either can not reclaim memory from deleted elements or //! suffer from the ABA problem. The keys returned by `slotmap` are versioned. //! This means that once a key is removed, it stays removed, even if the //! physical storage inside the slotmap is reused for new elements. The key is a //! permanently unique* reference to the inserted value. Despite //! supporting versioning, a [`SlotMap`] is often not (much) slower than the //! alternative, by internally using carefully checked unsafe code. Finally, //! `slotmap` simply has a lot of features that make your life easy. //! //! # Performance characteristics and implementation details //! //! Insertion, access and deletion is all O(1) with low overhead by storing the //! elements inside a [`Vec`]. Unlike references or indices into a vector, //! unless you remove a key it is never invalidated. Behind the scenes each //! slot in the vector is a `(value, version)` tuple. After insertion the //! returned key also contains a version. Only when the stored version and //! version in a key match is a key valid. This allows us to reuse space in the //! vector after deletion without letting removed keys point to spurious new //! elements. *After 231 deletions and insertions to the //! same underlying slot the version wraps around and such a spurious reference //! could potentially occur. It is incredibly unlikely however, and in all //! circumstances is the behavior safe. A slot map can hold up to //! 232 - 2 elements at a time. //! //! The memory usage for each slot in [`SlotMap`] is `4 + max(sizeof(T), 4)` //! rounded up to the alignment of `T`. Similarly it is `4 + max(sizeof(T), 12)` //! for [`HopSlotMap`]. [`DenseSlotMap`] has an overhead of 8 bytes per element //! and 8 bytes per slot. //! //! # Choosing [`SlotMap`], [`HopSlotMap`] or [`DenseSlotMap`] //! //! A [`SlotMap`] is the fastest for most operations, except iteration. It can //! never shrink the size of its underlying storage, because it must remember //! for each storage slot what the latest stored version was, even if the slot //! is empty now. This means that iteration can be slow as it must iterate over //! potentially a lot of empty slots. //! //! [`HopSlotMap`] solves this by maintaining more information on //! insertion/removal, allowing it to iterate only over filled slots by 'hopping //! over' contiguous blocks of vacant slots. This can give it significantly //! better iteration speed. If you expect to iterate over all elements in a //! [`SlotMap`] a lot, and potentially have a lot of deleted elements, choose //! [`HopSlotMap`]. The downside is that insertion and removal is roughly twice //! as slow. Random access is the same speed for both. //! //! [`DenseSlotMap`] goes even further and stores all elements on a contiguous //! block of memory. It uses two indirections per random access; the slots //! contain indices used to access the contiguous memory. This means random //! access is slower than both [`SlotMap`] and [`HopSlotMap`], but iteration is //! significantly faster, as fast as a normal [`Vec`]. //! //! # Choosing [`SecondaryMap`] or [`SparseSecondaryMap`] //! //! You want to associate extra data with objects stored in a slot map, so you //! use (multiple) secondary maps to map keys to that data. //! //! A [`SecondaryMap`] is simply a [`Vec`] of slots like slot map is, and //! essentially provides all the same guarantees as [`SlotMap`] does for its //! operations (with the exception that you provide the keys as produced by the //! primary slot map). This does mean that even if you associate data to only //! a single element from the primary slot map, you could need and have to //! initialize as much memory as the original. //! //! A [`SparseSecondaryMap`] is like a [`HashMap`] from keys to objects, however //! it automatically removes outdated keys for slots that had their space //! reused. You should use this variant if you expect to store some associated //! data for only a small portion of the primary slot map. //! //! # Custom key types //! //! If you have multiple slot maps it's an error to use the key of one slot map //! on another slot map. The result is safe, but unspecified, and can not be //! detected at runtime, so it can lead to a hard to find bug. //! //! To prevent this, slot maps allow you to specify what the type is of the key //! they return. You can construct new key types using the [`new_key_type!`] //! macro. The resulting type behaves exactly like [`DefaultKey`], but is a //! distinct type. So instead of simply using `SlotMap` you //! would use: //! //! ``` //! # use slotmap::*; //! # #[derive(Copy, Clone)] //! # struct Player; //! new_key_type! { struct PlayerKey; } //! let sm: SlotMap = SlotMap::with_key(); //! ``` //! //! You can write code generic over any key type using the [`Key`] trait. //! //! [`Vec`]: std::vec::Vec //! [`BTreeMap`]: std::collections::BTreeMap //! [`HashMap`]: std::collections::HashMap //! [`serde`]: https://github.com/serde-rs/serde //! [`slab`]: https://crates.io/crates/slab //! [`stable-vec`]: https://crates.io/crates/stable-vec //! [`no_std`]: https://doc.rust-lang.org/1.7.0/book/no-stdlib.html extern crate alloc; // So our macros can refer to these. #[doc(hidden)] pub mod __impl { #[cfg(feature = "serde")] pub use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub use core::convert::From; pub use core::result::Result; } pub mod basic; pub mod dense; pub mod hop; pub mod secondary; #[cfg(feature = "std")] pub mod sparse_secondary; pub(crate) mod util; use core::fmt::{self, Debug, Formatter}; use core::hash::{Hash, Hasher}; use core::num::NonZeroU32; #[doc(inline)] pub use crate::basic::SlotMap; #[doc(inline)] pub use crate::dense::DenseSlotMap; #[doc(inline)] pub use crate::hop::HopSlotMap; #[doc(inline)] pub use crate::secondary::SecondaryMap; #[cfg(feature = "std")] #[doc(inline)] pub use crate::sparse_secondary::SparseSecondaryMap; // Keep Slottable for backwards compatibility, but warn about deprecation // and hide from documentation. #[doc(hidden)] #[deprecated( since = "1.0.0", note = "Slottable is not necessary anymore, slotmap now supports all types on stable." )] pub trait Slottable {} #[doc(hidden)] #[allow(deprecated)] impl Slottable for T {} /// The actual data stored in a [`Key`]. /// /// This implements [`Ord`](std::cmp::Ord) so keys can be stored in e.g. /// [`BTreeMap`](std::collections::BTreeMap), but the order of keys is /// unspecified. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct KeyData { idx: u32, version: NonZeroU32, } impl KeyData { fn new(idx: u32, version: u32) -> Self { debug_assert!(version > 0); Self { idx, version: unsafe { NonZeroU32::new_unchecked(version | 1) }, } } fn null() -> Self { Self::new(core::u32::MAX, 1) } fn is_null(self) -> bool { self.idx == core::u32::MAX } /// Returns the key data as a 64-bit integer. No guarantees about its value /// are made other than that passing it to [`from_ffi`](Self::from_ffi) /// will return a key equal to the original. /// /// With this you can easily pass slot map keys as opaque handles to foreign /// code. After you get them back you can confidently use them in your slot /// map without worrying about unsafe behavior as you would with passing and /// receiving back references or pointers. /// /// This is not a substitute for proper serialization, use [`serde`] for /// that. If you are not doing FFI, you almost surely do not need this /// function. /// /// [`serde`]: crate#serialization-through-serde-no_std-support-and-unstable-features pub fn as_ffi(self) -> u64 { (u64::from(self.version.get()) << 32) | u64::from(self.idx) } /// Iff `value` is a value received from `k.as_ffi()`, returns a key equal /// to `k`. Otherwise the behavior is safe but unspecified. pub fn from_ffi(value: u64) -> Self { let idx = value & 0xffff_ffff; let version = (value >> 32) | 1; // Ensure version is odd. Self::new(idx as u32, version as u32) } } impl Debug for KeyData { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{}v{}", self.idx, self.version.get()) } } impl Default for KeyData { fn default() -> Self { Self::null() } } impl Hash for KeyData { fn hash(&self, state: &mut H) { // A derived Hash impl would call write_u32 twice. We call write_u64 // once, which is beneficial if the hasher implements write_u64 // explicitly. state.write_u64(self.as_ffi()) } } /// Key used to access stored values in a slot map. /// /// Do not use a key from one slot map in another. The behavior is safe but /// non-sensical (and might panic in case of out-of-bounds). /// /// To prevent this, it is suggested to have a unique key type for each slot /// map. You can create new key types using [`new_key_type!`], which makes a /// new type identical to [`DefaultKey`], just with a different name. /// /// This trait is intended to be a thin wrapper around [`KeyData`], and all /// methods must behave exactly as if we're operating on a [`KeyData`] directly. /// The internal unsafe code relies on this, therefore this trait is `unsafe` to /// implement. It is strongly suggested to simply use [`new_key_type!`] instead /// of implementing this trait yourself. pub unsafe trait Key: From + Copy + Clone + Default + Eq + PartialEq + Ord + PartialOrd + core::hash::Hash + core::fmt::Debug { /// Creates a new key that is always invalid and distinct from any non-null /// key. A null key can only be created through this method (or default /// initialization of keys made with [`new_key_type!`], which calls this /// method). /// /// A null key is always invalid, but an invalid key (that is, a key that /// has been removed from the slot map) does not become a null key. A null /// is safe to use with any safe method of any slot map instance. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let k = sm.insert(42); /// let nk = DefaultKey::null(); /// assert!(nk.is_null()); /// assert!(k != nk); /// assert_eq!(sm.get(nk), None); /// ``` fn null() -> Self { KeyData::null().into() } /// Checks if a key is null. There is only a single null key, that is /// `a.is_null() && b.is_null()` implies `a == b`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// new_key_type! { struct MyKey; } /// let a = MyKey::null(); /// let b = MyKey::default(); /// assert_eq!(a, b); /// assert!(a.is_null()); /// ``` fn is_null(&self) -> bool { self.data().is_null() } /// Gets the [`KeyData`] stored in this key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// new_key_type! { struct MyKey; } /// let dk = DefaultKey::null(); /// let mk = MyKey::null(); /// assert_eq!(dk.data(), mk.data()); /// ``` fn data(&self) -> KeyData; } /// A helper macro to create new key types. If you use a new key type for each /// slot map you create you can entirely prevent using the wrong key on the /// wrong slot map. /// /// The type constructed by this macro is defined exactly as [`DefaultKey`], /// but is a distinct type for the type checker and does not implicitly convert. /// /// # Examples /// /// ``` /// # extern crate slotmap; /// # use slotmap::*; /// new_key_type! { /// // A private key type. /// struct RocketKey; /// /// // A public key type with a doc comment. /// /// Key for the user slot map. /// pub struct UserKey; /// } /// /// fn main() { /// let mut users = SlotMap::with_key(); /// let mut rockets = SlotMap::with_key(); /// let bob: UserKey = users.insert("bobby"); /// let apollo: RocketKey = rockets.insert("apollo"); /// // Now this is a type error because rockets.get expects an RocketKey: /// // rockets.get(bob); /// /// // If for some reason you do end up needing to convert (e.g. storing /// // keys of multiple slot maps in the same data structure without /// // boxing), you can use KeyData as an intermediate representation. This /// // does mean that once again you are responsible for not using the wrong /// // key on the wrong slot map. /// let keys = vec![bob.data(), apollo.data()]; /// println!("{} likes rocket {}", /// users[keys[0].into()], rockets[keys[1].into()]); /// } /// ``` #[macro_export(local_inner_macros)] macro_rules! new_key_type { ( $(#[$outer:meta])* $vis:vis struct $name:ident; $($rest:tt)* ) => { $(#[$outer])* #[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] #[repr(transparent)] $vis struct $name($crate::KeyData); impl $crate::__impl::From<$crate::KeyData> for $name { fn from(k: $crate::KeyData) -> Self { $name(k) } } unsafe impl $crate::Key for $name { fn data(&self) -> $crate::KeyData { self.0 } } $crate::__serialize_key!($name); $crate::new_key_type!($($rest)*); }; () => {} } #[cfg(feature = "serde")] #[doc(hidden)] #[macro_export] macro_rules! __serialize_key { ( $name:ty ) => { impl $crate::__impl::Serialize for $name { fn serialize(&self, serializer: S) -> $crate::__impl::Result where S: $crate::__impl::Serializer, { $crate::Key::data(self).serialize(serializer) } } impl<'de> $crate::__impl::Deserialize<'de> for $name { fn deserialize(deserializer: D) -> $crate::__impl::Result where D: $crate::__impl::Deserializer<'de>, { let key_data: $crate::KeyData = $crate::__impl::Deserialize::deserialize(deserializer)?; Ok(key_data.into()) } } }; } #[cfg(not(feature = "serde"))] #[doc(hidden)] #[macro_export] macro_rules! __serialize_key { ( $name:ty ) => {}; } new_key_type! { /// The default slot map key type. pub struct DefaultKey; } // Serialization with serde. #[cfg(feature = "serde")] mod serialize { use serde::{Deserialize, Deserializer, Serialize, Serializer}; use super::*; #[derive(Serialize, Deserialize)] pub struct SerKey { idx: u32, version: u32, } impl Serialize for KeyData { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let ser_key = SerKey { idx: self.idx, version: self.version.get(), }; ser_key.serialize(serializer) } } impl<'de> Deserialize<'de> for KeyData { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let mut ser_key: SerKey = Deserialize::deserialize(deserializer)?; // Ensure a.is_null() && b.is_null() implies a == b. if ser_key.idx == core::u32::MAX { ser_key.version = 1; } ser_key.version |= 1; // Ensure version is odd. Ok(Self::new(ser_key.idx, ser_key.version)) } } } #[cfg(test)] mod tests { // Intentionally no `use super::*;` because we want to test macro expansion // in the *users* scope, which might not have that. #[test] fn macro_expansion() { #![allow(dead_code)] use super::new_key_type; // Clobber namespace with clashing names - should still work. trait Serialize { } trait Deserialize { } trait Serializer { } trait Deserializer { } trait Key { } trait From { } struct Result; struct KeyData; new_key_type! { struct A; pub(crate) struct B; pub struct C; } } #[test] fn check_is_older_version() { use super::util::is_older_version; let is_older = |a, b| is_older_version(a, b); assert!(!is_older(42, 42)); assert!(is_older(0, 1)); assert!(is_older(0, 1 << 31)); assert!(!is_older(0, (1 << 31) + 1)); assert!(is_older(u32::MAX, 0)); } #[test] fn iters_cloneable() { use super::*; struct NoClone; let mut sm = SlotMap::new(); let mut hsm = HopSlotMap::new(); let mut dsm = DenseSlotMap::new(); let mut scm = SecondaryMap::new(); let mut sscm = SparseSecondaryMap::new(); scm.insert(sm.insert(NoClone), NoClone); sscm.insert(hsm.insert(NoClone), NoClone); dsm.insert(NoClone); let _ = sm.keys().clone(); let _ = sm.values().clone(); let _ = sm.iter().clone(); let _ = hsm.keys().clone(); let _ = hsm.values().clone(); let _ = hsm.iter().clone(); let _ = dsm.keys().clone(); let _ = dsm.values().clone(); let _ = dsm.iter().clone(); let _ = scm.keys().clone(); let _ = scm.values().clone(); let _ = scm.iter().clone(); let _ = sscm.keys().clone(); let _ = sscm.values().clone(); let _ = sscm.iter().clone(); } #[cfg(feature = "serde")] #[test] fn key_serde() { use super::*; // Check round-trip through serde. let mut sm = SlotMap::new(); let k = sm.insert(42); let ser = serde_json::to_string(&k).unwrap(); let de: DefaultKey = serde_json::from_str(&ser).unwrap(); assert_eq!(k, de); // Even if a malicious entity sends up even (unoccupied) versions in the // key, we make the version point to the occupied version. let malicious: KeyData = serde_json::from_str(&r#"{"idx":0,"version":4}"#).unwrap(); assert_eq!(malicious.version.get(), 5); } } slotmap-1.0.7/src/secondary.rs000064400000000000000000001556330072674642500145010ustar 00000000000000//! Contains the secondary map implementation. #[cfg(all(nightly, any(doc, feature = "unstable")))] use alloc::collections::TryReserveError; use alloc::vec::Vec; use core::hint::unreachable_unchecked; use core::iter::{Enumerate, Extend, FromIterator, FusedIterator}; use core::marker::PhantomData; use core::mem::replace; #[allow(unused_imports)] // MaybeUninit is only used on nightly at the moment. use core::mem::MaybeUninit; use core::num::NonZeroU32; use core::ops::{Index, IndexMut}; use super::{Key, KeyData}; use crate::util::is_older_version; // This representation works because we don't have to store the versions // of removed elements. #[derive(Debug, Clone)] enum Slot { Occupied { value: T, version: NonZeroU32 }, Vacant, } use self::Slot::{Occupied, Vacant}; impl Slot { pub fn new_occupied(version: u32, value: T) -> Self { Occupied { value, version: unsafe { NonZeroU32::new_unchecked(version | 1u32) }, } } pub fn new_vacant() -> Self { Vacant } // Is this slot occupied? #[inline(always)] pub fn occupied(&self) -> bool { match self { Occupied { .. } => true, Vacant => false, } } #[inline(always)] pub fn version(&self) -> u32 { match self { Occupied { version, .. } => version.get(), Vacant => 0, } } pub unsafe fn get_unchecked(&self) -> &T { match self { Occupied { value, .. } => value, Vacant => unreachable_unchecked(), } } pub unsafe fn get_unchecked_mut(&mut self) -> &mut T { match self { Occupied { value, .. } => value, Vacant => unreachable_unchecked(), } } pub fn into_option(self) -> Option { match self { Occupied { value, .. } => Some(value), Vacant => None, } } } /// Secondary map, associate data with previously stored elements in a slot map. /// /// A [`SecondaryMap`] allows you to efficiently store additional information /// for each element in a slot map. You can have multiple secondary maps per /// slot map, but not multiple slot maps per secondary map. It is safe but /// unspecified behavior if you use keys from multiple different slot maps in /// the same [`SecondaryMap`]. /// /// A [`SecondaryMap`] does not leak memory even if you never remove elements. /// In return, when you remove a key from the primary slot map, after any insert /// the space associated with the removed element may be reclaimed. Don't expect /// the values associated with a removed key to stick around after an insertion /// has happened! /// /// Finally a note on memory complexity, the [`SecondaryMap`] can use memory for /// each slot in the primary slot map, and has to iterate over every slot during /// iteration, regardless of whether you have inserted an associative value at /// that key or not. If you have some property that you only expect to set for a /// minority of keys, use a [`SparseSecondaryMap`](crate::SparseSecondaryMap), /// which is backed by a [`HashMap`](std::collections::HashMap). /// /// Example usage: /// /// ``` /// # use slotmap::*; /// let mut players = SlotMap::new(); /// let mut health = SecondaryMap::new(); /// let mut ammo = SecondaryMap::new(); /// /// let alice = players.insert("alice"); /// let bob = players.insert("bob"); /// /// for p in players.keys() { /// health.insert(p, 100); /// ammo.insert(p, 30); /// } /// /// // Alice attacks Bob with all her ammo! /// health[bob] -= ammo[alice] * 3; /// ammo[alice] = 0; /// ``` #[derive(Debug, Clone)] pub struct SecondaryMap { slots: Vec>, num_elems: usize, _k: PhantomData K>, } impl SecondaryMap { /// Constructs a new, empty [`SecondaryMap`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sec: SecondaryMap = SecondaryMap::new(); /// ``` pub fn new() -> Self { Self::with_capacity(0) } /// Creates an empty [`SecondaryMap`] with the given capacity of slots. /// /// The secondary map will not reallocate until it holds at least `capacity` /// slots. Even inserting a single key-value pair might require as many /// slots as the slot map the key comes from, so it's recommended to match /// the capacity of a secondary map to its corresponding slot map. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm: SlotMap<_, i32> = SlotMap::with_capacity(10); /// let mut sec: SecondaryMap = SecondaryMap::with_capacity(sm.capacity()); /// ``` pub fn with_capacity(capacity: usize) -> Self { let mut slots = Vec::with_capacity(capacity + 1); // Sentinel. slots.push(Slot::new_vacant()); Self { slots, num_elems: 0, _k: PhantomData, } } /// Returns the number of elements in the secondary map. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let k = sm.insert(4); /// let mut squared = SecondaryMap::new(); /// assert_eq!(squared.len(), 0); /// squared.insert(k, 16); /// assert_eq!(squared.len(), 1); /// ``` pub fn len(&self) -> usize { self.num_elems } /// Returns if the secondary map is empty. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sec: SecondaryMap = SecondaryMap::new(); /// assert!(sec.is_empty()); /// ``` pub fn is_empty(&self) -> bool { self.num_elems == 0 } /// Returns the number of elements the [`SecondaryMap`] can hold without /// reallocating. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sec: SecondaryMap = SecondaryMap::with_capacity(10); /// assert!(sec.capacity() >= 10); /// ``` pub fn capacity(&self) -> usize { self.slots.capacity() - 1 // Sentinel. } /// Sets the capacity of the [`SecondaryMap`] to `new_capacity`, if it is /// bigger than the current capacity. /// /// It is recommended to set the capacity of a [`SecondaryMap`] to the /// capacity of its corresponding slot map before inserting many new /// elements to prevent frequent reallocations. The collection may reserve /// more space than requested. /// /// # Panics /// /// Panics if the new allocation size overflows [`usize`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sec: SecondaryMap = SecondaryMap::with_capacity(10); /// assert!(sec.capacity() >= 10); /// sec.set_capacity(1000); /// assert!(sec.capacity() >= 1000); /// ``` pub fn set_capacity(&mut self, new_capacity: usize) { let new_capacity = new_capacity + 1; // Sentinel. if new_capacity > self.slots.capacity() { let needed = new_capacity - self.slots.len(); self.slots.reserve(needed); } } /// Tries to set the capacity of the [`SecondaryMap`] to `new_capacity`, if it /// is bigger than the current capacity. /// /// It is recommended to set the capacity of a [`SecondaryMap`] to the /// capacity of its corresponding slot map before inserting many new /// elements to prevent frequent reallocations. The collection may reserve /// more space than requested. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sec: SecondaryMap = SecondaryMap::with_capacity(10); /// assert!(sec.capacity() >= 10); /// sec.try_set_capacity(1000).unwrap(); /// assert!(sec.capacity() >= 1000); /// ``` #[cfg(all(nightly, any(doc, feature = "unstable")))] #[cfg_attr(all(nightly, doc), doc(cfg(feature = "unstable")))] pub fn try_set_capacity(&mut self, new_capacity: usize) -> Result<(), TryReserveError> { let new_capacity = new_capacity + 1; // Sentinel. if new_capacity > self.slots.capacity() { let needed = new_capacity - self.slots.len(); self.slots.try_reserve(needed) } else { Ok(()) } } /// Returns [`true`] if the secondary map contains `key`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let k = sm.insert(4); /// let mut squared = SecondaryMap::new(); /// assert!(!squared.contains_key(k)); /// squared.insert(k, 16); /// assert!(squared.contains_key(k)); /// ``` pub fn contains_key(&self, key: K) -> bool { let kd = key.data(); self.slots .get(kd.idx as usize) .map_or(false, |slot| slot.version() == kd.version.get()) } /// Inserts a value into the secondary map at the given `key`. Can silently /// fail and return `None` if `key` was removed from the originating slot /// map. /// /// Returns [`None`] if this key was not present in the map, the old value /// otherwise. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let k = sm.insert(4); /// let mut squared = SecondaryMap::new(); /// assert_eq!(squared.insert(k, 0), None); /// assert_eq!(squared.insert(k, 4), Some(0)); /// // You don't have to use insert if the key is already in the secondary map. /// squared[k] *= squared[k]; /// assert_eq!(squared[k], 16); /// ``` pub fn insert(&mut self, key: K, value: V) -> Option { if key.is_null() { return None; } let kd = key.data(); self.slots .extend((self.slots.len()..=kd.idx as usize).map(|_| Slot::new_vacant())); let slot = &mut self.slots[kd.idx as usize]; if slot.version() == kd.version.get() { // Is always occupied. return Some(replace(unsafe { slot.get_unchecked_mut() }, value)); } if slot.occupied() { // Don't replace existing newer values. if is_older_version(kd.version.get(), slot.version()) { return None; } } else { self.num_elems += 1; } *slot = Slot::new_occupied(kd.version.get(), value); None } /// Removes a key from the secondary map, returning the value at the key if /// the key was not previously removed. If `key` was removed from the /// originating slot map, its corresponding entry in the secondary map may /// or may not already be removed. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut squared = SecondaryMap::new(); /// let k = sm.insert(4); /// squared.insert(k, 16); /// squared.remove(k); /// assert!(!squared.contains_key(k)); /// /// // It's not necessary to remove keys deleted from the primary slot map, they /// // get deleted automatically when their slots are reused on a subsequent insert. /// squared.insert(k, 16); /// sm.remove(k); // Remove k from the slot map, making an empty slot. /// let new_k = sm.insert(2); // Since sm only has one empty slot, this reuses it. /// assert!(!squared.contains_key(new_k)); // Space reuse does not mean equal keys. /// assert!(squared.contains_key(k)); // Slot has not been reused in squared yet. /// squared.insert(new_k, 4); /// assert!(!squared.contains_key(k)); // Old key is no longer available. /// ``` pub fn remove(&mut self, key: K) -> Option { let kd = key.data(); if let Some(slot) = self.slots.get_mut(kd.idx as usize) { if slot.version() == kd.version.get() { self.num_elems -= 1; return replace(slot, Slot::new_vacant()).into_option(); } } None } /// Retains only the elements specified by the predicate. /// /// In other words, remove all key-value pairs `(k, v)` such that /// `f(k, &mut v)` returns false. This method invalidates any removed keys. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let k1 = sm.insert(0); sec.insert(k1, 10); /// let k2 = sm.insert(1); sec.insert(k2, 11); /// let k3 = sm.insert(2); sec.insert(k3, 12); /// /// sec.retain(|key, val| key == k1 || *val == 11); /// /// assert!(sec.contains_key(k1)); /// assert!(sec.contains_key(k2)); /// assert!(!sec.contains_key(k3)); /// assert_eq!(sec.len(), 2); /// ``` pub fn retain(&mut self, mut f: F) where F: FnMut(K, &mut V) -> bool, { for (i, slot) in self.slots.iter_mut().enumerate() { if let Occupied { value, version } = slot { let key = KeyData::new(i as u32, version.get()).into(); if !f(key, value) { self.num_elems -= 1; *slot = Slot::new_vacant(); } } } } /// Clears the secondary map. Keeps the allocated memory for reuse. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// for i in 0..10 { /// sec.insert(sm.insert(i), i); /// } /// assert_eq!(sec.len(), 10); /// sec.clear(); /// assert_eq!(sec.len(), 0); /// ``` pub fn clear(&mut self) { self.drain(); } /// Clears the slot map, returning all key-value pairs in arbitrary order as /// an iterator. Keeps the allocated memory for reuse. /// /// When the iterator is dropped all elements in the slot map are removed, /// even if the iterator was not fully consumed. If the iterator is not /// dropped (using e.g. [`std::mem::forget`]), only the elements that were /// iterated over are removed. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::iter::FromIterator; /// let mut sm = SlotMap::new(); /// let k = sm.insert(0); /// let mut sec = SecondaryMap::new(); /// sec.insert(k, 1); /// let v: Vec<_> = sec.drain().collect(); /// assert_eq!(sec.len(), 0); /// assert_eq!(v, vec![(k, 1)]); /// ``` pub fn drain(&mut self) -> Drain { Drain { cur: 1, sm: self } } /// Returns a reference to the value corresponding to the key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("foo"); /// let mut sec = SecondaryMap::new(); /// sec.insert(key, "bar"); /// assert_eq!(sec.get(key), Some(&"bar")); /// sec.remove(key); /// assert_eq!(sec.get(key), None); /// ``` pub fn get(&self, key: K) -> Option<&V> { let kd = key.data(); self.slots .get(kd.idx as usize) .filter(|slot| slot.version() == kd.version.get()) .map(|slot| unsafe { slot.get_unchecked() }) } /// Returns a reference to the value corresponding to the key without /// version or bounds checking. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true. Otherwise it is /// potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("foo"); /// let mut sec = SecondaryMap::new(); /// sec.insert(key, "bar"); /// assert_eq!(unsafe { sec.get_unchecked(key) }, &"bar"); /// sec.remove(key); /// // sec.get_unchecked(key) is now dangerous! /// ``` pub unsafe fn get_unchecked(&self, key: K) -> &V { debug_assert!(self.contains_key(key)); let slot = self.slots.get_unchecked(key.data().idx as usize); slot.get_unchecked() } /// Returns a mutable reference to the value corresponding to the key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("test"); /// let mut sec = SecondaryMap::new(); /// sec.insert(key, 3.5); /// if let Some(x) = sec.get_mut(key) { /// *x += 3.0; /// } /// assert_eq!(sec[key], 6.5); /// ``` pub fn get_mut(&mut self, key: K) -> Option<&mut V> { let kd = key.data(); self.slots .get_mut(kd.idx as usize) .filter(|slot| slot.version() == kd.version.get()) .map(|slot| unsafe { slot.get_unchecked_mut() }) } /// Returns a mutable reference to the value corresponding to the key /// without version or bounds checking. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true. Otherwise it is /// potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("foo"); /// let mut sec = SecondaryMap::new(); /// sec.insert(key, "bar"); /// unsafe { *sec.get_unchecked_mut(key) = "baz" }; /// assert_eq!(sec[key], "baz"); /// sec.remove(key); /// // sec.get_unchecked_mut(key) is now dangerous! /// ``` pub unsafe fn get_unchecked_mut(&mut self, key: K) -> &mut V { debug_assert!(self.contains_key(key)); let slot = self.slots.get_unchecked_mut(key.data().idx as usize); slot.get_unchecked_mut() } /// Returns mutable references to the values corresponding to the given /// keys. All keys must be valid and disjoint, otherwise None is returned. /// /// Requires at least stable Rust version 1.51. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// let ka = sm.insert(()); sec.insert(ka, "butter"); /// let kb = sm.insert(()); sec.insert(kb, "apples"); /// let kc = sm.insert(()); sec.insert(kc, "charlie"); /// sec.remove(kc); // Make key c invalid. /// assert_eq!(sec.get_disjoint_mut([ka, kb, kc]), None); // Has invalid key. /// assert_eq!(sec.get_disjoint_mut([ka, ka]), None); // Not disjoint. /// let [a, b] = sec.get_disjoint_mut([ka, kb]).unwrap(); /// std::mem::swap(a, b); /// assert_eq!(sec[ka], "apples"); /// assert_eq!(sec[kb], "butter"); /// ``` #[cfg(has_min_const_generics)] pub fn get_disjoint_mut(&mut self, keys: [K; N]) -> Option<[&mut V; N]> { // Create an uninitialized array of `MaybeUninit`. The `assume_init` is // safe because the type we are claiming to have initialized here is a // bunch of `MaybeUninit`s, which do not require initialization. let mut ptrs: [MaybeUninit<*mut V>; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut slot_versions: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut i = 0; while i < N { let kd = keys[i].data(); match self.slots.get_mut(kd.idx as usize) { Some(Occupied { version, value }) if *version == kd.version => { // This key is valid, and the slot is occupied. Temporarily // set the version to 2 so duplicate keys would show up as // invalid, since keys always have an odd version. This // gives us a linear time disjointness check. ptrs[i] = MaybeUninit::new(&mut *value); slot_versions[i] = MaybeUninit::new(version.get()); *version = NonZeroU32::new(2).unwrap(); }, _ => break, } i += 1; } // Undo temporary unoccupied markings. for j in 0..i { let idx = keys[j].data().idx as usize; unsafe { match self.slots.get_mut(idx) { Some(Occupied { version, .. }) => { *version = NonZeroU32::new_unchecked(slot_versions[j].assume_init()); }, _ => unreachable_unchecked(), } } } if i == N { // All were valid and disjoint. Some(unsafe { core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs) }) } else { None } } /// Returns mutable references to the values corresponding to the given /// keys. All keys must be valid and disjoint. /// /// Requires at least stable Rust version 1.51. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true for every given /// key and no two keys are equal. Otherwise it is potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// let ka = sm.insert(()); sec.insert(ka, "butter"); /// let kb = sm.insert(()); sec.insert(kb, "apples"); /// let [a, b] = unsafe { sec.get_disjoint_unchecked_mut([ka, kb]) }; /// std::mem::swap(a, b); /// assert_eq!(sec[ka], "apples"); /// assert_eq!(sec[kb], "butter"); /// ``` #[cfg(has_min_const_generics)] pub unsafe fn get_disjoint_unchecked_mut( &mut self, keys: [K; N], ) -> [&mut V; N] { // Safe, see get_disjoint_mut. let mut ptrs: [MaybeUninit<*mut V>; N] = MaybeUninit::uninit().assume_init(); for i in 0..N { ptrs[i] = MaybeUninit::new(self.get_unchecked_mut(keys[i])); } core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs) } /// An iterator visiting all key-value pairs in arbitrary order. The /// iterator element type is `(K, &'a V)`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// let k0 = sm.insert(0); sec.insert(k0, 10); /// let k1 = sm.insert(1); sec.insert(k1, 11); /// let k2 = sm.insert(2); sec.insert(k2, 12); /// /// for (k, v) in sm.iter() { /// println!("key: {:?}, val: {}", k, v); /// } /// ``` pub fn iter(&self) -> Iter { Iter { num_left: self.num_elems, slots: self.slots.iter().enumerate(), _k: PhantomData, } } /// An iterator visiting all key-value pairs in arbitrary order, with /// mutable references to the values. The iterator element type is /// `(K, &'a mut V)`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// let k0 = sm.insert(1); sec.insert(k0, 10); /// let k1 = sm.insert(2); sec.insert(k1, 20); /// let k2 = sm.insert(3); sec.insert(k2, 30); /// /// for (k, v) in sec.iter_mut() { /// if k != k1 { /// *v *= -1; /// } /// } /// /// assert_eq!(sec[k0], -10); /// assert_eq!(sec[k1], 20); /// assert_eq!(sec[k2], -30); /// ``` pub fn iter_mut(&mut self) -> IterMut { IterMut { num_left: self.num_elems, slots: self.slots.iter_mut().enumerate(), _k: PhantomData, } } /// An iterator visiting all keys in arbitrary order. The iterator element /// type is `K`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// let k0 = sm.insert(1); sec.insert(k0, 10); /// let k1 = sm.insert(2); sec.insert(k1, 20); /// let k2 = sm.insert(3); sec.insert(k2, 30); /// let keys: HashSet<_> = sec.keys().collect(); /// let check: HashSet<_> = vec![k0, k1, k2].into_iter().collect(); /// assert_eq!(keys, check); /// ``` pub fn keys(&self) -> Keys { Keys { inner: self.iter() } } /// An iterator visiting all values in arbitrary order. The iterator element /// type is `&'a V`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// let k0 = sm.insert(1); sec.insert(k0, 10); /// let k1 = sm.insert(2); sec.insert(k1, 20); /// let k2 = sm.insert(3); sec.insert(k2, 30); /// let values: HashSet<_> = sec.values().collect(); /// let check: HashSet<_> = vec![&10, &20, &30].into_iter().collect(); /// assert_eq!(values, check); /// ``` pub fn values(&self) -> Values { Values { inner: self.iter() } } /// An iterator visiting all values mutably in arbitrary order. The iterator /// element type is `&'a mut V`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// sec.insert(sm.insert(1), 10); /// sec.insert(sm.insert(2), 20); /// sec.insert(sm.insert(3), 30); /// sec.values_mut().for_each(|n| { *n *= 3 }); /// let values: HashSet<_> = sec.into_iter().map(|(_k, v)| v).collect(); /// let check: HashSet<_> = vec![30, 60, 90].into_iter().collect(); /// assert_eq!(values, check); /// ``` pub fn values_mut(&mut self) -> ValuesMut { ValuesMut { inner: self.iter_mut(), } } /// Gets the given key's corresponding [`Entry`] in the map for in-place /// manipulation. May return [`None`] if the key was removed from the /// originating slot map. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// let k = sm.insert(1); /// let v = sec.entry(k).unwrap().or_insert(10); /// assert_eq!(*v, 10); /// ``` pub fn entry(&mut self, key: K) -> Option> { if key.is_null() { return None; } let kd = key.data(); // Ensure the slot exists so the Entry implementation can safely assume // the slot always exists without checking. self.slots .extend((self.slots.len()..=kd.idx as usize).map(|_| Slot::new_vacant())); let slot = unsafe { self.slots.get_unchecked(kd.idx as usize) }; if kd.version.get() == slot.version() { Some(Entry::Occupied(OccupiedEntry { map: self, kd, _k: PhantomData, })) } else if is_older_version(kd.version.get(), slot.version()) { None } else { Some(Entry::Vacant(VacantEntry { map: self, kd, _k: PhantomData, })) } } } impl Default for SecondaryMap { fn default() -> Self { Self::new() } } impl Index for SecondaryMap { type Output = V; fn index(&self, key: K) -> &V { match self.get(key) { Some(r) => r, None => panic!("invalid SecondaryMap key used"), } } } impl IndexMut for SecondaryMap { fn index_mut(&mut self, key: K) -> &mut V { match self.get_mut(key) { Some(r) => r, None => panic!("invalid SecondaryMap key used"), } } } impl PartialEq for SecondaryMap { fn eq(&self, other: &Self) -> bool { if self.len() != other.len() { return false; } self.iter() .all(|(key, value)| other.get(key).map_or(false, |other_value| *value == *other_value)) } } impl Eq for SecondaryMap {} impl FromIterator<(K, V)> for SecondaryMap { fn from_iter>(iter: I) -> Self { let mut sec = Self::new(); sec.extend(iter); sec } } impl Extend<(K, V)> for SecondaryMap { fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); for (k, v) in iter { self.insert(k, v); } } } impl<'a, K: Key, V: 'a + Copy> Extend<(K, &'a V)> for SecondaryMap { fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); for (k, v) in iter { self.insert(k, *v); } } } /// A view into a occupied entry in a [`SecondaryMap`]. It is part of the /// [`Entry`] enum. #[derive(Debug)] pub struct OccupiedEntry<'a, K: Key, V> { map: &'a mut SecondaryMap, kd: KeyData, _k: PhantomData K>, } /// A view into a vacant entry in a [`SecondaryMap`]. It is part of the /// [`Entry`] enum. #[derive(Debug)] pub struct VacantEntry<'a, K: Key, V> { map: &'a mut SecondaryMap, kd: KeyData, _k: PhantomData K>, } /// A view into a single entry in a [`SecondaryMap`], which may either be /// vacant or occupied. /// /// This `enum` is constructed using [`SecondaryMap::entry`]. #[derive(Debug)] pub enum Entry<'a, K: Key, V> { /// An occupied entry. Occupied(OccupiedEntry<'a, K, V>), /// A vacant entry. Vacant(VacantEntry<'a, K, V>), } impl<'a, K: Key, V> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting the default if empty, and /// returns a mutable reference to the value in the entry. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let k = sm.insert("poneyland"); /// let v = sec.entry(k).unwrap().or_insert(10); /// assert_eq!(*v, 10); /// *sec.entry(k).unwrap().or_insert(1) *= 2; /// assert_eq!(sec[k], 20); /// ``` pub fn or_insert(self, default: V) -> &'a mut V { self.or_insert_with(|| default) } /// Ensures a value is in the entry by inserting the result of the default /// function if empty, and returns a mutable reference to the value in the /// entry. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let k = sm.insert(1); /// let v = sec.entry(k).unwrap().or_insert_with(|| "foobar".to_string()); /// assert_eq!(v, &"foobar"); /// ``` pub fn or_insert_with V>(self, default: F) -> &'a mut V { match self { Entry::Occupied(x) => x.into_mut(), Entry::Vacant(x) => x.insert(default()), } } /// Returns this entry's key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec: SecondaryMap<_, ()> = SecondaryMap::new(); /// /// let k = sm.insert(1); /// let entry = sec.entry(k).unwrap(); /// assert_eq!(entry.key(), k); /// ``` pub fn key(&self) -> K { match self { Entry::Occupied(entry) => entry.kd.into(), Entry::Vacant(entry) => entry.kd.into(), } } /// Provides in-place mutable access to an occupied entry before any /// potential inserts into the map. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 0); /// sec.entry(k).unwrap().and_modify(|x| *x = 1); /// /// assert_eq!(sec[k], 1) /// ``` pub fn and_modify(self, f: F) -> Self where F: FnOnce(&mut V), { match self { Entry::Occupied(mut entry) => { f(entry.get_mut()); Entry::Occupied(entry) }, Entry::Vacant(entry) => Entry::Vacant(entry), } } } impl<'a, K: Key, V: Default> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec: SecondaryMap<_, Option> = SecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.entry(k).unwrap().or_default(); /// assert_eq!(sec[k], None) /// ``` pub fn or_default(self) -> &'a mut V { self.or_insert_with(Default::default) } } impl<'a, K: Key, V> OccupiedEntry<'a, K, V> { /// Returns this entry's key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 10); /// assert_eq!(sec.entry(k).unwrap().key(), k); /// ``` pub fn key(&self) -> K { self.kd.into() } /// Removes the entry from the slot map and returns the key and value. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::secondary::Entry; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let foo = sm.insert("foo"); /// sec.entry(foo).unwrap().or_insert("bar"); /// /// if let Some(Entry::Occupied(o)) = sec.entry(foo) { /// assert_eq!(o.remove_entry(), (foo, "bar")); /// } /// assert_eq!(sec.contains_key(foo), false); /// ``` pub fn remove_entry(self) -> (K, V) { (self.kd.into(), self.remove()) } /// Gets a reference to the value in the entry. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::secondary::Entry; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 10); /// /// if let Entry::Occupied(o) = sec.entry(k).unwrap() { /// assert_eq!(*o.get(), 10); /// } /// ``` pub fn get(&self) -> &V { unsafe { self.map.get_unchecked(self.kd.into()) } } /// Gets a mutable reference to the value in the entry. /// /// If you need a reference to the [`OccupiedEntry`] which may outlive the /// destruction of the [`Entry`] value, see [`into_mut`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::secondary::Entry; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 10); /// if let Entry::Occupied(mut o) = sec.entry(k).unwrap() { /// *o.get_mut() = 20; /// } /// assert_eq!(sec[k], 20); /// ``` /// /// [`into_mut`]: Self::into_mut pub fn get_mut(&mut self) -> &mut V { unsafe { self.map.get_unchecked_mut(self.kd.into()) } } /// Converts the [`OccupiedEntry`] into a mutable reference to the value in /// the entry with a lifetime bound to the map itself. /// /// If you need multiple references to the [`OccupiedEntry`], see /// [`get_mut`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::secondary::Entry; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let k = sm.insert(0); /// sec.insert(k, 0); /// /// let r; /// if let Entry::Occupied(o) = sec.entry(k).unwrap() { /// r = o.into_mut(); // v outlives the entry. /// } else { /// r = sm.get_mut(k).unwrap(); /// } /// *r = 1; /// assert_eq!((sm[k], sec[k]), (0, 1)); /// ``` /// /// [`get_mut`]: Self::get_mut pub fn into_mut(self) -> &'a mut V { unsafe { self.map.get_unchecked_mut(self.kd.into()) } } /// Sets the value of the entry, and returns the entry's old value. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::secondary::Entry; /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 10); /// /// if let Entry::Occupied(mut o) = sec.entry(k).unwrap() { /// let v = o.insert(20); /// assert_eq!(v, 10); /// assert_eq!(*o.get(), 20); /// } /// ``` pub fn insert(&mut self, value: V) -> V { replace(self.get_mut(), value) } /// Takes the value out of the entry, and returns it. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::secondary::Entry; /// /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 10); /// /// if let Entry::Occupied(mut o) = sec.entry(k).unwrap() { /// assert_eq!(o.remove(), 10); /// assert_eq!(sec.contains_key(k), false); /// } /// ``` pub fn remove(self) -> V { let slot = unsafe { self.map.slots.get_unchecked_mut(self.kd.idx as usize) }; self.map.num_elems -= 1; match replace(slot, Slot::new_vacant()) { Occupied { value, .. } => value, Vacant => unsafe { unreachable_unchecked() }, } } } impl<'a, K: Key, V> VacantEntry<'a, K, V> { /// Gets the key that would be used when inserting a value through the /// [`VacantEntry`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::secondary::Entry; /// /// let mut sm = SlotMap::new(); /// let mut sec: SecondaryMap<_, ()> = SecondaryMap::new(); /// /// let k = sm.insert(1); /// /// if let Entry::Vacant(v) = sec.entry(k).unwrap() { /// assert_eq!(v.key(), k); /// } /// ``` pub fn key(&self) -> K { self.kd.into() } /// Sets the value of the entry with the [`VacantEntry`]'s key, and returns /// a mutable reference to it. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::secondary::Entry; /// /// let mut sm = SlotMap::new(); /// let mut sec = SecondaryMap::new(); /// /// let k = sm.insert(1); /// /// if let Entry::Vacant(v) = sec.entry(k).unwrap() { /// let new_val = v.insert(3); /// assert_eq!(new_val, &mut 3); /// } /// ``` pub fn insert(self, value: V) -> &'a mut V { let slot = unsafe { self.map.slots.get_unchecked_mut(self.kd.idx as usize) }; // Despite the slot being considered Vacant for this entry, it might be occupied // with an outdated element. match replace(slot, Slot::new_occupied(self.kd.version.get(), value)) { Occupied { .. } => {}, Vacant => self.map.num_elems += 1, } unsafe { slot.get_unchecked_mut() } } } // Iterators. /// A draining iterator for [`SecondaryMap`]. /// /// This iterator is created by [`SecondaryMap::drain`]. #[derive(Debug)] pub struct Drain<'a, K: Key + 'a, V: 'a> { sm: &'a mut SecondaryMap, cur: usize, } /// An iterator that moves key-value pairs out of a [`SecondaryMap`]. /// /// This iterator is created by calling the `into_iter` method on [`SecondaryMap`], /// provided by the [`IntoIterator`] trait. #[derive(Debug)] pub struct IntoIter { num_left: usize, slots: Enumerate>>, _k: PhantomData K>, } /// An iterator over the key-value pairs in a [`SecondaryMap`]. /// /// This iterator is created by [`SecondaryMap::iter`]. #[derive(Debug)] pub struct Iter<'a, K: Key + 'a, V: 'a> { num_left: usize, slots: Enumerate>>, _k: PhantomData K>, } impl<'a, K: 'a + Key, V: 'a> Clone for Iter<'a, K, V> { fn clone(&self) -> Self { Iter { num_left: self.num_left, slots: self.slots.clone(), _k: self._k, } } } /// A mutable iterator over the key-value pairs in a [`SecondaryMap`]. /// /// This iterator is created by [`SecondaryMap::iter_mut`]. #[derive(Debug)] pub struct IterMut<'a, K: Key + 'a, V: 'a> { num_left: usize, slots: Enumerate>>, _k: PhantomData K>, } /// An iterator over the keys in a [`SecondaryMap`]. /// /// This iterator is created by [`SecondaryMap::keys`]. #[derive(Debug)] pub struct Keys<'a, K: Key + 'a, V: 'a> { inner: Iter<'a, K, V>, } impl<'a, K: 'a + Key, V: 'a> Clone for Keys<'a, K, V> { fn clone(&self) -> Self { Keys { inner: self.inner.clone(), } } } /// An iterator over the values in a [`SecondaryMap`]. /// /// This iterator is created by [`SecondaryMap::values`]. #[derive(Debug)] pub struct Values<'a, K: Key + 'a, V: 'a> { inner: Iter<'a, K, V>, } impl<'a, K: 'a + Key, V: 'a> Clone for Values<'a, K, V> { fn clone(&self) -> Self { Values { inner: self.inner.clone(), } } } /// A mutable iterator over the values in a [`SecondaryMap`]. /// /// This iterator is created by [`SecondaryMap::values_mut`]. #[derive(Debug)] pub struct ValuesMut<'a, K: Key + 'a, V: 'a> { inner: IterMut<'a, K, V>, } impl<'a, K: Key, V> Iterator for Drain<'a, K, V> { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { while let Some(slot) = self.sm.slots.get_mut(self.cur) { let idx = self.cur; self.cur += 1; if let Occupied { value, version } = replace(slot, Slot::new_vacant()) { self.sm.num_elems -= 1; let key = KeyData::new(idx as u32, version.get()).into(); return Some((key, value)); } } None } fn size_hint(&self) -> (usize, Option) { (self.sm.len(), Some(self.sm.len())) } } impl<'a, K: Key, V> Drop for Drain<'a, K, V> { fn drop(&mut self) { self.for_each(|_drop| {}); } } impl Iterator for IntoIter { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { while let Some((idx, mut slot)) = self.slots.next() { if let Occupied { value, version } = replace(&mut slot, Slot::new_vacant()) { self.num_left -= 1; let key = KeyData::new(idx as u32, version.get()).into(); return Some((key, value)); } } None } fn size_hint(&self) -> (usize, Option) { (self.num_left, Some(self.num_left)) } } impl<'a, K: Key, V> Iterator for Iter<'a, K, V> { type Item = (K, &'a V); fn next(&mut self) -> Option<(K, &'a V)> { while let Some((idx, slot)) = self.slots.next() { if let Occupied { value, version } = slot { self.num_left -= 1; let key = KeyData::new(idx as u32, version.get()).into(); return Some((key, value)); } } None } fn size_hint(&self) -> (usize, Option) { (self.num_left, Some(self.num_left)) } } impl<'a, K: Key, V> Iterator for IterMut<'a, K, V> { type Item = (K, &'a mut V); fn next(&mut self) -> Option<(K, &'a mut V)> { while let Some((idx, slot)) = self.slots.next() { if let Occupied { value, version } = slot { let key = KeyData::new(idx as u32, version.get()).into(); self.num_left -= 1; return Some((key, value)); } } None } fn size_hint(&self) -> (usize, Option) { (self.num_left, Some(self.num_left)) } } impl<'a, K: Key, V> Iterator for Keys<'a, K, V> { type Item = K; fn next(&mut self) -> Option { self.inner.next().map(|(key, _)| key) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Iterator for Values<'a, K, V> { type Item = &'a V; fn next(&mut self) -> Option<&'a V> { self.inner.next().map(|(_, value)| value) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; fn next(&mut self) -> Option<&'a mut V> { self.inner.next().map(|(_, value)| value) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> IntoIterator for &'a SecondaryMap { type Item = (K, &'a V); type IntoIter = Iter<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, K: Key, V> IntoIterator for &'a mut SecondaryMap { type Item = (K, &'a mut V); type IntoIter = IterMut<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl IntoIterator for SecondaryMap { type Item = (K, V); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { let len = self.len(); let mut it = self.slots.into_iter().enumerate(); it.next(); // Skip sentinel. IntoIter { num_left: len, slots: it, _k: PhantomData, } } } impl<'a, K: Key, V> FusedIterator for Iter<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for IterMut<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Keys<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Values<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for ValuesMut<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Drain<'a, K, V> {} impl FusedIterator for IntoIter {} impl<'a, K: Key, V> ExactSizeIterator for Iter<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for IterMut<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Keys<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Values<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for ValuesMut<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Drain<'a, K, V> {} impl ExactSizeIterator for IntoIter {} // Serialization with serde. #[cfg(feature = "serde")] mod serialize { use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use super::*; #[derive(Serialize, Deserialize)] struct SerdeSlot { value: Option, version: u32, } impl Serialize for Slot { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let serde_slot = SerdeSlot { version: self.version(), value: match self { Occupied { value, .. } => Some(value), Vacant => None, }, }; serde_slot.serialize(serializer) } } impl<'de, T> Deserialize<'de> for Slot where T: Deserialize<'de>, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let serde_slot: SerdeSlot = Deserialize::deserialize(deserializer)?; let occupied = serde_slot.version % 2 == 1; if occupied ^ serde_slot.value.is_some() { return Err(de::Error::custom(&"inconsistent occupation in Slot")); } Ok(match serde_slot.value { Some(value) => Self::new_occupied(serde_slot.version, value), None => Self::new_vacant(), }) } } impl Serialize for SecondaryMap { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.slots.serialize(serializer) } } impl<'de, K: Key, V: Deserialize<'de>> Deserialize<'de> for SecondaryMap { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let mut slots: Vec> = Deserialize::deserialize(deserializer)?; if slots.len() >= (u32::max_value() - 1) as usize { return Err(de::Error::custom(&"too many slots")); } // Ensure the first slot exists and is empty for the sentinel. if slots.get(0).map_or(true, |slot| slot.occupied()) { return Err(de::Error::custom(&"first slot not empty")); } slots[0] = Slot::new_vacant(); let num_elems = slots.iter().map(|s| s.occupied() as usize).sum(); Ok(Self { num_elems, slots, _k: PhantomData, }) } } } #[cfg(test)] mod tests { use std::collections::HashMap; use quickcheck::quickcheck; use crate::*; #[cfg(all(nightly, feature = "unstable"))] #[test] fn disjoint() { // Intended to be run with miri to find any potential UB. let mut sm = SlotMap::new(); let mut sec = SecondaryMap::new(); // Some churn. for i in 0..20usize { sm.insert(i); } sm.retain(|_, i| *i % 2 == 0); for (i, k) in sm.keys().enumerate() { sec.insert(k, i); } let keys: Vec<_> = sm.keys().collect(); for i in 0..keys.len() { for j in 0..keys.len() { if let Some([r0, r1]) = sec.get_disjoint_mut([keys[i], keys[j]]) { *r0 ^= *r1; *r1 = r1.wrapping_add(*r0); } else { assert!(i == j); } } } for i in 0..keys.len() { for j in 0..keys.len() { for k in 0..keys.len() { if let Some([r0, r1, r2]) = sec.get_disjoint_mut([keys[i], keys[j], keys[k]]) { *r0 ^= *r1; *r0 = r0.wrapping_add(*r2); *r1 ^= *r0; *r1 = r1.wrapping_add(*r2); *r2 ^= *r0; *r2 = r2.wrapping_add(*r1); } else { assert!(i == j || j == k || i == k); } } } } } quickcheck! { fn qc_secmap_equiv_hashmap(operations: Vec<(u8, u32)>) -> bool { let mut hm = HashMap::new(); let mut hm_keys = Vec::new(); let mut unique_key = 0u32; let mut sm = SlotMap::new(); let mut sec = SecondaryMap::new(); let mut sm_keys = Vec::new(); #[cfg(not(feature = "serde"))] let num_ops = 4; #[cfg(feature = "serde")] let num_ops = 5; for (op, val) in operations { match op % num_ops { // Insert. 0 => { hm.insert(unique_key, val); hm_keys.push(unique_key); unique_key += 1; let k = sm.insert(val); sec.insert(k, val); sm_keys.push(k); } // Delete. 1 => { if hm_keys.is_empty() { continue; } let idx = val as usize % hm_keys.len(); sm.remove(sm_keys[idx]); if hm.remove(&hm_keys[idx]) != sec.remove(sm_keys[idx]) { return false; } } // Access. 2 => { if hm_keys.is_empty() { continue; } let idx = val as usize % hm_keys.len(); let (hm_key, sm_key) = (&hm_keys[idx], sm_keys[idx]); if hm.contains_key(hm_key) != sec.contains_key(sm_key) || hm.get(hm_key) != sec.get(sm_key) { return false; } } // Clone. 3 => { sec = sec.clone(); } // Serde round-trip. #[cfg(feature = "serde")] 4 => { let ser = serde_json::to_string(&sec).unwrap(); sec = serde_json::from_str(&ser).unwrap(); } _ => unreachable!(), } } let mut secv: Vec<_> = sec.values().collect(); let mut hmv: Vec<_> = hm.values().collect(); secv.sort(); hmv.sort(); secv == hmv } } } slotmap-1.0.7/src/sparse_secondary.rs000064400000000000000000001474220072674642500160530ustar 00000000000000//! Contains the sparse secondary map implementation. #[cfg(all(nightly, any(doc, feature = "unstable")))] use alloc::collections::TryReserveError; #[allow(unused_imports)] // MaybeUninit is only used on nightly at the moment. use core::mem::MaybeUninit; use std::collections::hash_map::{self, HashMap}; use std::hash; use std::iter::{Extend, FromIterator, FusedIterator}; use std::marker::PhantomData; use std::ops::{Index, IndexMut}; use super::{Key, KeyData}; use crate::util::{is_older_version, UnwrapUnchecked}; #[derive(Debug, Clone)] struct Slot { version: u32, value: T, } /// Sparse secondary map, associate data with previously stored elements in a /// slot map. /// /// A [`SparseSecondaryMap`] allows you to efficiently store additional /// information for each element in a slot map. You can have multiple secondary /// maps per slot map, but not multiple slot maps per secondary map. It is safe /// but unspecified behavior if you use keys from multiple different slot maps /// in the same [`SparseSecondaryMap`]. /// /// A [`SparseSecondaryMap`] does not leak memory even if you never remove /// elements. In return, when you remove a key from the primary slot map, after /// any insert the space associated with the removed element may be reclaimed. /// Don't expect the values associated with a removed key to stick around after /// an insertion has happened! /// /// Unlike [`SecondaryMap`], the [`SparseSecondaryMap`] is backed by a /// [`HashMap`]. This means its access times are higher, but it uses less memory /// and iterates faster if there are only a few elements of the slot map in the /// secondary map. If most or all of the elements in a slot map are also found /// in the secondary map, use a [`SecondaryMap`] instead. /// /// The current implementation of [`SparseSecondaryMap`] requires [`std`] and is /// thus not available in `no_std` environments. /// /// [`SecondaryMap`]: crate::SecondaryMap /// [`HashMap`]: std::collections::HashMap /// /// Example usage: /// /// ``` /// # use slotmap::*; /// let mut players = SlotMap::new(); /// let mut health = SparseSecondaryMap::new(); /// let mut ammo = SparseSecondaryMap::new(); /// /// let alice = players.insert("alice"); /// let bob = players.insert("bob"); /// /// for p in players.keys() { /// health.insert(p, 100); /// ammo.insert(p, 30); /// } /// /// // Alice attacks Bob with all her ammo! /// health[bob] -= ammo[alice] * 3; /// ammo[alice] = 0; /// ``` #[derive(Debug, Clone)] pub struct SparseSecondaryMap { slots: HashMap, S>, _k: PhantomData K>, } impl SparseSecondaryMap { /// Constructs a new, empty [`SparseSecondaryMap`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sec: SparseSecondaryMap = SparseSecondaryMap::new(); /// ``` pub fn new() -> Self { Self::with_capacity(0) } /// Creates an empty [`SparseSecondaryMap`] with the given capacity of slots. /// /// The secondary map will not reallocate until it holds at least `capacity` /// slots. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm: SlotMap<_, i32> = SlotMap::with_capacity(10); /// let mut sec: SparseSecondaryMap = /// SparseSecondaryMap::with_capacity(sm.capacity()); /// ``` pub fn with_capacity(capacity: usize) -> Self { Self { slots: HashMap::with_capacity(capacity), _k: PhantomData, } } } impl SparseSecondaryMap { /// Creates an empty [`SparseSecondaryMap`] which will use the given hash /// builder to hash keys. /// /// The secondary map will not reallocate until it holds at least `capacity` /// slots. /// /// # Examples /// /// ``` /// # use std::collections::hash_map::RandomState; /// # use slotmap::*; /// let mut sm: SlotMap<_, i32> = SlotMap::with_capacity(10); /// let mut sec: SparseSecondaryMap = /// SparseSecondaryMap::with_hasher(RandomState::new()); /// ``` pub fn with_hasher(hash_builder: S) -> Self { Self { slots: HashMap::with_hasher(hash_builder), _k: PhantomData, } } /// Creates an empty [`SparseSecondaryMap`] with the given capacity of slots, /// using `hash_builder` to hash the keys. /// /// The secondary map will not reallocate until it holds at least `capacity` /// slots. /// /// # Examples /// /// ``` /// # use std::collections::hash_map::RandomState; /// # use slotmap::*; /// let mut sm: SlotMap<_, i32> = SlotMap::with_capacity(10); /// let mut sec: SparseSecondaryMap = /// SparseSecondaryMap::with_capacity_and_hasher(10, RandomState::new()); /// ``` pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { Self { slots: HashMap::with_capacity_and_hasher(capacity, hash_builder), _k: PhantomData, } } /// Returns the number of elements in the secondary map. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let k = sm.insert(4); /// let mut squared = SparseSecondaryMap::new(); /// assert_eq!(squared.len(), 0); /// squared.insert(k, 16); /// assert_eq!(squared.len(), 1); /// ``` pub fn len(&self) -> usize { self.slots.len() } /// Returns if the secondary map is empty. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sec: SparseSecondaryMap = SparseSecondaryMap::new(); /// assert!(sec.is_empty()); /// ``` pub fn is_empty(&self) -> bool { self.slots.is_empty() } /// Returns the number of elements the [`SparseSecondaryMap`] can hold without /// reallocating. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sec: SparseSecondaryMap = SparseSecondaryMap::with_capacity(10); /// assert!(sec.capacity() >= 10); /// ``` pub fn capacity(&self) -> usize { self.slots.capacity() } /// Reserves capacity for at least `additional` more slots in the /// [`SparseSecondaryMap`]. The collection may reserve more space to avoid /// frequent reallocations. /// /// # Panics /// /// Panics if the new allocation size overflows [`usize`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sec: SparseSecondaryMap = SparseSecondaryMap::new(); /// sec.reserve(10); /// assert!(sec.capacity() >= 10); /// ``` pub fn reserve(&mut self, additional: usize) { self.slots.reserve(additional); } /// Tries to reserve capacity for at least `additional` more slots in the /// [`SparseSecondaryMap`]. The collection may reserve more space to avoid /// frequent reallocations. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sec: SparseSecondaryMap = SparseSecondaryMap::new(); /// sec.try_reserve(10).unwrap(); /// assert!(sec.capacity() >= 10); /// ``` #[cfg(all(nightly, any(doc, feature = "unstable")))] #[cfg_attr(all(nightly, doc), doc(cfg(feature = "unstable")))] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.slots.try_reserve(additional) } /// Returns [`true`] if the secondary map contains `key`. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let k = sm.insert(4); /// let mut squared = SparseSecondaryMap::new(); /// assert!(!squared.contains_key(k)); /// squared.insert(k, 16); /// assert!(squared.contains_key(k)); /// ``` pub fn contains_key(&self, key: K) -> bool { let kd = key.data(); self.slots.get(&kd.idx).map_or(false, |slot| slot.version == kd.version.get()) } /// Inserts a value into the secondary map at the given `key`. Can silently /// fail if `key` was removed from the originating slot map. /// /// Returns [`None`] if this key was not present in the map, the old value /// otherwise. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let k = sm.insert(4); /// let mut squared = SparseSecondaryMap::new(); /// assert_eq!(squared.insert(k, 0), None); /// assert_eq!(squared.insert(k, 4), Some(0)); /// // You don't have to use insert if the key is already in the secondary map. /// squared[k] *= squared[k]; /// assert_eq!(squared[k], 16); /// ``` pub fn insert(&mut self, key: K, value: V) -> Option { if key.is_null() { return None; } let kd = key.data(); if let Some(slot) = self.slots.get_mut(&kd.idx) { if slot.version == kd.version.get() { return Some(std::mem::replace(&mut slot.value, value)); } // Don't replace existing newer values. if is_older_version(kd.version.get(), slot.version) { return None; } *slot = Slot { version: kd.version.get(), value, }; return None; } self.slots.insert(kd.idx, Slot { version: kd.version.get(), value, }); None } /// Removes a key from the secondary map, returning the value at the key if /// the key was not previously removed. If `key` was removed from the /// originating slot map, its corresponding entry in the secondary map may /// or may not already be removed. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut squared = SparseSecondaryMap::new(); /// let k = sm.insert(4); /// squared.insert(k, 16); /// squared.remove(k); /// assert!(!squared.contains_key(k)); /// /// // It's not necessary to remove keys deleted from the primary slot map, they /// // get deleted automatically when their slots are reused on a subsequent insert. /// squared.insert(k, 16); /// sm.remove(k); // Remove k from the slot map, making an empty slot. /// let new_k = sm.insert(2); // Since sm only has one empty slot, this reuses it. /// assert!(!squared.contains_key(new_k)); // Space reuse does not mean equal keys. /// assert!(squared.contains_key(k)); // Slot has not been reused in squared yet. /// squared.insert(new_k, 4); /// assert!(!squared.contains_key(k)); // Old key is no longer available. /// ``` pub fn remove(&mut self, key: K) -> Option { let kd = key.data(); if let hash_map::Entry::Occupied(entry) = self.slots.entry(kd.idx) { if entry.get().version == kd.version.get() { return Some(entry.remove_entry().1.value); } } None } /// Retains only the elements specified by the predicate. /// /// In other words, remove all key-value pairs `(k, v)` such that /// `f(k, &mut v)` returns false. This method invalidates any removed keys. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let k1 = sm.insert(0); sec.insert(k1, 10); /// let k2 = sm.insert(1); sec.insert(k2, 11); /// let k3 = sm.insert(2); sec.insert(k3, 12); /// /// sec.retain(|key, val| key == k1 || *val == 11); /// /// assert!(sec.contains_key(k1)); /// assert!(sec.contains_key(k2)); /// assert!(!sec.contains_key(k3)); /// /// assert_eq!(2, sec.len()); /// ``` pub fn retain(&mut self, mut f: F) where F: FnMut(K, &mut V) -> bool, { self.slots.retain(|&idx, slot| { let key = KeyData::new(idx, slot.version).into(); f(key, &mut slot.value) }) } /// Clears the secondary map. Keeps the allocated memory for reuse. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// for i in 0..10 { /// sec.insert(sm.insert(i), i); /// } /// assert_eq!(sec.len(), 10); /// sec.clear(); /// assert_eq!(sec.len(), 0); /// ``` pub fn clear(&mut self) { self.slots.clear(); } /// Clears the slot map, returning all key-value pairs in arbitrary order as /// an iterator. Keeps the allocated memory for reuse. /// /// When the iterator is dropped all elements in the slot map are removed, /// even if the iterator was not fully consumed. If the iterator is not /// dropped (using e.g. [`std::mem::forget`]), only the elements that were /// iterated over are removed. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::iter::FromIterator; /// let mut sm = SlotMap::new(); /// let k = sm.insert(0); /// let mut sec = SparseSecondaryMap::new(); /// sec.insert(k, 1); /// let v: Vec<_> = sec.drain().collect(); /// assert_eq!(sec.len(), 0); /// assert_eq!(v, vec![(k, 1)]); /// ``` pub fn drain(&mut self) -> Drain { Drain { inner: self.slots.drain(), _k: PhantomData, } } /// Returns a reference to the value corresponding to the key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("foo"); /// let mut sec = SparseSecondaryMap::new(); /// sec.insert(key, "bar"); /// assert_eq!(sec.get(key), Some(&"bar")); /// sec.remove(key); /// assert_eq!(sec.get(key), None); /// ``` pub fn get(&self, key: K) -> Option<&V> { let kd = key.data(); self.slots .get(&kd.idx) .filter(|slot| slot.version == kd.version.get()) .map(|slot| &slot.value) } /// Returns a reference to the value corresponding to the key without /// version or bounds checking. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true. Otherwise it is /// potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("foo"); /// let mut sec = SparseSecondaryMap::new(); /// sec.insert(key, "bar"); /// assert_eq!(unsafe { sec.get_unchecked(key) }, &"bar"); /// sec.remove(key); /// // sec.get_unchecked(key) is now dangerous! /// ``` pub unsafe fn get_unchecked(&self, key: K) -> &V { debug_assert!(self.contains_key(key)); self.get(key).unwrap_unchecked_() } /// Returns a mutable reference to the value corresponding to the key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("test"); /// let mut sec = SparseSecondaryMap::new(); /// sec.insert(key, 3.5); /// if let Some(x) = sec.get_mut(key) { /// *x += 3.0; /// } /// assert_eq!(sec[key], 6.5); /// ``` pub fn get_mut(&mut self, key: K) -> Option<&mut V> { let kd = key.data(); self.slots .get_mut(&kd.idx) .filter(|slot| slot.version == kd.version.get()) .map(|slot| &mut slot.value) } /// Returns a mutable reference to the value corresponding to the key /// without version or bounds checking. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true. Otherwise it is /// potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let key = sm.insert("foo"); /// let mut sec = SparseSecondaryMap::new(); /// sec.insert(key, "bar"); /// unsafe { *sec.get_unchecked_mut(key) = "baz" }; /// assert_eq!(sec[key], "baz"); /// sec.remove(key); /// // sec.get_unchecked_mut(key) is now dangerous! /// ``` pub unsafe fn get_unchecked_mut(&mut self, key: K) -> &mut V { debug_assert!(self.contains_key(key)); self.get_mut(key).unwrap_unchecked_() } /// Returns mutable references to the values corresponding to the given /// keys. All keys must be valid and disjoint, otherwise None is returned. /// /// Requires at least stable Rust version 1.51. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// let ka = sm.insert(()); sec.insert(ka, "butter"); /// let kb = sm.insert(()); sec.insert(kb, "apples"); /// let kc = sm.insert(()); sec.insert(kc, "charlie"); /// sec.remove(kc); // Make key c invalid. /// assert_eq!(sec.get_disjoint_mut([ka, kb, kc]), None); // Has invalid key. /// assert_eq!(sec.get_disjoint_mut([ka, ka]), None); // Not disjoint. /// let [a, b] = sec.get_disjoint_mut([ka, kb]).unwrap(); /// std::mem::swap(a, b); /// assert_eq!(sec[ka], "apples"); /// assert_eq!(sec[kb], "butter"); /// ``` #[cfg(has_min_const_generics)] pub fn get_disjoint_mut(&mut self, keys: [K; N]) -> Option<[&mut V; N]> { // Create an uninitialized array of `MaybeUninit`. The `assume_init` is // safe because the type we are claiming to have initialized here is a // bunch of `MaybeUninit`s, which do not require initialization. let mut ptrs: [MaybeUninit<*mut V>; N] = unsafe { MaybeUninit::uninit().assume_init() }; let mut i = 0; while i < N { let kd = keys[i].data(); match self.slots.get_mut(&kd.idx) { Some(Slot { version, value }) if *version == kd.version.get() => { // This key is valid, and the slot is occupied. Temporarily // make the version even so duplicate keys would show up as // invalid, since keys always have an odd version. This // gives us a linear time disjointness check. ptrs[i] = MaybeUninit::new(&mut *value); *version ^= 1; }, _ => break, } i += 1; } // Undo temporary even versions. for k in &keys[0..i] { match self.slots.get_mut(&k.data().idx) { Some(Slot { version, .. }) => { *version ^= 1; }, _ => unsafe { core::hint::unreachable_unchecked() }, } } if i == N { // All were valid and disjoint. Some(unsafe { core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs) }) } else { None } } /// Returns mutable references to the values corresponding to the given /// keys. All keys must be valid and disjoint. /// /// Requires at least stable Rust version 1.51. /// /// # Safety /// /// This should only be used if `contains_key(key)` is true for every given /// key and no two keys are equal. Otherwise it is potentially unsafe. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// let ka = sm.insert(()); sec.insert(ka, "butter"); /// let kb = sm.insert(()); sec.insert(kb, "apples"); /// let [a, b] = unsafe { sec.get_disjoint_unchecked_mut([ka, kb]) }; /// std::mem::swap(a, b); /// assert_eq!(sec[ka], "apples"); /// assert_eq!(sec[kb], "butter"); /// ``` #[cfg(has_min_const_generics)] pub unsafe fn get_disjoint_unchecked_mut( &mut self, keys: [K; N], ) -> [&mut V; N] { // Safe, see get_disjoint_mut. let mut ptrs: [MaybeUninit<*mut V>; N] = MaybeUninit::uninit().assume_init(); for i in 0..N { ptrs[i] = MaybeUninit::new(self.get_unchecked_mut(keys[i])); } core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs) } /// An iterator visiting all key-value pairs in arbitrary order. The /// iterator element type is `(K, &'a V)`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// let k0 = sm.insert(0); sec.insert(k0, 10); /// let k1 = sm.insert(1); sec.insert(k1, 11); /// let k2 = sm.insert(2); sec.insert(k2, 12); /// /// for (k, v) in sec.iter() { /// println!("key: {:?}, val: {}", k, v); /// } /// ``` pub fn iter(&self) -> Iter { Iter { inner: self.slots.iter(), _k: PhantomData, } } /// An iterator visiting all key-value pairs in arbitrary order, with /// mutable references to the values. The iterator element type is /// `(K, &'a mut V)`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// let k0 = sm.insert(1); sec.insert(k0, 10); /// let k1 = sm.insert(2); sec.insert(k1, 20); /// let k2 = sm.insert(3); sec.insert(k2, 30); /// /// for (k, v) in sec.iter_mut() { /// if k != k1 { /// *v *= -1; /// } /// } /// /// assert_eq!(sec[k0], -10); /// assert_eq!(sec[k1], 20); /// assert_eq!(sec[k2], -30); /// ``` pub fn iter_mut(&mut self) -> IterMut { IterMut { inner: self.slots.iter_mut(), _k: PhantomData, } } /// An iterator visiting all keys in arbitrary order. The iterator element /// type is `K`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// let k0 = sm.insert(1); sec.insert(k0, 10); /// let k1 = sm.insert(2); sec.insert(k1, 20); /// let k2 = sm.insert(3); sec.insert(k2, 30); /// let keys: HashSet<_> = sec.keys().collect(); /// let check: HashSet<_> = vec![k0, k1, k2].into_iter().collect(); /// assert_eq!(keys, check); /// ``` pub fn keys(&self) -> Keys { Keys { inner: self.iter() } } /// An iterator visiting all values in arbitrary order. The iterator element /// type is `&'a V`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// let k0 = sm.insert(1); sec.insert(k0, 10); /// let k1 = sm.insert(2); sec.insert(k1, 20); /// let k2 = sm.insert(3); sec.insert(k2, 30); /// let values: HashSet<_> = sec.values().collect(); /// let check: HashSet<_> = vec![&10, &20, &30].into_iter().collect(); /// assert_eq!(values, check); /// ``` pub fn values(&self) -> Values { Values { inner: self.iter() } } /// An iterator visiting all values mutably in arbitrary order. The iterator /// element type is `&'a mut V`. /// /// This function must iterate over all slots, empty or not. In the face of /// many deleted elements it can be inefficient. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use std::collections::HashSet; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// sec.insert(sm.insert(1), 10); /// sec.insert(sm.insert(2), 20); /// sec.insert(sm.insert(3), 30); /// sec.values_mut().for_each(|n| { *n *= 3 }); /// let values: HashSet<_> = sec.into_iter().map(|(_k, v)| v).collect(); /// let check: HashSet<_> = vec![30, 60, 90].into_iter().collect(); /// assert_eq!(values, check); /// ``` pub fn values_mut(&mut self) -> ValuesMut { ValuesMut { inner: self.iter_mut(), } } /// Gets the given key's corresponding [`Entry`] in the map for in-place /// manipulation. May return [`None`] if the key was removed from the /// originating slot map. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// let k = sm.insert(1); /// let v = sec.entry(k).unwrap().or_insert(10); /// assert_eq!(*v, 10); /// ``` pub fn entry(&mut self, key: K) -> Option> { if key.is_null() { return None; } let kd = key.data(); // Until we can map an OccupiedEntry to a VacantEntry I don't think // there is a way to avoid this extra lookup. if let hash_map::Entry::Occupied(o) = self.slots.entry(kd.idx) { if o.get().version != kd.version.get() { // Which is outdated, our key or the slot? if is_older_version(o.get().version, kd.version.get()) { o.remove(); } else { return None; } } } Some(match self.slots.entry(kd.idx) { hash_map::Entry::Occupied(inner) => { // We know for certain that this entry's key matches ours due // to the previous if block. Entry::Occupied(OccupiedEntry { inner, kd, _k: PhantomData, }) }, hash_map::Entry::Vacant(inner) => Entry::Vacant(VacantEntry { inner, kd, _k: PhantomData, }), }) } } impl Default for SparseSecondaryMap where K: Key, S: hash::BuildHasher + Default, { fn default() -> Self { Self::with_hasher(Default::default()) } } impl Index for SparseSecondaryMap where K: Key, S: hash::BuildHasher, { type Output = V; fn index(&self, key: K) -> &V { match self.get(key) { Some(r) => r, None => panic!("invalid SparseSecondaryMap key used"), } } } impl IndexMut for SparseSecondaryMap where K: Key, S: hash::BuildHasher, { fn index_mut(&mut self, key: K) -> &mut V { match self.get_mut(key) { Some(r) => r, None => panic!("invalid SparseSecondaryMap key used"), } } } impl PartialEq for SparseSecondaryMap where K: Key, V: PartialEq, S: hash::BuildHasher, { fn eq(&self, other: &Self) -> bool { if self.len() != other.len() { return false; } self.iter() .all(|(key, value)| other.get(key).map_or(false, |other_value| *value == *other_value)) } } impl Eq for SparseSecondaryMap where K: Key, V: Eq, S: hash::BuildHasher, { } impl FromIterator<(K, V)> for SparseSecondaryMap where K: Key, S: hash::BuildHasher + Default, { fn from_iter>(iter: I) -> Self { let mut sec = Self::default(); sec.extend(iter); sec } } impl Extend<(K, V)> for SparseSecondaryMap where K: Key, S: hash::BuildHasher, { fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); for (k, v) in iter { self.insert(k, v); } } } impl<'a, K, V, S> Extend<(K, &'a V)> for SparseSecondaryMap where K: Key, V: 'a + Copy, S: hash::BuildHasher, { fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); for (k, v) in iter { self.insert(k, *v); } } } /// A view into a occupied entry in a [`SparseSecondaryMap`]. It is part of the /// [`Entry`] enum. #[derive(Debug)] pub struct OccupiedEntry<'a, K: Key, V> { inner: hash_map::OccupiedEntry<'a, u32, Slot>, kd: KeyData, _k: PhantomData K>, } /// A view into a vacant entry in a [`SparseSecondaryMap`]. It is part of the /// [`Entry`] enum. #[derive(Debug)] pub struct VacantEntry<'a, K: Key, V> { inner: hash_map::VacantEntry<'a, u32, Slot>, kd: KeyData, _k: PhantomData K>, } /// A view into a single entry in a [`SparseSecondaryMap`], which may either be /// vacant or occupied. /// /// This `enum` is constructed using [`SparseSecondaryMap::entry`]. #[derive(Debug)] pub enum Entry<'a, K: Key, V> { /// An occupied entry. Occupied(OccupiedEntry<'a, K, V>), /// A vacant entry. Vacant(VacantEntry<'a, K, V>), } impl<'a, K: Key, V> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting the default if empty, and /// returns a mutable reference to the value in the entry. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let k = sm.insert("poneyland"); /// let v = sec.entry(k).unwrap().or_insert(10); /// assert_eq!(*v, 10); /// *sec.entry(k).unwrap().or_insert(1) *= 2; /// assert_eq!(sec[k], 20); /// ``` pub fn or_insert(self, default: V) -> &'a mut V { self.or_insert_with(|| default) } /// Ensures a value is in the entry by inserting the result of the default /// function if empty, and returns a mutable reference to the value in the /// entry. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let k = sm.insert(1); /// let v = sec.entry(k).unwrap().or_insert_with(|| "foobar".to_string()); /// assert_eq!(v, &"foobar"); /// ``` pub fn or_insert_with V>(self, default: F) -> &'a mut V { match self { Entry::Occupied(x) => x.into_mut(), Entry::Vacant(x) => x.insert(default()), } } /// Returns this entry's key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec: SparseSecondaryMap<_, ()> = SparseSecondaryMap::new(); /// /// let k = sm.insert(1); /// let entry = sec.entry(k).unwrap(); /// assert_eq!(entry.key(), k); /// ``` pub fn key(&self) -> K { match self { Entry::Occupied(entry) => entry.kd.into(), Entry::Vacant(entry) => entry.kd.into(), } } /// Provides in-place mutable access to an occupied entry before any /// potential inserts into the map. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 0); /// sec.entry(k).unwrap().and_modify(|x| *x = 1); /// /// assert_eq!(sec[k], 1) /// ``` pub fn and_modify(self, f: F) -> Self where F: FnOnce(&mut V), { match self { Entry::Occupied(mut entry) => { f(entry.get_mut()); Entry::Occupied(entry) }, Entry::Vacant(entry) => Entry::Vacant(entry), } } } impl<'a, K: Key, V: Default> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec: SparseSecondaryMap<_, Option> = SparseSecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.entry(k).unwrap().or_default(); /// assert_eq!(sec[k], None) /// ``` pub fn or_default(self) -> &'a mut V { self.or_insert_with(Default::default) } } impl<'a, K: Key, V> OccupiedEntry<'a, K, V> { /// Returns this entry's key. /// /// # Examples /// /// ``` /// # use slotmap::*; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 10); /// assert_eq!(sec.entry(k).unwrap().key(), k); /// ``` pub fn key(&self) -> K { self.kd.into() } /// Removes the entry from the slot map and returns the key and value. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::sparse_secondary::Entry; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let foo = sm.insert("foo"); /// sec.entry(foo).unwrap().or_insert("bar"); /// /// if let Some(Entry::Occupied(o)) = sec.entry(foo) { /// assert_eq!(o.remove_entry(), (foo, "bar")); /// } /// assert_eq!(sec.contains_key(foo), false); /// ``` pub fn remove_entry(self) -> (K, V) { (self.kd.into(), self.remove()) } /// Gets a reference to the value in the entry. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::sparse_secondary::Entry; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 10); /// /// if let Entry::Occupied(o) = sec.entry(k).unwrap() { /// assert_eq!(*o.get(), 10); /// } /// ``` pub fn get(&self) -> &V { &self.inner.get().value } /// Gets a mutable reference to the value in the entry. /// /// If you need a reference to the [`OccupiedEntry`] which may outlive the /// destruction of the [`Entry`] value, see [`into_mut`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::sparse_secondary::Entry; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 10); /// if let Entry::Occupied(mut o) = sec.entry(k).unwrap() { /// *o.get_mut() = 20; /// } /// assert_eq!(sec[k], 20); /// ``` /// /// [`into_mut`]: Self::into_mut pub fn get_mut(&mut self) -> &mut V { &mut self.inner.get_mut().value } /// Converts the [`OccupiedEntry`] into a mutable reference to the value in /// the entry with a lifetime bound to the map itself. /// /// If you need multiple references to the [`OccupiedEntry`], see /// [`get_mut`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::sparse_secondary::Entry; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let k = sm.insert(0); /// sec.insert(k, 0); /// /// let r; /// if let Entry::Occupied(o) = sec.entry(k).unwrap() { /// r = o.into_mut(); // v outlives the entry. /// } else { /// r = sm.get_mut(k).unwrap(); /// } /// *r = 1; /// assert_eq!((sm[k], sec[k]), (0, 1)); /// ``` /// /// [`get_mut`]: Self::get_mut pub fn into_mut(self) -> &'a mut V { &mut self.inner.into_mut().value } /// Sets the value of the entry, and returns the entry's old value. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::sparse_secondary::Entry; /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 10); /// /// if let Entry::Occupied(mut o) = sec.entry(k).unwrap() { /// let v = o.insert(20); /// assert_eq!(v, 10); /// assert_eq!(*o.get(), 20); /// } /// ``` pub fn insert(&mut self, value: V) -> V { std::mem::replace(self.get_mut(), value) } /// Takes the value out of the entry, and returns it. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::sparse_secondary::Entry; /// /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let k = sm.insert(1); /// sec.insert(k, 10); /// /// if let Entry::Occupied(mut o) = sec.entry(k).unwrap() { /// assert_eq!(o.remove(), 10); /// assert_eq!(sec.contains_key(k), false); /// } /// ``` pub fn remove(self) -> V { self.inner.remove().value } } impl<'a, K: Key, V> VacantEntry<'a, K, V> { /// Gets the key that would be used when inserting a value through the /// [`VacantEntry`]. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::sparse_secondary::Entry; /// /// let mut sm = SlotMap::new(); /// let mut sec: SparseSecondaryMap<_, ()> = SparseSecondaryMap::new(); /// /// let k = sm.insert(1); /// /// if let Entry::Vacant(v) = sec.entry(k).unwrap() { /// assert_eq!(v.key(), k); /// } /// ``` pub fn key(&self) -> K { self.kd.into() } /// Sets the value of the entry with the [`VacantEntry`]'s key, and returns /// a mutable reference to it. /// /// # Examples /// /// ``` /// # use slotmap::*; /// # use slotmap::sparse_secondary::Entry; /// /// let mut sm = SlotMap::new(); /// let mut sec = SparseSecondaryMap::new(); /// /// let k = sm.insert(1); /// /// if let Entry::Vacant(v) = sec.entry(k).unwrap() { /// let new_val = v.insert(3); /// assert_eq!(new_val, &mut 3); /// } /// ``` pub fn insert(self, value: V) -> &'a mut V { &mut self .inner .insert(Slot { version: self.kd.version.get(), value, }) .value } } // Iterators. /// A draining iterator for [`SparseSecondaryMap`]. /// /// This iterator is created by [`SparseSecondaryMap::drain`]. #[derive(Debug)] pub struct Drain<'a, K: Key + 'a, V: 'a> { inner: hash_map::Drain<'a, u32, Slot>, _k: PhantomData K>, } /// An iterator that moves key-value pairs out of a [`SparseSecondaryMap`]. /// /// This iterator is created by calling the `into_iter` method on [`SparseSecondaryMap`], /// provided by the [`IntoIterator`] trait. #[derive(Debug)] pub struct IntoIter { inner: hash_map::IntoIter>, _k: PhantomData K>, } /// An iterator over the key-value pairs in a [`SparseSecondaryMap`]. /// /// This iterator is created by [`SparseSecondaryMap::iter`]. #[derive(Debug)] pub struct Iter<'a, K: Key + 'a, V: 'a> { inner: hash_map::Iter<'a, u32, Slot>, _k: PhantomData K>, } impl<'a, K: 'a + Key, V: 'a> Clone for Iter<'a, K, V> { fn clone(&self) -> Self { Iter { inner: self.inner.clone(), _k: self._k, } } } /// A mutable iterator over the key-value pairs in a [`SparseSecondaryMap`]. /// /// This iterator is created by [`SparseSecondaryMap::iter_mut`]. #[derive(Debug)] pub struct IterMut<'a, K: Key + 'a, V: 'a> { inner: hash_map::IterMut<'a, u32, Slot>, _k: PhantomData K>, } /// An iterator over the keys in a [`SparseSecondaryMap`]. /// /// This iterator is created by [`SparseSecondaryMap::keys`]. #[derive(Debug)] pub struct Keys<'a, K: Key + 'a, V: 'a> { inner: Iter<'a, K, V>, } impl<'a, K: 'a + Key, V: 'a> Clone for Keys<'a, K, V> { fn clone(&self) -> Self { Keys { inner: self.inner.clone(), } } } /// An iterator over the values in a [`SparseSecondaryMap`]. /// /// This iterator is created by [`SparseSecondaryMap::values`]. #[derive(Debug)] pub struct Values<'a, K: Key + 'a, V: 'a> { inner: Iter<'a, K, V>, } impl<'a, K: 'a + Key, V: 'a> Clone for Values<'a, K, V> { fn clone(&self) -> Self { Values { inner: self.inner.clone(), } } } /// A mutable iterator over the values in a [`SparseSecondaryMap`]. /// /// This iterator is created by [`SparseSecondaryMap::values_mut`]. #[derive(Debug)] pub struct ValuesMut<'a, K: Key + 'a, V: 'a> { inner: IterMut<'a, K, V>, } impl<'a, K: Key, V> Iterator for Drain<'a, K, V> { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { self.inner.next().map(|(idx, slot)| { let key = KeyData::new(idx, slot.version).into(); (key, slot.value) }) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Drop for Drain<'a, K, V> { fn drop(&mut self) { self.for_each(|_drop| {}); } } impl Iterator for IntoIter { type Item = (K, V); fn next(&mut self) -> Option<(K, V)> { self.inner.next().map(|(idx, slot)| { let key = KeyData::new(idx, slot.version).into(); (key, slot.value) }) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Iterator for Iter<'a, K, V> { type Item = (K, &'a V); fn next(&mut self) -> Option<(K, &'a V)> { self.inner.next().map(|(&idx, slot)| { let key = KeyData::new(idx, slot.version).into(); (key, &slot.value) }) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Iterator for IterMut<'a, K, V> { type Item = (K, &'a mut V); fn next(&mut self) -> Option<(K, &'a mut V)> { self.inner.next().map(|(&idx, slot)| { let key = KeyData::new(idx, slot.version).into(); (key, &mut slot.value) }) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Iterator for Keys<'a, K, V> { type Item = K; fn next(&mut self) -> Option { self.inner.next().map(|(key, _)| key) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Iterator for Values<'a, K, V> { type Item = &'a V; fn next(&mut self) -> Option<&'a V> { self.inner.next().map(|(_, value)| value) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K: Key, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; fn next(&mut self) -> Option<&'a mut V> { self.inner.next().map(|(_, value)| value) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a, K, V, S> IntoIterator for &'a SparseSecondaryMap where K: Key, S: hash::BuildHasher, { type Item = (K, &'a V); type IntoIter = Iter<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, K, V, S> IntoIterator for &'a mut SparseSecondaryMap where K: Key, S: hash::BuildHasher, { type Item = (K, &'a mut V); type IntoIter = IterMut<'a, K, V>; fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl IntoIterator for SparseSecondaryMap where K: Key, S: hash::BuildHasher, { type Item = (K, V); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter { inner: self.slots.into_iter(), _k: PhantomData, } } } impl<'a, K: Key, V> FusedIterator for Iter<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for IterMut<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Keys<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Values<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for ValuesMut<'a, K, V> {} impl<'a, K: Key, V> FusedIterator for Drain<'a, K, V> {} impl FusedIterator for IntoIter {} impl<'a, K: Key, V> ExactSizeIterator for Iter<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for IterMut<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Keys<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Values<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for ValuesMut<'a, K, V> {} impl<'a, K: Key, V> ExactSizeIterator for Drain<'a, K, V> {} impl ExactSizeIterator for IntoIter {} // Serialization with serde. #[cfg(feature = "serde")] mod serialize { use serde::{Deserialize, Deserializer, Serialize, Serializer}; use super::*; use crate::SecondaryMap; impl Serialize for SparseSecondaryMap where K: Key, V: Serialize, H: hash::BuildHasher, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut serde_sec = SecondaryMap::new(); for (k, v) in self { serde_sec.insert(k, v); } serde_sec.serialize(serializer) } } impl<'de, K, V, S> Deserialize<'de> for SparseSecondaryMap where K: Key, V: Deserialize<'de>, S: hash::BuildHasher + Default, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let serde_sec: SecondaryMap = Deserialize::deserialize(deserializer)?; let mut sec = Self::default(); for (k, v) in serde_sec { sec.insert(k, v); } Ok(sec) } } } #[cfg(test)] mod tests { use std::collections::HashMap; use quickcheck::quickcheck; use crate::*; #[test] fn custom_hasher() { type FastSparseSecondaryMap = SparseSecondaryMap; let mut sm = SlotMap::new(); let mut sec = FastSparseSecondaryMap::default(); let key1 = sm.insert(42); sec.insert(key1, 1234); assert_eq!(sec[key1], 1234); assert_eq!(sec.len(), 1); let sec2 = sec.iter().map(|(k, &v)| (k, v)).collect::>(); assert_eq!(sec, sec2); } #[cfg(all(nightly, feature = "unstable"))] #[test] fn disjoint() { // Intended to be run with miri to find any potential UB. let mut sm = SlotMap::new(); let mut sec = SparseSecondaryMap::new(); // Some churn. for i in 0..20usize { sm.insert(i); } sm.retain(|_, i| *i % 2 == 0); for (i, k) in sm.keys().enumerate() { sec.insert(k, i); } let keys: Vec<_> = sm.keys().collect(); for i in 0..keys.len() { for j in 0..keys.len() { if let Some([r0, r1]) = sec.get_disjoint_mut([keys[i], keys[j]]) { *r0 ^= *r1; *r1 = r1.wrapping_add(*r0); } else { assert!(i == j); } } } for i in 0..keys.len() { for j in 0..keys.len() { for k in 0..keys.len() { if let Some([r0, r1, r2]) = sec.get_disjoint_mut([keys[i], keys[j], keys[k]]) { *r0 ^= *r1; *r0 = r0.wrapping_add(*r2); *r1 ^= *r0; *r1 = r1.wrapping_add(*r2); *r2 ^= *r0; *r2 = r2.wrapping_add(*r1); } else { assert!(i == j || j == k || i == k); } } } } } quickcheck! { fn qc_secmap_equiv_hashmap(operations: Vec<(u8, u32)>) -> bool { let mut hm = HashMap::new(); let mut hm_keys = Vec::new(); let mut unique_key = 0u32; let mut sm = SlotMap::new(); let mut sec = SparseSecondaryMap::new(); let mut sm_keys = Vec::new(); #[cfg(not(feature = "serde"))] let num_ops = 4; #[cfg(feature = "serde")] let num_ops = 5; for (op, val) in operations { match op % num_ops { // Insert. 0 => { hm.insert(unique_key, val); hm_keys.push(unique_key); unique_key += 1; let k = sm.insert(val); sec.insert(k, val); sm_keys.push(k); } // Delete. 1 => { if hm_keys.is_empty() { continue; } let idx = val as usize % hm_keys.len(); sm.remove(sm_keys[idx]); if hm.remove(&hm_keys[idx]) != sec.remove(sm_keys[idx]) { return false; } } // Access. 2 => { if hm_keys.is_empty() { continue; } let idx = val as usize % hm_keys.len(); let (hm_key, sm_key) = (&hm_keys[idx], sm_keys[idx]); if hm.contains_key(hm_key) != sec.contains_key(sm_key) || hm.get(hm_key) != sec.get(sm_key) { return false; } } // Clone. 3 => { sec = sec.clone(); } // Serde round-trip. #[cfg(feature = "serde")] 4 => { let ser = serde_json::to_string(&sec).unwrap(); sec = serde_json::from_str(&ser).unwrap(); } _ => unreachable!(), } } let mut secv: Vec<_> = sec.values().collect(); let mut hmv: Vec<_> = hm.values().collect(); secv.sort(); hmv.sort(); secv == hmv } } } slotmap-1.0.7/src/util.rs000064400000000000000000000024160072674642500134550ustar 00000000000000use core::fmt::Debug; use core::hint::unreachable_unchecked; /// Internal stable replacement for !. #[derive(Debug)] pub enum Never {} /// Returns if a is an older version than b, taking into account wrapping of /// versions. pub fn is_older_version(a: u32, b: u32) -> bool { let diff = a.wrapping_sub(b); diff >= (1 << 31) } /// An unwrapper that checks on debug, doesn't check on release. /// UB if unwrapped on release mode when unwrap would panic. pub trait UnwrapUnchecked { // Extra underscore because unwrap_unchecked is planned to be added to the stdlib. unsafe fn unwrap_unchecked_(self) -> T; } impl UnwrapUnchecked for Option { unsafe fn unwrap_unchecked_(self) -> T { if cfg!(debug_assertions) { self.unwrap() } else { match self { Some(x) => x, None => unreachable_unchecked(), } } } } impl UnwrapUnchecked for Result { unsafe fn unwrap_unchecked_(self) -> T { if cfg!(debug_assertions) { self.unwrap() } else { match self { Ok(x) => x, Err(_) => unreachable_unchecked(), } } } }