diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 3984379ea860..985a41722d7c 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -523,7 +523,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> BTreeMap { BTreeMap { - root: node::Root::new_leaf(), + root: node::Root::shared_empty_root(), length: 0, } } @@ -544,7 +544,6 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn clear(&mut self) { - // FIXME(gereeter) .clear() allocates *self = BTreeMap::new(); } @@ -687,6 +686,10 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, key: K, value: V) -> Option { + if self.root.is_shared_root() { + self.root = node::Root::new_leaf(); + } + match self.entry(key) { Occupied(mut entry) => Some(entry.insert(value)), Vacant(entry) => { @@ -890,6 +893,10 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry { + if self.root.is_shared_root() { + self.root = node::Root::new_leaf(); + } + match search::search_tree(self.root.as_mut(), &key) { Found(handle) => { Occupied(OccupiedEntry { @@ -910,6 +917,10 @@ impl BTreeMap { } fn from_sorted_iter>(&mut self, iter: I) { + if self.root.is_shared_root() { + self.root = node::Root::new_leaf(); + } + let mut cur_node = last_leaf_edge(self.root.as_mut()).into_node(); // Iterate through all key-value pairs, pushing them into nodes at the right level. for (key, value) in iter { diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 3e27331aa381..6381006e7fce 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -103,6 +103,18 @@ impl LeafNode { } } +// We need to implement Sync here in order to make a static instance +unsafe impl Sync for LeafNode<(), ()> {} + +// An empty node used as a placeholder for the root node, to avoid allocations +static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode { + parent: ptr::null(), + parent_idx: 0, + len: 0, + keys: [(); CAPACITY], + vals: [(); CAPACITY], +}; + /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden /// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an /// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the @@ -172,6 +184,24 @@ unsafe impl Sync for Root { } unsafe impl Send for Root { } impl Root { + pub fn is_shared_root(&self) -> bool { + ptr::eq( + self.node.as_ptr().as_ptr(), + &EMPTY_ROOT_NODE as *const _ as *const LeafNode, + ) + } + + pub fn shared_empty_root() -> Self { + Root { + node: unsafe { + BoxedNode::from_ptr(NonNull::new_unchecked( + &EMPTY_ROOT_NODE as *const _ as *const LeafNode as *mut _ + )) + }, + height: 0, + } + } + pub fn new_leaf() -> Self { Root { node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })),