Skip to content

[6.2, SE-0456] enable span properties for the small-String representation #80742

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: release/6.2
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions stdlib/public/core/StringUTF8View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ extension String {
/// print(String(s1.utf8.prefix(15))!)
/// // Prints "They call me 'B"
@frozen
@_addressableForDependencies
public struct UTF8View: Sendable {
@usableFromInline
internal var _guts: _StringGuts
Expand Down Expand Up @@ -336,7 +337,7 @@ extension String.UTF8View {
borrowing get {
#if _runtime(_ObjC)
// handle non-UTF8 Objective-C bridging cases here
if !_guts.isFastUTF8 && _guts._object.hasObjCBridgeableObject {
if !_guts.isFastUTF8, _guts._object.hasObjCBridgeableObject {
let storage = _guts._getOrAllocateAssociatedStorage()
let (start, count) = unsafe (storage.start, storage.count)
let span = unsafe Span(_unsafeStart: start, count: count)
Expand All @@ -345,15 +346,14 @@ extension String.UTF8View {
#endif
let count = _guts.count
if _guts.isSmall {
fatalError("Span over the small string form is not supported yet.")
// let a = Builtin.addressOfBorrow(self)
// let address = unsafe UnsafePointer<UTF8.CodeUnit>(a)
// let span = unsafe Span(_unsafeStart: address, count: count)
// return unsafe _overrideLifetime(span, borrowing: self)
let a = Builtin.addressOfBorrow(self)
let address = unsafe UnsafePointer<UTF8.CodeUnit>(a)
let span = unsafe Span(_unsafeStart: address, count: count)
return unsafe _overrideLifetime(span, borrowing: self)
}
_precondition(_guts.isFastUTF8)
let isFastUTF8 = _guts.isFastUTF8
_precondition(isFastUTF8, "String must be contiguous UTF8")
let buffer = unsafe _guts._object.fastUTF8
_internalInvariant(count == buffer.count)
let span = unsafe Span(_unsafeElements: buffer)
return unsafe _overrideLifetime(span, borrowing: self)
}
Expand Down
19 changes: 10 additions & 9 deletions stdlib/public/core/Substring.swift
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ extension Substring: LosslessStringConvertible {

extension Substring {
@frozen
@_addressableForDependencies
public struct UTF8View: Sendable {
@usableFromInline
internal var _slice: Slice<String.UTF8View>
Expand Down Expand Up @@ -778,25 +779,25 @@ extension Substring.UTF8View {
borrowing get {
#if _runtime(_ObjC)
// handle non-UTF8 Objective-C bridging cases here
if !_wholeGuts.isFastUTF8 && _wholeGuts._object.hasObjCBridgeableObject {
if !_wholeGuts.isFastUTF8, _wholeGuts._object.hasObjCBridgeableObject {
let base: String.UTF8View = self._base
let first = base._foreignDistance(from: base.startIndex, to: startIndex)
let count = base._foreignDistance(from: startIndex, to: endIndex)
let span = base.span._extracting(first..<(first &+ count))
let span = unsafe base.span._extracting(first..<(first &+ count))
return unsafe _overrideLifetime(span, borrowing: self)
}
#endif
let first = _slice._startIndex._encodedOffset
let end = _slice._endIndex._encodedOffset
if _wholeGuts.isSmall {
fatalError("Span over the small string form is not supported yet.")
// let a = Builtin.addressOfBorrow(self)
// let offset = first &+ (2 &* MemoryLayout<String.Index>.stride)
// let start = unsafe UnsafePointer<UTF8.CodeUnit>(a).advanced(by: offset)
// let span = unsafe Span(_unsafeStart: start, count: end &- first)
// return unsafe _overrideLifetime(span, borrowing: self)
let a = Builtin.addressOfBorrow(self)
let offset = first &+ (2 &* MemoryLayout<String.Index>.stride)
let start = unsafe UnsafePointer<UTF8.CodeUnit>(a).advanced(by: offset)
let span = unsafe Span(_unsafeStart: start, count: end &- first)
return unsafe _overrideLifetime(span, borrowing: self)
}
_internalInvariant(_wholeGuts.isFastUTF8)
let isFastUTF8 = _wholeGuts.isFastUTF8
_precondition(isFastUTF8, "Substring must be contiguous UTF8")
var span = unsafe Span(_unsafeElements: _wholeGuts._object.fastUTF8)
span = span._extracting(first..<end)
return unsafe _overrideLifetime(span, borrowing: self)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,8 @@ Func ContiguousArray.withUnsafeMutableBufferPointer(_:) is now without rethrows

// Adoption of @_addressableForDependencies
Struct CollectionOfOne is now with @_addressableForDependencies
Struct String.UTF8View is now with @_addressableForDependencies
Struct Substring.UTF8View is now with @_addressableForDependencies

Protocol CodingKey has added inherited protocol SendableMetatype
Protocol Error has added inherited protocol SendableMetatype
Expand Down
2 changes: 2 additions & 0 deletions test/api-digester/stability-stdlib-abi-without-asserts.test
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,8 @@ Func _SliceBuffer.withUnsafeMutableBufferPointer(_:) has mangled name changing f
Struct String.Index has added a conformance to an existing protocol CustomDebugStringConvertible

Struct CollectionOfOne is now with @_addressableForDependencies
Struct String.UTF8View is now with @_addressableForDependencies
Struct Substring.UTF8View is now with @_addressableForDependencies

Enum _SwiftifyInfo is a new API without @available attribute
Enum _SwiftifyExpr is a new API without @available attribute
Expand Down
5 changes: 2 additions & 3 deletions test/stdlib/Span/BridgedStringUTF8ViewSpanTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@ let strings = [
"A long ASCII string exceeding 16 code units.",
"🇯🇵",
"🏂☃❅❆❄︎⛄️❄️",
// Enable the following once the small native string form is supported
// "z",
// "",
"z",
"",
]

strings.forEach { expected in
Expand Down
4 changes: 0 additions & 4 deletions test/stdlib/Span/StringUTF8SpanProperty.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,11 @@ var suite = TestSuite("StringUTF8StorageProperty")
defer { runAllTests() }

suite.test("Span from Small String")
.skip(.wasiAny(reason: "Trap tests aren't supported on WASI."))
.require(.stdlib_6_2).code {
guard #available(SwiftStdlib 6.2, *) else { return }

let s = "A small string.".utf8
let u = Array(s)
expectCrashLater()
let span = s.span

let count = span.count
Expand Down Expand Up @@ -56,13 +54,11 @@ suite.test("Span from Large Native String")
}

suite.test("Span from Small String's Substring")
.skip(.wasiAny(reason: "Trap tests aren't supported on WASI."))
.require(.stdlib_6_2).code {
guard #available(SwiftStdlib 6.2, *) else { return }

let s = "A small string.".dropFirst(8).utf8
let u = Array("string.".utf8)
expectCrashLater()
let span = s.span

let count = span.count
Expand Down