Rewrite rc::Rc using cell::Cell
Since `Arc` has been using `Atomic`, this closes 12625. Closes #12625.
This commit is contained in:
parent
caf17fea06
commit
db5206c32a
2 changed files with 65 additions and 42 deletions
|
@ -24,18 +24,20 @@ pointers, and then storing the parent pointers as `Weak` pointers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use cast::transmute;
|
use cast::transmute;
|
||||||
|
use cell::Cell;
|
||||||
use clone::Clone;
|
use clone::Clone;
|
||||||
use cmp::{Eq, Ord};
|
use cmp::{Eq, Ord};
|
||||||
use kinds::marker;
|
use kinds::marker;
|
||||||
use ops::{Deref, Drop};
|
use ops::{Deref, Drop};
|
||||||
use option::{Option, Some, None};
|
use option::{Option, Some, None};
|
||||||
use ptr;
|
use ptr;
|
||||||
|
use ptr::RawPtr;
|
||||||
use rt::global_heap::exchange_free;
|
use rt::global_heap::exchange_free;
|
||||||
|
|
||||||
struct RcBox<T> {
|
struct RcBox<T> {
|
||||||
value: T,
|
value: T,
|
||||||
strong: uint,
|
strong: Cell<uint>,
|
||||||
weak: uint
|
weak: Cell<uint>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Immutable reference counted pointer type
|
/// Immutable reference counted pointer type
|
||||||
|
@ -56,7 +58,11 @@ impl<T> Rc<T> {
|
||||||
// destructor never frees the allocation while the
|
// destructor never frees the allocation while the
|
||||||
// strong destructor is running, even if the weak
|
// strong destructor is running, even if the weak
|
||||||
// pointer is stored inside the strong one.
|
// pointer is stored inside the strong one.
|
||||||
ptr: transmute(~RcBox { value: value, strong: 1, weak: 1 }),
|
ptr: transmute(~RcBox {
|
||||||
|
value: value,
|
||||||
|
strong: Cell::new(1),
|
||||||
|
weak: Cell::new(1)
|
||||||
|
}),
|
||||||
nosend: marker::NoSend,
|
nosend: marker::NoSend,
|
||||||
noshare: marker::NoShare
|
noshare: marker::NoShare
|
||||||
}
|
}
|
||||||
|
@ -67,13 +73,11 @@ impl<T> Rc<T> {
|
||||||
impl<T> Rc<T> {
|
impl<T> Rc<T> {
|
||||||
/// Downgrade the reference-counted pointer to a weak reference
|
/// Downgrade the reference-counted pointer to a weak reference
|
||||||
pub fn downgrade(&self) -> Weak<T> {
|
pub fn downgrade(&self) -> Weak<T> {
|
||||||
unsafe {
|
self.inc_weak();
|
||||||
(*self.ptr).weak += 1;
|
Weak {
|
||||||
Weak {
|
ptr: self.ptr,
|
||||||
ptr: self.ptr,
|
nosend: marker::NoSend,
|
||||||
nosend: marker::NoSend,
|
noshare: marker::NoShare
|
||||||
noshare: marker::NoShare
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +86,7 @@ impl<T> Deref<T> for Rc<T> {
|
||||||
/// Borrow the value contained in the reference-counted box
|
/// Borrow the value contained in the reference-counted box
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn deref<'a>(&'a self) -> &'a T {
|
fn deref<'a>(&'a self) -> &'a T {
|
||||||
unsafe { &(*self.ptr).value }
|
&self.inner().value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,16 +94,16 @@ impl<T> Deref<T> for Rc<T> {
|
||||||
impl<T> Drop for Rc<T> {
|
impl<T> Drop for Rc<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if self.ptr != 0 as *mut RcBox<T> {
|
if !self.ptr.is_null() {
|
||||||
(*self.ptr).strong -= 1;
|
self.dec_strong();
|
||||||
if (*self.ptr).strong == 0 {
|
if self.strong() == 0 {
|
||||||
ptr::read(self.deref()); // destroy the contained object
|
ptr::read(self.deref()); // destroy the contained object
|
||||||
|
|
||||||
// remove the implicit "strong weak" pointer now
|
// remove the implicit "strong weak" pointer now
|
||||||
// that we've destroyed the contents.
|
// that we've destroyed the contents.
|
||||||
(*self.ptr).weak -= 1;
|
self.dec_weak();
|
||||||
|
|
||||||
if (*self.ptr).weak == 0 {
|
if self.weak() == 0 {
|
||||||
exchange_free(self.ptr as *u8)
|
exchange_free(self.ptr as *u8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,10 +115,8 @@ impl<T> Drop for Rc<T> {
|
||||||
impl<T> Clone for Rc<T> {
|
impl<T> Clone for Rc<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Rc<T> {
|
fn clone(&self) -> Rc<T> {
|
||||||
unsafe {
|
self.inc_strong();
|
||||||
(*self.ptr).strong += 1;
|
Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
|
||||||
Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,13 +153,11 @@ pub struct Weak<T> {
|
||||||
impl<T> Weak<T> {
|
impl<T> Weak<T> {
|
||||||
/// Upgrade a weak reference to a strong reference
|
/// Upgrade a weak reference to a strong reference
|
||||||
pub fn upgrade(&self) -> Option<Rc<T>> {
|
pub fn upgrade(&self) -> Option<Rc<T>> {
|
||||||
unsafe {
|
if self.strong() == 0 {
|
||||||
if (*self.ptr).strong == 0 {
|
None
|
||||||
None
|
} else {
|
||||||
} else {
|
self.inc_strong();
|
||||||
(*self.ptr).strong += 1;
|
Some(Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare })
|
||||||
Some(Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,11 +166,11 @@ impl<T> Weak<T> {
|
||||||
impl<T> Drop for Weak<T> {
|
impl<T> Drop for Weak<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if self.ptr != 0 as *mut RcBox<T> {
|
if !self.ptr.is_null() {
|
||||||
(*self.ptr).weak -= 1;
|
self.dec_weak();
|
||||||
// the weak count starts at 1, and will only go to
|
// the weak count starts at 1, and will only go to
|
||||||
// zero if all the strong pointers have disappeared.
|
// zero if all the strong pointers have disappeared.
|
||||||
if (*self.ptr).weak == 0 {
|
if self.weak() == 0 {
|
||||||
exchange_free(self.ptr as *u8)
|
exchange_free(self.ptr as *u8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,13 +181,44 @@ impl<T> Drop for Weak<T> {
|
||||||
impl<T> Clone for Weak<T> {
|
impl<T> Clone for Weak<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Weak<T> {
|
fn clone(&self) -> Weak<T> {
|
||||||
unsafe {
|
self.inc_weak();
|
||||||
(*self.ptr).weak += 1;
|
Weak { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
|
||||||
Weak { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(missing_doc)]
|
||||||
|
trait RcBoxPtr<T> {
|
||||||
|
fn inner<'a>(&'a self) -> &'a RcBox<T>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn strong(&self) -> uint { self.inner().strong.get() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn weak(&self) -> uint { self.inner().weak.get() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> RcBoxPtr<T> for Rc<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn inner<'a>(&'a self) -> &'a RcBox<T> { unsafe { &(*self.ptr) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> RcBoxPtr<T> for Weak<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn inner<'a>(&'a self) -> &'a RcBox<T> { unsafe { &(*self.ptr) } }
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
|
@ -1156,14 +1156,6 @@ mod test {
|
||||||
use codemap::*;
|
use codemap::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn is_freeze<T: Freeze>() {}
|
|
||||||
|
|
||||||
// Assert that the AST remains Freeze (#10693).
|
|
||||||
#[test]
|
|
||||||
fn ast_is_freeze() {
|
|
||||||
is_freeze::<Item>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// are ASTs encodable?
|
// are ASTs encodable?
|
||||||
#[test]
|
#[test]
|
||||||
fn check_asts_encodable() {
|
fn check_asts_encodable() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue