Skip to content

Commit 8b8d350

Browse files
authored
Merge pull request #426 from cuviper/clone-intokv
`impl Clone for IntoKeys` and `IntoValues`
2 parents 3b6d04b + 88efd0c commit 8b8d350

File tree

1 file changed

+66
-3
lines changed

1 file changed

+66
-3
lines changed

src/map/iter.rs

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use super::{Bucket, IndexMap, Slice};
1+
use super::{Bucket, HashValue, IndexMap, Slice};
22
use crate::inner::{Core, ExtractCore};
33

44
use alloc::vec::{self, Vec};
55
use core::fmt;
66
use core::hash::{BuildHasher, Hash};
77
use core::iter::FusedIterator;
8+
use core::mem::MaybeUninit;
89
use core::ops::{Index, RangeBounds};
910
use core::slice;
1011

@@ -448,11 +449,42 @@ impl<K, V> Index<usize> for Keys<'_, K, V> {
448449
/// This `struct` is created by the [`IndexMap::into_keys`] method.
449450
/// See its documentation for more.
450451
pub struct IntoKeys<K, V> {
451-
iter: vec::IntoIter<Bucket<K, V>>,
452+
// We eagerly drop the values during construction so we can ignore them in
453+
// `Clone`, but we keep uninit values so the bucket's size and alignment
454+
// remain the same, and therefore the `Vec` conversion should be in-place.
455+
iter: vec::IntoIter<Bucket<K, MaybeUninit<V>>>,
452456
}
453457

454458
impl<K, V> IntoKeys<K, V> {
455459
pub(super) fn new(entries: Vec<Bucket<K, V>>) -> Self {
460+
// The original values will be dropped here.
461+
// The hash doesn't matter, but "copying" it in-place is free.
462+
let entries = entries
463+
.into_iter()
464+
.map(|Bucket { hash, key, .. }| Bucket {
465+
hash,
466+
key,
467+
value: MaybeUninit::uninit(),
468+
})
469+
.collect::<Vec<_>>();
470+
Self {
471+
iter: entries.into_iter(),
472+
}
473+
}
474+
}
475+
476+
impl<K: Clone, V> Clone for IntoKeys<K, V> {
477+
fn clone(&self) -> Self {
478+
let entries = self
479+
.iter
480+
.as_slice()
481+
.iter()
482+
.map(|Bucket { key, .. }| Bucket {
483+
hash: HashValue(0),
484+
key: key.clone(),
485+
value: MaybeUninit::uninit(),
486+
})
487+
.collect::<Vec<_>>();
456488
Self {
457489
iter: entries.into_iter(),
458490
}
@@ -601,11 +633,42 @@ impl<K, V> Default for ValuesMut<'_, K, V> {
601633
/// This `struct` is created by the [`IndexMap::into_values`] method.
602634
/// See its documentation for more.
603635
pub struct IntoValues<K, V> {
604-
iter: vec::IntoIter<Bucket<K, V>>,
636+
// We eagerly drop the keys during construction so we can ignore them in
637+
// `Clone`, but we keep uninit keys so the bucket's size and alignment
638+
// remain the same, and therefore the `Vec` conversion should be in-place.
639+
iter: vec::IntoIter<Bucket<MaybeUninit<K>, V>>,
605640
}
606641

607642
impl<K, V> IntoValues<K, V> {
608643
pub(super) fn new(entries: Vec<Bucket<K, V>>) -> Self {
644+
// The original keys will be dropped here.
645+
// The hash doesn't matter, but "copying" it in-place is free.
646+
let entries = entries
647+
.into_iter()
648+
.map(|Bucket { hash, value, .. }| Bucket {
649+
hash,
650+
key: MaybeUninit::uninit(),
651+
value,
652+
})
653+
.collect::<Vec<_>>();
654+
Self {
655+
iter: entries.into_iter(),
656+
}
657+
}
658+
}
659+
660+
impl<K, V: Clone> Clone for IntoValues<K, V> {
661+
fn clone(&self) -> Self {
662+
let entries = self
663+
.iter
664+
.as_slice()
665+
.iter()
666+
.map(|Bucket { value, .. }| Bucket {
667+
hash: HashValue(0),
668+
key: MaybeUninit::uninit(),
669+
value: value.clone(),
670+
})
671+
.collect::<Vec<_>>();
609672
Self {
610673
iter: entries.into_iter(),
611674
}

0 commit comments

Comments
 (0)