about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCharles Gleason <charles_gleason@alumni.brown.edu>2019-11-22 14:22:06 -0500
committerCharles Gleason <charles_gleason@alumni.brown.edu>2019-12-23 11:03:30 -0500
commitf547978392872684085c96a3d5c1d00bad24b724 (patch)
tree2b505f34afa213173edcd2979d9eae2ffcbdd9e3
parent293cdf7ac5d14811debdec3408afde104935caef (diff)
downloadrust-f547978392872684085c96a3d5c1d00bad24b724.tar.gz
rust-f547978392872684085c96a3d5c1d00bad24b724.zip
Implement clone_from for BTree collections
-rw-r--r--src/liballoc/collections/btree/map.rs54
-rw-r--r--src/liballoc/collections/btree/set.rs13
2 files changed, 66 insertions, 1 deletions
diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs
index e25a5e0773e..12174ffcbfa 100644
--- a/src/liballoc/collections/btree/map.rs
+++ b/src/liballoc/collections/btree/map.rs
@@ -207,6 +207,60 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
             clone_subtree(self.root.as_ref())
         }
     }
+
+    fn clone_from(&mut self, other: &Self) {
+        BTreeClone::clone_from(self, other);
+    }
+}
+
+trait BTreeClone {
+    fn clone_from(&mut self, other: &Self);
+}
+
+impl<K: Clone, V: Clone> BTreeClone for BTreeMap<K, V> {
+    default fn clone_from(&mut self, other: &Self) {
+        *self = other.clone();
+    }
+}
+
+impl<K: Clone + Ord, V: Clone> BTreeClone for BTreeMap<K, V> {
+    fn clone_from(&mut self, other: &Self) {
+        // This truncates `self` to `other.len()` by calling `split_off` on
+        // the first key after `other.len()` elements if it exists
+        if let Some(key) = {
+            if self.len() > other.len() {
+                let diff = self.len() - other.len();
+                if diff <= other.len() {
+                    self.iter().nth_back(diff - 1).map(|pair| (*pair.0).clone())
+                } else {
+                    self.iter().nth(other.len()).map(|pair| (*pair.0).clone())
+                }
+            } else {
+                None
+            }
+        } {
+            self.split_off(&key);
+        }
+        let mut siter = self.range_mut(..);
+        let mut oiter = other.iter();
+        // After truncation, `self` is at most as long as `other` so this loop
+        // replaces every key-value pair in `self`. Since `oiter` is in sorted
+        // order and the structure of the `BTreeMap` stays the same,
+        // the BTree invariants are maintained at the end of the loop
+        while siter.front != siter.back {
+            if let Some((ok, ov)) = oiter.next() {
+                // This is safe because the `siter.front != siter.back` check
+                // ensures that `siter` is nonempty
+                let (sk, sv) = unsafe { siter.next_unchecked() };
+                sk.clone_from(ok);
+                sv.clone_from(ov);
+            } else {
+                break;
+            }
+        }
+        // If `other` is longer than `self`, the remaining elements are inserted
+        self.extend(oiter.map(|(k, v)| ((*k).clone(), (*v).clone())));
+    }
 }
 
 impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()>
diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs
index 282d163141b..5bdefe5cecf 100644
--- a/src/liballoc/collections/btree/set.rs
+++ b/src/liballoc/collections/btree/set.rs
@@ -56,12 +56,23 @@ use crate::collections::btree_map::{self, BTreeMap, Keys};
 ///     println!("{}", book);
 /// }
 /// ```
-#[derive(Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
+#[derive(Hash, PartialEq, Eq, Ord, PartialOrd)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BTreeSet<T> {
     map: BTreeMap<T, ()>,
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Clone> Clone for BTreeSet<T> {
+    fn clone(&self) -> Self {
+        BTreeSet { map: self.map.clone() }
+    }
+
+    fn clone_from(&mut self, other: &Self) {
+        self.map.clone_from(&other.map);
+    }
+}
+
 /// An iterator over the items of a `BTreeSet`.
 ///
 /// This `struct` is created by the [`iter`] method on [`BTreeSet`].