import Foundation /// xxHash64 (seed 0) — pure Swift, streaming. Spec: github.com/Cyan4973/xxHash. public struct XXHash64 { private static let p1: UInt64 = 0x9E3779B185EBCA87 private static let p2: UInt64 = 0xC2B2AE3D27D4EB4F private static let p3: UInt64 = 0x165667B19E3779F9 private static let p4: UInt64 = 0x85EBCA77C2B2AE63 private static let p5: UInt64 = 0x27D4EB2F165667C5 private var v1: UInt64 private var v2: UInt64 private var v3: UInt64 private var v4: UInt64 private var buffer = [UInt8]() private var totalLength: UInt64 = 0 private let seed: UInt64 public init(seed: UInt64 = 0) { self.seed = seed v1 = seed &+ Self.p1 &+ Self.p2 v2 = seed &+ Self.p2 v3 = seed v4 = seed &- Self.p1 } @inline(__always) private static func rotl(_ x: UInt64, _ r: UInt64) -> UInt64 { (x << r) | (x >> (64 - r)) } @inline(__always) private static func round(_ acc: UInt64, _ input: UInt64) -> UInt64 { rotl(acc &+ input &* p2, 31) &* p1 } @inline(__always) private static func mergeRound(_ acc: UInt64, _ val: UInt64) -> UInt64 { (acc ^ round(0, val)) &* p1 &+ p4 } @inline(__always) private static func readLE64(_ bytes: [UInt8], _ offset: Int) -> UInt64 { var v: UInt64 = 0 for i in 0..<8 { v |= UInt64(bytes[offset + i]) << (8 * UInt64(i)) } return v } @inline(__always) private static func readLE32(_ bytes: [UInt8], _ offset: Int) -> UInt64 { var v: UInt64 = 0 for i in 0..<4 { v |= UInt64(bytes[offset + i]) << (8 * UInt64(i)) } return v } public mutating func update(_ data: Data) { totalLength += UInt64(data.count) buffer.append(contentsOf: data) // Consume full 32-byte stripes, keep remainder buffered. var offset = 0 while buffer.count - offset >= 32 { v1 = Self.round(v1, Self.readLE64(buffer, offset)) v2 = Self.round(v2, Self.readLE64(buffer, offset + 8)) v3 = Self.round(v3, Self.readLE64(buffer, offset + 16)) v4 = Self.round(v4, Self.readLE64(buffer, offset + 24)) offset += 32 } if offset > 0 { buffer.removeFirst(offset) } } public func finalize() -> UInt64 { var h: UInt64 if totalLength >= 32 { h = Self.rotl(v1, 1) &+ Self.rotl(v2, 7) &+ Self.rotl(v3, 12) &+ Self.rotl(v4, 18) h = Self.mergeRound(h, v1) h = Self.mergeRound(h, v2) h = Self.mergeRound(h, v3) h = Self.mergeRound(h, v4) } else { h = seed &+ Self.p5 } h &+= totalLength var offset = 0 let tail = buffer while tail.count - offset >= 8 { h ^= Self.round(0, Self.readLE64(tail, offset)) h = Self.rotl(h, 27) &* Self.p1 &+ Self.p4 offset += 8 } if tail.count - offset >= 4 { h ^= Self.readLE32(tail, offset) &* Self.p1 h = Self.rotl(h, 23) &* Self.p2 &+ Self.p3 offset += 4 } while offset < tail.count { h ^= UInt64(tail[offset]) &* Self.p5 h = Self.rotl(h, 11) &* Self.p1 offset += 1 } h ^= h >> 33 h &*= Self.p2 h ^= h >> 29 h &*= Self.p3 h ^= h >> 32 return h } /// One-shot. public static func hash(_ data: Data, seed: UInt64 = 0) -> UInt64 { var h = XXHash64(seed: seed) h.update(data) return h.finalize() } public static func hexString(_ value: UInt64) -> String { String(format: "%016lx", value) } }