diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index 1cb30eaa040b2..6ec3cdee7d018 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -120,7 +120,9 @@ impl Arc { pub fn new(data: T) -> Arc { Arc { x: UnsafeArc::new(data) } } +} +impl Arc { pub fn get<'a>(&'a self) -> &'a T { unsafe { &*self.x.get_immut() } } @@ -138,9 +140,56 @@ impl Arc { let Arc { x: x } = self; x.unwrap() } + + pub fn try_get_mut<'a>(&'a mut self) -> Either<&'a mut Arc, &'a mut T> { + unsafe { + if !self.x.is_owned() { + Left(self) + } else { + Right(&mut *self.x.get()) + } + } + } + + pub fn try_unwrap(self) -> Either, T> { + match self.x.try_unwrap() { + Left(this) => Left(Arc {x: this}), + Right(v) => Right(v) + } + } +} + +impl Arc { + /// Clones the content if there is more than one reference, and returns a + /// mutable reference to the data once this is the only refence + #[inline] + pub fn cow<'r>(&'r mut self) -> &'r mut T { + unsafe { + if !self.x.is_owned() { + self.cow_clone() + } else { + &mut *self.x.get() + } + } + } + + #[inline(never)] + unsafe fn cow_clone<'r>(&'r mut self) -> &'r mut T { + self.x = UnsafeArc::new_unsafe((*self.x.get_immut()).clone()); + &mut *self.x.get() + } + + pub fn value(self) -> T { + unsafe { + match self.x.try_unwrap() { + Left(this) => (*this.get()).clone(), + Right(v) => v + } + } + } } -impl Clone for Arc { +impl Clone for Arc { /** * Duplicate an atomically reference counted wrapper. * @@ -622,6 +671,15 @@ mod tests { info2!("{:?}", arc_v); } + #[test] + fn test_arc_mut() { + let mut x = Arc::new(5); + let y = x.clone(); + *x.cow() = 9; + assert_eq!(*x.get(), 9); + assert_eq!(*y.get(), 5); + } + #[test] fn test_mutex_arc_condvar() { let arc = ~MutexArc::new(false); diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs index 50dff380f007e..59605aebd2df4 100644 --- a/src/libstd/rc.rs +++ b/src/libstd/rc.rs @@ -21,10 +21,12 @@ reference is a unique handle and the type is marked as non-`Freeze`. */ use ptr::RawPtr; -use unstable::intrinsics::transmute; +use unstable::intrinsics::{forget, transmute}; +use cast; use ops::Drop; use kinds::{Freeze, Send}; use clone::{Clone, DeepClone}; +use either::{Either, Left, Right}; struct RcBox { value: T, @@ -61,9 +63,71 @@ impl Rc { /// Borrow the value contained in the reference-counted box #[inline] - pub fn borrow<'r>(&'r self) -> &'r T { + pub fn get<'r>(&'r self) -> &'r T { unsafe { &(*self.ptr).value } } + + /// Return a mutable reference that only alters this Rc if possible, + /// or return self + pub fn try_get_mut<'r>(&'r mut self) -> Either<&'r mut Rc, &'r mut T> { + unsafe { + if (*self.ptr).count > 1 { + Left(self) + } else { + Right(cast::copy_mut_lifetime(self, &mut (*self.ptr).value)) + } + } + } + + /// Return the contents while altering only this Rc if possible, + /// or return self + pub fn try_unwrap(self) -> Either, T> { + unsafe { + if (*self.ptr).count > 1 { + Left(self) + } else { + let box: ~RcBox = transmute(self.ptr); + forget(self); + Right(box.value) + } + } + } +} + +impl Rc { + /// Clones the content if there is more than one reference, and returns a + /// mutable reference to the data once this is the only refence + #[inline] + pub fn cow<'r>(&'r mut self) -> &'r mut T { + unsafe { + if (*self.ptr).count > 1 { + self.cow_clone() + } else { + cast::copy_mut_lifetime(self, &mut (*self.ptr).value) + } + } + } + + #[inline(never)] + unsafe fn cow_clone<'r>(&'r mut self) -> &'r mut T { + (*self.ptr).count -= 1; + self.ptr = transmute(~RcBox{value: (*self.ptr).value.clone(), count: 1}); + cast::copy_mut_lifetime(self, &mut (*self.ptr).value) + } + + /// Clones the content if there is more than one reference, or unwraps + /// the data if this is the only reference + pub fn value<'r>(self) -> T { + unsafe { + if (*self.ptr).count > 1 { + (*self.ptr).value.clone() + } else { + let box: ~RcBox = transmute(self.ptr); + forget(self); + box.value + } + } + } } impl Clone for Rc { @@ -79,7 +143,7 @@ impl Clone for Rc { impl DeepClone for Rc { #[inline] fn deep_clone(&self) -> Rc { - unsafe { Rc::new_unchecked(self.borrow().deep_clone()) } + unsafe { Rc::new_unchecked(self.get().deep_clone()) } } } @@ -107,10 +171,10 @@ mod test_rc { unsafe { let x = Rc::new_unchecked(Cell::new(5)); let y = x.clone(); - do x.borrow().with_mut_ref |inner| { + do x.get().with_mut_ref |inner| { *inner = 20; } - assert_eq!(y.borrow().take(), 20); + assert_eq!(y.get().take(), 20); } } @@ -119,34 +183,43 @@ mod test_rc { unsafe { let x = Rc::new_unchecked(Cell::new(5)); let y = x.deep_clone(); - do x.borrow().with_mut_ref |inner| { + do x.get().with_mut_ref |inner| { *inner = 20; } - assert_eq!(y.borrow().take(), 5); + assert_eq!(y.get().take(), 5); } } #[test] fn test_simple() { let x = Rc::new(5); - assert_eq!(*x.borrow(), 5); + assert_eq!(*x.get(), 5); } #[test] fn test_simple_clone() { let x = Rc::new(5); let y = x.clone(); - assert_eq!(*x.borrow(), 5); - assert_eq!(*y.borrow(), 5); + assert_eq!(*x.get(), 5); + assert_eq!(*y.get(), 5); } #[test] fn test_destructor() { unsafe { let x = Rc::new_unchecked(~5); - assert_eq!(**x.borrow(), 5); + assert_eq!(**x.get(), 5); } } + + #[test] + fn test_mut() { + let mut x = Rc::from_freeze(5); + let y = x.clone(); + *x.cow() = 9; + assert_eq!(*x.get(), 9); + assert_eq!(*y.get(), 5); + } } #[deriving(Eq)] @@ -159,7 +232,7 @@ enum Borrow { struct RcMutBox { value: T, count: uint, - borrow: Borrow + get: Borrow } /// Mutable reference counted pointer type @@ -193,32 +266,32 @@ impl RcMut { /// poorly with managed pointers. #[inline] pub unsafe fn new_unchecked(value: T) -> RcMut { - RcMut{ptr: transmute(~RcMutBox{value: value, count: 1, borrow: Nothing})} + RcMut{ptr: transmute(~RcMutBox{value: value, count: 1, get: Nothing})} } } impl RcMut { - /// Fails if there is already a mutable borrow of the box + /// Fails if there is already a mutable get of the box #[inline] - pub fn with_borrow(&self, f: &fn(&T) -> U) -> U { + pub fn with_get(&self, f: &fn(&T) -> U) -> U { unsafe { - assert!((*self.ptr).borrow != Mutable); - let previous = (*self.ptr).borrow; - (*self.ptr).borrow = Immutable; + assert!((*self.ptr).get != Mutable); + let previous = (*self.ptr).get; + (*self.ptr).get = Immutable; let res = f(&(*self.ptr).value); - (*self.ptr).borrow = previous; + (*self.ptr).get = previous; res } } - /// Fails if there is already a mutable or immutable borrow of the box + /// Fails if there is already a mutable or immutable get of the box #[inline] - pub fn with_mut_borrow(&self, f: &fn(&mut T) -> U) -> U { + pub fn with_mut_get(&self, f: &fn(&mut T) -> U) -> U { unsafe { - assert_eq!((*self.ptr).borrow, Nothing); - (*self.ptr).borrow = Mutable; + assert_eq!((*self.ptr).get, Nothing); + (*self.ptr).get = Mutable; let res = f(&mut (*self.ptr).value); - (*self.ptr).borrow = Nothing; + (*self.ptr).get = Nothing; res } } @@ -253,7 +326,7 @@ impl DeepClone for RcMut { /// Return a deep copy of the reference counted pointer. #[inline] fn deep_clone(&self) -> RcMut { - do self.with_borrow |x| { + do self.with_get |x| { // FIXME: #6497: should avoid freeze (slow) unsafe { RcMut::new_unchecked(x.deep_clone()) } } @@ -268,10 +341,10 @@ mod test_rc_mut { fn test_clone() { let x = RcMut::from_send(5); let y = x.clone(); - do x.with_mut_borrow |value| { + do x.with_mut_get |value| { *value = 20; } - do y.with_borrow |value| { + do y.with_get |value| { assert_eq!(*value, 20); } } @@ -280,24 +353,24 @@ mod test_rc_mut { fn test_deep_clone() { let x = RcMut::new(5); let y = x.deep_clone(); - do x.with_mut_borrow |value| { + do x.with_mut_get |value| { *value = 20; } - do y.with_borrow |value| { + do y.with_get |value| { assert_eq!(*value, 5); } } #[test] - fn borrow_many() { + fn get_many() { let x = RcMut::from_send(5); let y = x.clone(); - do x.with_borrow |a| { + do x.with_get |a| { assert_eq!(*a, 5); - do y.with_borrow |b| { + do y.with_get |b| { assert_eq!(*b, 5); - do x.with_borrow |c| { + do x.with_get |c| { assert_eq!(*c, 5); } } @@ -309,12 +382,12 @@ mod test_rc_mut { let x = RcMut::new(5); let y = x.clone(); - do y.with_mut_borrow |a| { + do y.with_mut_get |a| { assert_eq!(*a, 5); *a = 6; } - do x.with_borrow |a| { + do x.with_get |a| { assert_eq!(*a, 6); } } @@ -322,15 +395,15 @@ mod test_rc_mut { #[test] fn release_immutable() { let x = RcMut::from_send(5); - do x.with_borrow |_| {} - do x.with_mut_borrow |_| {} + do x.with_get |_| {} + do x.with_mut_get |_| {} } #[test] fn release_mutable() { let x = RcMut::new(5); - do x.with_mut_borrow |_| {} - do x.with_borrow |_| {} + do x.with_mut_get |_| {} + do x.with_get |_| {} } #[test] @@ -339,8 +412,8 @@ mod test_rc_mut { let x = RcMut::from_send(5); let y = x.clone(); - do x.with_borrow |_| { - do y.with_mut_borrow |_| { + do x.with_get |_| { + do y.with_mut_get |_| { } } } @@ -351,8 +424,8 @@ mod test_rc_mut { let x = RcMut::new(5); let y = x.clone(); - do x.with_mut_borrow |_| { - do y.with_mut_borrow |_| { + do x.with_mut_get |_| { + do y.with_mut_get |_| { } } } @@ -363,8 +436,8 @@ mod test_rc_mut { let x = RcMut::from_send(5); let y = x.clone(); - do x.with_mut_borrow |_| { - do y.with_borrow |_| { + do x.with_mut_get |_| { + do y.with_get |_| { } } } @@ -375,9 +448,9 @@ mod test_rc_mut { let x = RcMut::new(5); let y = x.clone(); - do x.with_borrow |_| { - do x.with_borrow |_| {} - do y.with_mut_borrow |_| {} + do x.with_get |_| { + do x.with_get |_| {} + do y.with_mut_get |_| {} } } } diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index f3945d8f3c9d4..a9c0ac5e64e89 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -42,16 +42,23 @@ struct ArcData { data: Option, } -unsafe fn new_inner(data: T, refcount: uint) -> *mut ArcData { +unsafe fn new_inner(data: T, refcount: uint) -> *mut ArcData { let data = ~ArcData { count: AtomicUint::new(refcount), unwrapper: AtomicOption::empty(), data: Some(data) }; cast::transmute(data) } +impl UnsafeArc +{ + pub unsafe fn new_unsafe(data: T) -> UnsafeArc { + UnsafeArc { data: new_inner(data, 1) } + } +} + impl UnsafeArc { pub fn new(data: T) -> UnsafeArc { - unsafe { UnsafeArc { data: new_inner(data, 1) } } + unsafe { UnsafeArc::new_unsafe(data) } } /// As new(), but returns an extra pre-cloned handle. @@ -73,7 +80,9 @@ impl UnsafeArc { } } } +} +impl UnsafeArc { /// As newN(), but from an already-existing handle. Uses one xadd. pub fn cloneN(self, num_handles: uint) -> ~[UnsafeArc] { if num_handles == 0 { @@ -109,6 +118,17 @@ impl UnsafeArc { } } + /// Whether this is the only reference to the data + #[inline] + pub fn is_owned(&self) -> bool { + unsafe { + let mut data: ~ArcData = cast::transmute(self.data); + let r = data.count.load(Acquire) == 1 && data.unwrapper.is_empty(Acquire); + cast::forget(data); + return r; + } + } + /// Wait until all other handles are dropped, then retrieve the enclosed /// data. See extra::arc::Arc for specific semantics documentation. /// If called when the task is already unkillable, unwrap will unkillably @@ -207,7 +227,7 @@ impl UnsafeArc { } } -impl Clone for UnsafeArc { +impl Clone for UnsafeArc { fn clone(&self) -> UnsafeArc { unsafe { // This barrier might be unnecessary, but I'm not sure... @@ -559,6 +579,12 @@ mod tests { p.recv(); } + #[test] + fn arclike_new_should_be_owned() { + let x = UnsafeArc::new(~~"hello"); + assert!(x.is_owned()) + } + #[test] fn exclusive_new_unwrap_basic() { // Unlike the above, also tests no double-freeing of the LittleLock.