mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[stdlib] On-demand unique contiguous Array storage
Lift the precondition that contiguous storage already exist on the use of Array.withUnsafe[Mutable]PointerToElements. Automatically guarantee that storage is unique when using the mutable variants of these methods. Also, fix some---essentially---inout aliasing violations in test/stdlib/Unicode.swift that were revealed by the new careful implementation of these methods. Swift SVN r20339
This commit is contained in:
@@ -354,26 +354,30 @@ extension _ArrayBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call body(p), where p is a pointer to the underlying contiguous storage
|
/// Call `body(p)`, where `p` is a pointer to the underlying
|
||||||
/// Requires: such contiguous storage exists or the buffer is empty
|
/// contiguous storage. If no contiguous storage exists, it is
|
||||||
|
/// created on-demand.
|
||||||
public
|
public
|
||||||
func withUnsafePointerToElements<R>(
|
func withUnsafePointerToElements<R>(
|
||||||
body: (UnsafePointer<T>)->R
|
body: (UnsafePointer<T>)->R
|
||||||
) -> R {
|
) -> R {
|
||||||
_precondition(
|
if _isClassOrObjCExistential(T.self) {
|
||||||
elementStorage != nil || count == 0,
|
if _nonNative {
|
||||||
"Array is bridging an opaque NSArray; can't get a pointer to the elements"
|
indirect.replaceStorage(_copyCollectionToNativeArrayBuffer(self))
|
||||||
)
|
}
|
||||||
let ret = body(elementStorage)
|
}
|
||||||
|
let ret = body(self.elementStorage)
|
||||||
_fixLifetime(self)
|
_fixLifetime(self)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call `body(p)`, where `p` is a pointer to the underlying contiguous
|
||||||
|
/// storage. Requires: Contiguous storage already exists
|
||||||
public
|
public
|
||||||
mutating func withUnsafeMutablePointerToElements<R>(
|
mutating func withUnsafeMutablePointerToElements<R>(
|
||||||
body: (UnsafeMutablePointer<T>)->R
|
body: (UnsafeMutablePointer<T>)->R
|
||||||
) -> R {
|
) -> R {
|
||||||
_precondition(
|
_sanityCheck(
|
||||||
elementStorage != nil || count == 0,
|
elementStorage != nil || count == 0,
|
||||||
"Array is bridging an opaque NSArray; can't get a pointer to the elements"
|
"Array is bridging an opaque NSArray; can't get a pointer to the elements"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -389,9 +389,6 @@ extension ${Self} {
|
|||||||
|
|
||||||
extension ${Self} {
|
extension ${Self} {
|
||||||
/// Call body(p), where p is a pointer to the ${Self}'s contiguous storage
|
/// Call body(p), where p is a pointer to the ${Self}'s contiguous storage
|
||||||
%if Self != 'Array':
|
|
||||||
/// Requires: the Array's storage is not provided by an opaque NSArray
|
|
||||||
%end
|
|
||||||
public func withUnsafePointerToElements<R>(
|
public func withUnsafePointerToElements<R>(
|
||||||
body: (UnsafePointer<T>) -> R
|
body: (UnsafePointer<T>) -> R
|
||||||
) -> R {
|
) -> R {
|
||||||
@@ -401,7 +398,20 @@ extension ${Self} {
|
|||||||
public mutating func withUnsafeMutablePointerToElements<R>(
|
public mutating func withUnsafeMutablePointerToElements<R>(
|
||||||
body: (UnsafeMutablePointer<T>) -> R
|
body: (UnsafeMutablePointer<T>) -> R
|
||||||
) -> R {
|
) -> R {
|
||||||
return _buffer.withUnsafeMutablePointerToElements(body)
|
// Ensure unique storage
|
||||||
|
_arrayReserve(&_buffer, 0)
|
||||||
|
|
||||||
|
// Ensure that body can't invalidate the storage or its bounds by
|
||||||
|
// moving self into a temporary working array.
|
||||||
|
var work = ${Self}()
|
||||||
|
swap(&work, &self)
|
||||||
|
|
||||||
|
// Invoke the body
|
||||||
|
let ret = work._buffer.withUnsafeMutablePointerToElements(body)
|
||||||
|
|
||||||
|
// Put the working array back before returning.
|
||||||
|
swap(&work, &self)
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public struct UnsafeArrayGenerator<T>: GeneratorType, SequenceType {
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
var position, end: UnsafeMutablePointer<T>
|
var position, end: UnsafePointer<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
%for Mutable in ('Mutable', ''):
|
%for Mutable in ('Mutable', ''):
|
||||||
@@ -55,7 +55,7 @@ public struct Unsafe${Mutable}Array<T> : ${Mutable}CollectionType {
|
|||||||
%end
|
%end
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(start: UnsafeMutablePointer<T>, length: Int) {
|
public init(start: Unsafe${Mutable}Pointer<T>, length: Int) {
|
||||||
_precondition(length >= 0, "Unsafe${Mutable}Array with negative length")
|
_precondition(length >= 0, "Unsafe${Mutable}Array with negative length")
|
||||||
_position = start
|
_position = start
|
||||||
_end = start + length
|
_end = start + length
|
||||||
@@ -64,8 +64,12 @@ public struct Unsafe${Mutable}Array<T> : ${Mutable}CollectionType {
|
|||||||
public func generate() -> UnsafeArrayGenerator<T> {
|
public func generate() -> UnsafeArrayGenerator<T> {
|
||||||
return UnsafeArrayGenerator(position: _position, end: _end)
|
return UnsafeArrayGenerator(position: _position, end: _end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var elementStorage: Unsafe${Mutable}Pointer<T> {
|
||||||
|
return _position
|
||||||
|
}
|
||||||
|
|
||||||
var _position, _end: UnsafeMutablePointer<T>
|
var _position, _end: Unsafe${Mutable}Pointer<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Unsafe${Mutable}Array : DebugPrintable {
|
extension Unsafe${Mutable}Array : DebugPrintable {
|
||||||
|
|||||||
@@ -252,6 +252,13 @@ func testCocoa() {
|
|||||||
|
|
||||||
println(a.capacity >= 30)
|
println(a.capacity >= 30)
|
||||||
// CHECK-NEXT: true
|
// CHECK-NEXT: true
|
||||||
|
|
||||||
|
// Prove that we create contiguous storage for an opaque NSArray
|
||||||
|
a.withUnsafePointerToElements {
|
||||||
|
(p)->() in
|
||||||
|
println(p.memory)
|
||||||
|
// CHECK-NEXT: foo
|
||||||
|
}
|
||||||
}
|
}
|
||||||
testCocoa()
|
testCocoa()
|
||||||
|
|
||||||
|
|||||||
@@ -259,25 +259,29 @@ func additionalUtf16Tests() {
|
|||||||
var u8: [UTF8.CodeUnit] = [ 0, 1, 2, 3, 4, 5 ]
|
var u8: [UTF8.CodeUnit] = [ 0, 1, 2, 3, 4, 5 ]
|
||||||
var u16: [UTF16.CodeUnit] = [ 6, 7, 8, 9, 10, 11 ]
|
var u16: [UTF16.CodeUnit] = [ 6, 7, 8, 9, 10, 11 ]
|
||||||
|
|
||||||
u16.withUnsafeMutablePointerToElements {
|
u16.withUnsafeMutableStorage {
|
||||||
(p16)->() in
|
(u16)->() in
|
||||||
u8.withUnsafeMutablePointerToElements {
|
let p16 = u16.elementStorage
|
||||||
(p8)->() in
|
|
||||||
|
u8.withUnsafeMutableStorage {
|
||||||
|
(u8)->() in
|
||||||
|
let p8 = u8.elementStorage
|
||||||
|
|
||||||
// CHECK-NEXT: [ 0, 1, 2, 9, 10, 11 ]
|
// CHECK-NEXT: [ 0, 1, 2, 9, 10, 11 ]
|
||||||
UTF16.copy(p8, destination: p16, count: 3)
|
UTF16.copy(p8, destination: p16, count: 3)
|
||||||
println(u16)
|
println(Array(u16))
|
||||||
|
|
||||||
// CHECK-NEXT: [ 9, 10, 11, 3, 4, 5 ]
|
// CHECK-NEXT: [ 9, 10, 11, 3, 4, 5 ]
|
||||||
UTF16.copy(p16 + 3, destination: p8, count: 3)
|
UTF16.copy(p16 + 3, destination: p8, count: 3)
|
||||||
println(u8)
|
println(Array(u8))
|
||||||
|
|
||||||
// CHECK-NEXT: [ 0, 1, 2, 0, 1, 2 ]
|
// CHECK-NEXT: [ 0, 1, 2, 0, 1, 2 ]
|
||||||
UTF16.copy(p16, destination: p16 + 3, count: 3)
|
UTF16.copy(p16, destination: p16 + 3, count: 3)
|
||||||
println(u16)
|
println(Array(u16))
|
||||||
|
|
||||||
// CHECK-NEXT: [ 9, 10, 11, 9, 10, 11 ]
|
// CHECK-NEXT: [ 9, 10, 11, 9, 10, 11 ]
|
||||||
UTF16.copy(p8, destination: p8 + 3, count: 3)
|
UTF16.copy(p8, destination: p8 + 3, count: 3)
|
||||||
println(u8)
|
println(Array(u8))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2341,7 +2345,7 @@ StringCookedViews.test("UTF8ForContiguousUTF16") {
|
|||||||
},
|
},
|
||||||
stopOnError: false)
|
stopOnError: false)
|
||||||
|
|
||||||
backingStorage.withUnsafeMutablePointerToElements {
|
backingStorage.withUnsafePointerToElements {
|
||||||
(ptr) -> () in
|
(ptr) -> () in
|
||||||
let cfstring = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault,
|
let cfstring = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault,
|
||||||
ptr, backingStorage.count, kCFAllocatorNull)
|
ptr, backingStorage.count, kCFAllocatorNull)
|
||||||
|
|||||||
Reference in New Issue
Block a user