@@ -1439,6 +1439,50 @@ private final class DataTests {
1439
1439
#expect( data. count == 0 )
1440
1440
}
1441
1441
}
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
+ }
1442
1486
1443
1487
@Test func sliceHash( ) {
1444
1488
let base1 = Data ( [ 0 , 0xFF , 0xFF , 0 ] )
@@ -2505,17 +2549,16 @@ extension DataTests {
2505
2549
// 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
2506
2550
@Suite( " Large Data Tests " , . serialized)
2507
2551
struct LargeDataTests {
2508
- @Test
2509
- func largeSliceDataSpan( ) throws {
2510
2552
#if _pointerBitWidth(_64)
2511
- let count = Int ( Int32 . max)
2553
+ let largeCount = Int ( Int32 . max)
2512
2554
#elseif _pointerBitWidth(_32)
2513
- let count = Int ( Int16 . max)
2555
+ let largeCount = Int ( Int16 . max)
2514
2556
#else
2515
2557
#error("This test needs updating")
2516
2558
#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 ( )
2519
2562
#expect( source. startIndex != 0 )
2520
2563
let span = source. span
2521
2564
let isEmpty = span. isEmpty
@@ -2524,20 +2567,11 @@ struct LargeDataTests {
2524
2567
2525
2568
@Test
2526
2569
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
-
2535
2570
#if !canImport(Darwin) || FOUNDATION_FRAMEWORK
2536
- var source = Data ( repeating: 0 , count: count ) . dropFirst ( )
2571
+ var source = Data ( repeating: 0 , count: largeCount ) . dropFirst ( )
2537
2572
#expect( source. startIndex != 0 )
2538
- count = source. count
2539
2573
var span = source. mutableSpan
2540
- #expect( span. count == count )
2574
+ #expect( span. count == largeCount - 1 )
2541
2575
let i = try #require( span. indices. dropFirst ( ) . randomElement ( ) )
2542
2576
span [ i] = . max
2543
2577
#expect( source [ i] == 0 )
@@ -2547,23 +2581,62 @@ struct LargeDataTests {
2547
2581
2548
2582
@Test
2549
2583
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 ( )
2559
2585
#expect( source. startIndex != 0 )
2560
- count = source. count
2561
2586
var span = source. mutableBytes
2562
2587
let byteCount = span. byteCount
2563
- #expect( byteCount == count )
2588
+ #expect( byteCount == largeCount - 1 )
2564
2589
let i = try #require( span. byteOffsets. dropFirst ( ) . randomElement ( ) )
2565
2590
span. storeBytes ( of: - 1 , toByteOffset: i, as: Int8 . self)
2566
2591
#expect( source [ i] == 0 )
2567
2592
#expect( source [ i+ 1 ] == . max)
2568
2593
}
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
+ }
2569
2642
}
0 commit comments