|
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