mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
225 lines
6.7 KiB
Swift
225 lines
6.7 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2018 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// TODO: describe
|
|
//
|
|
// HACK HACK HACK: For whatever reason, having this directly on String instead
|
|
// of _StringGuts avoids a cascade of ARC. Also note, we can have a global
|
|
// function that forwards, but that function **must not be on _StringGuts**,
|
|
// else ARC.
|
|
//
|
|
extension String {
|
|
@inlinable
|
|
@inline(__always)
|
|
func _visit<Result>(
|
|
range: (Range<Int>, performBoundsCheck: Bool)? = nil,
|
|
ascii: /*@convention(thin)*/ (_UnmanagedString<UInt8>) -> Result,
|
|
utf16: /*@convention(thin)*/ (_UnmanagedString<UInt16>) -> Result,
|
|
opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString) -> Result
|
|
) -> Result {
|
|
if _slowPath(_guts._isOpaque) {
|
|
return self._visitOpaque(
|
|
range: range, ascii: ascii, utf16: utf16, opaque: opaque)
|
|
}
|
|
|
|
defer { _fixLifetime(self) }
|
|
if _guts.isASCII {
|
|
var view = _guts._unmanagedASCIIView
|
|
if let (range, boundsCheck) = range {
|
|
if boundsCheck {
|
|
view._boundsCheck(offsetRange: range)
|
|
}
|
|
view = view[range]
|
|
}
|
|
return ascii(view)
|
|
} else {
|
|
var view = _guts._unmanagedUTF16View
|
|
if let (range, boundsCheck) = range {
|
|
if boundsCheck {
|
|
view._boundsCheck(offsetRange: range)
|
|
}
|
|
view = view[range]
|
|
}
|
|
return utf16(view)
|
|
}
|
|
}
|
|
|
|
@usableFromInline
|
|
@effects(readonly)
|
|
@inline(never) // @_outlined
|
|
func _visitOpaque<Result>(
|
|
range: (Range<Int>, performBoundsCheck: Bool)? = nil,
|
|
ascii: /*@convention(thin)*/ (_UnmanagedString<UInt8>) -> Result,
|
|
utf16: /*@convention(thin)*/ (_UnmanagedString<UInt16>) -> Result,
|
|
opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString) -> Result
|
|
) -> Result {
|
|
_sanityCheck(_guts._isOpaque)
|
|
|
|
if _guts._isSmall {
|
|
_sanityCheck(_guts._object._isSmallUTF8, "no other small forms yet")
|
|
let small = _guts._smallUTF8String
|
|
if small.isASCII {
|
|
return small.withUnmanagedASCII { view in
|
|
var view = view
|
|
if let (range, boundsCheck) = range {
|
|
if boundsCheck {
|
|
view._boundsCheck(offsetRange: range)
|
|
}
|
|
view = view[range]
|
|
}
|
|
return ascii(view)
|
|
}
|
|
}
|
|
return small.withUnmanagedUTF16 { view in
|
|
var view = view
|
|
if let (range, boundsCheck) = range {
|
|
if boundsCheck {
|
|
view._boundsCheck(offsetRange: range)
|
|
}
|
|
view = view[range]
|
|
}
|
|
return utf16(view)
|
|
}
|
|
}
|
|
|
|
// TODO: But can it provide a pointer+length representation?
|
|
defer { _fixLifetime(self) }
|
|
var view = _guts._asOpaque()
|
|
if let (range, boundsCheck) = range {
|
|
if boundsCheck {
|
|
view._boundsCheck(offsetRange: range)
|
|
}
|
|
view = view[range]
|
|
}
|
|
|
|
return opaque(view)
|
|
}
|
|
|
|
@inlinable
|
|
@inline(__always)
|
|
func _visit<T, Result>(
|
|
range: (Range<Int>, performBoundsCheck: Bool)?,
|
|
args x: T,
|
|
ascii: /*@convention(thin)*/ (_UnmanagedString<UInt8>, T) -> Result,
|
|
utf16: /*@convention(thin)*/ (_UnmanagedString<UInt16>, T) -> Result,
|
|
opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString, T) -> Result
|
|
) -> Result {
|
|
if _slowPath(_guts._isOpaque) {
|
|
return self._visitOpaque(
|
|
range: range, args: x, ascii: ascii, utf16: utf16, opaque: opaque)
|
|
}
|
|
|
|
defer { _fixLifetime(self) }
|
|
if _guts.isASCII {
|
|
var view = _guts._unmanagedASCIIView
|
|
if let (range, boundsCheck) = range {
|
|
if boundsCheck {
|
|
view._boundsCheck(offsetRange: range)
|
|
}
|
|
view = view[range]
|
|
}
|
|
return ascii(view, x)
|
|
} else {
|
|
var view = _guts._unmanagedUTF16View
|
|
if let (range, boundsCheck) = range {
|
|
if boundsCheck {
|
|
view._boundsCheck(offsetRange: range)
|
|
}
|
|
view = view[range]
|
|
}
|
|
return utf16(view, x)
|
|
}
|
|
}
|
|
|
|
@usableFromInline // @opaque
|
|
@effects(readonly)
|
|
@inline(never)
|
|
func _visitOpaque<T, Result>(
|
|
range: (Range<Int>, performBoundsCheck: Bool)?,
|
|
args x: T,
|
|
ascii: /*@convention(thin)*/ (_UnmanagedString<UInt8>, T) -> Result,
|
|
utf16: /*@convention(thin)*/ (_UnmanagedString<UInt16>, T) -> Result,
|
|
opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString, T) -> Result
|
|
) -> Result {
|
|
_sanityCheck(_guts._isOpaque)
|
|
|
|
if _fastPath(_guts._isSmall) {
|
|
_sanityCheck(_guts._object._isSmallUTF8, "no other small forms yet")
|
|
let small = _guts._smallUTF8String
|
|
if small.isASCII {
|
|
return small.withUnmanagedASCII { view in
|
|
var view = view
|
|
if let (range, boundsCheck) = range {
|
|
if boundsCheck {
|
|
view._boundsCheck(offsetRange: range)
|
|
}
|
|
view = view[range]
|
|
}
|
|
return ascii(view, x)
|
|
}
|
|
}
|
|
return small.withUnmanagedUTF16 { view in
|
|
var view = view
|
|
if let (range, boundsCheck) = range {
|
|
if boundsCheck {
|
|
view._boundsCheck(offsetRange: range)
|
|
}
|
|
view = view[range]
|
|
}
|
|
return utf16(view, x)
|
|
}
|
|
}
|
|
|
|
// TODO: But can it provide a pointer+length representation?
|
|
defer { _fixLifetime(self) }
|
|
var view = _guts._asOpaque()
|
|
if let (range, boundsCheck) = range {
|
|
if boundsCheck {
|
|
view._boundsCheck(offsetRange: range)
|
|
}
|
|
view = view[range]
|
|
}
|
|
|
|
return opaque(view, x)
|
|
}
|
|
}
|
|
|
|
@inlinable
|
|
@inline(__always)
|
|
internal
|
|
func _visitGuts<Result>(
|
|
_ guts: _StringGuts,
|
|
range: (Range<Int>, performBoundsCheck: Bool)? = nil,
|
|
ascii: /*@convention(thin)*/ (_UnmanagedString<UInt8>) -> Result,
|
|
utf16: /*@convention(thin)*/ (_UnmanagedString<UInt16>) -> Result,
|
|
opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString) -> Result
|
|
) -> Result {
|
|
return String(guts)._visit(
|
|
range: range, ascii: ascii, utf16: utf16, opaque: opaque)
|
|
}
|
|
|
|
@inlinable
|
|
@inline(__always)
|
|
internal
|
|
func _visitGuts<T, Result>(
|
|
_ guts: _StringGuts,
|
|
range: (Range<Int>, performBoundsCheck: Bool)? = nil,
|
|
args x: T,
|
|
ascii: /*@convention(thin)*/ (_UnmanagedString<UInt8>, T) -> Result,
|
|
utf16: /*@convention(thin)*/ (_UnmanagedString<UInt16>, T) -> Result,
|
|
opaque: /*@convention(thin)*/ (_UnmanagedOpaqueString, T) -> Result
|
|
) -> Result {
|
|
return String(guts)._visit(
|
|
range: range, args: x, ascii: ascii, utf16: utf16, opaque: opaque)
|
|
}
|
|
|