@@ -20,164 +20,44 @@ import SwiftShims
20
20
/// Effectively an untyped NSString that doesn't require foundation.
21
21
public typealias _CocoaString = AnyObject
22
22
23
- public // @testable
24
- func _stdlib_binary_CFStringCreateCopy(
25
- _ source: _CocoaString
26
- ) -> _CocoaString {
27
- let result = _swift_stdlib_CFStringCreateCopy ( nil , source) as AnyObject
28
- Builtin . release ( result)
29
- return result
30
- }
31
-
32
- public // @testable
33
- func _stdlib_binary_CFStringGetLength(
34
- _ source: _CocoaString
35
- ) -> Int {
36
- return _swift_stdlib_CFStringGetLength ( source)
37
- }
38
-
39
- public // @testable
40
- func _stdlib_binary_CFStringGetCharactersPtr(
41
- _ source: _CocoaString
42
- ) -> UnsafeMutablePointer < UTF16 . CodeUnit > ? {
43
- return UnsafeMutablePointer ( mutating: _swift_stdlib_CFStringGetCharactersPtr ( source) )
44
- }
45
-
46
- /// Bridges `source` to `Swift.String`, assuming that `source` has non-ASCII
47
- /// characters (does not apply ASCII optimizations).
48
- @inline ( never) @_semantics ( " stdlib_binary_only " ) // Hide the CF dependency
49
- func _cocoaStringToSwiftString_NonASCII(
50
- _ source: _CocoaString
51
- ) -> String {
52
- let cfImmutableValue = _stdlib_binary_CFStringCreateCopy ( source)
53
- let length = _stdlib_binary_CFStringGetLength ( cfImmutableValue)
54
- let start = _stdlib_binary_CFStringGetCharactersPtr ( cfImmutableValue)
55
-
56
- return String ( _StringCore (
57
- baseAddress: start,
58
- count: length,
59
- elementShift: 1 ,
60
- hasCocoaBuffer: true ,
61
- owner: unsafeBitCast ( cfImmutableValue, to: Optional< AnyObject> . self ) ) )
62
- }
63
-
64
- /// Loading Foundation initializes these function variables
65
- /// with useful values
66
-
67
- /// Produces a `_StringBuffer` from a given subrange of a source
68
- /// `_CocoaString`, having the given minimum capacity.
69
- @inline ( never) @_semantics ( " stdlib_binary_only " ) // Hide the CF dependency
70
- internal func _cocoaStringToContiguous(
71
- source: _CocoaString , range: Range < Int > , minimumCapacity: Int
72
- ) -> _StringBuffer {
73
- _sanityCheck ( _swift_stdlib_CFStringGetCharactersPtr ( source) == nil ,
74
- " Known contiguously stored strings should already be converted to Swift " )
75
-
76
- let startIndex = range. lowerBound
77
- let count = range. upperBound - startIndex
78
-
79
- let buffer = _StringBuffer ( capacity: max ( count, minimumCapacity) ,
80
- initialSize: count, elementWidth: 2 )
81
-
82
- _swift_stdlib_CFStringGetCharacters (
83
- source, _swift_shims_CFRange ( location: startIndex, length: count) ,
84
- buffer. start. assumingMemoryBound ( to: _swift_shims_UniChar. self) )
85
-
86
- return buffer
87
- }
88
-
89
- /// Reads the entire contents of a _CocoaString into contiguous
90
- /// storage of sufficient capacity.
91
- @inline ( never) @_semantics ( " stdlib_binary_only " ) // Hide the CF dependency
92
- internal func _cocoaStringReadAll(
93
- _ source: _CocoaString , _ destination: UnsafeMutablePointer < UTF16 . CodeUnit >
94
- ) {
95
- _swift_stdlib_CFStringGetCharacters (
96
- source, _swift_shims_CFRange (
97
- location: 0 , length: _swift_stdlib_CFStringGetLength ( source) ) , destination)
98
- }
99
-
100
- @inline ( never) @_semantics ( " stdlib_binary_only " ) // Hide the CF dependency
101
- internal func _cocoaStringSlice(
102
- _ target: _StringCore , _ bounds: Range < Int >
103
- ) -> _StringCore {
104
- _sanityCheck ( target. hasCocoaBuffer)
105
-
106
- let cfSelf : _swift_shims_CFStringRef = target. cocoaBuffer. unsafelyUnwrapped
107
-
108
- _sanityCheck (
109
- _swift_stdlib_CFStringGetCharactersPtr ( cfSelf) == nil ,
110
- " Known contiguously stored strings should already be converted to Swift " )
111
-
112
- let cfResult = _swift_stdlib_CFStringCreateWithSubstring (
113
- nil , cfSelf, _swift_shims_CFRange (
114
- location: bounds. lowerBound, length: bounds. count) ) as AnyObject
115
-
116
- return String ( _cocoaString: cfResult) . _core
117
- }
118
-
119
- @_versioned
120
- @inline ( never) @_semantics ( " stdlib_binary_only " ) // Hide the CF dependency
121
- internal func _cocoaStringSubscript(
122
- _ target: _StringCore , _ position: Int
123
- ) -> UTF16 . CodeUnit {
124
- let cfSelf : _swift_shims_CFStringRef = target. cocoaBuffer. unsafelyUnwrapped
125
-
126
- _sanityCheck ( _swift_stdlib_CFStringGetCharactersPtr ( cfSelf) == nil ,
127
- " Known contiguously stored strings should already be converted to Swift " )
128
-
129
- return _swift_stdlib_CFStringGetCharacterAtIndex ( cfSelf, position)
130
- }
131
-
132
- //
133
- // Conversion from NSString to Swift's native representation
134
- //
135
-
136
- internal var kCFStringEncodingASCII : _swift_shims_CFStringEncoding {
137
- return 0x0600
138
- }
139
-
140
23
extension String {
141
24
@inline ( never) @_semantics ( " stdlib_binary_only " ) // Hide the CF dependency
142
25
public // SPI(Foundation)
143
26
init ( _cocoaString: AnyObject ) {
27
+ // If the NSString is actually a Swift String in disguise,
28
+ // we can just copy out the internal repr.
144
29
if let wrapped = _cocoaString as? _NSContiguousString {
145
30
self . _core = wrapped. _core
146
31
return
147
32
}
148
33
149
- // "copy" it into a value to be sure nobody will modify behind
150
- // our backs. In practice, when value is already immutable, this
151
- // just does a retain.
152
- let cfImmutableValue
153
- = _stdlib_binary_CFStringCreateCopy ( _cocoaString) as AnyObject
34
+ let cocoaString = unsafeBitCast ( _cocoaString, to: _NSString. self)
154
35
155
- let length = _swift_stdlib_CFStringGetLength ( cfImmutableValue )
36
+ let length = cocoaString . length ( )
156
37
157
- // Look first for null-terminated ASCII
158
- // Note: the code in clownfish appears to guarantee
159
- // nul-termination, but I'm waiting for an answer from Chris Kane
160
- // about whether we can count on it for all time or not.
161
- let nulTerminatedASCII = _swift_stdlib_CFStringGetCStringPtr (
162
- cfImmutableValue, kCFStringEncodingASCII)
38
+ // The 0 here is `nullRequired: false` (bad hack)
39
+ let nulTerminatedASCII = cocoaString. _fastCStringContents ( 0 )
163
40
164
- // start will hold the base pointer of contiguous storage, if it
165
- // is found.
166
- var start : UnsafeMutableRawPointer ?
167
41
let isUTF16 = ( nulTerminatedASCII == nil )
42
+ let buffer = _StringBuffer ( capacity: length,
43
+ initialSize: length,
44
+ elementWidth: isUTF16 ? 2 : 1 )
45
+
46
+ // We try our darndest to just get a pointer and memcpy, falling back
47
+ // to having the string do it for us with getCharacters.
168
48
if isUTF16 {
169
- let utf16Buf = _swift_stdlib_CFStringGetCharactersPtr ( cfImmutableValue)
170
- start = UnsafeMutableRawPointer ( mutating: utf16Buf)
49
+ let bufPtr = buffer. start. assumingMemoryBound ( to: UInt16 . self)
50
+ if let utf16Ptr = cocoaString. _fastCharacterContents ( ) {
51
+ bufPtr. assign ( from: utf16Ptr, count: length)
52
+ } else {
53
+ cocoaString. getCharacters ( bufPtr)
54
+ }
55
+
171
56
} else {
172
- start = UnsafeMutableRawPointer ( mutating : nulTerminatedASCII)
57
+ buffer . start. copyBytes ( from : nulTerminatedASCII! , count : length )
173
58
}
174
59
175
- self . _core = _StringCore (
176
- baseAddress: start,
177
- count: length,
178
- elementShift: isUTF16 ? 1 : 0 ,
179
- hasCocoaBuffer: true ,
180
- owner: cfImmutableValue)
60
+ self . _core = _StringCore ( buffer)
181
61
}
182
62
}
183
63
@@ -187,25 +67,15 @@ extension String {
187
67
// The @_swift_native_objc_runtime_base attribute
188
68
// This allows us to subclass an Objective-C class and use the fast Swift
189
69
// memory allocator.
70
+ //
71
+ // Subclasses should provide:
72
+ // * func length() -> Int
73
+ // * func characterAtIndex(_ index: Int) -> UInt16
190
74
@objc @_swift_native_objc_runtime_base ( _SwiftNativeNSStringBase)
191
75
public class _SwiftNativeNSString { }
192
76
193
- @objc
194
- public protocol _NSStringCore :
195
- _NSCopying , _NSFastEnumeration {
196
-
197
- // The following methods should be overridden when implementing an
198
- // NSString subclass.
199
-
200
- func length( ) -> Int
201
-
202
- func characterAtIndex( _ index: Int ) -> UInt16
203
-
204
- // We also override the following methods for efficiency.
205
- }
206
-
207
77
/// An `NSString` built around a slice of contiguous Swift `String` storage.
208
- public final class _NSContiguousString : _SwiftNativeNSString {
78
+ public final class _NSContiguousString : _SwiftNativeNSString , _NSStringCore {
209
79
public init ( _ _core: _StringCore ) {
210
80
_sanityCheck (
211
81
_core. hasContiguousStorage,
@@ -218,16 +88,16 @@ public final class _NSContiguousString : _SwiftNativeNSString {
218
88
_sanityCheckFailure ( " init(coder:) not implemented for _NSContiguousString " )
219
89
}
220
90
221
- func length( ) -> Int {
91
+ public func length( ) -> Int {
222
92
return _core. count
223
93
}
224
94
225
- func characterAtIndex( _ index: Int ) -> UInt16 {
95
+ public func characterAtIndex( _ index: Int ) -> UInt16 {
226
96
return _core [ index]
227
97
}
228
98
229
99
@inline ( __always) // Performance: To save on reference count operations.
230
- func getCharacters(
100
+ public func getCharacters(
231
101
_ buffer: UnsafeMutablePointer < UInt16 > ,
232
102
range aRange: _SwiftNSRange ) {
233
103
@@ -248,7 +118,7 @@ public final class _NSContiguousString : _SwiftNativeNSString {
248
118
}
249
119
250
120
@objc
251
- func _fastCharacterContents( ) -> UnsafeMutablePointer < UInt16 > ? {
121
+ public func _fastCharacterContents( ) -> UnsafeMutablePointer < UInt16 > ? {
252
122
return _core. elementWidth == 2 ? _core. startUTF16 : nil
253
123
}
254
124
0 commit comments