Bug 1716518 - Upgrade indexmap to v1.6.2. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D117801
This commit is contained in:
Mike Hommey 2021-06-15 21:24:47 +00:00
parent 2d1c12dc65
commit f80a15d44b
11 changed files with 597 additions and 260 deletions

4
Cargo.lock generated
View File

@ -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",

View File

@ -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"}
{"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"}

View File

@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "indexmap"
version = "1.6.0"
version = "1.6.2"
authors = ["bluss", "Josh Stone <cuviper@gmail.com>"]
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"

View File

@ -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.

View File

@ -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;

View File

@ -252,6 +252,13 @@ impl<K, V, S> IndexMap<K, V, S> {
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<K, V, S> IndexMap<K, V, S> {
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<K, V, S> IndexMap<K, V, S>
@ -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<K, V, S> IndexMap<K, V, S> {
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<K, V, S> IndexMap<K, V, S> {
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')];

View File

@ -34,6 +34,27 @@ fn get_hash<K, V>(entries: &[Bucket<K, V>]) -> impl Fn(&usize) -> u64 + '_ {
move |&i| entries[i].hash.get()
}
#[inline]
fn equivalent<'a, K, V, Q: ?Sized + Equivalent<K>>(
key: &'a Q,
entries: &'a [Bucket<K, V>],
) -> impl Fn(&usize) -> bool + 'a {
move |&i| Q::equivalent(key, &entries[i].key)
}
#[inline]
fn erase_index(table: &mut RawTable<usize>, hash: HashValue, index: usize) {
table.erase_entry(hash.get(), move |&i| i == index);
}
#[inline]
fn update_index(table: &mut RawTable<usize>, hash: HashValue, old: usize, new: usize) {
let index = table
.get_mut(hash.get(), move |&i| i == old)
.expect("index not found");
*index = new;
}
impl<K, V> Clone for IndexMapCore<K, V>
where
K: Clone,
@ -129,6 +150,13 @@ impl<K, V> IndexMapCore<K, V> {
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<R>(&mut self, range: R) -> Drain<'_, Bucket<K, V>>
where
R: RangeBounds<usize>,
@ -138,6 +166,18 @@ impl<K, V> IndexMapCore<K, V> {
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<K, V> IndexMapCore<K, V> {
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<K, V> IndexMapCore<K, V> {
i
}
/// Return the index in `entries` where an equivalent key can be found
pub(crate) fn get_index_of<Q>(&self, hash: HashValue, key: &Q) -> Option<usize>
where
Q: ?Sized + Equivalent<K>,
{
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<V>)
where
K: Eq,
@ -191,6 +240,154 @@ impl<K, V> IndexMapCore<K, V> {
}
}
/// Remove an entry by shifting all entries that follow it
pub(crate) fn shift_remove_full<Q>(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)>
where
Q: ?Sized + Equivalent<K>,
{
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<Q>(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)>
where
Q: ?Sized + Equivalent<K>,
{
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<F>(&mut self, mut keep: F)
where
F: FnMut(&mut K, &mut V) -> bool,
@ -225,6 +422,17 @@ impl<K, V> IndexMapCore<K, V> {
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<F>(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<F>(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<K, V> 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

View File

@ -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<usize>;
pub(super) struct DebugIndices<'a>(pub &'a RawTable<usize>);
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<K, V> IndexMapCore<K, V> {
/// Return the raw bucket with an equivalent key
fn find_equivalent<Q>(&self, hash: HashValue, key: &Q) -> Option<RawBucket>
where
Q: ?Sized + Equivalent<K>,
{
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<RawBucket> {
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<Q>(&self, hash: HashValue, key: &Q) -> Option<usize>
where
Q: ?Sized + Equivalent<K>,
{
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<K, V> IndexMapCore<K, V> {
}
}
/// Remove an entry by shifting all entries that follow it
pub(crate) fn shift_remove_full<Q>(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)>
where
Q: ?Sized + Equivalent<K>,
{
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<Item = &mut usize> {
// 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<Q>(&mut self, hash: HashValue, key: &Q) -> Option<(usize, K, V)>
where
Q: ?Sized + Equivalent<K>,
{
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<K: Sync, V: Sync> 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)
}
}

View File

@ -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<K, V, S> Serialize for IndexMap<K, V, S>
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<K, V, S>
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<T, S> Serialize for IndexSet<T, S>
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<T, S>
where
T: Deserialize<'de> + Eq + Hash,

View File

@ -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<i32, u64>,
//! // ...
//! }
//! ```
//!
//! 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<i32, u64>,
/// // ...
/// }
/// ```
///
/// Requires crate feature `"serde"` or `"serde-1"`
pub fn serialize<K, V, S, T>(map: &IndexMap<K, V, S>, serializer: T) -> Result<T::Ok, T::Error>
where
K: Serialize + Hash + Eq,
V: Serialize,
S: BuildHasher,
T: Serializer,
{
serializer.collect_seq(map)
}
/// Visitor to deserialize a *sequenced* `IndexMap`
struct SeqVisitor<K, V, S>(PhantomData<(K, V, S)>);
impl<'de, K, V, S> Visitor<'de> for SeqVisitor<K, V, S>
where
K: Deserialize<'de> + Eq + Hash,
V: Deserialize<'de>,
S: Default + BuildHasher,
{
type Value = IndexMap<K, V, S>;
fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
write!(formatter, "a sequenced map")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
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<i32, u64>,
/// // ...
/// }
/// ```
///
/// Requires crate feature `"serde"` or `"serde-1"`
pub fn deserialize<'de, D, K, V, S>(deserializer: D) -> Result<IndexMap<K, V, S>, D::Error>
where
D: Deserializer<'de>,
K: Deserialize<'de> + Eq + Hash,
V: Deserialize<'de>,
S: Default + BuildHasher,
{
deserializer.deserialize_seq(SeqVisitor(PhantomData))
}

View File

@ -200,6 +200,13 @@ impl<T, S> IndexSet<T, S> {
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<T, S> IndexSet<T, S> {
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<T, S> IndexSet<T, S>
@ -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<Q: ?Sized>(&mut self, value: &Q) -> Option<(usize, T)>
@ -576,23 +599,37 @@ impl<T, S> IndexSet<T, S> {
///
/// 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<T> {
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<T, S> IndexSet<T, S> {
pub fn shift_remove_index(&mut self, index: usize) -> Option<T> {
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.