Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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.isTriviallyIdentical(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.isTriviallyIdentical(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 @@ -275,6 +277,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 @@ -378,6 +381,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
61 changes: 61 additions & 0 deletions stdlib/public/core/Dictionary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2154,3 +2154,64 @@ 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.
///
/// For any values `a`, `b`, and `c`:
///
/// - `a.isTriviallyIdentical(to: a)` is always `true`. (Reflexivity)
/// - `a.isTriviallyIdentical(to: b)` implies `b.isTriviallyIdentical(to: a)`.
/// (Symmetry)
/// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)`
/// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`.
/// (Transitivity)
/// - If `a` and `b` are `Equatable`, then `a.isTriviallyIdentical(b)` implies
/// `a == b`
/// - `a == b` does not imply `a.isTriviallyIdentical(b)`
///
/// Values produced by copying the same value, with no intervening mutations,
/// will compare identical:
///
/// ```swift
/// let d = c
/// print(c.isTriviallyIdentical(to: d))
/// // Prints true
/// ```
///
/// 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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lorentey Opaque here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type is generic, so sadly the answer is no -- we need this to be at least @inlinable. @_aeic is fine.

public func isTriviallyIdentical(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
}
}
59 changes: 59 additions & 0 deletions stdlib/public/core/Set.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1658,3 +1658,62 @@ 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.
///
/// For any values `a`, `b`, and `c`:
///
/// - `a.isTriviallyIdentical(to: a)` is always `true`. (Reflexivity)
/// - `a.isTriviallyIdentical(to: b)` implies `b.isTriviallyIdentical(to: a)`.
/// (Symmetry)
/// - If `a.isTriviallyIdentical(to: b)` and `b.isTriviallyIdentical(to: c)`
/// are both `true`, then `a.isTriviallyIdentical(to: c)` is also `true`.
/// (Transitivity)
/// - `a.isTriviallyIdentical(b)` implies `a == b`
/// - `a == b` does not imply `a.isTriviallyIdentical(b)`
///
/// Values produced by copying the same value, with no intervening mutations,
/// will compare identical:
///
/// ```swift
/// let d = c
/// print(c.isTriviallyIdentical(to: d))
/// // Prints true
/// ```
///
/// 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 isTriviallyIdentical(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.isTriviallyIdentical(to: d1))

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

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

let d4: Dictionary = ["a": 1, "b": 2, "c": 3]
expectFalse(d1.isTriviallyIdentical(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.isTriviallyIdentical(to: s1))

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

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

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