Merge pull request #4 from yaslab/refactoring

Refactoring
This commit is contained in:
Yasuhiro Hatta 2019-07-06 20:10:49 +09:00 committed by GitHub
commit a30d846585
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 164 additions and 155 deletions

View File

@ -39,103 +39,74 @@ extension Data {
/// Decode Crockford's Base32
init?(base32Encoded base32String: String, using table: [UInt8] = Base32.crockfordsDecodingTable) {
var base32String = base32String
while let last = base32String.last, last == "=" {
base32String.removeLast()
if base32String.last == "=", let index = base32String.lastIndex(where: { $0 != "=" }) {
base32String = String(base32String[...index])
}
let result: Data? = base32String.withCString(encodedAs: Unicode.UTF8.self) { (src) in
func _strlen(_ str: UnsafePointer<UInt8>) -> Int {
var str = str
var i = 0
while str.pointee != 0 {
str += 1
i += 1
}
return i
}
let srclen = _strlen(src)
guard [0, 2, 4, 5, 7].contains(srclen % 8) else {
return nil
}
let dstlen = srclen * 5 / 8
var buffer = Data(count: dstlen)
let success: Bool = buffer.withUnsafeMutableBytes { (dst: UnsafeMutableRawBufferPointer) -> Bool in
var srcleft = srclen
var srcp = src
var dsti: UnsafeMutableRawBufferPointer.Index = 0
let work = UnsafeMutablePointer<UInt8>.allocate(capacity: 8)
defer { work.deallocate() }
while srcleft > 0 {
let worklen = Swift.min(8, srcleft)
for i in 0 ..< worklen {
work[i] = table[Int(srcp[i])]
if work[i] == 0xff {
return false
}
}
switch worklen {
case 8:
dst[dsti + 4] = (work[6] << 5) | (work[7] )
fallthrough
case 7:
dst[dsti + 3] = (work[4] << 7) | (work[5] << 2) | (work[6] >> 3)
fallthrough
case 5:
dst[dsti + 2] = (work[3] << 4) | (work[4] >> 1)
fallthrough
case 4:
dst[dsti + 1] = (work[1] << 6) | (work[2] << 1) | (work[3] >> 4)
fallthrough
case 2:
dst[dsti + 0] = (work[0] << 3) | (work[1] >> 2)
default:
break
}
srcp += 8
srcleft -= 8
dsti += 5
}
return true
}
guard success else {
return nil
}
return buffer
}
guard let data = result else {
let src = base32String.utf8
guard [0, 2, 4, 5, 7].contains(src.count % 8) else {
return nil
}
var srcleft = src.count
var srci = 0
self = data
let dstlen = src.count * 5 / 8
let dst = UnsafeMutablePointer<UInt8>.allocate(capacity: dstlen)
var dsti = 0
defer { dst.deallocate() }
let work = UnsafeMutablePointer<UInt8>.allocate(capacity: 8)
defer { work.deallocate() }
while srcleft > 0 {
let worklen = Swift.min(8, srcleft)
for i in 0 ..< worklen {
work[i] = table[Int(src[src.index(src.startIndex, offsetBy: srci + i)])]
if work[i] == 0xff {
return nil
}
}
switch worklen {
case 8:
dst[dsti + 4] = (work[6] << 5) | (work[7] )
fallthrough
case 7:
dst[dsti + 3] = (work[4] << 7) | (work[5] << 2) | (work[6] >> 3)
fallthrough
case 5:
dst[dsti + 2] = (work[3] << 4) | (work[4] >> 1)
fallthrough
case 4:
dst[dsti + 1] = (work[1] << 6) | (work[2] << 1) | (work[3] >> 4)
fallthrough
case 2:
dst[dsti + 0] = (work[0] << 3) | (work[1] >> 2)
default:
break
}
srci += 8
srcleft -= 8
dsti += 5
}
self = Data(bytes: dst, count: dstlen)
}
/// Encode Crockford's Base32
func base32EncodedString(padding: Bool = true, using table: [UInt8] = Base32.crockfordsEncodingTable) -> String {
var srcleft = self.count
let dstlen: Int
if padding {
dstlen = (self.count + 4) / 5 * 8
} else {
dstlen = (self.count * 8 + 4) / 5
}
var dstleft = dstlen
return self.withUnsafeBytes { (src: UnsafeRawBufferPointer) -> String in
var srci: UnsafeRawBufferPointer.Index = 0
var srcleft = src.count
var srci = 0
let dstlen: Int
if padding {
dstlen = (src.count + 4) / 5 * 8
} else {
dstlen = (src.count * 8 + 4) / 5
}
var dstleft = dstlen
let dst = UnsafeMutablePointer<UInt8>.allocate(capacity: dstlen + 1)
var dstp = dst
defer { dst.deallocate() }
@ -179,18 +150,18 @@ extension Data {
if padding {
switch srcleft {
case 1:
dstp[2] = "=".utf8.first!
dstp[3] = "=".utf8.first!
dstp[2] = 0x3d
dstp[3] = 0x3d
fallthrough
case 2:
dstp[4] = "=".utf8.first!
dstp[4] = 0x3d
fallthrough
case 3:
dstp[5] = "=".utf8.first!
dstp[6] = "=".utf8.first!
dstp[5] = 0x3d
dstp[6] = 0x3d
fallthrough
case 4:
dstp[7] = "=".utf8.first!
dstp[7] = 0x3d
default:
break
}

View File

@ -28,7 +28,7 @@ public struct ULID: Hashable, Equatable, Comparable, CustomStringConvertible {
}
public init?(ulidString string: String) {
guard string.count == 26, let data = Data(base32Encoded: "000000" + string) else {
guard string.utf8.count == 26, let data = Data(base32Encoded: "000000" + string) else {
return nil
}
withUnsafeMutableBytes(of: &ulid) {

View File

@ -1,6 +1,8 @@
import XCTest
import ULIDTests
var tests = [XCTestCaseEntry]()
tests += ULIDTests.allTests()
tests += ULIDTests.__allTests()
XCTMain(tests)

View File

@ -224,28 +224,4 @@ final class Base32Tests: XCTestCase {
XCTAssertNil(data)
}
// MARK: -
static var allTests = [
("testEncodeBase32", testEncodeBase32),
("testEncode1", testEncode1),
("testEncode2", testEncode2),
("testEncode3", testEncode3),
("testEncode4", testEncode4),
("testEncode5", testEncode5),
("testEncode6", testEncode6),
("testEncode7", testEncode7),
("testEncode8", testEncode8),
("testEncodePad1", testEncodePad1),
("testEncodePad2", testEncodePad2),
("testEncodePad3", testEncodePad3),
("testEncodePad4", testEncodePad4),
("testEncodeNoPad", testEncodeNoPad),
("testDecodeBase32", testDecodeBase32),
("testDecodeTable", testDecodeTable),
("testDecodeInvalidCharacter", testDecodeInvalidCharacter),
("testDecodePadding", testDecodePadding),
("testDecodeIncorrectLength", testDecodeIncorrectLength)
]
}

View File

@ -61,6 +61,11 @@ final class ULIDTests: XCTestCase {
XCTAssertEqual(expected, actual!.ulidString)
}
func testParseULIDStringError() {
let zero = ""
XCTAssertNil(ULID(ulidString: zero))
}
func testParseULIDData() {
let expected: [UInt8] = [
0x01, 0x68, 0x3D, 0x17, 0x73, 0x09, 0xE5, 0x2D,
@ -73,6 +78,11 @@ final class ULIDTests: XCTestCase {
XCTAssertEqual(expected, Array(actual!.ulidData))
}
func testParseULIDDataError() {
let zero = Data()
XCTAssertNil(ULID(ulidData: zero))
}
func testULIDDataLength() {
let ulid = ULID()
XCTAssertEqual(16, ulid.ulidData.count)
@ -127,10 +137,10 @@ final class ULIDTests: XCTestCase {
}
func testComparable1() {
let lhs = ULID(ulid: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
let rhs = ULID(ulid: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1))
XCTAssertTrue(lhs < rhs)
XCTAssertFalse(lhs > rhs)
let lhs = ULID(ulid: (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
let rhs = ULID(ulid: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
XCTAssertFalse(lhs < rhs)
XCTAssertTrue(lhs > rhs)
}
func testComparable2() {
@ -141,6 +151,13 @@ final class ULIDTests: XCTestCase {
}
func testComparable3() {
let lhs = ULID(ulid: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
let rhs = ULID(ulid: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1))
XCTAssertTrue(lhs < rhs)
XCTAssertFalse(lhs > rhs)
}
func testComparable4() {
let now = Date()
let ulid0 = ULID(timestamp: now.addingTimeInterval(-120))
let ulid1 = ULID(timestamp: now.addingTimeInterval(-60))
@ -179,6 +196,21 @@ final class ULIDTests: XCTestCase {
}
}
func testDecodableError() {
let json = """
{ "ulid" : "" }
"""
do {
let decoder = JSONDecoder()
_ = try decoder.decode(CodableModel.self, from: json.data(using: .utf8)!)
XCTFail()
} catch DecodingError.dataCorrupted {
// Success
} catch {
XCTFail()
}
}
func testEncodable() {
let ulidString = "01D0YHEWR9WMPY4NNTPK1MR1TQ"
let expected = """
@ -198,27 +230,6 @@ final class ULIDTests: XCTestCase {
XCTAssertEqual(16, MemoryLayout<ULID>.size)
}
static var allTests = [
("testGenerateTimestamp", testGenerateTimestamp),
("testGenerateRandomness", testGenerateRandomness),
("testParseULIDString", testParseULIDString),
("testParseULIDData", testParseULIDData),
("testULIDDataLength", testULIDDataLength),
("testULIDStringLength", testULIDStringLength),
("testHashable1", testHashable1),
("testHashable2", testHashable2),
("testHashable3", testHashable3),
("testEquatable1", testEquatable1),
("testEquatable2", testEquatable2),
("testComparable1", testComparable1),
("testComparable2", testComparable2),
("testComparable3", testComparable3),
("testCustomStringConvertible", testCustomStringConvertible),
("testDecodable", testDecodable),
("testEncodable", testEncodable),
("testMemorySize", testMemorySize)
]
}
private struct MockRandomNumberGenerator: RandomNumberGenerator {

View File

@ -1,18 +1,67 @@
//
// XCTestManifests.swift
// ULIDTests
//
// Created by Yasuhiro Hatta on 2019/01/11.
// Copyright © 2019 yaslab. All rights reserved.
//
#if !canImport(ObjectiveC)
import XCTest
#if !os(macOS)
public func allTests() -> [XCTestCaseEntry] {
extension Base32Tests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__Base32Tests = [
("testDecodeBase32", testDecodeBase32),
("testDecodeIncorrectLength", testDecodeIncorrectLength),
("testDecodeInvalidCharacter", testDecodeInvalidCharacter),
("testDecodePadding", testDecodePadding),
("testDecodeTable", testDecodeTable),
("testEncode1", testEncode1),
("testEncode2", testEncode2),
("testEncode3", testEncode3),
("testEncode4", testEncode4),
("testEncode5", testEncode5),
("testEncode6", testEncode6),
("testEncode7", testEncode7),
("testEncode8", testEncode8),
("testEncodeBase32", testEncodeBase32),
("testEncodeNoPad", testEncodeNoPad),
("testEncodePad1", testEncodePad1),
("testEncodePad2", testEncodePad2),
("testEncodePad3", testEncodePad3),
("testEncodePad4", testEncodePad4),
]
}
extension ULIDTests {
// DO NOT MODIFY: This is autogenerated, use:
// `swift test --generate-linuxmain`
// to regenerate.
static let __allTests__ULIDTests = [
("testComparable1", testComparable1),
("testComparable2", testComparable2),
("testComparable3", testComparable3),
("testComparable4", testComparable4),
("testCustomStringConvertible", testCustomStringConvertible),
("testDecodable", testDecodable),
("testDecodableError", testDecodableError),
("testEncodable", testEncodable),
("testEquatable1", testEquatable1),
("testEquatable2", testEquatable2),
("testGenerateRandomness", testGenerateRandomness),
("testGenerateTimestamp", testGenerateTimestamp),
("testHashable1", testHashable1),
("testHashable2", testHashable2),
("testHashable3", testHashable3),
("testMemorySize", testMemorySize),
("testParseULIDData", testParseULIDData),
("testParseULIDDataError", testParseULIDDataError),
("testParseULIDString", testParseULIDString),
("testParseULIDStringError", testParseULIDStringError),
("testULIDDataLength", testULIDDataLength),
("testULIDStringLength", testULIDStringLength),
]
}
public func __allTests() -> [XCTestCaseEntry] {
return [
testCase(Base32Tests.allTests),
testCase(ULIDTests.allTests)
testCase(Base32Tests.__allTests__Base32Tests),
testCase(ULIDTests.__allTests__ULIDTests),
]
}
#endif