the leading cross- platform solution for integrating PDFs into your app • twitter: @krzyzanowskim • github.com/krzyzanowskim • OSS: CryptoSwift, ObjectivePGP, Natalie….
let arr = String(1) + String(2) + String(3) + String(4) • let arr:[Int] = [1] + [2] + [3] + [4] + [5] + [6] Expression is too complex to be solved in reasonable time
let arr = String(1) + String(2) + String(3) + String(4) • let arr:[Int] = [1] + [2] + [3] + [4] + [5] + [6] • Script Expression is too complex to be solved in reasonable time
let arr = String(1) + String(2) + String(3) + String(4) • let arr:[Int] = [1] + [2] + [3] + [4] + [5] + [6] • Script • Not optimized (-Onone) Expression is too complex to be solved in reasonable time
let arr = String(1) + String(2) + String(3) + String(4) • let arr:[Int] = [1] + [2] + [3] + [4] + [5] + [6] • Script • Not optimized (-Onone) • Really slow Expression is too complex to be solved in reasonable time
let arr = String(1) + String(2) + String(3) + String(4) • let arr:[Int] = [1] + [2] + [3] + [4] + [5] + [6] • Script • Not optimized (-Onone) • Really slow • Compiled Natalie is ~500% faster Expression is too complex to be solved in reasonable time
modify • pass-by-value-and-copy-back • The compiler may optimize an inout variable to pass-by- reference, rather than copying in and out. • core(block: &array) func core(block: inout Array<UInt8>) https://twitter.com/chriseidhof/status/815839860913270784
UInt32, UInt64 is not • Improve > 2x by using Int non-obvious The innocent loop: var count: UInt64 = 0 for index in 0 ..< loopLimit { count += UInt64(localArray[Int(index)]) } takes 2.4 times as long if preceded by: let loopLimit = UInt64(nbrBytes) compared to: let loopLimit = Int(nbrBytes)
iterations extension Dictionary { /// An immutable version of update. Returns a new dictionary containing /// self’s values and the key/value passed in. func withUpdate(key: Key, value: Value) -> Dictionary<Key, Value> { var result = self result[key] = value return result } } let dict1 = ["joe": 3, "mary": 4] let dict2 = dict1.reduce([:]) { dict2, element in dict2.withUpdate(element.0, value: element.1 * 5) } var dict2 = [Key:Value](minCapacity: dict1.count) for (k,v) in dict1 { let (k1,v1) = transform(k,v) dict2[k1] = v1 }
map is much better • lazy is default now • Array<UInt8> turns out to be nearly 10% slower compared to: UnsafeMutablePointer<UInt8>.allocate(capacity:) - var returnArray:[UInt8] = array.map({ _ in return 0 }) + var returnArray:[UInt8] = [UInt8](count: array.count, repeatedValue: 0)
things with @inline(__always) • @inlinable is the future (@_inlineable) • transparent functions are implicitly marked @_inlineable • Force inlining with @_transparent • be careful with ABI
@box on the heap large enough to hold a value of type T, along with a retain count and any other metadata required by the runtime. The result of the instruction is the reference-counted @box reference that owns the box. The project_box instruction is used to retrieve the address of the value inside the box. 1 func arrayAlloc() { 2 var arr = [Int](repeating: 0, count: 1) 3 DispatchQueue(label: "queue").async { 4 arr.append(1) 5 } 6 arr.append(-1) 7 }
hex = hex 3 var output = [UInt8]() 4 5 output.reserveCapacity(hex.unicodeScalars.lazy.underestimatedCount) 6 var buffer: UInt8? 7 for char in hex.unicodeScalars.lazy { 8 guard char.value >= 48 && char.value <= 102 else { 9 output.removeAll() 10 return output 11 } 12 let v: UInt8 13 let c: UInt8 = UInt8(char.value) 14 switch c { 15 case let c where c <= 57: 16 v = c - 48 17 case let c where c >= 65 && c <= 70: 18 v = c - 55 19 case let c where c >= 97: 20 v = c - 87 21 default: 22 output.removeAll() 23 return output 24 } 25 if let b = buffer { 26 output.append(b << 4 | v) 27 buffer = nil 28 } else { 29 buffer = v 30 } 31 } 32 if let b = buffer { 33 output.append(b) 34 } 35 return output 36 } Ranges
contains a group of elements • all of the same data type • each element identified by index • position of each element can be computed from its index • Array is convenient to use • Array is optimized (COW)
efficient for you to perform operations on sections of a larger array. Instead of copying over the elements of a slice to new storage, an ArraySlice instance presents a view onto the storage of a larger array. And because ArraySlice presents the same interface as Array, you can generally perform the same operations on a slice as you could on the original array.
module • otherwise use @_specialization • Whole Module Optimization won’t help • Sometimes it won’t optimize for the same module • Avoid generics in public API
- the leading cross- platform solution for integrating PDFs into your app • twitter: @krzyzanowskim • github.com/krzyzanowskim • OSS: CryptoSwift, ObjectivePGP, Natalie…. questions?