19
19
/// * Daniel J. Bernstein <
[email protected] >
20
20
//===----------------------------------------------------------------------===//
21
21
22
+ %{
23
+ # Number of bits in the Builtin.Word type
24
+ word_bits = int(CMAKE_SIZEOF_VOID_P) * 8
25
+ }%
26
+
22
27
@_fixed_layout // FIXME(sil-serialize-all)
23
28
@_versioned
24
29
internal enum _SipHashDetail {
25
- @_inlineable // FIXME(sil-serialize-all)
26
- @_versioned
27
- @inline(__always)
28
- internal static func _rotate(_ x: UInt64, leftBy amount: Int) -> UInt64 {
29
- return (x &<< UInt64(amount)) | (x &>> UInt64(64 - amount))
30
- }
31
-
32
- @_inlineable // FIXME(sil-serialize-all)
33
- @_versioned
34
- @inline(__always)
35
- internal static func _loadUnalignedUInt64LE(
36
- from p: UnsafeRawPointer
37
- ) -> UInt64 {
38
- // FIXME(integers): split into multiple expressions to speed up the
39
- // typechecking
40
- var result =
41
- UInt64(p.load(fromByteOffset: 0, as: UInt8.self))
42
- result |=
43
- (UInt64(p.load(fromByteOffset: 1, as: UInt8.self)) &<< (8 as UInt64))
44
- result |=
45
- (UInt64(p.load(fromByteOffset: 2, as: UInt8.self)) &<< (16 as UInt64))
46
- result |=
47
- (UInt64(p.load(fromByteOffset: 3, as: UInt8.self)) &<< (24 as UInt64))
48
- result |=
49
- (UInt64(p.load(fromByteOffset: 4, as: UInt8.self)) &<< (32 as UInt64))
50
- result |=
51
- (UInt64(p.load(fromByteOffset: 5, as: UInt8.self)) &<< (40 as UInt64))
52
- result |=
53
- (UInt64(p.load(fromByteOffset: 6, as: UInt8.self)) &<< (48 as UInt64))
54
- result |=
55
- (UInt64(p.load(fromByteOffset: 7, as: UInt8.self)) &<< (56 as UInt64))
56
- return result
57
- }
58
-
59
- @_inlineable // FIXME(sil-serialize-all)
60
30
@_versioned
61
31
@inline(__always)
62
- internal static func _loadPartialUnalignedUInt64LE(
63
- from p: UnsafeRawPointer,
64
- byteCount: Int
65
- ) -> UInt64 {
66
- _sanityCheck((0..<8).contains(byteCount))
67
- var result: UInt64 = 0
68
- if byteCount >= 1 { result |= UInt64(p.load(fromByteOffset: 0, as: UInt8.self)) }
69
- if byteCount >= 2 { result |= UInt64(p.load(fromByteOffset: 1, as: UInt8.self)) &<< (8 as UInt64) }
70
- if byteCount >= 3 { result |= UInt64(p.load(fromByteOffset: 2, as: UInt8.self)) &<< (16 as UInt64) }
71
- if byteCount >= 4 { result |= UInt64(p.load(fromByteOffset: 3, as: UInt8.self)) &<< (24 as UInt64) }
72
- if byteCount >= 5 { result |= UInt64(p.load(fromByteOffset: 4, as: UInt8.self)) &<< (32 as UInt64) }
73
- if byteCount >= 6 { result |= UInt64(p.load(fromByteOffset: 5, as: UInt8.self)) &<< (40 as UInt64) }
74
- if byteCount >= 7 { result |= UInt64(p.load(fromByteOffset: 6, as: UInt8.self)) &<< (48 as UInt64) }
75
- return result
32
+ internal static func _rotate(_ x: UInt64, leftBy amount: UInt64) -> UInt64 {
33
+ return (x &<< amount) | (x &>> (64 - amount))
76
34
}
77
35
78
- @_inlineable // FIXME(sil-serialize-all)
79
36
@_versioned
80
37
@inline(__always)
81
38
internal static func _sipRound(
@@ -102,7 +59,7 @@ internal enum _SipHashDetail {
102
59
}
103
60
104
61
% for (c_rounds, d_rounds) in [(2, 4), (1, 3)]:
105
- % Self = '_SipHash{}{}Context '.format(c_rounds, d_rounds)
62
+ % Self = '_SipHash{}{}'.format(c_rounds, d_rounds)
106
63
107
64
@_fixed_layout // FIXME(sil-serialize-all)
108
65
public // @testable
@@ -120,181 +77,125 @@ struct ${Self} {
120
77
@_versioned
121
78
internal var v3: UInt64 = 0x7465646279746573
122
79
80
+ /// This value holds the byte count and the pending bytes that haven't been
81
+ /// compressed yet, in the format that the finalization step needs. (The least
82
+ /// significant 56 bits hold the trailing bytes, while the most significant 8
83
+ /// bits hold the count of bytes appended so far, mod 256.)
123
84
@_versioned
124
- internal var hashedByteCount: UInt64 = 0
125
-
126
- @_versioned
127
- internal var dataTail: UInt64 = 0
128
-
129
- @_versioned
130
- internal var dataTailByteCount: Int = 0
85
+ internal var tailAndByteCount: UInt64 = 0
131
86
132
- @_versioned
133
- internal var finalizedHash: UInt64?
134
-
135
- @_inlineable // FIXME(sil-serialize-all)
87
+ @inline(__always)
136
88
public init(key: (UInt64, UInt64)) {
137
89
v3 ^= key.1
138
90
v2 ^= key.0
139
91
v1 ^= key.1
140
92
v0 ^= key.0
141
93
}
142
94
143
- // FIXME(ABI)#62 (UnsafeRawBufferPointer): Use UnsafeRawBufferPointer.
144
- @_inlineable // FIXME(sil-serialize-all)
145
- public // @testable
146
- mutating func append(_ data: UnsafeRawPointer, byteCount: Int) {
147
- _append_alwaysInline(data, byteCount: byteCount)
148
- }
149
-
150
- // FIXME(ABI)#63 (UnsafeRawBufferPointer): Use UnsafeRawBufferPointer.
151
- @_inlineable // FIXME(sil-serialize-all)
152
95
@_versioned
153
- @inline(__always)
154
- internal mutating func _append_alwaysInline(
155
- _ data: UnsafeRawPointer,
156
- byteCount: Int
157
- ) {
158
- precondition(finalizedHash == nil)
159
- _sanityCheck((0..<8).contains(dataTailByteCount))
160
-
161
- let dataEnd = data + byteCount
162
-
163
- var data = data
164
- var byteCount = byteCount
165
- if dataTailByteCount != 0 {
166
- let restByteCount = min(
167
- MemoryLayout<UInt64>.size - dataTailByteCount,
168
- byteCount)
169
- let rest = _SipHashDetail._loadPartialUnalignedUInt64LE(
170
- from: data,
171
- byteCount: restByteCount)
172
- dataTail |= rest &<< UInt64(dataTailByteCount * 8)
173
- dataTailByteCount += restByteCount
174
- data += restByteCount
175
- byteCount -= restByteCount
176
- }
177
-
178
- if dataTailByteCount == MemoryLayout<UInt64>.size {
179
- _appendDirectly(dataTail)
180
- dataTail = 0
181
- dataTailByteCount = 0
182
- } else if dataTailByteCount != 0 {
183
- _sanityCheck(data == dataEnd)
184
- return
185
- }
186
-
187
- let endOfWords =
188
- data + byteCount - (byteCount % MemoryLayout<UInt64>.size)
189
- while data != endOfWords {
190
- _appendDirectly(_SipHashDetail._loadUnalignedUInt64LE(from: data))
191
- data += 8
192
- // No need to update `byteCount`, it is not used beyond this point.
96
+ internal var byteCount: UInt64 {
97
+ @inline(__always)
98
+ get {
99
+ return tailAndByteCount &>> 56
193
100
}
101
+ }
194
102
195
- if data != dataEnd {
196
- dataTailByteCount = dataEnd - data
197
- dataTail = _SipHashDetail._loadPartialUnalignedUInt64LE(
198
- from: data,
199
- byteCount: dataTailByteCount )
103
+ @_versioned
104
+ internal var tail: UInt64 {
105
+ @inline(__always)
106
+ get {
107
+ return tailAndByteCount & ~(0xFF &<< 56 )
200
108
}
201
109
}
202
110
203
- /// This function mixes in the given word directly into the state,
204
- /// ignoring `dataTail`.
205
- @_inlineable // FIXME(sil-serialize-all)
206
- @_versioned
207
111
@inline(__always)
208
- internal mutating func _appendDirectly(_ m: UInt64) {
112
+ @_versioned
113
+ internal mutating func _compress(_ m: UInt64) {
209
114
v3 ^= m
210
115
for _ in 0..<${c_rounds} {
211
116
_SipHashDetail._sipRound(v0: &v0, v1: &v1, v2: &v2, v3: &v3)
212
117
}
213
118
v0 ^= m
214
- hashedByteCount += 8
215
119
}
216
120
217
- % for data_type in ['UInt', 'Int', 'UInt64', 'Int64', 'UInt32', 'Int32']:
218
- @_inlineable // FIXME(sil-serialize-all)
219
- public // @testable
220
- mutating func append(_ data: ${data_type}) {
221
- var data = data
222
- _append_alwaysInline(&data, byteCount: MemoryLayout.size(ofValue: data))
121
+ @inline(__always)
122
+ public mutating func append(_ value: Int) {
123
+ append(UInt(bitPattern: value))
223
124
}
224
- % end
225
125
226
- @_inlineable // FIXME(sil-serialize-all)
227
- public // @testable
228
- mutating func finalizeAndReturnHash() -> UInt64 {
229
- return _finalizeAndReturnHash_alwaysInline()
126
+ @inline(__always)
127
+ public mutating func append(_ value: UInt) {
128
+ % if word_bits == 64:
129
+ append(UInt64(_truncatingBits: value._lowWord))
130
+ % elif word_bits == 32:
131
+ append(UInt32(_truncatingBits: value._lowWord))
132
+ % else:
133
+ fatalError("Unsupported word width")
134
+ % end
230
135
}
231
136
232
- @_inlineable // FIXME(sil-serialize-all)
233
- @_versioned
234
137
@inline(__always)
235
- internal mutating func _finalizeAndReturnHash_alwaysInline() -> UInt64 {
236
- if let finalizedHash = finalizedHash {
237
- return finalizedHash
238
- }
239
-
240
- _sanityCheck((0..<8).contains(dataTailByteCount))
241
-
242
- hashedByteCount += UInt64(dataTailByteCount)
243
- let b: UInt64 = (hashedByteCount << 56) | dataTail
244
-
245
- v3 ^= b
246
- for _ in 0..<${c_rounds} {
247
- _SipHashDetail._sipRound(v0: &v0, v1: &v1, v2: &v2, v3: &v3)
248
- }
249
- v0 ^= b
250
-
251
- v2 ^= 0xff
138
+ public mutating func append(_ value: Int32) {
139
+ append(UInt32(bitPattern: value))
140
+ }
252
141
253
- for _ in 0..<${d_rounds} {
254
- _SipHashDetail._sipRound(v0: &v0, v1: &v1, v2: &v2, v3: &v3)
142
+ @inline(__always)
143
+ public mutating func append(_ value: UInt32) {
144
+ let m = UInt64(_truncatingBits: value._lowWord)
145
+ if byteCount & 4 == 0 {
146
+ _sanityCheck(byteCount & 7 == 0 && tail == 0)
147
+ tailAndByteCount = (tailAndByteCount | m) &+ (4 &<< 56)
148
+ } else {
149
+ _sanityCheck(byteCount & 3 == 0)
150
+ _compress((m &<< 32) | tail)
151
+ tailAndByteCount = (byteCount &+ 4) &<< 56
255
152
}
153
+ }
256
154
257
- finalizedHash = v0 ^ v1 ^ v2 ^ v3
258
- return finalizedHash!
155
+ @inline(__always)
156
+ public mutating func append(_ value: Int64) {
157
+ append(UInt64(bitPattern: value))
259
158
}
260
159
261
- @_inlineable // FIXME(sil-serialize-all)
262
- @_versioned // FIXME(sil-serialize-all)
263
- internal mutating func _finalizeAndReturnIntHash() -> Int {
264
- let hash: UInt64 = finalizeAndReturnHash()
265
- #if arch(i386) || arch(arm)
266
- return Int(truncatingIfNeeded: hash)
267
- #elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
268
- return Int(Int64(bitPattern: hash))
269
- #endif
160
+ @inline(__always)
161
+ public mutating func append(_ m: UInt64) {
162
+ if byteCount & 4 == 0 {
163
+ _sanityCheck(byteCount & 7 == 0 && tail == 0)
164
+ _compress(m)
165
+ tailAndByteCount = tailAndByteCount &+ (8 &<< 56)
166
+ } else {
167
+ _sanityCheck(byteCount & 3 == 0)
168
+ _compress((m &<< 32) | tail)
169
+ tailAndByteCount = ((byteCount &+ 8) &<< 56) | (m &>> 32)
170
+ }
270
171
}
271
172
272
- // FIXME(ABI)#64 (UnsafeRawBufferPointer): Use UnsafeRawBufferPointer.
273
- @_inlineable // FIXME(sil-serialize-all)
274
- public // @testable
275
- static func hash(
276
- data: UnsafeRawPointer,
277
- dataByteCount: Int,
278
- key: (UInt64, UInt64)
173
+ @inline(__always)
174
+ public mutating func finalize(
175
+ tailBytes: UInt64,
176
+ tailByteCount: Int
279
177
) -> UInt64 {
280
- return ${Self}._hash_alwaysInline(
281
- data: data,
282
- dataByteCount: dataByteCount,
283
- key: key)
178
+ _sanityCheck(tailByteCount >= 0)
179
+ _sanityCheck(tailByteCount < 8 - (byteCount & 7))
180
+ _sanityCheck(tailBytes >> (tailByteCount << 3) == 0)
181
+ let count = UInt64(_truncatingBits: tailByteCount._lowWord)
182
+ let currentByteCount = byteCount & 7
183
+ tailAndByteCount |= (tailBytes &<< (currentByteCount &<< 3))
184
+ tailAndByteCount = tailAndByteCount &+ (count &<< 56)
185
+ return finalize()
284
186
}
285
187
286
- // FIXME(ABI)#65 (UnsafeRawBufferPointer): Use UnsafeRawBufferPointer.
287
- @_inlineable // FIXME(sil-serialize-all)
288
188
@inline(__always)
289
- public // @testable
290
- static func _hash_alwaysInline(
291
- data: UnsafeRawPointer,
292
- dataByteCount: Int,
293
- key: (UInt64, UInt64)
294
- ) -> UInt64 {
295
- var context = ${Self}(key: key)
296
- context._append_alwaysInline(data, byteCount: dataByteCount)
297
- return context._finalizeAndReturnHash_alwaysInline()
189
+ public mutating func finalize() -> UInt64 {
190
+ _compress(tailAndByteCount)
191
+
192
+ v2 ^= 0xff
193
+
194
+ for _ in 0..<${d_rounds} {
195
+ _SipHashDetail._sipRound(v0: &v0, v1: &v1, v2: &v2, v3: &v3)
196
+ }
197
+
198
+ return (v0 ^ v1 ^ v2 ^ v3)
298
199
}
299
200
}
300
201
% end
0 commit comments