Skip to content

Commit b4a7993

Browse files
committed
Set: skip copying old values during removeAll
As noted in FIXME(performance), when not uniquely referenced, Set.nativeRemoveAll() makes a copy of the memory with same content and only then proceed to remove each element. This patch makes nativeRemoveAll() skip the copying part.
1 parent 2882816 commit b4a7993

File tree

1 file changed

+22
-14
lines changed

1 file changed

+22
-14
lines changed

stdlib/public/core/HashedCollections.swift.gyb

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,13 @@ public struct Set<Element : Hashable> :
575575
public mutating func intersectInPlace<
576576
S : SequenceType where S.Generator.Element == Element
577577
>(sequence: S) {
578+
if let other = sequence as? Set<Element> {
579+
// removeAll() is fast, prefer using it when possible
580+
if other.isEmpty {
581+
removeAll()
582+
}
583+
}
584+
578585
// Because `intersect` needs to both modify and iterate over
579586
// the left-hand side, the index may become invalidated during
580587
// traversal so an intermediate set must be created.
@@ -3394,26 +3401,27 @@ internal enum _Variant${Self}Storage<${TypeParametersDecl}> : _HashStorageType {
33943401
}
33953402

33963403
internal mutating func nativeRemoveAll() {
3397-
var nativeStorage = native
3398-
3399-
// FIXME(performance): if the storage is non-uniquely referenced, we
3400-
// shouldn’t be copying the elements into new storage and then immediately
3401-
// deleting the elements. We should detect that the storage is not uniquely
3402-
// referenced and allocate new empty storage of appropriate capacity.
34033404

34043405
// We have already checked for the empty dictionary case, so we will always
34053406
// mutating the dictionary storage. Request unique storage.
3406-
let (reallocated, _) = ensureUniqueNativeStorage(nativeStorage.capacity)
3407-
if reallocated {
3408-
nativeStorage = native
3409-
}
34103407

3411-
for var b = 0; b != nativeStorage.capacity; ++b {
3412-
if nativeStorage.isInitializedEntry(b) {
3413-
nativeStorage.destroyEntryAt(b)
3408+
if !isUniquelyReferenced() {
3409+
switch self {
3410+
case .Native(let owner):
3411+
owner.deinitializeHeapBufferBridged()
3412+
case .Cocoa:
3413+
_sanityCheckFailure("internal error: not backed by native storage")
3414+
}
3415+
let newNativeOwner = NativeStorageOwner(minimumCapacity: native.capacity)
3416+
self = .Native(newNativeOwner)
3417+
} else {
3418+
for b in 0..<native.capacity {
3419+
if native.isInitializedEntry(b) {
3420+
native.destroyEntryAt(b)
3421+
}
34143422
}
34153423
}
3416-
nativeStorage.count = 0
3424+
native.count = 0
34173425
}
34183426

34193427
internal mutating func removeAll(keepCapacity keepCapacity: Bool) {

0 commit comments

Comments
 (0)