@@ -1439,6 +1439,50 @@ private final class DataTests {
14391439            #expect( data. count ==  0 ) 
14401440        } 
14411441    } 
1442+     
1443+     @Test func  validateMutation_cow_mutableBytes( )  { 
1444+         var  data  =  Data ( count:  32 ) 
1445+         holdReference ( data)  { 
1446+             var  bytes  =  data. mutableBytes
1447+             bytes. storeBytes ( of:  1 ,  toByteOffset:  0 ,  as:  UInt8 . self) 
1448+             
1449+             #expect( data [ 0 ]  ==  1 ) 
1450+             #expect( heldData ? [ 0 ]  ==  0 ) 
1451+         } 
1452+         
1453+         var  data2  =  Data ( count:  32 ) 
1454+         // Escape the pointer to compare after a mutation without dereferencing the pointer
1455+         let  originalPointer  =  data2. withUnsafeBytes  {  $0. baseAddress } 
1456+         
1457+         var  bytes  =  data2. mutableBytes
1458+         bytes. storeBytes ( of:  1 ,  toByteOffset:  0 ,  as:  UInt8 . self) 
1459+         #expect( data2 [ 0 ]  ==  1 ) 
1460+         data2. withUnsafeBytes  { 
1461+             #expect( $0. baseAddress ==  originalPointer) 
1462+         } 
1463+     } 
1464+     
1465+     @Test func  validateMutation_cow_mutableSpan( )  { 
1466+         var  data  =  Data ( count:  32 ) 
1467+         holdReference ( data)  { 
1468+             var  bytes  =  data. mutableSpan
1469+             bytes [ 0 ]  =  1 
1470+             
1471+             #expect( data [ 0 ]  ==  1 ) 
1472+             #expect( heldData ? [ 0 ]  ==  0 ) 
1473+         } 
1474+         
1475+         var  data2  =  Data ( count:  32 ) 
1476+         // Escape the pointer to compare after a mutation without dereferencing the pointer
1477+         let  originalPointer  =  data2. withUnsafeBytes  {  $0. baseAddress } 
1478+         
1479+         var  bytes  =  data2. mutableSpan
1480+         bytes [ 0 ]  =  1 
1481+         #expect( data2 [ 0 ]  ==  1 ) 
1482+         data2. withUnsafeBytes  { 
1483+             #expect( $0. baseAddress ==  originalPointer) 
1484+         } 
1485+     } 
14421486
14431487    @Test func  sliceHash( )  { 
14441488        let  base1  =  Data ( [ 0 ,  0xFF ,  0xFF ,  0 ] ) 
@@ -2505,17 +2549,16 @@ extension DataTests {
25052549// These tests require allocating an extremely large amount of data and are serialized to prevent the test runner from using all available memory at once
25062550@Suite( " Large Data Tests " ,  . serialized) 
25072551struct  LargeDataTests { 
2508-     @Test  
2509-     func  largeSliceDataSpan( )  throws  { 
25102552#if _pointerBitWidth(_64) 
2511-          let  count  =  Int ( Int32 . max) 
2553+     let  largeCount  =  Int ( Int32 . max) 
25122554#elseif _pointerBitWidth(_32) 
2513-          let  count  =  Int ( Int16 . max) 
2555+     let  largeCount  =  Int ( Int16 . max) 
25142556#else 
25152557#error("This test needs updating") 
25162558#endif 
2517-         
2518-         let  source  =  Data ( repeating:  0 ,  count:  count) . dropFirst ( ) 
2559+     @Test  
2560+     func  largeSliceDataSpan( )  throws  { 
2561+         let  source  =  Data ( repeating:  0 ,  count:  largeCount) . dropFirst ( ) 
25192562        #expect( source. startIndex !=  0 ) 
25202563        let  span  =  source. span
25212564        let  isEmpty  =  span. isEmpty
@@ -2524,20 +2567,11 @@ struct LargeDataTests {
25242567
25252568    @Test  
25262569    func  largeSliceDataMutableSpan( )  throws  { 
2527- #if _pointerBitWidth(_64) 
2528-         var  count  =  Int ( Int32 . max) 
2529- #elseif _pointerBitWidth(_32) 
2530-         var  count  =  Int ( Int16 . max) 
2531- #else 
2532- #error("This test needs updating") 
2533- #endif 
2534-         
25352570#if !canImport(Darwin) || FOUNDATION_FRAMEWORK 
2536-         var  source  =  Data ( repeating:  0 ,  count:  count ) . dropFirst ( ) 
2571+         var  source  =  Data ( repeating:  0 ,  count:  largeCount ) . dropFirst ( ) 
25372572        #expect( source. startIndex !=  0 ) 
2538-         count =  source. count
25392573        var  span  =  source. mutableSpan
2540-         #expect( span. count ==  count ) 
2574+         #expect( span. count ==  largeCount  -   1 ) 
25412575        let  i  =  try   #require( span. indices. dropFirst ( ) . randomElement ( ) ) 
25422576        span [ i]  =  . max
25432577        #expect( source [ i]  ==  0 ) 
@@ -2547,23 +2581,62 @@ struct LargeDataTests {
25472581
25482582    @Test  
25492583    func  largeSliceDataMutableRawSpan( )  throws  { 
2550- #if _pointerBitWidth(_64) 
2551-         var  count  =  Int ( Int32 . max) 
2552- #elseif _pointerBitWidth(_32) 
2553-         var  count  =  Int ( Int16 . max) 
2554- #else 
2555- #error("This test needs updating") 
2556- #endif 
2557-         
2558-         var  source  =  Data ( repeating:  0 ,  count:  count) . dropFirst ( ) 
2584+         var  source  =  Data ( repeating:  0 ,  count:  largeCount) . dropFirst ( ) 
25592585        #expect( source. startIndex !=  0 ) 
2560-         count =  source. count
25612586        var  span  =  source. mutableBytes
25622587        let  byteCount  =  span. byteCount
2563-         #expect( byteCount ==  count ) 
2588+         #expect( byteCount ==  largeCount  -   1 ) 
25642589        let  i  =  try   #require( span. byteOffsets. dropFirst ( ) . randomElement ( ) ) 
25652590        span. storeBytes ( of:  - 1 ,  toByteOffset:  i,  as:  Int8 . self) 
25662591        #expect( source [ i]  ==  0 ) 
25672592        #expect( source [ i+ 1 ]  ==  . max) 
25682593    } 
2594+     
2595+     @Test   func  validateMutation_cow_largeMutableBytes( )  { 
2596+         // Avoid copying a large data on platforms with constrained memory limits
2597+         #if !canImport(Darwin) || os(macOS) 
2598+         var  data  =  Data ( count:  largeCount) 
2599+         let  heldData  =  data
2600+         var  bytes  =  data. mutableBytes
2601+         bytes. storeBytes ( of:  1 ,  toByteOffset:  0 ,  as:  UInt8 . self) 
2602+         
2603+         #expect( data [ 0 ]  ==  1 ) 
2604+         #expect( heldData [ 0 ]  ==  0 ) 
2605+         #endif 
2606+         
2607+         var  data2  =  Data ( count:  largeCount) 
2608+         // Escape the pointer to compare after a mutation without dereferencing the pointer
2609+         let  originalPointer  =  data2. withUnsafeBytes  {  $0. baseAddress } 
2610+         
2611+         var  bytes2  =  data2. mutableBytes
2612+         bytes2. storeBytes ( of:  1 ,  toByteOffset:  0 ,  as:  UInt8 . self) 
2613+         #expect( data2 [ 0 ]  ==  1 ) 
2614+         data2. withUnsafeBytes  { 
2615+             #expect( $0. baseAddress ==  originalPointer) 
2616+         } 
2617+     } 
2618+     
2619+     @Test   func  validateMutation_cow_largeMutableSpan( )  { 
2620+         // Avoid copying a large data on platforms with constrained memory limits
2621+         #if !canImport(Darwin) || os(macOS) 
2622+         var  data  =  Data ( count:  largeCount) 
2623+         let  heldData  =  data
2624+         var  bytes  =  data. mutableSpan
2625+         bytes [ 0 ]  =  1 
2626+         
2627+         #expect( data [ 0 ]  ==  1 ) 
2628+         #expect( heldData [ 0 ]  ==  0 ) 
2629+         #endif 
2630+         
2631+         var  data2  =  Data ( count:  largeCount) 
2632+         // Escape the pointer to compare after a mutation without dereferencing the pointer
2633+         let  originalPointer  =  data2. withUnsafeBytes  {  $0. baseAddress } 
2634+         
2635+         var  bytes2  =  data2. mutableSpan
2636+         bytes2 [ 0 ]  =  1 
2637+         #expect( data2 [ 0 ]  ==  1 ) 
2638+         data2. withUnsafeBytes  { 
2639+             #expect( $0. baseAddress ==  originalPointer) 
2640+         } 
2641+     } 
25692642} 
0 commit comments