From 914441ec8285ae1e8354c22f692a81ae9bb70de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20B=C3=B8dskov?= Date: Tue, 3 Jan 2017 14:40:59 +0100 Subject: [PATCH 1/3] converts Huffman Coding to Swift 3 syntax --- .../Huffman.playground/Contents.swift | 10 +- .../Huffman.playground/Sources/Heap.swift | 34 +- .../Huffman.playground/Sources/Huffman.swift | 30 +- .../Sources/NSData+Bits.swift | 8 +- .../Sources/PriorityQueue.swift | 8 +- .../Huffman.playground/timeline.xctimeline | 10 + Huffman Coding/Huffman.swift | 294 +++++++++--------- Huffman Coding/NSData+Bits.swift | 76 ++--- Huffman Coding/README.markdown | 52 ++-- 9 files changed, 265 insertions(+), 257 deletions(-) diff --git a/Huffman Coding/Huffman.playground/Contents.swift b/Huffman Coding/Huffman.playground/Contents.swift index b67f93a6a..017c5baf2 100644 --- a/Huffman Coding/Huffman.playground/Contents.swift +++ b/Huffman Coding/Huffman.playground/Contents.swift @@ -3,21 +3,21 @@ import Foundation let s1 = "so much words wow many compression" -if let originalData = s1.dataUsingEncoding(NSUTF8StringEncoding) { - print(originalData.length) +if let originalData = s1.data(using: String.Encoding.utf8) { + print(originalData.count) let huffman1 = Huffman() - let compressedData = huffman1.compressData(originalData) + let compressedData = huffman1.compressData(data: originalData as NSData) print(compressedData.length) let frequencyTable = huffman1.frequencyTable() //print(frequencyTable) let huffman2 = Huffman() - let decompressedData = huffman2.decompressData(compressedData, frequencyTable: frequencyTable) + let decompressedData = huffman2.decompressData(data: compressedData, frequencyTable: frequencyTable) print(decompressedData.length) - let s2 = String(data: decompressedData, encoding: NSUTF8StringEncoding)! + let s2 = String(data: decompressedData as Data, encoding: String.Encoding.utf8)! print(s2) assert(s1 == s2) } diff --git a/Huffman Coding/Huffman.playground/Sources/Heap.swift b/Huffman Coding/Huffman.playground/Sources/Heap.swift index 64bd90cd8..5ace98a17 100644 --- a/Huffman Coding/Huffman.playground/Sources/Heap.swift +++ b/Huffman Coding/Huffman.playground/Sources/Heap.swift @@ -8,14 +8,14 @@ public struct Heap { var elements = [T]() /** Determines whether this is a max-heap (>) or min-heap (<). */ - private var isOrderedBefore: (T, T) -> Bool + fileprivate var isOrderedBefore: (T, T) -> Bool /** * Creates an empty heap. * The sort function determines whether this is a min-heap or max-heap. * For integers, > makes a max-heap, < makes a min-heap. */ - public init(sort: (T, T) -> Bool) { + public init(sort: @escaping (T, T) -> Bool) { self.isOrderedBefore = sort } @@ -24,9 +24,9 @@ public struct Heap { * the elements are inserted into the heap in the order determined by the * sort function. */ - public init(array: [T], sort: (T, T) -> Bool) { + public init(array: [T], sort: @escaping (T, T) -> Bool) { self.isOrderedBefore = sort - buildHeap(array) + buildHeap(array: array) } /* @@ -45,7 +45,7 @@ public struct Heap { */ private mutating func buildHeap(array: [T]) { elements = array - for i in (elements.count/2 - 1).stride(through: 0, by: -1) { + for i in stride(from: elements.count/2 - 1, to: 0, by: -1) { shiftDown(index: i, heapSize: elements.count) } } @@ -96,12 +96,12 @@ public struct Heap { * Adds a new value to the heap. This reorders the heap so that the max-heap * or min-heap property still holds. Performance: O(log n). */ - public mutating func insert(value: T) { + public mutating func insert(_ value: T) { elements.append(value) shiftUp(index: elements.count - 1) } - public mutating func insert(sequence: S) { + public mutating func insert(sequence: S) where S.Iterator.Element == T { for value in sequence { insert(value) } @@ -154,15 +154,15 @@ public struct Heap { * Takes a child node and looks at its parents; if a parent is not larger * (max-heap) or not smaller (min-heap) than the child, we exchange them. */ - mutating func shiftUp(index index: Int) { + mutating func shiftUp(index: Int) { var childIndex = index let child = elements[childIndex] - var parentIndex = indexOfParent(childIndex) + var parentIndex = indexOfParent(i: childIndex) while childIndex > 0 && isOrderedBefore(child, elements[parentIndex]) { elements[childIndex] = elements[parentIndex] childIndex = parentIndex - parentIndex = indexOfParent(childIndex) + parentIndex = indexOfParent(i: childIndex) } elements[childIndex] = child @@ -176,11 +176,11 @@ public struct Heap { * Looks at a parent node and makes sure it is still larger (max-heap) or * smaller (min-heap) than its childeren. */ - mutating func shiftDown(index index: Int, heapSize: Int) { + mutating func shiftDown(index: Int, heapSize: Int) { var parentIndex = index while true { - let leftChildIndex = indexOfLeftChild(parentIndex) + let leftChildIndex = indexOfLeftChild(i: parentIndex) let rightChildIndex = leftChildIndex + 1 // Figure out which comes first if we order them by the sort function: @@ -208,16 +208,16 @@ extension Heap where T: Equatable { /** * Searches the heap for the given element. Performance: O(n). */ - public func indexOf(element: T) -> Int? { - return indexOf(element, 0) + public func index(of element: T) -> Int? { + return index(of: element, 0) } - private func indexOf(element: T, _ i: Int) -> Int? { + private func index(of element: T, _ i: Int) -> Int? { if i >= count { return nil } if isOrderedBefore(element, elements[i]) { return nil } if element == elements[i] { return i } - if let j = indexOf(element, indexOfLeftChild(i)) { return j } - if let j = indexOf(element, indexOfRightChild(i)) { return j } + if let j = index(of: element, indexOfLeftChild(i: i)) { return j } + if let j = index(of: element, indexOfRightChild(i: i)) { return j } return nil } } diff --git a/Huffman Coding/Huffman.playground/Sources/Huffman.swift b/Huffman Coding/Huffman.playground/Sources/Huffman.swift index d50b90d82..79b24b09a 100644 --- a/Huffman Coding/Huffman.playground/Sources/Huffman.swift +++ b/Huffman Coding/Huffman.playground/Sources/Huffman.swift @@ -29,7 +29,7 @@ public class Huffman { /* The tree structure. The first 256 entries are for the leaf nodes (not all of those may be used, depending on the input). We add additional nodes as we build the tree. */ - var tree = [Node](count: 256, repeatedValue: Node()) + var tree = [Node](repeating: Node(), count: 256) /* This is the last node we add to the tree. */ var root: NodeIndex = -1 @@ -50,10 +50,10 @@ extension Huffman { occurs. These counts are stored in the first 256 nodes in the tree, i.e. the leaf nodes. The frequency table used by decompression is derived from this. */ - private func countByteFrequency(data: NSData) { - var ptr = UnsafePointer(data.bytes) + fileprivate func countByteFrequency(inData data: NSData) { + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) for _ in 0..(sort: { $0.count < $1.count }) for node in tree where node.count > 0 { @@ -123,13 +123,13 @@ extension Huffman { extension Huffman { /* Compresses the contents of an NSData object. */ public func compressData(data: NSData) -> NSData { - countByteFrequency(data) + countByteFrequency(inData: data) buildTree() let writer = BitWriter() - var ptr = UnsafePointer(data.bytes) + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) for _ in 0.. NSData { - restoreTree(frequencyTable) + restoreTree(fromTable: frequencyTable) let reader = BitReader(data: data) let outData = NSMutableData() @@ -167,7 +167,7 @@ extension Huffman { var i = 0 while i < byteCount { var b = findLeafNode(reader: reader, nodeIndex: root) - outData.appendBytes(&b, length: 1) + outData.append(&b, length: 1) i += 1 } return outData @@ -177,7 +177,7 @@ extension Huffman { next bit and use that to determine whether to step to the left or right. When we get to the leaf node, we simply return its index, which is equal to the original byte value. */ - private func findLeafNode(reader reader: BitReader, nodeIndex: Int) -> UInt8 { + private func findLeafNode(reader: BitReader, nodeIndex: Int) -> UInt8 { var h = nodeIndex while tree[h].right != -1 { if reader.readBit() { diff --git a/Huffman Coding/Huffman.playground/Sources/NSData+Bits.swift b/Huffman Coding/Huffman.playground/Sources/NSData+Bits.swift index 0aa821f72..3e5163521 100644 --- a/Huffman Coding/Huffman.playground/Sources/NSData+Bits.swift +++ b/Huffman Coding/Huffman.playground/Sources/NSData+Bits.swift @@ -8,7 +8,7 @@ public class BitWriter { public func writeBit(bit: Bool) { if outCount == 8 { - data.appendBytes(&outByte, length: 1) + data.append(&outByte, length: 1) outCount = 0 } outByte = (outByte << 1) | (bit ? 1 : 0) @@ -21,7 +21,7 @@ public class BitWriter { let diff = UInt8(8 - outCount) outByte <<= diff } - data.appendBytes(&outByte, length: 1) + data.append(&outByte, length: 1) } } } @@ -33,12 +33,12 @@ public class BitReader { var inCount = 8 public init(data: NSData) { - ptr = UnsafePointer(data.bytes) + ptr = data.bytes.assumingMemoryBound(to: UInt8.self) } public func readBit() -> Bool { if inCount == 8 { - inByte = ptr.memory // load the next byte + inByte = ptr.pointee // load the next byte inCount = 0 ptr = ptr.successor() } diff --git a/Huffman Coding/Huffman.playground/Sources/PriorityQueue.swift b/Huffman Coding/Huffman.playground/Sources/PriorityQueue.swift index 757a6c539..4cc9d15ed 100644 --- a/Huffman Coding/Huffman.playground/Sources/PriorityQueue.swift +++ b/Huffman Coding/Huffman.playground/Sources/PriorityQueue.swift @@ -11,13 +11,13 @@ queue (largest element first) or a min-priority queue (smallest element first). */ public struct PriorityQueue { - private var heap: Heap + fileprivate var heap: Heap /* To create a max-priority queue, supply a > sort function. For a min-priority queue, use <. */ - public init(sort: (T, T) -> Bool) { + public init(sort: @escaping (T, T) -> Bool) { heap = Heap(sort: sort) } @@ -33,7 +33,7 @@ public struct PriorityQueue { return heap.peek() } - public mutating func enqueue(element: T) { + public mutating func enqueue(_ element: T) { heap.insert(element) } @@ -53,6 +53,6 @@ public struct PriorityQueue { extension PriorityQueue where T: Equatable { public func indexOf(element: T) -> Int? { - return heap.indexOf(element) + return heap.index(of: element) } } diff --git a/Huffman Coding/Huffman.playground/timeline.xctimeline b/Huffman Coding/Huffman.playground/timeline.xctimeline index bf468afec..2b2555bb1 100644 --- a/Huffman Coding/Huffman.playground/timeline.xctimeline +++ b/Huffman Coding/Huffman.playground/timeline.xctimeline @@ -2,5 +2,15 @@ + + + + diff --git a/Huffman Coding/Huffman.swift b/Huffman Coding/Huffman.swift index d50b90d82..7e2961a2f 100644 --- a/Huffman Coding/Huffman.swift +++ b/Huffman Coding/Huffman.swift @@ -1,191 +1,191 @@ import Foundation /* - Basic implementation of Huffman encoding. It encodes bytes that occur often - with a smaller number of bits than bytes that occur less frequently. - - Based on Al Stevens' C Programming column from Dr.Dobb's Magazine, February - 1991 and October 1992. - - Note: This code is not optimized for speed but explanation. -*/ + Basic implementation of Huffman encoding. It encodes bytes that occur often + with a smaller number of bits than bytes that occur less frequently. + + Based on Al Stevens' C Programming column from Dr.Dobb's Magazine, February + 1991 and October 1992. + + Note: This code is not optimized for speed but explanation. + */ public class Huffman { - /* Tree nodes don't use pointers to refer to each other, but simple integer + /* Tree nodes don't use pointers to refer to each other, but simple integer indices. That allows us to use structs for the nodes. */ - typealias NodeIndex = Int - - /* A node in the compression tree. Leaf nodes represent the actual bytes that + typealias NodeIndex = Int + + /* A node in the compression tree. Leaf nodes represent the actual bytes that are present in the input data. The count of an intermediary node is the sum of the counts of all nodes below it. The root node's count is the number of bytes in the original, uncompressed input data. */ - struct Node { - var count = 0 - var index: NodeIndex = -1 - var parent: NodeIndex = -1 - var left: NodeIndex = -1 - var right: NodeIndex = -1 - } - - /* The tree structure. The first 256 entries are for the leaf nodes (not all + struct Node { + var count = 0 + var index: NodeIndex = -1 + var parent: NodeIndex = -1 + var left: NodeIndex = -1 + var right: NodeIndex = -1 + } + + /* The tree structure. The first 256 entries are for the leaf nodes (not all of those may be used, depending on the input). We add additional nodes as we build the tree. */ - var tree = [Node](count: 256, repeatedValue: Node()) - - /* This is the last node we add to the tree. */ - var root: NodeIndex = -1 - - /* The frequency table describes how often a byte occurs in the input data. + var tree = [Node](repeating: Node(), count: 256) + + /* This is the last node we add to the tree. */ + var root: NodeIndex = -1 + + /* The frequency table describes how often a byte occurs in the input data. You need it to decompress the Huffman-encoded data. The frequency table should be serialized along with the compressed data. */ - public struct Freq { - var byte: UInt8 = 0 - var count = 0 - } - - public init() { } + public struct Freq { + var byte: UInt8 = 0 + var count = 0 + } + + public init() { } } extension Huffman { - /* To compress a block of data, first we need to count how often each byte + /* To compress a block of data, first we need to count how often each byte occurs. These counts are stored in the first 256 nodes in the tree, i.e. the leaf nodes. The frequency table used by decompression is derived from this. */ - private func countByteFrequency(data: NSData) { - var ptr = UnsafePointer(data.bytes) - for _ in 0.. [Freq] { - var a = [Freq]() - for i in 0..<256 where tree[i].count > 0 { - a.append(Freq(byte: UInt8(i), count: tree[i].count)) + public func frequencyTable() -> [Freq] { + var a = [Freq]() + for i in 0..<256 where tree[i].count > 0 { + a.append(Freq(byte: UInt8(i), count: tree[i].count)) + } + return a } - return a - } } extension Huffman { - /* Builds a Huffman tree from a frequency table. */ - private func buildTree() { - // Create a min-priority queue and enqueue all used nodes. - var queue = PriorityQueue(sort: { $0.count < $1.count }) - for node in tree where node.count > 0 { - queue.enqueue(node) + /* Builds a Huffman tree from a frequency table. */ + fileprivate func buildTree() { + // Create a min-priority queue and enqueue all used nodes. + var queue = PriorityQueue(sort: { $0.count < $1.count }) + for node in tree where node.count > 0 { + queue.enqueue(node) + } + + while queue.count > 1 { + // Find the two nodes with the smallest frequencies that do not have + // a parent node yet. + let node1 = queue.dequeue()! + let node2 = queue.dequeue()! + + // Create a new intermediate node. + var parentNode = Node() + parentNode.count = node1.count + node2.count + parentNode.left = node1.index + parentNode.right = node2.index + parentNode.index = tree.count + tree.append(parentNode) + + // Link the two nodes into their new parent node. + tree[node1.index].parent = parentNode.index + tree[node2.index].parent = parentNode.index + + // Put the intermediate node back into the queue. + queue.enqueue(parentNode) + } + + // The final remaining node in the queue becomes the root of the tree. + let rootNode = queue.dequeue()! + root = rootNode.index } - - while queue.count > 1 { - // Find the two nodes with the smallest frequencies that do not have - // a parent node yet. - let node1 = queue.dequeue()! - let node2 = queue.dequeue()! - - // Create a new intermediate node. - var parentNode = Node() - parentNode.count = node1.count + node2.count - parentNode.left = node1.index - parentNode.right = node2.index - parentNode.index = tree.count - tree.append(parentNode) - - // Link the two nodes into their new parent node. - tree[node1.index].parent = parentNode.index - tree[node2.index].parent = parentNode.index - - // Put the intermediate node back into the queue. - queue.enqueue(parentNode) - } - - // The final remaining node in the queue becomes the root of the tree. - let rootNode = queue.dequeue()! - root = rootNode.index - } } extension Huffman { - /* Compresses the contents of an NSData object. */ - public func compressData(data: NSData) -> NSData { - countByteFrequency(data) - buildTree() - - let writer = BitWriter() - var ptr = UnsafePointer(data.bytes) - for _ in 0.. NSData { + countByteFrequency(inData: data) + buildTree() + + let writer = BitWriter() + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) + for _ in 0.. NSData { - restoreTree(frequencyTable) - - let reader = BitReader(data: data) - let outData = NSMutableData() - let byteCount = tree[root].count - - var i = 0 - while i < byteCount { - var b = findLeafNode(reader: reader, nodeIndex: root) - outData.appendBytes(&b, length: 1) - i += 1 + /* Takes a Huffman-compressed NSData object and outputs the uncompressed data. */ + public func decompressData(data: NSData, frequencyTable: [Freq]) -> NSData { + restoreTree(fromTable: frequencyTable) + + let reader = BitReader(data: data) + let outData = NSMutableData() + let byteCount = tree[root].count + + var i = 0 + while i < byteCount { + var b = findLeafNode(reader: reader, nodeIndex: root) + outData.append(&b, length: 1) + i += 1 + } + return outData } - return outData - } - - /* Walks the tree from the root down to the leaf node. At every node, read the + + /* Walks the tree from the root down to the leaf node. At every node, read the next bit and use that to determine whether to step to the left or right. When we get to the leaf node, we simply return its index, which is equal to the original byte value. */ - private func findLeafNode(reader reader: BitReader, nodeIndex: Int) -> UInt8 { - var h = nodeIndex - while tree[h].right != -1 { - if reader.readBit() { - h = tree[h].left - } else { - h = tree[h].right - } + private func findLeafNode(reader: BitReader, nodeIndex: Int) -> UInt8 { + var h = nodeIndex + while tree[h].right != -1 { + if reader.readBit() { + h = tree[h].left + } else { + h = tree[h].right + } + } + return UInt8(h) } - return UInt8(h) - } } diff --git a/Huffman Coding/NSData+Bits.swift b/Huffman Coding/NSData+Bits.swift index 0aa821f72..4ae3c5c6d 100644 --- a/Huffman Coding/NSData+Bits.swift +++ b/Huffman Coding/NSData+Bits.swift @@ -2,49 +2,49 @@ import Foundation /* Helper class for writing bits to an NSData object. */ public class BitWriter { - public var data = NSMutableData() - var outByte: UInt8 = 0 - var outCount = 0 - - public func writeBit(bit: Bool) { - if outCount == 8 { - data.appendBytes(&outByte, length: 1) - outCount = 0 + public var data = NSMutableData() + var outByte: UInt8 = 0 + var outCount = 0 + + public func writeBit(bit: Bool) { + if outCount == 8 { + data.append(&outByte, length: 1) + outCount = 0 + } + outByte = (outByte << 1) | (bit ? 1 : 0) + outCount += 1 } - outByte = (outByte << 1) | (bit ? 1 : 0) - outCount += 1 - } - - public func flush() { - if outCount > 0 { - if outCount < 8 { - let diff = UInt8(8 - outCount) - outByte <<= diff - } - data.appendBytes(&outByte, length: 1) + + public func flush() { + if outCount > 0 { + if outCount < 8 { + let diff = UInt8(8 - outCount) + outByte <<= diff + } + data.append(&outByte, length: 1) + } } - } } /* Helper class for reading bits from an NSData object. */ public class BitReader { - var ptr: UnsafePointer - var inByte: UInt8 = 0 - var inCount = 8 - - public init(data: NSData) { - ptr = UnsafePointer(data.bytes) - } - - public func readBit() -> Bool { - if inCount == 8 { - inByte = ptr.memory // load the next byte - inCount = 0 - ptr = ptr.successor() + var ptr: UnsafePointer + var inByte: UInt8 = 0 + var inCount = 8 + + public init(data: NSData) { + ptr = data.bytes.assumingMemoryBound(to: UInt8.self) + } + + public func readBit() -> Bool { + if inCount == 8 { + inByte = ptr.pointee // load the next byte + inCount = 0 + ptr = ptr.successor() + } + let bit = inByte & 0x80 // read the next bit + inByte <<= 1 + inCount += 1 + return bit == 0 ? false : true } - let bit = inByte & 0x80 // read the next bit - inByte <<= 1 - inCount += 1 - return bit == 0 ? false : true - } } diff --git a/Huffman Coding/README.markdown b/Huffman Coding/README.markdown index 528ba3a1d..6b2c0d245 100644 --- a/Huffman Coding/README.markdown +++ b/Huffman Coding/README.markdown @@ -70,10 +70,10 @@ public class BitWriter { public var data = NSMutableData() var outByte: UInt8 = 0 var outCount = 0 - + public func writeBit(bit: Bool) { if outCount == 8 { - data.appendBytes(&outByte, length: 1) + data.append(&outByte, length: 1) outCount = 0 } outByte = (outByte << 1) | (bit ? 1 : 0) @@ -86,7 +86,7 @@ public class BitWriter { let diff = UInt8(8 - outCount) outByte <<= diff } - data.appendBytes(&outByte, length: 1) + data.append(&outByte, length: 1) } } } @@ -103,14 +103,14 @@ public class BitReader { var ptr: UnsafePointer var inByte: UInt8 = 0 var inCount = 8 - + public init(data: NSData) { - ptr = UnsafePointer(data.bytes) + ptr = data.bytes.assumingMemoryBound(to: UInt8.self) } - + public func readBit() -> Bool { if inCount == 8 { - inByte = ptr.memory // load the next byte + inByte = ptr.pointee // load the next byte inCount = 0 ptr = ptr.successor() } @@ -145,8 +145,8 @@ class Huffman { var left: NodeIndex = -1 var right: NodeIndex = -1 } - - var tree = [Node](count: 256, repeatedValue: Node()) + + var tree = [Node](repeating: Node(), count: 256) var root: NodeIndex = -1 } @@ -159,10 +159,10 @@ Note that `tree` currently has room for 256 entries. These are for the leaf node We use the following method to count how often each byte occurs in the input data: ```swift - private func countByteFrequency(data: NSData) { - var ptr = UnsafePointer(data.bytes) + fileprivate func countByteFrequency(inData data: NSData) { + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) for _ in 0..(sort: { $0.count < $1.count }) for node in tree where node.count > 0 { queue.enqueue(node) // 1 @@ -252,7 +252,7 @@ Here is how it works step-by-step: 4. Link the two nodes into their new parent node. Now this new intermediate node has become part of the tree. -5. Put the new intermediate node back into the queue. At this point we're done with `node1` and `node2`, but the `parentNode` stills need to be connected to other nodes in the tree. +5. Put the new intermediate node back into the queue. At this point we're done with `node1` and `node2`, but the `parentNode` still need to be connected to other nodes in the tree. 6. Repeat steps 2-5 until there is only one node left in the queue. This becomes the root node of the tree, and we're done. @@ -269,20 +269,18 @@ The animation shows what the process looks like: Now that we know how to build the compression tree from the frequency table, we can use it to compress the contents of an `NSData` object. Here is the code: ```swift - func compressData(data: NSData) -> NSData { - countByteFrequency(data) + public func compressData(data: NSData) -> NSData { + countByteFrequency(inData: data) buildTree() - - let writer = BitWriter() - var ptr = UnsafePointer(data.bytes) + let writer = BitWriter() + var ptr = data.bytes.assumingMemoryBound(to: UInt8.self) for _ in 0.. NSData { - restoreTree(frequencyTable) + restoreTree(fromTable: frequencyTable) let reader = BitReader(data: data) let outData = NSMutableData() @@ -364,7 +362,7 @@ Here is the code for `decompressData()`, which takes an `NSData` object with Huf var i = 0 while i < byteCount { var b = findLeafNode(reader: reader, nodeIndex: root) - outData.appendBytes(&b, length: 1) + outData.append(&b, length: 1) i += 1 } return outData From 58058cf6e9f6813ffbde7cf89ebefba07950d18b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20B=C3=B8dskov?= Date: Thu, 5 Jan 2017 08:02:06 +0100 Subject: [PATCH 2/3] aligning with style guidelines --- Huffman Coding/Huffman.playground/Contents.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Huffman Coding/Huffman.playground/Contents.swift b/Huffman Coding/Huffman.playground/Contents.swift index 017c5baf2..2d59908e9 100644 --- a/Huffman Coding/Huffman.playground/Contents.swift +++ b/Huffman Coding/Huffman.playground/Contents.swift @@ -3,7 +3,7 @@ import Foundation let s1 = "so much words wow many compression" -if let originalData = s1.data(using: String.Encoding.utf8) { +if let originalData = s1.data(using: .utf8) { print(originalData.count) let huffman1 = Huffman() @@ -17,7 +17,7 @@ if let originalData = s1.data(using: String.Encoding.utf8) { let decompressedData = huffman2.decompressData(data: compressedData, frequencyTable: frequencyTable) print(decompressedData.length) - let s2 = String(data: decompressedData as Data, encoding: String.Encoding.utf8)! + let s2 = String(data: decompressedData as Data, encoding: .utf8)! print(s2) assert(s1 == s2) } From c60c4635cce8f92bb749d9368c857d290ea27658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20B=C3=B8dskov?= Date: Thu, 5 Jan 2017 11:15:36 +0100 Subject: [PATCH 3/3] Migrates All-Pairs Shortest Paths to Swift 3 syntax --- .travis.yml | 2 +- .../APSP/APSP.xcodeproj/project.pbxproj | 13 +++++++++- .../xcshareddata/xcschemes/APSP.xcscheme | 2 +- .../xcshareddata/xcschemes/APSPTests.xcscheme | 2 +- All-Pairs Shortest Paths/APSP/APSP/APSP.swift | 2 +- .../APSP/APSP/FloydWarshall.swift | 26 +++++++++---------- .../APSP/APSP/Helpers.swift | 11 ++++---- .../APSP/APSPTests/APSPTests.swift | 6 ++--- 8 files changed, 38 insertions(+), 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4fbf215de..2417b4b6a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ install: script: -# - xcodebuild test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests +- xcodebuild test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests - xcodebuild test -project ./Array2D/Tests/Tests.xcodeproj -scheme Tests - xcodebuild test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests - xcodebuild test -project ./Binary\ Search/Tests/Tests.xcodeproj -scheme Tests diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj index e7e95bbb7..b2d93ea35 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj @@ -187,14 +187,16 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 493D8DDF1CDD2A1C0089795A = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0820; }; 493D8DF01CDD5B960089795A = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0820; }; }; }; @@ -305,8 +307,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -350,8 +354,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -370,6 +376,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; @@ -381,6 +388,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -392,6 +400,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -411,6 +420,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -432,6 +442,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme index 475997aa9..e313c4b88 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme @@ -1,6 +1,6 @@ ) -> P + static func apply(_ graph: AbstractGraph) -> P } diff --git a/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift b/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift index 806c8677c..b1a870f2a 100644 --- a/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift +++ b/All-Pairs Shortest Paths/APSP/APSP/FloydWarshall.swift @@ -17,7 +17,7 @@ private typealias StepResult = (distances: Distances, predecessors: Predecessors - note: In all complexity bounds, `V` is the number of vertices in the graph, and `E` is the number of edges. */ -public struct FloydWarshall: APSPAlgorithm { +public struct FloydWarshall: APSPAlgorithm where T: Hashable { public typealias Q = T public typealias P = FloydWarshallResult @@ -29,7 +29,7 @@ public struct FloydWarshall: APSPAlgorithm { - complexity: `Θ(V^3)` time, `Θ(V^2)` space - returns a `FloydWarshallResult` struct which can be queried for shortest paths and their total weights */ - public static func apply(graph: AbstractGraph) -> FloydWarshallResult { + public static func apply(_ graph: AbstractGraph) -> FloydWarshallResult { var previousDistance = constructInitialDistanceMatrix(graph) var previousPredecessor = constructInitialPredecessorMatrix(previousDistance) @@ -59,12 +59,12 @@ public struct FloydWarshall: APSPAlgorithm { - returns: a tuple containing the next distance matrix with weights of currently known shortest paths and the corresponding predecessor matrix */ - static private func nextStep(intermediateIdx: Int, previousDistances: Distances, + static fileprivate func nextStep(_ intermediateIdx: Int, previousDistances: Distances, previousPredecessors: Predecessors, graph: AbstractGraph) -> StepResult { let vertexCount = graph.vertices.count - var nextDistances = Array(count: vertexCount, repeatedValue: Array(count: vertexCount, repeatedValue: Double.infinity)) - var nextPredecessors = Array(count: vertexCount, repeatedValue: Array(count: vertexCount, repeatedValue: nil)) + var nextDistances = Array(repeating: Array(repeating: Double.infinity, count: vertexCount), count: vertexCount) + var nextPredecessors = Array(repeating: Array(repeating: nil, count: vertexCount), count: vertexCount) for fromIdx in 0 ..< vertexCount { for toIndex in 0 ..< vertexCount { @@ -97,12 +97,12 @@ public struct FloydWarshall: APSPAlgorithm { - complexity: `Θ(V^2)` time/space - returns: weighted adjacency matrix in form ready for processing with Floyd-Warshall */ - static private func constructInitialDistanceMatrix(graph: AbstractGraph) -> Distances { + static fileprivate func constructInitialDistanceMatrix(_ graph: AbstractGraph) -> Distances { let vertices = graph.vertices let vertexCount = graph.vertices.count - var distances = Array(count: vertexCount, repeatedValue: Array(count: vertexCount, repeatedValue: Double.infinity)) + var distances = Array(repeating: Array(repeating: Double.infinity, count: vertexCount), count: vertexCount) for row in vertices { for col in vertices { @@ -125,10 +125,10 @@ public struct FloydWarshall: APSPAlgorithm { - complexity: `Θ(V^2)` time/space */ - static private func constructInitialPredecessorMatrix(distances: Distances) -> Predecessors { + static fileprivate func constructInitialPredecessorMatrix(_ distances: Distances) -> Predecessors { let vertexCount = distances.count - var predecessors = Array(count: vertexCount, repeatedValue: Array(count: vertexCount, repeatedValue: nil)) + var predecessors = Array(repeating: Array(repeating: nil, count: vertexCount), count: vertexCount) for fromIdx in 0 ..< vertexCount { for toIdx in 0 ..< vertexCount { @@ -151,10 +151,10 @@ public struct FloydWarshall: APSPAlgorithm { It conforms to the `APSPResult` procotol which provides methods to retrieve distances and paths between given pairs of start and end nodes. */ -public struct FloydWarshallResult: APSPResult { +public struct FloydWarshallResult: APSPResult where T: Hashable { - private var weights: Distances - private var predecessors: Predecessors + fileprivate var weights: Distances + fileprivate var predecessors: Predecessors /** - returns: the total weight of the path from a starting vertex to a destination. @@ -190,7 +190,7 @@ public struct FloydWarshallResult: APSPResult { - returns: the list of predecessors discovered so far */ - private func recursePathFrom(fromVertex from: Vertex, toVertex to: Vertex, path: [Vertex], + fileprivate func recursePathFrom(fromVertex from: Vertex, toVertex to: Vertex, path: [Vertex], inGraph graph: AbstractGraph) -> [Vertex]? { if from.index == to.index { diff --git a/All-Pairs Shortest Paths/APSP/APSP/Helpers.swift b/All-Pairs Shortest Paths/APSP/APSP/Helpers.swift index 644454491..3812b3f58 100644 --- a/All-Pairs Shortest Paths/APSP/APSP/Helpers.swift +++ b/All-Pairs Shortest Paths/APSP/APSP/Helpers.swift @@ -7,10 +7,11 @@ import Foundation + /** Print a matrix, optionally specifying only the cells to display with the triplet (i, j, k) -> matrix[i][j], matrix[i][k], matrix[k][j] */ -func printMatrix(matrix: [[Double]], i: Int = -1, j: Int = -1, k: Int = -1) { +func printMatrix(_ matrix: [[Double]], i: Int = -1, j: Int = -1, k: Int = -1) { if i >= 0 { print(" k: \(k); i: \(i); j: \(j)\n") @@ -31,12 +32,12 @@ func printMatrix(matrix: [[Double]], i: Int = -1, j: Int = -1, k: Int = -1) { } grid.append(row) } - print((grid as NSArray).componentsJoinedByString("\n")) + print((grid as NSArray).componentsJoined(by: "\n")) print(" =======================") } -func printIntMatrix(matrix: [[Int?]]) { +func printIntMatrix(_ matrix: [[Int?]]) { var grid = [String]() @@ -46,14 +47,14 @@ func printIntMatrix(matrix: [[Int?]]) { for y in 0.. { +struct TestCase where T: Hashable { var from: Vertex var to: Vertex @@ -71,7 +71,7 @@ class APSPTests: XCTestCase { for testCase: TestCase in cases { if let computedPath = result.path(fromVertex: testCase.from, toVertex: testCase.to, inGraph: graph), - computedDistance = result.distance(fromVertex: testCase.from, toVertex: testCase.to) { + let computedDistance = result.distance(fromVertex: testCase.from, toVertex: testCase.to) { XCTAssert(computedDistance == testCase.expectedDistance, "expected distance \(testCase.expectedDistance) but got \(computedDistance)") XCTAssert(computedPath == testCase.expectedPath, "expected path \(testCase.expectedPath) but got \(computedPath)") } @@ -111,7 +111,7 @@ class APSPTests: XCTestCase { for testCase: TestCase in cases { if let computedPath = result.path(fromVertex: testCase.from, toVertex: testCase.to, inGraph: graph), - computedDistance = result.distance(fromVertex: testCase.from, toVertex: testCase.to) { + let computedDistance = result.distance(fromVertex: testCase.from, toVertex: testCase.to) { XCTAssert(computedDistance == testCase.expectedDistance, "expected distance \(testCase.expectedDistance) but got \(computedDistance)") XCTAssert(computedPath == testCase.expectedPath, "expected path \(testCase.expectedPath) but got \(computedPath)") }