Skip to content

Commit 0d30bcf

Browse files
committed
Separate out ASCII and UTF8 in NSString accessors, and use the ASCII one where we really need ASCII
1 parent 270fde9 commit 0d30bcf

File tree

4 files changed

+103
-9
lines changed

4 files changed

+103
-9
lines changed

stdlib/public/core/SmallString.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,28 @@ extension _SmallString {
372372
}
373373
self._invariantCheck()
374374
}
375+
376+
@_effects(readonly) // @opaque
377+
@usableFromInline // testable
378+
internal init?(taggedASCIICocoa cocoa: AnyObject) {
379+
self.init()
380+
var success = true
381+
self.withMutableCapacity {
382+
/*
383+
For regular NSTaggedPointerStrings we will always succeed here, but
384+
tagged NSLocalizedStrings may not fit in a SmallString
385+
*/
386+
if let len = _bridgeTaggedASCII(cocoa, intoUTF8: $0) {
387+
return len
388+
}
389+
success = false
390+
return 0
391+
}
392+
if !success {
393+
return nil
394+
}
395+
self._invariantCheck()
396+
}
375397
}
376398
#endif
377399

stdlib/public/core/StringBridge.swift

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,9 @@ internal func _cocoaStringSubscript(
167167
}
168168

169169
@_effects(releasenone)
170-
private func _NSStringCopyUTF8(
170+
private func _NSStringCopyBytes(
171171
_ o: _StringSelectorHolder,
172+
encoding: UInt,
172173
into bufPtr: UnsafeMutableRawBufferPointer
173174
) -> Int? {
174175
let ptr = bufPtr.baseAddress._unsafelyUnwrappedUnchecked
@@ -179,7 +180,7 @@ private func _NSStringCopyUTF8(
179180
ptr,
180181
maxLength: bufPtr.count,
181182
usedLength: &usedLen,
182-
encoding: _cocoaUTF8Encoding,
183+
encoding: encoding,
183184
options: 0,
184185
range: _SwiftNSRange(location: 0, length: len),
185186
remaining: &remainingRange
@@ -195,7 +196,23 @@ internal func _cocoaStringCopyUTF8(
195196
_ target: _CocoaString,
196197
into bufPtr: UnsafeMutableRawBufferPointer
197198
) -> Int? {
198-
return _NSStringCopyUTF8(_objc(target), into: bufPtr)
199+
return _NSStringCopyUTF8(
200+
_objc(target),
201+
encoding: _cocoaUTF8Encoding,
202+
into: bufPtr
203+
)
204+
}
205+
206+
@_effects(releasenone)
207+
internal func _cocoaStringCopyASCII(
208+
_ target: _CocoaString,
209+
into bufPtr: UnsafeMutableRawBufferPointer
210+
) -> Int? {
211+
return _NSStringCopyASCII(
212+
_objc(target),
213+
encoding: _cocoaASCIIEncoding,
214+
into: bufPtr
215+
)
199216
}
200217

201218
@_effects(readonly)
@@ -346,17 +363,30 @@ internal func _bridgeTagged(
346363
_internalInvariant(_isObjCTaggedPointer(cocoa))
347364
return _cocoaStringCopyUTF8(cocoa, into: bufPtr)
348365
}
366+
367+
@_effects(releasenone) // @opaque
368+
internal func _bridgeTaggedASCII(
369+
_ cocoa: _CocoaString,
370+
intoUTF8 bufPtr: UnsafeMutableRawBufferPointer
371+
) -> Int? {
372+
_internalInvariant(_isObjCTaggedPointer(cocoa))
373+
return _cocoaStringCopyASCII(cocoa, into: bufPtr)
374+
}
349375
#endif
350376

351377
@_effects(readonly)
352378
private func _NSStringASCIIPointer(_ str: _StringSelectorHolder) -> UnsafePointer<UInt8>? {
353-
// TODO(String bridging): Is there a better interface here? Ideally we'd be
354-
// able to ask for UTF8 rather than just ASCII
355379
//TODO(String bridging): Unconditionally asking for nul-terminated contents is
356380
// overly conservative and hurts perf with some NSStrings
357381
return str._fastCStringContents(1)?._asUInt8
358382
}
359383

384+
@_effects(readonly)
385+
private func _NSStringUTF8Pointer(_ str: _StringSelectorHolder) -> UnsafePointer<UInt8>? {
386+
//We don't have a way to ask for UTF8 here currently
387+
return _NSStringASCIIPointer(str)
388+
}
389+
360390
@_effects(readonly) // @opaque
361391
private func _withCocoaASCIIPointer<R>(
362392
_ str: _CocoaString,
@@ -371,7 +401,7 @@ private func _withCocoaASCIIPointer<R>(
371401
if requireStableAddress {
372402
return nil // tagged pointer strings don't support _fastCStringContents
373403
}
374-
if let smol = _SmallString(taggedCocoa: str) {
404+
if let smol = _SmallString(taggedASCIICocoa: str) {
375405
return _StringGuts(smol).withFastUTF8 {
376406
work($0.baseAddress._unsafelyUnwrappedUnchecked)
377407
}
@@ -385,6 +415,34 @@ private func _withCocoaASCIIPointer<R>(
385415
return nil
386416
}
387417

418+
@_effects(readonly) // @opaque
419+
private func _withCocoaUTF8Pointer<R>(
420+
_ str: _CocoaString,
421+
requireStableAddress: Bool,
422+
work: (UnsafePointer<UInt8>) -> R?
423+
) -> R? {
424+
#if !(arch(i386) || arch(arm) || arch(arm64_32))
425+
if _isObjCTaggedPointer(str) {
426+
if let ptr = getConstantTaggedCocoaContents(str)?.asciiContentsPointer {
427+
return work(ptr)
428+
}
429+
if requireStableAddress {
430+
return nil // tagged pointer strings don't support _fastCStringContents
431+
}
432+
if let smol = _SmallString(taggedCocoa: str) {
433+
return _StringGuts(smol).withFastUTF8 {
434+
work($0.baseAddress._unsafelyUnwrappedUnchecked)
435+
}
436+
}
437+
}
438+
#endif
439+
defer { _fixLifetime(str) }
440+
if let ptr = _NSStringUTF8Pointer(_objc(str)) {
441+
return work(ptr)
442+
}
443+
return nil
444+
}
445+
388446
@_effects(readonly) // @opaque
389447
internal func withCocoaASCIIPointer<R>(
390448
_ str: _CocoaString,
@@ -393,12 +451,26 @@ internal func withCocoaASCIIPointer<R>(
393451
return _withCocoaASCIIPointer(str, requireStableAddress: false, work: work)
394452
}
395453

454+
@_effects(readonly) // @opaque
455+
internal func withCocoaUTF8Pointer<R>(
456+
_ str: _CocoaString,
457+
work: (UnsafePointer<UInt8>) -> R?
458+
) -> R? {
459+
return _withCocoaUTF8Pointer(str, requireStableAddress: false, work: work)
460+
}
461+
396462
@_effects(readonly)
397463
internal func stableCocoaASCIIPointer(_ str: _CocoaString)
398464
-> UnsafePointer<UInt8>? {
399465
return _withCocoaASCIIPointer(str, requireStableAddress: true, work: { $0 })
400466
}
401467

468+
@_effects(readonly)
469+
internal func stableCocoaUTF8Pointer(_ str: _CocoaString)
470+
-> UnsafePointer<UInt8>? {
471+
return _withCocoaUTF8Pointer(str, requireStableAddress: true, work: { $0 })
472+
}
473+
402474
private enum CocoaStringPointer {
403475
case ascii(UnsafePointer<UInt8>)
404476
case utf8(UnsafePointer<UInt8>)

stdlib/public/core/StringObject.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,7 @@ extension _StringObject {
915915
_internalInvariant(largeFastIsShared)
916916
#if _runtime(_ObjC)
917917
if largeIsCocoa {
918-
return stableCocoaASCIIPointer(cocoaObject)._unsafelyUnwrappedUnchecked
918+
return stableCocoaUTF8Pointer(cocoaObject)._unsafelyUnwrappedUnchecked
919919
}
920920
#endif
921921

stdlib/public/core/StringStorageBridge.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import SwiftShims
1414

1515
#if _runtime(_ObjC)
1616

17-
internal let _cocoaASCIIEncoding:UInt = 1 /* NSASCIIStringEncoding */
18-
internal let _cocoaUTF8Encoding:UInt = 4 /* NSUTF8StringEncoding */
17+
internal let _cocoaASCIIEncoding:UInt { 1 } /* NSASCIIStringEncoding */
18+
internal let _cocoaUTF8Encoding:UInt { 4 } /* NSUTF8StringEncoding */
1919

2020
extension String {
2121
@available(SwiftStdlib 5.6, *)

0 commit comments

Comments
 (0)