Skip to content

Commit 14b679f

Browse files
committed
---
yaml --- r: 107978 b: refs/heads/dist-snap c: 28f277b h: refs/heads/master v: v3
1 parent 4e90191 commit 14b679f

File tree

3 files changed

+117
-1
lines changed

3 files changed

+117
-1
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ refs/heads/try: f64fdf524a434f0e5cd0bc91d09c144723f3c90d
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: 147ecfdd8221e4a4d4e090486829a06da1e0ca3c
9-
refs/heads/dist-snap: 01815b392058dbf862f4287be307821cf00cc964
9+
refs/heads/dist-snap: 28f277b909bf24728593710a952c65193cfbefe4
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503
1212
refs/heads/try3: 9387340aab40a73e8424c48fd42f0c521a4875c0

branches/dist-snap/src/libextra/arc.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,50 @@ impl<'a, T:Freeze + Send> RWReadMode<'a, T> {
554554
}
555555
}
556556

557+
/****************************************************************************
558+
* Copy-on-write Arc
559+
****************************************************************************/
560+
561+
pub struct CowArc<T> { priv x: UnsafeArc<T> }
562+
563+
/// A Copy-on-write Arc functions the same way as an `arc` except it allows
564+
/// mutation of the contents if there is only a single reference to
565+
/// the data. If there are multiple references the data is automatically
566+
/// cloned and the task modifies the cloned data in place of the shared data.
567+
impl<T:Clone+Send+Freeze> CowArc<T> {
568+
/// Create a copy-on-write atomically reference counted wrapper
569+
#[inline]
570+
pub fn new(data: T) -> CowArc<T> {
571+
CowArc { x: UnsafeArc::new(data) }
572+
}
573+
574+
#[inline]
575+
pub fn get<'a>(&'a self) -> &'a T {
576+
unsafe { &*self.x.get_immut() }
577+
}
578+
579+
/// get a mutable reference to the contents. If there are more then one
580+
/// reference to the contents of the `CowArc` will be cloned
581+
/// and this reference updated to point to the cloned data.
582+
#[inline]
583+
pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
584+
if !self.x.is_owned() {
585+
*self = CowArc::new(self.get().clone())
586+
}
587+
unsafe { &mut *self.x.get() }
588+
}
589+
}
590+
591+
impl<T:Clone+Send+Freeze> Clone for CowArc<T> {
592+
/// Duplicate a Copy-on-write Arc. See arc::clone for more details.
593+
#[inline]
594+
fn clone(&self) -> CowArc<T> {
595+
CowArc { x: self.x.clone() }
596+
}
597+
}
598+
599+
600+
557601
/****************************************************************************
558602
* Tests
559603
****************************************************************************/
@@ -963,4 +1007,68 @@ mod tests {
9631007
// and I wasn't sure why :( . This is a mediocre "next best" option.
9641008
for _ in range(0, 8) { test_rw_write_cond_downgrade_read_race_helper(); }
9651009
}
1010+
1011+
#[test]
1012+
fn test_cowarc_clone()
1013+
{
1014+
let cow0 = CowArc::new(75u);
1015+
let cow1 = cow0.clone();
1016+
let cow2 = cow1.clone();
1017+
1018+
assert!(75 == *cow0.get());
1019+
assert!(75 == *cow1.get());
1020+
assert!(75 == *cow2.get());
1021+
1022+
assert!(cow0.get() == cow1.get());
1023+
assert!(cow0.get() == cow2.get());
1024+
}
1025+
1026+
#[test]
1027+
fn test_cowarc_clone_get_mut()
1028+
{
1029+
let mut cow0 = CowArc::new(75u);
1030+
let mut cow1 = cow0.clone();
1031+
let mut cow2 = cow1.clone();
1032+
1033+
assert!(75 == *cow0.get_mut());
1034+
assert!(75 == *cow1.get_mut());
1035+
assert!(75 == *cow2.get_mut());
1036+
1037+
*cow0.get_mut() += 1;
1038+
*cow1.get_mut() += 2;
1039+
*cow2.get_mut() += 3;
1040+
1041+
assert!(76 == *cow0.get());
1042+
assert!(77 == *cow1.get());
1043+
assert!(78 == *cow2.get());
1044+
1045+
// none should point to the same backing memory
1046+
assert!(cow0.get() != cow1.get());
1047+
assert!(cow0.get() != cow2.get());
1048+
assert!(cow1.get() != cow2.get());
1049+
}
1050+
1051+
#[test]
1052+
fn test_cowarc_clone_get_mut2()
1053+
{
1054+
let mut cow0 = CowArc::new(75u);
1055+
let cow1 = cow0.clone();
1056+
let cow2 = cow1.clone();
1057+
1058+
assert!(75 == *cow0.get());
1059+
assert!(75 == *cow1.get());
1060+
assert!(75 == *cow2.get());
1061+
1062+
*cow0.get_mut() += 1;
1063+
1064+
assert!(76 == *cow0.get());
1065+
assert!(75 == *cow1.get());
1066+
assert!(75 == *cow2.get());
1067+
1068+
// cow1 and cow2 should share the same contents
1069+
// cow0 should have a unique reference
1070+
assert!(cow0.get() != cow1.get());
1071+
assert!(cow0.get() != cow2.get());
1072+
assert!(cow1.get() == cow2.get());
1073+
}
9661074
}

branches/dist-snap/src/libstd/sync/arc.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ impl<T: Send> UnsafeArc<T> {
9494
return &(*self.data).data as *T;
9595
}
9696
}
97+
98+
/// checks if this is the only reference to the arc protected data
99+
#[inline]
100+
pub fn is_owned(&self) -> bool {
101+
unsafe {
102+
(*self.data).count.load(Relaxed) == 1
103+
}
104+
}
97105
}
98106

99107
impl<T: Send> Clone for UnsafeArc<T> {

0 commit comments

Comments
 (0)