Skip to content

Commit 88a9ebb

Browse files
committed
stdlib: Don't request additional capacity in Array/ContiguousArray's remove.
Just copy the buffer if it's not unique. This also implies that if there is a copy-on-write in remove, "shrink" the capacity of the new buffer to the required amount of elements (instead of copying the capacity of the original buffer).
1 parent ea3b6a0 commit 88a9ebb

File tree

3 files changed

+34
-10
lines changed

3 files changed

+34
-10
lines changed

stdlib/public/core/Array.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,9 +1244,9 @@ extension Array: RangeReplaceableCollection {
12441244

12451245
@inlinable
12461246
public mutating func _customRemoveLast() -> Element? {
1247+
_makeMutableAndUnique()
12471248
let newCount = _getCount() - 1
12481249
_precondition(newCount >= 0, "Can't removeLast from an empty Array")
1249-
_makeUniqueAndReserveCapacityIfNotUnique()
12501250
let pointer = (_buffer.firstElementAddress + newCount)
12511251
let element = pointer.move()
12521252
_buffer.count = newCount
@@ -1271,10 +1271,11 @@ extension Array: RangeReplaceableCollection {
12711271
@inlinable
12721272
@discardableResult
12731273
public mutating func remove(at index: Int) -> Element {
1274-
_precondition(index < endIndex, "Index out of range")
1275-
_precondition(index >= startIndex, "Index out of range")
1276-
_makeUniqueAndReserveCapacityIfNotUnique()
1277-
let newCount = _getCount() - 1
1274+
_makeMutableAndUnique()
1275+
let currentCount = _getCount()
1276+
_precondition(index < currentCount, "Index out of range")
1277+
_precondition(index >= 0, "Index out of range")
1278+
let newCount = currentCount - 1
12781279
let pointer = (_buffer.firstElementAddress + index)
12791280
let result = pointer.move()
12801281
pointer.moveInitialize(from: pointer + 1, count: newCount - index)

stdlib/public/core/ContiguousArray.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -903,9 +903,10 @@ extension ContiguousArray: RangeReplaceableCollection {
903903
@inlinable
904904
@discardableResult
905905
public mutating func remove(at index: Int) -> Element {
906-
_precondition(index < endIndex, "Index out of range")
907-
_precondition(index >= startIndex, "Index out of range")
908-
_makeUniqueAndReserveCapacityIfNotUnique()
906+
_makeMutableAndUnique()
907+
let currentCount = _getCount()
908+
_precondition(index < currentCount, "Index out of range")
909+
_precondition(index >= 0, "Index out of range")
909910
let newCount = _getCount() - 1
910911
let pointer = (_buffer.firstElementAddress + index)
911912
let result = pointer.move()

test/stdlib/Inputs/CommonArrayTests.gyb

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,34 @@ ${Suite}.test("${ArrayType}/appendNonUnique")
106106
var x: ${ArrayType}<Int> = []
107107
x.reserveCapacity(10002)
108108
let capacity = x.capacity
109-
for _ in 1...10000 {
109+
for _ in 1...100 {
110110
let y = x
111111
x.append(1)
112112
expectTrue(x.capacity == capacity)
113-
let z = x
113+
}
114+
}
115+
116+
% if ArrayType != 'ArraySlice':
117+
${Suite}.test("${ArrayType}/removeNonUnique")
118+
.code {
119+
var x = ${ArrayType}<Int>(repeating: 27, count: 200)
120+
x.reserveCapacity(10002)
121+
for _ in 1...100 {
122+
let y = x
114123
x.remove(at: 0)
124+
expectTrue(x.capacity < 1000)
125+
}
126+
}
127+
% end
128+
129+
${Suite}.test("${ArrayType}/mutateNonUnique")
130+
.code {
131+
var x = ${ArrayType}<Int>(repeating: 27, count: 200)
132+
x.reserveCapacity(10002)
133+
for _ in 1...100 {
134+
let y = x
135+
x[0] = 0
136+
expectTrue(x.capacity < 1000)
115137
}
116138
}
117139

0 commit comments

Comments
 (0)