diff --git a/Cargo.lock b/Cargo.lock index 7fc90fab49fc..d33915fd2ad1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2429,9 +2429,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.0" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" +checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ "autocfg", "hashbrown", diff --git a/third_party/rust/indexmap/.cargo-checksum.json b/third_party/rust/indexmap/.cargo-checksum.json index 7cf443999b8a..752043eec824 100644 --- a/third_party/rust/indexmap/.cargo-checksum.json +++ b/third_party/rust/indexmap/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"b2e03e7a524d10bb253021375ccc06a3d2a060d2c7c045a1a60d8bb3739b46a9","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055","README.rst":"6751ed067142c9445ffb9c201457a40bb73af76aa3c7e525fb415508abec74b1","benches/bench.rs":"dda3c7e3cd68b8f5c74dbd60189e89f0e43339cdc25dae7b1e5a9d25b1fb80a9","benches/faststring.rs":"2472b9d0d52031988cd31401357908fd850d15f1efa9f9761aa6b6779aad1889","build.rs":"558b4d0b9e9b3a44f7e1a2b69f7a7567ea721cd45cb54f4e458e850bf702f35c","src/equivalent.rs":"2e6ae24ef09a09b917f4e2b0f6288f901878e42f5080f61b1bd1afdcc90aba87","src/lib.rs":"4c4fa0d4882387d2c1681fa29a333354230de157101783bea2af6af04951d973","src/macros.rs":"cb2e9742b7e2bcadc4eb356a4ca4eb3317d1a80e293f37a3cd5a0155c5347c50","src/map.rs":"21c0c04acfb25d526da41b447b2e572d14e52778b84910514869d1cd2dce267c","src/map/core.rs":"9d9df231fbc02e3539429451c6f8cfd142c97d6e47b0c1f58672f75e3806d578","src/map/core/raw.rs":"9842320404357ec15e536240a9ab32d969e61f31508d3c485c0c76077618ef63","src/mutable_keys.rs":"99fdec7c0182902ba19524f342c220b51475bcd41c44c2cb2c3f62eacb029335","src/rayon/map.rs":"cdbe6cad8e5753aca3f07b621d2bb3b480f1ae3e10697568b8c16aeb865de65b","src/rayon/mod.rs":"bf2b0fc074f20135a6734db600b04828e88dd263b3e361606be4efe8e916eafc","src/rayon/set.rs":"789efd10d41f03fa73268bae8afdc3b6582767420218a4b28f3c83c528ef726c","src/serde.rs":"2f7ce29e63e92ddbe14d3ad0b7e83bdc9662b226565ec0aa707d5cd92cb1e263","src/set.rs":"a88c5e902e8c67d014c7c1680a7e4b9156af67d2ac58e7dcf96698b742abc88b","src/util.rs":"c415261cff9f610d7331192feba0839cb05e04d3d375a5fa2f8190a29661994e","tests/equivalent_trait.rs":"efe9393069e3cfc893d2c9c0343679979578e437fdb98a10baefeced027ba310","tests/macros_full_path.rs":"c33c86d7341581fdd08e2e6375a4afca507fa603540c54a3b9e51c4cd011cd71","tests/quick.rs":"6efe8c6dfa5bdd466b3f5c491d9dfbf57fd730301849a710abff9358968218c5","tests/tests.rs":"f6dbeeb0e2950402b0e66ac52bf74c9e4197d3c5d9c0dde64a7998a2ef74d327"},"package":"55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"} \ No newline at end of file +{"files":{"Cargo.toml":"f74227e7c2cc4c8a1b407328d3dc5224b0633b6d81bd8bca7c4902f496e05f70","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055","README.rst":"8784bb0b101d06198fe989bbe85e5d597c6843de096faeed25a0beb2b9952722","benches/bench.rs":"dda3c7e3cd68b8f5c74dbd60189e89f0e43339cdc25dae7b1e5a9d25b1fb80a9","benches/faststring.rs":"2472b9d0d52031988cd31401357908fd850d15f1efa9f9761aa6b6779aad1889","build.rs":"558b4d0b9e9b3a44f7e1a2b69f7a7567ea721cd45cb54f4e458e850bf702f35c","src/equivalent.rs":"2e6ae24ef09a09b917f4e2b0f6288f901878e42f5080f61b1bd1afdcc90aba87","src/lib.rs":"a5f52cf1441511f3e71f1cbe8137410ecdbba96f95a61d039858c8f63768c36d","src/macros.rs":"cb2e9742b7e2bcadc4eb356a4ca4eb3317d1a80e293f37a3cd5a0155c5347c50","src/map.rs":"05b7eba2f7e2f11881e36f96abcf0038d6543ee6f1bb14b844b1a79cfc073065","src/map/core.rs":"7126a8ebc18b18e0349db01e0fbe24c3f6f40acd2346189306789dbeaaced3e0","src/map/core/raw.rs":"ef1337b6ba2820d96e34c696eeaf84c3b83cd064c2cca8f60fe9866b5caa45e6","src/mutable_keys.rs":"99fdec7c0182902ba19524f342c220b51475bcd41c44c2cb2c3f62eacb029335","src/rayon/map.rs":"cdbe6cad8e5753aca3f07b621d2bb3b480f1ae3e10697568b8c16aeb865de65b","src/rayon/mod.rs":"bf2b0fc074f20135a6734db600b04828e88dd263b3e361606be4efe8e916eafc","src/rayon/set.rs":"789efd10d41f03fa73268bae8afdc3b6582767420218a4b28f3c83c528ef726c","src/serde.rs":"d45ec8fb9c02594ca6f2e9b20764778b2b4193a24a52f1e233160a33efc6e683","src/serde_seq.rs":"c54a52fa607b6ccddda1e76e829778ca304c49b5f434edc5e582a5386c35d662","src/set.rs":"88b46246d5b39a91bf9318446bf6d8b0d7ff723ef6dd4ba4a965d67f7511f642","src/util.rs":"c415261cff9f610d7331192feba0839cb05e04d3d375a5fa2f8190a29661994e","tests/equivalent_trait.rs":"efe9393069e3cfc893d2c9c0343679979578e437fdb98a10baefeced027ba310","tests/macros_full_path.rs":"c33c86d7341581fdd08e2e6375a4afca507fa603540c54a3b9e51c4cd011cd71","tests/quick.rs":"6efe8c6dfa5bdd466b3f5c491d9dfbf57fd730301849a710abff9358968218c5","tests/tests.rs":"f6dbeeb0e2950402b0e66ac52bf74c9e4197d3c5d9c0dde64a7998a2ef74d327"},"package":"824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"} \ No newline at end of file diff --git a/third_party/rust/indexmap/Cargo.toml b/third_party/rust/indexmap/Cargo.toml index 96876f030e34..54e07a98c901 100644 --- a/third_party/rust/indexmap/Cargo.toml +++ b/third_party/rust/indexmap/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "indexmap" -version = "1.6.0" +version = "1.6.2" authors = ["bluss", "Josh Stone "] build = "build.rs" description = "A hash table with consistent order and fast iteration.\n\nThe indexmap is a hash table where the iteration order of the key-value\npairs is independent of the hash values of the keys. It has the usual\nhash table functionality, it preserves insertion order except after\nremovals, and it allows lookup of its elements by either hash table key\nor numerical index. A corresponding hash set type is also provided.\n\nThis crate was initially published under the name ordermap, but it was renamed to\nindexmap.\n" @@ -34,7 +34,7 @@ debug = true [lib] bench = false [dependencies.hashbrown] -version = "0.9.0" +version = "0.9.1" features = ["raw"] default-features = false @@ -65,6 +65,9 @@ default-features = false [dev-dependencies.rand] version = "0.7" features = ["small_rng"] + +[dev-dependencies.serde_derive] +version = "1.0" [build-dependencies.autocfg] version = "1" diff --git a/third_party/rust/indexmap/README.rst b/third_party/rust/indexmap/README.rst index 2c489850df41..1cf5368bf0dd 100644 --- a/third_party/rust/indexmap/README.rst +++ b/third_party/rust/indexmap/README.rst @@ -3,17 +3,17 @@ indexmap |build_status|_ |crates|_ |docs|_ |rustc|_ +.. |build_status| image:: https://github.com/bluss/indexmap/workflows/Continuous%20integration/badge.svg?branch=master +.. _build_status: https://github.com/bluss/indexmap/actions + .. |crates| image:: https://img.shields.io/crates/v/indexmap.svg .. _crates: https://crates.io/crates/indexmap -.. |build_status| image:: https://travis-ci.org/bluss/indexmap.svg -.. _build_status: https://travis-ci.org/bluss/indexmap - .. |docs| image:: https://docs.rs/indexmap/badge.svg .. _docs: https://docs.rs/indexmap -.. |rustc| image:: https://img.shields.io/badge/rust-1.32%2B-orange.svg -.. _rustc: https://img.shields.io/badge/rust-1.32%2B-orange.svg +.. |rustc| image:: https://img.shields.io/badge/rust-1.36%2B-orange.svg +.. _rustc: https://img.shields.io/badge/rust-1.36%2B-orange.svg A pure-Rust hash table which preserves (in a limited sense) insertion order. @@ -66,6 +66,29 @@ which is roughly: Recent Changes ============== +- 1.6.2 + + - Fixed to match ``std`` behavior, ``OccupiedEntry::key`` now references the + existing key in the map instead of the lookup key, by @cuviper in PR 170_. + + - The new ``Entry::or_insert_with_key`` matches Rust 1.50's ``Entry`` method, + passing ``&K`` to the callback to create a value, by @cuviper in PR 175_. + +.. _170: https://github.com/bluss/indexmap/pull/170 +.. _175: https://github.com/bluss/indexmap/pull/175 + +- 1.6.1 + + - The new ``serde_seq`` module implements ``IndexMap`` serialization as a + sequence to ensure order is preserved, by @cuviper in PR 158_. + + - New methods on maps and sets work like the ``Vec``/slice methods by the same name: + ``truncate``, ``split_off``, ``first``, ``first_mut``, ``last``, ``last_mut``, and + ``swap_indices``, by @cuviper in PR 160_. + +.. _158: https://github.com/bluss/indexmap/pull/158 +.. _160: https://github.com/bluss/indexmap/pull/160 + - 1.6.0 - **MSRV**: Rust 1.36 or later is now required. diff --git a/third_party/rust/indexmap/src/lib.rs b/third_party/rust/indexmap/src/lib.rs index 2df2ceed8a64..1a58a8302461 100644 --- a/third_party/rust/indexmap/src/lib.rs +++ b/third_party/rust/indexmap/src/lib.rs @@ -53,8 +53,7 @@ //! //! ### Rust Version //! -//! This version of indexmap requires Rust 1.32 or later, or Rust 1.36+ for -//! using with `alloc` (without `std`), see below. +//! This version of indexmap requires Rust 1.36 or later. //! //! The indexmap 1.x release series will use a carefully considered version //! upgrade policy, where in a later 1.x version, we will raise the minimum @@ -62,7 +61,7 @@ //! //! ## No Standard Library Targets //! -//! From Rust 1.36, this crate supports being built without `std`, requiring +//! This crate supports being built without `std`, requiring //! `alloc` instead. This is enabled automatically when it is detected that //! `std` is not available. There is no crate feature to enable/disable to //! trigger this. It can be tested by building for a std-less target. @@ -95,8 +94,10 @@ use std::vec::{self, Vec}; mod macros; mod equivalent; mod mutable_keys; -#[cfg(feature = "serde-1")] +#[cfg(feature = "serde")] mod serde; +#[cfg(feature = "serde")] +pub mod serde_seq; mod util; pub mod map; diff --git a/third_party/rust/indexmap/src/map.rs b/third_party/rust/indexmap/src/map.rs index 6829ef94b8d4..3bfaa1501c1d 100644 --- a/third_party/rust/indexmap/src/map.rs +++ b/third_party/rust/indexmap/src/map.rs @@ -252,6 +252,13 @@ impl IndexMap { self.core.clear(); } + /// Shortens the map, keeping the first `len` elements and dropping the rest. + /// + /// If `len` is greater than the map's current length, this has no effect. + pub fn truncate(&mut self, len: usize) { + self.core.truncate(len); + } + /// Clears the `IndexMap` in the given index range, returning those /// key-value pairs as a drain iterator. /// @@ -273,6 +280,23 @@ impl IndexMap { iter: self.core.drain(range), } } + + /// Splits the collection into two at the given index. + /// + /// Returns a newly allocated map containing the elements in the range + /// `[at, len)`. After the call, the original map will be left containing + /// the elements `[0, at)` with its previous capacity unchanged. + /// + /// ***Panics*** if `at > len`. + pub fn split_off(&mut self, at: usize) -> Self + where + S: Clone, + { + Self { + core: self.core.split_off(at), + hash_builder: self.hash_builder.clone(), + } + } } impl IndexMap @@ -485,7 +509,7 @@ where /// /// Like `Vec::swap_remove`, the pair is removed by swapping it with the /// last element of the map and popping it off. **This perturbs - /// the postion of what used to be the last element!** + /// the position of what used to be the last element!** /// /// Return `None` if `key` is not in map. /// @@ -501,7 +525,7 @@ where /// /// Like `Vec::swap_remove`, the pair is removed by swapping it with the /// last element of the map and popping it off. **This perturbs - /// the postion of what used to be the last element!** + /// the position of what used to be the last element!** /// /// Return `None` if `key` is not in map. /// @@ -521,7 +545,7 @@ where /// /// Like `Vec::swap_remove`, the pair is removed by swapping it with the /// last element of the map and popping it off. **This perturbs - /// the postion of what used to be the last element!** + /// the position of what used to be the last element!** /// /// Return `None` if `key` is not in map. /// @@ -693,13 +717,41 @@ impl IndexMap { self.as_entries_mut().get_mut(index).map(Bucket::muts) } + /// Get the first key-value pair + /// + /// Computes in **O(1)** time. + pub fn first(&self) -> Option<(&K, &V)> { + self.as_entries().first().map(Bucket::refs) + } + + /// Get the first key-value pair, with mutable access to the value + /// + /// Computes in **O(1)** time. + pub fn first_mut(&mut self) -> Option<(&K, &mut V)> { + self.as_entries_mut().first_mut().map(Bucket::ref_mut) + } + + /// Get the last key-value pair + /// + /// Computes in **O(1)** time. + pub fn last(&self) -> Option<(&K, &V)> { + self.as_entries().last().map(Bucket::refs) + } + + /// Get the last key-value pair, with mutable access to the value + /// + /// Computes in **O(1)** time. + pub fn last_mut(&mut self) -> Option<(&K, &mut V)> { + self.as_entries_mut().last_mut().map(Bucket::ref_mut) + } + /// Remove the key-value pair by index /// /// Valid indices are *0 <= index < self.len()* /// /// Like `Vec::swap_remove`, the pair is removed by swapping it with the /// last element of the map and popping it off. **This perturbs - /// the postion of what used to be the last element!** + /// the position of what used to be the last element!** /// /// Computes in **O(1)** time (average). pub fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { @@ -718,6 +770,13 @@ impl IndexMap { pub fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { self.core.shift_remove_index(index) } + + /// Swaps the position of two key-value pairs in the map. + /// + /// ***Panics*** if `a` or `b` are out of bounds. + pub fn swap_indices(&mut self, a: usize, b: usize) { + self.core.swap_indices(a, b) + } } /// An iterator over the keys of a `IndexMap`. @@ -1589,6 +1648,28 @@ mod tests { assert_eq!(&mut TestEnum::DefaultValue, map.entry(2).or_default()); } + #[test] + fn occupied_entry_key() { + // These keys match hash and equality, but their addresses are distinct. + let (k1, k2) = (&mut 1, &mut 1); + let k1_ptr = k1 as *const i32; + let k2_ptr = k2 as *const i32; + assert_ne!(k1_ptr, k2_ptr); + + let mut map = IndexMap::new(); + map.insert(k1, "value"); + match map.entry(k2) { + Entry::Occupied(ref e) => { + // `OccupiedEntry::key` should reference the key in the map, + // not the key that was used to find the entry. + let ptr = *e.key() as *const i32; + assert_eq!(ptr, k1_ptr); + assert_ne!(ptr, k2_ptr); + } + Entry::Vacant(_) => panic!(), + } + } + #[test] fn keys() { let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; diff --git a/third_party/rust/indexmap/src/map/core.rs b/third_party/rust/indexmap/src/map/core.rs index 7adb69a13333..c4e725c9a3c5 100644 --- a/third_party/rust/indexmap/src/map/core.rs +++ b/third_party/rust/indexmap/src/map/core.rs @@ -34,6 +34,27 @@ fn get_hash(entries: &[Bucket]) -> impl Fn(&usize) -> u64 + '_ { move |&i| entries[i].hash.get() } +#[inline] +fn equivalent<'a, K, V, Q: ?Sized + Equivalent>( + key: &'a Q, + entries: &'a [Bucket], +) -> impl Fn(&usize) -> bool + 'a { + move |&i| Q::equivalent(key, &entries[i].key) +} + +#[inline] +fn erase_index(table: &mut RawTable, hash: HashValue, index: usize) { + table.erase_entry(hash.get(), move |&i| i == index); +} + +#[inline] +fn update_index(table: &mut RawTable, hash: HashValue, old: usize, new: usize) { + let index = table + .get_mut(hash.get(), move |&i| i == old) + .expect("index not found"); + *index = new; +} + impl Clone for IndexMapCore where K: Clone, @@ -129,6 +150,13 @@ impl IndexMapCore { self.entries.clear(); } + pub(crate) fn truncate(&mut self, len: usize) { + if len < self.len() { + self.erase_indices(len, self.entries.len()); + self.entries.truncate(len); + } + } + pub(crate) fn drain(&mut self, range: R) -> Drain<'_, Bucket> where R: RangeBounds, @@ -138,6 +166,18 @@ impl IndexMapCore { self.entries.drain(range) } + pub(crate) fn split_off(&mut self, at: usize) -> Self { + assert!(at <= self.entries.len()); + self.erase_indices(at, self.entries.len()); + let entries = self.entries.split_off(at); + + let mut indices = RawTable::with_capacity(entries.len()); + for (i, entry) in enumerate(&entries) { + indices.insert_no_grow(entry.hash.get(), i); + } + Self { indices, entries } + } + /// Reserve capacity for `additional` more key-value pairs. pub(crate) fn reserve(&mut self, additional: usize) { self.indices.reserve(additional, get_hash(&self.entries)); @@ -160,7 +200,7 @@ impl IndexMapCore { pub(crate) fn pop(&mut self) -> Option<(K, V)> { if let Some(entry) = self.entries.pop() { let last = self.entries.len(); - self.erase_index(entry.hash, last); + erase_index(&mut self.indices, entry.hash, last); Some((entry.key, entry.value)) } else { None @@ -181,6 +221,15 @@ impl IndexMapCore { i } + /// Return the index in `entries` where an equivalent key can be found + pub(crate) fn get_index_of(&self, hash: HashValue, key: &Q) -> Option + where + Q: ?Sized + Equivalent, + { + let eq = equivalent(key, &self.entries); + self.indices.get(hash.get(), eq).copied() + } + pub(crate) fn insert_full(&mut self, hash: HashValue, key: K, value: V) -> (usize, Option) where K: Eq, @@ -191,6 +240,154 @@ impl IndexMapCore { } } + /// Remove an entry by shifting all entries that follow it + pub(crate) fn shift_remove_full(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> + where + Q: ?Sized + Equivalent, + { + let eq = equivalent(key, &self.entries); + match self.indices.remove_entry(hash.get(), eq) { + Some(index) => { + let (key, value) = self.shift_remove_finish(index); + Some((index, key, value)) + } + None => None, + } + } + + /// Remove an entry by shifting all entries that follow it + pub(crate) fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { + match self.entries.get(index) { + Some(entry) => { + erase_index(&mut self.indices, entry.hash, index); + Some(self.shift_remove_finish(index)) + } + None => None, + } + } + + /// Remove an entry by shifting all entries that follow it + /// + /// The index should already be removed from `self.indices`. + fn shift_remove_finish(&mut self, index: usize) -> (K, V) { + // use Vec::remove, but then we need to update the indices that point + // to all of the other entries that have to move + let entry = self.entries.remove(index); + + // correct indices that point to the entries that followed the removed entry. + // use a heuristic between a full sweep vs. a `find()` for every shifted item. + let raw_capacity = self.indices.buckets(); + let shifted_entries = &self.entries[index..]; + if shifted_entries.len() > raw_capacity / 2 { + // shift all indices greater than `index` + for i in self.indices_mut() { + if *i > index { + *i -= 1; + } + } + } else { + // find each following entry to shift its index + for (i, entry) in (index + 1..).zip(shifted_entries) { + update_index(&mut self.indices, entry.hash, i, i - 1); + } + } + + (entry.key, entry.value) + } + + /// Remove an entry by swapping it with the last + pub(crate) fn swap_remove_full(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> + where + Q: ?Sized + Equivalent, + { + let eq = equivalent(key, &self.entries); + match self.indices.remove_entry(hash.get(), eq) { + Some(index) => { + let (key, value) = self.swap_remove_finish(index); + Some((index, key, value)) + } + None => None, + } + } + + /// Remove an entry by swapping it with the last + pub(crate) fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { + match self.entries.get(index) { + Some(entry) => { + erase_index(&mut self.indices, entry.hash, index); + Some(self.swap_remove_finish(index)) + } + None => None, + } + } + + /// Finish removing an entry by swapping it with the last + /// + /// The index should already be removed from `self.indices`. + fn swap_remove_finish(&mut self, index: usize) -> (K, V) { + // use swap_remove, but then we need to update the index that points + // to the other entry that has to move + let entry = self.entries.swap_remove(index); + + // correct index that points to the entry that had to swap places + if let Some(entry) = self.entries.get(index) { + // was not last element + // examine new element in `index` and find it in indices + let last = self.entries.len(); + update_index(&mut self.indices, entry.hash, last, index); + } + + (entry.key, entry.value) + } + + /// Erase `start..end` from `indices`, and shift `end..` indices down to `start..` + /// + /// All of these items should still be at their original location in `entries`. + /// This is used by `drain`, which will let `Vec::drain` do the work on `entries`. + fn erase_indices(&mut self, start: usize, end: usize) { + let (init, shifted_entries) = self.entries.split_at(end); + let (start_entries, erased_entries) = init.split_at(start); + + let erased = erased_entries.len(); + let shifted = shifted_entries.len(); + let half_capacity = self.indices.buckets() / 2; + + // Use a heuristic between different strategies + if erased == 0 { + // Degenerate case, nothing to do + } else if start + shifted < half_capacity && start < erased { + // Reinsert everything, as there are few kept indices + self.indices.clear(); + + // Reinsert stable indices + for (i, entry) in enumerate(start_entries) { + self.indices.insert_no_grow(entry.hash.get(), i); + } + + // Reinsert shifted indices + for (i, entry) in (start..).zip(shifted_entries) { + self.indices.insert_no_grow(entry.hash.get(), i); + } + } else if erased + shifted < half_capacity { + // Find each affected index, as there are few to adjust + + // Find erased indices + for (i, entry) in (start..).zip(erased_entries) { + erase_index(&mut self.indices, entry.hash, i); + } + + // Find shifted indices + for ((new, old), entry) in (start..).zip(end..).zip(shifted_entries) { + update_index(&mut self.indices, entry.hash, old, new); + } + } else { + // Sweep the whole table for adjustments + self.erase_indices_sweep(start, end); + } + + debug_assert_eq!(self.indices.len(), start + shifted); + } + pub(crate) fn retain_in_order(&mut self, mut keep: F) where F: FnMut(&mut K, &mut V) -> bool, @@ -225,6 +422,17 @@ impl IndexMapCore { self.indices.insert_no_grow(entry.hash.get(), i); } } + + pub(crate) fn reverse(&mut self) { + self.entries.reverse(); + + // No need to save hash indices, can easily calculate what they should + // be, given that this is an in-place reversal. + let len = self.entries.len(); + for i in self.indices_mut() { + *i = len - *i - 1; + } + } } /// Entry for an existing key-value pair or a vacant location to @@ -237,6 +445,9 @@ pub enum Entry<'a, K, V> { } impl<'a, K, V> Entry<'a, K, V> { + /// Inserts the given default value in the entry if it is vacant and returns a mutable + /// reference to it. Otherwise a mutable reference to an already existent value is returned. + /// /// Computes in **O(1)** time (amortized average). pub fn or_insert(self, default: V) -> &'a mut V { match self { @@ -245,6 +456,9 @@ impl<'a, K, V> Entry<'a, K, V> { } } + /// Inserts the result of the `call` function in the entry if it is vacant and returns a mutable + /// reference to it. Otherwise a mutable reference to an already existent value is returned. + /// /// Computes in **O(1)** time (amortized average). pub fn or_insert_with(self, call: F) -> &'a mut V where @@ -256,6 +470,26 @@ impl<'a, K, V> Entry<'a, K, V> { } } + /// Inserts the result of the `call` function with a reference to the entry's key if it is + /// vacant, and returns a mutable reference to the new value. Otherwise a mutable reference to + /// an already existent value is returned. + /// + /// Computes in **O(1)** time (amortized average). + pub fn or_insert_with_key(self, call: F) -> &'a mut V + where + F: FnOnce(&K) -> V, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + let value = call(&entry.key); + entry.insert(value) + } + } + } + + /// Gets a reference to the entry's key, either within the map if occupied, + /// or else the new key that was used to find the entry. pub fn key(&self) -> &K { match *self { Entry::Occupied(ref entry) => entry.key(), @@ -329,7 +563,7 @@ impl OccupiedEntry<'_, K, V> { /// /// Like `Vec::swap_remove`, the pair is removed by swapping it with the /// last element of the map and popping it off. **This perturbs - /// the postion of what used to be the last element!** + /// the position of what used to be the last element!** /// /// Computes in **O(1)** time (average). pub fn swap_remove(self) -> V { @@ -375,10 +609,12 @@ pub struct VacantEntry<'a, K, V> { } impl<'a, K, V> VacantEntry<'a, K, V> { + /// Gets a reference to the key that was used to find the entry. pub fn key(&self) -> &K { &self.key } + /// Takes ownership of the key, leaving the entry vacant. pub fn into_key(self) -> K { self.key } @@ -388,6 +624,8 @@ impl<'a, K, V> VacantEntry<'a, K, V> { self.map.len() } + /// Inserts the entry's key and the given value into the map, and returns a mutable reference + /// to the value. pub fn insert(self, value: V) -> &'a mut V { let i = self.map.push(self.hash, self.key, value); &mut self.map.entries[i].value diff --git a/third_party/rust/indexmap/src/map/core/raw.rs b/third_party/rust/indexmap/src/map/core/raw.rs index fdfadb91c1d6..168e1af3cb09 100644 --- a/third_party/rust/indexmap/src/map/core/raw.rs +++ b/third_party/rust/indexmap/src/map/core/raw.rs @@ -2,8 +2,7 @@ //! This module encapsulates the `unsafe` access to `hashbrown::raw::RawTable`, //! mostly in dealing with its bucket "pointers". -use super::{Entry, Equivalent, HashValue, IndexMapCore, VacantEntry}; -use crate::util::enumerate; +use super::{equivalent, Entry, HashValue, IndexMapCore, VacantEntry}; use core::fmt; use core::mem::replace; use hashbrown::raw::RawTable; @@ -13,114 +12,37 @@ type RawBucket = hashbrown::raw::Bucket; pub(super) struct DebugIndices<'a>(pub &'a RawTable); impl fmt::Debug for DebugIndices<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // SAFETY: we're not letting any of the buckets escape this function let indices = unsafe { self.0.iter().map(|raw_bucket| raw_bucket.read()) }; f.debug_list().entries(indices).finish() } } impl IndexMapCore { - /// Return the raw bucket with an equivalent key - fn find_equivalent(&self, hash: HashValue, key: &Q) -> Option - where - Q: ?Sized + Equivalent, - { - self.indices.find(hash.get(), { - move |&i| Q::equivalent(key, &self.entries[i].key) - }) - } - - /// Return the raw bucket for the given index - fn find_index(&self, hash: HashValue, index: usize) -> Option { - self.indices.find(hash.get(), move |&i| i == index) - } - - /// Return the index in `entries` where an equivalent key can be found - pub(crate) fn get_index_of(&self, hash: HashValue, key: &Q) -> Option - where - Q: ?Sized + Equivalent, - { - match self.find_equivalent(hash, key) { - Some(raw_bucket) => Some(unsafe { raw_bucket.read() }), - None => None, - } - } - - /// Erase the given index from `indices`. - /// - /// The index doesn't need to be valid in `entries` while calling this. No other index - /// adjustments are made -- this is only used by `pop` for the greatest index. - pub(super) fn erase_index(&mut self, hash: HashValue, index: usize) { - debug_assert_eq!(index, self.indices.len() - 1); - let raw_bucket = self.find_index(hash, index).unwrap(); - unsafe { self.indices.erase(raw_bucket) }; - } - - /// Erase `start..end` from `indices`, and shift `end..` indices down to `start..` - /// - /// All of these items should still be at their original location in `entries`. - /// This is used by `drain`, which will let `Vec::drain` do the work on `entries`. - pub(super) fn erase_indices(&mut self, start: usize, end: usize) { - let (init, shifted_entries) = self.entries.split_at(end); - let (start_entries, erased_entries) = init.split_at(start); - - let erased = erased_entries.len(); - let shifted = shifted_entries.len(); - let half_capacity = self.indices.buckets() / 2; - - // Use a heuristic between different strategies - if erased == 0 { - // Degenerate case, nothing to do - } else if start + shifted < half_capacity && start < erased { - // Reinsert everything, as there are few kept indices - self.indices.clear(); - - // Reinsert stable indices - for (i, entry) in enumerate(start_entries) { - self.indices.insert_no_grow(entry.hash.get(), i); - } - - // Reinsert shifted indices - for (i, entry) in (start..).zip(shifted_entries) { - self.indices.insert_no_grow(entry.hash.get(), i); - } - } else if erased + shifted < half_capacity { - // Find each affected index, as there are few to adjust - - // Find erased indices - for (i, entry) in (start..).zip(erased_entries) { - let bucket = self.find_index(entry.hash, i).unwrap(); - unsafe { self.indices.erase(bucket) }; - } - - // Find shifted indices - for ((new, old), entry) in (start..).zip(end..).zip(shifted_entries) { - let bucket = self.find_index(entry.hash, old).unwrap(); - unsafe { bucket.write(new) }; - } - } else { - // Sweep the whole table for adjustments - unsafe { - for bucket in self.indices.iter() { - let i = bucket.read(); - if i >= end { - bucket.write(i - erased); - } else if i >= start { - self.indices.erase(bucket); - } + /// Sweep the whole table to erase indices start..end + pub(super) fn erase_indices_sweep(&mut self, start: usize, end: usize) { + // SAFETY: we're not letting any of the buckets escape this function + unsafe { + let offset = end - start; + for bucket in self.indices.iter() { + let i = bucket.read(); + if i >= end { + bucket.write(i - offset); + } else if i >= start { + self.indices.erase(bucket); } } } - - debug_assert_eq!(self.indices.len(), start + shifted); } pub(crate) fn entry(&mut self, hash: HashValue, key: K) -> Entry<'_, K, V> where K: Eq, { - match self.find_equivalent(hash, &key) { - // Safety: The entry is created with a live raw bucket, at the same time we have a &mut - // reference to the map, so it can not be modified further. + let eq = equivalent(&key, &self.entries); + match self.indices.find(hash.get(), eq) { + // SAFETY: The entry is created with a live raw bucket, at the same time + // we have a &mut reference to the map, so it can not be modified further. Some(raw_bucket) => Entry::Occupied(OccupiedEntry { map: self, raw_bucket, @@ -134,121 +56,33 @@ impl IndexMapCore { } } - /// Remove an entry by shifting all entries that follow it - pub(crate) fn shift_remove_full(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> - where - Q: ?Sized + Equivalent, - { - match self.find_equivalent(hash, key) { - Some(raw_bucket) => unsafe { Some(self.shift_remove_bucket(raw_bucket)) }, - None => None, - } + pub(super) fn indices_mut(&mut self) -> impl Iterator { + // SAFETY: we're not letting any of the buckets escape this function, + // only the item references that are appropriately bound to `&mut self`. + unsafe { self.indices.iter().map(|bucket| bucket.as_mut()) } } - /// Remove an entry by shifting all entries that follow it - pub(crate) fn shift_remove_index(&mut self, index: usize) -> Option<(K, V)> { - let raw_bucket = match self.entries.get(index) { - Some(entry) => self.find_index(entry.hash, index).unwrap(), - None => return None, - }; + /// Return the raw bucket for the given index + fn find_index(&self, index: usize) -> RawBucket { + // We'll get a "nice" bounds-check from indexing `self.entries`, + // and then we expect to find it in the table as well. + let hash = self.entries[index].hash.get(); + self.indices + .find(hash, move |&i| i == index) + .expect("index not found") + } + + pub(crate) fn swap_indices(&mut self, a: usize, b: usize) { + // SAFETY: Can't take two `get_mut` references from one table, so we + // must use raw buckets to do the swap. This is still safe because we + // are locally sure they won't dangle, and we write them individually. unsafe { - let (_, key, value) = self.shift_remove_bucket(raw_bucket); - Some((key, value)) - } - } - - /// Remove an entry by shifting all entries that follow it - /// - /// Safety: The caller must pass a live `raw_bucket`. - #[allow(unused_unsafe)] - unsafe fn shift_remove_bucket(&mut self, raw_bucket: RawBucket) -> (usize, K, V) { - // use Vec::remove, but then we need to update the indices that point - // to all of the other entries that have to move - let index = unsafe { self.indices.remove(raw_bucket) }; - let entry = self.entries.remove(index); - - // correct indices that point to the entries that followed the removed entry. - // use a heuristic between a full sweep vs. a `find()` for every shifted item. - let raw_capacity = self.indices.buckets(); - let shifted_entries = &self.entries[index..]; - if shifted_entries.len() > raw_capacity / 2 { - // shift all indices greater than `index` - unsafe { - for bucket in self.indices.iter() { - let i = bucket.read(); - if i > index { - bucket.write(i - 1); - } - } - } - } else { - // find each following entry to shift its index - for (i, entry) in (index + 1..).zip(shifted_entries) { - let shifted_bucket = self.find_index(entry.hash, i).unwrap(); - unsafe { shifted_bucket.write(i - 1) }; - } - } - - (index, entry.key, entry.value) - } - - /// Remove an entry by swapping it with the last - pub(crate) fn swap_remove_full(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)> - where - Q: ?Sized + Equivalent, - { - match self.find_equivalent(hash, key) { - Some(raw_bucket) => unsafe { Some(self.swap_remove_bucket(raw_bucket)) }, - None => None, - } - } - - /// Remove an entry by swapping it with the last - pub(crate) fn swap_remove_index(&mut self, index: usize) -> Option<(K, V)> { - let raw_bucket = match self.entries.get(index) { - Some(entry) => self.find_index(entry.hash, index).unwrap(), - None => return None, - }; - unsafe { - let (_, key, value) = self.swap_remove_bucket(raw_bucket); - Some((key, value)) - } - } - - /// Remove an entry by swapping it with the last - /// - /// Safety: The caller must pass a live `raw_bucket`. - #[allow(unused_unsafe)] - unsafe fn swap_remove_bucket(&mut self, raw_bucket: RawBucket) -> (usize, K, V) { - // use swap_remove, but then we need to update the index that points - // to the other entry that has to move - let index = unsafe { self.indices.remove(raw_bucket) }; - let entry = self.entries.swap_remove(index); - - // correct index that points to the entry that had to swap places - if let Some(entry) = self.entries.get(index) { - // was not last element - // examine new element in `index` and find it in indices - let last = self.entries.len(); - let swapped_bucket = self.find_index(entry.hash, last).unwrap(); - unsafe { swapped_bucket.write(index) }; - } - - (index, entry.key, entry.value) - } - - pub(crate) fn reverse(&mut self) { - self.entries.reverse(); - - // No need to save hash indices, can easily calculate what they should - // be, given that this is an in-place reversal. - let len = self.entries.len(); - unsafe { - for raw_bucket in self.indices.iter() { - let i = raw_bucket.read(); - raw_bucket.write(len - i - 1); - } + let raw_bucket_a = self.find_index(a); + let raw_bucket_b = self.find_index(b); + raw_bucket_a.write(b); + raw_bucket_b.write(a); } + self.entries.swap(a, b); } } @@ -270,14 +104,24 @@ unsafe impl Sync for OccupiedEntry<'_, K, V> {} // The parent module also adds methods that don't threaten the unsafe encapsulation. impl<'a, K, V> OccupiedEntry<'a, K, V> { + /// Gets a reference to the entry's key in the map. + /// + /// Note that this is not the key that was used to find the entry. There may be an observable + /// difference if the key type has any distinguishing features outside of `Hash` and `Eq`, like + /// extra fields or the memory address of an allocation. pub fn key(&self) -> &K { - &self.key + &self.map.entries[self.index()].key } + /// Gets a reference to the entry's value in the map. pub fn get(&self) -> &V { &self.map.entries[self.index()].value } + /// Gets a mutable reference to the entry's value in the map. + /// + /// If you need a reference which may outlive the destruction of the + /// `Entry` value, see `into_mut`. pub fn get_mut(&mut self) -> &mut V { let index = self.index(); &mut self.map.entries[index].value @@ -293,9 +137,12 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Return the index of the key-value pair #[inline] pub fn index(&self) -> usize { + // SAFETY: we have &mut map keep keeping the bucket stable unsafe { self.raw_bucket.read() } } + /// Converts into a mutable reference to the entry's value in the map, + /// with a lifetime bound to the map itself. pub fn into_mut(self) -> &'a mut V { let index = self.index(); &mut self.map.entries[index].value @@ -305,16 +152,14 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// Like `Vec::swap_remove`, the pair is removed by swapping it with the /// last element of the map and popping it off. **This perturbs - /// the postion of what used to be the last element!** + /// the position of what used to be the last element!** /// /// Computes in **O(1)** time (average). pub fn swap_remove_entry(self) -> (K, V) { - // This is safe because it can only happen once (self is consumed) + // SAFETY: This is safe because it can only happen once (self is consumed) // and map.indices have not been modified since entry construction - unsafe { - let (_, key, value) = self.map.swap_remove_bucket(self.raw_bucket); - (key, value) - } + let index = unsafe { self.map.indices.remove(self.raw_bucket) }; + self.map.swap_remove_finish(index) } /// Remove and return the key, value pair stored in the map for this entry @@ -325,11 +170,9 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// Computes in **O(n)** time (average). pub fn shift_remove_entry(self) -> (K, V) { - // This is safe because it can only happen once (self is consumed) + // SAFETY: This is safe because it can only happen once (self is consumed) // and map.indices have not been modified since entry construction - unsafe { - let (_, key, value) = self.map.shift_remove_bucket(self.raw_bucket); - (key, value) - } + let index = unsafe { self.map.indices.remove(self.raw_bucket) }; + self.map.shift_remove_finish(index) } } diff --git a/third_party/rust/indexmap/src/serde.rs b/third_party/rust/indexmap/src/serde.rs index 853c6b9aa301..c6dd6d5ea0fc 100644 --- a/third_party/rust/indexmap/src/serde.rs +++ b/third_party/rust/indexmap/src/serde.rs @@ -2,7 +2,7 @@ use serde::de::value::{MapDeserializer, SeqDeserializer}; use serde::de::{ Deserialize, Deserializer, Error, IntoDeserializer, MapAccess, SeqAccess, Visitor, }; -use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; +use serde::ser::{Serialize, Serializer}; use core::fmt::{self, Formatter}; use core::hash::{BuildHasher, Hash}; @@ -10,7 +10,7 @@ use core::marker::PhantomData; use crate::IndexMap; -/// Requires crate feature `"serde-1"` +/// Requires crate feature `"serde"` or `"serde-1"` impl Serialize for IndexMap where K: Serialize + Hash + Eq, @@ -21,11 +21,7 @@ where where T: Serializer, { - let mut map_serializer = serializer.serialize_map(Some(self.len()))?; - for (key, value) in self { - map_serializer.serialize_entry(key, value)?; - } - map_serializer.end() + serializer.collect_map(self) } } @@ -58,7 +54,7 @@ where } } -/// Requires crate feature `"serde-1"` +/// Requires crate feature `"serde"` or `"serde-1"` impl<'de, K, V, S> Deserialize<'de> for IndexMap where K: Deserialize<'de> + Eq + Hash, @@ -89,7 +85,7 @@ where use crate::IndexSet; -/// Requires crate feature `"serde-1"` +/// Requires crate feature `"serde"` or `"serde-1"` impl Serialize for IndexSet where T: Serialize + Hash + Eq, @@ -99,11 +95,7 @@ where where Se: Serializer, { - let mut set_serializer = serializer.serialize_seq(Some(self.len()))?; - for value in self { - set_serializer.serialize_element(value)?; - } - set_serializer.end() + serializer.collect_seq(self) } } @@ -135,7 +127,7 @@ where } } -/// Requires crate feature `"serde-1"` +/// Requires crate feature `"serde"` or `"serde-1"` impl<'de, T, S> Deserialize<'de> for IndexSet where T: Deserialize<'de> + Eq + Hash, diff --git a/third_party/rust/indexmap/src/serde_seq.rs b/third_party/rust/indexmap/src/serde_seq.rs new file mode 100644 index 000000000000..d326a02e377a --- /dev/null +++ b/third_party/rust/indexmap/src/serde_seq.rs @@ -0,0 +1,112 @@ +//! Functions to serialize and deserialize an `IndexMap` as an ordered sequence. +//! +//! The default `serde` implementation serializes `IndexMap` as a normal map, +//! but there is no guarantee that serialization formats will preserve the order +//! of the key-value pairs. This module serializes `IndexMap` as a sequence of +//! `(key, value)` elements instead, in order. +//! +//! This module may be used in a field attribute for derived implementations: +//! +//! ``` +//! # use indexmap::IndexMap; +//! # use serde_derive::{Deserialize, Serialize}; +//! #[derive(Deserialize, Serialize)] +//! struct Data { +//! #[serde(with = "indexmap::serde_seq")] +//! map: IndexMap, +//! // ... +//! } +//! ``` +//! +//! Requires crate feature `"serde"` or `"serde-1"` + +use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; +use serde::ser::{Serialize, Serializer}; + +use core::fmt::{self, Formatter}; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; + +use crate::IndexMap; + +/// Serializes an `IndexMap` as an ordered sequence. +/// +/// This function may be used in a field attribute for deriving `Serialize`: +/// +/// ``` +/// # use indexmap::IndexMap; +/// # use serde_derive::Serialize; +/// #[derive(Serialize)] +/// struct Data { +/// #[serde(serialize_with = "indexmap::serde_seq::serialize")] +/// map: IndexMap, +/// // ... +/// } +/// ``` +/// +/// Requires crate feature `"serde"` or `"serde-1"` +pub fn serialize(map: &IndexMap, serializer: T) -> Result +where + K: Serialize + Hash + Eq, + V: Serialize, + S: BuildHasher, + T: Serializer, +{ + serializer.collect_seq(map) +} + +/// Visitor to deserialize a *sequenced* `IndexMap` +struct SeqVisitor(PhantomData<(K, V, S)>); + +impl<'de, K, V, S> Visitor<'de> for SeqVisitor +where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + type Value = IndexMap; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + write!(formatter, "a sequenced map") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let capacity = seq.size_hint().unwrap_or(0); + let mut map = IndexMap::with_capacity_and_hasher(capacity, S::default()); + + while let Some((key, value)) = seq.next_element()? { + map.insert(key, value); + } + + Ok(map) + } +} + +/// Deserializes an `IndexMap` from an ordered sequence. +/// +/// This function may be used in a field attribute for deriving `Deserialize`: +/// +/// ``` +/// # use indexmap::IndexMap; +/// # use serde_derive::Deserialize; +/// #[derive(Deserialize)] +/// struct Data { +/// #[serde(deserialize_with = "indexmap::serde_seq::deserialize")] +/// map: IndexMap, +/// // ... +/// } +/// ``` +/// +/// Requires crate feature `"serde"` or `"serde-1"` +pub fn deserialize<'de, D, K, V, S>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: Default + BuildHasher, +{ + deserializer.deserialize_seq(SeqVisitor(PhantomData)) +} diff --git a/third_party/rust/indexmap/src/set.rs b/third_party/rust/indexmap/src/set.rs index 99493891871b..aa4e7749532d 100644 --- a/third_party/rust/indexmap/src/set.rs +++ b/third_party/rust/indexmap/src/set.rs @@ -200,6 +200,13 @@ impl IndexSet { self.map.clear(); } + /// Shortens the set, keeping the first `len` elements and dropping the rest. + /// + /// If `len` is greater than the set's current length, this has no effect. + pub fn truncate(&mut self, len: usize) { + self.map.truncate(len); + } + /// Clears the `IndexSet` in the given index range, returning those values /// as a drain iterator. /// @@ -221,6 +228,22 @@ impl IndexSet { iter: self.map.drain(range).iter, } } + + /// Splits the collection into two at the given index. + /// + /// Returns a newly allocated set containing the elements in the range + /// `[at, len)`. After the call, the original set will be left containing + /// the elements `[0, at)` with its previous capacity unchanged. + /// + /// ***Panics*** if `at > len`. + pub fn split_off(&mut self, at: usize) -> Self + where + S: Clone, + { + Self { + map: self.map.split_off(at), + } + } } impl IndexSet @@ -402,7 +425,7 @@ where /// /// Like `Vec::swap_remove`, the value is removed by swapping it with the /// last element of the set and popping it off. **This perturbs - /// the postion of what used to be the last element!** + /// the position of what used to be the last element!** /// /// Return `false` if `value` was not in the set. /// @@ -450,7 +473,7 @@ where /// /// Like `Vec::swap_remove`, the value is removed by swapping it with the /// last element of the set and popping it off. **This perturbs - /// the postion of what used to be the last element!** + /// the position of what used to be the last element!** /// /// Return `None` if `value` was not in the set. /// @@ -483,7 +506,7 @@ where /// /// Like `Vec::swap_remove`, the value is removed by swapping it with the /// last element of the set and popping it off. **This perturbs - /// the postion of what used to be the last element!** + /// the position of what used to be the last element!** /// /// Return `None` if `value` was not in the set. pub fn swap_remove_full(&mut self, value: &Q) -> Option<(usize, T)> @@ -576,23 +599,37 @@ impl IndexSet { /// /// Computes in **O(1)** time. pub fn get_index(&self, index: usize) -> Option<&T> { - self.map.get_index(index).map(|(x, &())| x) + self.as_entries().get(index).map(Bucket::key_ref) } - /// Remove the key-value pair by index + /// Get the first value + /// + /// Computes in **O(1)** time. + pub fn first(&self) -> Option<&T> { + self.as_entries().first().map(Bucket::key_ref) + } + + /// Get the last value + /// + /// Computes in **O(1)** time. + pub fn last(&self) -> Option<&T> { + self.as_entries().last().map(Bucket::key_ref) + } + + /// Remove the value by index /// /// Valid indices are *0 <= index < self.len()* /// /// Like `Vec::swap_remove`, the value is removed by swapping it with the /// last element of the set and popping it off. **This perturbs - /// the postion of what used to be the last element!** + /// the position of what used to be the last element!** /// /// Computes in **O(1)** time (average). pub fn swap_remove_index(&mut self, index: usize) -> Option { self.map.swap_remove_index(index).map(|(x, ())| x) } - /// Remove the key-value pair by index + /// Remove the value by index /// /// Valid indices are *0 <= index < self.len()* /// @@ -604,6 +641,13 @@ impl IndexSet { pub fn shift_remove_index(&mut self, index: usize) -> Option { self.map.shift_remove_index(index).map(|(x, ())| x) } + + /// Swaps the position of two values in the set. + /// + /// ***Panics*** if `a` or `b` are out of bounds. + pub fn swap_indices(&mut self, a: usize, b: usize) { + self.map.swap_indices(a, b) + } } /// Access `IndexSet` values at indexed positions.