Skip to content

Commit 9b423c5

Browse files
committed
Changed with_next() to use remove_next() + insert_after_unchecked() instead of drop handling, refactored code a bit, and updated comments
1 parent 97f5547 commit 9b423c5

File tree

2 files changed

+60
-206
lines changed

2 files changed

+60
-206
lines changed

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

Lines changed: 58 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
13181318
});
13191319
}
13201320
Ordering::Less =>
1321-
// Safety: we know our other_key's ordering is less than self_key,
1321+
// SAFETY: we know our other_key's ordering is less than self_key,
13221322
// so inserting before will guarantee sorted order
13231323
unsafe {
13241324
self_cursor.insert_before_unchecked(first_other_key, first_other_val);
@@ -1328,61 +1328,45 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
13281328
}
13291329
}
13301330
} else {
1331-
// Safety: if we reach here, that means our cursor has reached
1332-
// the end of self BTreeMap, (other_key is greater than all the
1333-
// previous self BTreeMap keys) so we just insert other_key here
1334-
// at the end of the CursorMut
1331+
// SAFETY: reaching here means our cursor is at the end
1332+
// self BTreeMap so we just insert other_key here
13351333
unsafe {
13361334
self_cursor.insert_after_unchecked(first_other_key, first_other_val);
13371335
}
13381336
}
13391337

13401338
for (other_key, other_val) in other_iter {
1341-
if self_cursor.peek_next().is_some() {
1342-
loop {
1343-
let self_entry = self_cursor.peek_next();
1344-
if let Some((self_key, _)) = self_entry {
1345-
match K::cmp(&other_key, self_key) {
1346-
Ordering::Equal => {
1347-
self_cursor.with_next(|self_key, self_val| {
1348-
conflict(self_key, self_val, other_val)
1349-
});
1350-
break;
1351-
}
1352-
Ordering::Less => {
1353-
// Safety: we know our other_key's ordering is less than self_key,
1354-
// so inserting before will guarantee sorted order
1355-
unsafe {
1356-
self_cursor.insert_before_unchecked(other_key, other_val);
1357-
}
1358-
break;
1359-
}
1360-
Ordering::Greater => {
1361-
// advance the cursor forward
1362-
self_cursor.next();
1339+
loop {
1340+
if let Some((self_key, _)) = self_cursor.peek_next() {
1341+
match K::cmp(&other_key, self_key) {
1342+
Ordering::Equal => {
1343+
self_cursor.with_next(|self_key, self_val| {
1344+
conflict(self_key, self_val, other_val)
1345+
});
1346+
break;
1347+
}
1348+
Ordering::Less => {
1349+
// SAFETY: we know our other_key's ordering is less than self_key,
1350+
// so inserting before will guarantee sorted order
1351+
unsafe {
1352+
self_cursor.insert_before_unchecked(other_key, other_val);
13631353
}
1354+
break;
13641355
}
1365-
} else {
1366-
// Safety: if we reach here, that means our cursor has reached
1367-
// the end of self BTreeMap, (other_key is greater than all the
1368-
// previous self BTreeMap keys) so we just insert other_key here
1369-
// at the end of the Cursor
1370-
unsafe {
1371-
self_cursor.insert_after_unchecked(other_key, other_val);
1356+
Ordering::Greater => {
1357+
// advance the cursor forward
1358+
self_cursor.next();
13721359
}
1373-
self_cursor.next();
1374-
break;
13751360
}
1361+
} else {
1362+
// SAFETY: reaching here means our cursor is at the end
1363+
// self BTreeMap so we just insert other_key here
1364+
unsafe {
1365+
self_cursor.insert_after_unchecked(other_key, other_val);
1366+
}
1367+
self_cursor.next();
1368+
break;
13761369
}
1377-
} else {
1378-
// Safety: if we reach here, that means our cursor has reached
1379-
// the end of self BTreeMap, (other_key is greater than all the
1380-
// previous self BTreeMap keys) so we just insert the rest of
1381-
// other_keys here at the end of CursorMut
1382-
unsafe {
1383-
self_cursor.insert_after_unchecked(other_key, other_val);
1384-
}
1385-
self_cursor.next();
13861370
}
13871371
}
13881372
}
@@ -3416,91 +3400,27 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
34163400
///
34173401
/// If the cursor is at the end of the map then the function is not called
34183402
/// and this essentially does not do anything.
3403+
///
3404+
/// # Safety
3405+
///
3406+
/// You must ensure that the `BTreeMap` invariants are maintained.
3407+
/// Specifically:
3408+
///
3409+
/// * The next element's key must be unique in the tree.
3410+
/// * All keys in the tree must remain in sorted order.
34193411
#[allow(dead_code)] /* This function exists for consistency with CursorMut */
34203412
pub(super) fn with_next(&mut self, f: impl FnOnce(K, V) -> (K, V)) {
3421-
/// Call `f` with the next entry's key and value, replacing the
3422-
/// next entry's key and value with the returned key and value.
3423-
/// if `f` unwinds, the next entry is removed.
3424-
/// Equivalent to a more efficient version of:
3425-
/// ```ignore (this is an example equivalent)
3426-
/// if let Some((k, v)) = self.remove_next() {
3427-
/// let (k, v) = f(k, v);
3428-
/// // Safety: key is unmodified
3429-
/// unsafe { self.insert_after_unchecked(k, v) };
3430-
/// }
3431-
/// ```
3432-
struct RemoveNextOnDrop<'a, 'b, K, V, A = Global>
3433-
where
3434-
K: Ord,
3435-
A: Allocator + Clone,
3436-
{
3437-
cursor: &'a mut CursorMutKey<'b, K, V, A>,
3438-
forget_next: bool,
3439-
}
3440-
3441-
impl<K: Ord, V, A: Allocator + Clone> Drop for RemoveNextOnDrop<'_, '_, K, V, A> {
3442-
fn drop(&mut self) {
3443-
if self.forget_next {
3444-
// Removes the next entry of the Cursor without running
3445-
// running the destructor on the key and value (prevents double
3446-
// free)
3447-
self.cursor.forget_next_key_and_value();
3448-
}
3449-
}
3450-
}
3451-
3452-
let mut remove_next_on_drop = RemoveNextOnDrop {
3453-
cursor: self,
3454-
forget_next: false, // next value is not known yet
3455-
};
3456-
3457-
if let Some((k_mut, v_mut)) = remove_next_on_drop.cursor.peek_next() {
3458-
remove_next_on_drop.forget_next = true;
3459-
// Safety: we move the K, V out of the next entry,
3460-
// we marked the entry's value to be forgotten
3461-
// when remove_next_on_drop is dropped that
3462-
// way we avoid returning to the caller leaving
3463-
// a moved-out invalid value if `f` unwinds.
3464-
let k = unsafe { ptr::read(k_mut) };
3465-
let v = unsafe { ptr::read(v_mut) };
3413+
// if `f` unwinds, the next entry is already removed leaving
3414+
// the tree in valid state.
3415+
// FIXME: Once `MaybeDangling` is implemented, we can optimize
3416+
// this through using a drop handler and transmutating CursorMutKey<K, V>
3417+
// to CursorMutKey<ManuallyDrop<K>, ManuallyDrop<V>> (see PR #152418)
3418+
if let Some((k, v)) = self.remove_next() {
3419+
// SAFETY: we remove the K, V out of the next entry,
3420+
// apply 'f' to get a new (K, V), and insert it back
3421+
// into the next entry that the cursor is pointing at
34663422
let (k, v) = f(k, v);
3467-
unsafe { ptr::write(k_mut, k) };
3468-
unsafe { ptr::write(v_mut, v) };
3469-
3470-
remove_next_on_drop.forget_next = false;
3471-
}
3472-
}
3473-
3474-
/// Forgets the next element's key and value from the `BTreeMap`.
3475-
///
3476-
/// The element's key and value does not run its destructor. The cursor position is
3477-
/// unchanged (before the forgotten element).
3478-
fn forget_next_key_and_value(&mut self) {
3479-
let current = match self.current.take() {
3480-
Some(current) => current,
3481-
None => return,
3482-
};
3483-
3484-
if current.reborrow().next_kv().is_err() {
3485-
self.current = Some(current);
3486-
return;
3487-
}
3488-
3489-
let mut emptied_internal_root = false;
3490-
if let Ok(next_kv) = current.next_kv() {
3491-
let ((key, val), pos) =
3492-
next_kv.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
3493-
// Don't run destructor on next element's key and value
3494-
mem::forget(key);
3495-
mem::forget(val);
3496-
self.current = Some(pos);
3497-
*self.length -= 1;
3498-
if emptied_internal_root {
3499-
// SAFETY: This is safe since current does not point within the now
3500-
// empty root node.
3501-
let root = unsafe { self.root.reborrow().as_mut().unwrap() };
3502-
root.pop_internal_level(self.alloc.clone());
3503-
}
3423+
unsafe { self.insert_after_unchecked(k, v) };
35043424
}
35053425
}
35063426

@@ -3717,85 +3637,17 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
37173637
/// If the cursor is at the end of the map then the function is not called
37183638
/// and this essentially does not do anything.
37193639
pub(super) fn with_next(&mut self, f: impl FnOnce(&K, V) -> V) {
3720-
/// Call `f` with the next entry's key and value, replacing the
3721-
/// next entry's value with the returned value. if `f` unwinds,
3722-
/// the next entry is removed.
3723-
/// Equivalent to a more efficient version of:
3724-
/// ```ignore (this is an example equivalent)
3725-
/// if let Some((k, v)) = self.remove_next() {
3726-
/// let v = f(&k, v);
3727-
/// // Safety: key is unmodified
3728-
/// unsafe { self.insert_after_unchecked(k, v) };
3729-
/// }
3730-
/// ```
3731-
struct RemoveNextOnDrop<'a, 'b, K, V, A = Global>
3732-
where
3733-
K: Ord,
3734-
A: Allocator + Clone,
3735-
{
3736-
cursor: &'a mut CursorMut<'b, K, V, A>,
3737-
forget_next: bool,
3738-
}
3739-
3740-
impl<K: Ord, V, A: Allocator + Clone> Drop for RemoveNextOnDrop<'_, '_, K, V, A> {
3741-
fn drop(&mut self) {
3742-
if self.forget_next {
3743-
// Removes the next entry of the Cursor without running
3744-
// running the destructor on the value (prevents double
3745-
// free)
3746-
self.cursor.forget_next_value();
3747-
}
3748-
}
3749-
}
3750-
3751-
let mut remove_next_on_drop = RemoveNextOnDrop {
3752-
cursor: self,
3753-
forget_next: false, // next value is not known yet
3754-
};
3755-
3756-
if let Some((k, v_mut)) = remove_next_on_drop.cursor.peek_next() {
3757-
remove_next_on_drop.forget_next = true;
3758-
// Safety: we move the V out of the next entry,
3759-
// we marked the entry's value to be forgotten
3760-
// when remove_next_on_drop is dropped that
3761-
// way we avoid returning to the caller leaving
3762-
// a moved-out invalid value if `f` unwinds.
3763-
let v = unsafe { ptr::read(v_mut) };
3764-
let v = f(k, v);
3765-
unsafe { ptr::write(v_mut, v) };
3766-
remove_next_on_drop.forget_next = false;
3767-
}
3768-
}
3769-
3770-
/// Forgets the next element's value from the `BTreeMap`.
3771-
///
3772-
/// The element's value does not run its destructor. The cursor position is
3773-
/// unchanged (before the forgotten element).
3774-
fn forget_next_value(&mut self) {
3775-
let current = match self.inner.current.take() {
3776-
Some(current) => current,
3777-
None => return,
3778-
};
3779-
3780-
if current.reborrow().next_kv().is_err() {
3781-
self.inner.current = Some(current);
3782-
return;
3783-
}
3784-
3785-
let mut emptied_internal_root = false;
3786-
if let Ok(next_kv) = current.next_kv() {
3787-
let ((_, val), pos) = next_kv
3788-
.remove_kv_tracking(|| emptied_internal_root = true, self.inner.alloc.clone());
3789-
// Don't run destructor on next element's value
3790-
mem::forget(val);
3791-
self.inner.current = Some(pos);
3792-
*self.inner.length -= 1;
3793-
if emptied_internal_root {
3794-
// SAFETY: This is safe since current does not point within the now
3795-
// empty root node.
3796-
let root = unsafe { self.inner.root.reborrow().as_mut().unwrap() };
3797-
root.pop_internal_level(self.inner.alloc.clone());
3798-
}
3640+
// if `f` unwinds, the next entry is already removed leaving
3641+
// the tree in valid state.
3642+
// FIXME: Once `MaybeDangling` is implemented, we can optimize
3643+
// this through using a drop handler and transmutating CursorMut<K, V>
3644+
// to CursorMut<K, ManuallyDrop<V>> (see PR #152418)
3645+
if let Some((k, v)) = self.remove_next() {
3646+
// SAFETY: we remove the K, V out of the next entry,
3647+
// apply 'f' to get a new V, and insert (K, V) back
3648+
// into the next entry that the cursor is pointing at
3649+
let v = f(&k, v);
3650+
unsafe { self.insert_after_unchecked(k, v) };
37993651
}
38003652
}
38013653

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,6 +2128,8 @@ create_append_test!(test_append_239, 239);
21282128
#[cfg(not(miri))] // Miri is too slow
21292129
create_append_test!(test_append_1700, 1700);
21302130

2131+
// On merging keys 5..8, the values are
2132+
// added together (i + 2 * i)
21312133
macro_rules! create_merge_test {
21322134
($name:ident, $len:expr) => {
21332135
#[test]

0 commit comments

Comments
 (0)