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
|
||||
/// Requires: such contiguous storage exists or the buffer is empty
|
||||
/// Call `body(p)`, where `p` is a pointer to the underlying
|
||||
/// contiguous storage. If no contiguous storage exists, it is
|
||||
/// created on-demand.
|
||||
public
|
||||
func withUnsafePointerToElements<R>(
|
||||
body: (UnsafePointer<T>)->R
|
||||
) -> R {
|
||||
_precondition(
|
||||
elementStorage != nil || count == 0,
|
||||
"Array is bridging an opaque NSArray; can't get a pointer to the elements"
|
||||
)
|
||||
let ret = body(elementStorage)
|
||||
if _isClassOrObjCExistential(T.self) {
|
||||
if _nonNative {
|
||||
indirect.replaceStorage(_copyCollectionToNativeArrayBuffer(self))
|
||||
}
|
||||
}
|
||||
let ret = body(self.elementStorage)
|
||||
_fixLifetime(self)
|
||||
return ret
|
||||
}
|
||||
|
||||
/// Call `body(p)`, where `p` is a pointer to the underlying contiguous
|
||||
/// storage. Requires: Contiguous storage already exists
|
||||
public
|
||||
mutating func withUnsafeMutablePointerToElements<R>(
|
||||
body: (UnsafeMutablePointer<T>)->R
|
||||
) -> R {
|
||||
_precondition(
|
||||
_sanityCheck(
|
||||
elementStorage != nil || count == 0,
|
||||
"Array is bridging an opaque NSArray; can't get a pointer to the elements"
|
||||
)
|
||||
|
||||
@@ -389,9 +389,6 @@ extension ${Self} {
|
||||
|
||||
extension ${Self} {
|
||||
/// 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>(
|
||||
body: (UnsafePointer<T>) -> R
|
||||
) -> R {
|
||||
@@ -401,7 +398,20 @@ extension ${Self} {
|
||||
public mutating func withUnsafeMutablePointerToElements<R>(
|
||||
body: (UnsafeMutablePointer<T>) -> 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
|
||||
}
|
||||
|
||||
var position, end: UnsafeMutablePointer<T>
|
||||
var position, end: UnsafePointer<T>
|
||||
}
|
||||
|
||||
%for Mutable in ('Mutable', ''):
|
||||
@@ -55,7 +55,7 @@ public struct Unsafe${Mutable}Array<T> : ${Mutable}CollectionType {
|
||||
%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")
|
||||
_position = start
|
||||
_end = start + length
|
||||
@@ -65,7 +65,11 @@ public struct Unsafe${Mutable}Array<T> : ${Mutable}CollectionType {
|
||||
return UnsafeArrayGenerator(position: _position, end: _end)
|
||||
}
|
||||
|
||||
var _position, _end: UnsafeMutablePointer<T>
|
||||
public var elementStorage: Unsafe${Mutable}Pointer<T> {
|
||||
return _position
|
||||
}
|
||||
|
||||
var _position, _end: Unsafe${Mutable}Pointer<T>
|
||||
}
|
||||
|
||||
extension Unsafe${Mutable}Array : DebugPrintable {
|
||||
|
||||
@@ -252,6 +252,13 @@ func testCocoa() {
|
||||
|
||||
println(a.capacity >= 30)
|
||||
// CHECK-NEXT: true
|
||||
|
||||
// Prove that we create contiguous storage for an opaque NSArray
|
||||
a.withUnsafePointerToElements {
|
||||
(p)->() in
|
||||
println(p.memory)
|
||||
// CHECK-NEXT: foo
|
||||
}
|
||||
}
|
||||
testCocoa()
|
||||
|
||||
|
||||
@@ -259,25 +259,29 @@ func additionalUtf16Tests() {
|
||||
var u8: [UTF8.CodeUnit] = [ 0, 1, 2, 3, 4, 5 ]
|
||||
var u16: [UTF16.CodeUnit] = [ 6, 7, 8, 9, 10, 11 ]
|
||||
|
||||
u16.withUnsafeMutablePointerToElements {
|
||||
(p16)->() in
|
||||
u8.withUnsafeMutablePointerToElements {
|
||||
(p8)->() in
|
||||
u16.withUnsafeMutableStorage {
|
||||
(u16)->() in
|
||||
let p16 = u16.elementStorage
|
||||
|
||||
u8.withUnsafeMutableStorage {
|
||||
(u8)->() in
|
||||
let p8 = u8.elementStorage
|
||||
|
||||
// CHECK-NEXT: [ 0, 1, 2, 9, 10, 11 ]
|
||||
UTF16.copy(p8, destination: p16, count: 3)
|
||||
println(u16)
|
||||
println(Array(u16))
|
||||
|
||||
// CHECK-NEXT: [ 9, 10, 11, 3, 4, 5 ]
|
||||
UTF16.copy(p16 + 3, destination: p8, count: 3)
|
||||
println(u8)
|
||||
println(Array(u8))
|
||||
|
||||
// CHECK-NEXT: [ 0, 1, 2, 0, 1, 2 ]
|
||||
UTF16.copy(p16, destination: p16 + 3, count: 3)
|
||||
println(u16)
|
||||
println(Array(u16))
|
||||
|
||||
// CHECK-NEXT: [ 9, 10, 11, 9, 10, 11 ]
|
||||
UTF16.copy(p8, destination: p8 + 3, count: 3)
|
||||
println(u8)
|
||||
println(Array(u8))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2341,7 +2345,7 @@ StringCookedViews.test("UTF8ForContiguousUTF16") {
|
||||
},
|
||||
stopOnError: false)
|
||||
|
||||
backingStorage.withUnsafeMutablePointerToElements {
|
||||
backingStorage.withUnsafePointerToElements {
|
||||
(ptr) -> () in
|
||||
let cfstring = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault,
|
||||
ptr, backingStorage.count, kCFAllocatorNull)
|
||||
|
||||
Reference in New Issue
Block a user