/// A version of `HashMap` that has a user controllable order for its entries. /// /// It achieves this by keeping its entries in an internal linked list and using a `HashMap` to /// point at nodes in this linked list. /// /// The order of entries defaults to "insertion order", but the user can also modify the order of /// existing entries by manually moving them to the front or back. /// /// There are two kinds of methods that modify the order of the internal list: /// /// * Methods that have names like `to_front` and `to_back` will unsurprisingly move an existing /// entry to the front or back /// * Methods that have the word `insert` will insert a new entry ot the back of the list, and if /// that method might replace an entry, that method will *also move that existing entry to the /// back*. pubstruct LinkedHashMap<K, V, S = DefaultHashBuilder> {
table: HashTable<NonNull<Node<K, V>>>, // We always need to keep our custom hash builder outside of the HashTable, because it doesn't // know how to do any hashing itself.
hash_builder: S, // Circular linked list of nodes. If `values` is non-null, it will point to a "guard node" // which will never have an initialized key or value, `values.prev` will contain the last key / // value in the list, `values.next` will contain the first key / value in the list.
values: Option<NonNull<Node<K, V>>>, // *Singly* linked list of free nodes. The `prev` pointers in the free list should be assumed // invalid.
free: Option<NonNull<Node<K, V>>>,
}
/// Inserts the given key / value pair at the *back* of the internal linked list. /// /// Returns the previously set value, if one existed prior to this call. After this call, /// calling `LinkedHashMap::back` will return a reference to this key / value pair. #[inline] pubfn insert(&mutself, k: K, v: V) -> Option<V> { matchself.raw_entry_mut().from_key(&k) {
RawEntryMut::Occupied(mut occupied) => {
occupied.to_back();
Some(occupied.replace_value(v))
}
RawEntryMut::Vacant(vacant) => {
vacant.insert(k, v);
None
}
}
}
/// If the given key is not in this map, inserts the key / value pair at the *back* of the /// internal linked list and returns `None`, otherwise, replaces the existing value with the /// given value *without* moving the entry in the internal linked list and returns the previous /// value. #[inline] pubfn replace(&mutself, k: K, v: V) -> Option<V> { matchself.raw_entry_mut().from_key(&k) {
RawEntryMut::Occupied(mut occupied) => Some(occupied.replace_value(v)),
RawEntryMut::Vacant(vacant) => {
vacant.insert(k, v);
None
}
}
}
/// If an entry with this key exists, move it to the front of the list and return a reference to /// the value. #[inline] pubfn to_front<Q>(&mutself, k: &Q) -> Option<&mut V> where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{ matchself.raw_entry_mut().from_key(k) {
RawEntryMut::Occupied(mut occupied) => {
occupied.to_front();
Some(occupied.into_mut())
}
RawEntryMut::Vacant(_) => None,
}
}
/// If an entry with this key exists, move it to the back of the list and return a reference to /// the value. #[inline] pubfn to_back<Q>(&mutself, k: &Q) -> Option<&mut V> where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{ matchself.raw_entry_mut().from_key(k) {
RawEntryMut::Occupied(mut occupied) => {
occupied.to_back();
Some(occupied.into_mut())
}
RawEntryMut::Vacant(_) => None,
}
}
iflet Some(values) = self.values { unsafe { letmut cur = values.as_ref().links.value.next; while cur != values { let next = cur.as_ref().links.value.next; let filter = { let (k, v) = (*cur.as_ptr()).entry_mut();
!f(k, v)
}; if filter { let k = (*cur.as_ptr()).key_ref(); let hash = hash_key(&self.hash_builder, k); self.table
.find_entry(hash, |o| (*o).as_ref().key_ref().eq(k))
.unwrap()
.remove();
drop_filtered_values.drop_later(cur);
}
cur = next;
}
}
}
}
/// Returns the `CursorMut` over the front node. /// /// Note: The `CursorMut` is pointing to the _guard_ node in an empty `LinkedHashMap` and /// will always return `None` as its current element, regardless of any move in any /// direction. pubfn cursor_front_mut(&mutself) -> CursorMut<K, V, S> { letmut c = self.cursor_mut();
c.move_next();
c
}
/// Returns the `CursorMut` over the back node. /// /// Note: The `CursorMut` is pointing to the _guard_ node in an empty `LinkedHashMap` and /// will always return `None` as its current element, regardless of any move in any /// direction. pubfn cursor_back_mut(&mutself) -> CursorMut<K, V, S> { letmut c = self.cursor_mut();
c.move_prev();
c
}
}
impl<'a, K, V, S> Entry<'a, K, V, S> { /// If this entry is vacant, inserts a new entry with the given value and returns a reference to /// it. /// /// If this entry is occupied, this method *moves the occupied entry to the back of the internal /// linked list* and returns a reference to the existing value. #[inline] pubfn or_insert(self, default: V) -> &'a mut V where
K: Hash,
S: BuildHasher,
{ matchself {
Entry::Occupied(mut entry) => {
entry.to_back();
entry.into_mut()
}
Entry::Vacant(entry) => entry.insert(default),
}
}
/// Similar to `Entry::or_insert`, but accepts a function to construct a new value if this entry /// is vacant. #[inline] pubfn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V where
K: Hash,
S: BuildHasher,
{ matchself {
Entry::Occupied(mut entry) => {
entry.to_back();
entry.into_mut()
}
Entry::Vacant(entry) => entry.insert(default()),
}
}
/// Replaces this entry's value with the provided value. /// /// Similarly to `LinkedHashMap::insert`, this moves the existing entry to the back of the /// internal linked list. #[inline] pubfn insert(&mutself, value: V) -> V { self.raw_entry.to_back(); self.raw_entry.replace_value(value)
}
#[inline] pubfn remove(self) -> V { self.raw_entry.remove()
}
/// Similar to `OccupiedEntry::replace_entry`, but *does* move the entry to the back of the /// internal linked list. #[inline] pubfn insert_entry(mutself, value: V) -> (K, V) { self.raw_entry.to_back(); self.replace_entry(value)
}
/// Returns a `CursorMut` over the current entry. #[inline] pubfn cursor_mut(self) -> CursorMut<'a, K, V, S> where
K: Eq + Hash,
S: BuildHasher,
{ self.raw_entry.cursor_mut()
}
/// Replaces the entry's key with the key provided to `LinkedHashMap::entry`, and replaces the /// entry's value with the given `value` parameter. /// /// Does *not* move the entry to the back of the internal linked list. pubfn replace_entry(mutself, value: V) -> (K, V) { let old_key = mem::replace(self.raw_entry.key_mut(), self.key); let old_value = mem::replace(self.raw_entry.get_mut(), value);
(old_key, old_value)
}
/// Replaces this entry's key with the key provided to `LinkedHashMap::entry`. /// /// Does *not* move the entry to the back of the internal linked list. #[inline] pubfn replace_key(mutself) -> K {
mem::replace(self.raw_entry.key_mut(), self.key)
}
}
/// Insert's the key for this vacant entry paired with the given value as a new entry at the /// *back* of the internal linked list. #[inline] pubfn insert(self, value: V) -> &'a mut V where
K: Hash,
S: BuildHasher,
{ self.raw_entry.insert(self.key, value).1
}
}
impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { /// Similarly to `Entry::or_insert`, if this entry is occupied, it will move the existing entry /// to the back of the internal linked list. #[inline] pubfn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a mut V) where
K: Hash,
S: BuildHasher,
{ matchself {
RawEntryMut::Occupied(mut entry) => {
entry.to_back();
entry.into_key_value()
}
RawEntryMut::Vacant(entry) => entry.insert(default_key, default_val),
}
}
/// Similarly to `Entry::or_insert_with`, if this entry is occupied, it will move the existing /// entry to the back of the internal linked list. #[inline] pubfn or_insert_with<F>(self, default: F) -> (&'a mut K, &'a mut V) where
F: FnOnce() -> (K, V),
K: Hash,
S: BuildHasher,
{ matchself {
RawEntryMut::Occupied(mut entry) => {
entry.to_back();
entry.into_key_value()
}
RawEntryMut::Vacant(entry) => { let (k, v) = default();
entry.insert(k, v)
}
}
}
/// The `CursorMut` struct and its implementation provide the basic mutable Cursor API for Linked /// lists as proposed in /// [here](https://github.com/rust-lang/rfcs/blob/master/text/2570-linked-list-cursors.md), with /// several exceptions: /// /// - It behaves similarly to Rust's Iterators, returning `None` when the end of the list is /// reached. A _guard_ node is positioned between the head and tail of the linked list to /// facilitate this. If the cursor is over this guard node, `None` is returned, signaling the end /// or start of the list. From this position, the cursor can move in either direction as the /// linked list is circular, with the guard node connecting the two ends. /// - The current implementation does not include an `index` method, as it does not track the index /// of its elements. It provides access to each map entry as a tuple of `(&K, &mut V)`. /// pubstruct CursorMut<'a, K, V, S> {
cur: *mut Node<K, V>,
hash_builder: &'a S,
free: &'a mut Option<NonNull<Node<K, V>>>,
values: &'a mut Option<NonNull<Node<K, V>>>,
table: &'a mut hashbrown::HashTable<NonNull<Node<K, V>>>,
}
impl<'a, K, V, S> CursorMut<'a, K, V, S> { /// Returns an `Option` of the current element in the list, provided it is not the /// _guard_ node, and `None` overwise. #[inline] pubfn current(&mutself) -> Option<(&K, &mut V)> { unsafe { let at = NonNull::new_unchecked(self.cur); self.peek(at)
}
}
/// Retrieves the next element in the list (moving towards the end). #[inline] pubfn peek_next(&mutself) -> Option<(&K, &mut V)> { unsafe { let at = (*self.cur).links.value.next; self.peek(at)
}
}
/// Retrieves the previous element in the list (moving towards the front). #[inline] pubfn peek_prev(&mutself) -> Option<(&K, &mut V)> { unsafe { let at = (*self.cur).links.value.prev; self.peek(at)
}
}
// Retrieves the element without advancing current position to it. #[inline] fn peek(&mutself, at: NonNull<Node<K, V>>) -> Option<(&K, &'color:red'>mut V)> { iflet Some(values) = self.values { unsafe { let node = at.as_ptr(); if node == values.as_ptr() {
None
} else { let entry = (*node).entry_mut();
Some((&entry.0, &mut entry.1))
}
}
} else {
None
}
}
/// Updates the pointer to the current element to the next element in the /// list (that is, moving towards the end). #[inline] pubfn move_next(&mutself) { let at = unsafe { (*self.cur).links.value.next }; self.muv(at);
}
/// Updates the pointer to the current element to the previous element in the /// list (that is, moving towards the front). #[inline] pubfn move_prev(&mutself) { let at = unsafe { (*self.cur).links.value.prev }; self.muv(at);
}
// Updates the pointer to the current element to the one returned by the at closure function. #[inline] fn muv(&mutself, at: NonNull<Node<K, V>>) { self.cur = at.as_ptr();
}
/// Inserts the provided key and value before the current element. It checks if an entry /// with the given key exists and, if so, replaces its value with the provided `key` /// parameter. The key is not updated; this matters for types that can be `==` without /// being identical. /// /// If the entry doesn't exist, it creates a new one. If a value has been updated, the /// function returns the *old* value wrapped with `Some` and `None` otherwise. #[inline] pubfn insert_before(&mutself, key: K, value: V) -> Option<V> where
K: Eq + Hash,
S: BuildHasher,
{ let before = unsafe { NonNull::new_unchecked(self.cur) }; self.insert(key, value, before)
}
/// Inserts the provided key and value after the current element. It checks if an entry /// with the given key exists and, if so, replaces its value with the provided `key` /// parameter. The key is not updated; this matters for types that can be `==` without /// being identical. /// /// If the entry doesn't exist, it creates a new one. If a value has been updated, the /// function returns the *old* value wrapped with `Some` and `None` otherwise. #[inline] pubfn insert_after(&mutself, key: K, value: V) -> Option<V> where
K: Eq + Hash,
S: BuildHasher,
{ let before = unsafe { (*self.cur).links.value.next }; self.insert(key, value, before)
}
// Inserts an element immediately before the given `before` node. #[inline] fn insert(&mutself, key: K, value: V, before: NonNull<Node<K, V>>) -> Option<V> where
K: Eq + Hash,
S: BuildHasher,
{ unsafe { let hash = hash_key(self.hash_builder, &key); let i_entry = self
.table
.find_entry(hash, |o| (*o).as_ref().key_ref().eq(&key));
// Given node is assumed to be the guard node and is *not* dropped. #[inline] unsafefn drop_value_nodes<K, V>(guard: NonNull<Node<K, V>>) { letmut cur = guard.as_ref().links.value.prev; while cur != guard { let prev = cur.as_ref().links.value.prev;
cur.as_mut().take_entry(); let _ = Box::from_raw(cur.as_ptr());
cur = prev;
}
}
// Drops all linked free nodes starting with the given node. Free nodes are only non-circular // singly linked, and should have uninitialized keys / values. #[inline] unsafefn drop_free_nodes<K, V>(mut free: Option<NonNull<Node<K, V>>>) { whilelet Some(some_free) = free { let next_free = some_free.as_ref().links.free.next; let _ = Box::from_raw(some_free.as_ptr());
free = next_free;
}
}
// We do not drop the key and value when a value is filtered from the map during the call to // `retain`. We need to be very careful not to have a live `HashMap` entry pointing to // either a dangling `Node` or a `Node` with dropped keys / values. Since the key and value // types may panic on drop, they may short-circuit the entry in the map actually being // removed. Instead, we push the removed nodes onto the free list eagerly, then try and // drop the keys and values for any newly freed nodes *after* `HashMap::retain` has // completely finished. struct DropFilteredValues<'a, K, V> {
free: &'a mut Option<NonNull<Node<K, V>>>,
cur_free: Option<NonNull<Node<K, V>>>,
}
impl<'a, K, V> Drop for DropFilteredValues<'a, K, V> { fn drop(&mutself) { unsafe { let end_free = self.cur_free; whileself.cur_free != *self.free { let cur_free = self.cur_free.as_ptr();
(*cur_free).take_entry(); self.cur_free = (*cur_free).links.free.next;
}
*self.free = end_free;
}
}
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.27Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-17)
¤
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.