Skip to content

Commit 0b2d143

Browse files
committed
BTree: keep values off the function call stack while inserting
1 parent d40f24e commit 0b2d143

File tree

5 files changed

+54
-61
lines changed

5 files changed

+54
-61
lines changed

library/alloc/src/collections/btree/append.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl<K, V> Root<K, V> {
4444
for (key, value) in iter {
4545
// Try to push key-value pair into the current leaf node.
4646
if cur_node.len() < node::CAPACITY {
47-
cur_node.push(key, value);
47+
cur_node.push(key).write(value);
4848
} else {
4949
// No space left, go up and push there.
5050
let mut open_node;

library/alloc/src/collections/btree/map.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ impl<K: Clone, V: Clone, A: Clone + Allocator> Clone for BTreeMap<K, V, A> {
216216
let (k, v) = kv.into_kv();
217217
in_edge = kv.right_edge();
218218

219-
out_node.push(k.clone(), v.clone());
219+
out_node.push(k.clone()).write(v.clone());
220220
out_tree.length += 1;
221221
}
222222
}

library/alloc/src/collections/btree/map/entry.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use core::mem;
55
use crate::alloc::{Allocator, Global};
66

77
use super::super::borrow::DormantMutRef;
8-
use super::super::node::{marker, Handle, NodeRef};
8+
use super::super::node::{marker, Handle, NodeRef, SplitResult};
99
use super::BTreeMap;
1010

1111
use Entry::*;
@@ -334,38 +334,38 @@ impl<'a, K: Ord, V, A: Allocator> VacantEntry<'a, K, V, A> {
334334
/// ```
335335
#[stable(feature = "rust1", since = "1.0.0")]
336336
pub fn insert(self, value: V) -> &'a mut V {
337-
let out_ptr = match self.handle {
337+
let val_ptr = match self.handle {
338338
None => {
339339
// SAFETY: There is no tree yet so no reference to it exists.
340340
let map = unsafe { self.dormant_map.awaken() };
341341
let mut root = NodeRef::new_leaf(self.alloc);
342-
let val_ptr = root.borrow_mut().push(self.key, value) as *mut V;
342+
let val_ptr = root.borrow_mut().push(self.key) as *mut _;
343343
map.root = Some(root.forget_type());
344344
map.length = 1;
345345
val_ptr
346346
}
347-
Some(handle) => match handle.insert_recursing(self.key, value, self.alloc) {
348-
(None, val_ptr) => {
347+
Some(handle) => match handle.insert_recursing(self.key, self.alloc) {
348+
(val_ptr, None) => {
349349
// SAFETY: We have consumed self.handle.
350350
let map = unsafe { self.dormant_map.awaken() };
351351
map.length += 1;
352352
val_ptr
353353
}
354-
(Some(ins), val_ptr) => {
355-
drop(ins.left);
354+
(val_ptr, Some(SplitResult { left, kv, right })) => {
355+
drop(left);
356356
// SAFETY: We have consumed self.handle and dropped the
357-
// remaining reference to the tree, ins.left.
357+
// remaining reference to the tree, `left`.
358358
let map = unsafe { self.dormant_map.awaken() };
359-
let root = map.root.as_mut().unwrap(); // same as ins.left
360-
root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right);
359+
let root = map.root.as_mut().unwrap(); // same as `left`
360+
root.push_internal_level(self.alloc).push(kv.0, kv.1, right);
361361
map.length += 1;
362362
val_ptr
363363
}
364364
},
365365
};
366366
// Now that we have finished growing the tree using borrowed references,
367367
// dereference the pointer to a part of it, that we picked up along the way.
368-
unsafe { &mut *out_ptr }
368+
unsafe { (*val_ptr).write(value) }
369369
}
370370
}
371371

library/alloc/src/collections/btree/node.rs

+40-47
Original file line numberDiff line numberDiff line change
@@ -626,16 +626,16 @@ impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
626626
}
627627

628628
impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
629-
/// Adds a key-value pair to the end of the node, and returns
630-
/// the mutable reference of the inserted value.
631-
pub fn push(&mut self, key: K, val: V) -> &mut V {
629+
/// Adds a key to the end of the node, and returns an exclusive reference
630+
/// to the space for the corresponding value.
631+
pub fn push(&mut self, key: K) -> &mut MaybeUninit<V> {
632632
let len = self.len_mut();
633633
let idx = usize::from(*len);
634634
assert!(idx < CAPACITY);
635635
*len += 1;
636636
unsafe {
637637
self.key_area_mut(idx).write(key);
638-
self.val_area_mut(idx).write(val)
638+
self.val_area_mut(idx)
639639
}
640640
}
641641
}
@@ -845,39 +845,35 @@ fn splitpoint(edge_idx: usize) -> (usize, LeftOrRight<usize>) {
845845
}
846846

847847
impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
848-
/// Inserts a new key-value pair between the key-value pairs to the right and left of
849-
/// this edge. This method assumes that there is enough space in the node for the new
850-
/// pair to fit.
848+
/// Inserts a new key between the keys to the left and right of this edge.
849+
/// This method assumes that the node is not yet filled to capacity.
851850
///
852851
/// The returned pointer points to the inserted value.
853-
fn insert_fit(&mut self, key: K, val: V) -> *mut V {
852+
fn insert_fit(&mut self, key: K) -> &mut MaybeUninit<V> {
854853
debug_assert!(self.node.len() < CAPACITY);
855854
let new_len = self.node.len() + 1;
856855

857856
unsafe {
858-
slice_insert(self.node.key_area_mut(..new_len), self.idx, key);
859-
slice_insert(self.node.val_area_mut(..new_len), self.idx, val);
860857
*self.node.len_mut() = new_len as u16;
861-
862-
self.node.val_area_mut(self.idx).assume_init_mut()
858+
slice_insert(self.node.key_area_mut(..new_len), self.idx).write(key);
859+
slice_insert(self.node.val_area_mut(..new_len), self.idx)
863860
}
864861
}
865862
}
866863

867864
impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
868-
/// Inserts a new key-value pair between the key-value pairs to the right and left of
869-
/// this edge. This method splits the node if there isn't enough room.
865+
/// Inserts a new key between the keys to the right and left of this edge.
866+
/// This method splits the node if there isn't enough room.
870867
///
871-
/// The returned pointer points to the inserted value.
868+
/// The returned pointer points to the space for the value paired with the key.
872869
fn insert<A: Allocator>(
873870
mut self,
874871
key: K,
875-
val: V,
876872
alloc: &A,
877-
) -> (Option<SplitResult<'a, K, V, marker::Leaf>>, *mut V) {
873+
) -> (*mut MaybeUninit<V>, Option<SplitResult<'a, K, V, marker::Leaf>>) {
878874
if self.node.len() < CAPACITY {
879-
let val_ptr = self.insert_fit(key, val);
880-
(None, val_ptr)
875+
let val_ptr = self.insert_fit(key);
876+
(val_ptr, None)
881877
} else {
882878
let (middle_kv_idx, insertion) = splitpoint(self.idx);
883879
let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
@@ -890,8 +886,8 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
890886
Handle::new_edge(result.right.borrow_mut(), insert_idx)
891887
},
892888
};
893-
let val_ptr = insertion_edge.insert_fit(key, val);
894-
(Some(result), val_ptr)
889+
let val_ptr = insertion_edge.insert_fit(key);
890+
(val_ptr, Some(result))
895891
}
896892
}
897893
}
@@ -918,11 +914,10 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
918914
let new_len = self.node.len() + 1;
919915

920916
unsafe {
921-
slice_insert(self.node.key_area_mut(..new_len), self.idx, key);
922-
slice_insert(self.node.val_area_mut(..new_len), self.idx, val);
923-
slice_insert(self.node.edge_area_mut(..new_len + 1), self.idx + 1, edge.node);
924917
*self.node.len_mut() = new_len as u16;
925-
918+
slice_insert(self.node.key_area_mut(..new_len), self.idx).write(key);
919+
slice_insert(self.node.val_area_mut(..new_len), self.idx).write(val);
920+
slice_insert(self.node.edge_area_mut(..new_len + 1), self.idx + 1).write(edge.node);
926921
self.node.correct_childrens_parent_links(self.idx + 1..new_len + 1);
927922
}
928923
}
@@ -961,31 +956,30 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
961956
}
962957

963958
impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
964-
/// Inserts a new key-value pair between the key-value pairs to the right and left of
965-
/// this edge. This method splits the node if there isn't enough room, and tries to
959+
/// Inserts a new key between the keys to the left and right of this edge.
960+
/// This method splits the node if there isn't enough room, and tries to
966961
/// insert the split off portion into the parent node recursively, until the root is reached.
967962
///
968963
/// If the returned result is some `SplitResult`, the `left` field will be the root node.
969-
/// The returned pointer points to the inserted value, which in the case of `SplitResult`
970-
/// is in the `left` or `right` tree.
964+
/// The returned pointer points to the space for the value paired with the key,
965+
/// which in the case of `SplitResult` is either in the `left` or `right` tree.
971966
pub fn insert_recursing<A: Allocator>(
972967
self,
973968
key: K,
974-
value: V,
975969
alloc: &A,
976-
) -> (Option<SplitResult<'a, K, V, marker::LeafOrInternal>>, *mut V) {
977-
let (mut split, val_ptr) = match self.insert(key, value, alloc) {
978-
(None, val_ptr) => return (None, val_ptr),
979-
(Some(split), val_ptr) => (split.forget_node_type(), val_ptr),
970+
) -> (*mut MaybeUninit<V>, Option<SplitResult<'a, K, V, marker::LeafOrInternal>>) {
971+
let (val_ptr, mut split) = match self.insert(key, alloc) {
972+
(val_ptr, None) => return (val_ptr, None),
973+
(val_ptr, Some(split)) => (val_ptr, split.forget_node_type()),
980974
};
981975

982976
loop {
983977
split = match split.left.ascend() {
984978
Ok(parent) => match parent.insert(split.kv.0, split.kv.1, split.right, alloc) {
985-
None => return (None, val_ptr),
986979
Some(split) => split.forget_node_type(),
980+
None => return (val_ptr, None),
987981
},
988-
Err(root) => return (Some(SplitResult { left: root, ..split }), val_ptr),
982+
Err(root) => return (val_ptr, Some(SplitResult { left: root, ..split })),
989983
};
990984
}
991985
}
@@ -1680,19 +1674,18 @@ pub mod marker {
16801674
pub enum Edge {}
16811675
}
16821676

1683-
/// Inserts a value into a slice of initialized elements followed by one uninitialized element.
1677+
/// Shifts values in a slice, where all elements but the last are initialized,
1678+
/// to make room for a new value, and returns that room.
16841679
///
16851680
/// # Safety
16861681
/// The slice has more than `idx` elements.
1687-
unsafe fn slice_insert<T>(slice: &mut [MaybeUninit<T>], idx: usize, val: T) {
1682+
unsafe fn slice_insert<T>(slice: &mut [MaybeUninit<T>], idx: usize) -> &mut MaybeUninit<T> {
16881683
unsafe {
16891684
let len = slice.len();
1690-
debug_assert!(len > idx);
1691-
let slice_ptr = slice.as_mut_ptr();
1692-
if len > idx + 1 {
1693-
ptr::copy(slice_ptr.add(idx), slice_ptr.add(idx + 1), len - idx - 1);
1694-
}
1695-
(*slice_ptr.add(idx)).write(val);
1685+
debug_assert!(idx < len);
1686+
let slice_ptr = slice.as_mut_ptr().add(idx);
1687+
ptr::copy(slice_ptr, slice_ptr.add(1), len - idx - 1);
1688+
&mut *slice_ptr
16961689
}
16971690
}
16981691

@@ -1705,9 +1698,9 @@ unsafe fn slice_remove<T>(slice: &mut [MaybeUninit<T>], idx: usize) -> T {
17051698
unsafe {
17061699
let len = slice.len();
17071700
debug_assert!(idx < len);
1708-
let slice_ptr = slice.as_mut_ptr();
1709-
let ret = (*slice_ptr.add(idx)).assume_init_read();
1710-
ptr::copy(slice_ptr.add(idx + 1), slice_ptr.add(idx), len - idx - 1);
1701+
let slice_ptr = slice.as_mut_ptr().add(idx);
1702+
let ret = (*slice_ptr).assume_init_read();
1703+
ptr::copy(slice_ptr.add(1), slice_ptr, len - idx - 1);
17111704
ret
17121705
}
17131706
}

library/alloc/src/collections/btree/node/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ fn test_splitpoint() {
6969
#[test]
7070
fn test_partial_eq() {
7171
let mut root1 = NodeRef::new_leaf(&Global);
72-
root1.borrow_mut().push(1, ());
72+
root1.borrow_mut().push(1).write(());
7373
let mut root1 = NodeRef::new_internal(root1.forget_type(), &Global).forget_type();
7474
let root2 = Root::new(&Global);
7575
root1.reborrow().assert_back_pointers();

0 commit comments

Comments
 (0)