|
16 | 16 | //
|
17 | 17 | //===----------------------------------------------------------------------===//
|
18 | 18 |
|
19 |
| -#if _runtime(_ObjC) |
20 |
| -// FIXME: These need to be implemented even for non-objc: |
21 |
| -// rdar://problem/18881196 |
22 |
| - |
23 |
| -internal enum _ValueOrReference { |
24 |
| - case reference, value |
25 |
| - |
26 |
| - internal init<T>(_: T.Type) { |
27 |
| - self = _isClassOrObjCExistential(T.self) ? .reference : .value |
28 |
| - } |
29 |
| -} |
30 |
| - |
31 |
| -internal enum _BridgeStyle { |
32 |
| - case verbatim, explicit |
33 |
| - |
34 |
| - internal init<T>(_: T.Type) { |
35 |
| - self = _isBridgedVerbatimToObjectiveC(T.self) ? .verbatim : .explicit |
36 |
| - } |
37 |
| -} |
38 |
| - |
39 |
| -//===--- Forced casts: [T] as! [U] ----------------------------------------===// |
40 |
| - |
41 | 19 | /// Implements `source as! [TargetElement]`.
|
42 | 20 | ///
|
43 |
| -/// - Precondition: At least one of `SourceElement` and `TargetElement` is a |
44 |
| -/// class type or ObjC existential. May trap for other "valid" inputs when |
45 |
| -/// `TargetElement` is not bridged verbatim, if an element can't be converted. |
| 21 | +/// - Note: When SourceElement and TargetElement are both bridged verbatim, type |
| 22 | +/// checking is deferred until elements are actually accessed. |
46 | 23 | public func _arrayForceCast<SourceElement, TargetElement>(
|
47 | 24 | _ source: Array<SourceElement>
|
48 | 25 | ) -> Array<TargetElement> {
|
49 |
| - switch ( |
50 |
| - _ValueOrReference(SourceElement.self), _BridgeStyle(TargetElement.self) |
51 |
| - ) { |
52 |
| - case (.reference, .verbatim): |
53 |
| - let native = source._buffer.requestNativeBuffer() |
54 |
| - |
55 |
| - if _fastPath(native != nil) { |
56 |
| - if _fastPath(native!.storesOnlyElementsOfType(TargetElement.self)) { |
| 26 | +#if _runtime(_ObjC) |
| 27 | + if _isClassOrObjCExistential(SourceElement.self) |
| 28 | + && _isClassOrObjCExistential(TargetElement.self) { |
| 29 | + let src = source._buffer |
| 30 | + if let native = src.requestNativeBuffer() { |
| 31 | + if native.storesOnlyElementsOfType(TargetElement.self) { |
57 | 32 | // A native buffer that is known to store only elements of the
|
58 | 33 | // TargetElement can be used directly
|
59 |
| - return Array(_buffer: source._buffer.cast(toBufferOf: TargetElement.self)) |
| 34 | + return Array(_buffer: src.cast(toBufferOf: TargetElement.self)) |
60 | 35 | }
|
61 | 36 | // Other native buffers must use deferred element type checking
|
62 | 37 | return Array(_buffer:
|
63 |
| - source._buffer.downcast( |
64 |
| - toBufferWithDeferredTypeCheckOf: TargetElement.self)) |
| 38 | + src.downcast(toBufferWithDeferredTypeCheckOf: TargetElement.self)) |
65 | 39 | }
|
66 |
| - // All non-native buffers use deferred element typechecking |
67 | 40 | return Array(_immutableCocoaArray: source._buffer._asCocoaArray())
|
68 |
| - |
69 |
| - case (.reference, .explicit): |
70 |
| - let result: [TargetElement]? = _arrayConditionalBridgeElements(source) |
71 |
| - _precondition(result != nil, "array cannot be bridged from Objective-C") |
72 |
| - return result! |
73 |
| - |
74 |
| - case (.value, .verbatim): |
75 |
| - if source.isEmpty { |
76 |
| - return Array() |
77 |
| - } |
78 |
| - |
79 |
| - var buf = _ContiguousArrayBuffer<TargetElement>( |
80 |
| - uninitializedCount: source.count, minimumCapacity: 0) |
81 |
| - |
82 |
| - let _: Void = buf.withUnsafeMutableBufferPointer { |
83 |
| - var p = $0.baseAddress! |
84 |
| - for value in source { |
85 |
| - let bridged: AnyObject? = _bridgeToObjectiveC(value) |
86 |
| - _precondition( |
87 |
| - bridged != nil, "array element cannot be bridged to Objective-C") |
88 |
| - // FIXME: should be an unsafeDowncast. |
89 |
| - p.initialize(with: unsafeBitCast(bridged!, to: TargetElement.self)) |
90 |
| - p += 1 |
91 |
| - } |
92 |
| - } |
93 |
| - return Array(_buffer: _ArrayBuffer(buf, shiftedToStartIndex: 0)) |
94 |
| - |
95 |
| - case (.value, .explicit): |
96 |
| - _sanityCheckFailure( |
97 |
| - "Force-casting between Arrays of value types not prevented at compile-time" |
98 |
| - ) |
99 | 41 | }
|
| 42 | +#endif |
| 43 | + return _arrayConditionalCast(source)! |
100 | 44 | }
|
101 | 45 |
|
102 |
| -//===--- Conditional casts: [T] as? [U] -----------------------------------===// |
| 46 | +internal struct _UnwrappingFailed : Error {} |
103 | 47 |
|
104 |
| -/// Implements the semantics of `x as? [TargetElement]` where `x` has type |
105 |
| -/// `[SourceElement]` and `TargetElement` is a verbatim-bridged trivial subtype of |
106 |
| -/// `SourceElement`. |
107 |
| -/// |
108 |
| -/// Returns an Array<TargetElement> containing the same elements as a |
109 |
| -/// |
110 |
| -/// O(1) if a's buffer elements are dynamically known to have type |
111 |
| -/// TargetElement or a type derived from TargetElement. O(N) |
112 |
| -/// otherwise. |
113 |
| -internal func _arrayConditionalDownCastElements<SourceElement, TargetElement>( |
114 |
| - _ a: Array<SourceElement> |
115 |
| -) -> [TargetElement]? { |
116 |
| - _sanityCheck(_isBridgedVerbatimToObjectiveC(SourceElement.self)) |
117 |
| - _sanityCheck(_isBridgedVerbatimToObjectiveC(TargetElement.self)) |
118 |
| - |
119 |
| - if _fastPath(!a.isEmpty) { |
120 |
| - let native = a._buffer.requestNativeBuffer() |
121 |
| - |
122 |
| - if _fastPath(native != nil) { |
123 |
| - if native!.storesOnlyElementsOfType(TargetElement.self) { |
124 |
| - return Array(_buffer: a._buffer.cast(toBufferOf: TargetElement.self)) |
125 |
| - } |
126 |
| - return nil |
127 |
| - } |
128 |
| - |
129 |
| - // slow path: we store an NSArray |
130 |
| - |
131 |
| - // We can skip the check if TargetElement happens to be AnyObject |
132 |
| - if !(AnyObject.self is TargetElement.Type) { |
133 |
| - for element in a { |
134 |
| - if !(element is TargetElement) { |
135 |
| - return nil |
136 |
| - } |
137 |
| - } |
138 |
| - } |
139 |
| - return Array(_buffer: a._buffer.cast(toBufferOf: TargetElement.self)) |
| 48 | +extension Optional { |
| 49 | + internal func unwrappedOrError() throws -> Wrapped { |
| 50 | + if let x = self { return x } |
| 51 | + throw _UnwrappingFailed() |
140 | 52 | }
|
141 |
| - return [] |
142 |
| -} |
143 |
| - |
144 |
| -/// Try to convert the source array of objects to an array of values |
145 |
| -/// produced by bridging the objects from Objective-C to `TargetElement`. |
146 |
| -/// |
147 |
| -/// - Precondition: SourceElement is a class type. |
148 |
| -/// - Precondition: TargetElement is bridged non-verbatim to Objective-C. |
149 |
| -/// O(n), because each element must be bridged separately. |
150 |
| -internal func _arrayConditionalBridgeElements< |
151 |
| - SourceElement, |
152 |
| - TargetElement |
153 |
| ->(_ source: Array<SourceElement>) -> Array<TargetElement>? { |
154 |
| - |
155 |
| - _sanityCheck(_isBridgedVerbatimToObjectiveC(SourceElement.self)) |
156 |
| - _sanityCheck(!_isBridgedVerbatimToObjectiveC(TargetElement.self)) |
157 |
| - |
158 |
| - let buf = _ContiguousArrayBuffer<TargetElement>( |
159 |
| - uninitializedCount: source.count, minimumCapacity: 0) |
160 |
| - |
161 |
| - var p = buf.firstElementAddress |
162 |
| - |
163 |
| - // Make sure the resulting array owns anything that is successfully stored |
164 |
| - // there. |
165 |
| - defer { buf.count = p - buf.firstElementAddress } |
166 |
| - |
167 |
| - for object: SourceElement in source { |
168 |
| - guard let value = object as? TargetElement else { |
169 |
| - return nil |
170 |
| - } |
171 |
| - p.initialize(with: value) |
172 |
| - p += 1 |
173 |
| - } |
174 |
| - return Array(_buffer: _ArrayBuffer(buf, shiftedToStartIndex: 0)) |
175 | 53 | }
|
176 | 54 |
|
177 | 55 | /// Implements `source as? [TargetElement]`: convert each element of
|
178 | 56 | /// `source` to a `TargetElement` and return the resulting array, or
|
179 | 57 | /// return `nil` if any element fails to convert.
|
180 | 58 | ///
|
181 |
| -/// - Precondition: `SourceElement` is a class or ObjC existential type. |
182 |
| -/// O(n), because each element must be checked. |
| 59 | +/// - Complexity: O(n), because each element must be checked. |
183 | 60 | public func _arrayConditionalCast<SourceElement, TargetElement>(
|
184 | 61 | _ source: [SourceElement]
|
185 | 62 | ) -> [TargetElement]? {
|
186 |
| - switch (_ValueOrReference(SourceElement.self), _BridgeStyle(TargetElement.self)) { |
187 |
| - case (.value, _): |
188 |
| - _sanityCheckFailure( |
189 |
| - "Conditional cast from array of value types not prevented at compile-time") |
190 |
| - case (.reference, .verbatim): |
191 |
| - return _arrayConditionalDownCastElements(source) |
192 |
| - case (.reference, .explicit): |
193 |
| - return _arrayConditionalBridgeElements(source) |
194 |
| - } |
| 63 | + return try? source.map { try ($0 as? TargetElement).unwrappedOrError() } |
195 | 64 | }
|
196 |
| -#endif |
0 commit comments