Skip to content

Commit

Permalink
Merge pull request #352 from vanvoorden/vanvoorden/tree-dictionary-ke…
Browse files Browse the repository at this point in the history
…ys-equality

[TreeDictionary][Keys] Add Equatable and Hashable Conformance to TreeDictionary.Keys
  • Loading branch information
lorentey committed Feb 7, 2024
2 parents 97b1949 + c61e5e2 commit 94cf62b
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 0 deletions.
57 changes: 57 additions & 0 deletions Benchmarks/Sources/Benchmarks/ShareableDictionaryBenchmarks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -471,5 +471,62 @@ extension Benchmark {
blackHole(d)
}
}

self.add(
title: "TreeDictionary<Int, Int> equality, unique",
input: [Int].self
) { input in
let keysAndValues = input.map { ($0, 2 * $0) }
let left = TreeDictionary(uniqueKeysWithValues: keysAndValues)
let right = TreeDictionary(uniqueKeysWithValues: keysAndValues)
return { timer in
timer.measure {
precondition(left == right)
}
}
}

self.add(
title: "TreeDictionary<Int, Int> equality, shared",
input: [Int].self
) { input in
let keysAndValues = input.map { ($0, 2 * $0) }
let left = TreeDictionary(uniqueKeysWithValues: keysAndValues)
let right = left
return { timer in
timer.measure {
precondition(left == right)
}
}
}

self.add(
title: "TreeDictionary<Int, Int>.Keys equality, unique",
input: [Int].self
) { input in
let keysAndValues = input.map { ($0, 2 * $0) }
let left = TreeDictionary(uniqueKeysWithValues: keysAndValues)
let right = TreeDictionary(uniqueKeysWithValues: keysAndValues)
return { timer in
timer.measure {
precondition(left.keys == right.keys)
}
}
}

self.add(
title: "TreeDictionary<Int, Int>.Keys equality, shared",
input: [Int].self
) { input in
let keysAndValues = input.map { ($0, 2 * $0) }
let left = TreeDictionary(uniqueKeysWithValues: keysAndValues)
let right = left
return { timer in
timer.measure {
precondition(left.keys == right.keys)
}
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,40 @@ extension TreeDictionary.Keys {
return d.keys
}
}

extension TreeDictionary.Keys: Equatable {
/// Returns a Boolean value indicating whether two values are equal.
///
/// Equality is the inverse of inequality. For any values `a` and `b`,
/// `a == b` implies that `a != b` is `false`.
///
/// - Parameter lhs: A value to compare.
/// - Parameter rhs: Another value to compare.
///
/// - Complexity: Generally O(`count`), as long as`Element` properly
/// implements hashing. That said, the implementation is careful to take
/// every available shortcut to reduce complexity, e.g. by skipping
/// comparing elements in shared subtrees.
@inlinable
public static func == (left: Self, right: Self) -> Bool {
left._base._root.isEqualSet(to: right._base._root, by: { _, _ in true })
}
}

extension TreeDictionary.Keys: Hashable {
/// Hashes the essential components of this value by feeding them into the
/// given hasher.
///
/// Complexity: O(`count`)
@inlinable
public func hash(into hasher: inout Hasher) {
let copy = hasher
let seed = copy.finalize()

var hash = 0
for member in self {
hash ^= member._rawHashValue(seed: seed)
}
hasher.combine(hash)
}
}
76 changes: 76 additions & 0 deletions Tests/HashTreeCollectionsTests/TreeDictionary.Keys Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,81 @@ class TreeDictionaryKeysTests: CollectionTestCase {
}
}
}

func test_isEqual_exhaustive() {
withEverySubset("a", of: testItems) { a in
let x = TreeDictionary<RawCollider, Int>(
uniqueKeysWithValues: a.lazy.map { ($0, 2 * $0.identity) })
let u = Set(a)
expectEqualSets(x.keys, u)
withEverySubset("b", of: testItems) { b in
let y = TreeDictionary<RawCollider, Int>(
uniqueKeysWithValues: b.lazy.map { ($0, -$0.identity - 1) })
let v = Set(b)
expectEqualSets(y.keys, v)

let reference = u == v
print(reference)

expectEqual(x.keys == y.keys, reference)
}
}
}

func test_Hashable() {
let strings: [[[String]]] = [
[
[]
],
[
["a"]
],
[
["b"]
],
[
["c"]
],
[
["d"]
],
[
["e"]
],
[
["f"], ["f"],
],
[
["g"], ["g"],
],
[
["h"], ["h"],
],
[
["i"], ["i"],
],
[
["j"], ["j"],
],
[
["a", "b"], ["b", "a"],
],
[
["a", "d"], ["d", "a"],
],
[
["a", "b", "c"], ["a", "c", "b"],
["b", "a", "c"], ["b", "c", "a"],
["c", "a", "b"], ["c", "b", "a"],
],
[
["a", "d", "e"], ["a", "e", "d"],
["d", "a", "e"], ["d", "e", "a"],
["e", "a", "d"], ["e", "d", "a"],
],
]
let keys = strings.map { $0.map { TreeDictionary(uniqueKeysWithValues: $0.map { ($0, Int.random(in: 1...100)) }).keys }}
checkHashable(equivalenceClasses: keys)
}

}
15 changes: 15 additions & 0 deletions Tests/HashTreeCollectionsTests/TreeSet Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,21 @@ class TreeSetTests: CollectionTestCase {
[
["e"]
],
[
["f"], ["f"],
],
[
["g"], ["g"],
],
[
["h"], ["h"],
],
[
["i"], ["i"],
],
[
["j"], ["j"],
],
[
["a", "b"], ["b", "a"],
],
Expand Down

0 comments on commit 94cf62b

Please sign in to comment.