@@ -346,7 +346,8 @@ extension Array {
346
346
@_semantics ( " array.make_mutable " )
347
347
internal mutating func _makeMutableAndUnique( ) {
348
348
if _slowPath ( !_buffer. isMutableAndUniquelyReferenced ( ) ) {
349
- _buffer = _Buffer ( copying: _buffer)
349
+ _createNewBuffer ( bufferIsUnique: false , minimumCapacity: count,
350
+ growForAppend: false )
350
351
}
351
352
}
352
353
@@ -1023,19 +1024,65 @@ extension Array: RangeReplaceableCollection {
1023
1024
@inlinable
1024
1025
@_semantics ( " array.mutate_unknown " )
1025
1026
public mutating func reserveCapacity( _ minimumCapacity: Int ) {
1026
- if _buffer. requestUniqueMutableBackingBuffer (
1027
- minimumCapacity: minimumCapacity) == nil {
1027
+ _reserveCapacityImpl ( minimumCapacity: minimumCapacity,
1028
+ growForAppend: false )
1029
+ }
1030
+
1031
+ /// Reserves enough space to store `minimumCapacity` elements.
1032
+ /// If a new buffer needs to be allocated and `growForAppend` is true,
1033
+ /// the new capacity is calculated using `_growArrayCapacity`, but at least
1034
+ /// kept at `minimumCapacity`.
1035
+ @_alwaysEmitIntoClient
1036
+ internal mutating func _reserveCapacityImpl(
1037
+ minimumCapacity: Int , growForAppend: Bool
1038
+ ) {
1039
+ let isUnique = _buffer. isUniquelyReferenced ( )
1040
+ if _slowPath ( !isUnique || _getCapacity ( ) < minimumCapacity) {
1041
+ _createNewBuffer ( bufferIsUnique: isUnique,
1042
+ minimumCapacity: Swift . max ( minimumCapacity, count) ,
1043
+ growForAppend: growForAppend)
1044
+ }
1045
+ _internalInvariant ( capacity >= minimumCapacity)
1046
+ _internalInvariant ( capacity == 0 || _buffer. isUniquelyReferenced ( ) )
1047
+ }
1028
1048
1029
- let newBuffer = _ContiguousArrayBuffer < Element > (
1030
- _uninitializedCount: count, minimumCapacity: minimumCapacity)
1049
+ /// Creates a new buffer, replacing the current buffer.
1050
+ ///
1051
+ /// If `bufferIsUnique` is true, the buffer is assumed to be uniquely
1052
+ /// referenced by this array and the elements are moved - instead of copied -
1053
+ /// to the new buffer.
1054
+ /// The `minimumCapacity` is the lower bound for the new capacity.
1055
+ /// If `growForAppend` is true, the new capacity is calculated using
1056
+ /// `_growArrayCapacity`, but at least kept at `minimumCapacity`.
1057
+ @_alwaysEmitIntoClient
1058
+ @inline ( never)
1059
+ internal mutating func _createNewBuffer(
1060
+ bufferIsUnique: Bool , minimumCapacity: Int , growForAppend: Bool
1061
+ ) {
1062
+ let newCapacity = _growArrayCapacity ( oldCapacity: _getCapacity ( ) ,
1063
+ minimumCapacity: minimumCapacity,
1064
+ growForAppend: growForAppend)
1065
+ let count = _getCount ( )
1066
+ _internalInvariant ( newCapacity >= count)
1067
+
1068
+ let newBuffer = _ContiguousArrayBuffer < Element > (
1069
+ _uninitializedCount: count, minimumCapacity: newCapacity)
1031
1070
1071
+ if bufferIsUnique {
1072
+ _internalInvariant ( _buffer. isUniquelyReferenced ( ) )
1073
+
1074
+ // As an optimization, if the original buffer is unique, we can just move
1075
+ // the elements instead of copying.
1076
+ let dest = newBuffer. firstElementAddress
1077
+ dest. moveInitialize ( from: _buffer. firstElementAddress,
1078
+ count: count)
1079
+ _buffer. count = 0
1080
+ } else {
1032
1081
_buffer. _copyContents (
1033
- subRange: _buffer . indices ,
1082
+ subRange: 0 ..< count ,
1034
1083
initializing: newBuffer. firstElementAddress)
1035
- _buffer = _Buffer (
1036
- _buffer: newBuffer, shiftedToStartIndex: _buffer. startIndex)
1037
1084
}
1038
- _internalInvariant ( capacity >= minimumCapacity )
1085
+ _buffer = _Buffer ( _buffer : newBuffer , shiftedToStartIndex : 0 )
1039
1086
}
1040
1087
1041
1088
/// Copy the contents of the current buffer to a new unique mutable buffer.
@@ -1054,7 +1101,9 @@ extension Array: RangeReplaceableCollection {
1054
1101
@_semantics ( " array.make_mutable " )
1055
1102
internal mutating func _makeUniqueAndReserveCapacityIfNotUnique( ) {
1056
1103
if _slowPath ( !_buffer. isMutableAndUniquelyReferenced ( ) ) {
1057
- _copyToNewBuffer ( oldCount: _buffer. count)
1104
+ _createNewBuffer ( bufferIsUnique: false ,
1105
+ minimumCapacity: count + 1 ,
1106
+ growForAppend: true )
1058
1107
}
1059
1108
}
1060
1109
@@ -1083,7 +1132,9 @@ extension Array: RangeReplaceableCollection {
1083
1132
_buffer. isMutableAndUniquelyReferenced ( ) )
1084
1133
1085
1134
if _slowPath ( oldCount + 1 > _buffer. capacity) {
1086
- _copyToNewBuffer ( oldCount: oldCount)
1135
+ _createNewBuffer ( bufferIsUnique: true ,
1136
+ minimumCapacity: oldCount + 1 ,
1137
+ growForAppend: true )
1087
1138
}
1088
1139
}
1089
1140
@@ -1124,6 +1175,8 @@ extension Array: RangeReplaceableCollection {
1124
1175
@inlinable
1125
1176
@_semantics ( " array.append_element " )
1126
1177
public mutating func append( _ newElement: __owned Element) {
1178
+ // Separating uniqueness check and capacity check allows hoisting the
1179
+ // uniqueness check out of a loop.
1127
1180
_makeUniqueAndReserveCapacityIfNotUnique ( )
1128
1181
let oldCount = _getCount ( )
1129
1182
_reserveCapacityAssumingUniqueBuffer ( oldCount: oldCount)
@@ -1160,7 +1213,7 @@ extension Array: RangeReplaceableCollection {
1160
1213
start: startNewElements,
1161
1214
count: self . capacity - oldCount)
1162
1215
1163
- let ( remainder, writtenUpTo) = buf. initialize ( from: newElements)
1216
+ var ( remainder, writtenUpTo) = buf. initialize ( from: newElements)
1164
1217
1165
1218
// trap on underflow from the sequence's underestimate:
1166
1219
let writtenCount = buf. distance ( from: buf. startIndex, to: writtenUpTo)
@@ -1176,30 +1229,39 @@ extension Array: RangeReplaceableCollection {
1176
1229
if writtenUpTo == buf. endIndex {
1177
1230
// there may be elements that didn't fit in the existing buffer,
1178
1231
// append them in slow sequence-only mode
1179
- _buffer. _arrayAppendSequence ( IteratorSequence ( remainder) )
1232
+ var newCount = _getCount ( )
1233
+ var nextItem = remainder. next ( )
1234
+ while nextItem != nil {
1235
+ reserveCapacityForAppend ( newElementsCount: 1 )
1236
+
1237
+ let currentCapacity = _getCapacity ( )
1238
+ let base = _buffer. firstElementAddress
1239
+
1240
+ // fill while there is another item and spare capacity
1241
+ while let next = nextItem, newCount < currentCapacity {
1242
+ ( base + newCount) . initialize ( to: next)
1243
+ newCount += 1
1244
+ nextItem = remainder. next ( )
1245
+ }
1246
+ _buffer. count = newCount
1247
+ }
1180
1248
}
1181
1249
}
1182
1250
1183
1251
@inlinable
1184
1252
@_semantics ( " array.reserve_capacity_for_append " )
1185
1253
internal mutating func reserveCapacityForAppend( newElementsCount: Int ) {
1186
- let oldCount = self . count
1187
- let oldCapacity = self . capacity
1188
- let newCount = oldCount + newElementsCount
1189
-
1190
1254
// Ensure uniqueness, mutability, and sufficient storage. Note that
1191
1255
// for consistency, we need unique self even if newElements is empty.
1192
- self . reserveCapacity (
1193
- newCount > oldCapacity ?
1194
- Swift . max ( newCount, _growArrayCapacity ( oldCapacity) )
1195
- : newCount)
1256
+ _reserveCapacityImpl ( minimumCapacity: self . count + newElementsCount,
1257
+ growForAppend: true )
1196
1258
}
1197
1259
1198
1260
@inlinable
1199
1261
public mutating func _customRemoveLast( ) -> Element ? {
1262
+ _makeMutableAndUnique ( )
1200
1263
let newCount = _getCount ( ) - 1
1201
1264
_precondition ( newCount >= 0 , " Can't removeLast from an empty Array " )
1202
- _makeUniqueAndReserveCapacityIfNotUnique ( )
1203
1265
let pointer = ( _buffer. firstElementAddress + newCount)
1204
1266
let element = pointer. move ( )
1205
1267
_buffer. count = newCount
@@ -1224,10 +1286,11 @@ extension Array: RangeReplaceableCollection {
1224
1286
@inlinable
1225
1287
@discardableResult
1226
1288
public mutating func remove( at index: Int ) -> Element {
1227
- _precondition ( index < endIndex, " Index out of range " )
1228
- _precondition ( index >= startIndex, " Index out of range " )
1229
- _makeUniqueAndReserveCapacityIfNotUnique ( )
1230
- let newCount = _getCount ( ) - 1
1289
+ _makeMutableAndUnique ( )
1290
+ let currentCount = _getCount ( )
1291
+ _precondition ( index < currentCount, " Index out of range " )
1292
+ _precondition ( index >= 0 , " Index out of range " )
1293
+ let newCount = currentCount - 1
1231
1294
let pointer = ( _buffer. firstElementAddress + index)
1232
1295
let result = pointer. move ( )
1233
1296
pointer. moveInitialize ( from: pointer + 1 , count: newCount - index)
@@ -1524,9 +1587,8 @@ extension Array {
1524
1587
public mutating func withUnsafeMutableBufferPointer< R> (
1525
1588
_ body: ( inout UnsafeMutableBufferPointer < Element > ) throws -> R
1526
1589
) rethrows -> R {
1590
+ _makeMutableAndUnique ( )
1527
1591
let count = self . count
1528
- // Ensure unique storage
1529
- _buffer. _outlinedMakeUniqueBuffer ( bufferCount: count)
1530
1592
1531
1593
// Ensure that body can't invalidate the storage or its bounds by
1532
1594
// moving self into a temporary working array.
@@ -1638,19 +1700,12 @@ extension Array {
1638
1700
_precondition ( subrange. upperBound <= _buffer. endIndex,
1639
1701
" Array replace: subrange extends past the end " )
1640
1702
1641
- let oldCount = _buffer. count
1642
1703
let eraseCount = subrange. count
1643
1704
let insertCount = newElements. count
1644
1705
let growth = insertCount - eraseCount
1645
1706
1646
- if _buffer. requestUniqueMutableBackingBuffer (
1647
- minimumCapacity: oldCount + growth) != nil {
1648
-
1649
- _buffer. replaceSubrange (
1650
- subrange, with: insertCount, elementsOf: newElements)
1651
- } else {
1652
- _buffer. _arrayOutOfPlaceReplace ( subrange, with: newElements, count: insertCount)
1653
- }
1707
+ reserveCapacityForAppend ( newElementsCount: growth)
1708
+ _buffer. replaceSubrange ( subrange, with: insertCount, elementsOf: newElements)
1654
1709
}
1655
1710
}
1656
1711
0 commit comments