@@ -1415,65 +1415,6 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
1415
1415
}
1416
1416
}
1417
1417
1418
- @inlinable
1419
- @_alwaysEmitIntoClient
1420
- internal mutating func _truncateOrZeroExtend( toCount newCount: Int ) {
1421
- switch self {
1422
- case . empty:
1423
- if newCount == 0 {
1424
- return
1425
- } else if InlineData . canStore ( count: newCount) {
1426
- self = . inline( InlineData ( count: newCount) )
1427
- } else if InlineSlice . canStore ( count: newCount) {
1428
- self = . slice( InlineSlice ( count: newCount) )
1429
- } else {
1430
- self = . large( LargeSlice ( count: newCount) )
1431
- }
1432
- case . inline( var inline) :
1433
- if newCount == 0 {
1434
- self = . empty
1435
- } else if InlineData . canStore ( count: newCount) {
1436
- guard inline. count != newCount else { return }
1437
- inline. count = newCount
1438
- self = . inline( inline)
1439
- } else if InlineSlice . canStore ( count: newCount) {
1440
- var slice = InlineSlice ( inline)
1441
- slice. count = newCount
1442
- self = . slice( slice)
1443
- } else {
1444
- var slice = LargeSlice ( inline)
1445
- slice. count = newCount
1446
- self = . large( slice)
1447
- }
1448
- case . slice( var slice) :
1449
- if newCount == 0 && slice. startIndex == 0 {
1450
- self = . empty
1451
- } else if slice. startIndex == 0 && InlineData . canStore ( count: newCount) {
1452
- self = . inline( InlineData ( slice, count: newCount) )
1453
- } else if InlineSlice . canStore ( count: newCount + slice. startIndex) {
1454
- guard slice. count != newCount else { return }
1455
- self = . empty // TODO: remove this when mgottesman lands optimizations
1456
- slice. count = newCount
1457
- self = . slice( slice)
1458
- } else {
1459
- var newSlice = LargeSlice ( slice)
1460
- newSlice. count = newCount
1461
- self = . large( newSlice)
1462
- }
1463
- case . large( var slice) :
1464
- if newCount == 0 && slice. startIndex == 0 {
1465
- self = . empty
1466
- } else if slice. startIndex == 0 && InlineData . canStore ( count: newCount) {
1467
- self = . inline( InlineData ( slice, count: newCount) )
1468
- } else {
1469
- guard slice. count != newCount else { return }
1470
- self = . empty // TODO: remove this when mgottesman lands optimizations
1471
- slice. count = newCount
1472
- self = . large( slice)
1473
- }
1474
- }
1475
- }
1476
-
1477
1418
@inlinable // This is @inlinable as reasonably small.
1478
1419
var count : Int {
1479
1420
get {
@@ -1485,7 +1426,69 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
1485
1426
}
1486
1427
}
1487
1428
set ( newValue) {
1488
- _truncateOrZeroExtend ( toCount: newValue)
1429
+ // HACK: The definition of this inline function takes an inout reference to self, giving the optimizer a unique referencing guarantee.
1430
+ // This allows us to avoid excessive retain-release traffic around modifying enum values, and inlining the function then avoids the additional frame.
1431
+ @inline ( __always)
1432
+ func apply( _ representation: inout _Representation , _ newValue: Int ) -> _Representation ? {
1433
+ switch representation {
1434
+ case . empty:
1435
+ if newValue == 0 {
1436
+ return nil
1437
+ } else if InlineData . canStore ( count: newValue) {
1438
+ return . inline( InlineData ( count: newValue) )
1439
+ } else if InlineSlice . canStore ( count: newValue) {
1440
+ return . slice( InlineSlice ( count: newValue) )
1441
+ } else {
1442
+ return . large( LargeSlice ( count: newValue) )
1443
+ }
1444
+ case . inline( var inline) :
1445
+ if newValue == 0 {
1446
+ return . empty
1447
+ } else if InlineData . canStore ( count: newValue) {
1448
+ guard inline. count != newValue else { return nil }
1449
+ inline. count = newValue
1450
+ return . inline( inline)
1451
+ } else if InlineSlice . canStore ( count: newValue) {
1452
+ var slice = InlineSlice ( inline)
1453
+ slice. count = newValue
1454
+ return . slice( slice)
1455
+ } else {
1456
+ var slice = LargeSlice ( inline)
1457
+ slice. count = newValue
1458
+ return . large( slice)
1459
+ }
1460
+ case . slice( var slice) :
1461
+ if newValue == 0 && slice. startIndex == 0 {
1462
+ return . empty
1463
+ } else if slice. startIndex == 0 && InlineData . canStore ( count: newValue) {
1464
+ return . inline( InlineData ( slice, count: newValue) )
1465
+ } else if InlineSlice . canStore ( count: newValue + slice. startIndex) {
1466
+ guard slice. count != newValue else { return nil }
1467
+ representation = . empty // TODO: remove this when mgottesman lands optimizations
1468
+ slice. count = newValue
1469
+ return . slice( slice)
1470
+ } else {
1471
+ var newSlice = LargeSlice ( slice)
1472
+ newSlice. count = newValue
1473
+ return . large( newSlice)
1474
+ }
1475
+ case . large( var slice) :
1476
+ if newValue == 0 && slice. startIndex == 0 {
1477
+ return . empty
1478
+ } else if slice. startIndex == 0 && InlineData . canStore ( count: newValue) {
1479
+ return . inline( InlineData ( slice, count: newValue) )
1480
+ } else {
1481
+ guard slice. count != newValue else { return nil }
1482
+ representation = . empty // TODO: remove this when mgottesman lands optimizations
1483
+ slice. count = newValue
1484
+ return . large( slice)
1485
+ }
1486
+ }
1487
+ }
1488
+
1489
+ if let rep = apply ( & self , newValue) {
1490
+ self = rep
1491
+ }
1489
1492
}
1490
1493
}
1491
1494
@@ -2385,16 +2388,17 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
2385
2388
// Copy as much as we can in one shot.
2386
2389
let underestimatedCount = elements. underestimatedCount
2387
2390
let originalCount = _representation. count
2388
- _representation . _truncateOrZeroExtend ( toCount : originalCount + underestimatedCount)
2391
+ resetBytes ( in : self . endIndex ..< self . endIndex + underestimatedCount)
2389
2392
var ( iter, copiedCount) : ( S . Iterator , Int ) = _representation. withUnsafeMutableBytes { buffer in
2393
+ assert ( buffer. count == originalCount + underestimatedCount)
2390
2394
let start = buffer. baseAddress!. assumingMemoryBound ( to: UInt8 . self) + originalCount
2391
2395
let b = UnsafeMutableBufferPointer ( start: start, count: buffer. count - originalCount)
2392
2396
return elements. _copyContents ( initializing: b)
2393
2397
}
2394
2398
guard copiedCount == underestimatedCount else {
2395
2399
// We can't trap here. We have to allow an underfilled buffer
2396
2400
// to emulate the previous implementation.
2397
- _representation. _truncateOrZeroExtend ( toCount : originalCount + copiedCount)
2401
+ _representation. replaceSubrange ( startIndex + originalCount + copiedCount ..< endIndex , with : nil , count : 0 )
2398
2402
return
2399
2403
}
2400
2404
0 commit comments