Import 'slotmap' crate
Request Document: go/android-rust-importing-crates
For CL Reviewers: go/android3p#cl-review
Bug: 395134064
Test: m libslotmap -j
Change-Id: I7111bf50d4b3eb2e01a6672d0252a508ee8e2251
diff --git a/crates/slotmap/.android-checksum.json b/crates/slotmap/.android-checksum.json
new file mode 100644
index 0000000..e10fe44
--- /dev/null
+++ b/crates/slotmap/.android-checksum.json
@@ -0,0 +1 @@
+{"package":null,"files":{".cargo-checksum.json":"57c08da436f0cdc3d537fc1c6366c6fe71dc7a1806cf3e4829910e7a89aa7798","Android.bp":"cc5edeec5900b26a48ce93c4c12f7136f3c2ecd59a3fefd797a0aacabe1404a7","Cargo.lock":"292f5c20184e103704e1231308b31dcf2610a0b5988fafe1a00ed9021267014c","Cargo.toml":"3d51c9b22ff16fd5823bf655f945ea43f51a11c06ac23352f3604ab657c79748","LICENSE":"d7f21f23ff9af7cb69e374346d5ef8d549ae3b6eac7143c27c4fa3556af7f1a5","METADATA":"a9bb42cf7c7c5207bba63f85520a86c5c505ad451d5803f3a8ae76a0371cec30","MODULE_LICENSE_ZLIB":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"421d14e5812f85833ccf5526f2ba893b721e93c077f6a867b08d2c2365f31bba","RELEASES.md":"c3590781106a4703cbe6560ea88388bfe914398b06e729022442f54a349baeb3","build.rs":"7c69b23e7ff51ad6ce773344b3ab2c60a19dafb10606d01f27137c7ee210593f","cargo_embargo.json":"0be745f01ba4955b20f2cb5011168c4d8cd396af75c007035ec693c67b17bce7","examples/doubly_linked_list.rs":"48173f754bd384043571b44a08fa1a71b20e795f223838a5287286a611b13ba4","examples/rand_meld_heap.rs":"b23bf84b10bf5de8a66d9809dc08607c7bbc60becb69f0f580c99ba43e5bdaea","src/basic.rs":"82bbe03b66a7c9f0976b2ff8cefb34ba9007e102937861b9b60968e5bdfb8820","src/dense.rs":"a51402f8e3cce5e8deac1ea4fbb1bea2349dcc77b5c25173f5080edaf87f32cd","src/hop.rs":"1af7a3d8031bfc011e6880df71d6ca6a9b722a490359732592ea838c4ae2dede","src/lib.rs":"307bb3662808f842c2d3d2a0d58fb7090588a4223e8d1d77121f3ab4f03d8ddd","src/secondary.rs":"2b27366f63a69865b98f3198425816de1ad1c687d6757628442682e62ac3dc0f","src/sparse_secondary.rs":"f219de332f863921d42a4f7a61f0834fee72ea76ca7ab66aa2754d44f22ca9f2","src/util.rs":"a853ff0b0e7333cd18b04450416a529a5e9d7e0b12518625878d458aad72cca8"}}
\ No newline at end of file
diff --git a/crates/slotmap/.cargo-checksum.json b/crates/slotmap/.cargo-checksum.json
new file mode 100644
index 0000000..0435700
--- /dev/null
+++ b/crates/slotmap/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.lock":"94822af614b8763e4a8ea7fa8a4a76b793765e9a47ff28980584828be4ab0a3b","Cargo.toml":"ca8d3e1b9d2bc3de5e56718195aba29609f4b0a5ceb14811a55dfedef61566bc","LICENSE":"940d3c7339956aa9e8917518305b485ef2aed42df81adbf48ab3a97f0685849b","README.md":"bdce0b82cd3266b923a86f12b872caf66aa0cd5a563d8dc59004c0d73eff110a","RELEASES.md":"c0f3e7e1e54a3a1a2a699101dae4c1e5237294efc9baee8031fda5811863afc0","build.rs":"2ea8b8a95a2b88f845505c6d555dff45372b110d30f36d1ba2eb8d2ec0901839","examples/doubly_linked_list.rs":"aa3bca7a9351e8ae3d2b51de65288437ba5d1c838c7d741d9d10e753848793e8","examples/rand_meld_heap.rs":"a7ce796313981466e96ff471ad5c58b8af65b6cdc78806614c35d4d2bef85dbf","src/basic.rs":"e714da1358d7547d4fdb339f751328c09cdbbe3fa68ecc65dea5590b6895ee02","src/dense.rs":"c52218d1e35544f7a9f70a102e5e4df589eb73ea1c46aa31b1b3869c70cc53b2","src/hop.rs":"87bbb19f6bef1cd15ef9b42cdd5ff7a551541ad95aa743abc14ee037ef63b436","src/lib.rs":"f2784f1dca09ea8c2471921e3a04e7a00581dcb711b78e32025aa15142e9fe7e","src/secondary.rs":"7c86cf230a3f9efb2ad3daa99e2cf23eac90cb5d2d3dee1ceafa4151c5917345","src/sparse_secondary.rs":"2a0e8bc4c39dfc5ad4e8bc1f0eeea59de7681d8051832877644e36361f7303af","src/util.rs":"5023602a8c259d2506e087cf22dd2abb2602e77d4bb9cd39b0221c642d6f61f7"},"package":"dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"}
\ No newline at end of file
diff --git a/crates/slotmap/Android.bp b/crates/slotmap/Android.bp
new file mode 100644
index 0000000..0e9f998
--- /dev/null
+++ b/crates/slotmap/Android.bp
@@ -0,0 +1,38 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file because the changes will be overridden on upgrade.
+
+package {
+ default_applicable_licenses: ["external_rust_crates_slotmap_license"],
+ default_team: "trendy_team_android_rust",
+}
+
+license {
+ name: "external_rust_crates_slotmap_license",
+ visibility: [":__subpackages__"],
+ license_kinds: ["SPDX-license-identifier-Zlib"],
+ license_text: ["LICENSE"],
+}
+
+rust_library {
+ name: "libslotmap",
+ host_supported: true,
+ crate_name: "slotmap",
+ cargo_env_compat: true,
+ cargo_pkg_version: "1.0.7",
+ crate_root: "src/lib.rs",
+ edition: "2018",
+ features: [
+ "default",
+ "std",
+ ],
+ cfgs: [
+ "has_min_const_generics",
+ "nightly",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ product_available: true,
+ vendor_available: true,
+}
diff --git a/crates/slotmap/Cargo.lock b/crates/slotmap/Cargo.lock
new file mode 100644
index 0000000..056c97a
--- /dev/null
+++ b/crates/slotmap/Cargo.lock
@@ -0,0 +1,275 @@
+# 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"
diff --git a/crates/slotmap/Cargo.toml b/crates/slotmap/Cargo.toml
new file mode 100644
index 0000000..fb6c010
--- /dev/null
+++ b/crates/slotmap/Cargo.toml
@@ -0,0 +1,64 @@
+# 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 <orsonpeters@gmail.com>"]
+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 = []
diff --git a/crates/slotmap/LICENSE b/crates/slotmap/LICENSE
new file mode 100644
index 0000000..238d3e6
--- /dev/null
+++ b/crates/slotmap/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2021 Orson Peters <orsonpeters@gmail.com>
+
+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.
diff --git a/crates/slotmap/METADATA b/crates/slotmap/METADATA
new file mode 100644
index 0000000..b24a922
--- /dev/null
+++ b/crates/slotmap/METADATA
@@ -0,0 +1,17 @@
+name: "slotmap"
+description: "Slotmap data structure"
+third_party {
+ version: "1.0.7"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2025
+ month: 2
+ day: 11
+ }
+ homepage: "https://crates.io/crates/slotmap"
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/slotmap/slotmap-1.0.7.crate"
+ version: "1.0.7"
+ }
+}
diff --git a/crates/slotmap/MODULE_LICENSE_ZLIB b/crates/slotmap/MODULE_LICENSE_ZLIB
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/crates/slotmap/MODULE_LICENSE_ZLIB
diff --git a/crates/slotmap/README.md b/crates/slotmap/README.md
new file mode 100644
index 0000000..6cba5f4
--- /dev/null
+++ b/crates/slotmap/README.md
@@ -0,0 +1,50 @@
+# 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.
diff --git a/crates/slotmap/RELEASES.md b/crates/slotmap/RELEASES.md
new file mode 100644
index 0000000..29524d8
--- /dev/null
+++ b/crates/slotmap/RELEASES.md
@@ -0,0 +1,147 @@
+Version 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<KeyData>` 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<i32>` would be `SlotMap<DefaultKey, i32>`. 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<Key>` is optimized.
+
+
+Version 0.2.0
+=============
+Start of version history.
diff --git a/crates/slotmap/build.rs b/crates/slotmap/build.rs
new file mode 100644
index 0000000..0de58a0
--- /dev/null
+++ b/crates/slotmap/build.rs
@@ -0,0 +1,17 @@
+fn 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");
+ }
+}
diff --git a/crates/slotmap/cargo_embargo.json b/crates/slotmap/cargo_embargo.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/crates/slotmap/cargo_embargo.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/crates/slotmap/examples/doubly_linked_list.rs b/crates/slotmap/examples/doubly_linked_list.rs
new file mode 100644
index 0000000..dc5bf7a
--- /dev/null
+++ b/crates/slotmap/examples/doubly_linked_list.rs
@@ -0,0 +1,135 @@
+// 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<T> {
+ value: T,
+ prev: ListKey,
+ next: ListKey,
+}
+
+pub struct List<T> {
+ sm: SlotMap<ListKey, Node<T>>,
+ head: ListKey,
+ tail: ListKey,
+}
+
+impl<T> List<T> {
+ 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<T> {
+ self.sm.remove(self.head).map(|old_head| {
+ self.head = old_head.next;
+ old_head.value
+ })
+ }
+
+ pub fn pop_tail(&mut self) -> Option<T> {
+ self.sm.remove(self.tail).map(|old_tail| {
+ self.tail = old_tail.prev;
+ old_tail.value
+ })
+ }
+
+ pub fn remove(&mut self, key: ListKey) -> Option<T> {
+ 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);
+}
diff --git a/crates/slotmap/examples/rand_meld_heap.rs b/crates/slotmap/examples/rand_meld_heap.rs
new file mode 100644
index 0000000..d0ab951
--- /dev/null
+++ b/crates/slotmap/examples/rand_meld_heap.rs
@@ -0,0 +1,174 @@
+// 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<T> {
+ value: T,
+ children: [HeapKey; 2],
+ parent: HeapKey,
+}
+
+struct RandMeldHeap<T: Ord> {
+ sm: SlotMap<HeapKey, Node<T>>,
+ rng: std::num::Wrapping<u32>,
+ root: HeapKey,
+}
+
+impl<T: Ord + std::fmt::Debug> RandMeldHeap<T> {
+ 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<T> {
+ 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());
+ }
+}
diff --git a/crates/slotmap/src/basic.rs b/crates/slotmap/src/basic.rs
new file mode 100644
index 0000000..6eee5cc
--- /dev/null
+++ b/crates/slotmap/src/basic.rs
@@ -0,0 +1,1541 @@
+// 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<T> {
+ value: ManuallyDrop<T>,
+ next_free: u32,
+}
+
+// A slot, which represents storage for a value and a current version.
+// Can be occupied or vacant.
+struct Slot<T> {
+ u: SlotUnion<T>,
+ 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<T> Slot<T> {
+ // Is this slot occupied?
+ #[inline(always)]
+ pub fn occupied(&self) -> bool {
+ self.version % 2 > 0
+ }
+
+ pub fn get(&self) -> SlotContent<T> {
+ unsafe {
+ if self.occupied() {
+ Occupied(&*self.u.value)
+ } else {
+ Vacant(&self.u.next_free)
+ }
+ }
+ }
+
+ pub fn get_mut(&mut self) -> SlotContentMut<T> {
+ unsafe {
+ if self.occupied() {
+ OccupiedMut(&mut *self.u.value)
+ } else {
+ VacantMut(&mut self.u.next_free)
+ }
+ }
+ }
+}
+
+impl<T> Drop for Slot<T> {
+ fn drop(&mut self) {
+ if core::mem::needs_drop::<T>() && self.occupied() {
+ // This is safe because we checked that we're occupied.
+ unsafe {
+ ManuallyDrop::drop(&mut self.u.value);
+ }
+ }
+ }
+}
+
+impl<T: Clone> Clone for Slot<T> {
+ 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<T: fmt::Debug> fmt::Debug for Slot<T> {
+ 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<K: Key, V> {
+ slots: Vec<Slot<V>>,
+ free_head: u32,
+ num_elems: u32,
+ _k: PhantomData<fn(K) -> K>,
+}
+
+impl<V> SlotMap<DefaultKey, V> {
+ /// 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<K: Key, V> SlotMap<K, V> {
+ /// Constructs a new, empty [`SlotMap`] with a custom key type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use slotmap::*;
+ /// new_key_type! {
+ /// struct PositionKey;
+ /// }
+ /// let mut positions: SlotMap<PositionKey, i32> = 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
+ /// 2<sup>32</sup> - 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
+ /// 2<sup>32</sup> - 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<F>(&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
+ /// 2<sup>32</sup> - 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<F, E>(&mut self, f: F) -> Result<K, E>
+ where
+ F: FnOnce(K) -> Result<V, E>,
+ {
+ // 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<V> {
+ 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<F>(&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<K, V> {
+ 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<const N: usize>(&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<const N: usize>(
+ &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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ ValuesMut {
+ inner: self.iter_mut(),
+ }
+ }
+}
+
+impl<K: Key, V> Clone for SlotMap<K, V>
+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<K: Key, V> Default for SlotMap<K, V> {
+ fn default() -> Self {
+ Self::with_key()
+ }
+}
+
+impl<K: Key, V> Index<K> for SlotMap<K, V> {
+ type Output = V;
+
+ fn index(&self, key: K) -> &V {
+ match self.get(key) {
+ Some(r) => r,
+ None => panic!("invalid SlotMap key used"),
+ }
+ }
+}
+
+impl<K: Key, V> IndexMut<K> for SlotMap<K, V> {
+ 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<K, V>,
+ 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<K: Key, V> {
+ num_left: usize,
+ slots: Enumerate<alloc::vec::IntoIter<Slot<V>>>,
+ _k: PhantomData<fn(K) -> 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<core::slice::Iter<'a, Slot<V>>>,
+ _k: PhantomData<fn(K) -> 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<core::slice::IterMut<'a, Slot<V>>>,
+ _k: PhantomData<fn(K) -> 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<usize>) {
+ (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<K: Key, V> Iterator for IntoIter<K, V> {
+ 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<usize>) {
+ (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<usize>) {
+ (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<usize>) {
+ (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<K> {
+ self.inner.next().map(|(key, _)| key)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ 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<usize>) {
+ 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<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+impl<'a, K: Key, V> IntoIterator for &'a SlotMap<K, V> {
+ 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<K, V> {
+ type Item = (K, &'a mut V);
+ type IntoIter = IterMut<'a, K, V>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+impl<K: Key, V> IntoIterator for SlotMap<K, V> {
+ type Item = (K, V);
+ type IntoIter = IntoIter<K, V>;
+
+ 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<K: Key, V> FusedIterator for IntoIter<K, V> {}
+
+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<K: Key, V> ExactSizeIterator for IntoIter<K, V> {}
+
+// Serialization with serde.
+#[cfg(feature = "serde")]
+mod serialize {
+ use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+
+ use super::*;
+
+ #[derive(Serialize, Deserialize)]
+ struct SerdeSlot<T> {
+ value: Option<T>,
+ version: u32,
+ }
+
+ impl<T: Serialize> Serialize for Slot<T> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ 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<T>
+ where
+ T: Deserialize<'de>,
+ {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let serde_slot: SerdeSlot<T> = 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<K: Key, V: Serialize> Serialize for SlotMap<K, V> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ self.slots.serialize(serializer)
+ }
+ }
+
+ impl<'de, K, V> Deserialize<'de> for SlotMap<K, V>
+ where
+ K: Key,
+ V: Deserialize<'de>,
+ {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let mut slots: Vec<Slot<V>> = 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<usize>);
+
+ 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<DefaultKey, (DefaultKey, i32)> = 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<DefaultKey, i32> = serde_json::from_str(&ser).unwrap();
+
+ de.insert(0);
+ de.insert(1);
+ de.insert(2);
+ assert_eq!(de.len(), 3);
+ }
+}
diff --git a/crates/slotmap/src/dense.rs b/crates/slotmap/src/dense.rs
new file mode 100644
index 0000000..b5f864f
--- /dev/null
+++ b/crates/slotmap/src/dense.rs
@@ -0,0 +1,1397 @@
+//! 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<K: Key, V> {
+ keys: Vec<K>,
+ values: Vec<V>,
+ slots: Vec<Slot>,
+ free_head: u32,
+}
+
+impl<V> DenseSlotMap<DefaultKey, V> {
+ /// 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<DefaultKey, V> {
+ Self::with_capacity_and_key(capacity)
+ }
+}
+
+impl<K: Key, V> DenseSlotMap<K, V> {
+ /// Constructs a new, empty [`DenseSlotMap`] with a custom key type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use slotmap::*;
+ /// new_key_type! {
+ /// struct PositionKey;
+ /// }
+ /// let mut positions: DenseSlotMap<PositionKey, i32> = 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
+ /// 2<sup>32</sup> - 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
+ /// 2<sup>32</sup> - 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<F>(&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
+ /// 2<sup>32</sup> - 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<F, E>(&mut self, f: F) -> Result<K, E>
+ where
+ F: FnOnce(K) -> Result<V, E>,
+ {
+ 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<V> {
+ 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<F>(&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<K, V> {
+ 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<const N: usize>(&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<const N: usize>(
+ &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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ ValuesMut {
+ inner: self.iter_mut(),
+ }
+ }
+}
+
+impl<K: Key, V> Clone for DenseSlotMap<K, V>
+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<K: Key, V> Default for DenseSlotMap<K, V> {
+ fn default() -> Self {
+ Self::with_key()
+ }
+}
+
+impl<K: Key, V> Index<K> for DenseSlotMap<K, V> {
+ type Output = V;
+
+ fn index(&self, key: K) -> &V {
+ match self.get(key) {
+ Some(r) => r,
+ None => panic!("invalid DenseSlotMap key used"),
+ }
+ }
+}
+
+impl<K: Key, V> IndexMut<K> for DenseSlotMap<K, V> {
+ 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<K, V>,
+}
+
+/// 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<K, V> {
+ inner_keys: alloc::vec::IntoIter<K>,
+ inner_values: alloc::vec::IntoIter<V>,
+}
+
+/// 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<usize>) {
+ 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<K: Key, V> Iterator for IntoIter<K, V> {
+ 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<usize>) {
+ 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<usize>) {
+ 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<usize>) {
+ 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<K> {
+ self.inner.next().map(|(key, _)| key)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ 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<usize>) {
+ 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<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+impl<'a, K: 'a + Key, V> IntoIterator for &'a DenseSlotMap<K, V> {
+ 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<K, V> {
+ type Item = (K, &'a mut V);
+ type IntoIter = IterMut<'a, K, V>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+impl<K: Key, V> IntoIterator for DenseSlotMap<K, V> {
+ type Item = (K, V);
+ type IntoIter = IntoIter<K, V>;
+
+ 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<K: Key, V> FusedIterator for IntoIter<K, V> {}
+
+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<K: Key, V> ExactSizeIterator for IntoIter<K, V> {}
+
+// Serialization with serde.
+#[cfg(feature = "serde")]
+mod serialize {
+ use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+
+ use super::*;
+
+ #[derive(Serialize, Deserialize)]
+ struct SerdeSlot<T> {
+ value: Option<T>,
+ version: u32,
+ }
+
+ impl<K: Key, V: Serialize> Serialize for DenseSlotMap<K, V> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ 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<K, V> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let serde_slots: Vec<SerdeSlot<V>> = 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<usize>);
+
+ 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<DefaultKey, (DefaultKey, i32)> = 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<DefaultKey, i32> = serde_json::from_str(&ser).unwrap();
+
+ de.insert(0);
+ de.insert(1);
+ de.insert(2);
+ assert_eq!(de.len(), 3);
+ }
+}
diff --git a/crates/slotmap/src/hop.rs b/crates/slotmap/src/hop.rs
new file mode 100644
index 0000000..d5cf8b3
--- /dev/null
+++ b/crates/slotmap/src/hop.rs
@@ -0,0 +1,1684 @@
+// 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<T> {
+ value: ManuallyDrop<T>,
+ free: FreeListEntry,
+}
+
+// A slot, which represents storage for a value and a current version.
+// Can be occupied or vacant.
+struct Slot<T> {
+ u: SlotUnion<T>,
+ 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<T> Slot<T> {
+ // Is this slot occupied?
+ #[inline(always)]
+ pub fn occupied(&self) -> bool {
+ self.version % 2 == 1
+ }
+
+ pub fn get(&self) -> SlotContent<T> {
+ unsafe {
+ if self.occupied() {
+ Occupied(&*self.u.value)
+ } else {
+ Vacant(&self.u.free)
+ }
+ }
+ }
+
+ pub fn get_mut(&mut self) -> SlotContentMut<T> {
+ unsafe {
+ if self.occupied() {
+ OccupiedMut(&mut *self.u.value)
+ } else {
+ VacantMut(&mut self.u.free)
+ }
+ }
+ }
+}
+
+impl<T> Drop for Slot<T> {
+ fn drop(&mut self) {
+ if core::mem::needs_drop::<T>() && self.occupied() {
+ // This is safe because we checked that we're occupied.
+ unsafe {
+ ManuallyDrop::drop(&mut self.u.value);
+ }
+ }
+ }
+}
+
+impl<T: Clone> Clone for Slot<T> {
+ 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<T: fmt::Debug> fmt::Debug for Slot<T> {
+ 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<K: Key, V> {
+ slots: Vec<Slot<V>>,
+ num_elems: u32,
+ _k: PhantomData<fn(K) -> K>,
+}
+
+impl<V> HopSlotMap<DefaultKey, V> {
+ /// 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<K: Key, V> HopSlotMap<K, V> {
+ /// Constructs a new, empty [`HopSlotMap`] with a custom key type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use slotmap::*;
+ /// new_key_type! {
+ /// struct PositionKey;
+ /// }
+ /// let mut positions: HopSlotMap<PositionKey, i32> = 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
+ /// 2<sup>32</sup> - 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
+ /// 2<sup>32</sup> - 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<F>(&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
+ /// 2<sup>32</sup> - 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<F, E>(&mut self, f: F) -> Result<K, E>
+ where
+ F: FnOnce(K) -> Result<V, E>,
+ {
+ // 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<V> {
+ 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<F>(&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<K, V> {
+ 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<const N: usize>(&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<const N: usize>(
+ &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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ ValuesMut {
+ inner: self.iter_mut(),
+ }
+ }
+}
+
+impl<K: Key, V> Clone for HopSlotMap<K, V>
+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<K: Key, V> Default for HopSlotMap<K, V> {
+ fn default() -> Self {
+ Self::with_key()
+ }
+}
+
+impl<K: Key, V> Index<K> for HopSlotMap<K, V> {
+ type Output = V;
+
+ fn index(&self, key: K) -> &V {
+ match self.get(key) {
+ Some(r) => r,
+ None => panic!("invalid HopSlotMap key used"),
+ }
+ }
+}
+
+impl<K: Key, V> IndexMut<K> for HopSlotMap<K, V> {
+ 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<K, V>,
+}
+
+/// 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<K: Key, V> {
+ cur: usize,
+ num_left: usize,
+ slots: Vec<Slot<V>>,
+ _k: PhantomData<fn(K) -> 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<V>],
+ _k: PhantomData<fn(K) -> 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<V>],
+ _k: PhantomData<fn(K) -> 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<usize>) {
+ (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<K: Key, V> Iterator for IntoIter<K, V> {
+ 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<usize>) {
+ (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<usize>) {
+ (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<usize>) {
+ (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<K> {
+ self.inner.next().map(|(key, _)| key)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ 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<usize>) {
+ 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<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+impl<'a, K: Key, V> IntoIterator for &'a HopSlotMap<K, V> {
+ 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<K, V> {
+ type Item = (K, &'a mut V);
+ type IntoIter = IterMut<'a, K, V>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+impl<K: Key, V> IntoIterator for HopSlotMap<K, V> {
+ type Item = (K, V);
+ type IntoIter = IntoIter<K, V>;
+
+ 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<K: Key, V> FusedIterator for IntoIter<K, V> {}
+
+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<K: Key, V> ExactSizeIterator for IntoIter<K, V> {}
+
+// Serialization with serde.
+#[cfg(feature = "serde")]
+mod serialize {
+ use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+
+ use super::*;
+
+ #[derive(Serialize, Deserialize)]
+ struct SerdeSlot<T> {
+ value: Option<T>,
+ version: u32,
+ }
+
+ impl<T: Serialize> Serialize for Slot<T> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ 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<T>
+ where
+ T: Deserialize<'de>,
+ {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let serde_slot: SerdeSlot<T> = 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<K: Key, V: Serialize> Serialize for HopSlotMap<K, V> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ self.slots.serialize(serializer)
+ }
+ }
+
+ impl<'de, K: Key, V: Deserialize<'de>> Deserialize<'de> for HopSlotMap<K, V> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let mut slots: Vec<Slot<V>> = 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<usize>);
+
+ 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<DefaultKey, (DefaultKey, i32)> = 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<DefaultKey, i32> = serde_json::from_str(&ser).unwrap();
+
+ de.insert(0);
+ de.insert(1);
+ de.insert(2);
+ assert_eq!(de.len(), 3);
+ }
+}
diff --git a/crates/slotmap/src/lib.rs b/crates/slotmap/src/lib.rs
new file mode 100644
index 0000000..fb3d24d
--- /dev/null
+++ b/crates/slotmap/src/lib.rs
@@ -0,0 +1,652 @@
+#![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<sup>*</sup> 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. <sup>*</sup>After 2<sup>31</sup> 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
+//! 2<sup>32</sup> - 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<DefaultKey, Player>` you
+//! would use:
+//!
+//! ```
+//! # use slotmap::*;
+//! # #[derive(Copy, Clone)]
+//! # struct Player;
+//! new_key_type! { struct PlayerKey; }
+//! let sm: SlotMap<PlayerKey, Player> = 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<T> 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<H: Hasher>(&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<KeyData>
+ + 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<S>(&self, serializer: S) -> $crate::__impl::Result<S::Ok, S::Error>
+ where
+ S: $crate::__impl::Serializer,
+ {
+ $crate::Key::data(self).serialize(serializer)
+ }
+ }
+
+ impl<'de> $crate::__impl::Deserialize<'de> for $name {
+ fn deserialize<D>(deserializer: D) -> $crate::__impl::Result<Self, D::Error>
+ 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ 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<D>(deserializer: D) -> Result<Self, D::Error>
+ 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);
+ }
+}
diff --git a/crates/slotmap/src/secondary.rs b/crates/slotmap/src/secondary.rs
new file mode 100644
index 0000000..29d5032
--- /dev/null
+++ b/crates/slotmap/src/secondary.rs
@@ -0,0 +1,1767 @@
+//! 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<T> {
+ Occupied { value: T, version: NonZeroU32 },
+
+ Vacant,
+}
+
+use self::Slot::{Occupied, Vacant};
+
+impl<T> Slot<T> {
+ 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<T> {
+ 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<K: Key, V> {
+ slots: Vec<Slot<V>>,
+ num_elems: usize,
+ _k: PhantomData<fn(K) -> K>,
+}
+
+impl<K: Key, V> SecondaryMap<K, V> {
+ /// Constructs a new, empty [`SecondaryMap`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use slotmap::*;
+ /// let mut sec: SecondaryMap<DefaultKey, i32> = 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<DefaultKey, i32> = 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<DefaultKey, i32> = 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<DefaultKey, i32> = 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<DefaultKey, i32> = 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<DefaultKey, i32> = 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<V> {
+ 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<V> {
+ 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<F>(&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<K, V> {
+ 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<const N: usize>(&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<u32>; 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<const N: usize>(
+ &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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<Entry<K, V>> {
+ 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<K: Key, V> Default for SecondaryMap<K, V> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<K: Key, V> Index<K> for SecondaryMap<K, V> {
+ type Output = V;
+
+ fn index(&self, key: K) -> &V {
+ match self.get(key) {
+ Some(r) => r,
+ None => panic!("invalid SecondaryMap key used"),
+ }
+ }
+}
+
+impl<K: Key, V> IndexMut<K> for SecondaryMap<K, V> {
+ fn index_mut(&mut self, key: K) -> &mut V {
+ match self.get_mut(key) {
+ Some(r) => r,
+ None => panic!("invalid SecondaryMap key used"),
+ }
+ }
+}
+
+impl<K: Key, V: PartialEq> PartialEq for SecondaryMap<K, V> {
+ 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<K: Key, V: Eq> Eq for SecondaryMap<K, V> {}
+
+impl<K: Key, V> FromIterator<(K, V)> for SecondaryMap<K, V> {
+ fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
+ let mut sec = Self::new();
+ sec.extend(iter);
+ sec
+ }
+}
+
+impl<K: Key, V> Extend<(K, V)> for SecondaryMap<K, V> {
+ fn extend<I: IntoIterator<Item = (K, V)>>(&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<K, V> {
+ fn extend<I: IntoIterator<Item = (K, &'a V)>>(&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<K, V>,
+ kd: KeyData,
+ _k: PhantomData<fn(K) -> 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<K, V>,
+ kd: KeyData,
+ _k: PhantomData<fn(K) -> 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<F: FnOnce() -> 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<F>(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<i32>> = 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<K, V>,
+ 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<K: Key, V> {
+ num_left: usize,
+ slots: Enumerate<alloc::vec::IntoIter<Slot<V>>>,
+ _k: PhantomData<fn(K) -> 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<core::slice::Iter<'a, Slot<V>>>,
+ _k: PhantomData<fn(K) -> 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<core::slice::IterMut<'a, Slot<V>>>,
+ _k: PhantomData<fn(K) -> 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<usize>) {
+ (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<K: Key, V> Iterator for IntoIter<K, V> {
+ 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<usize>) {
+ (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<usize>) {
+ (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<usize>) {
+ (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<K> {
+ self.inner.next().map(|(key, _)| key)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ 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<usize>) {
+ 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<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+impl<'a, K: Key, V> IntoIterator for &'a SecondaryMap<K, V> {
+ 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<K, V> {
+ type Item = (K, &'a mut V);
+ type IntoIter = IterMut<'a, K, V>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+impl<K: Key, V> IntoIterator for SecondaryMap<K, V> {
+ type Item = (K, V);
+ type IntoIter = IntoIter<K, V>;
+
+ 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<K: Key, V> FusedIterator for IntoIter<K, V> {}
+
+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<K: Key, V> ExactSizeIterator for IntoIter<K, V> {}
+
+// Serialization with serde.
+#[cfg(feature = "serde")]
+mod serialize {
+ use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
+
+ use super::*;
+
+ #[derive(Serialize, Deserialize)]
+ struct SerdeSlot<T> {
+ value: Option<T>,
+ version: u32,
+ }
+
+ impl<T: Serialize> Serialize for Slot<T> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ 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<T>
+ where
+ T: Deserialize<'de>,
+ {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let serde_slot: SerdeSlot<T> = 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<K: Key, V: Serialize> Serialize for SecondaryMap<K, V> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ self.slots.serialize(serializer)
+ }
+ }
+
+ impl<'de, K: Key, V: Deserialize<'de>> Deserialize<'de> for SecondaryMap<K, V> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let mut slots: Vec<Slot<V>> = 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
+ }
+ }
+}
diff --git a/crates/slotmap/src/sparse_secondary.rs b/crates/slotmap/src/sparse_secondary.rs
new file mode 100644
index 0000000..0365fef
--- /dev/null
+++ b/crates/slotmap/src/sparse_secondary.rs
@@ -0,0 +1,1715 @@
+//! 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<T> {
+ 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<K: Key, V, S: hash::BuildHasher = hash_map::RandomState> {
+ slots: HashMap<u32, Slot<V>, S>,
+ _k: PhantomData<fn(K) -> K>,
+}
+
+impl<K: Key, V> SparseSecondaryMap<K, V, hash_map::RandomState> {
+ /// Constructs a new, empty [`SparseSecondaryMap`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use slotmap::*;
+ /// let mut sec: SparseSecondaryMap<DefaultKey, i32> = 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<DefaultKey, i32> =
+ /// SparseSecondaryMap::with_capacity(sm.capacity());
+ /// ```
+ pub fn with_capacity(capacity: usize) -> Self {
+ Self {
+ slots: HashMap::with_capacity(capacity),
+ _k: PhantomData,
+ }
+ }
+}
+
+impl<K: Key, V, S: hash::BuildHasher> SparseSecondaryMap<K, V, S> {
+ /// 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<DefaultKey, i32, _> =
+ /// 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<DefaultKey, i32, _> =
+ /// 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<DefaultKey, i32> = 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<DefaultKey, i32> = 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<DefaultKey, i32> = 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<DefaultKey, i32> = 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<V> {
+ 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<V> {
+ 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<F>(&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<K, V> {
+ 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<const N: usize>(&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<const N: usize>(
+ &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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<K, V> {
+ 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<Entry<K, V>> {
+ 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<K, V, S> Default for SparseSecondaryMap<K, V, S>
+where
+ K: Key,
+ S: hash::BuildHasher + Default,
+{
+ fn default() -> Self {
+ Self::with_hasher(Default::default())
+ }
+}
+
+impl<K, V, S> Index<K> for SparseSecondaryMap<K, V, S>
+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<K, V, S> IndexMut<K> for SparseSecondaryMap<K, V, S>
+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<K, V, S> PartialEq for SparseSecondaryMap<K, V, S>
+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<K, V, S> Eq for SparseSecondaryMap<K, V, S>
+where
+ K: Key,
+ V: Eq,
+ S: hash::BuildHasher,
+{
+}
+
+impl<K, V, S> FromIterator<(K, V)> for SparseSecondaryMap<K, V, S>
+where
+ K: Key,
+ S: hash::BuildHasher + Default,
+{
+ fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
+ let mut sec = Self::default();
+ sec.extend(iter);
+ sec
+ }
+}
+
+impl<K, V, S> Extend<(K, V)> for SparseSecondaryMap<K, V, S>
+where
+ K: Key,
+ S: hash::BuildHasher,
+{
+ fn extend<I: IntoIterator<Item = (K, V)>>(&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<K, V, S>
+where
+ K: Key,
+ V: 'a + Copy,
+ S: hash::BuildHasher,
+{
+ fn extend<I: IntoIterator<Item = (K, &'a V)>>(&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<V>>,
+ kd: KeyData,
+ _k: PhantomData<fn(K) -> 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<V>>,
+ kd: KeyData,
+ _k: PhantomData<fn(K) -> 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<F: FnOnce() -> 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<F>(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<i32>> = 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<V>>,
+ _k: PhantomData<fn(K) -> 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<K: Key, V> {
+ inner: hash_map::IntoIter<u32, Slot<V>>,
+ _k: PhantomData<fn(K) -> 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<V>>,
+ _k: PhantomData<fn(K) -> 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<V>>,
+ _k: PhantomData<fn(K) -> 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<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+impl<'a, K: Key, V> Drop for Drain<'a, K, V> {
+ fn drop(&mut self) {
+ self.for_each(|_drop| {});
+ }
+}
+
+impl<K: Key, V> Iterator for IntoIter<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<usize>) {
+ 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<usize>) {
+ 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<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+impl<'a, K: Key, V> Iterator for Keys<'a, K, V> {
+ type Item = K;
+
+ fn next(&mut self) -> Option<K> {
+ self.inner.next().map(|(key, _)| key)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ 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<usize>) {
+ 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<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+impl<'a, K, V, S> IntoIterator for &'a SparseSecondaryMap<K, V, S>
+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<K, V, S>
+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<K, V, S> IntoIterator for SparseSecondaryMap<K, V, S>
+where
+ K: Key,
+ S: hash::BuildHasher,
+{
+ type Item = (K, V);
+ type IntoIter = IntoIter<K, V>;
+
+ 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<K: Key, V> FusedIterator for IntoIter<K, V> {}
+
+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<K: Key, V> ExactSizeIterator for IntoIter<K, V> {}
+
+// Serialization with serde.
+#[cfg(feature = "serde")]
+mod serialize {
+ use serde::{Deserialize, Deserializer, Serialize, Serializer};
+
+ use super::*;
+ use crate::SecondaryMap;
+
+ impl<K, V, H> Serialize for SparseSecondaryMap<K, V, H>
+ where
+ K: Key,
+ V: Serialize,
+ H: hash::BuildHasher,
+ {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ 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<K, V, S>
+ where
+ K: Key,
+ V: Deserialize<'de>,
+ S: hash::BuildHasher + Default,
+ {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let serde_sec: SecondaryMap<K, V> = 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<K, V> = SparseSecondaryMap<K, V, fxhash::FxBuildHasher>;
+ 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::<FastSparseSecondaryMap<_, _>>();
+ 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
+ }
+ }
+}
diff --git a/crates/slotmap/src/util.rs b/crates/slotmap/src/util.rs
new file mode 100644
index 0000000..193552c
--- /dev/null
+++ b/crates/slotmap/src/util.rs
@@ -0,0 +1,46 @@
+use 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<T> {
+ // Extra underscore because unwrap_unchecked is planned to be added to the stdlib.
+ unsafe fn unwrap_unchecked_(self) -> T;
+}
+
+impl<T> UnwrapUnchecked<T> for Option<T> {
+ unsafe fn unwrap_unchecked_(self) -> T {
+ if cfg!(debug_assertions) {
+ self.unwrap()
+ } else {
+ match self {
+ Some(x) => x,
+ None => unreachable_unchecked(),
+ }
+ }
+ }
+}
+
+impl<T, E: Debug> UnwrapUnchecked<T> for Result<T, E> {
+ unsafe fn unwrap_unchecked_(self) -> T {
+ if cfg!(debug_assertions) {
+ self.unwrap()
+ } else {
+ match self {
+ Ok(x) => x,
+ Err(_) => unreachable_unchecked(),
+ }
+ }
+ }
+}
diff --git a/pseudo_crate/Cargo.lock b/pseudo_crate/Cargo.lock
index efb217e..6fc1d93 100644
--- a/pseudo_crate/Cargo.lock
+++ b/pseudo_crate/Cargo.lock
@@ -421,6 +421,7 @@
"signal-hook-registry",
"siphasher",
"slab",
+ "slotmap",
"smallvec",
"smccc",
"socket2",
@@ -5706,6 +5707,15 @@
]
[[package]]
+name = "slotmap"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
name = "smallvec"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/pseudo_crate/Cargo.toml b/pseudo_crate/Cargo.toml
index 040c107..84d616a 100644
--- a/pseudo_crate/Cargo.toml
+++ b/pseudo_crate/Cargo.toml
@@ -330,6 +330,7 @@
signal-hook-registry = "=1.4.2"
siphasher = "=1.0.1"
slab = "=0.4.9"
+slotmap = "=1.0.7"
smallvec = "=1.14.0"
smccc = "=0.1.1"
socket2 = "=0.5.8"
diff --git a/pseudo_crate/crate-list.txt b/pseudo_crate/crate-list.txt
index 5dd23a3..0f86736 100644
--- a/pseudo_crate/crate-list.txt
+++ b/pseudo_crate/crate-list.txt
@@ -324,6 +324,7 @@
signal-hook-registry
siphasher
slab
+slotmap
smallvec
smccc
socket2