Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
tsolomko committed Jun 3, 2017
2 parents 38bd80b + 27fec89 commit 90060b5
Show file tree
Hide file tree
Showing 86 changed files with 449 additions and 547 deletions.
4 changes: 2 additions & 2 deletions .jazzy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ clean: true
exclude: Tests/
author: Timofey Solomko
module: SWCompression
module_version: 3.0.0
module_version: 3.0.1
copyright: '© 2017 Timofey Solomko'
readme: README.md
github_url: https://github.com/tsolomko/SWCompression
github_file_prefix: https://github.com/tsolomko/SWCompression/tree/v3.0.0
github_file_prefix: https://github.com/tsolomko/SWCompression/tree/v3.0.1
theme: fullwidth
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Changelog
v3.0.1
----------------
- Significanty reduced memory usage and improved speed of Deflate compression.

v3.0.0
----------------
- All errors have been renamed, so they conform to Swift Naming Conventions (lowerCamelCase).
Expand Down
2 changes: 1 addition & 1 deletion SWCompression.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|

s.name = "SWCompression"
s.version = "3.0.0"
s.version = "3.0.1"
s.summary = "Framework with implementations in Swift of different (de)compression algorithms"

s.description = <<-DESC
Expand Down
2 changes: 1 addition & 1 deletion Sources/BZip2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public class BZip2: DecompressionAlgorithm {
out.append(byte)
}
totalCRC = (totalCRC << 1) | (totalCRC >> 31)
totalCRC ^= blockCRC32;
totalCRC ^= blockCRC32
} else if blockType == 0x177245385090 {
guard totalCRC == blockCRC32
else { throw BZip2Error.wrongCRC(Data(bytes: out)) }
Expand Down
69 changes: 18 additions & 51 deletions Sources/Deflate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,19 @@ public class Deflate: DecompressionAlgorithm {
switch code {
case .byte(let byte):
try mainLiterals.code(symbol: byte.toInt(), &bitWriter, DeflateError.symbolNotFound)
case .lengthDistance(let ld):
try mainLiterals.code(symbol: ld.lengthSymbol, &bitWriter, DeflateError.symbolNotFound)
bitWriter.write(number: ld.lengthExtraBits, bitsCount: ld.lengthExtraBitsCount)

try mainDistances.code(symbol: ld.distanceSymbol, &bitWriter, DeflateError.symbolNotFound)
bitWriter.write(number: ld.distanceExtraBits, bitsCount: ld.distanceExtraBitsCount)
case .lengthDistance(let length, let distance):
let lengthSymbol = Constants.lengthCode[Int(length) - 3]
let lengthExtraBits = Int(length) - Constants.lengthBase[lengthSymbol - 257]
let lengthExtraBitsCount = (257 <= lengthSymbol && lengthSymbol <= 260) || lengthSymbol == 285 ?
0 : (((lengthSymbol - 257) >> 2) - 1)
try mainLiterals.code(symbol: lengthSymbol, &bitWriter, DeflateError.symbolNotFound)
bitWriter.write(number: lengthExtraBits, bitsCount: lengthExtraBitsCount)

let distanceSymbol = ((Constants.distanceBase.index { $0 > Int(distance) }) ?? 30) - 1
let distanceExtraBits = Int(distance) - Constants.distanceBase[distanceSymbol]
let distanceExtraBitsCount = distanceSymbol == 0 || distanceSymbol == 1 ? 0 : ((distanceSymbol >> 1) - 1)
try mainDistances.code(symbol: distanceSymbol, &bitWriter, DeflateError.symbolNotFound)
bitWriter.write(number: distanceExtraBits, bitsCount: distanceExtraBitsCount)
}
}

Expand All @@ -397,48 +404,9 @@ public class Deflate: DecompressionAlgorithm {
return bitWriter.buffer
}

private struct LengthDistance {

let length: Int
let lengthSymbol: Int
let lengthExtraBits: Int
let lengthExtraBitsCount: Int

let distance: Int
let distanceSymbol: Int
let distanceExtraBits: Int
let distanceExtraBitsCount: Int

init(_ length: Int, _ distance: Int) {
self.length = length
let lengthSymbol = Constants.lengthCode[length - 3]
self.lengthSymbol = lengthSymbol
self.lengthExtraBits = length - Constants.lengthBase[lengthSymbol - 257]
self.lengthExtraBitsCount = (257 <= lengthSymbol && lengthSymbol <= 260) || lengthSymbol == 285 ?
0 : (((lengthSymbol - 257) >> 2) - 1)

self.distance = distance
let distanceSymbol = ((Constants.distanceBase.index { $0 > distance }) ?? 30) - 1
self.distanceSymbol = distanceSymbol
self.distanceExtraBits = distance - Constants.distanceBase[distanceSymbol]
self.distanceExtraBitsCount = distanceSymbol == 0 || distanceSymbol == 1 ? 0 : ((distanceSymbol >> 1) - 1)
}

}

private enum BLDCode: CustomStringConvertible {
private enum BLDCode {
case byte(UInt8)
case lengthDistance(LengthDistance)

var description: String {
switch self {
case .byte(let byte):
return "raw symbol: \(byte)"
case .lengthDistance(let ld):
return "length: \(ld.length), length symbol: \(ld.lengthSymbol), " +
"distance: \(ld.distance), distance symbol: \(ld.distanceSymbol)"
}
}
case lengthDistance(UInt16, UInt16)
}

private static func lengthEncode(_ rawBytes: [UInt8]) -> (codes: [BLDCode], stats: [Int]) {
Expand Down Expand Up @@ -493,10 +461,9 @@ public class Deflate: DecompressionAlgorithm {
repeatIndex = matchStartIndex + 1
}
}
let ld = LengthDistance(matchLength, distance)
buffer.append(BLDCode.lengthDistance(ld))
stats[ld.lengthSymbol] += 1
stats[286 + ld.distanceSymbol] += 1
buffer.append(BLDCode.lengthDistance(UInt16(truncatingBitPattern: matchLength), UInt16(truncatingBitPattern: distance)))
stats[Constants.lengthCode[matchLength - 3]] += 1 // Length symbol.
stats[286 + ((Constants.distanceBase.index { $0 > distance }) ?? 30) - 1] += 1 // Distance symbol.
inputIndex += matchLength
} else {
buffer.append(BLDCode.byte(byte))
Expand Down
134 changes: 27 additions & 107 deletions Sources/HuffmanTree.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ import Foundation

class HuffmanTree {

private enum HTNode {
case leaf(Int)
case branch(Set<Int>)
}

private var pointerData: DataWithPointer

private var tree: [HTNode]
private var tree: [Int]
private let leafCount: Int

private var codingIndices: [[Int]]
private let coding: Bool

init(bootstrap: [[Int]], _ pointerData: inout DataWithPointer, _ coding: Bool = false) {
Expand Down Expand Up @@ -66,7 +62,9 @@ class HuffmanTree {

// Calculate maximum amount of leaves possible in a tree.
self.leafCount = 1 << (lengths.last![1] + 1)
self.tree = Array(repeating: .leaf(-1), count: leafCount)
self.tree = Array(repeating: -1, count: leafCount)

self.codingIndices = coding ? Array(repeating: [-1, -1], count: lengths.count) : []

// Calculates symbols for each length in 'lengths' array and put them in the tree.
var loopBits = -1
Expand All @@ -81,53 +79,19 @@ class HuffmanTree {
}
// Then we need to reverse bit order of the symbol.
var treeCode = reverse(bits: loopBits, in: symbol)

if coding {
self.codingIndices[length[0]] = [treeCode, bits]
}

// Finally, we put it at its place in the tree.
var index = 0
for _ in 0..<bits {
let bit = treeCode & 1
index = bit == 0 ? 2 * index + 1 : 2 * index + 2
treeCode >>= 1
}
self.tree[index] = .leaf(length[0])
}

if coding {
for treeIndex in stride(from: self.leafCount - 1, through: 0, by: -1) {
switch self.tree[treeIndex] {
case .leaf(let symbol):
if symbol == -1 {
var replacementArray = Set<Int>()

let leftChildIndex = 2 * treeIndex + 1
if leftChildIndex < self.leafCount {
switch self.tree[leftChildIndex] {
case .leaf(let leftSymbol):
replacementArray.insert(leftSymbol)
case .branch(let leftArray):
for leftChild in leftArray {
replacementArray.insert(leftChild)
}
}
}

let rightChildIndex = 2 * treeIndex + 2
if rightChildIndex < self.leafCount {
switch self.tree[rightChildIndex] {
case .leaf(let rightSymbol):
replacementArray.insert(rightSymbol)
case .branch(let rightArray):
for rightChild in rightArray {
replacementArray.insert(rightChild)
}
}
}

self.tree[treeIndex] = .branch(replacementArray)
}
default:
continue
}
}
self.tree[index] = length[0]
}
}

Expand All @@ -147,74 +111,30 @@ class HuffmanTree {
guard index < self.leafCount else {
return -1
}
switch self.tree[index] {
case .leaf(let symbol):
if symbol > -1 {
return symbol
}
default:
continue
if self.tree[index] > -1 {
return self.tree[index]
}
}
}

func code(symbol: Int, _ bitWriter: inout BitToByteWriter, _ symbolNotFoundError: Error) throws {
precondition(self.coding, "HuffmanTree is not initalized for coding!")

var index = 0
while true {
switch self.tree[index] {
case .leaf(let foundSymbol):
if foundSymbol == symbol {
return
} else {
throw symbolNotFoundError
}
case .branch:
let leftChildIndex = 2 * index + 1
if leftChildIndex < self.leafCount {
switch self.tree[leftChildIndex] {
case .leaf(let foundLeftSymbol):
if foundLeftSymbol == symbol {
index = leftChildIndex
bitWriter.write(bit: 0)
continue
} else {
break
}
case .branch(let leftArray):
if leftArray.contains(symbol) {
index = leftChildIndex
bitWriter.write(bit: 0)
continue
} else {
break
}
}
}
guard symbol < self.codingIndices.count
else { throw symbolNotFoundError }

let rightChildIndex = 2 * index + 2
if rightChildIndex < self.leafCount {
switch self.tree[rightChildIndex] {
case .leaf(let foundRightSymbol):
if foundRightSymbol == symbol {
index = rightChildIndex
bitWriter.write(bit: 1)
continue
} else {
throw symbolNotFoundError
}
case .branch(let rightArray):
if rightArray.contains(symbol) {
index = rightChildIndex
bitWriter.write(bit: 1)
continue
} else {
throw symbolNotFoundError
}
}
}
}
let codingIndex = self.codingIndices[symbol]

guard codingIndex[0] > -1
else { throw symbolNotFoundError }

var treeCode = codingIndex[0]
let bits = codingIndex[1]

for _ in 0..<bits {
let bit = treeCode & 1
bitWriter.write(bit: bit == 0 ? 0 : 1)
treeCode >>= 1
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Service/Info-iOS.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.0.0</string>
<string>3.0.1</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
Expand Down
2 changes: 1 addition & 1 deletion Sources/Service/Info-tvOS.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.0.0</string>
<string>3.0.1</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
Expand Down
2 changes: 1 addition & 1 deletion Sources/Service/Info-watchOS.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.0.0</string>
<string>3.0.1</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
Expand Down
2 changes: 1 addition & 1 deletion Sources/Service/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.0.0</string>
<string>3.0.1</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
Expand Down
6 changes: 3 additions & 3 deletions Tests/DeflateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ class DeflateTests: XCTestCase {
self.perform(compressionTest: "test6")
}

// func testDeflate7() {
// self.perform(compressionTest: "test7")
// }
func testDeflate7() {
self.perform(compressionTest: "test7")
}

func testDeflate8() {
self.perform(compressionTest: "test8")
Expand Down
Loading

0 comments on commit 90060b5

Please sign in to comment.