//! Opt-in access to the experimental raw entry API. //! //! This module is designed to mimic the raw entry API of [`HashMap`][std::collections::hash_map], //! matching its unstable state as of Rust 1.75. See the tracking issue //! [rust#56167](https://github.com/rust-lang/rust/issues/56167) for more details. //! //! The trait [`RawEntryApiV1`] and the `_v1` suffix on its methods are meant to insulate this for //! the future, in case later breaking changes are needed. If the standard library stabilizes its //! `hash_raw_entry` feature (or some replacement), matching *inherent* methods will be added to //! `IndexMap` without such an opt-in trait.
usesuper::raw::RawTableEntry; usesuper::IndexMapCore; usecrate::{Equivalent, HashValue, IndexMap}; use core::fmt; use core::hash::{BuildHasher, Hash, Hasher}; use core::marker::PhantomData; use core::mem;
/// Opt-in access to the experimental raw entry API. /// /// See the [`raw_entry_v1`][self] module documentation for more information. pubtrait RawEntryApiV1<K, V, S>: private::Sealed { /// Creates a raw immutable entry builder for the [`IndexMap`]. /// /// Raw entries provide the lowest level of control for searching and /// manipulating a map. They must be manually initialized with a hash and /// then manually searched. /// /// This is useful for /// * Hash memoization /// * Using a search key that doesn't work with the [`Equivalent`] trait /// * Using custom comparison logic without newtype wrappers /// /// Unless you are in such a situation, higher-level and more foolproof APIs like /// [`get`][IndexMap::get] should be preferred. /// /// Immutable raw entries have very limited use; you might instead want /// [`raw_entry_mut_v1`][Self::raw_entry_mut_v1]. /// /// # Examples /// /// ``` /// use core::hash::{BuildHasher, Hash}; /// use indexmap::map::{IndexMap, RawEntryApiV1}; /// /// let mut map = IndexMap::new(); /// map.extend([("a", 100), ("b", 200), ("c", 300)]); /// /// fn compute_hash<K: Hash + ?Sized, S: BuildHasher>(hash_builder: &S, key: &K) -> u64 { /// use core::hash::Hasher; /// let mut state = hash_builder.build_hasher(); /// key.hash(&mut state); /// state.finish() /// } /// /// for k in ["a", "b", "c", "d", "e", "f"] { /// let hash = compute_hash(map.hasher(), k); /// let i = map.get_index_of(k); /// let v = map.get(k); /// let kv = map.get_key_value(k); /// let ikv = map.get_full(k); /// /// println!("Key: {} and value: {:?}", k, v); /// /// assert_eq!(map.raw_entry_v1().from_key(k), kv); /// assert_eq!(map.raw_entry_v1().from_hash(hash, |q| *q == k), kv); /// assert_eq!(map.raw_entry_v1().from_key_hashed_nocheck(hash, k), kv); /// assert_eq!(map.raw_entry_v1().from_hash_full(hash, |q| *q == k), ikv); /// assert_eq!(map.raw_entry_v1().index_from_hash(hash, |q| *q == k), i); /// } /// ``` fn raw_entry_v1(&self) -> RawEntryBuilder<'_, K, V, S>;
/// Creates a raw entry builder for the [`IndexMap`]. /// /// Raw entries provide the lowest level of control for searching and /// manipulating a map. They must be manually initialized with a hash and /// then manually searched. After this, insertions into a vacant entry /// still require an owned key to be provided. /// /// Raw entries are useful for such exotic situations as: /// /// * Hash memoization /// * Deferring the creation of an owned key until it is known to be required /// * Using a search key that doesn't work with the [`Equivalent`] trait /// * Using custom comparison logic without newtype wrappers /// /// Because raw entries provide much more low-level control, it's much easier /// to put the `IndexMap` into an inconsistent state which, while memory-safe, /// will cause the map to produce seemingly random results. Higher-level and more /// foolproof APIs like [`entry`][IndexMap::entry] should be preferred when possible. /// /// Raw entries give mutable access to the keys. This must not be used /// to modify how the key would compare or hash, as the map will not re-evaluate /// where the key should go, meaning the keys may become "lost" if their /// location does not reflect their state. For instance, if you change a key /// so that the map now contains keys which compare equal, search may start /// acting erratically, with two keys randomly masking each other. Implementations /// are free to assume this doesn't happen (within the limits of memory-safety). /// /// # Examples /// /// ``` /// use core::hash::{BuildHasher, Hash}; /// use indexmap::map::{IndexMap, RawEntryApiV1}; /// use indexmap::map::raw_entry_v1::RawEntryMut; /// /// let mut map = IndexMap::new(); /// map.extend([("a", 100), ("b", 200), ("c", 300)]); /// /// fn compute_hash<K: Hash + ?Sized, S: BuildHasher>(hash_builder: &S, key: &K) -> u64 { /// use core::hash::Hasher; /// let mut state = hash_builder.build_hasher(); /// key.hash(&mut state); /// state.finish() /// } /// /// // Existing key (insert and update) /// match map.raw_entry_mut_v1().from_key("a") { /// RawEntryMut::Vacant(_) => unreachable!(), /// RawEntryMut::Occupied(mut view) => { /// assert_eq!(view.index(), 0); /// assert_eq!(view.get(), &100); /// let v = view.get_mut(); /// let new_v = (*v) * 10; /// *v = new_v; /// assert_eq!(view.insert(1111), 1000); /// } /// } /// /// assert_eq!(map["a"], 1111); /// assert_eq!(map.len(), 3); /// /// // Existing key (take) /// let hash = compute_hash(map.hasher(), "c"); /// match map.raw_entry_mut_v1().from_key_hashed_nocheck(hash, "c") { /// RawEntryMut::Vacant(_) => unreachable!(), /// RawEntryMut::Occupied(view) => { /// assert_eq!(view.index(), 2); /// assert_eq!(view.shift_remove_entry(), ("c", 300)); /// } /// } /// assert_eq!(map.raw_entry_v1().from_key("c"), None); /// assert_eq!(map.len(), 2); /// /// // Nonexistent key (insert and update) /// let key = "d"; /// let hash = compute_hash(map.hasher(), key); /// match map.raw_entry_mut_v1().from_hash(hash, |q| *q == key) { /// RawEntryMut::Occupied(_) => unreachable!(), /// RawEntryMut::Vacant(view) => { /// assert_eq!(view.index(), 2); /// let (k, value) = view.insert("d", 4000); /// assert_eq!((*k, *value), ("d", 4000)); /// *value = 40000; /// } /// } /// assert_eq!(map["d"], 40000); /// assert_eq!(map.len(), 3); /// /// match map.raw_entry_mut_v1().from_hash(hash, |q| *q == key) { /// RawEntryMut::Vacant(_) => unreachable!(), /// RawEntryMut::Occupied(view) => { /// assert_eq!(view.index(), 2); /// assert_eq!(view.swap_remove_entry(), ("d", 40000)); /// } /// } /// assert_eq!(map.get("d"), None); /// assert_eq!(map.len(), 2); /// ``` fn raw_entry_mut_v1(&mutself) -> RawEntryBuilderMut<'_, K, V, S>;
}
/// A builder for computing where in an [`IndexMap`] a key-value pair would be stored. /// /// This `struct` is created by the [`IndexMap::raw_entry_v1`] method, provided by the /// [`RawEntryApiV1`] trait. See its documentation for more. pubstruct RawEntryBuilder<'a, K, V, S> {
map: &'a IndexMap<K, V, S>,
}
/// Access an entry by a key and its hash. pubfn from_key_hashed_nocheck<Q>(self, hash: u64, key: &Q) -> Option<(&'a K, &'a V)> where
Q: ?Sized + Equivalent<K>,
{ let hash = HashValue(hash as usize); let i = self.map.core.get_index_of(hash, key)?; self.map.get_index(i)
}
/// Access an entry by hash. pubfn from_hash<F>(self, hash: u64, is_match: F) -> Option<(&'a K, &'an>a V)> where
F: FnMut(&K) -> bool,
{ let map = self.map; let i = self.index_from_hash(hash, is_match)?;
map.get_index(i)
}
/// Access an entry by hash, including its index. pubfn from_hash_full<F>(self, hash: u64, is_match: F) -> Option<(usize, &'a K, &'a V)> where
F: FnMut(&K) -> bool,
{ let map = self.map; let i = self.index_from_hash(hash, is_match)?; let (key, value) = map.get_index(i)?;
Some((i, key, value))
}
/// Access the index of an entry by hash. pubfn index_from_hash<F>(self, hash: u64, mut is_match: F) -> Option<usize> where
F: FnMut(&K) -> bool,
{ let hash = HashValue(hash as usize); let entries = &*self.map.core.entries; let eq = move |&i: &usize| is_match(&entries[i].key); self.map.core.indices.get(hash.get(), eq).copied()
}
}
/// A builder for computing where in an [`IndexMap`] a key-value pair would be stored. /// /// This `struct` is created by the [`IndexMap::raw_entry_mut_v1`] method, provided by the /// [`RawEntryApiV1`] trait. See its documentation for more. pubstruct RawEntryBuilderMut<'a, K, V, S> {
map: &'a mut IndexMap<K, V, S>,
}
/// Raw entry for an existing key-value pair or a vacant location to /// insert one. pubenum RawEntryMut<'a, K, V, S> { /// Existing slot with equivalent key.
Occupied(RawOccupiedEntryMut<'a, K, V, S>), /// Vacant slot (no equivalent key in the map).
Vacant(RawVacantEntryMut<'a, K, V, S>),
}
impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { /// Return the index where the key-value pair exists or may be inserted. #[inline] pubfn index(&self) -> usize { matchself { Self::Occupied(entry) => entry.index(), Self::Vacant(entry) => entry.index(),
}
}
/// Inserts the given default key and value in the entry if it is vacant and returns mutable /// references to them. Otherwise mutable references to an already existent pair are returned. pubfn or_insert(self, default_key: K, default_value: V) -> (&'a mut K, &'a mut V) where
K: Hash,
S: BuildHasher,
{ matchself { Self::Occupied(entry) => entry.into_key_value_mut(), Self::Vacant(entry) => entry.insert(default_key, default_value),
}
}
/// Inserts the result of the `call` function in the entry if it is vacant and returns mutable /// references to them. Otherwise mutable references to an already existent pair are returned. pubfn or_insert_with<F>(self, call: F) -> (&'a mut K, &'a mut V) where
F: FnOnce() -> (K, V),
K: Hash,
S: BuildHasher,
{ matchself { Self::Occupied(entry) => entry.into_key_value_mut(), Self::Vacant(entry) => { let (key, value) = call();
entry.insert(key, value)
}
}
}
/// Modifies the entry if it is occupied. pubfn and_modify<F>(mutself, f: F) -> Self where
F: FnOnce(&mut K, &mut V),
{ ifletSelf::Occupied(entry) = &mutself { let (k, v) = entry.get_key_value_mut();
f(k, v);
} self
}
}
/// A raw view into an occupied entry in an [`IndexMap`]. /// It is part of the [`RawEntryMut`] enum. pubstruct RawOccupiedEntryMut<'a, K, V, S> {
raw: RawTableEntry<'a, K, V>,
hash_builder: PhantomData<&'a S>,
}
impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// Return the index of the key-value pair #[inline] pubfn index(&self) -> usize { self.raw.index()
}
/// 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. pubfn key(&self) -> &K {
&self.raw.bucket().key
}
/// Gets a mutable 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. pubfn key_mut(&mutself) -> &mut K {
&mutself.raw.bucket_mut().key
}
/// Converts into a mutable reference to the entry's key in the map, /// with a lifetime bound to the map itself. /// /// 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. pubfn into_key(self) -> &'a mut K {
&mutself.raw.into_bucket().key
}
/// Gets a reference to the entry's value in the map. pubfn get(&self) -> &V {
&self.raw.bucket().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 /// [`RawEntryMut`] value, see [`into_mut`][Self::into_mut]. pubfn get_mut(&mutself) -> &mut V {
&mutself.raw.bucket_mut().value
}
/// Converts into a mutable reference to the entry's value in the map, /// with a lifetime bound to the map itself. pubfn into_mut(self) -> &'a mut V {
&mutself.raw.into_bucket().value
}
/// Gets a reference to the entry's key and value in the map. pubfn get_key_value(&self) -> (&K, &V) { self.raw.bucket().refs()
}
/// Gets a reference to the entry's key and value in the map. pubfn get_key_value_mut(&mutself) -> (&mut K, &mut V) { self.raw.bucket_mut().muts()
}
/// Converts into a mutable reference to the entry's key and value in the map, /// with a lifetime bound to the map itself. pubfn into_key_value_mut(self) -> (&'a mut K, &'a mut V) { self.raw.into_bucket().muts()
}
/// Sets the value of the entry, and returns the entry's old value. pubfn insert(&mutself, value: V) -> V {
mem::replace(self.get_mut(), value)
}
/// Sets the key of the entry, and returns the entry's old key. pubfn insert_key(&mutself, key: K) -> K {
mem::replace(self.key_mut(), key)
}
/// Remove the key, value pair stored in the map for this entry, and return the value. /// /// **NOTE:** This is equivalent to [`.swap_remove()`][Self::swap_remove], replacing this /// entry's position with the last element, and it is deprecated in favor of calling that /// explicitly. If you need to preserve the relative order of the keys in the map, use /// [`.shift_remove()`][Self::shift_remove] instead. #[deprecated(note = "`remove` disrupts the map order -- \ use `swap_remove` or `shift_remove` for explicit behavior.")] pubfn remove(self) -> V { self.swap_remove()
}
/// Remove the key, value pair stored in the map for this entry, and return the value. /// /// Like [`Vec::swap_remove`][crate::Vec::swap_remove], the pair is removed by swapping it with /// the last element of the map and popping it off. /// **This perturbs the position of what used to be the last element!** /// /// Computes in **O(1)** time (average). pubfn swap_remove(self) -> V { self.swap_remove_entry().1
}
/// Remove the key, value pair stored in the map for this entry, and return the value. /// /// Like [`Vec::remove`][crate::Vec::remove], the pair is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// /// Computes in **O(n)** time (average). pubfn shift_remove(self) -> V { self.shift_remove_entry().1
}
/// Remove and return the key, value pair stored in the map for this entry /// /// **NOTE:** This is equivalent to [`.swap_remove_entry()`][Self::swap_remove_entry], /// replacing this entry's position with the last element, and it is deprecated in favor of /// calling that explicitly. If you need to preserve the relative order of the keys in the map, /// use [`.shift_remove_entry()`][Self::shift_remove_entry] instead. #[deprecated(note = "`remove_entry` disrupts the map order -- \ use `swap_remove_entry` or `shift_remove_entry` for explicit behavior.")] pubfn remove_entry(self) -> (K, V) { self.swap_remove_entry()
}
/// Remove and return the key, value pair stored in the map for this entry /// /// Like [`Vec::swap_remove`][crate::Vec::swap_remove], the pair is removed by swapping it with /// the last element of the map and popping it off. /// **This perturbs the position of what used to be the last element!** /// /// Computes in **O(1)** time (average). pubfn swap_remove_entry(self) -> (K, V) { let (map, index) = self.raw.remove_index();
map.swap_remove_finish(index)
}
/// Remove and return the key, value pair stored in the map for this entry /// /// Like [`Vec::remove`][crate::Vec::remove], the pair is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// /// Computes in **O(n)** time (average). pubfn shift_remove_entry(self) -> (K, V) { let (map, index) = self.raw.remove_index();
map.shift_remove_finish(index)
}
/// Moves the position of the entry to a new index /// by shifting all other entries in-between. /// /// This is equivalent to [`IndexMap::move_index`] /// coming `from` the current [`.index()`][Self::index]. /// /// * If `self.index() < to`, the other pairs will shift down while the targeted pair moves up. /// * If `self.index() > to`, the other pairs will shift up while the targeted pair moves down. /// /// ***Panics*** if `to` is out of bounds. /// /// Computes in **O(n)** time (average). pubfn move_index(self, to: usize) { let (map, index) = self.raw.into_inner();
map.move_index(index, to);
}
/// Swaps the position of entry with another. /// /// This is equivalent to [`IndexMap::swap_indices`] /// with the current [`.index()`][Self::index] as one of the two being swapped. /// /// ***Panics*** if the `other` index is out of bounds. /// /// Computes in **O(1)** time (average). pubfn swap_indices(self, other: usize) { let (map, index) = self.raw.into_inner();
map.swap_indices(index, other)
}
}
/// A view into a vacant raw entry in an [`IndexMap`]. /// It is part of the [`RawEntryMut`] enum. pubstruct RawVacantEntryMut<'a, K, V, S> {
map: &'a mut IndexMapCore<K, V>,
hash_builder: &'a S,
}
impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { /// Return the index where a key-value pair may be inserted. pubfn index(&self) -> usize { self.map.indices.len()
}
/// Inserts the given key and value into the map, /// and returns mutable references to them. pubfn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V) where
K: Hash,
S: BuildHasher,
{ letmut h = self.hash_builder.build_hasher();
key.hash(&mut h); self.insert_hashed_nocheck(h.finish(), key, value)
}
/// Inserts the given key and value into the map with the provided hash, /// and returns mutable references to them. pubfn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&>'a mut K, &'a mut V) { let hash = HashValue(hash as usize); let i = self.map.insert_unique(hash, key, value); self.map.entries[i].muts()
}
/// Inserts the given key and value into the map at the given index, /// shifting others to the right, and returns mutable references to them. /// /// ***Panics*** if `index` is out of bounds. /// /// Computes in **O(n)** time (average). pubfn shift_insert(self, index: usize, key: K, value: V) -> (&'a mut K, &'a mut V) where
K: Hash,
S: BuildHasher,
{ letmut h = self.hash_builder.build_hasher();
key.hash(&mut h); self.shift_insert_hashed_nocheck(index, h.finish(), key, value)
}
/// Inserts the given key and value into the map with the provided hash /// at the given index, and returns mutable references to them. /// /// ***Panics*** if `index` is out of bounds. /// /// Computes in **O(n)** time (average). pubfn shift_insert_hashed_nocheck( self,
index: usize,
hash: u64,
key: K,
value: V,
) -> (&'a mut K, &'a mut V) { let hash = HashValue(hash as usize); self.map.shift_insert_unique(index, hash, key, value); self.map.entries[index].muts()
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.