about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_macros/src/query.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs1
-rw-r--r--compiler/rustc_middle/src/ty/query/mod.rs1
-rw-r--r--compiler/rustc_middle/src/ty/query/plumbing.rs4
-rw-r--r--compiler/rustc_query_system/src/query/config.rs3
-rw-r--r--library/alloc/src/collections/btree/map.rs24
-rw-r--r--library/alloc/src/collections/btree/split.rs85
7 files changed, 72 insertions, 50 deletions
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index cff8e983318..bd20c7689ea 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -417,8 +417,8 @@ fn add_query_description_impl(
         fn describe(
             #tcx: TyCtxt<'tcx>,
             #key: #arg,
-        ) -> Cow<'static, str> {
-            ::rustc_middle::ty::print::with_no_trimmed_paths(|| format!(#desc).into())
+        ) -> String {
+            ::rustc_middle::ty::print::with_no_trimmed_paths(|| format!(#desc))
         }
     };
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index a3040f498ce..f0166ec2167 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -13,7 +13,6 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_query_system::query::QueryDescription;
 
 use rustc_span::symbol::Symbol;
-use std::borrow::Cow;
 
 fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
     if def_id.is_top_level_module() {
diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs
index f580cb14dc9..804c045a690 100644
--- a/compiler/rustc_middle/src/ty/query/mod.rs
+++ b/compiler/rustc_middle/src/ty/query/mod.rs
@@ -53,7 +53,6 @@ use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
-use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::ops::Deref;
 use std::path::PathBuf;
diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs
index d0730bd121c..46addcdaead 100644
--- a/compiler/rustc_middle/src/ty/query/plumbing.rs
+++ b/compiler/rustc_middle/src/ty/query/plumbing.rs
@@ -277,14 +277,14 @@ macro_rules! define_queries {
                 }
             }
 
-            pub fn describe(&self, tcx: TyCtxt<$tcx>) -> Cow<'static, str> {
+            pub fn describe(&self, tcx: TyCtxt<$tcx>) -> String {
                 let (r, name) = match *self {
                     $(Query::$name(key) => {
                         (queries::$name::describe(tcx, key), stringify!($name))
                     })*
                 };
                 if tcx.sess.verbose() {
-                    format!("{} [{}]", r, name).into()
+                    format!("{} [{}]", r, name)
                 } else {
                     r
                 }
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index 0f0684b3547..94e906fc433 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -7,7 +7,6 @@ use crate::query::plumbing::CycleError;
 use crate::query::{QueryContext, QueryState};
 
 use rustc_data_structures::fingerprint::Fingerprint;
-use std::borrow::Cow;
 use std::fmt::Debug;
 use std::hash::Hash;
 
@@ -95,7 +94,7 @@ pub trait QueryAccessors<CTX: QueryContext>: QueryConfig {
 }
 
 pub trait QueryDescription<CTX: QueryContext>: QueryAccessors<CTX> {
-    fn describe(tcx: CTX, key: Self::Key) -> Cow<'static, str>;
+    fn describe(tcx: CTX, key: Self::Key) -> String;
 
     #[inline]
     fn cache_on_disk(_: CTX, _: &Self::Key, _: Option<&Self::Value>) -> bool {
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index c26388a1db1..dc109875726 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -20,6 +20,14 @@ use Entry::*;
 /// We might temporarily have fewer elements during methods.
 pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
 
+// A tree in a `BTreeMap` is a tree in the `node` module with addtional invariants:
+// - Keys must appear in ascending order (according to the key's type).
+// - If the root node is internal, it must contain at least 1 element.
+// - Every non-root node contains at least MIN_LEN elements.
+//
+// An empty map may be represented both by the absense of a root node or by a
+// root node that is an empty leaf.
+
 /// A map based on a B-Tree.
 ///
 /// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing
@@ -1131,20 +1139,12 @@ impl<K, V> BTreeMap<K, V> {
         let total_num = self.len();
         let left_root = self.root.as_mut().unwrap(); // unwrap succeeds because not empty
 
-        let mut right = Self::new();
-        let right_root = Self::ensure_is_owned(&mut right.root);
-
-        left_root.split_off(right_root, key);
+        let right_root = left_root.split_off(key);
 
-        if left_root.height() < right_root.height() {
-            self.length = left_root.reborrow().calc_length();
-            right.length = total_num - self.len();
-        } else {
-            right.length = right_root.reborrow().calc_length();
-            self.length = total_num - right.len();
-        }
+        let (new_left_len, right_len) = Root::calc_split_length(total_num, &left_root, &right_root);
+        self.length = new_left_len;
 
-        right
+        BTreeMap { root: Some(right_root), length: right_len }
     }
 
     /// Creates an iterator that visits all elements (key-value pairs) in
diff --git a/library/alloc/src/collections/btree/split.rs b/library/alloc/src/collections/btree/split.rs
index 62c5e3a46d7..1921982464a 100644
--- a/library/alloc/src/collections/btree/split.rs
+++ b/library/alloc/src/collections/btree/split.rs
@@ -4,46 +4,71 @@ use super::search::SearchResult::*;
 use core::borrow::Borrow;
 
 impl<K, V> Root<K, V> {
-    pub fn split_off<Q: ?Sized + Ord>(&mut self, right_root: &mut Self, key: &Q)
+    /// Calculates the length of both trees that result from splitting up
+    /// a given number of distinct key-value pairs.
+    pub fn calc_split_length(
+        total_num: usize,
+        root_a: &Root<K, V>,
+        root_b: &Root<K, V>,
+    ) -> (usize, usize) {
+        let (length_a, length_b);
+        if root_a.height() < root_b.height() {
+            length_a = root_a.reborrow().calc_length();
+            length_b = total_num - length_a;
+            debug_assert_eq!(length_b, root_b.reborrow().calc_length());
+        } else {
+            length_b = root_b.reborrow().calc_length();
+            length_a = total_num - length_b;
+            debug_assert_eq!(length_a, root_a.reborrow().calc_length());
+        }
+        (length_a, length_b)
+    }
+
+    /// Split off a tree with key-value pairs at and after the given key.
+    /// The result is meaningful only if the tree is ordered by key,
+    /// and if the ordering of `Q` corresponds to that of `K`.
+    /// If `self` respects all `BTreeMap` tree invariants, then both
+    /// `self` and the returned tree will respect those invariants.
+    pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self
     where
         K: Borrow<Q>,
     {
-        debug_assert!(right_root.height() == 0);
-        debug_assert!(right_root.len() == 0);
-
         let left_root = self;
-        for _ in 0..left_root.height() {
-            right_root.push_internal_level();
-        }
-
-        {
-            let mut left_node = left_root.borrow_mut();
-            let mut right_node = right_root.borrow_mut();
-
-            loop {
-                let mut split_edge = match left_node.search_node(key) {
-                    // key is going to the right tree
-                    Found(kv) => kv.left_edge(),
-                    GoDown(edge) => edge,
-                };
-
-                split_edge.move_suffix(&mut right_node);
-
-                match (split_edge.force(), right_node.force()) {
-                    (Internal(edge), Internal(node)) => {
-                        left_node = edge.descend();
-                        right_node = node.first_edge().descend();
-                    }
-                    (Leaf(_), Leaf(_)) => {
-                        break;
-                    }
-                    _ => unreachable!(),
+        let mut right_root = Root::new_pillar(left_root.height());
+        let mut left_node = left_root.borrow_mut();
+        let mut right_node = right_root.borrow_mut();
+
+        loop {
+            let mut split_edge = match left_node.search_node(key) {
+                // key is going to the right tree
+                Found(kv) => kv.left_edge(),
+                GoDown(edge) => edge,
+            };
+
+            split_edge.move_suffix(&mut right_node);
+
+            match (split_edge.force(), right_node.force()) {
+                (Internal(edge), Internal(node)) => {
+                    left_node = edge.descend();
+                    right_node = node.first_edge().descend();
                 }
+                (Leaf(_), Leaf(_)) => break,
+                _ => unreachable!(),
             }
         }
 
         left_root.fix_right_border();
         right_root.fix_left_border();
+        right_root
+    }
+
+    /// Creates a tree consisting of empty nodes.
+    fn new_pillar(height: usize) -> Self {
+        let mut root = Root::new();
+        for _ in 0..height {
+            root.push_internal_level();
+        }
+        root
     }
 
     /// Removes empty levels on the top, but keeps an empty leaf if the entire tree is empty.