@@ -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 ( 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+ }
9661074}
0 commit comments