Skip to content

Commit

Permalink
127
Browse files Browse the repository at this point in the history
  • Loading branch information
stephencelis committed Nov 30, 2020
1 parent b28c84f commit 4e7b7d1
Show file tree
Hide file tree
Showing 15 changed files with 293 additions and 0 deletions.
5 changes: 5 additions & 0 deletions 0127-parsing-performance-pt1/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
5 changes: 5 additions & 0 deletions 0127-parsing-performance-pt1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## [Point-Free](https://www.pointfree.co)

> #### This directory contains code from Point-Free Episode: [Parsing Performance: Strings](https://www.pointfree.co/episodes/ep127-parsing-performance-strings)
>
> We want to explore the performance of composable parsers, but to do so we must first take a deep dive into the Swift string API. There are multiple abstractions of strings in Swift, each with its own benefits and performance characteristics. We will benchmark them in order to get a scientific basis for comparison, and will describe how to properly write a benchmark.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

let bigString = String.init(repeating: "A", count: 1_000_000)

var copy = bigString
copy.removeFirst()

var anotherCopy = bigString
anotherCopy.removeFirst()

let truncatedBigString = bigString.dropFirst() as Substring

bigString.index(after: bigString.startIndex) == truncatedBigString.startIndex

var copy1 = truncatedBigString.dropFirst(100)
var copy2 = truncatedBigString.dropFirst(1_000)
var copy3 = truncatedBigString.dropFirst(10_000)

let acuteE1 = "é"
let acuteE2 = ""
acuteE1 == acuteE2
acuteE1.count
acuteE2.count

acuteE1.unicodeScalars.count
acuteE2.unicodeScalars.count

Array(acuteE1.unicodeScalars)
Array(acuteE2.unicodeScalars)

acuteE1.unicodeScalars.elementsEqual(acuteE2.unicodeScalars)

"🇺"
"🇸"
"🇺" + "🇸"
"\u{1F1FA}\u{1F1F8}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='macos' buildActiveScheme='true'>
<timeline fileName='timeline.xctimeline'/>
</playground>
5 changes: 5 additions & 0 deletions 0127-parsing-performance-pt1/string-performance/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1230"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "string-performance"
BuildableName = "string-performance"
BlueprintName = "string-performance"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "string-performanceTests"
BuildableName = "string-performanceTests"
BlueprintName = "string-performanceTests"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "string-performanceTests"
BuildableName = "string-performanceTests"
BlueprintName = "string-performanceTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "string-performance"
BuildableName = "string-performance"
BlueprintName = "string-performance"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "--allow-debug-build"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "string-performance"
BuildableName = "string-performance"
BlueprintName = "string-performance"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
23 changes: 23 additions & 0 deletions 0127-parsing-performance-pt1/string-performance/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "string-performance",
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(name: "Benchmark", url: "https://github.com/google/swift-benchmark", .branch("master"))
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "string-performance",
dependencies: [.product(name: "Benchmark", package: "Benchmark")]),
.testTarget(
name: "string-performanceTests",
dependencies: ["string-performance"]),
]
)
3 changes: 3 additions & 0 deletions 0127-parsing-performance-pt1/string-performance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# string-performance

A description of this package.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Benchmark

let copyingSuite = BenchmarkSuite(name: "Copying") { suite in
let string = String.init(repeating: "A", count: 1_000_000)

suite.benchmark("String") {
var copy = string
copy.removeFirst()
var copy1 = copy
copy1.removeFirst()
var copy2 = copy1
copy2.removeFirst()
var copy3 = copy2
copy3.removeFirst()
}

suite.benchmark("Substring") {
var copy = string[...]
copy.removeFirst()
var copy1 = copy
copy1.removeFirst()
var copy2 = copy1
copy2.removeFirst()
var copy3 = copy2
copy3.removeFirst()
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Benchmark

Benchmark.main([
copyingSuite,
])

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import XCTest

import string_performanceTests

var tests = [XCTestCaseEntry]()
tests += string_performanceTests.allTests()
XCTMain(tests)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import XCTest

#if !canImport(ObjectiveC)
public func allTests() -> [XCTestCaseEntry] {
return [
testCase(string_performanceTests.allTests),
]
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import XCTest
import class Foundation.Bundle

final class string_performanceTests: XCTestCase {
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.

// Some of the APIs that we use below are available in macOS 10.13 and above.
guard #available(macOS 10.13, *) else {
return
}

let fooBinary = productsDirectory.appendingPathComponent("string-performance")

let process = Process()
process.executableURL = fooBinary

let pipe = Pipe()
process.standardOutput = pipe

try process.run()
process.waitUntilExit()

let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)

XCTAssertEqual(output, "Hello, world!\n")
}

/// Returns path to the built products directory.
var productsDirectory: URL {
#if os(macOS)
for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") {
return bundle.bundleURL.deletingLastPathComponent()
}
fatalError("couldn't find the products directory")
#else
return Bundle.main.bundleURL
#endif
}

static var allTests = [
("testExample", testExample),
]
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,4 @@ This repository is the home of code written on episodes of
1. [Generalized Parsing: Part 1](0124-generalized-parsing-pt1)
1. [Generalized Parsing: Part 2](0125-generalized-parsing-pt2)
1. [Generalized Parsing: Part 3](0126-generalized-parsing-pt3)
1. [Parsing Performance: Strings](0127-parsing-performance-pt1)

0 comments on commit 4e7b7d1

Please sign in to comment.