-
Notifications
You must be signed in to change notification settings - Fork 13k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #74437 - ssomers:btree_no_root_in_noderef, r=Mark-Simul…
…acrum BTreeMap: move up reference to map's root from NodeRef Since the introduction of `NodeRef` years ago, it also contained a mutable reference to the owner of the root node of the tree (somewhat disguised as *const). Its intent is to be used only when the rest of the `NodeRef` is no longer needed. Moving this to where it's actually used, thought me 2 things: - Some sort of "postponed mutable reference" is required in most places that it is/was used, and that's exactly where we also need to store a reference to the length (number of elements) of the tree, for the same reason. The length reference can be a normal reference, because the tree code does not care about tree length (just length per node). - It's downright obfuscation in `from_sorted_iter` (transplanted to #75329) - It's one of the reasons for the scary notice on `reborrow_mut`, the other one being addressed in #73971. This does repeat the raw pointer code in a few places, but it could be bundled up with the length reference. r? `@Mark-Simulacrum`
- Loading branch information
Showing
5 changed files
with
163 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
use core::marker::PhantomData; | ||
use core::ptr::NonNull; | ||
|
||
/// Models a reborrow of some unique reference, when you know that the reborrow | ||
/// and all its descendants (i.e., all pointers and references derived from it) | ||
/// will not be used any more at some point, after which you want to use the | ||
/// original unique reference again. | ||
/// | ||
/// The borrow checker usually handles this stacking of borrows for you, but | ||
/// some control flows that accomplish this stacking are too complicated for | ||
/// the compiler to follow. A `DormantMutRef` allows you to check borrowing | ||
/// yourself, while still expressing its stacked nature, and encapsulating | ||
/// the raw pointer code needed to do this without undefined behavior. | ||
pub struct DormantMutRef<'a, T> { | ||
ptr: NonNull<T>, | ||
_marker: PhantomData<&'a mut T>, | ||
} | ||
|
||
impl<'a, T> DormantMutRef<'a, T> { | ||
/// Capture a unique borrow, and immediately reborrow it. For the compiler, | ||
/// the lifetime of the new reference is the same as the lifetime of the | ||
/// original reference, but you promise to use it for a shorter period. | ||
pub fn new(t: &'a mut T) -> (&'a mut T, Self) { | ||
let ptr = NonNull::from(t); | ||
// SAFETY: we hold the borrow throughout 'a via `_marker`, and we expose | ||
// only this reference, so it is unique. | ||
let new_ref = unsafe { &mut *ptr.as_ptr() }; | ||
(new_ref, Self { ptr, _marker: PhantomData }) | ||
} | ||
|
||
/// Revert to the unique borrow initially captured. | ||
/// | ||
/// # Safety | ||
/// | ||
/// The reborrow must have ended, i.e., the reference returned by `new` and | ||
/// all pointers and references derived from it, must not be used anymore. | ||
pub unsafe fn awaken(self) -> &'a mut T { | ||
// SAFETY: our own safety conditions imply this reference is again unique. | ||
unsafe { &mut *self.ptr.as_ptr() } | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use super::DormantMutRef; | ||
|
||
#[test] | ||
fn test_borrow() { | ||
let mut data = 1; | ||
let mut stack = vec![]; | ||
let mut rr = &mut data; | ||
for factor in [2, 3, 7].iter() { | ||
let (r, dormant_r) = DormantMutRef::new(rr); | ||
rr = r; | ||
assert_eq!(*rr, 1); | ||
stack.push((factor, dormant_r)); | ||
} | ||
while let Some((factor, dormant_r)) = stack.pop() { | ||
let r = unsafe { dormant_r.awaken() }; | ||
*r *= factor; | ||
} | ||
assert_eq!(data, 42); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
mod borrow; | ||
pub mod map; | ||
mod navigate; | ||
mod node; | ||
|
Oops, something went wrong.