1
1
mirror of https://github.com/github/semantic.git synced 2024-12-30 18:36:27 +03:00
semantic/prototype/Doubt/Hash.swift

109 lines
2.2 KiB
Swift
Raw Normal View History

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 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)
}
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: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 {
var hash: Hash { get }
}
extension AlgebraicHashable {
public var hashValue: Int {
return hash.hashValue
}
}
extension RawRepresentable where RawValue: Hashable {
public var hash: Hash {
return Hash(rawValue)
}
}
extension RawRepresentable where RawValue: AlgebraicHashable {
public var hash: Hash {
return Hash(rawValue)
}
}