Skip to content

Commit 6cef0be

Browse files
authored
Merge pull request #19495 from lorentey/simplify-rawHashValue
[stdlib] Finalize one-shot hashing interface
2 parents 5142b41 + b2ef455 commit 6cef0be

26 files changed

+183
-195
lines changed

stdlib/private/StdlibUnittest/StdlibUnittest.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2378,7 +2378,7 @@ public func checkHashable<Instances: Collection>(
23782378
""",
23792379
stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
23802380
expectEqual(
2381-
x._rawHashValue(seed: (0, 0)), y._rawHashValue(seed: (0, 0)),
2381+
x._rawHashValue(seed: 0), y._rawHashValue(seed: 0),
23822382
"""
23832383
_rawHashValue expected to match, found to differ
23842384
lhs (at index \(i)): \(x)
@@ -2399,8 +2399,8 @@ public func checkHashable<Instances: Collection>(
23992399
""",
24002400
stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
24012401
expectTrue(
2402-
(0..<10 as Range<UInt64>).contains { i in
2403-
x._rawHashValue(seed: (0, i)) != y._rawHashValue(seed: (0, i))
2402+
(0..<10).contains { i in
2403+
x._rawHashValue(seed: i) != y._rawHashValue(seed: i)
24042404
},
24052405
"""
24062406
_rawHashValue(seed:) expected to differ, found to match

stdlib/public/SDK/ObjectiveC/ObjectiveC.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ extension NSObject : Equatable, Hashable {
240240
hasher.combine(hashValue)
241241
}
242242

243-
public func _rawHashValue(seed: (UInt64, UInt64)) -> Int {
243+
public func _rawHashValue(seed: Int) -> Int {
244244
// FIXME: We should use self.hash here, but hashValue is currently
245245
// overridable.
246246
return self.hashValue._rawHashValue(seed: seed)

stdlib/public/SwiftShims/GlobalObjects.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ struct _SwiftDictionaryBodyStorage {
4444
__swift_intptr_t count;
4545
__swift_intptr_t capacity;
4646
__swift_intptr_t scale;
47-
__swift_uint64_t seed0;
48-
__swift_uint64_t seed1;
47+
__swift_intptr_t seed;
4948
void *rawKeys;
5049
void *rawValues;
5150
};
@@ -54,8 +53,7 @@ struct _SwiftSetBodyStorage {
5453
__swift_intptr_t count;
5554
__swift_intptr_t capacity;
5655
__swift_intptr_t scale;
57-
__swift_uint64_t seed0;
58-
__swift_uint64_t seed1;
56+
__swift_intptr_t seed;
5957
void *rawElements;
6058
};
6159

stdlib/public/core/AnyHashable.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ internal protocol _AnyHashableBox {
4949
func _isEqual(to box: _AnyHashableBox) -> Bool?
5050
var _hashValue: Int { get }
5151
func _hash(into hasher: inout Hasher)
52-
func _rawHashValue(_seed: (UInt64, UInt64)) -> Int
52+
func _rawHashValue(_seed: Int) -> Int
5353

5454
var _base: Any { get }
5555
func _unbox<T: Hashable>() -> T?
@@ -97,7 +97,7 @@ internal struct _ConcreteHashableBox<Base : Hashable> : _AnyHashableBox {
9797
}
9898

9999
@inlinable // FIXME(sil-serialize-all)
100-
func _rawHashValue(_seed: (UInt64, UInt64)) -> Int {
100+
func _rawHashValue(_seed: Int) -> Int {
101101
return _baseHashable._rawHashValue(seed: _seed)
102102
}
103103

@@ -269,7 +269,7 @@ extension AnyHashable : Hashable {
269269
}
270270

271271
@inlinable // FIXME(sil-serialize-all)
272-
public func _rawHashValue(seed: (UInt64, UInt64)) -> Int {
272+
public func _rawHashValue(seed: Int) -> Int {
273273
return _box._canonicalBox._rawHashValue(_seed: seed)
274274
}
275275
}

stdlib/public/core/Array.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1836,7 +1836,7 @@ internal struct _ArrayAnyHashableBox<Element: Hashable>
18361836
}
18371837
}
18381838

1839-
func _rawHashValue(_seed: (UInt64, UInt64)) -> Int {
1839+
func _rawHashValue(_seed: Int) -> Int {
18401840
var hasher = Hasher(_seed: _seed)
18411841
self._hash(into: &hasher)
18421842
return hasher._finalize()

stdlib/public/core/Dictionary.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1584,7 +1584,7 @@ internal struct _DictionaryAnyHashableBox<Key: Hashable, Value: Hashable>
15841584
_canonical.hash(into: &hasher)
15851585
}
15861586

1587-
internal func _rawHashValue(_seed: Hasher._Seed) -> Int {
1587+
internal func _rawHashValue(_seed: Int) -> Int {
15881588
return _canonical._rawHashValue(seed: _seed)
15891589
}
15901590

stdlib/public/core/DictionaryStorage.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ internal class _RawDictionaryStorage: __SwiftNativeNSDictionary {
4444
internal final var _scale: Int
4545

4646
@usableFromInline
47-
internal final var _seed: Hasher._Seed
47+
internal final var _seed: Int
4848

4949
@usableFromInline
5050
@nonobjc
@@ -287,9 +287,8 @@ final internal class _DictionaryStorage<Key: Hashable, Value>
287287
// FIXME: Use true per-instance seeding instead. Per-capacity seeding still
288288
// leaves hash values the same in same-sized tables, which may affect
289289
// operations on two tables at once. (E.g., union.)
290-
storage._seed = (
291-
Hasher._seed.0 ^ UInt64(truncatingIfNeeded: scale),
292-
Hasher._seed.1)
290+
storage._seed = scale
291+
293292
// Initialize hash table metadata.
294293
storage._hashTable.clear()
295294
return storage

stdlib/public/core/FloatingPointTypes.swift.gyb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,7 +1519,7 @@ extension ${Self} : Hashable {
15191519
}
15201520

15211521
@inlinable
1522-
public func _rawHashValue(seed: (UInt64, UInt64)) -> Int {
1522+
public func _rawHashValue(seed: Int) -> Int {
15231523
// To satisfy the axiom that equality implies hash equality, we need to
15241524
// finesse the hash value of -0.0 to match +0.0.
15251525
let v = isZero ? 0 : self
@@ -1839,7 +1839,7 @@ internal struct _${Self}AnyHashableBox: _AnyHashableBox {
18391839
}
18401840

18411841
internal var _hashValue: Int {
1842-
return _rawHashValue(_seed: Hasher._seed)
1842+
return _rawHashValue(_seed: 0)
18431843
}
18441844

18451845
internal func _hash(into hasher: inout Hasher) {
@@ -1848,7 +1848,7 @@ internal struct _${Self}AnyHashableBox: _AnyHashableBox {
18481848
hasher.combine(_value)
18491849
}
18501850

1851-
internal func _rawHashValue(_seed: (UInt64, UInt64)) -> Int {
1851+
internal func _rawHashValue(_seed: Int) -> Int {
18521852
var hasher = Hasher(_seed: _seed)
18531853
_hash(into: &hasher)
18541854
return hasher.finalize()

stdlib/public/core/Hashable.swift

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,13 @@ public protocol Hashable : Equatable {
126126
// Raw top-level hashing interface. Some standard library types (mostly
127127
// primitives) specialize this to eliminate small resiliency overheads. (This
128128
// only matters for tiny keys.)
129-
//
130-
// FIXME(hasher): Change to take a Hasher instead. To achieve the same
131-
// performance, this requires Set and Dictionary to store their fully
132-
// initialized local hashers, not just their seeds.
133-
func _rawHashValue(seed: (UInt64, UInt64)) -> Int
129+
func _rawHashValue(seed: Int) -> Int
134130
}
135131

136132
extension Hashable {
137133
@inlinable
138134
@inline(__always)
139-
public func _rawHashValue(seed: (UInt64, UInt64)) -> Int {
135+
public func _rawHashValue(seed: Int) -> Int {
140136
var hasher = Hasher(_seed: seed)
141137
hasher.combine(self)
142138
return hasher._finalize()
@@ -147,7 +143,7 @@ extension Hashable {
147143
@inlinable
148144
@inline(__always)
149145
public func _hashValue<H: Hashable>(for value: H) -> Int {
150-
return value._rawHashValue(seed: Hasher._seed)
146+
return value._rawHashValue(seed: 0)
151147
}
152148

153149
// Called by the SwiftValue implementation.

stdlib/public/core/Hasher.swift

Lines changed: 49 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,27 @@ import SwiftShims
2020
// rdar://problem/38549901
2121
@usableFromInline
2222
internal protocol _HasherCore {
23-
init(seed: Hasher._Seed)
23+
init(rawSeed: (UInt64, UInt64))
2424
mutating func compress(_ value: UInt64)
2525
mutating func finalize(tailAndByteCount: UInt64) -> UInt64
26+
}
2627

27-
// FIXME(hasher): Remove once one-shot hashing has a hasher parameter.
28-
/// Generate a seed value from the current state of this hasher.
29-
///
30-
/// Note that the returned value is not same as the seed that was used to
31-
/// initialize the hasher.
32-
///
33-
/// This comes handy when type's _hash(into:) implementation needs to perform
34-
/// one-shot hashing for some of its components. (E.g., for commutative
35-
/// hashing.)
36-
func _generateSeed() -> Hasher._Seed
28+
extension _HasherCore {
29+
@inline(__always)
30+
internal init() {
31+
self.init(rawSeed: Hasher._executionSeed)
32+
}
33+
34+
@inline(__always)
35+
internal init(seed: Int) {
36+
let executionSeed = Hasher._executionSeed
37+
// Prevent sign-extending the supplied seed; this makes testing slightly
38+
// easier.
39+
let seed = UInt(bitPattern: seed)
40+
self.init(rawSeed: (
41+
executionSeed.0 ^ UInt64(truncatingIfNeeded: seed),
42+
executionSeed.1))
43+
}
3744
}
3845

3946
@inline(__always)
@@ -155,14 +162,24 @@ internal struct _HasherTailBuffer {
155162
// FIXME: Remove @usableFromInline and @_fixed_layout once Hasher is resilient.
156163
// rdar://problem/38549901
157164
@usableFromInline @_fixed_layout
158-
internal struct _BufferingHasher<Core: _HasherCore> {
165+
internal struct _BufferingHasher<RawCore: _HasherCore> {
159166
private var _buffer: _HasherTailBuffer
160-
private var _core: Core
167+
private var _core: RawCore
161168

162169
@inline(__always)
163-
internal init(seed: Hasher._Seed) {
170+
internal init(core: RawCore) {
164171
self._buffer = _HasherTailBuffer()
165-
self._core = Core(seed: seed)
172+
self._core = core
173+
}
174+
175+
@inline(__always)
176+
internal init() {
177+
self.init(core: RawCore())
178+
}
179+
180+
@inline(__always)
181+
internal init(seed: Int) {
182+
self.init(core: RawCore(seed: seed))
166183
}
167184

168185
@inline(__always)
@@ -249,13 +266,6 @@ internal struct _BufferingHasher<Core: _HasherCore> {
249266
}
250267
}
251268

252-
// Generate a seed value from the current state of this hasher.
253-
// FIXME(hasher): Remove
254-
@inline(__always)
255-
internal func _generateSeed() -> Hasher._Seed {
256-
return _core._generateSeed()
257-
}
258-
259269
@inline(__always)
260270
internal mutating func finalize() -> UInt64 {
261271
return _core.finalize(tailAndByteCount: _buffer.value)
@@ -296,9 +306,6 @@ public struct Hasher {
296306
@usableFromInline
297307
internal typealias Core = _BufferingHasher<RawCore>
298308

299-
@usableFromInline
300-
internal typealias _Seed = (UInt64, UInt64)
301-
302309
internal var _core: Core
303310

304311
/// Creates a new hasher.
@@ -307,14 +314,22 @@ public struct Hasher {
307314
/// startup, usually from a high-quality random source.
308315
@_effects(releasenone)
309316
public init() {
310-
self._core = Core(seed: Hasher._seed)
317+
self._core = Core()
311318
}
312319

313320
/// Initialize a new hasher using the specified seed value.
321+
/// The provided seed is mixed in with the global execution seed.
314322
@usableFromInline
315323
@_effects(releasenone)
316-
internal init(_seed seed: _Seed) {
317-
self._core = Core(seed: seed)
324+
internal init(_seed: Int) {
325+
self._core = Core(seed: _seed)
326+
}
327+
328+
/// Initialize a new hasher using the specified seed value.
329+
@usableFromInline // @testable
330+
@_effects(releasenone)
331+
internal init(_rawSeed: (UInt64, UInt64)) {
332+
self._core = Core(core: RawCore(rawSeed: _rawSeed))
318333
}
319334

320335
/// Indicates whether we're running in an environment where hashing needs to
@@ -333,8 +348,8 @@ public struct Hasher {
333348

334349
/// The 128-bit hash seed used to initialize the hasher state. Initialized
335350
/// once during process startup.
336-
@inlinable
337-
internal static var _seed: _Seed {
351+
@inlinable // @testable
352+
internal static var _executionSeed: (UInt64, UInt64) {
338353
@inline(__always)
339354
get {
340355
// The seed itself is defined in C++ code so that it is initialized during
@@ -427,17 +442,9 @@ public struct Hasher {
427442
return Int(truncatingIfNeeded: core.finalize())
428443
}
429444

430-
// Generate a seed value from the current state of this hasher.
431-
// FIXME(hasher): Remove
432-
@_effects(readnone)
433-
@usableFromInline
434-
internal func _generateSeed() -> Hasher._Seed {
435-
return _core._generateSeed()
436-
}
437-
438445
@_effects(readnone)
439446
@usableFromInline
440-
internal static func _hash(seed: _Seed, _ value: UInt64) -> Int {
447+
internal static func _hash(seed: Int, _ value: UInt64) -> Int {
441448
var core = RawCore(seed: seed)
442449
core.compress(value)
443450
let tbc = _HasherTailBuffer(tail: 0, byteCount: 8)
@@ -446,7 +453,7 @@ public struct Hasher {
446453

447454
@_effects(readnone)
448455
@usableFromInline
449-
internal static func _hash(seed: _Seed, _ value: UInt) -> Int {
456+
internal static func _hash(seed: Int, _ value: UInt) -> Int {
450457
var core = RawCore(seed: seed)
451458
#if arch(i386) || arch(arm)
452459
_sanityCheck(UInt.bitWidth < UInt64.bitWidth)
@@ -464,7 +471,7 @@ public struct Hasher {
464471
@_effects(readnone)
465472
@usableFromInline
466473
internal static func _hash(
467-
seed: _Seed,
474+
seed: Int,
468475
bytes value: UInt64,
469476
count: Int) -> Int {
470477
_sanityCheck(count >= 0 && count < 8)
@@ -476,7 +483,7 @@ public struct Hasher {
476483
@_effects(readnone)
477484
@usableFromInline
478485
internal static func _hash(
479-
seed: _Seed,
486+
seed: Int,
480487
bytes: UnsafeRawBufferPointer) -> Int {
481488
var core = Core(seed: seed)
482489
core.combine(bytes: bytes)

stdlib/public/core/IntegerTypes.swift.gyb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,7 +1673,7 @@ extension ${Self} : Hashable {
16731673
}
16741674

16751675
@inlinable
1676-
public func _rawHashValue(seed: (UInt64, UInt64)) -> Int {
1676+
public func _rawHashValue(seed: Int) -> Int {
16771677
% if bits == 64:
16781678
return Hasher._hash(seed: seed, UInt64(_value))
16791679
% elif bits == word_bits:
@@ -1905,7 +1905,7 @@ internal struct _IntegerAnyHashableBox<
19051905
_value.hash(into: &hasher)
19061906
}
19071907

1908-
internal func _rawHashValue(_seed: (UInt64, UInt64)) -> Int {
1908+
internal func _rawHashValue(_seed: Int) -> Int {
19091909
_sanityCheck(Base.self == UInt64.self || Base.self == Int64.self,
19101910
"self isn't canonical")
19111911
return _value._rawHashValue(seed: _seed)

stdlib/public/core/NewtypeWrapper.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ extension _SwiftNewtypeWrapper where Self: Hashable, Self.RawValue: Hashable {
3434
}
3535

3636
@inlinable // FIXME(sil-serialize-all)
37-
public func _rawHashValue(seed: (UInt64, UInt64)) -> Int {
37+
public func _rawHashValue(seed: Int) -> Int {
3838
return rawValue._rawHashValue(seed: seed)
3939
}
4040
}
@@ -75,7 +75,7 @@ where Base: _SwiftNewtypeWrapper & Hashable, Base.RawValue: Hashable {
7575
_preconditionFailure("_hash(into:) called on non-canonical AnyHashable box")
7676
}
7777

78-
func _rawHashValue(_seed: (UInt64, UInt64)) -> Int {
78+
func _rawHashValue(_seed: Int) -> Int {
7979
_preconditionFailure("_rawHashValue(_seed:) called on non-canonical AnyHashable box")
8080
}
8181

stdlib/public/core/Pointer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ extension _Pointer /*: Hashable */ {
236236
}
237237

238238
@inlinable
239-
public func _rawHashValue(seed: (UInt64, UInt64)) -> Int {
239+
public func _rawHashValue(seed: Int) -> Int {
240240
return Hasher._hash(seed: seed, UInt(bitPattern: self))
241241
}
242242
}

0 commit comments

Comments
 (0)