Use UnsafeRawPointer in StringCore.

This is another necessary step in introducing changes
for SE-0107: UnsafeRawPointer.

UnsafeRawPointer is great for bytewise pointer operations.

OpaquePointer goes away.

The _RawByte type goes away.

StringBuffer always binds memory to the correct CodeUnit
when allocating memory.

Before accessing the string, a dynamic element width check
allows us to assume the bound memory type.

Generic entry points like atomicCompareExchange no longer handle
both kinds of pointers. Normally that's good because you
should not be using generics in that case, just upcast
to raw pointer. However, with pointers-to-pointers
you can't do that.
This commit is contained in:
Andrew Trick
2016-07-26 18:28:39 -07:00
parent 3e2372b6a3
commit 9886e4ef54
12 changed files with 133 additions and 119 deletions

View File

@@ -35,7 +35,7 @@ vectorElementNames = [
public func _indexHomogeneousValue<TTT, T>(_ aggregate: UnsafePointer<TTT>, public func _indexHomogeneousValue<TTT, T>(_ aggregate: UnsafePointer<TTT>,
_ index: Int) -> T { _ index: Int) -> T {
return UnsafeRawPointer(aggregate).load( return UnsafeRawPointer(aggregate).load(
fromByteOffset: index * strideof(T), as: T.self) fromByteOffset: index * strideof(T.self), as: T.self)
} }
%{ %{

View File

@@ -183,7 +183,7 @@ public struct Character :
} }
else { else {
if let native = s._core.nativeBuffer, if let native = s._core.nativeBuffer,
native.start == UnsafeMutablePointer(s._core._baseAddress!) { native.start == s._core._baseAddress! {
_representation = .large(native._storage) _representation = .large(native._storage)
return return
} }

View File

@@ -20,19 +20,21 @@ import SwiftShims
// Atomics // Atomics
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
public typealias _PointerToPointer = UnsafeMutablePointer<UnsafeRawPointer?>
@_transparent @_transparent
public // @testable public // @testable
func _stdlib_atomicCompareExchangeStrongPtrImpl( func _stdlib_atomicCompareExchangeStrongPtr(
object target: UnsafeMutablePointer<UnsafeMutableRawPointer?>, object target: _PointerToPointer,
expected: UnsafeMutablePointer<UnsafeMutableRawPointer?>, expected: _PointerToPointer,
desired: UnsafeMutableRawPointer?) -> Bool { desired: UnsafeRawPointer?) -> Bool {
// We use Builtin.Word here because Builtin.RawPointer can't be nil. // We use Builtin.Word here because Builtin.RawPointer can't be nil.
let (oldValue, won) = Builtin.cmpxchg_seqcst_seqcst_Word( let (oldValue, won) = Builtin.cmpxchg_seqcst_seqcst_Word(
target._rawValue, target._rawValue,
UInt(bitPattern: expected.pointee)._builtinWordValue, UInt(bitPattern: expected.pointee)._builtinWordValue,
UInt(bitPattern: desired)._builtinWordValue) UInt(bitPattern: desired)._builtinWordValue)
expected.pointee = UnsafeMutableRawPointer(bitPattern: Int(oldValue)) expected.pointee = UnsafeRawPointer(bitPattern: Int(oldValue))
return Bool(won) return Bool(won)
} }
@@ -70,12 +72,12 @@ func _stdlib_atomicCompareExchangeStrongPtr<T>(
object target: UnsafeMutablePointer<UnsafeMutablePointer<T>${optional}>, object target: UnsafeMutablePointer<UnsafeMutablePointer<T>${optional}>,
expected: UnsafeMutablePointer<UnsafeMutablePointer<T>${optional}>, expected: UnsafeMutablePointer<UnsafeMutablePointer<T>${optional}>,
desired: UnsafeMutablePointer<T>${optional}) -> Bool { desired: UnsafeMutablePointer<T>${optional}) -> Bool {
return _stdlib_atomicCompareExchangeStrongPtrImpl( return _stdlib_atomicCompareExchangeStrongPtr(
object: UnsafeMutablePointer(target), object: unsafeBitCast(target, to: _PointerToPointer.self),
expected: UnsafeMutablePointer(expected), expected: unsafeBitCast(expected, to: _PointerToPointer.self),
desired: UnsafeMutablePointer(desired)) desired: unsafeBitCast(desired, to: Optional<UnsafeRawPointer>.self))
} }
% end % end # optional
@_transparent @_transparent
@discardableResult @discardableResult
@@ -83,10 +85,10 @@ public // @testable
func _stdlib_atomicInitializeARCRef( func _stdlib_atomicInitializeARCRef(
object target: UnsafeMutablePointer<AnyObject?>, object target: UnsafeMutablePointer<AnyObject?>,
desired: AnyObject) -> Bool { desired: AnyObject) -> Bool {
var expected: UnsafeMutableRawPointer? = nil var expected: UnsafeRawPointer? = nil
let desiredPtr = Unmanaged.passRetained(desired).toOpaque() let desiredPtr = Unmanaged.passRetained(desired).toOpaque()
let wonRace = _stdlib_atomicCompareExchangeStrongPtrImpl( let wonRace = _stdlib_atomicCompareExchangeStrongPtr(
object: UnsafeMutablePointer(target), object: unsafeBitCast(target, to: _PointerToPointer.self),
expected: &expected, expected: &expected,
desired: desiredPtr) desired: desiredPtr)
if !wonRace { if !wonRace {

View File

@@ -400,7 +400,7 @@ extension String : _ExpressibleByBuiltinUTF16StringLiteral {
) { ) {
self = String( self = String(
_StringCore( _StringCore(
baseAddress: OpaquePointer(start), baseAddress: UnsafeMutableRawPointer(start),
count: Int(utf16CodeUnitCount), count: Int(utf16CodeUnitCount),
elementShift: 1, elementShift: 1,
hasCocoaBuffer: false, hasCocoaBuffer: false,
@@ -418,7 +418,7 @@ extension String : _ExpressibleByBuiltinStringLiteral {
if Bool(isASCII) { if Bool(isASCII) {
self = String( self = String(
_StringCore( _StringCore(
baseAddress: OpaquePointer(start), baseAddress: UnsafeMutableRawPointer(start),
count: Int(utf8CodeUnitCount), count: Int(utf8CodeUnitCount),
elementShift: 0, elementShift: 0,
hasCocoaBuffer: false, hasCocoaBuffer: false,
@@ -699,13 +699,15 @@ extension String : Hashable {
} }
#else #else
if self._core.isASCII { if self._core.isASCII {
return _swift_stdlib_unicode_hash_ascii( return _core.startASCII.withMemoryRebound(
UnsafeMutablePointer<Int8>(_core.startASCII), to: CChar.self, capacity: _core.count) {
Int32(_core.count)) _swift_stdlib_unicode_hash_ascii($0, Int32(_core.count))
}
} else { } else {
return _swift_stdlib_unicode_hash( return _core.startUTF16.withMemoryRebound(
UnsafeMutablePointer<UInt16>(_core.startUTF16), to: UInt16.self, capacity: _core.count) {
Int32(_core.count)) _swift_stdlib_unicode_hash($0, Int32(_core.count))
}
} }
#endif #endif
} }
@@ -821,7 +823,8 @@ internal func _nativeUnicodeLowercaseString(_ str: String) -> String {
capacity: str._core.count, initialSize: str._core.count, elementWidth: 2) capacity: str._core.count, initialSize: str._core.count, elementWidth: 2)
// Try to write it out to the same length. // Try to write it out to the same length.
let dest = UnsafeMutablePointer<UTF16.CodeUnit>(buffer.start) let dest = buffer.start.bindMemory(
to: UTF16.CodeUnit.self, capacity: str._core.count)
let z = _swift_stdlib_unicode_strToLower( let z = _swift_stdlib_unicode_strToLower(
dest, Int32(str._core.count), dest, Int32(str._core.count),
str._core.startUTF16, Int32(str._core.count)) str._core.startUTF16, Int32(str._core.count))
@@ -831,7 +834,8 @@ internal func _nativeUnicodeLowercaseString(_ str: String) -> String {
if correctSize != str._core.count { if correctSize != str._core.count {
buffer = _StringBuffer( buffer = _StringBuffer(
capacity: correctSize, initialSize: correctSize, elementWidth: 2) capacity: correctSize, initialSize: correctSize, elementWidth: 2)
let dest = UnsafeMutablePointer<UTF16.CodeUnit>(buffer.start) let dest = buffer.start.bindMemory(
to: UTF16.CodeUnit.self, capacity: str._core.count)
_swift_stdlib_unicode_strToLower( _swift_stdlib_unicode_strToLower(
dest, Int32(correctSize), str._core.startUTF16, Int32(str._core.count)) dest, Int32(correctSize), str._core.startUTF16, Int32(str._core.count))
} }
@@ -844,7 +848,8 @@ internal func _nativeUnicodeUppercaseString(_ str: String) -> String {
capacity: str._core.count, initialSize: str._core.count, elementWidth: 2) capacity: str._core.count, initialSize: str._core.count, elementWidth: 2)
// Try to write it out to the same length. // Try to write it out to the same length.
let dest = UnsafeMutablePointer<UTF16.CodeUnit>(buffer.start) let dest = buffer.start.bindMemory(
to: UTF16.CodeUnit.self, capacity: str._core.count)
let z = _swift_stdlib_unicode_strToUpper( let z = _swift_stdlib_unicode_strToUpper(
dest, Int32(str._core.count), dest, Int32(str._core.count),
str._core.startUTF16, Int32(str._core.count)) str._core.startUTF16, Int32(str._core.count))
@@ -854,7 +859,8 @@ internal func _nativeUnicodeUppercaseString(_ str: String) -> String {
if correctSize != str._core.count { if correctSize != str._core.count {
buffer = _StringBuffer( buffer = _StringBuffer(
capacity: correctSize, initialSize: correctSize, elementWidth: 2) capacity: correctSize, initialSize: correctSize, elementWidth: 2)
let dest = UnsafeMutablePointer<UTF16.CodeUnit>(buffer.start) let dest = buffer.start.bindMemory(
to: UTF16.CodeUnit.self, capacity: str._core.count)
_swift_stdlib_unicode_strToUpper( _swift_stdlib_unicode_strToUpper(
dest, Int32(correctSize), str._core.startUTF16, Int32(str._core.count)) dest, Int32(correctSize), str._core.startUTF16, Int32(str._core.count))
} }
@@ -904,7 +910,7 @@ extension String {
let source = self._core.startASCII let source = self._core.startASCII
let buffer = _StringBuffer( let buffer = _StringBuffer(
capacity: count, initialSize: count, elementWidth: 1) capacity: count, initialSize: count, elementWidth: 1)
let dest = UnsafeMutablePointer<UInt8>(buffer.start) let dest = buffer.start
for i in 0..<count { for i in 0..<count {
// For each character in the string, we lookup if it should be shifted // For each character in the string, we lookup if it should be shifted
// in our ascii table, then we return 0x20 if it should, 0x0 if not. // in our ascii table, then we return 0x20 if it should, 0x0 if not.
@@ -923,7 +929,8 @@ extension String {
// Since we are left with either 0x0 or 0x20, we can safely truncate to // Since we are left with either 0x0 or 0x20, we can safely truncate to
// a UInt8 and add to our ASCII value (this will not overflow numbers in // a UInt8 and add to our ASCII value (this will not overflow numbers in
// the ASCII range). // the ASCII range).
dest[i] = value &+ UInt8(truncatingBitPattern: add) dest.storeBytes(of: value &+ UInt8(truncatingBitPattern: add),
toByteOffset: i, as: UInt8.self)
} }
return String(_storage: buffer) return String(_storage: buffer)
} }
@@ -953,7 +960,7 @@ extension String {
let source = self._core.startASCII let source = self._core.startASCII
let buffer = _StringBuffer( let buffer = _StringBuffer(
capacity: count, initialSize: count, elementWidth: 1) capacity: count, initialSize: count, elementWidth: 1)
let dest = UnsafeMutablePointer<UInt8>(buffer.start) let dest = buffer.start
for i in 0..<count { for i in 0..<count {
// See the comment above in lowercaseString. // See the comment above in lowercaseString.
let value = source[i] let value = source[i]
@@ -961,7 +968,8 @@ extension String {
_asciiLowerCaseTable >> _asciiLowerCaseTable >>
UInt64(((value &- 1) & 0b0111_1111) >> 1) UInt64(((value &- 1) & 0b0111_1111) >> 1)
let add = (isLower & 0x1) << 5 let add = (isLower & 0x1) << 5
dest[i] = value &- UInt8(truncatingBitPattern: add) dest.storeBytes(of: value &- UInt8(truncatingBitPattern: add),
toByteOffset: i, as: UInt8.self)
} }
return String(_storage: buffer) return String(_storage: buffer)
} }

View File

@@ -54,7 +54,7 @@ func _cocoaStringToSwiftString_NonASCII(
let start = _stdlib_binary_CFStringGetCharactersPtr(cfImmutableValue) let start = _stdlib_binary_CFStringGetCharactersPtr(cfImmutableValue)
return String(_StringCore( return String(_StringCore(
baseAddress: OpaquePointer(start), baseAddress: start,
count: length, count: length,
elementShift: 1, elementShift: 1,
hasCocoaBuffer: true, hasCocoaBuffer: true,
@@ -81,7 +81,7 @@ internal func _cocoaStringToContiguous(
_swift_stdlib_CFStringGetCharacters( _swift_stdlib_CFStringGetCharacters(
source, _swift_shims_CFRange(location: startIndex, length: count), source, _swift_shims_CFRange(location: startIndex, length: count),
UnsafeMutablePointer<_swift_shims_UniChar>(buffer.start)) buffer.start.assumingMemoryBound(to: _swift_shims_UniChar.self))
return buffer return buffer
} }
@@ -163,13 +163,13 @@ extension String {
// start will hold the base pointer of contiguous storage, if it // start will hold the base pointer of contiguous storage, if it
// is found. // is found.
var start: OpaquePointer? var start: UnsafeMutableRawPointer?
let isUTF16 = (nulTerminatedASCII == nil) let isUTF16 = (nulTerminatedASCII == nil)
if isUTF16 { if isUTF16 {
let utf16Buf = _swift_stdlib_CFStringGetCharactersPtr(cfImmutableValue) let utf16Buf = _swift_stdlib_CFStringGetCharactersPtr(cfImmutableValue)
start = OpaquePointer(utf16Buf) start = UnsafeMutableRawPointer(mutating: utf16Buf)
} else { } else {
start = OpaquePointer(nulTerminatedASCII) start = UnsafeMutableRawPointer(mutating: nulTerminatedASCII)
} }
self._core = _StringCore( self._core = _StringCore(

View File

@@ -19,7 +19,7 @@ struct _StringBufferIVars {
} }
internal init( internal init(
_usedEnd: UnsafeMutablePointer<_RawByte>, _usedEnd: UnsafeMutableRawPointer,
byteCapacity: Int, byteCapacity: Int,
elementWidth: Int elementWidth: Int
) { ) {
@@ -31,7 +31,7 @@ struct _StringBufferIVars {
// This stored property should be stored at offset zero. We perform atomic // This stored property should be stored at offset zero. We perform atomic
// operations on it using _HeapBuffer's pointer. // operations on it using _HeapBuffer's pointer.
var usedEnd: UnsafeMutablePointer<_RawByte>? var usedEnd: UnsafeMutableRawPointer?
var capacityAndElementShift: Int var capacityAndElementShift: Int
var byteCapacity: Int { var byteCapacity: Int {
@@ -78,6 +78,14 @@ public struct _StringBuffer {
_StringBufferIVars(_elementWidth: elementWidth), _StringBufferIVars(_elementWidth: elementWidth),
(capacity + capacityBump + divRound) >> divRound (capacity + capacityBump + divRound) >> divRound
) )
// This conditional branch should fold away during code gen.
if elementShift == 0 {
start.bindMemory(to: UTF8.CodeUnit.self, capacity: initialSize)
}
else {
start.bindMemory(to: UTF16.CodeUnit.self, capacity: initialSize)
}
self.usedEnd = start + (initialSize << elementShift) self.usedEnd = start + (initialSize << elementShift)
_storage.value.capacityAndElementShift _storage.value.capacityAndElementShift
= ((_storage._capacity() - capacityBump) << 1) + elementShift = ((_storage._capacity() - capacityBump) << 1) + elementShift
@@ -107,7 +115,7 @@ public struct _StringBuffer {
elementWidth: isAscii ? 1 : 2) elementWidth: isAscii ? 1 : 2)
if isAscii { if isAscii {
var p = UnsafeMutablePointer<UTF8.CodeUnit>(result.start) var p = result.start.assumingMemoryBound(to: UTF8.CodeUnit.self)
let sink: (UTF32.CodeUnit) -> Void = { let sink: (UTF32.CodeUnit) -> Void = {
p.pointee = UTF8.CodeUnit($0) p.pointee = UTF8.CodeUnit($0)
p += 1 p += 1
@@ -137,12 +145,12 @@ public struct _StringBuffer {
/// A pointer to the start of this buffer's data area. /// A pointer to the start of this buffer's data area.
public // @testable public // @testable
var start: UnsafeMutablePointer<_RawByte> { var start: UnsafeMutableRawPointer {
return UnsafeMutablePointer(_storage.baseAddress) return UnsafeMutableRawPointer(_storage.baseAddress)
} }
/// A past-the-end pointer for this buffer's stored data. /// A past-the-end pointer for this buffer's stored data.
var usedEnd: UnsafeMutablePointer<_RawByte> { var usedEnd: UnsafeMutableRawPointer {
get { get {
return _storage.value.usedEnd! return _storage.value.usedEnd!
} }
@@ -156,7 +164,7 @@ public struct _StringBuffer {
} }
/// A past-the-end pointer for this buffer's available storage. /// A past-the-end pointer for this buffer's available storage.
var capacityEnd: UnsafeMutablePointer<_RawByte> { var capacityEnd: UnsafeMutableRawPointer {
return start + _storage.value.byteCapacity return start + _storage.value.byteCapacity
} }
@@ -181,11 +189,11 @@ public struct _StringBuffer {
// two separate phases. Operations with one-phase growth should use // two separate phases. Operations with one-phase growth should use
// "grow()," below. // "grow()," below.
func hasCapacity( func hasCapacity(
_ cap: Int, forSubRange r: Range<UnsafePointer<_RawByte>> _ cap: Int, forSubRange r: Range<UnsafeRawPointer>
) -> Bool { ) -> Bool {
// The substring to be grown could be pointing in the middle of this // The substring to be grown could be pointing in the middle of this
// _StringBuffer. // _StringBuffer.
let offset = (r.lowerBound - UnsafePointer(start)) >> elementShift let offset = (r.lowerBound - UnsafeRawPointer(start)) >> elementShift
return cap + offset <= capacity return cap + offset <= capacity
} }
@@ -202,13 +210,14 @@ public struct _StringBuffer {
@inline(__always) @inline(__always)
@discardableResult @discardableResult
mutating func grow( mutating func grow(
oldBounds bounds: Range<UnsafePointer<_RawByte>>, newUsedCount: Int oldBounds bounds: Range<UnsafeRawPointer>, newUsedCount: Int
) -> Bool { ) -> Bool {
var newUsedCount = newUsedCount var newUsedCount = newUsedCount
// The substring to be grown could be pointing in the middle of this // The substring to be grown could be pointing in the middle of this
// _StringBuffer. Adjust the size so that it covers the imaginary // _StringBuffer. Adjust the size so that it covers the imaginary
// substring from the start of the buffer to `oldUsedEnd`. // substring from the start of the buffer to `oldUsedEnd`.
newUsedCount += (bounds.lowerBound - UnsafePointer(start)) >> elementShift newUsedCount
+= (bounds.lowerBound - UnsafeRawPointer(start)) >> elementShift
if _slowPath(newUsedCount > capacity) { if _slowPath(newUsedCount > capacity) {
return false return false
@@ -230,11 +239,14 @@ public struct _StringBuffer {
// usedEnd = newUsedEnd // usedEnd = newUsedEnd
// return true // return true
// } // }
let usedEndPhysicalPtr =
UnsafeMutablePointer<UnsafeMutablePointer<_RawByte>>(_storage._value) // &StringBufferIVars.usedEnd
var expected = UnsafeMutablePointer<_RawByte>(bounds.upperBound) let usedEndPhysicalPtr = _PointerToPointer(_storage._value)
// Create a temp var to hold the exchanged `expected` value.
var expected : UnsafeRawPointer? = bounds.upperBound
if _stdlib_atomicCompareExchangeStrongPtr( if _stdlib_atomicCompareExchangeStrongPtr(
object: usedEndPhysicalPtr, expected: &expected, desired: newUsedEnd) { object: usedEndPhysicalPtr, expected: &expected,
desired: UnsafeRawPointer(newUsedEnd)) {
return true return true
} }

View File

@@ -28,13 +28,13 @@
public struct _StringCore { public struct _StringCore {
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// Internals // Internals
public var _baseAddress: OpaquePointer? public var _baseAddress: UnsafeMutableRawPointer?
var _countAndFlags: UInt var _countAndFlags: UInt
public var _owner: AnyObject? public var _owner: AnyObject?
/// (private) create the implementation of a string from its component parts. /// (private) create the implementation of a string from its component parts.
init( init(
baseAddress: OpaquePointer?, baseAddress: UnsafeMutableRawPointer?,
_countAndFlags: UInt, _countAndFlags: UInt,
owner: AnyObject? owner: AnyObject?
) { ) {
@@ -68,10 +68,9 @@ public struct _StringCore {
_sanityCheck(!hasCocoaBuffer) _sanityCheck(!hasCocoaBuffer)
_sanityCheck(elementWidth == buffer.elementWidth, _sanityCheck(elementWidth == buffer.elementWidth,
"_StringCore elementWidth doesn't match its buffer's") "_StringCore elementWidth doesn't match its buffer's")
_sanityCheck(UnsafeMutablePointer(_baseAddress!) >= buffer.start) _sanityCheck(_baseAddress! >= buffer.start)
_sanityCheck(UnsafeMutablePointer(_baseAddress!) <= buffer.usedEnd) _sanityCheck(_baseAddress! <= buffer.usedEnd)
_sanityCheck( _sanityCheck(_pointer(toElementAt: count) <= buffer.usedEnd)
UnsafeMutablePointer(_pointer(toElementAt: count)) <= buffer.usedEnd)
} }
#endif #endif
} }
@@ -97,29 +96,28 @@ public struct _StringCore {
/// storage. Caveats: The string must have contiguous storage; the /// storage. Caveats: The string must have contiguous storage; the
/// element may be 1 or 2 bytes wide, depending on elementWidth; the /// element may be 1 or 2 bytes wide, depending on elementWidth; the
/// result may be null if the string is empty. /// result may be null if the string is empty.
func _pointer(toElementAt n: Int) -> OpaquePointer { func _pointer(toElementAt n: Int) -> UnsafeMutableRawPointer {
_sanityCheck(hasContiguousStorage && n >= 0 && n <= count) _sanityCheck(hasContiguousStorage && n >= 0 && n <= count)
return OpaquePointer( return _baseAddress! + (n << elementShift)
UnsafeMutablePointer<_RawByte>(_baseAddress!) + (n << elementShift))
} }
static func _copyElements( static func _copyElements(
_ srcStart: OpaquePointer, srcElementWidth: Int, _ srcStart: UnsafeMutableRawPointer, srcElementWidth: Int,
dstStart: OpaquePointer, dstElementWidth: Int, dstStart: UnsafeMutableRawPointer, dstElementWidth: Int,
count: Int count: Int
) { ) {
// Copy the old stuff into the new storage // Copy the old stuff into the new storage
if _fastPath(srcElementWidth == dstElementWidth) { if _fastPath(srcElementWidth == dstElementWidth) {
// No change in storage width; we can use memcpy // No change in storage width; we can use memcpy
_memcpy( _memcpy(
dest: UnsafeMutablePointer(dstStart), dest: dstStart,
src: UnsafeMutablePointer(srcStart), src: srcStart,
size: UInt(count << (srcElementWidth - 1))) size: UInt(count << (srcElementWidth - 1)))
} }
else if (srcElementWidth < dstElementWidth) { else if (srcElementWidth < dstElementWidth) {
// Widening ASCII to UTF-16; we need to copy the bytes manually // Widening ASCII to UTF-16; we need to copy the bytes manually
var dest = UnsafeMutablePointer<UTF16.CodeUnit>(dstStart) var dest = dstStart.assumingMemoryBound(to: UTF16.CodeUnit.self)
var src = UnsafeMutablePointer<UTF8.CodeUnit>(srcStart) var src = srcStart.assumingMemoryBound(to: UTF8.CodeUnit.self)
let srcEnd = src + count let srcEnd = src + count
while (src != srcEnd) { while (src != srcEnd) {
dest.pointee = UTF16.CodeUnit(src.pointee) dest.pointee = UTF16.CodeUnit(src.pointee)
@@ -129,8 +127,8 @@ public struct _StringCore {
} }
else { else {
// Narrowing UTF-16 to ASCII; we need to copy the bytes manually // Narrowing UTF-16 to ASCII; we need to copy the bytes manually
var dest = UnsafeMutablePointer<UTF8.CodeUnit>(dstStart) var dest = dstStart.assumingMemoryBound(to: UTF8.CodeUnit.self)
var src = UnsafeMutablePointer<UTF16.CodeUnit>(srcStart) var src = srcStart.assumingMemoryBound(to: UTF16.CodeUnit.self)
let srcEnd = src + count let srcEnd = src + count
while (src != srcEnd) { while (src != srcEnd) {
dest.pointee = UTF8.CodeUnit(src.pointee) dest.pointee = UTF8.CodeUnit(src.pointee)
@@ -143,7 +141,7 @@ public struct _StringCore {
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// Initialization // Initialization
public init( public init(
baseAddress: OpaquePointer?, baseAddress: UnsafeMutableRawPointer?,
count: Int, count: Int,
elementShift: Int, elementShift: Int,
hasCocoaBuffer: Bool, hasCocoaBuffer: Bool,
@@ -165,7 +163,7 @@ public struct _StringCore {
/// Create a _StringCore that covers the entire length of the _StringBuffer. /// Create a _StringCore that covers the entire length of the _StringBuffer.
init(_ buffer: _StringBuffer) { init(_ buffer: _StringBuffer) {
self = _StringCore( self = _StringCore(
baseAddress: OpaquePointer(buffer.start), baseAddress: buffer.start,
count: buffer.usedCount, count: buffer.usedCount,
elementShift: buffer.elementShift, elementShift: buffer.elementShift,
hasCocoaBuffer: false, hasCocoaBuffer: false,
@@ -199,7 +197,7 @@ public struct _StringCore {
} }
/// Left shift amount to apply to an offset N so that when /// Left shift amount to apply to an offset N so that when
/// added to a UnsafeMutablePointer<_RawByte>, it traverses N elements. /// added to a UnsafeMutableRawPointer, it traverses N elements.
var elementShift: Int { var elementShift: Int {
return Int(_countAndFlags >> (UInt._sizeInBits - 1)) return Int(_countAndFlags >> (UInt._sizeInBits - 1))
} }
@@ -227,7 +225,7 @@ public struct _StringCore {
public var startASCII: UnsafeMutablePointer<UTF8.CodeUnit> { public var startASCII: UnsafeMutablePointer<UTF8.CodeUnit> {
_sanityCheck(elementWidth == 1, "String does not contain contiguous ASCII") _sanityCheck(elementWidth == 1, "String does not contain contiguous ASCII")
return UnsafeMutablePointer(_baseAddress!) return _baseAddress!.assumingMemoryBound(to: UTF8.CodeUnit.self)
} }
/// True iff a contiguous ASCII buffer available. /// True iff a contiguous ASCII buffer available.
@@ -239,7 +237,7 @@ public struct _StringCore {
_sanityCheck( _sanityCheck(
count == 0 || elementWidth == 2, count == 0 || elementWidth == 2,
"String does not contain contiguous UTF-16") "String does not contain contiguous UTF-16")
return UnsafeMutablePointer(_baseAddress!) return _baseAddress!.assumingMemoryBound(to: UTF16.CodeUnit.self)
} }
/// the native _StringBuffer, if any, or `nil`. /// the native _StringBuffer, if any, or `nil`.
@@ -336,7 +334,7 @@ public struct _StringCore {
if _fastPath(_baseAddress != nil) { if _fastPath(_baseAddress != nil) {
if _fastPath(elementWidth == 1) { if _fastPath(elementWidth == 1) {
for x in UnsafeBufferPointer( for x in UnsafeBufferPointer(
start: UnsafeMutablePointer<UTF8.CodeUnit>(_baseAddress!), start: _baseAddress!.assumingMemoryBound(to: UTF8.CodeUnit.self),
count: count count: count
) { ) {
Encoding.encode(UnicodeScalar(x), into: processCodeUnit) Encoding.encode(UnicodeScalar(x), into: processCodeUnit)
@@ -345,7 +343,7 @@ public struct _StringCore {
else { else {
let hadError = transcode( let hadError = transcode(
UnsafeBufferPointer( UnsafeBufferPointer(
start: UnsafeMutablePointer<UTF16.CodeUnit>(_baseAddress!), start: _baseAddress!.assumingMemoryBound(to: UTF16.CodeUnit.self),
count: count count: count
).makeIterator(), ).makeIterator(),
from: UTF16.self, from: UTF16.self,
@@ -381,7 +379,7 @@ public struct _StringCore {
/// existing buffer, the suggested new capacity will at least double /// existing buffer, the suggested new capacity will at least double
/// the existing buffer's storage. /// the existing buffer's storage.
mutating func _claimCapacity( mutating func _claimCapacity(
_ newSize: Int, minElementWidth: Int) -> (Int, OpaquePointer?) { _ newSize: Int, minElementWidth: Int) -> (Int, UnsafeMutableRawPointer?) {
if _fastPath((nativeBuffer != nil) && elementWidth >= minElementWidth) { if _fastPath((nativeBuffer != nil) && elementWidth >= minElementWidth) {
var buffer = nativeBuffer! var buffer = nativeBuffer!
@@ -394,7 +392,7 @@ public struct _StringCore {
// Attempt to claim unused capacity in the buffer // Attempt to claim unused capacity in the buffer
if _fastPath( if _fastPath(
buffer.grow( buffer.grow(
oldBounds: UnsafePointer(usedStart)..<UnsafePointer(usedEnd), oldBounds: UnsafeRawPointer(usedStart)..<UnsafeRawPointer(usedEnd),
newUsedCount: newSize) newUsedCount: newSize)
) { ) {
count = newSize count = newSize
@@ -415,7 +413,7 @@ public struct _StringCore {
/// you must immediately copy valid data into that storage. /// you must immediately copy valid data into that storage.
mutating func _growBuffer( mutating func _growBuffer(
_ newSize: Int, minElementWidth: Int _ newSize: Int, minElementWidth: Int
) -> OpaquePointer { ) -> UnsafeMutableRawPointer {
let (newCapacity, existingStorage) let (newCapacity, existingStorage)
= _claimCapacity(newSize, minElementWidth: minElementWidth) = _claimCapacity(newSize, minElementWidth: minElementWidth)
@@ -455,7 +453,7 @@ public struct _StringCore {
if hasContiguousStorage { if hasContiguousStorage {
_StringCore._copyElements( _StringCore._copyElements(
_baseAddress!, srcElementWidth: elementWidth, _baseAddress!, srcElementWidth: elementWidth,
dstStart: OpaquePointer(newStorage.start), dstStart: UnsafeMutableRawPointer(newStorage.start),
dstElementWidth: newElementWidth, count: oldCount) dstElementWidth: newElementWidth, count: oldCount)
} }
else { else {
@@ -465,7 +463,8 @@ public struct _StringCore {
// FIXME: can we get Cocoa to tell us quickly that an opaque // FIXME: can we get Cocoa to tell us quickly that an opaque
// string is ASCII? Do we care much about that edge case? // string is ASCII? Do we care much about that edge case?
_sanityCheck(newStorage.elementShift == 1) _sanityCheck(newStorage.elementShift == 1)
_cocoaStringReadAll(cocoaBuffer!, UnsafeMutablePointer(newStorage.start)) _cocoaStringReadAll(cocoaBuffer!,
newStorage.start.assumingMemoryBound(to: UTF16.CodeUnit.self))
#else #else
_sanityCheckFailure("_copyInPlace: non-native string without objc runtime") _sanityCheckFailure("_copyInPlace: non-native string without objc runtime")
#endif #endif
@@ -502,15 +501,14 @@ public struct _StringCore {
count + utf16Width, minElementWidth: minBytesPerCodeUnit) count + utf16Width, minElementWidth: minBytesPerCodeUnit)
if _fastPath(elementWidth == 1) { if _fastPath(elementWidth == 1) {
_sanityCheck( _sanityCheck(_pointer(toElementAt:count) == destination + 1)
_pointer(toElementAt:count)
== OpaquePointer(UnsafeMutablePointer<_RawByte>(destination) + 1))
UnsafeMutablePointer<UTF8.CodeUnit>(destination)[0] = UTF8.CodeUnit(u0) destination.assumingMemoryBound(to: UTF8.CodeUnit.self)[0]
= UTF8.CodeUnit(u0)
} }
else { else {
let destination16 let destination16
= UnsafeMutablePointer<UTF16.CodeUnit>(destination._rawValue) = destination.assumingMemoryBound(to: UTF16.CodeUnit.self)
destination16[0] = u0 destination16[0] = u0
if u1 != nil { if u1 != nil {
@@ -539,7 +537,8 @@ public struct _StringCore {
else { else {
#if _runtime(_ObjC) #if _runtime(_ObjC)
_sanityCheck(elementWidth == 2) _sanityCheck(elementWidth == 2)
_cocoaStringReadAll(rhs.cocoaBuffer!, UnsafeMutablePointer(destination)) _cocoaStringReadAll(rhs.cocoaBuffer!,
destination.assumingMemoryBound(to: UTF16.CodeUnit.self))
#else #else
_sanityCheckFailure("subscript: non-native string without objc runtime") _sanityCheckFailure("subscript: non-native string without objc runtime")
#endif #endif
@@ -560,7 +559,7 @@ public struct _StringCore {
} }
let unsafeBuffer = let unsafeBuffer =
UnsafeBufferPointer( UnsafeBufferPointer(
start: UnsafeMutablePointer<UTF16.CodeUnit>(_baseAddress), start: _baseAddress!.assumingMemoryBound(to: UTF16.CodeUnit.self),
count: count) count: count)
return !unsafeBuffer.contains { $0 > 0x7f } return !unsafeBuffer.contains { $0 > 0x7f }
} }
@@ -618,24 +617,23 @@ extension _StringCore : RangeReplaceableCollection {
) ? _claimCapacity(newCount, minElementWidth: width).1 : nil ) ? _claimCapacity(newCount, minElementWidth: width).1 : nil
if _fastPath(existingStorage != nil) { if _fastPath(existingStorage != nil) {
let rangeStart = UnsafeMutablePointer<UInt8>( let rangeStart = _pointer(toElementAt:bounds.lowerBound)
_pointer(toElementAt:bounds.lowerBound))
let tailStart = rangeStart + (replacedCount << elementShift) let tailStart = rangeStart + (replacedCount << elementShift)
if growth > 0 { if growth > 0 {
(tailStart + (growth << elementShift)).assign( (tailStart + (growth << elementShift)).copyBytes(
from: tailStart, count: tailCount << elementShift) from: tailStart, count: tailCount << elementShift)
} }
if _fastPath(elementWidth == 1) { if _fastPath(elementWidth == 1) {
var dst = rangeStart var dst = rangeStart.assumingMemoryBound(to: UTF8.CodeUnit.self)
for u in newElements { for u in newElements {
dst.pointee = UInt8(truncatingBitPattern: u) dst.pointee = UInt8(truncatingBitPattern: u)
dst += 1 dst += 1
} }
} }
else { else {
var dst = UnsafeMutablePointer<UTF16.CodeUnit>(rangeStart) var dst = rangeStart.assumingMemoryBound(to: UTF16.CodeUnit.self)
for u in newElements { for u in newElements {
dst.pointee = u dst.pointee = u
dst += 1 dst += 1
@@ -643,7 +641,7 @@ extension _StringCore : RangeReplaceableCollection {
} }
if growth < 0 { if growth < 0 {
(tailStart + (growth << elementShift)).assign( (tailStart + (growth << elementShift)).copyBytes(
from: tailStart, count: tailCount << elementShift) from: tailStart, count: tailCount << elementShift)
} }
} }
@@ -668,8 +666,9 @@ extension _StringCore : RangeReplaceableCollection {
if _fastPath(!hasCocoaBuffer) { if _fastPath(!hasCocoaBuffer) {
if _fastPath(isKnownUniquelyReferenced(&_owner)) { if _fastPath(isKnownUniquelyReferenced(&_owner)) {
let bounds: Range<UnsafePointer<_RawByte>> let bounds: Range<UnsafeRawPointer>
= UnsafePointer(_pointer(toElementAt:0))..<UnsafePointer(_pointer(toElementAt:count)) = UnsafeRawPointer(_pointer(toElementAt:0))
..< UnsafeRawPointer(_pointer(toElementAt:count))
if _fastPath(nativeBuffer!.hasCapacity(n, forSubRange: bounds)) { if _fastPath(nativeBuffer!.hasCapacity(n, forSubRange: bounds)) {
return return
@@ -700,13 +699,15 @@ extension _StringCore : RangeReplaceableCollection {
let newSize = count + growth let newSize = count + growth
let destination = _growBuffer(newSize, minElementWidth: width) let destination = _growBuffer(newSize, minElementWidth: width)
if elementWidth == 1 { if elementWidth == 1 {
let destination8 = UnsafeMutablePointer<UTF8.CodeUnit>(destination) let destination8
= destination.assumingMemoryBound(to: UTF8.CodeUnit.self)
for i in 0..<growth { for i in 0..<growth {
destination8[i] = UTF8.CodeUnit(iter.next()!) destination8[i] = UTF8.CodeUnit(iter.next()!)
} }
} }
else { else {
let destination16 = UnsafeMutablePointer<UTF16.CodeUnit>(destination) let destination16
= destination.assumingMemoryBound(to: UTF16.CodeUnit.self)
for i in 0..<growth { for i in 0..<growth {
destination16[i] = iter.next()! destination16[i] = iter.next()!
} }
@@ -723,7 +724,6 @@ extension _StringCore : RangeReplaceableCollection {
// storage have a non-NULL base address. // storage have a non-NULL base address.
var _emptyStringStorage: UInt32 = 0 var _emptyStringStorage: UInt32 = 0
var _emptyStringBase: OpaquePointer { var _emptyStringBase: UnsafeMutableRawPointer {
return OpaquePointer( return UnsafeMutableRawPointer(Builtin.addressof(&_emptyStringStorage))
UnsafeMutablePointer<UInt16>(Builtin.addressof(&_emptyStringStorage)))
} }

View File

@@ -43,8 +43,8 @@ extension _StringCore {
var result: _UTF8Chunk = ~0 // Start with all bits set var result: _UTF8Chunk = ~0 // Start with all bits set
_memcpy( _memcpy(
dest: UnsafeMutablePointer(Builtin.addressof(&result)), dest: UnsafeMutableRawPointer(Builtin.addressof(&result)),
src: UnsafeMutablePointer(startASCII + i), src: startASCII + i,
size: numericCast(utf16Count)) size: numericCast(utf16Count))
// Convert the _UTF8Chunk into host endianness. // Convert the _UTF8Chunk into host endianness.

View File

@@ -204,13 +204,15 @@ extension String {
self._baseSet = true self._baseSet = true
if _base.isASCII { if _base.isASCII {
self._ascii = true self._ascii = true
self._asciiBase = UnsafeBufferPointer<UInt8>( self._asciiBase = UnsafeBufferPointer(
start: UnsafePointer(_base._baseAddress), start: _base._baseAddress?.assumingMemoryBound(
to: UTF8.CodeUnit.self),
count: _base.count).makeIterator() count: _base.count).makeIterator()
} else { } else {
self._ascii = false self._ascii = false
self._base = UnsafeBufferPointer<UInt16>( self._base = UnsafeBufferPointer<UInt16>(
start: UnsafePointer(_base._baseAddress), start: _base._baseAddress?.assumingMemoryBound(
to: UTF16.CodeUnit.self),
count: _base.count).makeIterator() count: _base.count).makeIterator()
} }
} else { } else {

View File

@@ -629,16 +629,6 @@ extension UInt {
} }
% end # for mutable % end # for mutable
/// A byte-sized thing that isn't designed to interoperate with
/// any other types; it makes a decent parameter to
/// `UnsafeMutablePointer<Pointee>` when you just want to do bytewise
/// pointer arithmetic.
@_fixed_layout
public // @testable
struct _RawByte {
let _inaccessible: UInt8
}
// ${'Local Variables'}: // ${'Local Variables'}:
// eval: (read-only-mode 1) // eval: (read-only-mode 1)
// End: // End:

View File

@@ -37,8 +37,8 @@ func repr(_ x: _StringCore) -> String {
if x.hasContiguousStorage { if x.hasContiguousStorage {
if let b = x.nativeBuffer { if let b = x.nativeBuffer {
var offset = x.elementWidth == 2 var offset = x.elementWidth == 2
? UnsafeMutablePointer(b.start) - x.startUTF16 ? b.start - UnsafeMutableRawPointer(x.startUTF16)
: UnsafeMutablePointer(b.start) - x.startASCII : b.start - UnsafeMutableRawPointer(x.startASCII)
return "Contiguous(owner: " return "Contiguous(owner: "
+ "\(hexAddr(x._owner))[\(offset)...\(x.count + offset)]" + "\(hexAddr(x._owner))[\(offset)...\(x.count + offset)]"
+ ", capacity = \(b.capacity))" + ", capacity = \(b.capacity))"

View File

@@ -39,8 +39,8 @@ func repr(_ x: _StringCore) -> String {
if x.hasContiguousStorage { if x.hasContiguousStorage {
if let b = x.nativeBuffer { if let b = x.nativeBuffer {
var offset = x.elementWidth == 2 var offset = x.elementWidth == 2
? UnsafeMutablePointer(b.start) - x.startUTF16 ? b.start - UnsafeMutableRawPointer(x.startUTF16)
: UnsafeMutablePointer(b.start) - x.startASCII : b.start - UnsafeMutableRawPointer(x.startASCII)
return "Contiguous(owner: " return "Contiguous(owner: "
+ "\(hexAddr(x._owner))[\(offset)...\(x.count + offset)]" + "\(hexAddr(x._owner))[\(offset)...\(x.count + offset)]"
+ ", capacity = \(b.capacity))" + ", capacity = \(b.capacity))"