Refactoring

This commit is contained in:
Yasuhiro Hatta 2019-01-11 21:39:03 +09:00
parent 9d45ad0a3a
commit fed2b36d19
1 changed files with 48 additions and 25 deletions

View File

@ -7,44 +7,67 @@
import Foundation
public typealias ulid_t = uuid_t
public struct ULID {
public let ulidString: String
public private(set) var ulid: ulid_t = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
public init(ulid: ulid_t) {
self.ulid = ulid
}
public init(timestamp: Date = Date()) {
let now = UInt64(timestamp.timeIntervalSince1970 * 1000.0)
let timestampBase32 = withUnsafePointer(to: now.bigEndian) { (pointer) -> String in
var data = Data(bytes: pointer, count: 8)
data.insert(contentsOf: [0x00, 0x00], at: 0)
return String(data.base32EncodedString().suffix(10))
withUnsafeMutableBytes(of: &ulid) { (buffer) in
var millisec = UInt64(timestamp.timeIntervalSince1970 * 1000.0).bigEndian
withUnsafeBytes(of: &millisec) {
for i in 0 ..< 6 {
buffer[i] = $0[2 + i]
}
}
let range = UInt8.min ... .max
for i in 6 ..< 16 {
buffer[i] = UInt8.random(in: range)
}
}
let randomness = (0 ..< 16).map { _ in
Base32.crockfordsEncodingTable[Int.random(in: 0 ..< Base32.crockfordsEncodingTable.count)]
}
self.ulidString = timestampBase32 + String(randomness)
}
public init(ulidString string: String) {
self.ulidString = string
}
}
extension ULID {
private func decodeTimestamp() -> Date? {
let base32 = "000000" + String(self.ulidString.prefix(10))
guard let data = Data(base32Encoded: base32) else {
public init?(ulidData data: Data) {
guard data.count == 16 else {
return nil
}
return data.suffix(8).withUnsafeBytes { (pointer: UnsafePointer<UInt64>) in
Date(timeIntervalSince1970: TimeInterval(pointer.pointee.bigEndian) / 1000.0)
withUnsafeMutableBytes(of: &ulid) {
$0.copyBytes(from: data)
}
}
public init?(ulidString string: String) {
guard string.count == 26, let data = Data(base32Encoded: "000000" + string) else {
return nil
}
self.init(ulidData: data.dropFirst(4))
}
public var ulidData: Data {
return withUnsafeBytes(of: ulid) {
return Data(buffer: $0.bindMemory(to: UInt8.self))
}
}
public var ulidString: String {
return String((Data(count: 4) + ulidData).base32EncodedString().dropFirst(6))
}
public var timestamp: Date {
// TODO: Validate on `init`
return self.decodeTimestamp()!
return withUnsafeBytes(of: ulid) { (buffer) in
var millisec: UInt64 = 0
withUnsafeMutableBytes(of: &millisec) {
for i in 0 ..< 6 {
$0[2 + i] = buffer[i]
}
}
return Date(timeIntervalSince1970: TimeInterval(millisec.bigEndian) / 1000.0)
}
}
}