Skip to content

Commit 633e948

Browse files
committed
Auto merge of #66648 - crgl:btree-clone-from, r=<try>
Implement clone_from for BTreeMap and BTreeSet See #28481. This results in up to 90% speedups on simple data types when `self` and `other` are the same size, and is generally comparable or faster. Some concerns: 1. This implementation requires an `Ord` bound on the `Clone` implementation for `BTreeMap` and `BTreeSet`. Since these structs can only be created externally for keys with `Ord` implemented, this should be fine? If not, there's certainly a less safe way to do this. 2. Changing `next_unchecked` on `RangeMut` to return mutable key references allows for replacing the entire overlapping portion of both maps without changing the external interface in any way. However, if `clone_from` fails it can leave the `BTreeMap` in an invalid state, which might be unacceptable. This probably needs an FCP since it changes a trait bound, but (as far as I know?) that change cannot break any external code.
2 parents 5fa0af2 + 8f05f02 commit 633e948

File tree

3 files changed

+74
-15
lines changed

3 files changed

+74
-15
lines changed

src/liballoc/collections/btree/map.rs

+42-14
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap<K, V> {
135135
}
136136

137137
#[stable(feature = "rust1", since = "1.0.0")]
138-
impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
138+
impl<K: Clone + Ord, V: Clone> Clone for BTreeMap<K, V> {
139139
fn clone(&self) -> BTreeMap<K, V> {
140140
fn clone_subtree<'a, K: Clone, V: Clone>(
141141
node: node::NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
@@ -201,16 +201,40 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
201201
}
202202

203203
if self.is_empty() {
204-
// Ideally we'd call `BTreeMap::new` here, but that has the `K:
205-
// Ord` constraint, which this method lacks.
206-
BTreeMap {
207-
root: node::Root::shared_empty_root(),
208-
length: 0,
209-
}
204+
BTreeMap::new()
210205
} else {
211206
clone_subtree(self.root.as_ref())
212207
}
213208
}
209+
210+
fn clone_from(&mut self, other: &Self) {
211+
if let Some(key) = {
212+
if self.len() > other.len() {
213+
let diff = self.len() - other.len();
214+
if diff <= other.len() {
215+
self.iter().nth_back(diff - 1).map(|pair| (*pair.0).clone())
216+
} else {
217+
self.iter().nth(other.len()).map(|pair| (*pair.0).clone())
218+
}
219+
} else {
220+
None
221+
}
222+
} {
223+
self.split_off(&key);
224+
}
225+
let mut siter = self.range_mut(..);
226+
let mut oiter = other.iter();
227+
while siter.front != siter.back {
228+
if let Some((ok, ov)) = oiter.next() {
229+
let (sk, sv) = unsafe { siter.next_unchecked() };
230+
sk.clone_from(ok);
231+
sv.clone_from(ov);
232+
} else {
233+
break ;
234+
}
235+
}
236+
self.extend(oiter.map(|(k, v)| ((*k).clone(), (*v).clone())));
237+
}
214238
}
215239

216240
impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()>
@@ -1364,7 +1388,10 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
13641388
None
13651389
} else {
13661390
self.length -= 1;
1367-
unsafe { Some(self.range.next_unchecked()) }
1391+
unsafe {
1392+
let (k, v) = self.range.next_unchecked();
1393+
Some((k, v)) // coerce k from `&mut K` to `&K`
1394+
}
13681395
}
13691396
}
13701397

@@ -1761,7 +1788,10 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> {
17611788
if self.front == self.back {
17621789
None
17631790
} else {
1764-
unsafe { Some(self.next_unchecked()) }
1791+
unsafe {
1792+
let (k, v) = self.next_unchecked();
1793+
Some((k, v)) // coerce k from `&mut K` to `&K`
1794+
}
17651795
}
17661796
}
17671797

@@ -1771,16 +1801,15 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> {
17711801
}
17721802

17731803
impl<'a, K, V> RangeMut<'a, K, V> {
1774-
unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) {
1804+
unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
17751805
let handle = ptr::read(&self.front);
17761806

17771807
let mut cur_handle = match handle.right_kv() {
17781808
Ok(kv) => {
17791809
self.front = ptr::read(&kv).right_edge();
17801810
// Doing the descend invalidates the references returned by `into_kv_mut`,
17811811
// so we have to do this last.
1782-
let (k, v) = kv.into_kv_mut();
1783-
return (k, v); // coerce k from `&mut K` to `&K`
1812+
return kv.into_kv_mut();
17841813
}
17851814
Err(last_edge) => {
17861815
let next_level = last_edge.into_node().ascend().ok();
@@ -1794,8 +1823,7 @@ impl<'a, K, V> RangeMut<'a, K, V> {
17941823
self.front = first_leaf_edge(ptr::read(&kv).right_edge().descend());
17951824
// Doing the descend invalidates the references returned by `into_kv_mut`,
17961825
// so we have to do this last.
1797-
let (k, v) = kv.into_kv_mut();
1798-
return (k, v); // coerce k from `&mut K` to `&K`
1826+
return kv.into_kv_mut();
17991827
}
18001828
Err(last_edge) => {
18011829
let next_level = last_edge.into_node().ascend().ok();

src/liballoc/collections/btree/set.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,23 @@ use super::Recover;
5656
/// println!("{}", book);
5757
/// }
5858
/// ```
59-
#[derive(Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
59+
#[derive(Hash, PartialEq, Eq, Ord, PartialOrd)]
6060
#[stable(feature = "rust1", since = "1.0.0")]
6161
pub struct BTreeSet<T> {
6262
map: BTreeMap<T, ()>,
6363
}
6464

65+
#[stable(feature = "rust1", since = "1.0.0")]
66+
impl<T: Clone + Ord> Clone for BTreeSet<T> {
67+
fn clone(&self) -> Self {
68+
BTreeSet { map: self.map.clone() }
69+
}
70+
71+
fn clone_from(&mut self, other: &Self) {
72+
self.map.clone_from(&other.map);
73+
}
74+
}
75+
6576
/// An iterator over the items of a `BTreeSet`.
6677
///
6778
/// This `struct` is created by the [`iter`] method on [`BTreeSet`].

src/liballoc/tests/btree/map.rs

+20
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,26 @@ fn test_clone() {
552552
}
553553
}
554554

555+
#[test]
556+
fn test_clone_from() {
557+
let mut map1 = BTreeMap::new();
558+
let size = 30;
559+
560+
for i in 0..size {
561+
map1.insert(i, 10 * i);
562+
let mut map2 = BTreeMap::new();
563+
for j in 0..i {
564+
map2.insert(100 * j + 1, 2 * j + 1);
565+
let mut map1_copy = map2.clone();
566+
map1_copy.clone_from(&map1);
567+
assert_eq!(map1_copy, map1);
568+
let mut map2_copy = map1.clone();
569+
map2_copy.clone_from(&map2);
570+
assert_eq!(map2_copy, map2);
571+
}
572+
}
573+
}
574+
555575
#[test]
556576
#[allow(dead_code)]
557577
fn test_variance() {

0 commit comments

Comments
 (0)