Skip to content

Commit dc53da9

Browse files
carllerchereem
authored andcommitted
Provide an iterator over OccupiedEntry
Allows iterating `LinkedHashMap` entries with the option to remove visited entries during iteration.
1 parent d26a785 commit dc53da9

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

src/lib.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,43 @@ impl<K: Hash + Eq, V, S: BuildHasher> LinkedHashMap<K, V, S> {
230230
})
231231
}
232232

233+
/// Returns an iterator visiting all entries in order insertion.
234+
/// Iterator element type is `OccupiedEntry<K, V, S>`. Allows for removal
235+
/// as well as replacing the entry.
236+
///
237+
/// # Examples
238+
/// ```
239+
/// use linked_hash_map::LinkedHashMap;
240+
///
241+
/// let mut map = LinkedHashMap::new();
242+
/// map.insert("a", 10);
243+
/// map.insert("c", 30);
244+
/// map.insert("b", 20);
245+
///
246+
/// {
247+
/// let mut iter = map.entries();
248+
/// let mut entry = iter.next().unwrap();
249+
/// assert_eq!(&"a", entry.key());
250+
/// *entry.get_mut() = 17;
251+
/// }
252+
///
253+
/// assert_eq!(&17, map.get(&"a").unwrap());
254+
/// ```
255+
pub fn entries(&mut self) -> Entries<K, V, S> {
256+
let head = if ! self.head.is_null() {
257+
unsafe { (*self.head).prev }
258+
} else {
259+
ptr::null_mut()
260+
};
261+
Entries {
262+
map: self,
263+
head: head,
264+
tail: self.head,
265+
remaining: self.len(),
266+
marker: marker::PhantomData,
267+
}
268+
}
269+
233270
/// Inserts a key-value pair into the map. If the key already existed, the old value is
234271
/// returned.
235272
///
@@ -785,14 +822,28 @@ pub struct IterMut<'a, K: 'a, V: 'a> {
785822
marker: marker::PhantomData<(&'a K, &'a mut V)>,
786823
}
787824

825+
/// An insertion-order iterator over a `LinkedHashMap`'s entries represented as
826+
/// an `OccupiedEntry`.
827+
pub struct Entries<'a, K: 'a, V: 'a, S: 'a> {
828+
map: *mut LinkedHashMap<K, V, S>,
829+
head: *mut LinkedHashMapEntry<K, V>,
830+
tail: *mut LinkedHashMapEntry<K, V>,
831+
remaining: usize,
832+
marker: marker::PhantomData<(&'a K, &'a mut V, &'a S)>,
833+
}
834+
788835
unsafe impl<'a, K, V> Send for Iter<'a, K, V> where K: Send, V: Send {}
789836

790837
unsafe impl<'a, K, V> Send for IterMut<'a, K, V> where K: Send, V: Send {}
791838

839+
unsafe impl<'a, K, V, S> Send for Entries<'a, K, V, S> where K: Send, V: Send, S: Send {}
840+
792841
unsafe impl<'a, K, V> Sync for Iter<'a, K, V> where K: Sync, V: Sync {}
793842

794843
unsafe impl<'a, K, V> Sync for IterMut<'a, K, V> where K: Sync, V: Sync {}
795844

845+
unsafe impl<'a, K, V, S> Sync for Entries<'a, K, V, S> where K: Sync, V: Sync, S: Sync {}
846+
796847
impl<'a, K, V> Clone for Iter<'a, K, V> {
797848
fn clone(&self) -> Self { Iter { ..*self } }
798849
}
@@ -839,6 +890,32 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
839890
}
840891
}
841892

893+
impl<'a, K, V, S: HashState> Iterator for Entries<'a, K, V, S> {
894+
type Item = OccupiedEntry<'a, K, V, S>;
895+
896+
fn next(&mut self) -> Option<OccupiedEntry<'a, K, V, S>> {
897+
if self.head == self.tail {
898+
None
899+
} else {
900+
self.remaining -= 1;
901+
unsafe {
902+
let r = Some(OccupiedEntry {
903+
map: self.map,
904+
entry: self.head,
905+
marker: marker::PhantomData,
906+
});
907+
908+
self.head = (*self.head).prev;
909+
r
910+
}
911+
}
912+
}
913+
914+
fn size_hint(&self) -> (usize, Option<usize>) {
915+
(self.remaining, Some(self.remaining))
916+
}
917+
}
918+
842919
impl<'a, K, V> DoubleEndedIterator for Iter<'a, K, V> {
843920
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
844921
if self.head == self.tail {

tests/test.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,21 @@ fn test_entry_insert_vacant() {
6767
}
6868
}
6969

70+
#[test]
71+
fn test_entries_replacing() {
72+
let mut map = LinkedHashMap::new();
73+
map.insert("a", 10);
74+
75+
{
76+
let mut iter = map.entries();
77+
let mut entry = iter.next().unwrap();
78+
assert_eq!(entry.insert(20), 10);
79+
assert!(iter.next().is_none());
80+
}
81+
82+
assert_eq!(map["a"], 20);
83+
}
84+
7085
#[test]
7186
fn test_debug() {
7287
let mut map = LinkedHashMap::new();

0 commit comments

Comments
 (0)