Skip to content

Commit 050c1db

Browse files
milsemanairspeedswift
authored andcommitted
[5.0] [String] UTF8View.withContiguousStorageIfAvailable (#21194)
* [String] UTF8View implements withContiguousStorageIfAvailable * [test] Test String.UTF8View.withContiguousStorageIfAvailable
1 parent 4affa87 commit 050c1db

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

stdlib/public/core/StringUTF8View.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,3 +510,13 @@ extension String.Index {
510510
return target._guts.isOnUnicodeScalarBoundary(self)
511511
}
512512
}
513+
514+
extension String.UTF8View {
515+
@inlinable
516+
public func withContiguousStorageIfAvailable<R>(
517+
_ body: (UnsafeBufferPointer<Element>) throws -> R
518+
) rethrows -> R? {
519+
guard _guts.isFastUTF8 else { return nil }
520+
return try _guts.withFastUTF8(body)
521+
}
522+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: if [ %target-runtime == "objc" ]; \
3+
// RUN: then \
4+
// RUN: %target-clang -fobjc-arc %S/Inputs/NSSlowString/NSSlowString.m -c -o %t/NSSlowString.o && \
5+
// RUN: %target-build-swift -I %S/Inputs/NSSlowString/ %t/NSSlowString.o %s -o %t/String; \
6+
// RUN: else \
7+
// RUN: %target-build-swift %s -o %t/String; \
8+
// RUN: fi
9+
10+
// RUN: %target-codesign %t/String
11+
// RUN: %target-run %t/String
12+
// REQUIRES: executable_test
13+
// XFAIL: interpret
14+
15+
import StdlibUnittest
16+
import StdlibCollectionUnittest
17+
18+
#if _runtime(_ObjC)
19+
import NSSlowString
20+
import Foundation // For NSRange
21+
#endif
22+
23+
extension String {
24+
func withFastUTF8IfAvailable<R>(
25+
_ f: (UnsafeBufferPointer<UInt8>) throws -> R
26+
) rethrows -> R? {
27+
return try utf8.withContiguousStorageIfAvailable(f)
28+
}
29+
var isFastUTF8: Bool {
30+
return withFastUTF8IfAvailable({ _ in return 0 }) != nil
31+
}
32+
mutating func makeNative() { self += "" }
33+
34+
var isASCII: Bool { return utf8.allSatisfy { $0 < 0x7f } }
35+
}
36+
37+
var UTF8Tests = TestSuite("StringUTF8Tests")
38+
39+
var strings: Array<String> = [
40+
"abcd",
41+
"abcdefghijklmnop",
42+
"abcde\u{301}fghijk",
43+
"a\u{301}",
44+
"👻",
45+
"Spooky long string. 👻",
46+
"в чащах юга жил-был цитрус? да, но фальшивый экземпляр",
47+
"",
48+
]
49+
50+
let kCFStringEncodingASCII: UInt32 = 0x0600
51+
52+
UTF8Tests.test("Contiguous Access") {
53+
for string in strings {
54+
print(string)
55+
56+
// Native strings are contiguous UTF-8
57+
expectTrue(string.isFastUTF8)
58+
expectEqualSequence(
59+
Array(string.utf8), string.withFastUTF8IfAvailable(Array.init)!)
60+
61+
// FIXME: Bridge small non-ASCII as StringStorage
62+
// expectTrue(((string as NSString) as String).isFastUTF8)
63+
64+
var copy = string
65+
expectTrue(copy.isFastUTF8)
66+
copy.makeNative()
67+
expectTrue(copy.isFastUTF8)
68+
69+
// FIXME: Bridge small non-ASCII as StringStorage
70+
// expectTrue(((copy as NSString) as String).isFastUTF8)
71+
72+
#if _runtime(_ObjC)
73+
// Lazily bridged strings are not contiguous UTF-8
74+
var slowString = NSSlowString(string: string) as String
75+
expectFalse(slowString.isFastUTF8)
76+
expectEqualSequence(string.utf8, slowString.utf8)
77+
78+
// They become fast when mutated
79+
slowString.makeNative()
80+
expectTrue(slowString.isFastUTF8)
81+
expectEqualSequence(
82+
string.utf8, slowString.withFastUTF8IfAvailable(Array.init)!)
83+
84+
// Contiguous ASCII CFStrings provide access, even if lazily bridged
85+
if string.isASCII {
86+
let cfString = string.withCString {
87+
CFStringCreateWithCString(nil, $0, kCFStringEncodingASCII)!
88+
} as String
89+
expectTrue(cfString.isFastUTF8)
90+
expectEqualSequence(
91+
string.utf8, cfString.withFastUTF8IfAvailable(Array.init)!)
92+
}
93+
#endif
94+
}
95+
}
96+
97+
runAllTests()
98+

0 commit comments

Comments
 (0)