Skip to content

Commit e6db79f

Browse files
committed
Auto merge of #50352 - porglezomp:btree-no-empty-alloc, r=Gankro
Don't allocate when creating an empty BTree Following the discussion in #50266, this adds a static instance of `LeafNode` that empty BTrees point to, and then replaces it on `insert`, `append`, and `entry`. This avoids allocating for empty maps. Fixes #50266 r? @gankro
2 parents 5f98fe7 + e83c18f commit e6db79f

File tree

2 files changed

+128
-31
lines changed

2 files changed

+128
-31
lines changed

src/liballoc/btree/map.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()>
246246
}
247247

248248
fn replace(&mut self, key: K) -> Option<K> {
249+
self.ensure_root_is_owned();
249250
match search::search_tree::<marker::Mut, K, (), K>(self.root.as_mut(), &key) {
250251
Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)),
251252
GoDown(handle) => {
@@ -523,7 +524,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
523524
#[stable(feature = "rust1", since = "1.0.0")]
524525
pub fn new() -> BTreeMap<K, V> {
525526
BTreeMap {
526-
root: node::Root::new_leaf(),
527+
root: node::Root::shared_empty_root(),
527528
length: 0,
528529
}
529530
}
@@ -544,7 +545,6 @@ impl<K: Ord, V> BTreeMap<K, V> {
544545
/// ```
545546
#[stable(feature = "rust1", since = "1.0.0")]
546547
pub fn clear(&mut self) {
547-
// FIXME(gereeter) .clear() allocates
548548
*self = BTreeMap::new();
549549
}
550550

@@ -890,6 +890,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
890890
/// ```
891891
#[stable(feature = "rust1", since = "1.0.0")]
892892
pub fn entry(&mut self, key: K) -> Entry<K, V> {
893+
// FIXME(@porglezomp) Avoid allocating if we don't insert
894+
self.ensure_root_is_owned();
893895
match search::search_tree(self.root.as_mut(), &key) {
894896
Found(handle) => {
895897
Occupied(OccupiedEntry {
@@ -910,6 +912,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
910912
}
911913

912914
fn from_sorted_iter<I: Iterator<Item = (K, V)>>(&mut self, iter: I) {
915+
self.ensure_root_is_owned();
913916
let mut cur_node = last_leaf_edge(self.root.as_mut()).into_node();
914917
// Iterate through all key-value pairs, pushing them into nodes at the right level.
915918
for (key, value) in iter {
@@ -1019,6 +1022,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
10191022
let total_num = self.len();
10201023

10211024
let mut right = Self::new();
1025+
right.root = node::Root::new_leaf();
10221026
for _ in 0..(self.root.as_ref().height()) {
10231027
right.root.push_level();
10241028
}
@@ -1153,6 +1157,13 @@ impl<K: Ord, V> BTreeMap<K, V> {
11531157

11541158
self.fix_top();
11551159
}
1160+
1161+
/// If the root node is the shared root node, allocate our own node.
1162+
fn ensure_root_is_owned(&mut self) {
1163+
if self.root.is_shared_root() {
1164+
self.root = node::Root::new_leaf();
1165+
}
1166+
}
11561167
}
11571168

11581169
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1290,6 +1301,10 @@ impl<K, V> Drop for IntoIter<K, V> {
12901301
self.for_each(drop);
12911302
unsafe {
12921303
let leaf_node = ptr::read(&self.front).into_node();
1304+
if leaf_node.is_shared_root() {
1305+
return;
1306+
}
1307+
12931308
if let Some(first_parent) = leaf_node.deallocate_and_ascend() {
12941309
let mut cur_node = first_parent.into_node();
12951310
while let Some(parent) = cur_node.deallocate_and_ascend() {

src/liballoc/btree/node.rs

+111-29
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ pub const CAPACITY: usize = 2 * B - 1;
6060
///
6161
/// See also rust-lang/rfcs#197, which would make this structure significantly more safe by
6262
/// avoiding accidentally dropping unused and uninitialized keys and values.
63+
///
64+
/// We put the metadata first so that its position is the same for every `K` and `V`, in order
65+
/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to
66+
/// prevent them from being reordered.
67+
#[repr(C)]
6368
struct LeafNode<K, V> {
64-
/// The arrays storing the actual data of the node. Only the first `len` elements of each
65-
/// array are initialized and valid.
66-
keys: [K; CAPACITY],
67-
vals: [V; CAPACITY],
68-
6969
/// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`.
7070
/// This either points to an actual node or is null.
7171
parent: *const InternalNode<K, V>,
@@ -77,10 +77,14 @@ struct LeafNode<K, V> {
7777

7878
/// The number of keys and values this node stores.
7979
///
80-
/// This is at the end of the node's representation and next to `parent_idx` to encourage
81-
/// the compiler to join `len` and `parent_idx` into the same 32-bit word, reducing space
82-
/// overhead.
80+
/// This next to `parent_idx` to encourage the compiler to join `len` and
81+
/// `parent_idx` into the same 32-bit word, reducing space overhead.
8382
len: u16,
83+
84+
/// The arrays storing the actual data of the node. Only the first `len` elements of each
85+
/// array are initialized and valid.
86+
keys: [K; CAPACITY],
87+
vals: [V; CAPACITY],
8488
}
8589

8690
impl<K, V> LeafNode<K, V> {
@@ -97,8 +101,26 @@ impl<K, V> LeafNode<K, V> {
97101
len: 0
98102
}
99103
}
104+
105+
fn is_shared_root(&self) -> bool {
106+
self as *const _ == &EMPTY_ROOT_NODE as *const _ as *const LeafNode<K, V>
107+
}
100108
}
101109

110+
// We need to implement Sync here in order to make a static instance.
111+
unsafe impl Sync for LeafNode<(), ()> {}
112+
113+
// An empty node used as a placeholder for the root node, to avoid allocations.
114+
// We use () in order to save space, since no operation on an empty tree will
115+
// ever take a pointer past the first key.
116+
static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode {
117+
parent: ptr::null(),
118+
parent_idx: 0,
119+
len: 0,
120+
keys: [(); CAPACITY],
121+
vals: [(); CAPACITY],
122+
};
123+
102124
/// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
103125
/// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an
104126
/// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the
@@ -168,6 +190,21 @@ unsafe impl<K: Sync, V: Sync> Sync for Root<K, V> { }
168190
unsafe impl<K: Send, V: Send> Send for Root<K, V> { }
169191

170192
impl<K, V> Root<K, V> {
193+
pub fn is_shared_root(&self) -> bool {
194+
self.as_ref().is_shared_root()
195+
}
196+
197+
pub fn shared_empty_root() -> Self {
198+
Root {
199+
node: unsafe {
200+
BoxedNode::from_ptr(NonNull::new_unchecked(
201+
&EMPTY_ROOT_NODE as *const _ as *const LeafNode<K, V> as *mut _
202+
))
203+
},
204+
height: 0,
205+
}
206+
}
207+
171208
pub fn new_leaf() -> Self {
172209
Root {
173210
node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })),
@@ -209,6 +246,7 @@ impl<K, V> Root<K, V> {
209246
/// new node the root. This increases the height by 1 and is the opposite of `pop_level`.
210247
pub fn push_level(&mut self)
211248
-> NodeRef<marker::Mut, K, V, marker::Internal> {
249+
debug_assert!(!self.is_shared_root());
212250
let mut new_node = Box::new(unsafe { InternalNode::new() });
213251
new_node.edges[0] = unsafe { BoxedNode::from_ptr(self.node.as_ptr()) };
214252

@@ -353,12 +391,16 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
353391
}
354392
}
355393

394+
pub fn is_shared_root(&self) -> bool {
395+
self.as_leaf().is_shared_root()
396+
}
397+
356398
pub fn keys(&self) -> &[K] {
357-
self.reborrow().into_slices().0
399+
self.reborrow().into_key_slice()
358400
}
359401

360-
pub fn vals(&self) -> &[V] {
361-
self.reborrow().into_slices().1
402+
fn vals(&self) -> &[V] {
403+
self.reborrow().into_val_slice()
362404
}
363405

364406
/// Finds the parent of the current node. Returns `Ok(handle)` if the current
@@ -433,6 +475,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
433475
marker::Edge
434476
>
435477
> {
478+
debug_assert!(!self.is_shared_root());
436479
let node = self.node;
437480
let ret = self.ascend().ok();
438481
Global.dealloc(node.as_opaque(), Layout::new::<LeafNode<K, V>>());
@@ -500,30 +543,51 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
500543
}
501544
}
502545

503-
pub fn keys_mut(&mut self) -> &mut [K] {
504-
unsafe { self.reborrow_mut().into_slices_mut().0 }
546+
fn keys_mut(&mut self) -> &mut [K] {
547+
unsafe { self.reborrow_mut().into_key_slice_mut() }
505548
}
506549

507-
pub fn vals_mut(&mut self) -> &mut [V] {
508-
unsafe { self.reborrow_mut().into_slices_mut().1 }
550+
fn vals_mut(&mut self) -> &mut [V] {
551+
unsafe { self.reborrow_mut().into_val_slice_mut() }
509552
}
510553
}
511554

512555
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
513-
pub fn into_slices(self) -> (&'a [K], &'a [V]) {
514-
unsafe {
515-
(
556+
fn into_key_slice(self) -> &'a [K] {
557+
// When taking a pointer to the keys, if our key has a stricter
558+
// alignment requirement than the shared root does, then the pointer
559+
// would be out of bounds, which LLVM assumes will not happen. If the
560+
// alignment is more strict, we need to make an empty slice that doesn't
561+
// use an out of bounds pointer.
562+
if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
563+
&[]
564+
} else {
565+
// Here either it's not the root, or the alignment is less strict,
566+
// in which case the keys pointer will point "one-past-the-end" of
567+
// the node, which is allowed by LLVM.
568+
unsafe {
516569
slice::from_raw_parts(
517570
self.as_leaf().keys.as_ptr(),
518571
self.len()
519-
),
520-
slice::from_raw_parts(
521-
self.as_leaf().vals.as_ptr(),
522-
self.len()
523572
)
573+
}
574+
}
575+
}
576+
577+
fn into_val_slice(self) -> &'a [V] {
578+
debug_assert!(!self.is_shared_root());
579+
unsafe {
580+
slice::from_raw_parts(
581+
self.as_leaf().vals.as_ptr(),
582+
self.len()
524583
)
525584
}
526585
}
586+
587+
fn into_slices(self) -> (&'a [K], &'a [V]) {
588+
let k = unsafe { ptr::read(&self) };
589+
(k.into_key_slice(), self.into_val_slice())
590+
}
527591
}
528592

529593
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
@@ -535,27 +599,41 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
535599
}
536600
}
537601

538-
pub fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) {
539-
unsafe {
540-
(
602+
fn into_key_slice_mut(mut self) -> &'a mut [K] {
603+
if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
604+
&mut []
605+
} else {
606+
unsafe {
541607
slice::from_raw_parts_mut(
542608
&mut self.as_leaf_mut().keys as *mut [K] as *mut K,
543609
self.len()
544-
),
545-
slice::from_raw_parts_mut(
546-
&mut self.as_leaf_mut().vals as *mut [V] as *mut V,
547-
self.len()
548610
)
611+
}
612+
}
613+
}
614+
615+
fn into_val_slice_mut(mut self) -> &'a mut [V] {
616+
debug_assert!(!self.is_shared_root());
617+
unsafe {
618+
slice::from_raw_parts_mut(
619+
&mut self.as_leaf_mut().vals as *mut [V] as *mut V,
620+
self.len()
549621
)
550622
}
551623
}
624+
625+
fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) {
626+
let k = unsafe { ptr::read(&self) };
627+
(k.into_key_slice_mut(), self.into_val_slice_mut())
628+
}
552629
}
553630

554631
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
555632
/// Adds a key/value pair the end of the node.
556633
pub fn push(&mut self, key: K, val: V) {
557634
// Necessary for correctness, but this is an internal module
558635
debug_assert!(self.len() < CAPACITY);
636+
debug_assert!(!self.is_shared_root());
559637

560638
let idx = self.len();
561639

@@ -571,6 +649,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
571649
pub fn push_front(&mut self, key: K, val: V) {
572650
// Necessary for correctness, but this is an internal module
573651
debug_assert!(self.len() < CAPACITY);
652+
debug_assert!(!self.is_shared_root());
574653

575654
unsafe {
576655
slice_insert(self.keys_mut(), 0, key);
@@ -884,6 +963,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
884963
fn insert_fit(&mut self, key: K, val: V) -> *mut V {
885964
// Necessary for correctness, but in a private module
886965
debug_assert!(self.node.len() < CAPACITY);
966+
debug_assert!(!self.node.is_shared_root());
887967

888968
unsafe {
889969
slice_insert(self.node.keys_mut(), self.idx, key);
@@ -1061,6 +1141,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV>
10611141
/// allocated node.
10621142
pub fn split(mut self)
10631143
-> (NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, K, V, Root<K, V>) {
1144+
debug_assert!(!self.node.is_shared_root());
10641145
unsafe {
10651146
let mut new_node = Box::new(LeafNode::new());
10661147

@@ -1098,6 +1179,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV>
10981179
/// now adjacent key/value pairs to the left and right of this handle.
10991180
pub fn remove(mut self)
11001181
-> (Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>, K, V) {
1182+
debug_assert!(!self.node.is_shared_root());
11011183
unsafe {
11021184
let k = slice_remove(self.node.keys_mut(), self.idx);
11031185
let v = slice_remove(self.node.vals_mut(), self.idx);

0 commit comments

Comments
 (0)