1
Fork 0

Rewrite rc::Rc using cell::Cell

Since `Arc` has been using `Atomic`, this closes 12625.

Closes #12625.
This commit is contained in:
Edward Wang 2014-03-21 15:16:07 +08:00
parent caf17fea06
commit db5206c32a
2 changed files with 65 additions and 42 deletions

View file

@ -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::*;

View file

@ -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() {