[stdlib] Restore Array value semantics

'nuff said.

Swift SVN r18923
This commit is contained in:
Dave Abrahams
2014-06-16 13:56:15 +00:00
parent acc2c3be40
commit 85533dd7d3
9 changed files with 69 additions and 46 deletions

View File

@@ -183,6 +183,10 @@ extension ArrayBuffer {
}
return nil
}
mutating func isMutableAndUniquelyReferenced() -> Bool {
return Swift.isUniquelyReferenced(&storage) && _hasMutableBuffer
}
/// If this buffer is backed by a ContiguousArrayBuffer, return it.
/// Otherwise, return nil. Note: the result's elementStorage may

View File

@@ -47,6 +47,14 @@ protocol ArrayBufferType : MutableCollection {
mutating func requestUniqueMutableBuffer(minimumCapacity: Int)
-> ContiguousArrayBuffer<Element>?
/// Returns true iff this buffer is backed by a uniquely-referenced mutable
/// ContiguousArrayBuffer.
///
/// Note: this function must remain mutating; otherwise the buffer
/// may acquire spurious extra references, which will cause
/// unnecessary reallocation.
mutating func isMutableAndUniquelyReferenced() -> Bool
/// If this buffer is backed by a ContiguousArrayBuffer, return it.
/// Otherwise, return nil. Note: the result's elementStorage may
/// not match ours, if we are a SliceBuffer.

View File

@@ -39,7 +39,7 @@ protocol ArrayType
/// element. Otherwise, nil.
var _elementStorageIfContiguous: UnsafePointer<Element> {get}
subscript(index: Int) -> Self.GeneratorType.Element {get nonmutating set}
subscript(index: Int) -> Self.GeneratorType.Element {get set}
//===--- basic mutations ------------------------------------------------===//

View File

@@ -42,10 +42,25 @@ struct ${Self}<T> : MutableCollection, Sliceable {
_precondition(index >= 0, "Negative ${Self} index is out of range")
return _buffer[index]
}
nonmutating set {
set {
_precondition(index < count, "${Self} index out of range")
_precondition(index >= 0, "Negative array index is out of range")
_buffer[index] = newValue
if _buffer.isMutableAndUniquelyReferenced() {
_buffer[index] = newValue
}
else {
{
(inout buffer: _Buffer, e: Element)->() in
var newBuffer = ContiguousArrayBuffer<T>(
count: buffer.count, minimumCapacity: buffer.count)
let target = buffer._uninitializedCopy(
0..index, target: newBuffer.elementStorage)
target.initialize(e)
buffer._uninitializedCopy(
(index + 1)..buffer.count, target: target + 1)
buffer = _Buffer(newBuffer)
}(&_buffer, newValue)
}
}
}
@@ -147,15 +162,12 @@ extension ${Self} : ArrayType {
/// array.
/// Complexity: O(N)
func copy() -> ${Self} {
var result = self
result.reserveCapacity(0)
return result
return self
}
/// Ensure the uniqueness of the array.
/// Complexity: O(N)
mutating func unshare() {
reserveCapacity(0)
func unshare() {
}
/// Ensure the array has enough mutable contiguous storage to store

View File

@@ -123,6 +123,10 @@ struct ContiguousArrayBuffer<T> : ArrayBufferType, LogicValue {
return isUniquelyReferenced() && capacity >= minimumCapacity ? self : nil
}
mutating func isMutableAndUniquelyReferenced() -> Bool {
return isUniquelyReferenced()
}
/// If this buffer is backed by a ContiguousArrayBuffer, return it.
/// Otherwise, return nil. Note: the result's elementStorage may
/// not match ours, if we are a SliceBuffer.

View File

@@ -95,6 +95,10 @@ struct SliceBuffer<T> : ArrayBufferType {
return nil
}
mutating func isMutableAndUniquelyReferenced() -> Bool {
return _hasNativeBuffer && Swift.isUniquelyReferenced(&owner)
}
/// If this buffer is backed by a ContiguousArrayBuffer, return it.
/// Otherwise, return nil. Note: the result's elementStorage may
/// not match ours, since we are a SliceBuffer.

View File

@@ -183,7 +183,7 @@ func testBridgedVerbatim() {
println(nsArrayOfBaseConvertedToAnyObjectArray[0] as Base)
//===--- Up- and Down-casts -----------------------------------------------===//
let derived: Derived[] = [Derived(11), Derived(22)]
var derived: Derived[] = [Derived(11), Derived(22)]
// CHECK-NEXT: [[derived0:\[Derived#[0-9]+\(11\), Derived#[0-9]+\(22\)\]{1}]]
println(derived)

View File

@@ -132,18 +132,8 @@ where T.GeneratorType.Element == T._Buffer.Element,
let y = x
x[x.endIndex.pred()] = 17
let bufferId3 = checkReallocation(x, bufferId2, false)
checkEqual(x, y, true)
if x !== y {
println("unexpectedly, x !== y")
}
x += 42
let bufferId3 = checkReallocation(x, bufferId2, true)
checkEqual(x, y, false)
if x === y {
println("unexpectedly, x === y")
}
println("done.")
}
@@ -223,9 +213,9 @@ func testCocoa() {
printSequence(a)
// CHECK-NEXT: [foo, garply, baz]
// Mutating an element in a changes b, too
// Mutating an element in a has no effect on b
printSequence(b)
// CHECK-NEXT: [foo, garply, baz]
// CHECK-NEXT: [foo, bar, baz]
a = nsArrayOfStrings()
a.insert("bag", atIndex:2)
@@ -259,24 +249,25 @@ func testSlice() {
var bSlice = b[3..5]
println("<\(bSlice.count)>")
// CHECK-NEXT: <2>
printSequence(bSlice)
// CHECK-NEXT: [3, 4]
println("bSlice0: \(bSlice)") // CHECK-NEXT: bSlice0: [3, 4]
// bSlice += X(11)..X(13)
// Writing into b changes bSlice
// Writing into b does not change bSlice
b[4] = 41
printSequence(bSlice) // CHECK-NEXT: [3, 41]
println("bSlice1: \(bSlice)") // CHECK-NEXT: bSlice1: [3, 4]
// Writing into bSlice changes b
bSlice[1] = 42 // CHECK-NEXT: [3, 42]
printSequence(bSlice)
printSequence(b) // CHECK-NEXT: [0, 1, 2, 3, 42, 5, 6]
// Writing into bSlice does not change b
bSlice[1] = 42
println("bSlice2: \(bSlice)") // CHECK-NEXT: bSlice2: [3, 42]
printSequence(b) // CHECK-NEXT: [0, 1, 2, 3, 41, 5, 6]
var c = b
b[4..b.count].qsort(<)
printSequence(b) // CHECK-NEXT: [0, 1, 2, 3, 5, 6, 42]
printSequence(c) // CHECK-NEXT: [0, 1, 2, 3, 5, 6, 42]
printSequence(b) // CHECK-NEXT: [0, 1, 2, 3, 5, 6, 41]
printSequence(c) // CHECK-NEXT: [0, 1, 2, 3, 41, 5, 6]
// Now a bridged slice
var a = Array<NSString>(
@@ -291,8 +282,8 @@ func testSlice() {
aSlice[0] = "buzz" // CHECK-NEXT: [buzz, baz]
printSequence(aSlice)
// ...and also changes a with reference semantics
printSequence(a) // CHECK-NEXT: [foo, buzz, baz]
// ...and doesn't affect a
printSequence(a) // CHECK-NEXT: [foo, bar, baz]
// Appending to aSlice works...
aSlice += "fodder"
@@ -300,7 +291,7 @@ func testSlice() {
printSequence(aSlice) // CHECK-NEXT: [buzz, baz, fodder]
// And doesn't change a
printSequence(a) // CHECK-NEXT: [foo, buzz, baz]
printSequence(a) // CHECK-NEXT: [foo, bar, baz]
}
testSlice()

View File

@@ -1,7 +1,11 @@
// RUN: %target-run-simple-swift | FileCheck %s
// Generate all possible permutes.
func _permuteInternal(elem: Int, size : Int, perm : Int[], visited : Bool[], verify : (Int[]) -> ()) {
func _permuteInternal(
elem: Int, size : Int,
inout perm : Int[], inout visited : Bool[],
verify : (Int[]) -> ()
) {
if (elem == size) {
verify(perm)
return
@@ -13,20 +17,16 @@ func _permuteInternal(elem: Int, size : Int, perm : Int[], visited : Bool[], ver
}
visited[i] = true
perm[elem] = i
_permuteInternal(elem + 1, size, perm, visited, verify)
_permuteInternal(elem + 1, size, &perm, &visited, verify)
visited[i] = false
}
}
// Convenience wrapper for the permute method.
func permute(size : Int, verify : (Int[]) -> ()) {
var perm : Int[] = []
var visited : Bool[] = []
for i in 0..size {
visited.append(false)
perm.append(0)
}
_permuteInternal(0, size, perm, visited, verify)
var perm = Int[](count: size, repeatedValue: 0)
var visited = Bool[](count: size, repeatedValue: false)
_permuteInternal(0, size, &perm, &visited, verify)
}
@@ -62,8 +62,8 @@ permute(3, printer)
let sort_verifier : (Int[]) -> () = {
var y = sorted($0)
for i in 0..y.count - 1 {
if (y[i] > y[i+1]) {
print("Error!\n")
if (y[i] > y[i+1]) {
println("Error: \(y)")
return
}
}