Skip to content

Commit ae22fe7

Browse files
committed
stdlib/Foundation: optimize the NSDictionary and NSSet copy-constructors
rdar://problem/27678985
1 parent 177ad2c commit ae22fe7

File tree

2 files changed

+70
-5
lines changed

2 files changed

+70
-5
lines changed

stdlib/public/SDK/Foundation/Foundation.swift

+60-5
Original file line numberDiff line numberDiff line change
@@ -1242,8 +1242,28 @@ extension NSSet {
12421242
/// receiver.
12431243
@nonobjc
12441244
public convenience init(set anSet: NSSet) {
1245-
// FIXME: This is a bit weird. Maybe there's a better way?
1246-
self.init(set: anSet as Set<NSObject> as Set<AnyHashable>)
1245+
// FIXME(performance)(compiler limitation): we actually want to do just
1246+
// `self = anSet.copy()`, but Swift does not have factory
1247+
// initializers right now.
1248+
let numElems = anSet.count
1249+
let stride = MemoryLayout<Optional<UnsafeRawPointer>>.stride
1250+
let alignment = MemoryLayout<Optional<UnsafeRawPointer>>.alignment
1251+
let bufferSize = stride * numElems
1252+
assert(stride == MemoryLayout<AnyObject>.stride)
1253+
assert(alignment == MemoryLayout<AnyObject>.alignment)
1254+
1255+
let rawBuffer = UnsafeMutableRawPointer.allocate(
1256+
bytes: bufferSize, alignedTo: alignment)
1257+
defer {
1258+
rawBuffer.deallocate(bytes: bufferSize, alignedTo: alignment)
1259+
_fixLifetime(anSet)
1260+
}
1261+
let valueBuffer = rawBuffer.bindMemory(
1262+
to: Optional<UnsafeRawPointer>.self, capacity: numElems)
1263+
1264+
CFSetGetValues(anSet, valueBuffer)
1265+
let valueBufferForInit = rawBuffer.assumingMemoryBound(to: AnyObject.self)
1266+
self.init(objects: valueBufferForInit, count: numElems)
12471267
}
12481268
}
12491269

@@ -1256,12 +1276,47 @@ extension NSDictionary {
12561276
/// found in `otherDictionary`.
12571277
@objc(_swiftInitWithDictionary_NSDictionary:)
12581278
public convenience init(dictionary otherDictionary: NSDictionary) {
1259-
// FIXME: This is a bit weird. Maybe there's a better way?
1260-
self.init(dictionary: otherDictionary as [NSObject: AnyObject]
1261-
as [AnyHashable: Any])
1279+
// FIXME(performance)(compiler limitation): we actually want to do just
1280+
// `self = otherDictionary.copy()`, but Swift does not have factory
1281+
// initializers right now.
1282+
let numElems = otherDictionary.count
1283+
let stride = MemoryLayout<AnyObject>.stride
1284+
let alignment = MemoryLayout<AnyObject>.alignment
1285+
let singleSize = stride * numElems
1286+
let totalSize = singleSize * 2
1287+
_sanityCheck(stride == MemoryLayout<NSCopying>.stride)
1288+
_sanityCheck(alignment == MemoryLayout<NSCopying>.alignment)
1289+
1290+
// Allocate a buffer containing both the keys and values.
1291+
let buffer = UnsafeMutableRawPointer.allocate(
1292+
bytes: totalSize, alignedTo: alignment)
1293+
defer {
1294+
buffer.deallocate(bytes: totalSize, alignedTo: alignment)
1295+
_fixLifetime(otherDictionary)
1296+
}
1297+
1298+
let valueBuffer = buffer.bindMemory(to: AnyObject.self, capacity: numElems)
1299+
let buffer2 = buffer + singleSize
1300+
let keyBuffer = buffer2.bindMemory(to: AnyObject.self, capacity: numElems)
1301+
1302+
_stdlib_NSDictionary_getObjects(
1303+
nsDictionary: otherDictionary,
1304+
objects: valueBuffer,
1305+
andKeys: keyBuffer)
1306+
1307+
let keyBufferCopying = buffer2.assumingMemoryBound(to: NSCopying.self)
1308+
self.init(objects: valueBuffer, forKeys: keyBufferCopying, count: numElems)
12621309
}
12631310
}
12641311

1312+
@_silgen_name("__NSDictionaryGetObjects")
1313+
func _stdlib_NSDictionary_getObjects(
1314+
nsDictionary: NSDictionary,
1315+
objects: UnsafeMutablePointer<AnyObject>?,
1316+
andKeys keys: UnsafeMutablePointer<AnyObject>?
1317+
)
1318+
1319+
12651320
//===----------------------------------------------------------------------===//
12661321
// NSUndoManager
12671322
//===----------------------------------------------------------------------===//

stdlib/public/SDK/Foundation/Thunks.mm

+10
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,13 @@
212212
void *_Nullable contextInfo) {
213213
objc_msgSend(delegate, selector, success, contextInfo);
214214
}
215+
216+
// -- NSDictionary
217+
SWIFT_CC(swift)
218+
extern "C" void
219+
__NSDictionaryGetObjects(NSDictionary *_Nonnull nsDictionary,
220+
id *objects, id *keys) {
221+
[nsDictionary getObjects:objects andKeys:keys];
222+
[nsDictionary release];
223+
}
224+

0 commit comments

Comments
 (0)