Skip to content

Commit 781b431

Browse files
committed
[stdlib] array identical
1 parent a782752 commit 781b431

File tree

11 files changed

+367
-0
lines changed

11 files changed

+367
-0
lines changed

benchmark/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ set(SWIFT_BENCH_MODULES
3939
single-source/ArrayOfRef
4040
single-source/ArrayRemoveAll
4141
single-source/ArraySetElement
42+
single-source/ArraySliceTests
4243
single-source/ArraySubscript
44+
single-source/ArrayTests
4345
single-source/AsyncTree
4446
single-source/BinaryFloatingPointConversionFromBinaryInteger
4547
single-source/BinaryFloatingPointProperties
@@ -65,6 +67,7 @@ set(SWIFT_BENCH_MODULES
6567
single-source/ClassArrayGetter
6668
single-source/CodableTest
6769
single-source/Combos
70+
single-source/ContiguousArrayTests
6871
single-source/CountAlgo
6972
single-source/DataBenchmarks
7073
single-source/DeadArray
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===--- ArraySliceTests.swift --------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import TestsUtils
14+
15+
public let benchmarks = [
16+
BenchmarkInfo(name: "ArraySliceEqualUnique", runFunction: run_ArraySliceEqualUnique, tags: [.validation, .api, .Array]),
17+
BenchmarkInfo(name: "ArraySliceEqualShared", runFunction: run_ArraySliceEqualShared, tags: [.validation, .api, .Array]),
18+
BenchmarkInfo(name: "ArraySliceIdentical", runFunction: run_ArraySliceIdentical, tags: [.validation, .api, .Array]),
19+
]
20+
21+
@inline(never)
22+
public func run_ArraySliceEqualUnique(_ n: Int) {
23+
let a1 = ArraySlice(0 ..< n)
24+
let a2 = ArraySlice(0 ..< n)
25+
for _ in 0 ..< 100_000 {
26+
check(a1 == a2)
27+
}
28+
}
29+
30+
@inline(never)
31+
public func run_ArraySliceEqualShared(_ n: Int) {
32+
let a1 = ArraySlice(0 ..< n)
33+
let a2 = a1
34+
for _ in 0 ..< 100_000 {
35+
check(a1 == a2)
36+
}
37+
}
38+
39+
@inline(never)
40+
public func run_ArraySliceIdentical(_ n: Int) {
41+
let a1 = ArraySlice(0 ..< n)
42+
let a2 = a1
43+
for _ in 0 ..< 100_000 {
44+
check(a1.isIdentical(to: a2))
45+
}
46+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===--- ArrayTests.swift -------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import TestsUtils
14+
15+
public let benchmarks = [
16+
BenchmarkInfo(name: "ArrayEqualUnique", runFunction: run_ArrayEqualUnique, tags: [.validation, .api, .Array]),
17+
BenchmarkInfo(name: "ArrayEqualShared", runFunction: run_ArrayEqualShared, tags: [.validation, .api, .Array]),
18+
BenchmarkInfo(name: "ArrayIdentical", runFunction: run_ArrayIdentical, tags: [.validation, .api, .Array]),
19+
]
20+
21+
@inline(never)
22+
public func run_ArrayEqualUnique(_ n: Int) {
23+
let a1 = Array(0 ..< n)
24+
let a2 = Array(0 ..< n)
25+
for _ in 0 ..< 100_000 {
26+
check(a1 == a2)
27+
}
28+
}
29+
30+
@inline(never)
31+
public func run_ArrayEqualShared(_ n: Int) {
32+
let a1 = Array(0 ..< n)
33+
let a2 = a1
34+
for _ in 0 ..< 100_000 {
35+
check(a1 == a2)
36+
}
37+
}
38+
39+
@inline(never)
40+
public func run_ArrayIdentical(_ n: Int) {
41+
let a1 = Array(0 ..< n)
42+
let a2 = a1
43+
for _ in 0 ..< 100_000 {
44+
check(a1.isIdentical(to: a2))
45+
}
46+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===--- ContiguousArrayTests.swift ---------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import TestsUtils
14+
15+
public let benchmarks = [
16+
BenchmarkInfo(name: "ContiguousArrayEqualUnique", runFunction: run_ContiguousArrayEqualUnique, tags: [.validation, .api, .Array]),
17+
BenchmarkInfo(name: "ContiguousArrayEqualShared", runFunction: run_ContiguousArrayEqualShared, tags: [.validation, .api, .Array]),
18+
BenchmarkInfo(name: "ContiguousArrayIdentical", runFunction: run_ContiguousArrayIdentical, tags: [.validation, .api, .Array]),
19+
]
20+
21+
@inline(never)
22+
public func run_ContiguousArrayEqualUnique(_ n: Int) {
23+
let a1 = ContiguousArray(0 ..< n)
24+
let a2 = ContiguousArray(0 ..< n)
25+
for _ in 0 ..< 100_000 {
26+
check(a1 == a2)
27+
}
28+
}
29+
30+
@inline(never)
31+
public func run_ContiguousArrayEqualShared(_ n: Int) {
32+
let a1 = ContiguousArray(0 ..< n)
33+
let a2 = a1
34+
for _ in 0 ..< 100_000 {
35+
check(a1 == a2)
36+
}
37+
}
38+
39+
@inline(never)
40+
public func run_ContiguousArrayIdentical(_ n: Int) {
41+
let a1 = ContiguousArray(0 ..< n)
42+
let a2 = a1
43+
for _ in 0 ..< 100_000 {
44+
check(a1.isIdentical(to: a2))
45+
}
46+
}

benchmark/utils/main.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ import ArrayOfPOD
2727
import ArrayOfRef
2828
import ArrayRemoveAll
2929
import ArraySetElement
30+
import ArraySliceTests
3031
import ArraySubscript
32+
import ArrayTests
3133
import AsyncTree
3234
import BinaryFloatingPointConversionFromBinaryInteger
3335
import BinaryFloatingPointProperties
@@ -53,6 +55,7 @@ import Chars
5355
import ClassArrayGetter
5456
import CodableTest
5557
import Combos
58+
import ContiguousArrayTests
5659
import CountAlgo
5760
import CreateObjects
5861
// rdar://128520766
@@ -228,7 +231,9 @@ register(ArrayOfPOD.benchmarks)
228231
register(ArrayOfRef.benchmarks)
229232
register(ArrayRemoveAll.benchmarks)
230233
register(ArraySetElement.benchmarks)
234+
register(ArraySliceTests.benchmarks)
231235
register(ArraySubscript.benchmarks)
236+
register(ArrayTests.benchmarks)
232237
register(AsyncTree.benchmarks)
233238
register(BinaryFloatingPointConversionFromBinaryInteger.benchmarks)
234239
register(BinaryFloatingPointProperties.benchmarks)
@@ -253,8 +258,10 @@ register(CharacterRecognizer.benchmarks)
253258
register(Chars.benchmarks)
254259
register(CodableTest.benchmarks)
255260
register(Combos.benchmarks)
261+
register(ContiguousArrayTests.benchmarks)
256262
register(CountAlgo.benchmarks)
257263
register(ClassArrayGetter.benchmarks)
264+
register(ContiguousArrayTests.benchmarks)
258265
register(CreateObjects.benchmarks)
259266
// rdar://128520766
260267
// register(CxxSetToCollection.benchmarks)

stdlib/public/core/Array.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,3 +2157,33 @@ internal struct _ArrayAnyHashableBox<Element: Hashable>
21572157
}
21582158

21592159
extension Array: @unchecked Sendable where Element: Sendable { }
2160+
2161+
extension Array {
2162+
/// Returns a boolean value indicating whether this array is identical to
2163+
/// `other`.
2164+
///
2165+
/// Two array values are identical if there is no way to distinguish between
2166+
/// them.
2167+
///
2168+
/// Comparing arrays this way includes comparing (normally) hidden
2169+
/// implementation details such as the memory location of any underlying
2170+
/// array storage object. Therefore, identical arrays are guaranteed to
2171+
/// compare equal with `==`, but not all equal arrays are considered
2172+
/// identical.
2173+
///
2174+
/// - Performance: O(1)
2175+
@_alwaysEmitIntoClient
2176+
public func isIdentical(to other: Self) -> Bool {
2177+
let lhsCount = self.count
2178+
if lhsCount != other.count {
2179+
return false
2180+
}
2181+
2182+
// Test referential equality.
2183+
if unsafe lhsCount == 0 || self._buffer.identity == other._buffer.identity {
2184+
return true
2185+
}
2186+
2187+
return false
2188+
}
2189+
}

stdlib/public/core/ArraySlice.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,3 +1607,33 @@ extension ArraySlice {
16071607
}
16081608
}
16091609
#endif
1610+
1611+
extension ArraySlice {
1612+
/// Returns a boolean value indicating whether this array is identical to
1613+
/// `other`.
1614+
///
1615+
/// Two array values are identical if there is no way to distinguish between
1616+
/// them.
1617+
///
1618+
/// Comparing arrays this way includes comparing (normally) hidden
1619+
/// implementation details such as the memory location of any underlying
1620+
/// array storage object. Therefore, identical arrays are guaranteed to
1621+
/// compare equal with `==`, but not all equal arrays are considered
1622+
/// identical.
1623+
///
1624+
/// - Performance: O(1)
1625+
@_alwaysEmitIntoClient
1626+
public func isIdentical(to other: Self) -> Bool {
1627+
let lhsCount = self.count
1628+
if lhsCount != other.count {
1629+
return false
1630+
}
1631+
1632+
// Test referential equality.
1633+
if unsafe lhsCount == 0 || self._buffer.identity == other._buffer.identity {
1634+
return true
1635+
}
1636+
1637+
return false
1638+
}
1639+
}

stdlib/public/core/ContiguousArray.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,3 +1515,33 @@ extension ContiguousArray {
15151515

15161516
extension ContiguousArray: @unchecked Sendable
15171517
where Element: Sendable { }
1518+
1519+
extension ContiguousArray {
1520+
/// Returns a boolean value indicating whether this array is identical to
1521+
/// `other`.
1522+
///
1523+
/// Two array values are identical if there is no way to distinguish between
1524+
/// them.
1525+
///
1526+
/// Comparing arrays this way includes comparing (normally) hidden
1527+
/// implementation details such as the memory location of any underlying
1528+
/// array storage object. Therefore, identical arrays are guaranteed to
1529+
/// compare equal with `==`, but not all equal arrays are considered
1530+
/// identical.
1531+
///
1532+
/// - Performance: O(1)
1533+
@_alwaysEmitIntoClient
1534+
public func isIdentical(to other: Self) -> Bool {
1535+
let lhsCount = self.count
1536+
if lhsCount != other.count {
1537+
return false
1538+
}
1539+
1540+
// Test referential equality.
1541+
if unsafe lhsCount == 0 || self._buffer.identity == other._buffer.identity {
1542+
return true
1543+
}
1544+
1545+
return false
1546+
}
1547+
}

test/stdlib/ArraySliceTests.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// RUN: %target-run-simple-swift(-parse-as-library)
14+
// REQUIRES: executable_test
15+
// END.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
import StdlibUnittest
20+
21+
@main
22+
enum ArraySliceTests {
23+
static func main() {
24+
let testSuite = TestSuite("ArraySliceTests")
25+
testSuite.test("Identical", testIdentical)
26+
runAllTests()
27+
}
28+
29+
static func testIdentical() {
30+
let a1: ArraySlice = [0, 1, 2, 3]
31+
expectTrue(a1.isIdentical(to: a1))
32+
33+
let a2: ArraySlice = a1
34+
expectTrue(a1.isIdentical(to: a2))
35+
36+
var a3: ArraySlice = a2
37+
a3.reserveCapacity(0)
38+
expectFalse(a1.isIdentical(to: a3))
39+
40+
let a4: ArraySlice = [0, 1, 2, 3]
41+
expectFalse(a1.isIdentical(to: a4))
42+
}
43+
}

test/stdlib/ArrayTests.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// RUN: %target-run-simple-swift(-parse-as-library)
14+
// REQUIRES: executable_test
15+
// END.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
import StdlibUnittest
20+
21+
@main
22+
enum ArrayTests {
23+
static func main() {
24+
let testSuite = TestSuite("ArrayTests")
25+
testSuite.test("Identical", testIdentical)
26+
runAllTests()
27+
}
28+
29+
static func testIdentical() {
30+
let a1: Array = [0, 1, 2, 3]
31+
expectTrue(a1.isIdentical(to: a1))
32+
33+
let a2: Array = a1
34+
expectTrue(a1.isIdentical(to: a2))
35+
36+
var a3: Array = a2
37+
a3.reserveCapacity(0)
38+
expectFalse(a1.isIdentical(to: a3))
39+
40+
let a4: Array = [0, 1, 2, 3]
41+
expectFalse(a1.isIdentical(to: a4))
42+
}
43+
}

0 commit comments

Comments
 (0)