1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#if FOUNDATION_FRAMEWORK
@_exported import Foundation // Clang module
@_spi(Foundation) import Swift
internal import CoreFoundation_Private.CFString
internal import ObjectiveC_Private.objc_internal
internal import CoreFoundation_Private.ForFoundationOnly
//===----------------------------------------------------------------------===//
// New Strings
//===----------------------------------------------------------------------===//
//
// Conversion from NSString to Swift's native representation
//
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
extension String {
public init(_ cocoaString: NSString) {
self = String._unconditionallyBridgeFromObjectiveC(cocoaString)
}
}
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
extension String : _ObjectiveCBridgeable {
@_semantics("convertToObjectiveC")
public func _bridgeToObjectiveC() -> NSString {
// This method should not do anything extra except calling into the
// implementation inside core. (These two entry points should be
// equivalent.)
return unsafeBitCast(_bridgeToObjectiveCImpl(), to: NSString.self)
}
public static func _forceBridgeFromObjectiveC(_ x: NSString, result: inout String?) {
result = String._unconditionallyBridgeFromObjectiveC(x)
}
public static func _conditionallyBridgeFromObjectiveC(_ x: NSString, result: inout String?) -> Bool {
self._forceBridgeFromObjectiveC(x, result: &result)
return result != nil
}
@_effects(readonly)
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSString?) -> String {
// `nil` has historically been used as a stand-in for an empty
// string; map it to an empty string.
guard let source = source else {
return ""
}
#if !(arch(i386) || arch(arm) || arch(arm64_32))
var SMALL_STRING_CAPACITY:Int { 15 }
if OBJC_HAVE_TAGGED_POINTERS == 1 && _objc_isTaggedPointer(unsafeBitCast(source, to: UnsafeRawPointer.self)) {
let tag = _objc_getTaggedPointerTag(unsafeBitCast(source, to: UnsafeRawPointer.self))
if tag == OBJC_TAG_NSString {
return String(unsafeUninitializedCapacity: SMALL_STRING_CAPACITY) {
_NSTaggedPointerStringGetBytes(source, $0.baseAddress!)
}
} else if tag == OBJC_TAG_NSAtom {
var len = UInt16(0)
let contentsPtr = _CFIndirectTaggedPointerStringGetContents(source, &len)
let contents = UnsafeBufferPointer(start: contentsPtr, count: Int(len))
// Will only fail if contents aren't valid UTF8/ASCII
if let result = _SwiftCreateImmortalString_ForFoundation(buffer: contents, isASCII: true) {
return result
}
// Since our contents are invalid, force a real copy of the string and bridge that instead. This should basically never be hit in practice
return source.mutableCopy() as! String
} else if tag.rawValue == 22 /* OBJC_TAG_Foundation_1 */ {
let cStr = source.utf8String!
return String.init(utf8String: cStr)!
}
}
#endif
var ascii = false
var len = 0
var mutable = false
var constant = false
if __CFStringIsCF(unsafeBitCast(source, to: CFString.self), &mutable, &len, &ascii, &constant) {
if len == 0 {
return ""
}
if constant {
if ascii {
// We would like to use _SwiftCreateImmortalString_ForFoundation here, but we can't because we need to maintain the invariant
// (constantString as String as NSString) === constantString
// and using _SwiftCreateImmortalString_ForFoundation would make an indirect tagged string instead on the way back
return String(_immortalCocoaString: source, count: len, encoding: Unicode.ASCII.self)
} else {
return String(_immortalCocoaString: source, count: len, encoding: Unicode.UTF16.self)
}
}
/*
If `source` is a mutable string, we should eagerly bridge.
Lazy bridging will still wastefully copy it to immutable first.
*/
if mutable {
let eagerBridge = { (source: NSString, encoding: CFStringBuiltInEncodings, capacity: Int) -> String? in
let result = String(unsafeUninitializedCapacity: capacity) { buffer in
var usedLen = 0
let convertedCount = _CFNonObjCStringGetBytes(
unsafeBitCast(source, to: CFString.self),
CFRangeMake(0, len),
encoding.rawValue,
0,
false,
buffer.baseAddress.unsafelyUnwrapped,
capacity,
&usedLen
)
if convertedCount != len {
return 0
}
return usedLen
}
return result.isEmpty ? nil : result
}
if ascii {
if let result = eagerBridge(source, CFStringBuiltInEncodings.ASCII, len) {
return result
}
} else {
if let result = eagerBridge(source, CFStringBuiltInEncodings.UTF8, source.lengthOfBytes(using: String.Encoding.utf8.rawValue)) {
return result
}
}
}
} else { //not an __NSCFString
// If `source` is a Swift-native string ("rebridging"), we should return it as-is.
if let result = String(_nativeStorage: source) {
return result
}
len = source.length
if len == 0 {
return ""
}
}
/*
Future
• If `source` is an immutable NSCFString, we should get what String
needs with as few calls as possible. A unified
"get isASCII, providesFastUTF8, length" method? Is this the same
"prepare for bridging" concept?
• Complication: if we can prove an NSCFString has no associated objects
we may want to eagerly bridge it. Checking that is rdar://50255938,
but even once we have that, when to eagerly bridge vs lazily bridge
is not necessarily an obvious set of tradeoffs.
Existing stdlib entry points:
`String(unsafeUninitializedCapacity:, initializingWith:)`
`String(_cocoaString:)`
`String?(_nativeStorage:)`
`String(_immortalCocoaString:, count:, encoding:)`
Should the stdlib expose
`String(_preparedCocoaString:,isASCII:,providesFastUTF8:,length:)` for
this code to use? Is there a better signature? (This one is just the
one from the underlying _StringGuts() initializer)
If we do all this, aside from major speedups, we can delete everything
in _bridgeCocoaString() in the stdlib, keeping all the smarts about
how bridging works in one place (here).
*/
return String(_cocoaString: source)
}
}
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
extension Substring : _ObjectiveCBridgeable {
@_semantics("convertToObjectiveC")
public func _bridgeToObjectiveC() -> NSString {
return String(self)._bridgeToObjectiveC()
}
public static func _forceBridgeFromObjectiveC(_ x: NSString, result: inout Substring?) {
let s = String(x)
result = s[...]
}
public static func _conditionallyBridgeFromObjectiveC(_ x: NSString, result: inout Substring?) -> Bool {
self._forceBridgeFromObjectiveC(x, result: &result)
return result != nil
}
@_effects(readonly)
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSString?) -> Substring {
let str = String._unconditionallyBridgeFromObjectiveC(source)
return str[...]
}
}
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
extension String: CVarArg {}
/*
This is on NSObject so that the stdlib can call it in StringBridge.swift
without having to synthesize a receiver (e.g. lookup a class or allocate)
TODO: In the future (once the Foundation overlay can know about SmallString),
we should move the caller of this method up into the overlay and avoid this
indirection.
*/
private extension NSObject {
// The ObjC selector has to start with "new" to get ARC to not autorelease
@_effects(releasenone)
@objc(newTaggedNSStringWithASCIIBytes_:length_:)
func createTaggedString(bytes: UnsafePointer<UInt8>,
count: Int) -> AnyObject? {
if let result = _CFStringCreateTaggedPointerString(
bytes,
count
) {
return result.takeRetainedValue() as NSString as NSString? //just "as AnyObject" inserts unwanted bridging
}
return nil
}
}
extension Substring {
func _components(separatedBy characterSet: CharacterSet) -> [String] {
var result = [String]()
var searchStart = startIndex
while searchStart < endIndex {
let r = self[searchStart...]._rangeOfCharacter(from: characterSet, options: [])
guard let r, !r.isEmpty else {
break
}
result.append(String(self[searchStart ..< r.lowerBound]))
searchStart = r.upperBound
}
result.append(String(self[searchStart..<endIndex]))
return result
}
}
extension BidirectionalCollection where Element == Unicode.Scalar, Index == String.Index {
func _trimmingCharacters(in set: CharacterSet) -> SubSequence {
var idx = startIndex
while idx < endIndex && set.contains(self[idx]) {
formIndex(after: &idx)
}
let startOfNonTrimmedRange = idx // Points at the first char not in the set
guard startOfNonTrimmedRange != endIndex else {
return self[endIndex...]
}
let beforeEnd = index(before: endIndex)
guard startOfNonTrimmedRange < beforeEnd else {
return self[startOfNonTrimmedRange ..< endIndex]
}
var backIdx = beforeEnd
// No need to bound-check because we've already trimmed from the beginning, so we'd definitely break off of this loop before `backIdx` rewinds before `startIndex`
while set.contains(self[backIdx]) {
formIndex(before: &backIdx)
}
return self[startOfNonTrimmedRange ... backIdx]
}
}
#endif
|