Skip to content

Commit 390f0c7

Browse files
committed
[stdlib] dictionary identical
1 parent d11c8d0 commit 390f0c7

File tree

8 files changed

+279
-0
lines changed

8 files changed

+279
-0
lines changed

benchmark/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ set(SWIFT_BENCH_MODULES
8080
single-source/DictionaryCompactMapValues
8181
single-source/DictionaryCopy
8282
single-source/DictionaryGroup
83+
single-source/DictionaryIdentical
8384
single-source/DictionaryKeysContains
8485
single-source/DictionaryLiteralTest
8586
single-source/DictionaryOfAnyHashableStrings
@@ -173,6 +174,7 @@ set(SWIFT_BENCH_MODULES
173174
# Disabled while layout prespecializations are experimental
174175
#single-source/SimpleArraySpecialization
175176
single-source/SequenceAlgos
177+
single-source/SetIdentical
176178
single-source/SetTests
177179
single-source/SevenBoom
178180
single-source/Sim2DArray
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===--- DictionaryIdentical.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: "DictionaryEqualUnique", runFunction: run_DictionaryEqualUnique, tags: [.validation, .api, .Dictionary]),
17+
BenchmarkInfo(name: "DictionaryEqualShared", runFunction: run_DictionaryEqualShared, tags: [.validation, .api, .Dictionary]),
18+
BenchmarkInfo(name: "DictionaryIdentical", runFunction: run_DictionaryIdentical, tags: [.validation, .api, .Dictionary]),
19+
]
20+
21+
@inline(never)
22+
public func run_DictionaryEqualUnique(_ n: Int) {
23+
let d1 = Dictionary(uniqueKeysWithValues: zip(1...n, 1...n))
24+
let d2 = Dictionary(uniqueKeysWithValues: zip(1...n, 1...n))
25+
for _ in 0 ..< 100_000 {
26+
check(d1 == d2)
27+
}
28+
}
29+
30+
@inline(never)
31+
public func run_DictionaryEqualShared(_ n: Int) {
32+
let d1 = Dictionary(uniqueKeysWithValues: zip(1...n, 1...n))
33+
let d2 = d1
34+
for _ in 0 ..< 100_000 {
35+
check(d1 == d2)
36+
}
37+
}
38+
39+
@inline(never)
40+
public func run_DictionaryIdentical(_ n: Int) {
41+
let d1 = Dictionary(uniqueKeysWithValues: zip(1...n, 1...n))
42+
let d2 = d1
43+
for _ in 0 ..< 100_000 {
44+
check(d1.isIdentical(to: d2))
45+
}
46+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===--- SetIdentical.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: "SetEqualUnique", runFunction: run_SetEqualUnique, tags: [.validation, .api, .Set]),
17+
BenchmarkInfo(name: "SetEqualShared", runFunction: run_SetEqualShared, tags: [.validation, .api, .Set]),
18+
BenchmarkInfo(name: "SetIdentical", runFunction: run_SetIdentical, tags: [.validation, .api, .Set]),
19+
]
20+
21+
@inline(never)
22+
public func run_SetEqualUnique(_ n: Int) {
23+
let s1 = Set(1...n)
24+
let s2 = Set(1...n)
25+
for _ in 0 ..< 100_000 {
26+
check(s1 == s2)
27+
}
28+
}
29+
30+
@inline(never)
31+
public func run_SetEqualShared(_ n: Int) {
32+
let s1 = Set(1...n)
33+
let s2 = s1
34+
for _ in 0 ..< 100_000 {
35+
check(s1 == s2)
36+
}
37+
}
38+
39+
@inline(never)
40+
public func run_SetIdentical(_ n: Int) {
41+
let s1 = Set(1...n)
42+
let s2 = s1
43+
for _ in 0 ..< 100_000 {
44+
check(s1.isIdentical(to: s2))
45+
}
46+
}

benchmark/utils/main.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ import DictionaryBridgeToObjC
7575
import DictionaryCompactMapValues
7676
import DictionaryCopy
7777
import DictionaryGroup
78+
import DictionaryIdentical
7879
import DictionaryKeysContains
7980
import DictionaryLiteralTest
8081
import DictionaryOfAnyHashableStrings
@@ -177,6 +178,7 @@ import RomanNumbers
177178
import SIMDRandomMask
178179
import SIMDReduceInteger
179180
import SequenceAlgos
181+
import SetIdentical
180182
import SetTests
181183
import SevenBoom
182184
import Sim2DArray
@@ -276,6 +278,7 @@ register(DictionaryBridgeToObjC.benchmarks)
276278
register(DictionaryCompactMapValues.benchmarks)
277279
register(DictionaryCopy.benchmarks)
278280
register(DictionaryGroup.benchmarks)
281+
register(DictionaryIdentical.benchmarks)
279282
register(DictionaryKeysContains.benchmarks)
280283
register(DictionaryLiteralTest.benchmarks)
281284
register(DictionaryOfAnyHashableStrings.benchmarks)
@@ -379,6 +382,7 @@ register(RomanNumbers.benchmarks)
379382
register(SIMDRandomMask.benchmarks)
380383
register(SIMDReduceInteger.benchmarks)
381384
register(SequenceAlgos.benchmarks)
385+
register(SetIdentical.benchmarks)
382386
register(SetTests.benchmarks)
383387
register(SevenBoom.benchmarks)
384388
register(Sim2DArray.benchmarks)

stdlib/public/core/Dictionary.swift

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,3 +2154,51 @@ extension Dictionary.Index: @unchecked Sendable
21542154
where Key: Sendable, Value: Sendable {}
21552155
extension Dictionary.Iterator: @unchecked Sendable
21562156
where Key: Sendable, Value: Sendable {}
2157+
2158+
extension Dictionary {
2159+
/// Returns a boolean value indicating whether this dictionary is identical to
2160+
/// `other`.
2161+
///
2162+
/// Two dictionary values are identical if there is no way to distinguish
2163+
/// between them.
2164+
///
2165+
/// For any values `a`, `b`, and `c`:
2166+
///
2167+
/// - `a.isIdentical(to: a)` is always `true`. (Reflexivity)
2168+
/// - `a.isIdentical(to: b)` implies `b.isIdentical(to: a)`. (Symmetry)
2169+
/// - If `a.isIdentical(to: b)` and `b.isIdentical(to: c)` are both `true`,
2170+
/// then `a.isIdentical(to: c)` is also `true`. (Transitivity)
2171+
/// - If `a` and `b` are `Equatable`, then `a.isIdentical(b)` implies `a == b`
2172+
///
2173+
/// Comparing dictionaries this way includes comparing (normally) hidden
2174+
/// implementation details such as the memory location of any underlying
2175+
/// dictionary storage object. Therefore, identical dictionaries are
2176+
/// guaranteed to compare equal with `==`, but not all equal dictionaries are
2177+
/// considered identical.
2178+
///
2179+
/// - Performance: O(1)
2180+
@_alwaysEmitIntoClient
2181+
public func isIdentical(to other: Self) -> Bool {
2182+
#if _runtime(_ObjC)
2183+
if
2184+
self._variant.isNative,
2185+
other._variant.isNative,
2186+
unsafe (self._variant.asNative._storage === other._variant.asNative._storage)
2187+
{
2188+
return true
2189+
}
2190+
if
2191+
!self._variant.isNative,
2192+
!other._variant.isNative,
2193+
self._variant.asCocoa.object === other._variant.asCocoa.object
2194+
{
2195+
return true
2196+
}
2197+
#else
2198+
if unsafe (self._variant.asNative._storage === other._variant.asNative._storage) {
2199+
return true
2200+
}
2201+
#endif
2202+
return false
2203+
}
2204+
}

stdlib/public/core/Set.swift

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,3 +1658,50 @@ extension Set.Index: @unchecked Sendable
16581658
where Element: Sendable { }
16591659
extension Set.Iterator: @unchecked Sendable
16601660
where Element: Sendable { }
1661+
1662+
extension Set {
1663+
/// Returns a boolean value indicating whether this set is identical to
1664+
/// `other`.
1665+
///
1666+
/// Two set values are identical if there is no way to distinguish between
1667+
/// them.
1668+
///
1669+
/// For any values `a`, `b`, and `c`:
1670+
///
1671+
/// - `a.isIdentical(to: a)` is always `true`. (Reflexivity)
1672+
/// - `a.isIdentical(to: b)` implies `b.isIdentical(to: a)`. (Symmetry)
1673+
/// - If `a.isIdentical(to: b)` and `b.isIdentical(to: c)` are both `true`,
1674+
/// then `a.isIdentical(to: c)` is also `true`. (Transitivity)
1675+
/// - `a.isIdentical(b)` implies `a == b`
1676+
///
1677+
/// Comparing sets this way includes comparing (normally) hidden
1678+
/// implementation details such as the memory location of any underlying set
1679+
/// storage object. Therefore, identical sets are guaranteed to compare equal
1680+
/// with `==`, but not all equal sets are considered identical.
1681+
///
1682+
/// - Performance: O(1)
1683+
@_alwaysEmitIntoClient
1684+
public func isIdentical(to other: Self) -> Bool {
1685+
#if _runtime(_ObjC)
1686+
if
1687+
self._variant.isNative,
1688+
other._variant.isNative,
1689+
unsafe (self._variant.asNative._storage === other._variant.asNative._storage)
1690+
{
1691+
return true
1692+
}
1693+
if
1694+
!self._variant.isNative,
1695+
!other._variant.isNative,
1696+
self._variant.asCocoa.object === other._variant.asCocoa.object
1697+
{
1698+
return true
1699+
}
1700+
#else
1701+
if unsafe (self._variant.asNative._storage === other._variant.asNative._storage) {
1702+
return true
1703+
}
1704+
#endif
1705+
return false
1706+
}
1707+
}

test/stdlib/DictionaryTests.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 DictionaryTests {
23+
static func main() {
24+
let testSuite = TestSuite("DictionaryTests")
25+
testSuite.test("Identical", testIdentical)
26+
runAllTests()
27+
}
28+
29+
static func testIdentical() {
30+
let d1: Dictionary = ["a": 1, "b": 2, "c": 3]
31+
expectTrue(d1.isIdentical(to: d1))
32+
33+
let d2: Dictionary = d1
34+
expectTrue(d1.isIdentical(to: d2))
35+
36+
var d3: Dictionary = d2
37+
d3.reserveCapacity(0)
38+
expectFalse(d1.isIdentical(to: d3))
39+
40+
let d4: Dictionary = ["a": 1, "b": 2, "c": 3]
41+
expectFalse(d1.isIdentical(to: d4))
42+
}
43+
}

test/stdlib/SetTests.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 SetTests {
23+
static func main() {
24+
let testSuite = TestSuite("SetTests")
25+
testSuite.test("Identical", testIdentical)
26+
runAllTests()
27+
}
28+
29+
static func testIdentical() {
30+
let s1: Set = [0, 1, 2, 3]
31+
expectTrue(s1.isIdentical(to: s1))
32+
33+
let s2: Set = s1
34+
expectTrue(s1.isIdentical(to: s2))
35+
36+
var s3: Set = s2
37+
s3.reserveCapacity(0)
38+
expectFalse(s1.isIdentical(to: s3))
39+
40+
let s4: Set = [0, 1, 2, 3]
41+
expectFalse(s1.isIdentical(to: s4))
42+
}
43+
}

0 commit comments

Comments
 (0)