Skip to content

Commit abd5f7f

Browse files
committed
[test] MinimalHashable types: Replace hashValue hook with hash(into:)
1 parent dd7367d commit abd5f7f

File tree

6 files changed

+57
-45
lines changed

6 files changed

+57
-45
lines changed

stdlib/private/StdlibUnittest/MinimalTypes.swift.gyb

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,12 @@ public func < (
112112
/// other conformances.
113113
public ${decl_keyword} ${Self} : Equatable, Hashable {
114114
public static var timesEqualEqualWasCalled: Int = 0
115-
public static var timesHashValueWasCalled: Int = 0
115+
public static var timesHashIntoWasCalled: Int = 0
116116

117117
public static var equalImpl =
118118
ResettableValue<(Int, Int) -> Bool>({ $0 == $1 })
119-
public static var hashValueImpl =
120-
ResettableValue<(Int) -> Int>({ $0.hashValue })
119+
public static var hashIntoImpl =
120+
ResettableValue<(Int, inout _Hasher) -> Void>({ $1.combine($0) })
121121

122122
public var value: Int
123123
public var identity: Int
@@ -133,8 +133,14 @@ public ${decl_keyword} ${Self} : Equatable, Hashable {
133133
}
134134

135135
public var hashValue: Int {
136-
${Self}.timesHashValueWasCalled += 1
137-
return ${Self}.hashValueImpl.value(value)
136+
var hasher = _Hasher()
137+
_hash(into: &hasher)
138+
return hasher.finalize()
139+
}
140+
141+
public func _hash(into hasher: inout _Hasher) {
142+
${Self}.timesHashIntoWasCalled += 1
143+
${Self}.hashIntoImpl.value(value, &hasher)
138144
}
139145
}
140146

@@ -152,12 +158,13 @@ public func == (
152158
% Self = 'GenericMinimalHashable%s' % kind
153159

154160
public var ${Self}_timesEqualEqualWasCalled: Int = 0
161+
public var ${Self}_timesHashIntoWasCalled: Int = 0
155162
public var ${Self}_timesHashValueWasCalled: Int = 0
156163

157164
public var ${Self}_equalImpl = ResettableValue<(Any, Any) -> Bool>(
158165
{ _, _ in fatalError("${Self}_equalImpl is not set yet"); () })
159-
public var ${Self}_hashValueImpl = ResettableValue<(Any) -> Int>(
160-
{ _ in fatalError("${Self}_hashValueImpl is not set yet"); () })
166+
public var ${Self}_hashIntoImpl = ResettableValue<(Any, inout _Hasher) -> Void>(
167+
{ _ in fatalError("${Self}_hashIntoImpl is not set yet"); () })
161168

162169
/// A type that conforms only to `Equatable` and `Hashable`.
163170
///
@@ -179,7 +186,12 @@ public ${decl_keyword} ${Self}<Wrapped> : Equatable, Hashable {
179186

180187
public var hashValue: Int {
181188
${Self}_timesHashValueWasCalled += 1
182-
return ${Self}_hashValueImpl.value(value)
189+
return _unsafeHashValue()
190+
}
191+
192+
public func _hash(into hasher: inout _Hasher) {
193+
${Self}_timesHashIntoWasCalled += 1
194+
return ${Self}_hashIntoImpl.value(value, &hasher)
183195
}
184196
}
185197

validation-test/stdlib/AnyHashable.swift.gyb

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ import Foundation
5858
let AnyHashableTests = TestSuite("AnyHashableTests")
5959

6060
AnyHashableTests.test("CustomStringConvertible, CustomDebugStringConvertible, CustomReflectable") {
61-
var v = AnyHashable(CustomPrintableValue(1))
61+
let v = AnyHashable(CustomPrintableValue(1))
6262
expectPrinted("(value: 1).description", v)
6363
expectDebugPrinted("AnyHashable((value: 1).debugDescription)", v)
6464
expectDumped(
@@ -117,8 +117,8 @@ AnyHashableTests.test("AnyHashable(${wrapped}<OpaqueValue<Int>>)/Hashable") {
117117
${wrapped}_equalImpl.value = {
118118
($0 as! ${payload}).value == ($1 as! ${payload}).value
119119
}
120-
${wrapped}_hashValueImpl.value = {
121-
($0 as! ${payload}).value
120+
${wrapped}_hashIntoImpl.value = {
121+
$1.combine(($0 as! ${payload}).value)
122122
}
123123
let xs = (0...5).flatMap {
124124
[ ${wrapped}(${payload}($0), identity: 0),
@@ -142,7 +142,7 @@ AnyHashableTests.test("AnyHashable(mixed minimal hashables)/Hashable") {
142142
var xs: [AnyHashable] = []
143143

144144
% for wrapped in ['MinimalHashableValue', 'MinimalHashableClass']:
145-
xs += (0...5).flatMap {
145+
xs += (0..<6).flatMap {
146146
[ ${wrapped}($0, identity: 0),
147147
${wrapped}($0, identity: 1) ].map(AnyHashable.init)
148148
}
@@ -157,18 +157,18 @@ AnyHashableTests.test("AnyHashable(mixed minimal hashables)/Hashable") {
157157
}
158158
return (lhs as! LifetimeTracked) == (rhs as! LifetimeTracked)
159159
}
160-
${wrapped}_hashValueImpl.value = {
161-
payload in
160+
${wrapped}_hashIntoImpl.value = { payload, hasher in
162161
if let x = payload as? OpaqueValue<Int> {
163-
return x.value
162+
hasher.combine(x.value)
163+
return
164164
}
165-
return (payload as! LifetimeTracked).value
165+
hasher.combine((payload as! LifetimeTracked).value)
166166
}
167167
% end
168168

169169
% for wrapped in ['GenericMinimalHashableValue', 'GenericMinimalHashableClass']:
170170
% for payload in [ 'OpaqueValue<Int>', 'LifetimeTracked' ]:
171-
xs += (0...5).flatMap {
171+
xs += (0..<6).flatMap {
172172
[ ${wrapped}(${payload}($0), identity: 0),
173173
${wrapped}(${payload}($0), identity: 1) ].map(AnyHashable.init)
174174
}
@@ -311,8 +311,8 @@ AnyHashableTests.test("AnyHashable(${genericWrapped}<${payload}>)/Hashable") {
311311
GenericMinimalHashableValue_equalImpl.value = {
312312
($0 as! ${payload}).value == ($1 as! ${payload}).value
313313
}
314-
GenericMinimalHashableValue_hashValueImpl.value = {
315-
($0 as! ${payload}).value
314+
GenericMinimalHashableValue_hashIntoImpl.value = { v, hasher in
315+
hasher.combine((v as! ${payload}).value)
316316
}
317317
let xs = (-2...2).flatMap {
318318
[ ${genericWrapped}(
@@ -379,8 +379,8 @@ AnyHashableTests.test("AnyHashable containing values with recursive custom repre
379379
GenericMinimalHashableValue_equalImpl.value = {
380380
($0 as! ${payload}).value == ($1 as! ${payload}).value
381381
}
382-
GenericMinimalHashableValue_hashValueImpl.value = {
383-
($0 as! ${payload}).value
382+
GenericMinimalHashableValue_hashIntoImpl.value = { v, hasher in
383+
hasher.combine((v as! ${payload}).value)
384384
}
385385
// If the custom representation has its own custom representation,
386386
// we ignore it.

validation-test/stdlib/CollectionType.swift.gyb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ CollectionTypeTests.test("Set<T>.find/CustomImplementation/${dispatch}") {
659659
let s = Set<MinimalHashableValue>(
660660
test.sequence.map { MinimalHashableValue($0.value) })
661661
MinimalHashableValue.timesEqualEqualWasCalled = 0
662-
MinimalHashableValue.timesHashValueWasCalled = 0
662+
MinimalHashableValue.timesHashIntoWasCalled = 0
663663
expectEqual(
664664
test.expected
665665
.map { _ in MinimalHashableValue(test.element.value) },
@@ -671,11 +671,11 @@ CollectionTypeTests.test("Set<T>.find/CustomImplementation/${dispatch}") {
671671
0, MinimalHashableValue.timesEqualEqualWasCalled,
672672
stackTrace: SourceLocStack().with(test.loc))
673673
expectEqual(
674-
0, MinimalHashableValue.timesHashValueWasCalled,
674+
0, MinimalHashableValue.timesHashIntoWasCalled,
675675
stackTrace: SourceLocStack().with(test.loc))
676676
} else {
677677
expectNotEqual(
678-
0, MinimalHashableValue.timesHashValueWasCalled,
678+
0, MinimalHashableValue.timesHashIntoWasCalled,
679679
stackTrace: SourceLocStack().with(test.loc))
680680
}
681681
if test.expected != nil {

validation-test/stdlib/Dictionary.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,13 @@ DictionaryTestSuite.test("COW.Fast.SubscriptWithKeyDoesNotReallocate")
274274
do {
275275
var d2: [MinimalHashableValue : OpaqueValue<Int>] = [:]
276276
MinimalHashableValue.timesEqualEqualWasCalled = 0
277-
MinimalHashableValue.timesHashValueWasCalled = 0
277+
MinimalHashableValue.timesHashIntoWasCalled = 0
278278
expectNil(d2[MinimalHashableValue(42)])
279279

280280
// If the dictionary is empty, we shouldn't be computing the hash value of
281281
// the provided key.
282282
expectEqual(0, MinimalHashableValue.timesEqualEqualWasCalled)
283-
expectEqual(0, MinimalHashableValue.timesHashValueWasCalled)
283+
expectEqual(0, MinimalHashableValue.timesHashIntoWasCalled)
284284
}
285285
}
286286

@@ -330,14 +330,14 @@ DictionaryTestSuite.test("COW.Slow.SubscriptWithKeyDoesNotReallocate")
330330
do {
331331
var d2: [MinimalHashableClass : OpaqueValue<Int>] = [:]
332332
MinimalHashableClass.timesEqualEqualWasCalled = 0
333-
MinimalHashableClass.timesHashValueWasCalled = 0
333+
MinimalHashableClass.timesHashIntoWasCalled = 0
334334

335335
expectNil(d2[MinimalHashableClass(42)])
336336

337337
// If the dictionary is empty, we shouldn't be computing the hash value of
338338
// the provided key.
339339
expectEqual(0, MinimalHashableClass.timesEqualEqualWasCalled)
340-
expectEqual(0, MinimalHashableClass.timesHashValueWasCalled)
340+
expectEqual(0, MinimalHashableClass.timesHashIntoWasCalled)
341341
}
342342
}
343343

@@ -864,13 +864,13 @@ DictionaryTestSuite.test("COW.Fast.IndexForKeyDoesNotReallocate") {
864864
do {
865865
var d2: [MinimalHashableValue : OpaqueValue<Int>] = [:]
866866
MinimalHashableValue.timesEqualEqualWasCalled = 0
867-
MinimalHashableValue.timesHashValueWasCalled = 0
867+
MinimalHashableValue.timesHashIntoWasCalled = 0
868868
expectNil(d2.index(forKey: MinimalHashableValue(42)))
869869

870870
// If the dictionary is empty, we shouldn't be computing the hash value of
871871
// the provided key.
872872
expectEqual(0, MinimalHashableValue.timesEqualEqualWasCalled)
873-
expectEqual(0, MinimalHashableValue.timesHashValueWasCalled)
873+
expectEqual(0, MinimalHashableValue.timesHashIntoWasCalled)
874874
}
875875
}
876876

@@ -901,13 +901,13 @@ DictionaryTestSuite.test("COW.Slow.IndexForKeyDoesNotReallocate") {
901901
do {
902902
var d2: [MinimalHashableClass : OpaqueValue<Int>] = [:]
903903
MinimalHashableClass.timesEqualEqualWasCalled = 0
904-
MinimalHashableClass.timesHashValueWasCalled = 0
904+
MinimalHashableClass.timesHashIntoWasCalled = 0
905905
expectNil(d2.index(forKey: MinimalHashableClass(42)))
906906

907907
// If the dictionary is empty, we shouldn't be computing the hash value of
908908
// the provided key.
909909
expectEqual(0, MinimalHashableClass.timesEqualEqualWasCalled)
910-
expectEqual(0, MinimalHashableClass.timesHashValueWasCalled)
910+
expectEqual(0, MinimalHashableClass.timesHashIntoWasCalled)
911911
}
912912
}
913913

@@ -1713,13 +1713,13 @@ DictionaryTestSuite.test("mapValues(_:)") {
17131713
uniqueKeysWithValues: d1.lazy.map { (MinimalHashableValue($0), $1) })
17141714
expectEqual(d3.count, 3)
17151715
MinimalHashableValue.timesEqualEqualWasCalled = 0
1716-
MinimalHashableValue.timesHashValueWasCalled = 0
1716+
MinimalHashableValue.timesHashIntoWasCalled = 0
17171717

17181718
// Calling mapValues shouldn't ever recalculate any hashes.
17191719
let d4 = d3.mapValues(String.init)
17201720
expectEqual(d4.count, d3.count)
17211721
expectEqual(0, MinimalHashableValue.timesEqualEqualWasCalled)
1722-
expectEqual(0, MinimalHashableValue.timesHashValueWasCalled)
1722+
expectEqual(0, MinimalHashableValue.timesHashIntoWasCalled)
17231723
}
17241724
}
17251725

validation-test/stdlib/SequenceType.swift.gyb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ SequenceTypeTests.test("Set<T>.contains/CustomImplementation/${dispatch}") {
573573
let s = Set<MinimalHashableValue>(
574574
test.sequence.map { MinimalHashableValue($0.value) })
575575
MinimalHashableValue.timesEqualEqualWasCalled = 0
576-
MinimalHashableValue.timesHashValueWasCalled = 0
576+
MinimalHashableValue.timesHashIntoWasCalled = 0
577577
expectEqual(
578578
test.expected != nil,
579579
call${dispatch}Contains(s, MinimalHashableValue(test.element.value)),
@@ -583,11 +583,11 @@ SequenceTypeTests.test("Set<T>.contains/CustomImplementation/${dispatch}") {
583583
0, MinimalHashableValue.timesEqualEqualWasCalled,
584584
stackTrace: SourceLocStack().with(test.loc))
585585
expectEqual(
586-
0, MinimalHashableValue.timesHashValueWasCalled,
586+
0, MinimalHashableValue.timesHashIntoWasCalled,
587587
stackTrace: SourceLocStack().with(test.loc))
588588
} else {
589589
expectNotEqual(
590-
0, MinimalHashableValue.timesHashValueWasCalled,
590+
0, MinimalHashableValue.timesHashIntoWasCalled,
591591
stackTrace: SourceLocStack().with(test.loc))
592592
}
593593
if test.expected != nil {

validation-test/stdlib/Set.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -442,13 +442,13 @@ SetTestSuite.test("COW.Fast.ContainsDoesNotReallocate") {
442442
do {
443443
var s2: Set<MinimalHashableValue> = []
444444
MinimalHashableValue.timesEqualEqualWasCalled = 0
445-
MinimalHashableValue.timesHashValueWasCalled = 0
445+
MinimalHashableValue.timesHashIntoWasCalled = 0
446446
expectFalse(s2.contains(MinimalHashableValue(42)))
447447

448448
// If the set is empty, we shouldn't be computing the hash value of the
449449
// provided key.
450450
expectEqual(0, MinimalHashableValue.timesEqualEqualWasCalled)
451-
expectEqual(0, MinimalHashableValue.timesHashValueWasCalled)
451+
expectEqual(0, MinimalHashableValue.timesHashIntoWasCalled)
452452
}
453453
}
454454

@@ -488,13 +488,13 @@ SetTestSuite.test("COW.Slow.ContainsDoesNotReallocate")
488488
do {
489489
var s2: Set<MinimalHashableClass> = []
490490
MinimalHashableClass.timesEqualEqualWasCalled = 0
491-
MinimalHashableClass.timesHashValueWasCalled = 0
491+
MinimalHashableClass.timesHashIntoWasCalled = 0
492492
expectFalse(s2.contains(MinimalHashableClass(42)))
493493

494494
// If the set is empty, we shouldn't be computing the hash value of the
495495
// provided key.
496496
expectEqual(0, MinimalHashableClass.timesEqualEqualWasCalled)
497-
expectEqual(0, MinimalHashableClass.timesHashValueWasCalled)
497+
expectEqual(0, MinimalHashableClass.timesHashIntoWasCalled)
498498
}
499499
}
500500

@@ -619,13 +619,13 @@ SetTestSuite.test("COW.Fast.IndexForMemberDoesNotReallocate") {
619619
do {
620620
var s2: Set<MinimalHashableValue> = []
621621
MinimalHashableValue.timesEqualEqualWasCalled = 0
622-
MinimalHashableValue.timesHashValueWasCalled = 0
622+
MinimalHashableValue.timesHashIntoWasCalled = 0
623623
expectNil(s2.index(of: MinimalHashableValue(42)))
624624

625625
// If the set is empty, we shouldn't be computing the hash value of the
626626
// provided key.
627627
expectEqual(0, MinimalHashableValue.timesEqualEqualWasCalled)
628-
expectEqual(0, MinimalHashableValue.timesHashValueWasCalled)
628+
expectEqual(0, MinimalHashableValue.timesHashIntoWasCalled)
629629
}
630630
}
631631

@@ -655,13 +655,13 @@ SetTestSuite.test("COW.Slow.IndexForMemberDoesNotReallocate") {
655655
do {
656656
var s2: Set<MinimalHashableClass> = []
657657
MinimalHashableClass.timesEqualEqualWasCalled = 0
658-
MinimalHashableClass.timesHashValueWasCalled = 0
658+
MinimalHashableClass.timesHashIntoWasCalled = 0
659659
expectNil(s2.index(of: MinimalHashableClass(42)))
660660

661661
// If the set is empty, we shouldn't be computing the hash value of the
662662
// provided key.
663663
expectEqual(0, MinimalHashableClass.timesEqualEqualWasCalled)
664-
expectEqual(0, MinimalHashableClass.timesHashValueWasCalled)
664+
expectEqual(0, MinimalHashableClass.timesHashIntoWasCalled)
665665
}
666666
}
667667

0 commit comments

Comments
 (0)