@@ -61,6 +61,140 @@ extension Dictionary : _ObjectiveCBridgeable {
61
61
to: NSDictionary . self)
62
62
}
63
63
64
+ /***
65
+ Precondition: `buffer` points to a region of memory bound to `AnyObject`,
66
+ with a capacity large enough to fit at least `index`+1 elements of type `T`
67
+
68
+ _bridgeInitialize rebinds the `index`th `T` of `buffer` to `T`,
69
+ and initializes it to `value`
70
+
71
+ Note: *not* the `index`th element of `buffer`, since T and AnyObject may be
72
+ different sizes. e.g. if T is String (2 words) then given a buffer like so:
73
+
74
+ [object:AnyObject, object:AnyObject, uninitialized, uninitialized]
75
+
76
+ `_bridgeInitialize(1, of: buffer, to: buffer[1] as! T)` will leave it as:
77
+
78
+ [object:AnyObject, object:AnyObject, string:String]
79
+
80
+ and `_bridgeInitialize(0, of: buffer, to: buffer[0] as! T)` will then leave:
81
+
82
+ [string:String, string:String]
83
+
84
+ Doing this in reverse order as shown above is required if T and AnyObject are
85
+ different sizes. Here's what we get if instead of 1, 0 we did 0, 1:
86
+
87
+ [object:AnyObject, object:AnyObject, uninitialized, uninitialized]
88
+ [string:String, uninitialized, uninitialized]
89
+ <segfault trying to treat the second word of 'string' as an AnyObject>
90
+
91
+ Note: if you have retained any of the objects in `buffer`, you must release
92
+ them separately, _bridgeInitialize will overwrite them without releasing them
93
+ */
94
+ @inline ( __always)
95
+ private static func _bridgeInitialize< T> ( index: Int ,
96
+ of buffer: UnsafePointer < AnyObject > , to value: T ) {
97
+ let typedBase = UnsafeMutableRawPointer ( mutating:
98
+ buffer) . assumingMemoryBound ( to: T . self)
99
+ let rawTarget = UnsafeMutableRawPointer ( mutating: typedBase + index)
100
+ rawTarget. initializeMemory ( as: T . self, repeating: value, count: 1 )
101
+ }
102
+
103
+ @inline ( __always)
104
+ private static func _verbatimForceBridge< T> (
105
+ _ buffer: UnsafeMutablePointer < AnyObject > ,
106
+ count: Int ,
107
+ to: T . Type
108
+ ) {
109
+ //doesn't have to iterate in reverse because sizeof(T) == sizeof(AnyObject)
110
+ for i in 0 ..< count {
111
+ _bridgeInitialize ( index: i, of: buffer, to: buffer [ i] as! T )
112
+ }
113
+ }
114
+
115
+ @inline ( __always)
116
+ private static func _verbatimBridge< T> (
117
+ _ buffer: UnsafeMutablePointer < AnyObject > ,
118
+ count: Int ,
119
+ to type: T . Type
120
+ ) -> Int {
121
+ var numUninitialized = count
122
+ while numUninitialized > 0 {
123
+ guard let bridged = buffer [ numUninitialized - 1 ] as? T else {
124
+ return numUninitialized
125
+ }
126
+ numUninitialized -= 1
127
+ _bridgeInitialize ( index: numUninitialized, of: buffer, to: bridged)
128
+ }
129
+ return numUninitialized
130
+ }
131
+
132
+ @inline ( __always)
133
+ private static func _nonVerbatimForceBridge< T> (
134
+ _ buffer: UnsafeMutablePointer < AnyObject > ,
135
+ count: Int ,
136
+ to: T . Type
137
+ ) {
138
+ for i in ( 0 ..< count) . reversed ( ) {
139
+ let bridged = Swift . _forceBridgeFromObjectiveC ( buffer [ i] , T . self)
140
+ _bridgeInitialize ( index: i, of: buffer, to: bridged)
141
+ }
142
+ }
143
+
144
+ @inline ( __always)
145
+ private static func _nonVerbatimBridge< T> (
146
+ _ buffer: UnsafeMutablePointer < AnyObject > ,
147
+ count: Int ,
148
+ to: T . Type
149
+ ) -> Int {
150
+ var numUninitialized = count
151
+ while numUninitialized > 0 {
152
+ guard let bridged = Swift . _conditionallyBridgeFromObjectiveC (
153
+ buffer [ numUninitialized - 1 ] , T . self)
154
+ else {
155
+ return numUninitialized
156
+ }
157
+ numUninitialized -= 1
158
+ _bridgeInitialize ( index: numUninitialized, of: buffer, to: bridged)
159
+ }
160
+ return numUninitialized
161
+ }
162
+
163
+ @inline ( __always)
164
+ private static func _forceBridge< T> (
165
+ _ buffer: UnsafeMutablePointer < AnyObject > ,
166
+ count: Int ,
167
+ to: T . Type
168
+ ) {
169
+ if _isBridgedVerbatimToObjectiveC ( T . self) {
170
+ _verbatimForceBridge ( buffer, count: count, to: T . self)
171
+ } else {
172
+ _nonVerbatimForceBridge ( buffer, count: count, to: T . self)
173
+ }
174
+ }
175
+
176
+ @inline ( __always)
177
+ private static func _conditionallyBridge< T> (
178
+ _ buffer: UnsafeMutablePointer < AnyObject > ,
179
+ count: Int ,
180
+ to: T . Type
181
+ ) -> Bool {
182
+ let numUninitialized : Int
183
+ if _isBridgedVerbatimToObjectiveC ( T . self) {
184
+ numUninitialized = _verbatimBridge ( buffer, count: count, to: T . self)
185
+ } else {
186
+ numUninitialized = _nonVerbatimBridge ( buffer, count: count, to: T . self)
187
+ }
188
+ if numUninitialized == 0 {
189
+ return true
190
+ }
191
+ let numInitialized = count - numUninitialized
192
+ ( UnsafeMutableRawPointer ( mutating: buffer) . assumingMemoryBound ( to:
193
+ T . self) + numUninitialized) . deinitialize ( count: numInitialized)
194
+ return false
195
+ }
196
+
197
+ @_specialize ( where Key == String, Value == Any)
64
198
public static func _forceBridgeFromObjectiveC(
65
199
_ d: NSDictionary ,
66
200
result: inout Dictionary ?
@@ -73,53 +207,120 @@ extension Dictionary : _ObjectiveCBridgeable {
73
207
74
208
if _isBridgedVerbatimToObjectiveC ( Key . self) &&
75
209
_isBridgedVerbatimToObjectiveC ( Value . self) {
210
+ //Lazily type-checked on access
76
211
result = [ Key : Value] ( _cocoaDictionary: d)
77
212
return
78
213
}
79
214
80
- if Key . self == String . self {
215
+ let keyStride = MemoryLayout< Key> . stride
216
+ let valueStride = MemoryLayout< Value> . stride
217
+ let objectStride = MemoryLayout< AnyObject> . stride
218
+
219
+ //If Key or Value are smaller than AnyObject, a Dictionary with N elements
220
+ //doesn't have large enough backing stores to hold the objects to be bridged
221
+ //For now we just handle that case the slow way.
222
+ if keyStride < objectStride || valueStride < objectStride {
223
+ var builder = _DictionaryBuilder < Key , Value > ( count: d. count)
224
+ d. enumerateKeysAndObjects ( { ( anyKey: Any , anyValue: Any , _) in
225
+ let anyObjectKey = anyKey as AnyObject
226
+ let anyObjectValue = anyValue as AnyObject
227
+ builder. add (
228
+ key: Swift . _forceBridgeFromObjectiveC ( anyObjectKey, Key . self) ,
229
+ value: Swift . _forceBridgeFromObjectiveC ( anyObjectValue, Value . self) )
230
+ } )
231
+ result = builder. take ( )
232
+ } else {
233
+ defer { _fixLifetime ( d) }
234
+
235
+ let numElems = d. count
236
+
81
237
// String and NSString have different concepts of equality, so
82
238
// string-keyed NSDictionaries may generate key collisions when bridged
83
239
// over to Swift. See rdar://problem/35995647
84
- var dict = Dictionary ( minimumCapacity: d. count)
85
- d. enumerateKeysAndObjects ( { ( anyKey: Any , anyValue: Any , _) in
86
- let key = Swift . _forceBridgeFromObjectiveC (
87
- anyKey as AnyObject , Key . self)
88
- let value = Swift . _forceBridgeFromObjectiveC (
89
- anyValue as AnyObject , Value . self)
90
- // FIXME: Log a warning if `dict` already had a value for `key`
91
- dict [ key] = value
92
- } )
93
- result = dict
94
- return
95
- }
240
+ let handleDuplicates = ( Key . self == String . self)
241
+
242
+ result = Dictionary ( _unsafeUninitializedCapacity: numElems,
243
+ allowingDuplicates: handleDuplicates) { ( keys, vals, outCount) in
244
+
245
+ let objectKeys = UnsafeMutableRawPointer ( mutating:
246
+ keys. baseAddress!) . assumingMemoryBound ( to: AnyObject . self)
247
+ let objectVals = UnsafeMutableRawPointer ( mutating:
248
+ vals. baseAddress!) . assumingMemoryBound ( to: AnyObject . self)
96
249
97
- // `Dictionary<Key, Value>` where either `Key` or `Value` is a value type
98
- // may not be backed by an NSDictionary.
99
- var builder = _DictionaryBuilder < Key , Value > ( count: d. count)
100
- d. enumerateKeysAndObjects ( { ( anyKey: Any , anyValue: Any , _) in
101
- let anyObjectKey = anyKey as AnyObject
102
- let anyObjectValue = anyValue as AnyObject
103
- builder. add (
104
- key: Swift . _forceBridgeFromObjectiveC ( anyObjectKey, Key . self) ,
105
- value: Swift . _forceBridgeFromObjectiveC ( anyObjectValue, Value . self) )
106
- } )
107
- result = builder. take ( )
108
- }
250
+ //This initializes the first N AnyObjects of the Dictionary buffers.
251
+ //Any unused buffer space is left uninitialized
252
+ //This is fixed up in-place as we bridge elements, by _bridgeInitialize
253
+ __NSDictionaryGetObjects ( d, objectVals, objectKeys, numElems)
109
254
255
+ _forceBridge ( objectKeys, count: numElems, to: Key . self)
256
+ _forceBridge ( objectVals, count: numElems, to: Value . self)
257
+
258
+ outCount = numElems
259
+ }
260
+ }
261
+ }
262
+
263
+ @_specialize ( where Key == String, Value == Any)
110
264
public static func _conditionallyBridgeFromObjectiveC(
111
265
_ x: NSDictionary ,
112
266
result: inout Dictionary ?
113
267
) -> Bool {
114
- let anyDict = x as [ NSObject : AnyObject ]
115
- if _isBridgedVerbatimToObjectiveC ( Key . self) &&
116
- _isBridgedVerbatimToObjectiveC ( Value . self) {
117
- result = Swift . _dictionaryDownCastConditional ( anyDict)
268
+
269
+ if let native = [ Key : Value ] . _bridgeFromObjectiveCAdoptingNativeStorageOf (
270
+ x as AnyObject ) {
271
+ result = native
272
+ return true
273
+ }
274
+
275
+ let keyStride = MemoryLayout< Key> . stride
276
+ let valueStride = MemoryLayout< Value> . stride
277
+ let objectStride = MemoryLayout< AnyObject> . stride
278
+
279
+ //If Key or Value are smaller than AnyObject, a Dictionary with N elements
280
+ //doesn't have large enough backing stores to hold the objects to be bridged
281
+ //For now we just handle that case the slow way.
282
+ if keyStride < objectStride || valueStride < objectStride {
283
+ result = x as [ NSObject : AnyObject ] as? Dictionary
118
284
return result != nil
119
285
}
120
286
121
- result = anyDict as? Dictionary
122
- return result != nil
287
+ defer { _fixLifetime ( x) }
288
+
289
+ let numElems = x. count
290
+ var success = true
291
+
292
+ // String and NSString have different concepts of equality, so
293
+ // string-keyed NSDictionaries may generate key collisions when bridged
294
+ // over to Swift. See rdar://problem/35995647
295
+ let handleDuplicates = ( Key . self == String . self)
296
+
297
+ let tmpResult = Dictionary ( _unsafeUninitializedCapacity: numElems,
298
+ allowingDuplicates: handleDuplicates) { ( keys, vals, outCount) in
299
+
300
+ let objectKeys = UnsafeMutableRawPointer ( mutating:
301
+ keys. baseAddress!) . assumingMemoryBound ( to: AnyObject . self)
302
+ let objectVals = UnsafeMutableRawPointer ( mutating:
303
+ vals. baseAddress!) . assumingMemoryBound ( to: AnyObject . self)
304
+
305
+ //This initializes the first N AnyObjects of the Dictionary buffers.
306
+ //Any unused buffer space is left uninitialized
307
+ //This is fixed up in-place as we bridge elements, by _bridgeInitialize
308
+ __NSDictionaryGetObjects ( x, objectVals, objectKeys, numElems)
309
+
310
+ success = _conditionallyBridge ( objectKeys, count: numElems, to: Key . self)
311
+ if success {
312
+ success = _conditionallyBridge ( objectVals,
313
+ count: numElems, to: Value . self)
314
+ if !success {
315
+ ( UnsafeMutableRawPointer ( mutating: objectKeys) . assumingMemoryBound ( to:
316
+ Key . self) ) . deinitialize ( count: numElems)
317
+ }
318
+ }
319
+ outCount = success ? numElems : 0
320
+ }
321
+
322
+ result = success ? tmpResult : nil
323
+ return success
123
324
}
124
325
125
326
@_effects ( readonly)
0 commit comments