about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorEdward Wang <edward.yu.wang@gmail.com>2014-03-21 15:16:07 +0800
committerEdward Wang <edward.yu.wang@gmail.com>2014-03-21 20:49:18 +0800
commitdb5206c32a879d5058d6a5cdce39c13c763fbdd5 (patch)
tree799db68c952b9713635668ae8e45906e823b6652 /src/libstd
parentcaf17fea06bdf3d1540aded41a161f04a8c5a2c9 (diff)
downloadrust-db5206c32a879d5058d6a5cdce39c13c763fbdd5.tar.gz
rust-db5206c32a879d5058d6a5cdce39c13c763fbdd5.zip
Rewrite rc::Rc using cell::Cell
Since `Arc` has been using `Atomic`, this closes 12625.

Closes #12625.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/rc.rs99
1 files changed, 65 insertions, 34 deletions
diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs
index 605cbd3f28a..dcf4d31c308 100644
--- a/src/libstd/rc.rs
+++ b/src/libstd/rc.rs
@@ -24,18 +24,20 @@ pointers, and then storing the parent pointers as `Weak` pointers.
 */
 
 use cast::transmute;
+use cell::Cell;
 use clone::Clone;
 use cmp::{Eq, Ord};
 use kinds::marker;
 use ops::{Deref, Drop};
 use option::{Option, Some, None};
 use ptr;
+use ptr::RawPtr;
 use rt::global_heap::exchange_free;
 
 struct RcBox<T> {
     value: T,
-    strong: uint,
-    weak: uint
+    strong: Cell<uint>,
+    weak: Cell<uint>
 }
 
 /// Immutable reference counted pointer type
@@ -56,7 +58,11 @@ impl<T> Rc<T> {
                 // destructor never frees the allocation while the
                 // strong destructor is running, even if the weak
                 // 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,
                 noshare: marker::NoShare
             }
@@ -67,13 +73,11 @@ impl<T> Rc<T> {
 impl<T> Rc<T> {
     /// Downgrade the reference-counted pointer to a weak reference
     pub fn downgrade(&self) -> Weak<T> {
-        unsafe {
-            (*self.ptr).weak += 1;
-            Weak {
-                ptr: self.ptr,
-                nosend: marker::NoSend,
-                noshare: marker::NoShare
-            }
+        self.inc_weak();
+        Weak {
+            ptr: self.ptr,
+            nosend: marker::NoSend,
+            noshare: marker::NoShare
         }
     }
 }
@@ -82,7 +86,7 @@ impl<T> Deref<T> for Rc<T> {
     /// Borrow the value contained in the reference-counted box
     #[inline(always)]
     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> {
     fn drop(&mut self) {
         unsafe {
-            if self.ptr != 0 as *mut RcBox<T> {
-                (*self.ptr).strong -= 1;
-                if (*self.ptr).strong == 0 {
+            if !self.ptr.is_null() {
+                self.dec_strong();
+                if self.strong() == 0 {
                     ptr::read(self.deref()); // destroy the contained object
 
                     // remove the implicit "strong weak" pointer now
                     // 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)
                     }
                 }
@@ -111,10 +115,8 @@ impl<T> Drop for Rc<T> {
 impl<T> Clone for Rc<T> {
     #[inline]
     fn clone(&self) -> Rc<T> {
-        unsafe {
-            (*self.ptr).strong += 1;
-            Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
-        }
+        self.inc_strong();
+        Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
     }
 }
 
@@ -151,13 +153,11 @@ pub struct Weak<T> {
 impl<T> Weak<T> {
     /// Upgrade a weak reference to a strong reference
     pub fn upgrade(&self) -> Option<Rc<T>> {
-        unsafe {
-            if (*self.ptr).strong == 0 {
-                None
-            } else {
-                (*self.ptr).strong += 1;
-                Some(Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare })
-            }
+        if self.strong() == 0 {
+            None
+        } else {
+            self.inc_strong();
+            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> {
     fn drop(&mut self) {
         unsafe {
-            if self.ptr != 0 as *mut RcBox<T> {
-                (*self.ptr).weak -= 1;
+            if !self.ptr.is_null() {
+                self.dec_weak();
                 // the weak count starts at 1, and will only go to
                 // zero if all the strong pointers have disappeared.
-                if (*self.ptr).weak == 0 {
+                if self.weak() == 0 {
                     exchange_free(self.ptr as *u8)
                 }
             }
@@ -181,13 +181,44 @@ impl<T> Drop for Weak<T> {
 impl<T> Clone for Weak<T> {
     #[inline]
     fn clone(&self) -> Weak<T> {
-        unsafe {
-            (*self.ptr).weak += 1;
-            Weak { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }
-        }
+        self.inc_weak();
+        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)]
 mod tests {
     use prelude::*;