Add more hashers

This commit is contained in:
Justin Mazzocchi 2020-09-06 02:18:32 -07:00
parent fc2aa33fae
commit 94c41facd0
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
2 changed files with 29 additions and 5 deletions

View file

@ -4,33 +4,47 @@ import Foundation
public enum DeterministicHasher: String, Codable { public enum DeterministicHasher: String, Codable {
case djb2 case djb2
case djb2a
case sdbm case sdbm
case fnv1
case fnv1a
} }
extension DeterministicHasher { extension DeterministicHasher {
func apply(_ hashable: DeterministicallyHashable) -> Int { func apply(_ hashable: DeterministicallyHashable) -> Int {
Array(hashable.hashableData) Array(hashable.hashableData)
.map(Int.init) .map(Int.init)
.reduce(initial, then) .reduce(offsetBasis, hash)
} }
} }
// http://www.cse.yorku.ca/~oz/hash.html // http://www.cse.yorku.ca/~oz/hash.html
// http://www.isthe.com/chongo/tech/comp/fnv/
private extension DeterministicHasher { private extension DeterministicHasher {
var initial: Int { static let fnvPrime = 16777619
static let u32mod = 2 << 31
var offsetBasis: Int {
switch self { switch self {
case .djb2: return 5381 case .djb2, .djb2a: return 5381
case .sdbm: return 0 case .sdbm: return 0
case .fnv1, .fnv1a: return 2166136261
} }
} }
func then(result: Int, next: Int) -> Int { func hash(result: Int, next: Int) -> Int {
switch self { switch self {
case .djb2: case .djb2:
return (result << 5) &+ result &+ next return (result << 5) &+ result &+ next
case .djb2a:
return ((result << 5) &+ result ^ next) % Self.u32mod
case .sdbm: case .sdbm:
return next &+ (result << 6) &+ (result << 16) - result return next &+ (result << 6) &+ (result << 16) - result
case .fnv1:
return (result * Self.fnvPrime % Self.u32mod) ^ next
case .fnv1a:
return (result ^ next) * Self.fnvPrime % Self.u32mod
} }
} }
} }

View file

@ -1,9 +1,19 @@
// Copyright © 2020 Metabolist. All rights reserved.
@testable import CodableBloomFilter @testable import CodableBloomFilter
import XCTest import XCTest
final class CodableBloomFilterTests: XCTestCase { final class CodableBloomFilterTests: XCTestCase {
func testHashers() {
XCTAssertEqual(DeterministicHasher.djb2.apply("hash"), 6385287881)
XCTAssertEqual(DeterministicHasher.djb2a.apply("hash"), 2087809207)
XCTAssertEqual(DeterministicHasher.sdbm.apply("hash"), 29358318056884782)
XCTAssertEqual(DeterministicHasher.fnv1.apply("hash"), 0xd7918815)
XCTAssertEqual(DeterministicHasher.fnv1a.apply("hash"), 0xcec577d1)
}
func testContains() { func testContains() {
var sut = BloomFilter<String>(hashers: [.djb2, .sdbm], byteCount: 128) var sut = BloomFilter<String>(hashers: [.djb2, .sdbm, .fnv1, .fnv1a], byteCount: 128)
sut.insert("lol") sut.insert("lol")
sut.insert("ok") sut.insert("ok")