@@ -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 ] )
@@ -2385,17 +2429,16 @@ extension DataTests {
23852429// 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
23862430@Suite( " Large Data Tests " , . serialized)
23872431struct LargeDataTests {
2388- @Test
2389- func largeSliceDataSpan( ) throws {
23902432#if _pointerBitWidth(_64)
2391- let count = Int ( Int32 . max)
2433+ let largeCount = Int ( Int32 . max)
23922434#elseif _pointerBitWidth(_32)
2393- let count = Int ( Int16 . max)
2435+ let largeCount = Int ( Int16 . max)
23942436#else
23952437#error("This test needs updating")
23962438#endif
2397-
2398- let source = Data ( repeating: 0 , count: count) . dropFirst ( )
2439+ @Test
2440+ func largeSliceDataSpan( ) throws {
2441+ let source = Data ( repeating: 0 , count: largeCount) . dropFirst ( )
23992442 #expect( source. startIndex != 0 )
24002443 let span = source. span
24012444 let isEmpty = span. isEmpty
@@ -2404,20 +2447,11 @@ struct LargeDataTests {
24042447
24052448 @Test
24062449 func largeSliceDataMutableSpan( ) throws {
2407- #if _pointerBitWidth(_64)
2408- var count = Int ( Int32 . max)
2409- #elseif _pointerBitWidth(_32)
2410- var count = Int ( Int16 . max)
2411- #else
2412- #error("This test needs updating")
2413- #endif
2414-
24152450#if !canImport(Darwin) || FOUNDATION_FRAMEWORK
2416- var source = Data ( repeating: 0 , count: count ) . dropFirst ( )
2451+ var source = Data ( repeating: 0 , count: largeCount ) . dropFirst ( )
24172452 #expect( source. startIndex != 0 )
2418- count = source. count
24192453 var span = source. mutableSpan
2420- #expect( span. count == count )
2454+ #expect( span. count == largeCount - 1 )
24212455 let i = try #require( span. indices. dropFirst ( ) . randomElement ( ) )
24222456 span [ i] = . max
24232457 #expect( source [ i] == 0 )
@@ -2427,23 +2461,62 @@ struct LargeDataTests {
24272461
24282462 @Test
24292463 func largeSliceDataMutableRawSpan( ) throws {
2430- #if _pointerBitWidth(_64)
2431- var count = Int ( Int32 . max)
2432- #elseif _pointerBitWidth(_32)
2433- var count = Int ( Int16 . max)
2434- #else
2435- #error("This test needs updating")
2436- #endif
2437-
2438- var source = Data ( repeating: 0 , count: count) . dropFirst ( )
2464+ var source = Data ( repeating: 0 , count: largeCount) . dropFirst ( )
24392465 #expect( source. startIndex != 0 )
2440- count = source. count
24412466 var span = source. mutableBytes
24422467 let byteCount = span. byteCount
2443- #expect( byteCount == count )
2468+ #expect( byteCount == largeCount - 1 )
24442469 let i = try #require( span. byteOffsets. dropFirst ( ) . randomElement ( ) )
24452470 span. storeBytes ( of: - 1 , toByteOffset: i, as: Int8 . self)
24462471 #expect( source [ i] == 0 )
24472472 #expect( source [ i+ 1 ] == . max)
24482473 }
2474+
2475+ @Test func validateMutation_cow_largeMutableBytes( ) {
2476+ // Avoid copying a large data on platforms with constrained memory limits
2477+ #if !canImport(Darwin) || os(macOS)
2478+ var data = Data ( count: largeCount)
2479+ let heldData = data
2480+ var bytes = data. mutableBytes
2481+ bytes. storeBytes ( of: 1 , toByteOffset: 0 , as: UInt8 . self)
2482+
2483+ #expect( data [ 0 ] == 1 )
2484+ #expect( heldData [ 0 ] == 0 )
2485+ #endif
2486+
2487+ var data2 = Data ( count: largeCount)
2488+ // Escape the pointer to compare after a mutation without dereferencing the pointer
2489+ let originalPointer = data2. withUnsafeBytes { $0. baseAddress }
2490+
2491+ var bytes2 = data2. mutableBytes
2492+ bytes2. storeBytes ( of: 1 , toByteOffset: 0 , as: UInt8 . self)
2493+ #expect( data2 [ 0 ] == 1 )
2494+ data2. withUnsafeBytes {
2495+ #expect( $0. baseAddress == originalPointer)
2496+ }
2497+ }
2498+
2499+ @Test func validateMutation_cow_largeMutableSpan( ) {
2500+ // Avoid copying a large data on platforms with constrained memory limits
2501+ #if !canImport(Darwin) || os(macOS)
2502+ var data = Data ( count: largeCount)
2503+ let heldData = data
2504+ var bytes = data. mutableSpan
2505+ bytes [ 0 ] = 1
2506+
2507+ #expect( data [ 0 ] == 1 )
2508+ #expect( heldData [ 0 ] == 0 )
2509+ #endif
2510+
2511+ var data2 = Data ( count: largeCount)
2512+ // Escape the pointer to compare after a mutation without dereferencing the pointer
2513+ let originalPointer = data2. withUnsafeBytes { $0. baseAddress }
2514+
2515+ var bytes2 = data2. mutableSpan
2516+ bytes2 [ 0 ] = 1
2517+ #expect( data2 [ 0 ] == 1 )
2518+ data2. withUnsafeBytes {
2519+ #expect( $0. baseAddress == originalPointer)
2520+ }
2521+ }
24492522}
0 commit comments