@@ -554,6 +554,50 @@ impl<'a, T:Freeze + Send> RWReadMode<'a, T> {
554
554
}
555
555
}
556
556
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
+
557
601
/****************************************************************************
558
602
* Tests
559
603
****************************************************************************/
@@ -963,4 +1007,68 @@ mod tests {
963
1007
// and I wasn't sure why :( . This is a mediocre "next best" option.
964
1008
for _ in range ( 0 , 8 ) { test_rw_write_cond_downgrade_read_race_helper ( ) ; }
965
1009
}
1010
+
1011
+ #[ test]
1012
+ fn test_cowarc_clone ( )
1013
+ {
1014
+ let cow0 = CowArc :: new ( 75 u) ;
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 ( 75 u) ;
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 ( 75 u) ;
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
+ }
966
1074
}
0 commit comments