Skip to content

Commit 83ef4e8

Browse files
authored
Merge pull request #57 from dtolnay/intoiter
Consuming iterator
2 parents e30a48c + d8c4475 commit 83ef4e8

File tree

2 files changed

+203
-0
lines changed

2 files changed

+203
-0
lines changed

src/lib.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,18 +767,65 @@ pub struct IterMut<'a, K: 'a, V: 'a> {
767767
marker: marker::PhantomData<(&'a K, &'a mut V)>,
768768
}
769769

770+
/// A consuming insertion-order iterator over a `LinkedHashMap`'s entries.
771+
pub struct IntoIter<K, V> {
772+
head: *mut LinkedHashMapEntry<K, V>,
773+
tail: *mut LinkedHashMapEntry<K, V>,
774+
remaining: usize,
775+
marker: marker::PhantomData<(K, V)>,
776+
}
777+
770778
unsafe impl<'a, K, V> Send for Iter<'a, K, V> where K: Send, V: Send {}
771779

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

782+
unsafe impl<K, V> Send for IntoIter<K, V> where K: Send, V: Send {}
783+
774784
unsafe impl<'a, K, V> Sync for Iter<'a, K, V> where K: Sync, V: Sync {}
775785

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

788+
unsafe impl<K, V> Sync for IntoIter<K, V> where K: Sync, V: Sync {}
789+
778790
impl<'a, K, V> Clone for Iter<'a, K, V> {
779791
fn clone(&self) -> Self { Iter { ..*self } }
780792
}
781793

794+
impl<K, V> Clone for IntoIter<K, V> where K: Clone, V: Clone {
795+
fn clone(&self) -> Self {
796+
if self.remaining == 0 {
797+
return IntoIter { ..*self }
798+
}
799+
800+
fn clone_entry<K, V>(e: *mut LinkedHashMapEntry<K, V>) -> *mut LinkedHashMapEntry<K, V>
801+
where K: Clone, V: Clone,
802+
{
803+
Box::into_raw(Box::new(LinkedHashMapEntry::new(
804+
unsafe { (*e).key.clone() }, unsafe { (*e).value.clone() }
805+
)))
806+
}
807+
808+
let mut cur = self.head;
809+
let head = clone_entry(cur);
810+
let mut tail = head;
811+
for _ in 1..self.remaining {
812+
unsafe {
813+
(*tail).prev = clone_entry((*cur).prev);
814+
(*(*tail).prev).next = tail;
815+
tail = (*tail).prev;
816+
cur = (*cur).prev;
817+
}
818+
}
819+
820+
IntoIter {
821+
head: head,
822+
tail: tail,
823+
remaining: self.remaining,
824+
marker: marker::PhantomData,
825+
}
826+
}
827+
}
828+
782829
impl<'a, K, V> Iterator for Iter<'a, K, V> {
783830
type Item = (&'a K, &'a V);
784831

@@ -821,6 +868,27 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
821868
}
822869
}
823870

871+
impl<K: Hash + Eq, V> Iterator for IntoIter<K, V> {
872+
type Item = (K, V);
873+
874+
fn next(&mut self) -> Option<(K, V)> {
875+
if self.remaining == 0 {
876+
return None
877+
}
878+
self.remaining -= 1;
879+
unsafe {
880+
let prev = (*self.head).prev;
881+
let e = *Box::from_raw(self.head);
882+
self.head = prev;
883+
Some((e.key, e.value))
884+
}
885+
}
886+
887+
fn size_hint(&self) -> (usize, Option<usize>) {
888+
(self.remaining, Some(self.remaining))
889+
}
890+
}
891+
824892
impl<'a, K, V> DoubleEndedIterator for Iter<'a, K, V> {
825893
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
826894
if self.head == self.tail {
@@ -849,6 +917,21 @@ impl<'a, K, V> DoubleEndedIterator for IterMut<'a, K, V> {
849917
}
850918
}
851919

920+
impl<K: Hash + Eq, V> DoubleEndedIterator for IntoIter<K, V> {
921+
fn next_back(&mut self) -> Option<(K, V)> {
922+
if self.remaining == 0 {
923+
return None
924+
}
925+
self.remaining -= 1;
926+
unsafe {
927+
let next = (*self.tail).next;
928+
let e = *Box::from_raw(self.tail);
929+
self.tail = next;
930+
Some((e.key, e.value))
931+
}
932+
}
933+
}
934+
852935
impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
853936
fn len(&self) -> usize { self.remaining }
854937
}
@@ -857,6 +940,22 @@ impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
857940
fn len(&self) -> usize { self.remaining }
858941
}
859942

943+
impl<K: Hash + Eq, V> ExactSizeIterator for IntoIter<K, V> {
944+
fn len(&self) -> usize { self.remaining }
945+
}
946+
947+
impl<K, V> Drop for IntoIter<K, V> {
948+
fn drop(&mut self) {
949+
for _ in 0..self.remaining {
950+
unsafe {
951+
let next = (*self.tail).next;
952+
Box::from_raw(self.tail);
953+
self.tail = next;
954+
}
955+
}
956+
}
957+
}
958+
860959
/// An insertion-order iterator over a `LinkedHashMap`'s keys.
861960
pub struct Keys<'a, K: 'a, V: 'a> {
862961
#[cfg_attr(feature = "clippy", allow(type_complexity))]
@@ -919,6 +1018,34 @@ impl<'a, K: Hash + Eq, V, S: BuildHasher> IntoIterator for &'a mut LinkedHashMap
9191018
fn into_iter(self) -> IterMut<'a, K, V> { self.iter_mut() }
9201019
}
9211020

1021+
impl<K: Hash + Eq, V, S: BuildHasher> IntoIterator for LinkedHashMap<K, V, S> {
1022+
type Item = (K, V);
1023+
type IntoIter = IntoIter<K, V>;
1024+
fn into_iter(mut self) -> IntoIter<K, V> {
1025+
let (head, tail) = if !self.head.is_null() {
1026+
unsafe { ((*self.head).prev, (*self.head).next) }
1027+
} else {
1028+
(ptr::null_mut(), ptr::null_mut())
1029+
};
1030+
let len = self.len();
1031+
1032+
if !self.head.is_null() {
1033+
unsafe { drop_empty_entry_box(self.head) }
1034+
}
1035+
self.clear_free_list();
1036+
// drop the HashMap but not the LinkedHashMap
1037+
self.map = unsafe { mem::uninitialized() };
1038+
mem::forget(self);
1039+
1040+
IntoIter {
1041+
head: head,
1042+
tail: tail,
1043+
remaining: len,
1044+
marker: marker::PhantomData,
1045+
}
1046+
}
1047+
}
1048+
9221049
#[cfg(all(feature = "nightly", test))]
9231050
mod bench {
9241051
extern crate test;

tests/test.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,81 @@ fn test_iter_mut() {
177177
assert_eq!(23, map[&"b"]);
178178
}
179179

180+
#[test]
181+
fn test_consuming_iter() {
182+
let map = {
183+
let mut map = LinkedHashMap::new();
184+
map.insert("a", 10);
185+
map.insert("c", 30);
186+
map.insert("b", 20);
187+
map
188+
};
189+
190+
let mut iter = map.into_iter();
191+
assert_eq!(Some(("a", 10)), iter.next());
192+
193+
let clone = iter.clone();
194+
for iter in &mut [iter, clone] {
195+
assert_eq!(Some(("b", 20)), iter.next_back());
196+
assert_eq!(1, iter.len());
197+
assert_eq!(Some(("c", 30)), iter.next());
198+
assert_eq!(None, iter.next());
199+
}
200+
}
201+
202+
#[test]
203+
fn test_consuming_iter_empty() {
204+
let map = LinkedHashMap::<&str, i32>::new();
205+
let mut iter = map.into_iter();
206+
assert_eq!(None, iter.next());
207+
let mut clone = iter.clone();
208+
assert_eq!(None, clone.next());
209+
}
210+
211+
#[test]
212+
fn test_consuming_iter_with_free_list() {
213+
let mut map = LinkedHashMap::new();
214+
map.insert("a", 10);
215+
map.insert("c", 30);
216+
map.insert("b", 20);
217+
map.remove("a");
218+
map.remove("b");
219+
220+
let mut iter = map.into_iter();
221+
assert_eq!(Some(("c", 30)), iter.next());
222+
assert_eq!(None, iter.next());
223+
}
224+
225+
#[test]
226+
fn test_into_iter_drop() {
227+
struct Counter<'a>(&'a mut usize);
228+
229+
impl<'a> Drop for Counter<'a> {
230+
fn drop(&mut self) {
231+
*self.0 += 1;
232+
}
233+
}
234+
235+
let mut a = 0;
236+
let mut b = 0;
237+
let mut c = 0;
238+
239+
{
240+
let mut map = LinkedHashMap::new();
241+
map.insert("a", Counter(&mut a));
242+
map.insert("b", Counter(&mut b));
243+
map.insert("c", Counter(&mut c));
244+
245+
let mut iter = map.into_iter();
246+
iter.next();
247+
iter.next_back();
248+
}
249+
250+
assert_eq!(a, 1);
251+
assert_eq!(b, 1);
252+
assert_eq!(c, 1);
253+
}
254+
180255
#[test]
181256
fn test_borrow() {
182257
#[derive(PartialEq, Eq, Hash)] struct Foo(Bar);
@@ -228,6 +303,7 @@ fn test_send_sync() {
228303
is_send_sync::<LinkedHashMap<u32, i32>>();
229304
is_send_sync::<linked_hash_map::Iter<u32, i32>>();
230305
is_send_sync::<linked_hash_map::IterMut<u32, i32>>();
306+
is_send_sync::<linked_hash_map::IntoIter<u32, i32>>();
231307
is_send_sync::<linked_hash_map::Keys<u32, i32>>();
232308
is_send_sync::<linked_hash_map::Values<u32, i32>>();
233309
}

0 commit comments

Comments
 (0)