Skip to content

Commit cbdcfca

Browse files
committed
Swapped key comparisons to match lower_bound_mut, added FIXME comments on bulk inserting other_keys into self map, and inlined with_next() insertion on conflicts from Cursor*
1 parent 24efac1 commit cbdcfca

1 file changed

Lines changed: 36 additions & 68 deletions

File tree

  • library/alloc/src/collections/btree

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

Lines changed: 36 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,7 +1253,6 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
12531253
/// Similar to [`insert`], though, the key is not overwritten,
12541254
/// which matters for types that can be `==` without being identical.
12551255
///
1256-
///
12571256
/// [`insert`]: BTreeMap::insert
12581257
/// [`append`]: BTreeMap::append
12591258
///
@@ -1311,19 +1310,28 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
13111310
let mut self_cursor = self.lower_bound_mut(Bound::Included(&first_other_key));
13121311

13131312
if let Some((self_key, _)) = self_cursor.peek_next() {
1314-
match K::cmp(&first_other_key, self_key) {
1313+
match K::cmp(self_key, &first_other_key) {
13151314
Ordering::Equal => {
1316-
self_cursor.with_next(|self_key, self_val| {
1317-
conflict(self_key, self_val, first_other_val)
1318-
});
1315+
// if `f` unwinds, the next entry is already removed leaving
1316+
// the tree in valid state.
1317+
// FIXME: Once `MaybeDangling` is implemented, we can optimize
1318+
// this through using a drop handler and transmutating CursorMutKey<K, V>
1319+
// to CursorMutKey<ManuallyDrop<K>, ManuallyDrop<V>> (see PR #152418)
1320+
if let Some((k, v)) = self_cursor.remove_next() {
1321+
// SAFETY: we remove the K, V out of the next entry,
1322+
// apply 'f' to get a new (K, V), and insert it back
1323+
// into the next entry that the cursor is pointing at
1324+
let v = conflict(&k, v, first_other_val);
1325+
unsafe { self_cursor.insert_after_unchecked(k, v) };
1326+
}
13191327
}
1320-
Ordering::Less =>
1328+
Ordering::Greater =>
13211329
// SAFETY: we know our other_key's ordering is less than self_key,
13221330
// so inserting before will guarantee sorted order
13231331
unsafe {
13241332
self_cursor.insert_before_unchecked(first_other_key, first_other_val);
13251333
},
1326-
Ordering::Greater => {
1334+
Ordering::Less => {
13271335
unreachable!("Cursor's peek_next should return None.");
13281336
}
13291337
}
@@ -1338,22 +1346,31 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
13381346
for (other_key, other_val) in other_iter {
13391347
loop {
13401348
if let Some((self_key, _)) = self_cursor.peek_next() {
1341-
match K::cmp(&other_key, self_key) {
1349+
match K::cmp(self_key, &other_key) {
13421350
Ordering::Equal => {
1343-
self_cursor.with_next(|self_key, self_val| {
1344-
conflict(self_key, self_val, other_val)
1345-
});
1351+
// if `f` unwinds, the next entry is already removed leaving
1352+
// the tree in valid state.
1353+
// FIXME: Once `MaybeDangling` is implemented, we can optimize
1354+
// this through using a drop handler and transmutating CursorMutKey<K, V>
1355+
// to CursorMutKey<ManuallyDrop<K>, ManuallyDrop<V>> (see PR #152418)
1356+
if let Some((k, v)) = self_cursor.remove_next() {
1357+
// SAFETY: we remove the K, V out of the next entry,
1358+
// apply 'f' to get a new (K, V), and insert it back
1359+
// into the next entry that the cursor is pointing at
1360+
let v = conflict(&k, v, other_val);
1361+
unsafe { self_cursor.insert_after_unchecked(k, v) };
1362+
}
13461363
break;
13471364
}
1348-
Ordering::Less => {
1349-
// SAFETY: we know our other_key's ordering is less than self_key,
1365+
Ordering::Greater => {
1366+
// SAFETY: we know our self_key's ordering is greater than other_key,
13501367
// so inserting before will guarantee sorted order
13511368
unsafe {
13521369
self_cursor.insert_before_unchecked(other_key, other_val);
13531370
}
13541371
break;
13551372
}
1356-
Ordering::Greater => {
1373+
Ordering::Less => {
13571374
// FIXME: instead of doing a linear search here,
13581375
// this can be optimized to search the tree by starting
13591376
// from self_cursor and going towards the root and then
@@ -1363,6 +1380,11 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
13631380
}
13641381
}
13651382
} else {
1383+
// FIXME: If we get here, that means all of other's keys are greater than
1384+
// self's keys. For performance, this should really do a bulk insertion of items
1385+
// from other_iter into the end of self `BTreeMap`. Maybe this should be
1386+
// a method for Cursor*?
1387+
13661388
// SAFETY: reaching here means our cursor is at the end
13671389
// self BTreeMap so we just insert other_key here
13681390
unsafe {
@@ -3396,37 +3418,6 @@ impl<'a, K, V, A> CursorMutKey<'a, K, V, A> {
33963418

33973419
// Now the tree editing operations
33983420
impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
3399-
/// Calls a function with ownership of the next element's key and
3400-
/// and value and expects it to return a value to write
3401-
/// back to the next element's key and value. The cursor is not
3402-
/// advanced forward.
3403-
///
3404-
/// If the cursor is at the end of the map then the function is not called
3405-
/// and this essentially does not do anything.
3406-
///
3407-
/// # Safety
3408-
///
3409-
/// You must ensure that the `BTreeMap` invariants are maintained.
3410-
/// Specifically:
3411-
///
3412-
/// * The next element's key must be unique in the tree.
3413-
/// * All keys in the tree must remain in sorted order.
3414-
#[allow(dead_code)] /* This function exists for consistency with CursorMut */
3415-
pub(super) fn with_next(&mut self, f: impl FnOnce(K, V) -> (K, V)) {
3416-
// if `f` unwinds, the next entry is already removed leaving
3417-
// the tree in valid state.
3418-
// FIXME: Once `MaybeDangling` is implemented, we can optimize
3419-
// this through using a drop handler and transmutating CursorMutKey<K, V>
3420-
// to CursorMutKey<ManuallyDrop<K>, ManuallyDrop<V>> (see PR #152418)
3421-
if let Some((k, v)) = self.remove_next() {
3422-
// SAFETY: we remove the K, V out of the next entry,
3423-
// apply 'f' to get a new (K, V), and insert it back
3424-
// into the next entry that the cursor is pointing at
3425-
let (k, v) = f(k, v);
3426-
unsafe { self.insert_after_unchecked(k, v) };
3427-
}
3428-
}
3429-
34303421
/// Inserts a new key-value pair into the map in the gap that the
34313422
/// cursor is currently pointing to.
34323423
///
@@ -3632,29 +3623,6 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
36323623
}
36333624

36343625
impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
3635-
/// Calls a function with a reference to the next element's key and
3636-
/// ownership of its value. The function is expected to return a value
3637-
/// to write back to the next element's value. The cursor is not
3638-
/// advanced forward.
3639-
///
3640-
/// If the cursor is at the end of the map then the function is not called
3641-
/// and this essentially does not do anything.
3642-
pub(super) fn with_next(&mut self, f: impl FnOnce(&K, V) -> V) {
3643-
// FIXME: This can be optimized to not do all the removing/reinserting
3644-
// logic by using ptr::read, calling `f`, and then using ptr::write.
3645-
// if `f` unwinds, then we need to remove the entry while being careful to
3646-
// not cause UB by moving or dropping the already-dropped `V`
3647-
// for the entry. Some implementation ideas:
3648-
// https://github.com/rust-lang/rust/pull/152418#discussion_r2800232576
3649-
if let Some((k, v)) = self.remove_next() {
3650-
// SAFETY: we remove the K, V out of the next entry,
3651-
// apply 'f' to get a new V, and insert (K, V) back
3652-
// into the next entry that the cursor is pointing at
3653-
let v = f(&k, v);
3654-
unsafe { self.insert_after_unchecked(k, v) };
3655-
}
3656-
}
3657-
36583626
/// Inserts a new key-value pair into the map in the gap that the
36593627
/// cursor is currently pointing to.
36603628
///

0 commit comments

Comments
 (0)