2015-10-01 21:25:17 +03:00
|
|
|
|
/// An algebraic representation of a non-cryptographic hash.
|
2015-10-01 17:46:25 +03:00
|
|
|
|
public enum Hash: AlgebraicHashable {
|
2015-10-01 21:25:17 +03:00
|
|
|
|
/// An ordered sequence of sub-hashes to mix.
|
2015-10-01 17:09:44 +03:00
|
|
|
|
case Ordered([Hash])
|
2015-10-01 21:25:17 +03:00
|
|
|
|
|
|
|
|
|
/// An unordered collection of sub-hashes to mix. These will be mixed with an associative, commutative operation.
|
2015-10-01 17:45:47 +03:00
|
|
|
|
case Unordered([Hash])
|
2015-10-01 21:25:17 +03:00
|
|
|
|
|
|
|
|
|
/// A label, e.g. for an enum case or a dictionary key.
|
2015-09-30 17:42:43 +03:00
|
|
|
|
case Label(String)
|
2015-10-01 21:25:17 +03:00
|
|
|
|
|
|
|
|
|
/// The embedding of a raw hash value into an algebraic hash.
|
2015-09-30 17:40:45 +03:00
|
|
|
|
case Raw(Int)
|
2015-09-30 00:00:26 +03:00
|
|
|
|
|
2015-10-02 19:24:18 +03:00
|
|
|
|
/// The empty hash.
|
|
|
|
|
///
|
|
|
|
|
/// This is the right and left unit for Unordered.
|
|
|
|
|
case Empty
|
|
|
|
|
|
2015-09-30 17:44:48 +03:00
|
|
|
|
public init(_ label: String, _ hashes: Hash...) {
|
2015-10-01 17:09:44 +03:00
|
|
|
|
self = .Ordered([ Hash(label) ] + hashes)
|
2015-09-30 00:02:35 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-30 17:42:27 +03:00
|
|
|
|
public init(_ string: String) {
|
|
|
|
|
self = .Label(string)
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-30 17:43:18 +03:00
|
|
|
|
public init(_ raw: Int) {
|
|
|
|
|
self = .Raw(raw)
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-30 00:01:38 +03:00
|
|
|
|
public init<A: AlgebraicHashable>(_ hashable: A) {
|
|
|
|
|
self = hashable.hash
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public init<A: Hashable>(_ hashable: A) {
|
2015-09-30 17:40:28 +03:00
|
|
|
|
self = .Raw(hashable.hashValue)
|
2015-09-30 00:01:38 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-30 00:00:26 +03:00
|
|
|
|
|
2015-10-01 17:46:25 +03:00
|
|
|
|
public var hash: Hash {
|
|
|
|
|
return self
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-30 17:40:45 +03:00
|
|
|
|
public var hashValue: Int {
|
2015-09-30 00:00:26 +03:00
|
|
|
|
switch self {
|
2015-10-01 17:09:44 +03:00
|
|
|
|
case let .Ordered(s):
|
2015-09-30 00:00:26 +03:00
|
|
|
|
// Bob Jenkins’ one-at-a-time hash: https://en.wikipedia.org/wiki/Jenkins_hash_function
|
|
|
|
|
var hash = 0
|
|
|
|
|
for each in s {
|
|
|
|
|
hash += each.hashValue
|
|
|
|
|
hash += hash << 10
|
|
|
|
|
hash ^= hash >> 6
|
|
|
|
|
}
|
|
|
|
|
hash += hash << 3
|
|
|
|
|
hash ^= hash >> 11
|
|
|
|
|
hash += hash << 15
|
|
|
|
|
return hash
|
2015-10-01 17:45:47 +03:00
|
|
|
|
case let .Unordered(s):
|
|
|
|
|
return s.lazy.map { $0.hashValue }.reduce(0, combine: +)
|
2015-09-30 17:42:27 +03:00
|
|
|
|
case let .Label(s):
|
2015-09-30 00:00:26 +03:00
|
|
|
|
return s.hashValue
|
2015-09-30 17:40:28 +03:00
|
|
|
|
case let .Raw(i):
|
2015-09-30 00:00:26 +03:00
|
|
|
|
return i.hashValue
|
2015-10-02 19:24:18 +03:00
|
|
|
|
case .Empty:
|
|
|
|
|
return 0
|
2015-09-30 00:00:26 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public func == (left: Hash, right: Hash) -> Bool {
|
|
|
|
|
switch (left, right) {
|
2015-10-01 17:09:44 +03:00
|
|
|
|
case let (.Ordered(a), .Ordered(b)):
|
2015-09-30 00:00:26 +03:00
|
|
|
|
return a == b
|
2015-10-01 17:45:47 +03:00
|
|
|
|
case let (.Unordered(a), .Unordered(b)):
|
|
|
|
|
return a == b
|
2015-09-30 17:42:27 +03:00
|
|
|
|
case let (.Label(a), .Label(b)):
|
2015-09-30 00:00:26 +03:00
|
|
|
|
return a == b
|
2015-09-30 17:40:28 +03:00
|
|
|
|
case let (.Raw(a), .Raw(b)):
|
2015-09-30 00:00:26 +03:00
|
|
|
|
return a == b
|
2015-10-02 19:24:18 +03:00
|
|
|
|
case (.Empty, .Empty):
|
|
|
|
|
return true
|
2015-09-30 00:00:26 +03:00
|
|
|
|
default:
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-30 22:02:31 +03:00
|
|
|
|
public protocol AlgebraicHashable: Hashable {
|
2015-09-30 00:00:52 +03:00
|
|
|
|
var hash: Hash { get }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension AlgebraicHashable {
|
|
|
|
|
public var hashValue: Int {
|
|
|
|
|
return hash.hashValue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-30 00:02:01 +03:00
|
|
|
|
extension RawRepresentable where RawValue: Hashable {
|
|
|
|
|
public var hash: Hash {
|
|
|
|
|
return Hash(rawValue)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension RawRepresentable where RawValue: AlgebraicHashable {
|
|
|
|
|
public var hash: Hash {
|
|
|
|
|
return Hash(rawValue)
|
|
|
|
|
}
|
|
|
|
|
}
|