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