Skip to content

Commit fc4d4e2

Browse files
committed
[stdlib] Switch to _hash(into:) in standard Hashable types.
1 parent a8bca08 commit fc4d4e2

13 files changed

+137
-75
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3584,8 +3584,8 @@ getOrCreateKeyPathEqualsAndHash(SILGenFunction &SGF,
35843584

35853585
SILValue hashCode;
35863586

3587-
// TODO: Combine hashes of the indexes. There isn't a great hash combining
3588-
// interface in the standard library to do this yet.
3587+
// TODO: Combine hashes of the indexes using an _UnsafeHasher passed in as
3588+
// an extra parameter.
35893589
{
35903590
auto &index = indexes[0];
35913591

stdlib/public/core/Bool.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ extension Bool : Equatable, Hashable {
159159
return self ? 1 : 0
160160
}
161161

162+
@_inlineable // FIXME(sil-serialize-all)
163+
@_transparent
164+
public func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {
165+
return hasher.appending((self ? 1 : 0) as UInt8)
166+
}
167+
162168
@_inlineable // FIXME(sil-serialize-all)
163169
@_transparent
164170
public static func == (lhs: Bool, rhs: Bool) -> Bool {

stdlib/public/core/CTypes.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,12 @@ extension OpaquePointer: Hashable {
162162
/// program runs.
163163
@_inlineable // FIXME(sil-serialize-all)
164164
public var hashValue: Int {
165-
return Int(Builtin.ptrtoint_Word(_rawValue))
165+
return _hashValue(for: self)
166+
}
167+
168+
@_inlineable // FIXME(sil-serialize-all)
169+
public func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {
170+
return hasher.appending(Int(Builtin.ptrtoint_Word(_rawValue)))
166171
}
167172
}
168173

stdlib/public/core/DoubleWidth.swift.gyb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,12 @@ 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: _UnsafeHasher) -> _UnsafeHasher {
159+
return hasher.appending(low).appending(high)
158160
}
159161
}
160162

stdlib/public/core/DropWhile.swift.gyb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ extension LazyDropWhileIndex : Hashable where Base.Index : Hashable {
144144
public var hashValue: Int {
145145
return base.hashValue
146146
}
147+
148+
public func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {
149+
return hasher.appending(base)
150+
}
147151
}
148152

149153
% for Traversal in ['Forward', 'Bidirectional']:

stdlib/public/core/Flatten.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,13 @@ 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: _UnsafeHasher) -> _UnsafeHasher {
240+
let h = hasher.appending(_outer)
241+
guard let inner = _inner else { return h }
242+
return h.appending(inner)
237243
}
238244
}
239245

stdlib/public/core/FloatingPointTypes.swift.gyb

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,26 +1508,26 @@ extension ${Self} : Hashable {
15081508
/// your program. Do not save hash values to use during a future execution.
15091509
@_inlineable // FIXME(sil-serialize-all)
15101510
public var hashValue: Int {
1511+
return _hashValue(for: self)
1512+
}
1513+
1514+
@_inlineable // FIXME(sil-serialize-all)
1515+
public func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {
1516+
var v = self
15111517
if isZero {
15121518
// To satisfy the axiom that equality implies hash equality, we need to
15131519
// finesse the hash value of -0.0 to match +0.0.
1514-
return 0
1515-
} else {
1516-
%if bits <= word_bits:
1517-
return Int(bitPattern: UInt(bitPattern))
1518-
%elif bits == 64: # Double -> 32-bit Int
1519-
return Int(truncatingIfNeeded: bitPattern &>> 32) ^
1520-
Int(truncatingIfNeeded: bitPattern)
1521-
%elif word_bits == 32: # Float80 -> 32-bit Int
1522-
return Int(truncatingIfNeeded: significandBitPattern &>> 32) ^
1523-
Int(truncatingIfNeeded: significandBitPattern) ^
1524-
Int(_representation.signAndExponent)
1525-
%else: # Float80 -> 64-bit Int
1526-
return Int(bitPattern: UInt(significandBitPattern)) ^
1527-
Int(_representation.signAndExponent)
1528-
%end
1520+
v = 0
15291521
}
1522+
%if bits == 80:
1523+
return hasher
1524+
.appending(v._representation.signAndExponent)
1525+
.appending(v.significandBitPattern)
1526+
%else:
1527+
return hasher.appending(v.bitPattern)
1528+
%end
15301529
}
1530+
15311531
}
15321532

15331533
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: _UnsafeHasher) -> _UnsafeHasher {
800+
var hash = 0
796801
for member in self {
797-
result ^= _mixInt(member.hashValue)
802+
hash ^= _hashValue(for: member)
798803
}
799-
return result
804+
return hasher.appending(hash)
800805
}
801806
}
802807

stdlib/public/core/KeyPath.swift

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,27 @@ 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: _UnsafeHasher) -> _UnsafeHasher {
57+
return withBuffer {
58+
var hasher = hasher
5459
var buffer = $0
5560
while true {
5661
let (component, type) = buffer.next()
57-
hash ^= _mixInt(component.value.hashValue)
62+
hasher = hasher.appending(component.value)
5863
if let type = type {
59-
hash ^= _mixInt(unsafeBitCast(type, to: Int.self))
64+
hasher = hasher.appending(unsafeBitCast(type, to: Int.self))
6065
} else {
6166
break
6267
}
6368
}
69+
return hasher
6470
}
65-
return hash
6671
}
72+
6773
@_inlineable // FIXME(sil-serialize-all)
6874
public static func ==(a: AnyKeyPath, b: AnyKeyPath) -> Bool {
6975
// Fast-path identical objects
@@ -452,11 +458,15 @@ internal struct ComputedPropertyID: Hashable {
452458
@_inlineable // FIXME(sil-serialize-all)
453459
@_versioned // FIXME(sil-serialize-all)
454460
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
461+
return _hashValue(for: self)
462+
}
463+
464+
@_inlineable // FIXME(sil-serialize-all)
465+
public func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {
466+
return hasher
467+
.appending(value)
468+
.appending(isStoredProperty)
469+
.appending(isTableOffset)
460470
}
461471
}
462472

@@ -473,6 +483,7 @@ internal struct ComputedArgumentWitnesses {
473483
(_ xInstanceArguments: UnsafeRawPointer,
474484
_ yInstanceArguments: UnsafeRawPointer,
475485
_ size: Int) -> Bool
486+
// FIXME(hashing) Pass in, append to and return _UnsafeHasher instead
476487
internal typealias Hash = @convention(thin)
477488
(_ instanceArguments: UnsafeRawPointer,
478489
_ size: Int) -> Int
@@ -584,46 +595,50 @@ internal enum KeyPathComponent: Hashable {
584595
@_inlineable // FIXME(sil-serialize-all)
585596
@_versioned // FIXME(sil-serialize-all)
586597
internal var hashValue: Int {
587-
var hash: Int = 0
588-
func mixHashFromArgument(_ argument: KeyPathComponent.ArgumentRef?) {
598+
return _hashValue(for: self)
599+
}
600+
601+
@_inlineable // FIXME(sil-serialize-all)
602+
@_versioned // FIXME(sil-serialize-all)
603+
internal func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {
604+
var hasher = hasher
605+
func appendHashFromArgument(
606+
_ argument: KeyPathComponent.ArgumentRef?
607+
) {
589608
if let argument = argument {
590-
let addedHash = argument.witnesses.pointee.hash(
609+
let hash = argument.witnesses.pointee.hash(
591610
argument.data.baseAddress.unsafelyUnwrapped,
592611
argument.data.count)
593612
// Returning 0 indicates that the arguments should not impact the
594613
// hash value of the overall key path.
595-
if addedHash != 0 {
596-
hash ^= _mixInt(addedHash)
614+
// FIXME(hasher): hash witness should just return hasher directly
615+
if hash != 0 {
616+
hasher = hasher.appending(hash)
597617
}
598618
}
599619
}
600620
switch self {
601621
case .struct(offset: let a):
602-
hash ^= _mixInt(0)
603-
hash ^= _mixInt(a)
622+
hasher = hasher.appending(0).appending(a)
604623
case .class(offset: let b):
605-
hash ^= _mixInt(1)
606-
hash ^= _mixInt(b)
624+
hasher = hasher.appending(1).appending(b)
607625
case .optionalChain:
608-
hash ^= _mixInt(2)
626+
hasher = hasher.appending(2)
609627
case .optionalForce:
610-
hash ^= _mixInt(3)
628+
hasher = hasher.appending(3)
611629
case .optionalWrap:
612-
hash ^= _mixInt(4)
630+
hasher = hasher.appending(4)
613631
case .get(id: let id, get: _, argument: let argument):
614-
hash ^= _mixInt(5)
615-
hash ^= _mixInt(id.hashValue)
616-
mixHashFromArgument(argument)
632+
hasher = hasher.appending(5).appending(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 = hasher.appending(6).appending(id)
636+
appendHashFromArgument(argument)
621637
case .nonmutatingGetSet(id: let id, get: _, set: _, argument: let argument):
622-
hash ^= _mixInt(7)
623-
hash ^= _mixInt(id.hashValue)
624-
mixHashFromArgument(argument)
638+
hasher = hasher.appending(7).appending(id)
639+
appendHashFromArgument(argument)
625640
}
626-
return hash
641+
return hasher
627642
}
628643
}
629644

stdlib/public/core/PrefixWhile.swift.gyb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,15 @@ public struct LazyPrefixWhileIndex<Base : Collection> : Comparable {
164164

165165
extension LazyPrefixWhileIndex : Hashable where Base.Index : Hashable {
166166
public var hashValue: Int {
167+
return _hashValue(for: self)
168+
}
169+
170+
public func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {
167171
switch _value {
168172
case .index(let value):
169-
return value.hashValue
173+
return hasher.appending(value)
170174
case .pastEnd:
171-
return .max
175+
return hasher.appending(Int.max)
172176
}
173177
}
174178
}

stdlib/public/core/Reverse.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ extension ReversedCollection.Index: Hashable where Base.Index: Hashable {
197197
public var hashValue: Int {
198198
return base.hashValue
199199
}
200+
201+
public func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {
202+
return hasher.appending(base)
203+
}
200204
}
201205

202206
extension ReversedCollection: BidirectionalCollection {

stdlib/public/core/StringHashable.swift

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,34 +37,33 @@ extension Unicode {
3737
// @_inlineable // FIXME(sil-serialize-all)
3838
// @_versioned // FIXME(sil-serialize-all)
3939
internal static func hashASCII(
40-
_ string: UnsafeBufferPointer<UInt8>
41-
) -> Int {
40+
_ string: UnsafeBufferPointer<UInt8>,
41+
into hasher: inout _Hasher
42+
) {
4243
let collationTable = _swift_stdlib_unicode_getASCIICollationTable()
43-
var hasher = _SipHash13Context(key: _Hashing.secretKey)
4444
for c in string {
4545
_precondition(c <= 127)
4646
let element = collationTable[Int(c)]
4747
// Ignore zero valued collation elements. They don't participate in the
4848
// ordering relation.
4949
if element != 0 {
50-
hasher.append(element)
50+
hasher.append(Int(truncatingIfNeeded: element))
5151
}
5252
}
53-
return hasher._finalizeAndReturnIntHash()
5453
}
5554

5655
// FIXME: cannot be marked @_versioned. See <rdar://problem/34438258>
5756
// @_inlineable // FIXME(sil-serialize-all)
5857
// @_versioned // FIXME(sil-serialize-all)
5958
internal static func hashUTF16(
60-
_ string: UnsafeBufferPointer<UInt16>
61-
) -> Int {
59+
_ string: UnsafeBufferPointer<UInt16>,
60+
into hasher: inout _Hasher
61+
) {
6262
let collationIterator = _swift_stdlib_unicodeCollationIterator_create(
6363
string.baseAddress!,
6464
UInt32(string.count))
6565
defer { _swift_stdlib_unicodeCollationIterator_delete(collationIterator) }
6666

67-
var hasher = _SipHash13Context(key: _Hashing.secretKey)
6867
while true {
6968
var hitEnd = false
7069
let element =
@@ -75,10 +74,9 @@ extension Unicode {
7574
// Ignore zero valued collation elements. They don't participate in the
7675
// ordering relation.
7776
if element != 0 {
78-
hasher.append(element)
77+
hasher.append(Int(truncatingIfNeeded: element))
7978
}
8079
}
81-
return hasher._finalizeAndReturnIntHash()
8280
}
8381
}
8482

@@ -100,7 +98,9 @@ extension _UnmanagedString where CodeUnit == UInt8 {
10098
// Swift.String.hashValue and NSString.hash being the same.
10199
return stringHashOffset ^ hash
102100
#else
103-
return Unicode.hashASCII(self.buffer)
101+
var hasher = _Hasher()
102+
Unicode.hashASCII(self.buffer, into: &hasher)
103+
return hasher.finalize()
104104
#endif // _runtime(_ObjC)
105105
}
106106
}
@@ -118,7 +118,9 @@ extension _UnmanagedString where CodeUnit == UTF16.CodeUnit {
118118
// Swift.String.hashValue and NSString.hash being the same.
119119
return stringHashOffset ^ hash
120120
#else
121-
return Unicode.hashUTF16(self.buffer)
121+
var hasher = _Hasher()
122+
Unicode.hashUTF16(self.buffer, into: &hasher)
123+
return hasher.finalize()
122124
#endif // _runtime(_ObjC)
123125
}
124126
}
@@ -139,7 +141,11 @@ extension _UnmanagedOpaqueString {
139141
defer { p.deallocate(capacity: count) }
140142
let buffer = UnsafeMutableBufferPointer(start: p, count: count)
141143
_copy(into: buffer)
142-
return Unicode.hashUTF16(UnsafeBufferPointer(buffer))
144+
var hasher = _Hasher()
145+
Unicode.hashUTF16(
146+
UnsafeBufferPointer(start: p, count: count),
147+
into: &hasher)
148+
return hasher.finalize()
143149
#endif
144150
}
145151
}

0 commit comments

Comments
 (0)