Browse Source

Merge pull request #768 from valeriyvan/array-extention

Refactors `[UInt8].toUInt32Array()` and `[UInt8].toUInt64Array()`
Marcin Krzyzanowski 5 years ago
parent
commit
53d3fe5d78

+ 27 - 14
Sources/CryptoSwift/Collection+Extension.swift

@@ -15,31 +15,44 @@
 extension Collection where Self.Element == UInt8, Self.Index == Int {
   // Big endian order
   func toUInt32Array() -> Array<UInt32> {
-    if isEmpty {
+    guard !isEmpty else {
       return []
     }
 
-    var result = Array<UInt32>(reserveCapacity: 16)
-    for idx in stride(from: startIndex, to: endIndex, by: 4) {
-      let val = UInt32(bytes: self, fromIndex: idx).bigEndian
-      result.append(val)
+    let c = strideCount(from: startIndex, to: endIndex, by: 4)
+    return Array<UInt32>(unsafeUninitializedCapacity: c) { buf, count in
+      var counter = 0
+      for idx in stride(from: startIndex, to: endIndex, by: 4) {
+        let val = UInt32(bytes: self, fromIndex: idx).bigEndian
+        buf[counter] = val
+        counter += 1
+      }
+      count = counter
+      assert(counter == c)
     }
-
-    return result
   }
 
   // Big endian order
   func toUInt64Array() -> Array<UInt64> {
-    if isEmpty {
+    guard !isEmpty else {
       return []
     }
 
-    var result = Array<UInt64>(reserveCapacity: 32)
-    for idx in stride(from: startIndex, to: endIndex, by: 8) {
-      let val = UInt64(bytes: self, fromIndex: idx).bigEndian
-      result.append(val)
+    let c = strideCount(from: startIndex, to: endIndex, by: 8)
+    return Array<UInt64>(unsafeUninitializedCapacity: c) { buf, count in
+      var counter = 0
+      for idx in stride(from: startIndex, to: endIndex, by: 8) {
+        let val = UInt64(bytes: self, fromIndex: idx).bigEndian
+        buf[counter] = val
+        counter += 1
+      }
+      count = counter
+      assert(counter == c)
     }
-
-    return result
   }
 }
+
+private func strideCount(from: Int, to: Int, by: Int) -> Int {
+    let count = to - from
+    return count / by + (count % by > 0 ? 1 : 0)
+}

+ 26 - 0
Tests/CryptoSwiftTests/ExtensionsTest.swift

@@ -40,6 +40,32 @@ final class ExtensionsTest: XCTestCase {
     XCTAssertEqual(result[1], 0x1020304)
   }
 
+  func testToUInt32Performance() {
+    let len = 1_000_000
+    let a = [UInt8](unsafeUninitializedCapacity: len) { buf, count in
+      for i in 0..<len {
+      buf[i] = UInt8.random(in: 0...UInt8.max)
+      }
+      count = len
+    }
+    self.measure {
+      _ = a.toUInt32Array()
+    }
+  }
+
+  func testToUInt64Performance() {
+    let len = 1_000_000
+    let a = [UInt8](unsafeUninitializedCapacity: len) { buf, count in
+      for i in 0..<len {
+        buf[i] = UInt8.random(in: 0...UInt8.max)
+      }
+      count = len
+    }
+    self.measure {
+      _ = a.toUInt64Array()
+    }
+  }
+
   func testDataInit() {
     let data = Data( [0x01, 0x02, 0x03])
     XCTAssert(data.count == 3, "Invalid data")