|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
13 | 13 | //
|
14 |
| -// This file implements helpers for constructing non-cryptographic hash |
15 |
| -// functions. |
| 14 | +// This file implements helpers for hashing collections. |
16 | 15 | //
|
17 |
| -// This code was ported from LLVM's ADT/Hashing.h. |
18 |
| -// |
19 |
| -// Currently the algorithm is based on CityHash, but this is an implementation |
20 |
| -// detail. Even more, there are facilities to mix in a per-execution seed to |
21 |
| -// ensure that hash values differ between executions. |
22 |
| -// |
23 |
| - |
24 |
| -@_frozen // FIXME(sil-serialize-all) |
25 |
| -public // @testable |
26 |
| -enum _HashingDetail { |
27 |
| - |
28 |
| - // FIXME(hasher): Remove |
29 |
| - @inlinable // FIXME(sil-serialize-all) |
30 |
| - @_transparent |
31 |
| - internal static func getExecutionSeed() -> UInt64 { |
32 |
| - // FIXME: This needs to be a per-execution seed. This is just a placeholder |
33 |
| - // implementation. |
34 |
| - return 0xff51afd7ed558ccd |
35 |
| - } |
36 |
| - |
37 |
| - // FIXME(hasher): Remove |
38 |
| - @inlinable // FIXME(sil-serialize-all) |
39 |
| - @_transparent |
40 |
| - internal static func hash16Bytes(_ low: UInt64, _ high: UInt64) -> UInt64 { |
41 |
| - // Murmur-inspired hashing. |
42 |
| - let mul: UInt64 = 0x9ddfea08eb382d69 |
43 |
| - var a: UInt64 = (low ^ high) &* mul |
44 |
| - a ^= (a >> 47) |
45 |
| - var b: UInt64 = (high ^ a) &* mul |
46 |
| - b ^= (b >> 47) |
47 |
| - b = b &* mul |
48 |
| - return b |
49 |
| - } |
50 |
| -} |
51 |
| - |
52 |
| -// |
53 |
| -// API functions. |
54 |
| -// |
55 |
| - |
56 |
| -// |
57 |
| -// _mix*() functions all have type (T) -> T. These functions don't compress |
58 |
| -// their inputs and just exhibit avalanche effect. |
59 |
| -// |
60 |
| - |
61 |
| -// FIXME(hasher): Remove |
62 |
| -@inlinable // FIXME(sil-serialize-all) |
63 |
| -@_transparent |
64 |
| -public // @testable |
65 |
| -func _mixUInt32(_ value: UInt32) -> UInt32 { |
66 |
| - // Zero-extend to 64 bits, hash, select 32 bits from the hash. |
67 |
| - // |
68 |
| - // NOTE: this differs from LLVM's implementation, which selects the lower |
69 |
| - // 32 bits. According to the statistical tests, the 3 lowest bits have |
70 |
| - // weaker avalanche properties. |
71 |
| - let extendedValue = UInt64(value) |
72 |
| - let extendedResult = _mixUInt64(extendedValue) |
73 |
| - return UInt32((extendedResult >> 3) & 0xffff_ffff) |
74 |
| -} |
75 |
| - |
76 |
| -// FIXME(hasher): Remove |
77 |
| -@inlinable // FIXME(sil-serialize-all) |
78 |
| -@_transparent |
79 |
| -public // @testable |
80 |
| -func _mixInt32(_ value: Int32) -> Int32 { |
81 |
| - return Int32(bitPattern: _mixUInt32(UInt32(bitPattern: value))) |
82 |
| -} |
83 |
| - |
84 |
| -// FIXME(hasher): Remove |
85 |
| -@inlinable // FIXME(sil-serialize-all) |
86 |
| -@_transparent |
87 |
| -public // @testable |
88 |
| -func _mixUInt64(_ value: UInt64) -> UInt64 { |
89 |
| - // Similar to hash_4to8_bytes but using a seed instead of length. |
90 |
| - let seed: UInt64 = _HashingDetail.getExecutionSeed() |
91 |
| - let low: UInt64 = value & 0xffff_ffff |
92 |
| - let high: UInt64 = value >> 32 |
93 |
| - return _HashingDetail.hash16Bytes(seed &+ (low << 3), high) |
94 |
| -} |
95 |
| - |
96 |
| -// FIXME(hasher): Remove |
97 |
| -@inlinable // FIXME(sil-serialize-all) |
98 |
| -@_transparent |
99 |
| -public // @testable |
100 |
| -func _mixInt64(_ value: Int64) -> Int64 { |
101 |
| - return Int64(bitPattern: _mixUInt64(UInt64(bitPattern: value))) |
102 |
| -} |
103 |
| - |
104 |
| -// FIXME(hasher): Remove |
105 |
| -@inlinable // FIXME(sil-serialize-all) |
106 |
| -@_transparent |
107 |
| -public // @testable |
108 |
| -func _mixUInt(_ value: UInt) -> UInt { |
109 |
| -#if arch(i386) || arch(arm) |
110 |
| - return UInt(_mixUInt32(UInt32(value))) |
111 |
| -#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x) |
112 |
| - return UInt(_mixUInt64(UInt64(value))) |
113 |
| -#endif |
114 |
| -} |
115 |
| - |
116 |
| -// FIXME(hasher): Remove |
117 |
| -@inlinable // FIXME(sil-serialize-all) |
118 |
| -@_transparent |
119 |
| -public // @testable |
120 |
| -func _mixInt(_ value: Int) -> Int { |
121 |
| -#if arch(i386) || arch(arm) |
122 |
| - return Int(_mixInt32(Int32(value))) |
123 |
| -#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x) |
124 |
| - return Int(_mixInt64(Int64(value))) |
125 |
| -#endif |
126 |
| -} |
127 |
| - |
128 |
| -/// Returns a new value that combines the two given hash values. |
129 |
| -/// |
130 |
| -/// Combining is performed using [a hash function][ref] described by T.C. Hoad |
131 |
| -/// and J. Zobel, which is also adopted in the Boost C++ libraries. |
132 |
| -/// |
133 |
| -/// This function is used by synthesized implementations of `hashValue` to |
134 |
| -/// combine the hash values of individual `struct` fields and associated values |
135 |
| -/// of `enum`s. It is factored out into a standard library function so that the |
136 |
| -/// specific hashing logic can be refined without requiring major changes to the |
137 |
| -/// code that creates the synthesized AST nodes. |
138 |
| -/// |
139 |
| -/// [ref]: https://pdfs.semanticscholar.org/03bf/7be88e88ba047c6ab28036d0f28510299226.pdf |
140 |
| -@_transparent |
141 |
| -public // @testable |
142 |
| -func _combineHashValues(_ firstValue: Int, _ secondValue: Int) -> Int { |
143 |
| - // Use a magic number based on the golden ratio |
144 |
| - // (0x1.9e3779b97f4a7c15f39cc0605cedc8341082276bf3a27251f86c6a11d0c18e95p0). |
145 |
| -#if arch(i386) || arch(arm) |
146 |
| - let magic = 0x9e3779b9 as UInt |
147 |
| -#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x) |
148 |
| - let magic = 0x9e3779b97f4a7c15 as UInt |
149 |
| -#endif |
150 |
| - var x = UInt(bitPattern: firstValue) |
151 |
| - x ^= UInt(bitPattern: secondValue) &+ magic &+ (x &<< 6) &+ (x &>> 2) |
152 |
| - return Int(bitPattern: x) |
153 |
| -} |
154 |
| - |
155 |
| -// FIXME(hasher): This hasher emulates Swift 4.1 hashValues. It is purely for |
156 |
| -// benchmarking; to be removed. |
157 |
| -internal struct _LegacyHasherCore: _HasherCore { |
158 |
| - internal var _hash: Int |
159 |
| - |
160 |
| - @inline(__always) |
161 |
| - internal init(seed: (UInt64, UInt64) = (0, 0)) { // seed is ignored |
162 |
| - _hash = 0 |
163 |
| - } |
164 |
| - |
165 |
| - @inline(__always) |
166 |
| - internal mutating func compress(_ value: UInt64) { |
167 |
| - let value = (UInt64.bitWidth > Int.bitWidth |
168 |
| - ? Int(truncatingIfNeeded: value ^ (value &>> 32)) |
169 |
| - : Int(truncatingIfNeeded: value)) |
170 |
| - _hash = (_hash == 0 ? value : _combineHashValues(_hash, value)) |
171 |
| - } |
172 |
| - |
173 |
| - @inline(__always) |
174 |
| - internal mutating func finalize(tailAndByteCount: UInt64) -> UInt64 { |
175 |
| - let count = (tailAndByteCount &>> 56) & 7 |
176 |
| - if count > 0 { |
177 |
| - compress(tailAndByteCount & ((1 &<< (count &<< 3)) - 1)) |
178 |
| - } |
179 |
| - return UInt64( |
180 |
| - _truncatingBits: UInt(bitPattern: _mixInt(_hash))._lowWord) |
181 |
| - } |
182 |
| - |
183 |
| - @inline(__always) |
184 |
| - func _generateSeed() -> (UInt64, UInt64) { |
185 |
| - return (0, 0) |
186 |
| - } |
187 |
| -} |
188 |
| - |
189 | 16 |
|
190 | 17 | /// This protocol is only used for compile-time checks that
|
191 | 18 | /// every buffer type implements all required operations.
|
|
0 commit comments