Skip to content

[StdLib][RFC][DNM] Add isIdentical Methods for Quick Comparisons to Dictionary and Set #82439

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ set(SWIFT_BENCH_MODULES
single-source/DictionaryCompactMapValues
single-source/DictionaryCopy
single-source/DictionaryGroup
single-source/DictionaryIdentical
single-source/DictionaryKeysContains
single-source/DictionaryLiteralTest
single-source/DictionaryOfAnyHashableStrings
Expand Down Expand Up @@ -173,6 +174,7 @@ set(SWIFT_BENCH_MODULES
# Disabled while layout prespecializations are experimental
#single-source/SimpleArraySpecialization
single-source/SequenceAlgos
single-source/SetIdentical
single-source/SetTests
single-source/SevenBoom
single-source/Sim2DArray
Expand Down
46 changes: 46 additions & 0 deletions benchmark/single-source/DictionaryIdentical.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===--- DictionaryIdentical.swift ----------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 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
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import TestsUtils

public let benchmarks = [
BenchmarkInfo(name: "DictionaryEqualUnique", runFunction: run_DictionaryEqualUnique, tags: [.validation, .api, .Dictionary]),
BenchmarkInfo(name: "DictionaryEqualShared", runFunction: run_DictionaryEqualShared, tags: [.validation, .api, .Dictionary]),
BenchmarkInfo(name: "DictionaryIdentical", runFunction: run_DictionaryIdentical, tags: [.validation, .api, .Dictionary]),
]

@inline(never)
public func run_DictionaryEqualUnique(_ n: Int) {
let d1 = Dictionary(uniqueKeysWithValues: zip(1...n, 1...n))
let d2 = Dictionary(uniqueKeysWithValues: zip(1...n, 1...n))
for _ in 0 ..< 100_000 {
check(d1 == d2)
}
}

@inline(never)
public func run_DictionaryEqualShared(_ n: Int) {
let d1 = Dictionary(uniqueKeysWithValues: zip(1...n, 1...n))
let d2 = d1
for _ in 0 ..< 100_000 {
check(d1 == d2)
}
}

@inline(never)
public func run_DictionaryIdentical(_ n: Int) {
let d1 = Dictionary(uniqueKeysWithValues: zip(1...n, 1...n))
let d2 = d1
for _ in 0 ..< 100_000 {
check(d1.isIdentical(to: d2))
}
}
46 changes: 46 additions & 0 deletions benchmark/single-source/SetIdentical.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===--- SetIdentical.swift -----------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 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
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import TestsUtils

public let benchmarks = [
BenchmarkInfo(name: "SetEqualUnique", runFunction: run_SetEqualUnique, tags: [.validation, .api, .Set]),
BenchmarkInfo(name: "SetEqualShared", runFunction: run_SetEqualShared, tags: [.validation, .api, .Set]),
BenchmarkInfo(name: "SetIdentical", runFunction: run_SetIdentical, tags: [.validation, .api, .Set]),
]

@inline(never)
public func run_SetEqualUnique(_ n: Int) {
let s1 = Set(1...n)
let s2 = Set(1...n)
for _ in 0 ..< 100_000 {
check(s1 == s2)
}
}

@inline(never)
public func run_SetEqualShared(_ n: Int) {
let s1 = Set(1...n)
let s2 = s1
for _ in 0 ..< 100_000 {
check(s1 == s2)
}
}

@inline(never)
public func run_SetIdentical(_ n: Int) {
let s1 = Set(1...n)
let s2 = s1
for _ in 0 ..< 100_000 {
check(s1.isIdentical(to: s2))
}
}
4 changes: 4 additions & 0 deletions benchmark/utils/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import DictionaryBridgeToObjC
import DictionaryCompactMapValues
import DictionaryCopy
import DictionaryGroup
import DictionaryIdentical
import DictionaryKeysContains
import DictionaryLiteralTest
import DictionaryOfAnyHashableStrings
Expand Down Expand Up @@ -177,6 +178,7 @@ import RomanNumbers
import SIMDRandomMask
import SIMDReduceInteger
import SequenceAlgos
import SetIdentical
import SetTests
import SevenBoom
import Sim2DArray
Expand Down Expand Up @@ -276,6 +278,7 @@ register(DictionaryBridgeToObjC.benchmarks)
register(DictionaryCompactMapValues.benchmarks)
register(DictionaryCopy.benchmarks)
register(DictionaryGroup.benchmarks)
register(DictionaryIdentical.benchmarks)
register(DictionaryKeysContains.benchmarks)
register(DictionaryLiteralTest.benchmarks)
register(DictionaryOfAnyHashableStrings.benchmarks)
Expand Down Expand Up @@ -379,6 +382,7 @@ register(RomanNumbers.benchmarks)
register(SIMDRandomMask.benchmarks)
register(SIMDReduceInteger.benchmarks)
register(SequenceAlgos.benchmarks)
register(SetIdentical.benchmarks)
register(SetTests.benchmarks)
register(SevenBoom.benchmarks)
register(Sim2DArray.benchmarks)
Expand Down
40 changes: 40 additions & 0 deletions stdlib/public/core/Dictionary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2154,3 +2154,43 @@ extension Dictionary.Index: @unchecked Sendable
where Key: Sendable, Value: Sendable {}
extension Dictionary.Iterator: @unchecked Sendable
where Key: Sendable, Value: Sendable {}

extension Dictionary {
/// Returns a boolean value indicating whether this dictionary is identical to
/// `other`.
///
/// Two dictionary values are identical if there is no way to distinguish
/// between them.
///
/// Comparing dictionaries this way includes comparing (normally) hidden
/// implementation details such as the memory location of any underlying
/// dictionary storage object. Therefore, identical dictionaries are
/// guaranteed to compare equal with `==`, but not all equal dictionaries are
/// considered identical.
///
/// - Performance: O(1)
@_alwaysEmitIntoClient
public func isIdentical(to other: Self) -> Bool {
#if _runtime(_ObjC)
if
self._variant.isNative,
other._variant.isNative,
unsafe (self._variant.asNative._storage === other._variant.asNative._storage)
{
return true
}
if
!self._variant.isNative,
!other._variant.isNative,
self._variant.asCocoa.object === other._variant.asCocoa.object
{
return true
}
#else
if unsafe (self._variant.asNative._storage === other._variant.asNative._storage) {
return true
}
#endif
return false
}
}
39 changes: 39 additions & 0 deletions stdlib/public/core/Set.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1658,3 +1658,42 @@ extension Set.Index: @unchecked Sendable
where Element: Sendable { }
extension Set.Iterator: @unchecked Sendable
where Element: Sendable { }

extension Set {
/// Returns a boolean value indicating whether this set is identical to
/// `other`.
///
/// Two set values are identical if there is no way to distinguish between
/// them.
///
/// Comparing sets this way includes comparing (normally) hidden
/// implementation details such as the memory location of any underlying set
/// storage object. Therefore, identical sets are guaranteed to compare equal
/// with `==`, but not all equal sets are considered identical.
///
/// - Performance: O(1)
@_alwaysEmitIntoClient
public func isIdentical(to other: Self) -> Bool {
#if _runtime(_ObjC)
if
self._variant.isNative,
other._variant.isNative,
unsafe (self._variant.asNative._storage === other._variant.asNative._storage)
{
return true
}
if
!self._variant.isNative,
!other._variant.isNative,
self._variant.asCocoa.object === other._variant.asCocoa.object
{
return true
}
#else
if unsafe (self._variant.asNative._storage === other._variant.asNative._storage) {
return true
}
#endif
return false
}
}
43 changes: 43 additions & 0 deletions test/stdlib/DictionaryTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 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
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// RUN: %target-run-simple-swift(-parse-as-library)
// REQUIRES: executable_test
// END.
//
//===----------------------------------------------------------------------===//

import StdlibUnittest

@main
enum DictionaryTests {
static func main() {
let testSuite = TestSuite("DictionaryTests")
testSuite.test("Identical", testIdentical)
runAllTests()
}

static func testIdentical() {
let d1: Dictionary = ["a": 1, "b": 2, "c": 3]
expectTrue(d1.isIdentical(to: d1))

let d2: Dictionary = d1
expectTrue(d1.isIdentical(to: d2))

var d3: Dictionary = d2
d3.reserveCapacity(0)
expectFalse(d1.isIdentical(to: d3))

let d4: Dictionary = ["a": 1, "b": 2, "c": 3]
expectFalse(d1.isIdentical(to: d4))
}
}
43 changes: 43 additions & 0 deletions test/stdlib/SetTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 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
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// RUN: %target-run-simple-swift(-parse-as-library)
// REQUIRES: executable_test
// END.
//
//===----------------------------------------------------------------------===//

import StdlibUnittest

@main
enum SetTests {
static func main() {
let testSuite = TestSuite("SetTests")
testSuite.test("Identical", testIdentical)
runAllTests()
}

static func testIdentical() {
let s1: Set = [0, 1, 2, 3]
expectTrue(s1.isIdentical(to: s1))

let s2: Set = s1
expectTrue(s1.isIdentical(to: s2))

var s3: Set = s2
s3.reserveCapacity(0)
expectFalse(s1.isIdentical(to: s3))

let s4: Set = [0, 1, 2, 3]
expectFalse(s1.isIdentical(to: s4))
}
}