Skip to content

Commit fad36c8

Browse files
committed
Speed up short key hashing
Use a packed 64-bit hash for keys up to 8 bytes, falling back to FNV for longer keys to reduce hashing work in hot paths.
1 parent f4bc2e1 commit fad36c8

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

Sources/TOMLDecoder/Parsing/Parser.swift

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,9 @@ func fastKeyHash(_ key: String) -> Int {
17721772
let prime: UInt64 = 1_099_511_628_211
17731773

17741774
if let hash = key.utf8.withContiguousStorageIfAvailable({ buffer -> UInt64 in
1775+
if buffer.count <= 8 {
1776+
return packedKeyHash(buffer)
1777+
}
17751778
var hash = offsetBasis
17761779
for byte in buffer {
17771780
hash ^= UInt64(byte)
@@ -1783,11 +1786,50 @@ func fastKeyHash(_ key: String) -> Int {
17831786
}
17841787

17851788
var hash = offsetBasis
1789+
var packed: UInt64 = 0
1790+
var count = 0
17861791
for byte in key.utf8 {
1792+
if count < 8 {
1793+
packed |= UInt64(byte) << (UInt64(count) * 8)
1794+
}
17871795
hash ^= UInt64(byte)
17881796
hash &*= prime
1797+
count += 1
1798+
}
1799+
return Int(truncatingIfNeeded: count <= 8 ? packed : hash)
1800+
}
1801+
1802+
@inline(__always)
1803+
private func packedKeyHash(_ buffer: UnsafeBufferPointer<UInt8>) -> UInt64 {
1804+
var packed: UInt64 = 0
1805+
switch buffer.count {
1806+
case 8:
1807+
packed |= UInt64(buffer[7]) << 56
1808+
fallthrough
1809+
case 7:
1810+
packed |= UInt64(buffer[6]) << 48
1811+
fallthrough
1812+
case 6:
1813+
packed |= UInt64(buffer[5]) << 40
1814+
fallthrough
1815+
case 5:
1816+
packed |= UInt64(buffer[4]) << 32
1817+
fallthrough
1818+
case 4:
1819+
packed |= UInt64(buffer[3]) << 24
1820+
fallthrough
1821+
case 3:
1822+
packed |= UInt64(buffer[2]) << 16
1823+
fallthrough
1824+
case 2:
1825+
packed |= UInt64(buffer[1]) << 8
1826+
fallthrough
1827+
case 1:
1828+
packed |= UInt64(buffer[0])
1829+
default:
1830+
break
17891831
}
1790-
return Int(truncatingIfNeeded: hash)
1832+
return packed
17911833
}
17921834

17931835
private func makeString(bytes: UnsafeBufferPointer<UInt8>, range: Range<Int>) -> String {

0 commit comments

Comments
 (0)