mirror of
https://github.com/tsolomko/SWCompression.git
synced 2026-06-23 14:56:41 +00:00
Merge branch 'develop'
This commit is contained in:
+2
-2
@@ -3,11 +3,11 @@ sourcekitten_sourcefile: docs.json
|
||||
clean: false
|
||||
author: Timofey Solomko
|
||||
module: SWCompression
|
||||
module_version: 4.6.0
|
||||
module_version: 4.6.1
|
||||
copyright: '© 2021 Timofey Solomko'
|
||||
readme: README.md
|
||||
github_url: https://github.com/tsolomko/SWCompression
|
||||
github_file_prefix: https://github.com/tsolomko/SWCompression/tree/4.6.0
|
||||
github_file_prefix: https://github.com/tsolomko/SWCompression/tree/4.6.1
|
||||
theme: fullwidth
|
||||
|
||||
custom_categories:
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
# TODO: There is probably a way to simplify this very explicit build matrix.
|
||||
git:
|
||||
depth: 1
|
||||
submodules: false
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
language: swift
|
||||
os: osx
|
||||
osx_image: xcode12.5 # Swift 5.4
|
||||
env:
|
||||
- HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
- WATCHOS_ACTIONS='clean test'
|
||||
- WATCHOS_SIMULATOR='Apple Watch Series 6 - 44mm'
|
||||
before_install:
|
||||
- brew update
|
||||
install:
|
||||
- ./utils.py ci install-macos
|
||||
before_script:
|
||||
- ./utils.py prepare-workspace macos --xcf
|
||||
script:
|
||||
- ./utils.py ci script-macos
|
||||
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## 4.6.1
|
||||
|
||||
- Fixed a crash in LZMA2 when trying to process an empty `Data`.
|
||||
- swcomp changes:
|
||||
- Added `benchmark create-tar` benchmarking command.
|
||||
- Benchmarking results are now printed in the units of speed instead of time elapsed.
|
||||
|
||||
## 4.6.0
|
||||
|
||||
- Swift 4.2 is no longer supported.
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
[](https://developer.apple.com/swift/)
|
||||
[](https://raw.githubusercontent.com/tsolomko/SWCompression/master/LICENSE)
|
||||
[](https://travis-ci.com/tsolomko/SWCompression)
|
||||
[](https://dev.azure.com/tsolomko/SWCompression/_build/latest?definitionId=3&branchName=develop)
|
||||
|
||||
A framework with (de)compression algorithms and functions for working with various archives and containers.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Pod::Spec.new do |s|
|
||||
|
||||
s.name = "SWCompression"
|
||||
s.version = "4.6.0"
|
||||
s.version = "4.6.1"
|
||||
s.summary = "A framework with functions for working with compression, archives and containers."
|
||||
|
||||
s.description = "A framework with (de)compression algorithms and functions for processing various archives and containers."
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.6.0</string>
|
||||
<string>4.6.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>80</string>
|
||||
<string>81</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2021 Timofey Solomko</string>
|
||||
</dict>
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.6.0</string>
|
||||
<string>4.6.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>80</string>
|
||||
<string>81</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -220,6 +220,9 @@
|
||||
E652D8F5263D678000FC229B /* test_nonstandard_runlength.answer in Resources */ = {isa = PBXBuildFile; fileRef = E652D8F4263D678000FC229B /* test_nonstandard_runlength.answer */; };
|
||||
E66F36242538726E00076A6E /* test_empty.lzma in Resources */ = {isa = PBXBuildFile; fileRef = E66F36232538726E00076A6E /* test_empty.lzma */; };
|
||||
E66F362C2538E2B700076A6E /* test_empty.zlib in Resources */ = {isa = PBXBuildFile; fileRef = E66F362B2538E2B700076A6E /* test_empty.zlib */; };
|
||||
E6EDD6A826F7767F00884532 /* test_minor_version_3.7z in Resources */ = {isa = PBXBuildFile; fileRef = E6EDD6A626F7767E00884532 /* test_minor_version_3.7z */; };
|
||||
E6EDD6A926F7767F00884532 /* test_minor_version_4.7z in Resources */ = {isa = PBXBuildFile; fileRef = E6EDD6A726F7767E00884532 /* test_minor_version_4.7z */; };
|
||||
E6EDD6AC26F77C0E00884532 /* test_minor_version_2.7z in Resources */ = {isa = PBXBuildFile; fileRef = E6EDD6AB26F77C0E00884532 /* test_minor_version_2.7z */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -447,6 +450,9 @@
|
||||
E652D8F4263D678000FC229B /* test_nonstandard_runlength.answer */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_nonstandard_runlength.answer; sourceTree = "<group>"; };
|
||||
E66F36232538726E00076A6E /* test_empty.lzma */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_empty.lzma; sourceTree = "<group>"; };
|
||||
E66F362B2538E2B700076A6E /* test_empty.zlib */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_empty.zlib; sourceTree = "<group>"; };
|
||||
E6EDD6A626F7767E00884532 /* test_minor_version_3.7z */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_minor_version_3.7z; sourceTree = "<group>"; };
|
||||
E6EDD6A726F7767E00884532 /* test_minor_version_4.7z */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_minor_version_4.7z; sourceTree = "<group>"; };
|
||||
E6EDD6AB26F77C0E00884532 /* test_minor_version_2.7z */ = {isa = PBXFileReference; lastKnownFileType = file; path = test_minor_version_2.7z; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -883,6 +889,9 @@
|
||||
06F066061FFB763300312A82 /* test_win.7z */,
|
||||
0627A4D220FE521B0023987C /* test_unicode.7z */,
|
||||
068D070321368617002A6C3B /* test_delta_filter.7z */,
|
||||
E6EDD6AB26F77C0E00884532 /* test_minor_version_2.7z */,
|
||||
E6EDD6A626F7767E00884532 /* test_minor_version_3.7z */,
|
||||
E6EDD6A726F7767E00884532 /* test_minor_version_4.7z */,
|
||||
06F066071FFB763300312A82 /* SWCompressionSourceCode.7z */,
|
||||
);
|
||||
path = 7z;
|
||||
@@ -949,7 +958,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0920;
|
||||
LastUpgradeCheck = 1250;
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = "Timofey Solomko";
|
||||
TargetAttributes = {
|
||||
06BE1AC71DB410F100EE0F59 = {
|
||||
@@ -991,6 +1000,7 @@
|
||||
06F066201FFB763300312A82 /* test1.answer in Resources */,
|
||||
06F0664E1FFB763400312A82 /* test_v7.tar in Resources */,
|
||||
06F0662E1FFB763400312A82 /* test2.gz in Resources */,
|
||||
E6EDD6AC26F77C0E00884532 /* test_minor_version_2.7z in Resources */,
|
||||
06F0665C1FFB763400312A82 /* test9.lzma in Resources */,
|
||||
06F066661FFB763400312A82 /* test3.7z in Resources */,
|
||||
06F0664B1FFB763400312A82 /* test.tar in Resources */,
|
||||
@@ -1073,6 +1083,7 @@
|
||||
06F066351FFB763400312A82 /* test5.xz in Resources */,
|
||||
06F066631FFB763400312A82 /* test_complicated_coding_scheme.7z in Resources */,
|
||||
06F066641FFB763400312A82 /* test_anti_file.7z in Resources */,
|
||||
E6EDD6A826F7767F00884532 /* test_minor_version_3.7z in Resources */,
|
||||
064D01AD20FD077D00CAE058 /* test_unicode_pax.tar in Resources */,
|
||||
06F0665E1FFB763400312A82 /* test_empty_cont.7z in Resources */,
|
||||
06F066731FFB763400312A82 /* test3.bz2 in Resources */,
|
||||
@@ -1083,6 +1094,7 @@
|
||||
06F066571FFB763400312A82 /* test_empty_file.tar in Resources */,
|
||||
06F066441FFB763400312A82 /* test_data_descriptor.zip in Resources */,
|
||||
06F066581FFB763400312A82 /* full_test.tar in Resources */,
|
||||
E6EDD6A926F7767F00884532 /* test_minor_version_4.7z in Resources */,
|
||||
06F0662B1FFB763400312A82 /* test3.gz in Resources */,
|
||||
06F0664C1FFB763400312A82 /* test_pax.tar in Resources */,
|
||||
06F0663A1FFB763400312A82 /* test_multi.xz in Resources */,
|
||||
@@ -1270,7 +1282,7 @@
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CURRENT_PROJECT_VERSION = 80;
|
||||
CURRENT_PROJECT_VERSION = 81;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -1351,7 +1363,7 @@
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CURRENT_PROJECT_VERSION = 80;
|
||||
CURRENT_PROJECT_VERSION = 81;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
"FRAMEWORK_SEARCH_PATHS[sdk=appletvos*]" = (
|
||||
@@ -1412,7 +1424,7 @@
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 80;
|
||||
DYLIB_CURRENT_VERSION = 81;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
@@ -1439,7 +1451,7 @@
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 80;
|
||||
DYLIB_CURRENT_VERSION = 81;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = SWCompression.xcodeproj/SWCompression.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1250"
|
||||
LastUpgradeVersion = "1300"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
class SevenZipProperty {
|
||||
struct SevenZipProperty {
|
||||
|
||||
let type: UInt8
|
||||
let size: Int
|
||||
|
||||
@@ -24,6 +24,8 @@ public class LZMA2: DecompressionAlgorithm {
|
||||
*/
|
||||
public static func decompress(data: Data) throws -> Data {
|
||||
let byteReader = LittleEndianByteReader(data: data)
|
||||
guard byteReader.bytesLeft >= 1
|
||||
else { throw LZMAError.rangeDecoderInitError }
|
||||
return try decompress(byteReader, byteReader.byte())
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
import Foundation
|
||||
import BitByteData
|
||||
|
||||
#if os(Linux)
|
||||
import CoreFoundation
|
||||
#endif
|
||||
|
||||
extension LittleEndianByteReader {
|
||||
|
||||
func zipString(_ length: Int, _ useUtf8: Bool) -> String? {
|
||||
@@ -21,12 +17,7 @@ extension LittleEndianByteReader {
|
||||
return String(data: stringData, encoding: .utf8)
|
||||
}
|
||||
if String.cp437Available && !stringData.needsUtf8() {
|
||||
#if os(Windows)
|
||||
return String(data: stringData, encoding: String.cp437Encoding)
|
||||
#else
|
||||
return String(data: stringData, encoding: String.Encoding(rawValue:
|
||||
CFStringConvertEncodingToNSStringEncoding(String.cp437Encoding)))
|
||||
#endif
|
||||
} else {
|
||||
return String(data: stringData, encoding: .utf8)
|
||||
}
|
||||
@@ -36,21 +27,9 @@ extension LittleEndianByteReader {
|
||||
|
||||
fileprivate extension String {
|
||||
|
||||
#if os(Linux)
|
||||
#if compiler(>=5.3)
|
||||
static let cp437Encoding: CFStringEncoding = CFStringEncoding(CFStringEncodings.dosLatinUS.rawValue)
|
||||
#else
|
||||
static let cp437Encoding: CFStringEncoding = UInt32(truncatingIfNeeded: UInt(kCFStringEncodingDOSLatinUS))
|
||||
#endif
|
||||
static let cp437Available: Bool = CFStringIsEncodingAvailable(cp437Encoding)
|
||||
#elseif os(Windows)
|
||||
// "Latin-US (DOS)" CP437-2147483120
|
||||
static let cp437Encoding = String.Encoding(rawValue: 0x80000400)
|
||||
static let cp437Available = String.availableStringEncodings.contains(cp437Encoding)
|
||||
#else
|
||||
static let cp437Encoding = CFStringEncoding(CFStringEncodings.dosLatinUS.rawValue)
|
||||
static let cp437Available = CFStringIsEncodingAvailable(cp437Encoding)
|
||||
#endif
|
||||
// "Latin-US (DOS)" CP437-2147483120
|
||||
static let cp437Encoding = String.Encoding(rawValue: 0x80000400)
|
||||
static let cp437Available = String.availableStringEncodings.contains(cp437Encoding)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -13,12 +13,28 @@ import SwiftCLI
|
||||
|
||||
protocol BenchmarkCommand: Command {
|
||||
|
||||
var files: CollectedParameter { get }
|
||||
associatedtype InputType
|
||||
|
||||
var inputs: CollectedParameter { get }
|
||||
|
||||
var benchmarkName: String { get }
|
||||
|
||||
var benchmarkFunction: (Data) throws -> Any { get }
|
||||
func loadInput(_ input: String) throws -> (InputType, Double)
|
||||
|
||||
var benchmarkFunction: (InputType) throws -> Any { get }
|
||||
|
||||
}
|
||||
|
||||
extension BenchmarkCommand where InputType == Data {
|
||||
|
||||
func loadInput(_ input: String) throws -> (Data, Double) {
|
||||
let inputURL = URL(fileURLWithPath: input)
|
||||
let inputData = try Data(contentsOf: inputURL, options: .mappedIfSafe)
|
||||
let attr = try FileManager.default.attributesOfItem(atPath: input)
|
||||
let inputSize = Double(attr[.size] as! UInt64)
|
||||
return (inputData, inputSize)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension BenchmarkCommand {
|
||||
@@ -28,16 +44,15 @@ extension BenchmarkCommand {
|
||||
print(String(repeating: "=", count: title.count))
|
||||
print(title)
|
||||
|
||||
for file in self.files.value {
|
||||
print("File: \(file)")
|
||||
for input in self.inputs.value {
|
||||
print("Input: \(input)")
|
||||
|
||||
let inputURL = URL(fileURLWithPath: file)
|
||||
let fileData = try Data(contentsOf: inputURL, options: .mappedIfSafe)
|
||||
let (loadedInput, inputSize) = try self.loadInput(input)
|
||||
|
||||
var totalTime: Double = 0
|
||||
var totalSpeed: Double = 0
|
||||
|
||||
var maxTime = Double(Int.min)
|
||||
var minTime = Double(Int.max)
|
||||
var maxSpeed = Double(Int.min)
|
||||
var minSpeed = Double(Int.max)
|
||||
|
||||
print("Iterations: ", terminator: "")
|
||||
#if !os(Linux)
|
||||
@@ -45,30 +60,35 @@ extension BenchmarkCommand {
|
||||
#endif
|
||||
// Zeroth (excluded) iteration.
|
||||
let startTime = CFAbsoluteTimeGetCurrent()
|
||||
_ = try benchmarkFunction(fileData)
|
||||
_ = try benchmarkFunction(loadedInput)
|
||||
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
|
||||
print(String(format: "(%.3f) ", timeElapsed), terminator: "")
|
||||
let speed = inputSize / timeElapsed
|
||||
print("(\(SpeedFormat(speed).format())), ", terminator: "")
|
||||
#if !os(Linux)
|
||||
fflush(__stdoutp)
|
||||
#endif
|
||||
|
||||
for _ in 1...10 {
|
||||
let startTime = CFAbsoluteTimeGetCurrent()
|
||||
_ = try benchmarkFunction(fileData)
|
||||
_ = try benchmarkFunction(loadedInput)
|
||||
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
|
||||
print(String(format: "%.3f ", timeElapsed), terminator: "")
|
||||
let speed = inputSize / timeElapsed
|
||||
print(SpeedFormat(speed).format() + ", ", terminator: "")
|
||||
#if !os(Linux)
|
||||
fflush(__stdoutp)
|
||||
#endif
|
||||
totalTime += timeElapsed
|
||||
if timeElapsed > maxTime {
|
||||
maxTime = timeElapsed
|
||||
totalSpeed += speed
|
||||
if speed > maxSpeed {
|
||||
maxSpeed = speed
|
||||
}
|
||||
if timeElapsed < minTime {
|
||||
minTime = timeElapsed
|
||||
if speed < minSpeed {
|
||||
minSpeed = speed
|
||||
}
|
||||
}
|
||||
print(String(format: "\nAverage: %.3f \u{B1} %.3f\n", totalTime / 10, (maxTime - minTime) / 2))
|
||||
let avgSpeed = totalSpeed / 10
|
||||
let avgSpeedFormat = SpeedFormat(avgSpeed)
|
||||
let speedUncertainty = (maxSpeed - minSpeed) / 2
|
||||
print("\nAverage: \(avgSpeedFormat.format().prefix { $0 != " " }) \u{B1} \(avgSpeedFormat.format(speedUncertainty))\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
class BenchmarkGroup: CommandGroup {
|
||||
@@ -11,6 +12,102 @@ class BenchmarkGroup: CommandGroup {
|
||||
let name = "benchmark"
|
||||
let shortDescription = "Run the specified benchmark using external files"
|
||||
|
||||
let children: [Routable] = [UnGzip(), UnXz(), UnBz2(), InfoTar(), InfoZip(), Info7z(), CompDeflate(), CompBz2()]
|
||||
let children: [Routable] = [UnGzip(), UnXz(), UnBz2(), InfoTar(), InfoZip(), Info7z(), CompDeflate(), CompBz2(), CreateTar()]
|
||||
|
||||
}
|
||||
|
||||
class CompBz2: BenchmarkCommand {
|
||||
|
||||
let name = "comp-bz2"
|
||||
let shortDescription = "BZip2 compression"
|
||||
|
||||
let inputs = CollectedParameter()
|
||||
|
||||
let benchmarkName = "BZip2 Compression"
|
||||
let benchmarkFunction: (Data) throws -> Any = BZip2.compress
|
||||
|
||||
}
|
||||
|
||||
class CompDeflate: BenchmarkCommand {
|
||||
|
||||
let name = "comp-deflate"
|
||||
let shortDescription = "Deflate compression"
|
||||
|
||||
let inputs = CollectedParameter()
|
||||
|
||||
let benchmarkName = "Deflate Compression"
|
||||
let benchmarkFunction: (Data) throws -> Any = Deflate.compress
|
||||
|
||||
}
|
||||
|
||||
class Info7z: BenchmarkCommand {
|
||||
|
||||
let name = "info-7z"
|
||||
let shortDescription = "7-Zip info function"
|
||||
|
||||
let inputs = CollectedParameter()
|
||||
|
||||
let benchmarkName = "7-Zip info function"
|
||||
let benchmarkFunction: (Data) throws -> Any = SevenZipContainer.info
|
||||
|
||||
}
|
||||
|
||||
class InfoTar: BenchmarkCommand {
|
||||
|
||||
let name = "info-tar"
|
||||
let shortDescription = "TAR info function"
|
||||
|
||||
let inputs = CollectedParameter()
|
||||
|
||||
let benchmarkName = "TAR info function"
|
||||
let benchmarkFunction: (Data) throws -> Any = TarContainer.info
|
||||
|
||||
}
|
||||
|
||||
class InfoZip: BenchmarkCommand {
|
||||
|
||||
let name = "info-zip"
|
||||
let shortDescription = "ZIP info function"
|
||||
|
||||
let inputs = CollectedParameter()
|
||||
|
||||
let benchmarkName = "ZIP info function"
|
||||
let benchmarkFunction: (Data) throws -> Any = ZipContainer.info
|
||||
|
||||
}
|
||||
|
||||
class UnBz2: BenchmarkCommand {
|
||||
|
||||
let name = "un-bz2"
|
||||
let shortDescription = "BZip2 unarchiving"
|
||||
|
||||
let inputs = CollectedParameter()
|
||||
|
||||
let benchmarkName = "BZip2 Unarchive"
|
||||
let benchmarkFunction: (Data) throws -> Any = BZip2.decompress
|
||||
|
||||
}
|
||||
|
||||
class UnGzip: BenchmarkCommand {
|
||||
|
||||
let name = "un-gzip"
|
||||
let shortDescription = "GZip unarchiving"
|
||||
|
||||
let inputs = CollectedParameter()
|
||||
|
||||
let benchmarkName = "GZip Unarchive"
|
||||
let benchmarkFunction: (Data) throws -> Any = GzipArchive.unarchive
|
||||
|
||||
}
|
||||
|
||||
class UnXz: BenchmarkCommand {
|
||||
|
||||
let name = "un-xz"
|
||||
let shortDescription = "XZ unarchiving"
|
||||
|
||||
let inputs = CollectedParameter()
|
||||
|
||||
let benchmarkName = "XZ Unarchive"
|
||||
let benchmarkFunction: (Data) throws -> Any = XZArchive.unarchive
|
||||
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2021 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
class CompBz2: BenchmarkCommand {
|
||||
|
||||
let name = "comp-bz2"
|
||||
let shortDescription = "BZip2 compression"
|
||||
|
||||
let files = CollectedParameter()
|
||||
|
||||
let benchmarkName = "BZip2 Compression"
|
||||
let benchmarkFunction: (Data) throws -> Any = BZip2.compress
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2021 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
class CompDeflate: BenchmarkCommand {
|
||||
|
||||
let name = "comp-deflate"
|
||||
let shortDescription = "Deflate compression"
|
||||
|
||||
let files = CollectedParameter()
|
||||
|
||||
let benchmarkName = "Deflate Compression"
|
||||
let benchmarkFunction: (Data) throws -> Any = Deflate.compress
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2021 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
class CreateTar: BenchmarkCommand {
|
||||
|
||||
let name = "create-tar"
|
||||
let shortDescription = "Tar container creation"
|
||||
|
||||
let inputs = CollectedParameter()
|
||||
|
||||
let benchmarkName = "TAR Create"
|
||||
let benchmarkFunction: ([TarEntry]) throws -> Any = TarContainer.create
|
||||
|
||||
func loadInput(_ input: String) throws -> ([TarEntry], Double) {
|
||||
return try (TarEntry.createEntries(input, false), Double(URL(fileURLWithPath: input).directorySize()))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fileprivate extension URL {
|
||||
|
||||
func directorySize() throws -> Int {
|
||||
let urls = FileManager.default.enumerator(at: self, includingPropertiesForKeys: nil)?.allObjects as! [URL]
|
||||
return try urls.lazy.reduce(0) {
|
||||
(try $1.resourceValues(forKeys: [.totalFileAllocatedSizeKey]).totalFileAllocatedSize ?? 0) + $0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2021 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
class Info7z: BenchmarkCommand {
|
||||
|
||||
let name = "info-7z"
|
||||
let shortDescription = "7-Zip info function"
|
||||
|
||||
let files = CollectedParameter()
|
||||
|
||||
let benchmarkName = "7-Zip info function"
|
||||
let benchmarkFunction: (Data) throws -> Any = SevenZipContainer.info
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2021 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
class InfoTar: BenchmarkCommand {
|
||||
|
||||
let name = "info-tar"
|
||||
let shortDescription = "TAR info function"
|
||||
|
||||
let files = CollectedParameter()
|
||||
|
||||
let benchmarkName = "TAR info function"
|
||||
let benchmarkFunction: (Data) throws -> Any = TarContainer.info
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2021 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
class InfoZip: BenchmarkCommand {
|
||||
|
||||
let name = "info-zip"
|
||||
let shortDescription = "ZIP info function"
|
||||
|
||||
let files = CollectedParameter()
|
||||
|
||||
let benchmarkName = "ZIP info function"
|
||||
let benchmarkFunction: (Data) throws -> Any = ZipContainer.info
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2021 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
|
||||
enum SpeedFormat {
|
||||
|
||||
case bytes(Double)
|
||||
case kilo(Double)
|
||||
case mega(Double)
|
||||
case giga(Double)
|
||||
case tera(Double)
|
||||
|
||||
init(_ speed: Double) {
|
||||
if speed > pow(1000, 4) {
|
||||
self = .tera(speed)
|
||||
} else if speed > pow(1000, 3) {
|
||||
self = .giga(speed)
|
||||
} else if speed > pow(1000, 2) {
|
||||
self = .mega(speed)
|
||||
} else if speed > 1000 {
|
||||
self = .kilo(speed)
|
||||
} else {
|
||||
self = .bytes(speed)
|
||||
}
|
||||
}
|
||||
|
||||
func format() -> String {
|
||||
switch self {
|
||||
case .bytes(let speed):
|
||||
return String(format: "%.3f B/s", speed)
|
||||
case .kilo(let speed):
|
||||
return String(format: "%.3f kB/s", speed / 1000)
|
||||
case .mega(let speed):
|
||||
return String(format: "%.3f MB/s", speed / 1000 / 1000)
|
||||
case .giga(let speed):
|
||||
return String(format: "%.3f GB/s", speed / 1000 / 1000 / 1000)
|
||||
case .tera(let speed):
|
||||
return String(format: "%.3f TB/s", speed / 1000 / 1000 / 1000 / 1000)
|
||||
}
|
||||
}
|
||||
|
||||
func format(_ speed: Double) -> String {
|
||||
switch self {
|
||||
case .bytes(_):
|
||||
return String(format: "%.3f B/s", speed)
|
||||
case .kilo(_):
|
||||
return String(format: "%.3f kB/s", speed / 1000)
|
||||
case .mega(_):
|
||||
return String(format: "%.3f MB/s", speed / 1000 / 1000)
|
||||
case .giga(_):
|
||||
return String(format: "%.3f GB/s", speed / 1000 / 1000 / 1000)
|
||||
case .tera(_):
|
||||
return String(format: "%.3f TB/s", speed / 1000 / 1000 / 1000 / 1000)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2021 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
class UnBz2: BenchmarkCommand {
|
||||
|
||||
let name = "un-bz2"
|
||||
let shortDescription = "BZip2 unarchiving"
|
||||
|
||||
let files = CollectedParameter()
|
||||
|
||||
let benchmarkName = "BZip2 Unarchive"
|
||||
let benchmarkFunction: (Data) throws -> Any = BZip2.decompress
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2021 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
class UnGzip: BenchmarkCommand {
|
||||
|
||||
let name = "un-gzip"
|
||||
let shortDescription = "GZip unarchiving"
|
||||
|
||||
let files = CollectedParameter()
|
||||
|
||||
let benchmarkName = "GZip Unarchive"
|
||||
let benchmarkFunction: (Data) throws -> Any = GzipArchive.unarchive
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2021 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
class UnXz: BenchmarkCommand {
|
||||
|
||||
let name = "un-xz"
|
||||
let shortDescription = "XZ unarchiving"
|
||||
|
||||
let files = CollectedParameter()
|
||||
|
||||
let benchmarkName = "XZ Unarchive"
|
||||
let benchmarkFunction: (Data) throws -> Any = XZArchive.unarchive
|
||||
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import SwiftCLI
|
||||
|
||||
class SevenZipCommand: ContainerCommand {
|
||||
|
||||
typealias ContainerType = SevenZipContainer
|
||||
|
||||
let name = "7z"
|
||||
let shortDescription = "Extracts a 7-Zip container"
|
||||
|
||||
@@ -18,7 +20,4 @@ class SevenZipCommand: ContainerCommand {
|
||||
|
||||
let archive = Parameter()
|
||||
|
||||
let openFunction: (Data) throws -> [SevenZipEntry] = SevenZipContainer.open
|
||||
let infoFunction: (Data) throws -> [SevenZipEntryInfo] = SevenZipContainer.info
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import SwiftCLI
|
||||
|
||||
protocol ContainerCommand: Command {
|
||||
|
||||
associatedtype Entry: ContainerEntry
|
||||
associatedtype ContainerType: Container
|
||||
|
||||
var info: Flag { get }
|
||||
var extract: Key<String> { get }
|
||||
@@ -17,9 +17,6 @@ protocol ContainerCommand: Command {
|
||||
|
||||
var archive: Parameter { get }
|
||||
|
||||
var openFunction: (Data) throws -> [Entry] { get }
|
||||
var infoFunction: (Data) throws -> [Entry.Info] { get }
|
||||
|
||||
}
|
||||
|
||||
extension ContainerCommand {
|
||||
@@ -33,7 +30,7 @@ extension ContainerCommand {
|
||||
let fileData = try Data(contentsOf: URL(fileURLWithPath: self.archive.value),
|
||||
options: .mappedIfSafe)
|
||||
if info.value {
|
||||
let entries = try infoFunction(fileData)
|
||||
let entries = try ContainerType.info(container: fileData)
|
||||
swcomp.printInfo(entries)
|
||||
} else if let outputPath = self.extract.value {
|
||||
if try !isValidOutputDirectory(outputPath, create: true) {
|
||||
@@ -41,7 +38,7 @@ extension ContainerCommand {
|
||||
exit(1)
|
||||
}
|
||||
|
||||
let entries = try openFunction(fileData)
|
||||
let entries = try ContainerType.open(container: fileData)
|
||||
try swcomp.write(entries, outputPath, verbose.value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,94 +92,10 @@ class TarCommand: Command {
|
||||
print("Creating new container at \"\(self.archive.value)\" from \"\(inputPath)\"")
|
||||
print("d = directory, f = file, l = symbolic link")
|
||||
}
|
||||
let entries = try self.createEntries(inputPath, verbose.value)
|
||||
let entries = try TarEntry.createEntries(inputPath, verbose.value)
|
||||
let containerData = TarContainer.create(from: entries)
|
||||
try containerData.write(to: URL(fileURLWithPath: self.archive.value))
|
||||
}
|
||||
}
|
||||
|
||||
private func createEntries(_ inputPath: String, _ verbose: Bool) throws -> [TarEntry] {
|
||||
let inputURL = URL(fileURLWithPath: inputPath)
|
||||
let fileManager = FileManager.default
|
||||
|
||||
let fileAttributes = try fileManager.attributesOfItem(atPath: inputPath)
|
||||
|
||||
let name = inputURL.relativePath
|
||||
|
||||
let entryType: ContainerEntryType
|
||||
if let typeFromAttributes = fileAttributes[.type] as? FileAttributeType {
|
||||
switch typeFromAttributes {
|
||||
case .typeBlockSpecial:
|
||||
entryType = .blockSpecial
|
||||
case .typeCharacterSpecial:
|
||||
entryType = .characterSpecial
|
||||
case .typeDirectory:
|
||||
entryType = .directory
|
||||
case .typeRegular:
|
||||
entryType = .regular
|
||||
case .typeSocket:
|
||||
entryType = .socket
|
||||
case .typeSymbolicLink:
|
||||
entryType = .symbolicLink
|
||||
case .typeUnknown:
|
||||
entryType = .unknown
|
||||
default:
|
||||
entryType = .unknown
|
||||
}
|
||||
} else {
|
||||
entryType = .unknown
|
||||
}
|
||||
|
||||
var info = TarEntryInfo(name: name, type: entryType)
|
||||
info.creationTime = fileAttributes[.creationDate] as? Date
|
||||
info.groupID = (fileAttributes[.groupOwnerAccountID] as? NSNumber)?.intValue
|
||||
info.ownerGroupName = fileAttributes[.groupOwnerAccountName] as? String
|
||||
info.modificationTime = fileAttributes[.modificationDate] as? Date
|
||||
info.ownerID = (fileAttributes[.ownerAccountID] as? NSNumber)?.intValue
|
||||
info.ownerUserName = fileAttributes[.ownerAccountName] as? String
|
||||
if let posixPermissions = (fileAttributes[.posixPermissions] as? NSNumber)?.intValue {
|
||||
info.permissions = Permissions(rawValue: UInt32(truncatingIfNeeded: posixPermissions))
|
||||
}
|
||||
|
||||
var entryData = Data()
|
||||
if entryType == .symbolicLink {
|
||||
info.linkName = try fileManager.destinationOfSymbolicLink(atPath: inputPath)
|
||||
} else if entryType != .directory {
|
||||
entryData = try Data(contentsOf: URL(fileURLWithPath: inputPath))
|
||||
}
|
||||
|
||||
if verbose {
|
||||
var log = ""
|
||||
switch entryType {
|
||||
case .regular:
|
||||
log += "f: "
|
||||
case .directory:
|
||||
log += "d: "
|
||||
case .symbolicLink:
|
||||
log += "l:"
|
||||
default:
|
||||
log += "u: "
|
||||
}
|
||||
log += name
|
||||
if entryType == .symbolicLink {
|
||||
log += " -> " + info.linkName
|
||||
}
|
||||
print(log)
|
||||
}
|
||||
|
||||
let entry = TarEntry(info: info, data: entryData)
|
||||
|
||||
var entries = [TarEntry]()
|
||||
entries.append(entry)
|
||||
|
||||
if entryType == .directory {
|
||||
for subPath in try fileManager.contentsOfDirectory(atPath: inputPath) {
|
||||
entries.append(contentsOf: try self.createEntries(inputURL.appendingPathComponent(subPath).relativePath,
|
||||
verbose))
|
||||
}
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import SwiftCLI
|
||||
|
||||
class ZipCommand: ContainerCommand {
|
||||
|
||||
typealias ContainerType = ZipContainer
|
||||
|
||||
let name = "zip"
|
||||
let shortDescription = "Extracts a ZIP container"
|
||||
|
||||
@@ -18,7 +20,4 @@ class ZipCommand: ContainerCommand {
|
||||
|
||||
let archive = Parameter()
|
||||
|
||||
let openFunction: (Data) throws -> [ZipEntry] = ZipContainer.open
|
||||
let infoFunction: (Data) throws -> [ZipEntryInfo] = ZipContainer.info
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2021 Timofey Solomko
|
||||
// Licensed under MIT License
|
||||
//
|
||||
// See LICENSE for license information
|
||||
|
||||
import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
extension TarEntry {
|
||||
|
||||
static func createEntries(_ inputPath: String, _ verbose: Bool) throws -> [TarEntry] {
|
||||
let inputURL = URL(fileURLWithPath: inputPath)
|
||||
let fileManager = FileManager.default
|
||||
|
||||
let fileAttributes = try fileManager.attributesOfItem(atPath: inputPath)
|
||||
|
||||
let name = inputURL.relativePath
|
||||
|
||||
let entryType: ContainerEntryType
|
||||
if let typeFromAttributes = fileAttributes[.type] as? FileAttributeType {
|
||||
switch typeFromAttributes {
|
||||
case .typeBlockSpecial:
|
||||
entryType = .blockSpecial
|
||||
case .typeCharacterSpecial:
|
||||
entryType = .characterSpecial
|
||||
case .typeDirectory:
|
||||
entryType = .directory
|
||||
case .typeRegular:
|
||||
entryType = .regular
|
||||
case .typeSocket:
|
||||
entryType = .socket
|
||||
case .typeSymbolicLink:
|
||||
entryType = .symbolicLink
|
||||
case .typeUnknown:
|
||||
entryType = .unknown
|
||||
default:
|
||||
entryType = .unknown
|
||||
}
|
||||
} else {
|
||||
entryType = .unknown
|
||||
}
|
||||
|
||||
var info = TarEntryInfo(name: name, type: entryType)
|
||||
info.creationTime = fileAttributes[.creationDate] as? Date
|
||||
info.groupID = (fileAttributes[.groupOwnerAccountID] as? NSNumber)?.intValue
|
||||
info.ownerGroupName = fileAttributes[.groupOwnerAccountName] as? String
|
||||
info.modificationTime = fileAttributes[.modificationDate] as? Date
|
||||
info.ownerID = (fileAttributes[.ownerAccountID] as? NSNumber)?.intValue
|
||||
info.ownerUserName = fileAttributes[.ownerAccountName] as? String
|
||||
if let posixPermissions = (fileAttributes[.posixPermissions] as? NSNumber)?.intValue {
|
||||
info.permissions = Permissions(rawValue: UInt32(truncatingIfNeeded: posixPermissions))
|
||||
}
|
||||
|
||||
var entryData = Data()
|
||||
if entryType == .symbolicLink {
|
||||
info.linkName = try fileManager.destinationOfSymbolicLink(atPath: inputPath)
|
||||
} else if entryType != .directory {
|
||||
entryData = try Data(contentsOf: URL(fileURLWithPath: inputPath))
|
||||
}
|
||||
|
||||
if verbose {
|
||||
var log = ""
|
||||
switch entryType {
|
||||
case .regular:
|
||||
log += "f: "
|
||||
case .directory:
|
||||
log += "d: "
|
||||
case .symbolicLink:
|
||||
log += "l:"
|
||||
default:
|
||||
log += "u: "
|
||||
}
|
||||
log += name
|
||||
if entryType == .symbolicLink {
|
||||
log += " -> " + info.linkName
|
||||
}
|
||||
print(log)
|
||||
}
|
||||
|
||||
let entry = TarEntry(info: info, data: entryData)
|
||||
|
||||
var entries = [TarEntry]()
|
||||
entries.append(entry)
|
||||
|
||||
if entryType == .directory {
|
||||
for subPath in try fileManager.contentsOfDirectory(atPath: inputPath) {
|
||||
entries.append(contentsOf: try self.createEntries(inputURL.appendingPathComponent(subPath).relativePath,
|
||||
verbose))
|
||||
}
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import Foundation
|
||||
import SWCompression
|
||||
import SwiftCLI
|
||||
|
||||
let cli = CLI(name: "swcomp", version: "4.6.0",
|
||||
let cli = CLI(name: "swcomp", version: "4.6.1",
|
||||
description: """
|
||||
swcomp - a small command-line client for SWCompression framework.
|
||||
Serves as an example of SWCompression usage.
|
||||
|
||||
@@ -67,4 +67,8 @@ class BZip2Tests: XCTestCase {
|
||||
XCTAssertThrowsError(try BZip2.decompress(data: testData))
|
||||
}
|
||||
|
||||
func testEmptyData() throws {
|
||||
XCTAssertThrowsError(try BZip2.decompress(data: Data()))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -151,4 +151,8 @@ class GzipTests: XCTestCase {
|
||||
XCTAssertThrowsError(try GzipArchive.multiUnarchive(archive: testData))
|
||||
}
|
||||
|
||||
func testEmptyData() throws {
|
||||
XCTAssertThrowsError(try GzipArchive.unarchive(archive: Data()))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,5 +51,9 @@ class LzmaTests: XCTestCase {
|
||||
XCTAssertThrowsError(try LZMA.decompress(data: testData))
|
||||
}
|
||||
|
||||
func testEmptyData() throws {
|
||||
XCTAssertThrowsError(try LZMA.decompress(data: Data()))
|
||||
XCTAssertThrowsError(try LZMA2.decompress(data: Data()))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+64
-54
@@ -1,18 +1,24 @@
|
||||
# Test Results
|
||||
|
||||
In this document you can find the results of benchmarking which was performed on Macbook Pro, Late 2011. The main
|
||||
purpose of these results is to track progress from version to version.
|
||||
In this document you can find the results of benchmarking which was performed on Macbook Air, Retina, 13-inch, Early
|
||||
2020 with 1,1 GHz Quad-Core Intel Core i5 CPU. The main purpose of these results is to track progress from version to
|
||||
version.
|
||||
|
||||
__Note:__ Since 4.1.0 version of SWCompression internal functionality related to reading/writing bits and bytes
|
||||
is published as a separate framework, [BitByteData](https://github.com/tsolomko/BitByteData).
|
||||
The overall performance heavily depends on the speed of reading and writing, and thus BitByteData's version, which is
|
||||
specified in a separate column in the tables below, becomes relevant to benchmarking, since newer versions can contain
|
||||
performance improvements.
|
||||
## Changelog
|
||||
|
||||
__Note:__ Since 4.3.0 version of SWCompression the first (zeroth, actually) iteration is excluded from averages
|
||||
calculation since this iteration has abnormally longer execution time than any of the following iterations. This
|
||||
exclusion led not only to (artificially) improved results, but also to the increased quality of the results by reducing
|
||||
calculated uncertainty.
|
||||
__September 2021.__ The results are now listed in terms of speed (e.g. MB/s); the benchmarks for Deflate, BZip2 compression and
|
||||
TAR container creation have been added; all previous results have been removed since newer hardware is now used; added
|
||||
results for the `-Ounchecked` compiler option; the macOS version is now listed for results.
|
||||
|
||||
__April 2018.__ The first (zeroth, actually) iteration is now excluded from averages calculation since this iteration
|
||||
has abnormally longer execution time than any of the following iterations. This exclusion led not only to (artificially)
|
||||
improved results, but also to the increased quality of the results by reducing calculated uncertainty. In addition, the
|
||||
averages are now computed over 10 iterations instead of 6.
|
||||
|
||||
__January 2018.__ SWCompression internal functionality related to reading/writing bits and bytes is published as a
|
||||
separate framework, [BitByteData](https://github.com/tsolomko/BitByteData). The overall performance heavily depends on
|
||||
the speed of reading and writing, and thus BitByteData's version, which is specified in a separate column in the tables
|
||||
below, becomes relevant to benchmarking, since newer versions can contain performance improvements.
|
||||
|
||||
## Tests description
|
||||
|
||||
@@ -29,64 +35,68 @@ using "Release" configuration.
|
||||
|
||||
__Note:__ External commands used to create compressed files were run using their default sets of options.
|
||||
|
||||
__Note:__ All results are averages over 10 iterations (6 iterations until 4.3.0 version).
|
||||
__Note:__ All results are averages over 10 iterations. If the uncertainty is not listed it means that it is less than
|
||||
10% in terms of the units listed.
|
||||
|
||||
## BZip2 Decompress
|
||||
|
||||
|SWCompression<br>version|BitByteData<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|---|---|---|
|
||||
|4.0.0|—|4.0.X|6.821 ± 0.042|54.214 ± 1.398|7.255 ± 0.117|
|
||||
|4.0.1|—|4.0.X|6.797 ± 0.080|54.046 ± 1.070|7.177 ± 0.029|
|
||||
|4.1.0|1.0.1|4.0.X|4.452 ± 0.125|36.768 ± 0.382|4.880 ± 0.094|
|
||||
|4.3.0|1.2.0|4.1.0|3.481 ± 0.038|27.187 ± 0.152|3.914 ± 0.091|
|
||||
|4.4.0|1.2.0|4.1.2|3.548 ± 0.037|27.950 ± 0.975|3.956 ± 0.063|
|
||||
|SWCompression<br>version|BitByteData<br>version|macOS<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|:---:|---|---|---|
|
||||
|4.6.0|2.0.1|11.5.2|5.4.2|2.764 MB/s|2.973 MB/s|2.410 MB/s|
|
||||
|4.6.0-unchecked|2.0.1|11.5.2|5.4.2|3.279 ± 0.429 MB/s|4.361 ± 0.306 MB/s|3.169 ± 0.180 MB/s|
|
||||
|
||||
## XZ Unarchive (LZMA/LZMA2 Decompress)
|
||||
|
||||
|SWCompression<br>version|BitByteData<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|---|---|---|
|
||||
|4.0.0|—|4.0.X|error|24.663 ± 2.349|2.904 ± 0.076|
|
||||
|4.0.1|—|4.0.X|2.475 ± 0.067|23.507 ± 0.423|2.901 ± 0.049|
|
||||
|4.1.0|1.0.1|4.0.X|2.480 ± 0.091|24.126 ± 1.239|2.892 ± 0.052|
|
||||
|4.3.0|1.2.0|4.1.0|2.664 ± 0.031|26.030 ± 1.200|3.111 ± 0.053|
|
||||
|4.4.0|1.2.0|4.1.2|2.494 ± 0.038|23.773 ± 0.563|2.912 ± 0.018|
|
||||
|SWCompression<br>version|BitByteData<br>version|macOS<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|:---:|---|---|---|
|
||||
|4.6.0|2.0.1|11.5.2|5.4.2|5.246 ± 0.279 MB/s|5.543 ± 0.143 MB/s|5.322 ± 0.26 MB/s|
|
||||
|4.6.0-unchecked|2.0.1|11.5.2|5.4.2|6.015 ± 0.319 MB/s|6.374 ± 0.143 MB/s|5.841 ± 0.212 MB/s|
|
||||
|
||||
## GZip Unarchive (Deflate Decompress)
|
||||
|
||||
|SWCompression<br>version|BitByteData<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|---|---|---|
|
||||
|4.0.0|—|4.0.X|4.007 ± 0.196|32.043 ± 0.581|4.303 ± 0.045|
|
||||
|4.0.1|—|4.0.X|3.886 ± 0.100|32.390 ± 0.896|4.295 ± 0.040|
|
||||
|4.1.0|1.0.1|4.0.X|2.886 ± 0.571|22.134 ± 1.473|2.700 ± 0.168|
|
||||
|4.3.0|1.2.0|4.1.0|1.622 ± 0.016|13.641 ± 0.069|1.804 ± 0.028|
|
||||
|4.4.0|1.2.0|4.1.2|1.665 ± 0.037|14.046 ± 0.093|1.858 ± 0.055|
|
||||
|SWCompression<br>version|BitByteData<br>version|macOS<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|:---:|---|---|---|
|
||||
|4.6.0|2.0.1|11.5.2|5.4.2|5.946 ± 0.432 MB/s|6.034 ± 0.175 MB/s|6.071 ± 0.25 MB/s|
|
||||
|4.6.0-unchecked|2.0.1|11.5.2|5.4.2|8.562 ± 0.388 MB/s|9.908 ± 0.204 MB/s|8.286 ± 0.250 MB/s|
|
||||
|
||||
## BZip2 Compress
|
||||
|
||||
|SWCompression<br>version|BitByteData<br>version|macOS<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|:---:|---|---|---|
|
||||
|4.6.0|2.0.1|11.5.2|5.4.2|3.540 MB/s|2.862 MB/s|4.253 MB/s|
|
||||
|4.6.0-unchecked|2.0.1|11.5.2|5.4.2|3.816 MB/s|3.060 MB/s|4.647 MB/s|
|
||||
|
||||
## Deflate Compress
|
||||
|
||||
|SWCompression<br>version|BitByteData<br>version|macOS<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|:---:|---|---|---|
|
||||
|4.6.0|2.0.1|11.5.2|5.4.2|12.177 ± 0.259 MB/s|8.809 MB/s|13.594 ± 0.355 MB/s|
|
||||
|4.6.0-unchecked|2.0.1|11.5.2|5.4.2|12.914 ± 0.355 MB/s|9.361 MB/s|15.020 ± 0.277 MB/s|
|
||||
|
||||
## 7-Zip Info Function
|
||||
|
||||
|SWCompression<br>version|BitByteData<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|---|---|---|
|
||||
|4.0.0|—|4.0.X|0.270 ± 0.010|crash|0.601 ± 0.057|
|
||||
|4.0.1|—|4.0.X|0.258 ± 0.003|0.601 ± 0.010|0.473 ± 0.008|
|
||||
|4.1.0|1.0.1|4.0.X|0.062 ± 0.008|0.208 ± 0.010|0.122 ± 0.003|
|
||||
|4.3.0|1.2.0|4.1.0|0.060 ± 0.006|0.208 ± 0.008|0.123 ± 0.008|
|
||||
|4.4.0|1.2.0|4.1.2|0.062 ± 0.005|0.212 ± 0.008|0.122 ± 0.007|
|
||||
|SWCompression<br>version|BitByteData<br>version|macOS<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|:---:|---|---|---|
|
||||
|4.6.0|2.0.1|11.5.2|5.4.2|77.072 ± 6.625 MB/s|111.246 ± 4.855 MB/s|38.721 ± 2.681 MB/s|
|
||||
|4.6.0-unchecked|2.0.1|11.5.2|5.4.2|82.367 ± 7.381 MB/s|116.923 ± 3.812 MB/s|38.519 ± 2.988 MB/s|
|
||||
|
||||
## TAR Info Function
|
||||
|
||||
|SWCompression<br>version|BitByteData<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|---|---|---|
|
||||
|4.0.0|—|4.0.X|0.248 ± 0.172|1.563 ± 0.442|1.254 ± 0.277|
|
||||
|4.0.1|—|4.0.X|0.187 ± 0.177|1.257 ± 0.404|1.016 ± 0.325|
|
||||
|4.1.0|1.0.1|4.0.X|0.194 ± 0.190|1.335 ± 0.475|1.062 ± 0.353|
|
||||
|4.3.0|1.2.0|4.1.0|0.111 ± 0.008|1.014 ± 0.016|0.813 ± 0.015|
|
||||
|4.4.0|1.2.0|4.1.2|0.095 ± 0.005|0.810 ± 0.025|0.680 ± 0.014|
|
||||
|SWCompression<br>version|BitByteData<br>version|macOS<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|:---:|---|---|---|
|
||||
|4.6.0|2.0.1|11.5.2|5.4.2|967.792 ± 58.436 MB/s|1.006 GB/s|217.082 ± 19.783 MB/s|
|
||||
|4.6.0-unchecked|2.0.1|11.5.2|5.4.2|1.073 ± 0.115 GB/s|1.053 GB/s|246.854 ± 6.763 MB/s|
|
||||
|
||||
## ZIP Info Function
|
||||
|
||||
|SWCompression<br>version|BitByteData<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|---|---|---|
|
||||
|4.0.0|—|4.0.X|0.072 ± 0.065|0.669 ± 0.147|0.120 ± 0.081|
|
||||
|4.0.1|—|4.0.X|0.076 ± 0.064|0.670 ± 0.142|0.123 ± 0.080|
|
||||
|4.1.0|1.0.1|4.0.X|0.063 ± 0.076|0.148 ± 0.107|0.105 ± 0.089|
|
||||
|4.3.0|1.2.0|4.1.0|0.044 ± 0.007|0.122 ± 0.009|0.086 ± 0.008|
|
||||
|4.4.0|1.2.0|4.1.2|0.048 ± 0.005|0.125 ± 0.005|0.091 ± 0.010|
|
||||
|SWCompression<br>version|BitByteData<br>version|macOS<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|:---:|---|---|---|
|
||||
|4.6.0|2.0.1|11.5.2|5.4.2|597.002 ± 75.017 MB/s|1.941 ± 0.135 GB/s|389.626 ± 22.006 MB/s|
|
||||
|4.6.0-unchecked|2.0.1|11.5.2|5.4.2|685.266 ± 53.895 MB/s|2.147 GB/s|420.461 ± 15.156 MB/s|
|
||||
|
||||
## TAR Create Function
|
||||
|
||||
|SWCompression<br>version|BitByteData<br>version|macOS<br>version|Swift<br>version|Test 1|Test 2|Test 3|
|
||||
|:---:|:---:|:---:|:---:|---|---|---|
|
||||
|4.6.0|2.0.1|11.5.2|5.4.2|139.649 ± 8.310 MB/s|446.101 ± 21.476 MB/s|215.556 ± 17.5 MB/s|
|
||||
|4.6.0-unchecked|2.0.1|11.5.2|5.4.2|142.681 ± 5.664 MB/s|459.403 ± 17.862 MB/s|220.238 ± 3.476 MB/s|
|
||||
|
||||
@@ -19,6 +19,11 @@ class SevenZipTests: XCTestCase {
|
||||
XCTAssertThrowsError(try SevenZipContainer.open(container: testData))
|
||||
}
|
||||
|
||||
func testEmptyData() throws {
|
||||
XCTAssertThrowsError(try SevenZipContainer.info(container: Data()))
|
||||
XCTAssertThrowsError(try SevenZipContainer.open(container: Data()))
|
||||
}
|
||||
|
||||
func test1() throws {
|
||||
let testData = try Constants.data(forTest: "test1", withType: SevenZipTests.testType)
|
||||
let entries = try SevenZipContainer.open(container: testData)
|
||||
@@ -388,4 +393,65 @@ class SevenZipTests: XCTestCase {
|
||||
XCTAssertEqual(entries[0].data, answerData)
|
||||
}
|
||||
|
||||
func testFormatMinorVersions() throws {
|
||||
let answerData = try Constants.data(forAnswer: "test2")
|
||||
|
||||
var testData = try Constants.data(forTest: "test_minor_version_2", withType: SevenZipTests.testType)
|
||||
var entries = try SevenZipContainer.open(container: testData)
|
||||
|
||||
XCTAssertEqual(entries.count, 1)
|
||||
XCTAssertEqual(entries[0].info.name, "test2.answer")
|
||||
XCTAssertEqual(entries[0].info.type, .regular)
|
||||
XCTAssertEqual(entries[0].info.size, answerData.count)
|
||||
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 0))
|
||||
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
|
||||
// Checking times' values is a bit difficult since they are extremely precise.
|
||||
XCTAssertNotNil(entries[0].info.modificationTime)
|
||||
XCTAssertNil(entries[0].info.accessTime)
|
||||
XCTAssertNil(entries[0].info.creationTime)
|
||||
XCTAssertEqual(entries[0].info.hasStream, true)
|
||||
XCTAssertEqual(entries[0].info.isEmpty, false)
|
||||
XCTAssertEqual(entries[0].info.isAnti, false)
|
||||
XCTAssertEqual(entries[0].info.crc, 4168830779)
|
||||
XCTAssertEqual(entries[0].data, answerData)
|
||||
|
||||
testData = try Constants.data(forTest: "test_minor_version_3", withType: SevenZipTests.testType)
|
||||
entries = try SevenZipContainer.open(container: testData)
|
||||
|
||||
XCTAssertEqual(entries.count, 1)
|
||||
XCTAssertEqual(entries[0].info.name, "test2.answer")
|
||||
XCTAssertEqual(entries[0].info.type, .regular)
|
||||
XCTAssertEqual(entries[0].info.size, answerData.count)
|
||||
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
|
||||
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
|
||||
// Checking times' values is a bit difficult since they are extremely precise.
|
||||
XCTAssertNotNil(entries[0].info.modificationTime)
|
||||
XCTAssertNotNil(entries[0].info.accessTime)
|
||||
XCTAssertNotNil(entries[0].info.creationTime)
|
||||
XCTAssertEqual(entries[0].info.hasStream, true)
|
||||
XCTAssertEqual(entries[0].info.isEmpty, false)
|
||||
XCTAssertEqual(entries[0].info.isAnti, false)
|
||||
XCTAssertEqual(entries[0].info.crc, 4168830779)
|
||||
XCTAssertEqual(entries[0].data, answerData)
|
||||
|
||||
testData = try Constants.data(forTest: "test_minor_version_4", withType: SevenZipTests.testType)
|
||||
entries = try SevenZipContainer.open(container: testData)
|
||||
|
||||
XCTAssertEqual(entries.count, 1)
|
||||
XCTAssertEqual(entries[0].info.name, "test2.answer")
|
||||
XCTAssertEqual(entries[0].info.type, .regular)
|
||||
XCTAssertEqual(entries[0].info.size, answerData.count)
|
||||
XCTAssertEqual(entries[0].info.permissions, Permissions(rawValue: 420))
|
||||
XCTAssertEqual(entries[0].info.dosAttributes, DosAttributes(rawValue: 0x20))
|
||||
// Checking times' values is a bit difficult since they are extremely precise.
|
||||
XCTAssertNotNil(entries[0].info.modificationTime)
|
||||
XCTAssertNotNil(entries[0].info.accessTime)
|
||||
XCTAssertNotNil(entries[0].info.creationTime)
|
||||
XCTAssertEqual(entries[0].info.hasStream, true)
|
||||
XCTAssertEqual(entries[0].info.isEmpty, false)
|
||||
XCTAssertEqual(entries[0].info.isAnti, false)
|
||||
XCTAssertEqual(entries[0].info.crc, 4168830779)
|
||||
XCTAssertEqual(entries[0].data, answerData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
Submodule Tests/Test Files updated: fe35c32fda...36e6d8fa8e
@@ -18,6 +18,11 @@ class ZipTests: XCTestCase {
|
||||
let testData = try Constants.data(forAnswer: "test6")
|
||||
XCTAssertThrowsError(try ZipContainer.open(container: testData))
|
||||
}
|
||||
|
||||
func testEmptyData() throws {
|
||||
XCTAssertThrowsError(try ZipContainer.info(container: Data()))
|
||||
XCTAssertThrowsError(try ZipContainer.open(container: Data()))
|
||||
}
|
||||
|
||||
func testBigContainer() throws {
|
||||
let testData = try Constants.data(forTest: "SWCompressionSourceCode", withType: ZipTests.testType)
|
||||
|
||||
@@ -52,4 +52,8 @@ class ZlibTests: XCTestCase {
|
||||
XCTAssertThrowsError(try ZlibArchive.unarchive(archive: testData))
|
||||
}
|
||||
|
||||
func testEmptyData() throws {
|
||||
XCTAssertThrowsError(try ZlibArchive.unarchive(archive: Data()))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-8
@@ -37,12 +37,18 @@ stages:
|
||||
WATCHOS_ACTIONS: 'clean build'
|
||||
WATCHOS_SIMULATOR: 'Apple Watch Series 4 - 44mm'
|
||||
UTILS_PW_XCF_FLAG: '--xcf'
|
||||
# macosSwift54:
|
||||
# imageName: 'macOS-11.3'
|
||||
# DEVELOPER_DIR: '/Applications/Xcode_12.5.app'
|
||||
# WATCHOS_ACTIONS: 'clean test'
|
||||
# WATCHOS_SIMULATOR: 'Apple Watch Series 6 - 44mm'
|
||||
# UTILS_PW_XCF_FLAG: '--xcf'
|
||||
macosSwift54:
|
||||
imageName: 'macOS-11'
|
||||
DEVELOPER_DIR: '/Applications/Xcode_12.5.1.app'
|
||||
WATCHOS_ACTIONS: 'clean test'
|
||||
WATCHOS_SIMULATOR: 'Apple Watch Series 6 - 44mm'
|
||||
UTILS_PW_XCF_FLAG: '--xcf'
|
||||
macosSwift55:
|
||||
imageName: 'macOS-11'
|
||||
DEVELOPER_DIR: '/Applications/Xcode_13.0.app'
|
||||
WATCHOS_ACTIONS: 'clean test'
|
||||
WATCHOS_SIMULATOR: 'Apple Watch Series 6 - 44mm'
|
||||
UTILS_PW_XCF_FLAG: '--xcf'
|
||||
pool:
|
||||
vmImage: $(imageName)
|
||||
steps:
|
||||
@@ -74,7 +80,10 @@ stages:
|
||||
containerImage: 'swift:5.3.3-bionic'
|
||||
linuxSwift54:
|
||||
imageName: 'ubuntu-18.04'
|
||||
containerImage: 'swift:5.4.2-bionic'
|
||||
containerImage: 'swift:5.4.3-bionic'
|
||||
linuxSwift55:
|
||||
imageName: 'ubuntu-18.04'
|
||||
containerImage: 'swift:5.5-bionic'
|
||||
pool:
|
||||
vmImage: $(imageName)
|
||||
container: $[ variables['containerImage'] ]
|
||||
@@ -90,7 +99,10 @@ stages:
|
||||
matrix:
|
||||
windowsSwift54:
|
||||
imageName: 'windows-2019'
|
||||
SWIFT_VERSION: '5.4.2'
|
||||
SWIFT_VERSION: '5.4.3'
|
||||
windowsSwift55:
|
||||
imageName: 'windows-2019'
|
||||
SWIFT_VERSION: '5.5'
|
||||
pool:
|
||||
vmImage: $(imageName)
|
||||
variables:
|
||||
|
||||
Reference in New Issue
Block a user