Skip to content

Commit f8ce962

Browse files
committed
[stdlib] Implement _hash(into:) for standard Hashable types.
1 parent 42cab58 commit f8ce962

13 files changed

+148
-77
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3593,8 +3593,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
35933593

35943594
SILValue hashCode;
35953595

3596-
// TODO: Combine hashes of the indexes. There isn't a great hash combining
3597-
// interface in the standard library to do this yet.
3596+
// TODO: Combine hashes of the indexes using an inout _Hasher
35983597
{
35993598
auto &index = indexes[0];
36003599

stdlib/public/core/Bool.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,13 @@ extension Bool : Equatable, Hashable {
154154
/// invocations of the same program. Do not persist the hash value across
155155
/// program runs.
156156
@_inlineable // FIXME(sil-serialize-all)
157-
@_transparent
158157
public var hashValue: Int {
159-
return self ? 1 : 0
158+
return _hashValue(for: self)
159+
}
160+
161+
@_inlineable // FIXME(sil-serialize-all)
162+
public func _hash(into hasher: inout _Hasher) {
163+
hasher.append((self ? 1 : 0) as UInt8)
160164
}
161165

162166
@_inlineable // FIXME(sil-serialize-all)

stdlib/public/core/CTypes.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,12 @@ extension OpaquePointer: Hashable {
182182
/// program runs.
183183
@_inlineable // FIXME(sil-serialize-all)
184184
public var hashValue: Int {
185-
return Int(Builtin.ptrtoint_Word(_rawValue))
185+
return _hashValue(for: self)
186+
}
187+
188+
@_inlineable // FIXME(sil-serialize-all)
189+
public func _hash(into hasher: inout _Hasher) {
190+
hasher.append(Int(Builtin.ptrtoint_Word(_rawValue)))
186191
}
187192
}
188193

stdlib/public/core/DoubleWidth.swift.gyb

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,13 @@ extension DoubleWidth : Comparable {
151151
extension DoubleWidth : Hashable {
152152
@_inlineable // FIXME(sil-serialize-all)
153153
public var hashValue: Int {
154-
var result = 0
155-
result = _combineHashValues(result, _storage.high.hashValue)
156-
result = _combineHashValues(result, _storage.low.hashValue)
157-
return result
154+
return _hashValue(for: self)
155+
}
156+
157+
@_inlineable // FIXME(sil-serialize-all)
158+
public func _hash(into hasher: inout _Hasher) {
159+
hasher.append(low)
160+
hasher.append(high)
158161
}
159162
}
160163

stdlib/public/core/DropWhile.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ extension LazyDropWhileCollection.Index: Hashable where Base.Index: Hashable {
190190
public var hashValue: Int {
191191
return base.hashValue
192192
}
193+
194+
public func _hash(into hasher: inout _Hasher) {
195+
hasher.append(base)
196+
}
193197
}
194198

195199
extension LazyDropWhileCollection: Collection {

stdlib/public/core/Flatten.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,14 @@ extension FlattenCollection.Index : Comparable {
233233
extension FlattenCollection.Index : Hashable
234234
where Base.Index : Hashable, Base.Element.Index : Hashable {
235235
public var hashValue: Int {
236-
return _combineHashValues(_inner?.hashValue ?? 0, _outer.hashValue)
236+
return _hashValue(for: self)
237+
}
238+
239+
public func _hash(into hasher: inout _Hasher) {
240+
hasher.append(_outer)
241+
if let inner = _inner {
242+
hasher.append(inner)
243+
}
237244
}
238245
}
239246

stdlib/public/core/FloatingPointTypes.swift.gyb

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,26 +1524,25 @@ extension ${Self} : Hashable {
15241524
/// your program. Do not save hash values to use during a future execution.
15251525
@_inlineable // FIXME(sil-serialize-all)
15261526
public var hashValue: Int {
1527+
return _hashValue(for: self)
1528+
}
1529+
1530+
@_inlineable // FIXME(sil-serialize-all)
1531+
public func _hash(into hasher: inout _Hasher) {
1532+
var v = self
15271533
if isZero {
15281534
// To satisfy the axiom that equality implies hash equality, we need to
15291535
// finesse the hash value of -0.0 to match +0.0.
1530-
return 0
1531-
} else {
1532-
%if bits <= word_bits:
1533-
return Int(bitPattern: UInt(bitPattern))
1534-
%elif bits == 64: # Double -> 32-bit Int
1535-
return Int(truncatingIfNeeded: bitPattern &>> 32) ^
1536-
Int(truncatingIfNeeded: bitPattern)
1537-
%elif word_bits == 32: # Float80 -> 32-bit Int
1538-
return Int(truncatingIfNeeded: significandBitPattern &>> 32) ^
1539-
Int(truncatingIfNeeded: significandBitPattern) ^
1540-
Int(_representation.signAndExponent)
1541-
%else: # Float80 -> 64-bit Int
1542-
return Int(bitPattern: UInt(significandBitPattern)) ^
1543-
Int(_representation.signAndExponent)
1544-
%end
1536+
v = 0
15451537
}
1538+
%if bits == 80:
1539+
hasher.append(v._representation.signAndExponent)
1540+
hasher.append(v.significandBitPattern)
1541+
%else:
1542+
hasher.append(v.bitPattern)
1543+
%end
15461544
}
1545+
15471546
}
15481547

15491548
extension ${Self} {

stdlib/public/core/HashedCollections.swift.gyb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -792,11 +792,16 @@ extension Set : Hashable {
792792
@_inlineable // FIXME(sil-serialize-all)
793793
public var hashValue: Int {
794794
// FIXME(ABI)#177: <rdar://problem/18915294> Cache Set<T> hashValue
795-
var result: Int = _mixInt(0)
795+
return _hashValue(for: self)
796+
}
797+
798+
@_inlineable // FIXME(sil-serialize-all)
799+
public func _hash(into hasher: inout _Hasher) {
800+
var hash = 0
796801
for member in self {
797-
result ^= _mixInt(member.hashValue)
802+
hash ^= _hashValue(for: member)
798803
}
799-
return result
804+
hasher.append(hash)
800805
}
801806
}
802807

stdlib/public/core/KeyPath.swift

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,25 @@ public class AnyKeyPath: Hashable, _AppendKeyPath {
4949

5050
@_inlineable // FIXME(sil-serialize-all)
5151
final public var hashValue: Int {
52-
var hash = 0
53-
withBuffer {
52+
return _hashValue(for: self)
53+
}
54+
55+
@_inlineable // FIXME(sil-serialize-all)
56+
public func _hash(into hasher: inout _Hasher) {
57+
return withBuffer {
5458
var buffer = $0
5559
while true {
5660
let (component, type) = buffer.next()
57-
hash ^= _mixInt(component.value.hashValue)
61+
hasher.append(component.value)
5862
if let type = type {
59-
hash ^= _mixInt(unsafeBitCast(type, to: Int.self))
63+
hasher.append(unsafeBitCast(type, to: Int.self))
6064
} else {
6165
break
6266
}
6367
}
6468
}
65-
return hash
6669
}
70+
6771
@_inlineable // FIXME(sil-serialize-all)
6872
public static func ==(a: AnyKeyPath, b: AnyKeyPath) -> Bool {
6973
// Fast-path identical objects
@@ -452,11 +456,14 @@ internal struct ComputedPropertyID: Hashable {
452456
@_inlineable // FIXME(sil-serialize-all)
453457
@_versioned // FIXME(sil-serialize-all)
454458
internal var hashValue: Int {
455-
var hash = 0
456-
hash ^= _mixInt(value)
457-
hash ^= _mixInt(isStoredProperty ? 13 : 17)
458-
hash ^= _mixInt(isTableOffset ? 19 : 23)
459-
return hash
459+
return _hashValue(for: self)
460+
}
461+
462+
@_inlineable // FIXME(sil-serialize-all)
463+
public func _hash(into hasher: inout _Hasher) {
464+
hasher.append(value)
465+
hasher.append(isStoredProperty)
466+
hasher.append(isTableOffset)
460467
}
461468
}
462469

@@ -473,6 +480,7 @@ internal struct ComputedArgumentWitnesses {
473480
(_ xInstanceArguments: UnsafeRawPointer,
474481
_ yInstanceArguments: UnsafeRawPointer,
475482
_ size: Int) -> Bool
483+
// FIXME(hasher) Append to an inout _Hasher instead
476484
internal typealias Hash = @convention(thin)
477485
(_ instanceArguments: UnsafeRawPointer,
478486
_ size: Int) -> Int
@@ -584,46 +592,54 @@ internal enum KeyPathComponent: Hashable {
584592
@_inlineable // FIXME(sil-serialize-all)
585593
@_versioned // FIXME(sil-serialize-all)
586594
internal var hashValue: Int {
587-
var hash: Int = 0
588-
func mixHashFromArgument(_ argument: KeyPathComponent.ArgumentRef?) {
595+
return _hashValue(for: self)
596+
}
597+
598+
@_inlineable // FIXME(sil-serialize-all)
599+
@_versioned // FIXME(sil-serialize-all)
600+
internal func _hash(into hasher: inout _Hasher) {
601+
var hasher = hasher
602+
func appendHashFromArgument(
603+
_ argument: KeyPathComponent.ArgumentRef?
604+
) {
589605
if let argument = argument {
590-
let addedHash = argument.witnesses.pointee.hash(
606+
let hash = argument.witnesses.pointee.hash(
591607
argument.data.baseAddress.unsafelyUnwrapped,
592608
argument.data.count)
593609
// Returning 0 indicates that the arguments should not impact the
594610
// hash value of the overall key path.
595-
if addedHash != 0 {
596-
hash ^= _mixInt(addedHash)
611+
// FIXME(hasher): hash witness should just mutate hasher directly
612+
if hash != 0 {
613+
hasher.append(hash)
597614
}
598615
}
599616
}
600617
switch self {
601618
case .struct(offset: let a):
602-
hash ^= _mixInt(0)
603-
hash ^= _mixInt(a)
619+
hasher.append(0)
620+
hasher.append(a)
604621
case .class(offset: let b):
605-
hash ^= _mixInt(1)
606-
hash ^= _mixInt(b)
622+
hasher.append(1)
623+
hasher.append(b)
607624
case .optionalChain:
608-
hash ^= _mixInt(2)
625+
hasher.append(2)
609626
case .optionalForce:
610-
hash ^= _mixInt(3)
627+
hasher.append(3)
611628
case .optionalWrap:
612-
hash ^= _mixInt(4)
629+
hasher.append(4)
613630
case .get(id: let id, get: _, argument: let argument):
614-
hash ^= _mixInt(5)
615-
hash ^= _mixInt(id.hashValue)
616-
mixHashFromArgument(argument)
631+
hasher.append(5)
632+
hasher.append(id)
633+
appendHashFromArgument(argument)
617634
case .mutatingGetSet(id: let id, get: _, set: _, argument: let argument):
618-
hash ^= _mixInt(6)
619-
hash ^= _mixInt(id.hashValue)
620-
mixHashFromArgument(argument)
635+
hasher.append(6)
636+
hasher.append(id)
637+
appendHashFromArgument(argument)
621638
case .nonmutatingGetSet(id: let id, get: _, set: _, argument: let argument):
622-
hash ^= _mixInt(7)
623-
hash ^= _mixInt(id.hashValue)
624-
mixHashFromArgument(argument)
639+
hasher.append(7)
640+
hasher.append(id)
641+
appendHashFromArgument(argument)
625642
}
626-
return hash
627643
}
628644
}
629645

stdlib/public/core/PrefixWhile.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,15 @@ extension LazyPrefixWhileCollection.Index: Comparable {
208208

209209
extension LazyPrefixWhileCollection.Index: Hashable where Base.Index: Hashable {
210210
public var hashValue: Int {
211+
return _hashValue(for: self)
212+
}
213+
214+
public func _hash(into hasher: inout _Hasher) {
211215
switch _value {
212216
case .index(let value):
213-
return value.hashValue
217+
hasher.append(value)
214218
case .pastEnd:
215-
return .max
219+
hasher.append(Int.max)
216220
}
217221
}
218222
}

0 commit comments

Comments
 (0)