Skip to content

Commit c1a4725

Browse files
committed
[stdlib] array identical
1 parent 860f2db commit c1a4725

File tree

11 files changed

+401
-0
lines changed

11 files changed

+401
-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.isTriviallyIdentical(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.isTriviallyIdentical(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.isTriviallyIdentical(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
@@ -227,7 +230,9 @@ register(ArrayOfPOD.benchmarks)
227230
register(ArrayOfRef.benchmarks)
228231
register(ArrayRemoveAll.benchmarks)
229232
register(ArraySetElement.benchmarks)
233+
register(ArraySliceTests.benchmarks)
230234
register(ArraySubscript.benchmarks)
235+
register(ArrayTests.benchmarks)
231236
register(AsyncTree.benchmarks)
232237
register(BinaryFloatingPointConversionFromBinaryInteger.benchmarks)
233238
register(BinaryFloatingPointProperties.benchmarks)
@@ -252,8 +257,10 @@ register(CharacterRecognizer.benchmarks)
252257
register(Chars.benchmarks)
253258
register(CodableTest.benchmarks)
254259
register(Combos.benchmarks)
260+
register(ContiguousArrayTests.benchmarks)
255261
register(CountAlgo.benchmarks)
256262
register(ClassArrayGetter.benchmarks)
263+
register(ContiguousArrayTests.benchmarks)
257264
register(CreateObjects.benchmarks)
258265
// rdar://128520766
259266
// register(CxxSetToCollection.benchmarks)

stdlib/public/core/Array.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2160,3 +2160,44 @@ internal struct _ArrayAnyHashableBox<Element: Hashable>
21602160
}
21612161

21622162
extension Array: @unchecked Sendable where Element: Sendable { }
2163+
2164+
extension Array {
2165+
/// Returns a boolean value indicating whether this array is identical to
2166+
/// `other`.
2167+
///
2168+
/// Two array values are identical if there is no way to distinguish between
2169+
/// them.
2170+
///
2171+
/// For any values `a`, `b`, and `c`:
2172+
///
2173+
/// - `a.isTriviallyIdentical(to: a)` is always `true`. (Reflexivity)
2174+
/// - `a.isTriviallyIdentical(to: b)` implies `b.isTriviallyIdentical(to: a)`.
2175+
/// (Symmetry)
2176+
/// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)`
2177+
/// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`.
2178+
/// (Transitivity)
2179+
/// - If `a` and `b` are `Equatable`, then `a.isTriviallyIdentical(b)` implies
2180+
/// `a == b`
2181+
/// - `a == b` does not imply `a.isTriviallyIdentical(b)`
2182+
///
2183+
/// Values produced by copying the same value, with no intervening mutations,
2184+
/// will compare identical:
2185+
///
2186+
/// ```swift
2187+
/// let d = c
2188+
/// print(c.isTriviallyIdentical(to: d))
2189+
/// // Prints true
2190+
/// ```
2191+
///
2192+
/// Comparing arrays this way includes comparing (normally) hidden
2193+
/// implementation details such as the memory location of any underlying
2194+
/// array storage object. Therefore, identical arrays are guaranteed to
2195+
/// compare equal with `==`, but not all equal arrays are considered
2196+
/// identical.
2197+
///
2198+
/// - Performance: O(1)
2199+
@_alwaysEmitIntoClient
2200+
public func isTriviallyIdentical(to other: Self) -> Bool {
2201+
self._buffer.identity == other._buffer.identity
2202+
}
2203+
}

stdlib/public/core/ArraySlice.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,3 +1607,45 @@ 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+
/// For any values `a`, `b`, and `c`:
1619+
///
1620+
/// - `a.isTriviallyIdentical(to: a)` is always `true`. (Reflexivity)
1621+
/// - `a.isTriviallyIdentical(to: b)` implies `b.isTriviallyIdentical(to: a)`.
1622+
/// (Symmetry)
1623+
/// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)`
1624+
/// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`.
1625+
/// (Transitivity)
1626+
/// - If `a` and `b` are `Equatable`, then `a.isTriviallyIdentical(b)` implies
1627+
/// `a == b`
1628+
/// - `a == b` does not imply `a.isTriviallyIdentical(b)`
1629+
///
1630+
/// Values produced by copying the same value, with no intervening mutations,
1631+
/// will compare identical:
1632+
///
1633+
/// ```swift
1634+
/// let d = c
1635+
/// print(c.isTriviallyIdentical(to: d))
1636+
/// // Prints true
1637+
/// ```
1638+
///
1639+
/// Comparing arrays this way includes comparing (normally) hidden
1640+
/// implementation details such as the memory location of any underlying
1641+
/// array storage object. Therefore, identical arrays are guaranteed to
1642+
/// compare equal with `==`, but not all equal arrays are considered
1643+
/// identical.
1644+
///
1645+
/// - Performance: O(1)
1646+
@_alwaysEmitIntoClient
1647+
public func isTriviallyIdentical(to other: Self) -> Bool {
1648+
self._buffer.identity == other._buffer.identity &&
1649+
self.count == other.count
1650+
}
1651+
}

stdlib/public/core/ContiguousArray.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,3 +1515,44 @@ 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+
/// For any values `a`, `b`, and `c`:
1527+
///
1528+
/// - `a.isTriviallyIdentical(to: a)` is always `true`. (Reflexivity)
1529+
/// - `a.isTriviallyIdentical(to: b)` implies `b.isTriviallyIdentical(to: a)`.
1530+
/// (Symmetry)
1531+
/// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)`
1532+
/// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`.
1533+
/// (Transitivity)
1534+
/// - If `a` and `b` are `Equatable`, then `a.isTriviallyIdentical(b)` implies
1535+
/// `a == b`
1536+
/// - `a == b` does not imply `a.isTriviallyIdentical(b)`
1537+
///
1538+
/// Values produced by copying the same value, with no intervening mutations,
1539+
/// will compare identical:
1540+
///
1541+
/// ```swift
1542+
/// let d = c
1543+
/// print(c.isTriviallyIdentical(to: d))
1544+
/// // Prints true
1545+
/// ```
1546+
///
1547+
/// Comparing arrays this way includes comparing (normally) hidden
1548+
/// implementation details such as the memory location of any underlying
1549+
/// array storage object. Therefore, identical arrays are guaranteed to
1550+
/// compare equal with `==`, but not all equal arrays are considered
1551+
/// identical.
1552+
///
1553+
/// - Performance: O(1)
1554+
@_alwaysEmitIntoClient
1555+
public func isTriviallyIdentical(to other: Self) -> Bool {
1556+
self._buffer.identity == other._buffer.identity
1557+
}
1558+
}

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.isTriviallyIdentical(to: a1))
32+
33+
let a2: ArraySlice = a1
34+
expectTrue(a1.isTriviallyIdentical(to: a2))
35+
36+
var a3: ArraySlice = a2
37+
a3.reserveCapacity(0)
38+
expectFalse(a1.isTriviallyIdentical(to: a3))
39+
40+
let a4: ArraySlice = [0, 1, 2, 3]
41+
expectFalse(a1.isTriviallyIdentical(to: a4))
42+
}
43+
}

0 commit comments

Comments
 (0)