mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[stdlib] Implement _copyContents on internal Array types
`_copyContents(initializing:)` is a core method of Sequence, and it is used surprisingly often to copy stuff out of sequences. Array’s internal types currently have explicit implementations of it that trap (to prevent a performance bug due to the default iterator-based implementation. This has proved a bad idea, as not all code paths that end up calling `_copyContents` have actually been expunged — so we replaced a performance bug with a catastrophic correctness bug. 😥 Rather than trying to play whack-a-mole with code paths that end up in `_copyContents`, replace the traps with (relatively) efficient implementations, based on the ancient `_copyContents(subRange:initializing)` methods that have already been there all this time. This resolves https://bugs.swift.org/browse/SR-14663. I expect specialization will make this fix deploy back to earlier OSes in most (but unfortunately not all) cases.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
||||
// Copyright (c) 2014 - 2021 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
|
||||
@@ -471,6 +471,8 @@ tests.test("testMutableArray") {
|
||||
}
|
||||
|
||||
tests.test("rdar://problem/27905230") {
|
||||
// Casting an NSArray to Array<Any> would trap because of an erroneous
|
||||
// precondition.
|
||||
let dict = RDar27905230.mutableDictionaryOfMutableLists()!
|
||||
let arr = dict["list"]!
|
||||
expectEqual(arr[0] as! NSNull, NSNull())
|
||||
@@ -482,4 +484,69 @@ tests.test("rdar://problem/27905230") {
|
||||
expectEqual(arr[5] as! Date, Date(timeIntervalSince1970: 0))
|
||||
}
|
||||
|
||||
tests.test("verbatimBridged/Base/withUnsafeBufferPointer") {
|
||||
let a = NSArray(array: [Base(0), Base(1), Base(2), Base(3)])
|
||||
let b = a as! [Base]
|
||||
let success: Bool = b.withUnsafeBufferPointer { buffer in
|
||||
expectEqual(buffer.count, 4)
|
||||
guard buffer.count == 4 else { return false }
|
||||
expectEqual(buffer[0].value, 0)
|
||||
expectEqual(buffer[1].value, 1)
|
||||
expectEqual(buffer[2].value, 2)
|
||||
expectEqual(buffer[3].value, 3)
|
||||
return true
|
||||
}
|
||||
expectTrue(success)
|
||||
}
|
||||
|
||||
// https://bugs.swift.org/browse/SR-14663
|
||||
tests.test("verbatimBridged/AnyObject/withUnsafeBufferPointer") {
|
||||
let a = NSArray(array: [Base(0), Base(1), Base(2), Base(3)])
|
||||
let b = a as [AnyObject]
|
||||
let success: Bool = b.withUnsafeBufferPointer { buffer in
|
||||
expectEqual(buffer.count, 4)
|
||||
guard buffer.count == 4 else { return false }
|
||||
expectEqual((buffer[0] as? Base)?.value, 0)
|
||||
expectEqual((buffer[1] as? Base)?.value, 1)
|
||||
expectEqual((buffer[2] as? Base)?.value, 2)
|
||||
expectEqual((buffer[3] as? Base)?.value, 3)
|
||||
return true
|
||||
}
|
||||
expectTrue(success)
|
||||
}
|
||||
|
||||
tests.test("verbatimBridged/Base/withUnsafeMutableBufferPointer") {
|
||||
let a = NSArray(array: [Base(0), Base(1), Base(2), Base(3)])
|
||||
var b = a as! [Base]
|
||||
let success: Bool = b.withUnsafeMutableBufferPointer { buffer in
|
||||
expectEqual(buffer.count, 4)
|
||||
guard buffer.count == 4 else { return false }
|
||||
expectEqual(buffer[0].value, 0)
|
||||
expectEqual(buffer[1].value, 1)
|
||||
expectEqual(buffer[2].value, 2)
|
||||
expectEqual(buffer[3].value, 3)
|
||||
buffer[0] = Base(4)
|
||||
return true
|
||||
}
|
||||
expectTrue(success)
|
||||
expectEqual(b[0].value, 4)
|
||||
}
|
||||
|
||||
tests.test("verbatimBridged/AnyObject/withUnsafeMutableBufferPointer") {
|
||||
let a = NSArray(array: [Base(0), Base(1), Base(2), Base(3)])
|
||||
var b = a as [AnyObject]
|
||||
let success: Bool = b.withUnsafeMutableBufferPointer { buffer in
|
||||
expectEqual(buffer.count, 4)
|
||||
guard buffer.count == 4 else { return false }
|
||||
expectEqual((buffer[0] as? Base)?.value, 0)
|
||||
expectEqual((buffer[1] as? Base)?.value, 1)
|
||||
expectEqual((buffer[2] as? Base)?.value, 2)
|
||||
expectEqual((buffer[3] as? Base)?.value, 3)
|
||||
buffer[0] = Base(4)
|
||||
return true
|
||||
}
|
||||
expectTrue(success)
|
||||
expectEqual((b[0] as? Base)?.value, 4)
|
||||
}
|
||||
|
||||
runAllTests()
|
||||
|
||||
Reference in New Issue
Block a user