Skip to content
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

[TreeDictionary][Keys] Add Equatable and Hashable Conformance to TreeDictionary.Keys #352

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)
}
}
}

}
}
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)
}
}
40 changes: 40 additions & 0 deletions Tests/HashTreeCollectionsTests/TreeDictionary.Keys Tests.swift
Expand Up @@ -105,5 +105,45 @@ 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_Equatable_Hashable() {
let samples: [[TreeDictionary<Int, Int>]] = [
[[:], [:]],
[[1: 100], [1: 100]],
[[2: 200], [2: 200]],
[[3: 300], [3: 300]],
[[100: 1], [100: 1]],
[[1: 1], [1: 1]],
[[100: 100], [100: 100]],
[[1: 100, 2: 200], [2: 200, 1: 100]],
[[1: 100, 2: 200, 3: 300],
[1: 100, 3: 300, 2: 200],
[2: 200, 1: 100, 3: 300],
[2: 200, 3: 300, 1: 100],
[3: 300, 1: 100, 2: 200],
[3: 300, 2: 200, 1: 100]]
]
checkHashable(equivalenceClasses: samples.map { $0.map { $0.keys }})
vanvoorden marked this conversation as resolved.
Show resolved Hide resolved
}

}