// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms.
// Optional Serde support #[cfg(feature = "serde_impl")] pubmod serde; // Optional Heapsize support #[cfg(feature = "heapsize_impl")] mod heapsize; #[cfg(test)] mod tests;
use std::borrow::Borrow; use std::cmp::Ordering; use std::collections::hash_map::{self, HashMap}; use std::fmt; use std::hash::{BuildHasher, Hash, Hasher}; use std::iter; use std::marker; use std::mem; use std::ops::{Index, IndexMut}; use std::ptr::{self, addr_of_mut};
// This type exists only to support borrowing `KeyRef`s, which cannot be borrowed to `Q` directly // due to conflicting implementations of `Borrow`. The layout of `&Qey<Q>` must be identical to // `&Q` in order to support transmuting in the `Qey::from_ref` method. #[derive(Hash, PartialEq, Eq)] #[repr(transparent)] struct Qey<Q: ?Sized>(Q);
// drop empty node without dropping its key and value unsafefn drop_empty_node<K, V>(the_box: *mut Node<K, V>) { // Safety: // In this crate all `Node` is allocated via `Box` or `alloc`, and `Box` uses the // Global allocator for its allocation, // (https://doc.rust-lang.org/std/boxed/index.html#memory-layout) so we can safely // deallocate the pointer to `Node` by calling `dealloc` method let layout = std::alloc::Layout::new::<Node<K, V>>();
std::alloc::dealloc(the_box as *mut u8, layout);
}
// Caller must check `!self.head.is_null()` unsafefn drop_entries(&mutself) { letmut cur = (*self.head).next; while cur != self.head { let next = (*cur).next; Box::from_raw(cur);
cur = next;
}
}
/// Creates an empty linked hash map with the given initial hash builder. pubfn with_hasher(hash_builder: S) -> Self { Self::with_map(HashMap::with_hasher(hash_builder))
}
/// Creates an empty linked hash map with the given initial capacity and hash builder. pubfn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { Self::with_map(HashMap::with_capacity_and_hasher(capacity, hash_builder))
}
/// Reserves capacity for at least `additional` more elements to be inserted into the map. The /// map may reserve more space to avoid frequent allocations. /// /// # Panics /// /// Panics if the new allocation size overflows `usize.` pubfn reserve(&mutself, additional: usize) { self.map.reserve(additional);
}
/// Shrinks the capacity of the map as much as possible. It will drop down as much as possible /// while maintaining the internal rules and possibly leaving some space in accordance with the /// resize policy. pubfn shrink_to_fit(&mutself) { self.map.shrink_to_fit(); self.clear_free_list();
}
/// Gets the given key's corresponding entry in the map for in-place manipulation. /// /// # Examples /// /// ``` /// use linked_hash_map::LinkedHashMap; /// /// let mut letters = LinkedHashMap::new(); /// /// for ch in "a short treatise on fungi".chars() { /// let counter = letters.entry(ch).or_insert(0); /// *counter += 1; /// } /// /// assert_eq!(letters[&'s'], 2); /// assert_eq!(letters[&'t'], 3); /// assert_eq!(letters[&'u'], 1); /// assert_eq!(letters.get(&'y'), None); /// ``` pubfn entry(&mutself, k: K) -> Entry<K, V, S> { let self_ptr: *mutSelf = self;
/// Returns an iterator visiting all entries in insertion order. /// Iterator element type is `OccupiedEntry<K, V, S>`. Allows for removal /// as well as replacing the entry. /// /// # Examples /// ``` /// use linked_hash_map::LinkedHashMap; /// /// let mut map = LinkedHashMap::new(); /// map.insert("a", 10); /// map.insert("c", 30); /// map.insert("b", 20); /// /// { /// let mut iter = map.entries(); /// let mut entry = iter.next().unwrap(); /// assert_eq!(&"a", entry.key()); /// *entry.get_mut() = 17; /// } /// /// assert_eq!(&17, map.get(&"a").unwrap()); /// ``` pubfn entries(&mutself) -> Entries<K, V, S> { let head = if !self.head.is_null() { unsafe { (*self.head).prev }
} else {
ptr::null_mut()
};
Entries {
map: self,
head,
remaining: self.len(),
marker: marker::PhantomData,
}
}
/// Inserts a key-value pair into the map. If the key already existed, the old value is /// returned. /// /// # Examples /// /// ``` /// use linked_hash_map::LinkedHashMap; /// let mut map = LinkedHashMap::new(); /// /// map.insert(1, "a"); /// map.insert(2, "b"); /// assert_eq!(map[&1], "a"); /// assert_eq!(map[&2], "b"); /// ``` pubfn insert(&mutself, k: K, v: V) -> Option<V> { self.ensure_guard_node();
let (node, old_val) = matchself.map.get(&KeyRef { k: &k }) {
Some(node) => { let old_val = unsafe { ptr::replace(&mut (**node).value, v) };
(*node, Some(old_val))
}
None => { let node = ifself.free.is_null() { Box::into_raw(Box::new(Node::new(k, v)))
} else { // use a recycled box unsafe { let free = self.free; self.free = (*free).next;
ptr::write(free, Node::new(k, v));
free
}
};
(node, None)
}
}; match old_val {
Some(_) => { // Existing node, just update LRU position self.detach(node); self.attach(node);
}
None => { let keyref = unsafe { &(*node).key }; self.map.insert(KeyRef { k: keyref }, node); self.attach(node);
}
}
old_val
}
/// Checks if the map contains the given key. pubfn contains_key<Q: ?Sized>(&self, k: &Q) -> bool where
K: Borrow<Q>,
Q: Eq + Hash,
{ self.map.contains_key(Qey::from_ref(k))
}
/// Returns the value corresponding to the key in the map. /// /// # Examples /// /// ``` /// use linked_hash_map::LinkedHashMap; /// let mut map = LinkedHashMap::new(); /// /// map.insert(1, "a"); /// map.insert(2, "b"); /// map.insert(2, "c"); /// map.insert(3, "d"); /// /// assert_eq!(map.get(&1), Some(&"a")); /// assert_eq!(map.get(&2), Some(&"c")); /// ``` pubfn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where
K: Borrow<Q>,
Q: Eq + Hash,
{ self.map
.get(Qey::from_ref(k))
.map(|e| unsafe { &(**e).value })
}
/// Returns the mutable reference corresponding to the key in the map. /// /// # Examples /// /// ``` /// use linked_hash_map::LinkedHashMap; /// let mut map = LinkedHashMap::new(); /// /// map.insert(1, "a"); /// map.insert(2, "b"); /// /// *map.get_mut(&1).unwrap() = "c"; /// assert_eq!(map.get(&1), Some(&"c")); /// ``` pubfn get_mut<Q: ?Sized>(&mutself, k: &Q) -> Option<&mut V> where
K: Borrow<Q>,
Q: Eq + Hash,
{ self.map
.get(Qey::from_ref(k))
.map(|e| unsafe { &mut (**e).value })
}
/// Returns the value corresponding to the key in the map. /// /// If value is found, it is moved to the end of the list. /// This operation can be used in implemenation of LRU cache. /// /// # Examples /// /// ``` /// use linked_hash_map::LinkedHashMap; /// let mut map = LinkedHashMap::new(); /// /// map.insert(1, "a"); /// map.insert(2, "b"); /// map.insert(3, "d"); /// /// assert_eq!(map.get_refresh(&2), Some(&mut "b")); /// /// assert_eq!((&2, &"b"), map.iter().rev().next().unwrap()); /// ``` pubfn get_refresh<Q: ?Sized>(&mutself, k: &Q) -> Option<&='color:red'>mut V> where
K: Borrow<Q>,
Q: Eq + Hash,
{ let (value, node_ptr_opt) = matchself.map.get(Qey::from_ref(k)) {
None => (None, None),
Some(node) => (Some(unsafe { &mut (**node).value }), Some(*node)),
}; iflet Some(node_ptr) = node_ptr_opt { self.detach(node_ptr); self.attach(node_ptr);
}
value
}
/// Removes and returns the value corresponding to the key from the map. /// /// # Examples /// /// ``` /// use linked_hash_map::LinkedHashMap; /// let mut map = LinkedHashMap::new(); /// /// map.insert(2, "a"); /// /// assert_eq!(map.remove(&1), None); /// assert_eq!(map.remove(&2), Some("a")); /// assert_eq!(map.remove(&2), None); /// assert_eq!(map.len(), 0); /// ``` pubfn remove<Q: ?Sized>(&mutself, k: &Q) -> Option<V> where
K: Borrow<Q>,
Q: Eq + Hash,
{ let removed = self.map.remove(Qey::from_ref(k));
removed.map(|node| { self.detach(node); unsafe { // add to free list
(*node).next = self.free; self.free = node; // drop the key and return the value
drop(ptr::read(&(*node).key));
ptr::read(&(*node).value)
}
})
}
/// Returns the maximum number of key-value pairs the map can hold without reallocating. /// /// # Examples /// /// ``` /// use linked_hash_map::LinkedHashMap; /// let mut map: LinkedHashMap<i32, &str> = LinkedHashMap::new(); /// let capacity = map.capacity(); /// ``` pubfn capacity(&self) -> usize { self.map.capacity()
}
/// Removes the first entry. /// /// Can be used in implementation of LRU cache. /// /// # Examples /// /// ``` /// use linked_hash_map::LinkedHashMap; /// let mut map = LinkedHashMap::new(); /// map.insert(1, 10); /// map.insert(2, 20); /// map.pop_front(); /// assert_eq!(map.get(&1), None); /// assert_eq!(map.get(&2), Some(&20)); /// ``` #[inline] pubfn pop_front(&mutself) -> Option<(K, V)> { ifself.is_empty() { return None;
} let lru = unsafe { (*self.head).prev }; self.detach(lru); self.map
.remove(&KeyRef {
k: unsafe { &(*lru).key },
})
.map(|e| { let e = *unsafe { Box::from_raw(e) };
(e.key, e.value)
})
}
/// Returns the number of key-value pairs in the map. pubfn len(&self) -> usize { self.map.len()
}
/// Returns whether the map is currently empty. pubfn is_empty(&self) -> bool { self.len() == 0
}
/// Returns a reference to the map's hasher. pubfn hasher(&self) -> &S { self.map.hasher()
}
/// Clears the map of all key-value pairs. pubfn clear(&mutself) { self.map.clear(); // update the guard node if present if !self.head.is_null() { unsafe { self.drop_entries();
(*self.head).prev = self.head;
(*self.head).next = self.head;
}
}
}
/// Returns a double-ended iterator visiting all key-value pairs in order of insertion. /// Iterator element type is `(&'a K, &'a V)` /// /// # Examples /// ``` /// use linked_hash_map::LinkedHashMap; /// /// let mut map = LinkedHashMap::new(); /// map.insert("a", 10); /// map.insert("c", 30); /// map.insert("b", 20); /// /// let mut iter = map.iter(); /// assert_eq!((&"a", &10), iter.next().unwrap()); /// assert_eq!((&"c", &30), iter.next().unwrap()); /// assert_eq!((&"b", &20), iter.next().unwrap()); /// assert_eq!(None, iter.next()); /// ``` pubfn iter(&self) -> Iter<K, V> { let head = ifself.head.is_null() {
ptr::null_mut()
} else { unsafe { (*self.head).prev }
};
Iter {
head,
tail: self.head,
remaining: self.len(),
marker: marker::PhantomData,
}
}
/// Returns a double-ended iterator visiting all key-value pairs in order of insertion. /// Iterator element type is `(&'a K, &'a mut V)` /// # Examples /// ``` /// use linked_hash_map::LinkedHashMap; /// /// let mut map = LinkedHashMap::new(); /// map.insert("a", 10); /// map.insert("c", 30); /// map.insert("b", 20); /// /// { /// let mut iter = map.iter_mut(); /// let mut entry = iter.next().unwrap(); /// assert_eq!(&"a", entry.0); /// *entry.1 = 17; /// } /// /// assert_eq!(&17, map.get(&"a").unwrap()); /// ``` pubfn iter_mut(&mutself) -> IterMut<K, V> { let head = ifself.head.is_null() {
ptr::null_mut()
} else { unsafe { (*self.head).prev }
};
IterMut {
head,
tail: self.head,
remaining: self.len(),
marker: marker::PhantomData,
}
}
/// Clears the map, returning all key-value pairs as an iterator. Keeps the /// allocated memory for reuse. /// /// If the returned iterator is dropped before being fully consumed, it /// drops the remaining key-value pairs. The returned iterator keeps a /// mutable borrow on the vector to optimize its implementation. /// /// Current performance implications (why to use this over into_iter()): /// /// * Clears the inner HashMap instead of dropping it /// * Puts all drained nodes in the free-list instead of deallocating them /// * Avoids deallocating the sentinel node pubfn drain(&mutself) -> Drain<K, V> { let len = self.len(); // Map should be empty now, regardless of current state self.map.clear(); let (head, tail) = if len != 0 { // This is basically the same as IntoIter's impl, but we don't // deallocate/drop anything. Instead we make the sentinel head node // point at itself (same state you get from removing the last element from a map), // and then append the entire list to the free list. At this point all the entries // have essentially been fed into mem::forget. The Drain iterator will then iterate // over those nodes in the freelist (using `len` to know where to stop) and `read` // the values out of the nodes, "unforgetting" them. // // This design results in no observable consequences for mem::forgetting the // drain iterator, because the drain iterator has no responsibility to "fix up" // things during iteration/destruction. That said, you will effectively mem::forget // any elements that weren't yielded yet. unsafe {
debug_assert!(!self.head.is_null());
debug_assert!(!(*self.head).prev.is_null());
debug_assert!((*self.head).prev != self.head); let head = (*self.head).prev; let tail = (*self.head).next;
(*self.head).prev = self.head;
(*self.head).next = self.head;
(*head).next = self.free;
(*tail).prev = ptr::null_mut(); self.free = tail;
(head, tail)
}
} else {
(ptr::null_mut(), ptr::null_mut())
};
impl<'a, K, V> Iterator for Drain<'a, K, V> { type Item = (K, V);
fn next(&mutself) -> Option<(K, V)> { ifself.remaining == 0 { return None;
} self.remaining -= 1; unsafe { let prev = (*self.head).prev; // Read the values out, the node is in the free-list already so these will // be treated as uninit memory. let k = addr_of_mut!((*self.head).key).read(); let v = addr_of_mut!((*self.head).value).read(); self.head = prev;
Some((k, v))
}
}
impl<'a, K, V> DoubleEndedIterator for Drain<'a, K, V> { fn next_back(&mutself) -> Option<(K, V)> { ifself.remaining == 0 { return None;
} self.remaining -= 1; unsafe { let next = (*self.tail).next; // Read the values out, the node is in the free-list already so these will // be treated as uninit memory. let k = addr_of_mut!((*self.tail).key).read(); let v = addr_of_mut!((*self.tail).value).read(); self.tail = next;
Some((k, v))
}
}
}
impl<K: Hash + Eq, V, S: BuildHasher> IntoIterator for LinkedHashMap<K, V, S> { type Item = (K, V); type IntoIter = IntoIter<K, V>; fn into_iter(mutself) -> IntoIter<K, V> { let (head, tail) = if !self.head.is_null() { unsafe { ((*self.head).prev, (*self.head).next) }
} else {
(ptr::null_mut(), ptr::null_mut())
}; let len = self.len();
if !self.head.is_null() { unsafe { drop_empty_node(self.head) }
} self.clear_free_list(); // drop the HashMap but not the LinkedHashMap unsafe {
ptr::drop_in_place(&mutself.map);
}
mem::forget(self);
/// A view into a single location in a map, which may be vacant or occupied. pubenum Entry<'a, K: 'a, V: 'a, S: 'a = hash_map::RandomState> { /// An occupied Entry.
Occupied(OccupiedEntry<'a, K, V, S>), /// A vacant Entry.
Vacant(VacantEntry<'a, K, V, S>),
}
/// A view into a single occupied location in a `LinkedHashMap`. pubstruct OccupiedEntry<'a, K: 'a, V: 'a, S: 'a = hash_map::RandomState> {
entry: *mut Node<K, V>,
map: *mut LinkedHashMap<K, V, S>,
marker: marker::PhantomData<&'a K>,
}
/// A view into a single empty location in a `LinkedHashMap`. pubstruct VacantEntry<'a, K: 'a, V: 'a, S: 'a = hash_map::RandomState> {
key: K,
map: &'a mut LinkedHashMap<K, V, S>,
}
/// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. pubfn or_insert(self, default: V) -> &'a mut V { matchself {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => entry.insert(default),
}
}
/// Ensures a value is in the entry by inserting the result of the default function if empty, /// and returns a mutable reference to the value in the entry. pubfn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V { matchself {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => entry.insert(default()),
}
}
/// Provides in-place mutable access to an occupied entry before any /// potential inserts into the map. pubfn and_modify<F>(self, f: F) -> Self where
F: FnOnce(&mut V),
{ matchself {
Entry::Occupied(mut entry) => {
f(entry.get_mut());
Entry::Occupied(entry)
}
Entry::Vacant(entry) => Entry::Vacant(entry),
}
}
/// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. pubfn or_default(self) -> &'a mut V where
V: Default,
{ matchself {
Entry::Occupied(entry) => entry.into_mut(),
Entry::Vacant(entry) => entry.insert(V::default()),
}
}
}
/// Gets a reference to the value in the entry. pubfn get(&self) -> &V { unsafe { &(*self.entry).value }
}
/// Gets a mutable reference to the value in the entry. pubfn get_mut(&mutself) -> &mut V { unsafe { &mut (*self.entry).value }
}
/// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the map itself pubfn into_mut(self) -> &'a mut V { unsafe { &mut (*self.entry).value }
}
/// Sets the value of the entry, and returns the entry's old value pubfn insert(&mutself, value: V) -> V { unsafe {
(*self.map).ensure_guard_node();
let old_val = mem::replace(&mut (*self.entry).value, value); let node_ptr: *mut Node<K, V> = self.entry;
// Existing node, just update LRU position
(*self.map).detach(node_ptr);
(*self.map).attach(node_ptr);
old_val
}
}
/// Takes the value out of the entry, and returns it pubfn remove(self) -> V { unsafe { (*self.map).remove(&(*self.entry).key) }.unwrap()
}
}
impl<'a, K: 'a + Hash + Eq, V: 'a, S: BuildHasher> VacantEntry<'a, K, V, S> { /// Gets a reference to the entry key /// /// # Examples /// /// ``` /// use linked_hash_map::LinkedHashMap; /// /// let mut map = LinkedHashMap::<String, u32>::new(); /// /// assert_eq!("foo", map.entry("foo".to_string()).key()); /// ``` pubfn key(&self) -> &K {
&self.key
}
/// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it pubfn insert(self, value: V) -> &'a mut V { self.map.ensure_guard_node();
let node = ifself.map.free.is_null() { Box::into_raw(Box::new(Node::new(self.key, value)))
} else { // use a recycled box unsafe { let free = self.map.free; self.map.free = (*free).next;
ptr::write(free, Node::new(self.key, value));
free
}
};
let keyref = unsafe { &(*node).key };
self.map.attach(node);
let ret = self.map.map.entry(KeyRef { k: keyref }).or_insert(node); unsafe { &mut (**ret).value }
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.46 Sekunden
(vorverarbeitet am 2026-06-18)
¤
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.