Skip to content

Commit

Permalink
Merge pull request #16320 from milseman/identity_crisis
Browse files Browse the repository at this point in the history
[string] Only bridge tagged NSStrings to small string form.
  • Loading branch information
milseman authored May 4, 2018
2 parents c25188b + 5f1ba83 commit cd32463
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 18 deletions.
16 changes: 0 additions & 16 deletions stdlib/public/core/StringBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -203,22 +203,6 @@ func _makeCocoaStringGuts(_ cocoaString: _CocoaString) -> _StringGuts {

let length = _StringGuts.getCocoaLength(
_unsafeBitPattern: Builtin.reinterpretCast(immutableCopy))

// TODO(SSO): And also for UTF-16 strings and non-contiguous strings
if let ptr = start, !isUTF16 && length <= _SmallUTF8String.capacity {
if let small = _SmallUTF8String(
UnsafeBufferPointer(
start: ptr.assumingMemoryBound(to: UInt8.self), count: length)
) {
return _StringGuts(small)
} else {
#if arch(i386) || arch(arm)
#else
_sanityCheckFailure("Couldn't fit 15-char ASCII small string?")
#endif
}
}

return _StringGuts(
_largeNonTaggedCocoaObject: immutableCopy,
count: length,
Expand Down
6 changes: 4 additions & 2 deletions stdlib/public/core/StringStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ where CodeUnit : UnsignedInteger & FixedWidthInteger {

#if arch(i386) || arch(arm)
#else
_sanityCheck((CodeUnit.self != UInt8.self || capacity > 15),
"Should prefer a small representation")
// TODO(SR-7594): Restore below invariant
// _sanityCheck(
// CodeUnit.self != UInt8.self || capacity > _SmallUTF8String.capacity,
// "Should prefer a small representation")
#endif // 64-bit

let storage = Builtin.allocWithTailElems_1(
Expand Down
72 changes: 72 additions & 0 deletions test/stdlib/StringBridge.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// RUN: %target-run-simple-swift
// REQUIRES: executable_test

// REQUIRES: objc_interop

import Foundation
import StdlibUnittest

var StringBridgeTests = TestSuite("StringBridgeTests")

extension String {
init(fromCocoa s: String) {
self = (s as NSString) as String
}


}

func expectSmall(_ str: String,
stackTrace: SourceLocStack = SourceLocStack(),
showFrame: Bool = true,
file: String = #file, line: UInt = #line
) {
expectTrue(str._guts._isSmall,
stackTrace: stackTrace, showFrame: showFrame, file: file, line: line)
}
func expectCocoa(_ str: String,
stackTrace: SourceLocStack = SourceLocStack(),
showFrame: Bool = true,
file: String = #file, line: UInt = #line
) {
expectTrue(str._guts._isCocoa,
stackTrace: stackTrace, showFrame: showFrame, file: file, line: line)
}

StringBridgeTests.test("Tagged NSString") {
#if arch(i386) || arch(arm)
#else
// Bridge tagged strings as small
expectSmall((("0123456" as NSString) as String))
expectSmall((("012345678" as NSString) as String))
expectSmall((("aaaaaaaaaaa" as NSString) as String))
expectSmall((("bbbbbbbbb" as NSString) as String))

// Bridge non-tagged as non-small even if they fit, for fear of losing
// associated information
let bigAs = ("aaaaaaaaaaaa" as NSString) as String
let bigBs = ("bbbbbbbbbb" as NSString) as String
let bigQs = ("????????" as NSString) as String
expectCocoa(bigAs)
expectCocoa(bigBs)
expectCocoa(bigQs)

#if false // TODO(SR-7594): re-enable
let littleAsNSString = ("aa" as NSString)
var littleAs = littleAsNSString as String

// But become small when appended to
expectSmall(bigAs + "c")
expectSmall(bigBs + "c")
expectSmall("a\(bigAs)")
expectSmall("a\(bigBs)")
expectSmall(littleAs + bigQs)
expectSmall(bigQs + littleAs)
expectSmall("\(littleAs)bigQs\(littleAs)")
#endif // false

#endif // not 32bit
}

runAllTests()

0 comments on commit cd32463

Please sign in to comment.