Skip to content

Commit 16ba9d0

Browse files
committed
Merge branch 'main' into shrink_consumer_interface
2 parents ded0d1b + cc309e6 commit 16ba9d0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2915
-965
lines changed

Package.swift

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,19 @@ let availabilityDefinition = PackageDescription.SwiftSetting.unsafeFlags([
1111
"-Xfrontend",
1212
"-define-availability",
1313
"-Xfrontend",
14-
"SwiftStdlib 5.8:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999",
14+
"SwiftStdlib 5.8:macOS 13.3, iOS 16.4, watchOS 9.4, tvOS 16.4",
15+
"-Xfrontend",
16+
"-define-availability",
17+
"-Xfrontend",
18+
"SwiftStdlib 5.9:macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0",
19+
"-Xfrontend",
20+
"-define-availability",
21+
"-Xfrontend",
22+
"SwiftStdlib 5.10:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999",
23+
"-Xfrontend",
24+
"-define-availability",
25+
"-Xfrontend",
26+
"SwiftStdlib 6.0:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999",
1527
])
1628

1729
/// Swift settings for building a private stdlib-like module that is to be used
@@ -85,7 +97,7 @@ let package = Package(
8597
name: "RegexTests",
8698
dependencies: ["_StringProcessing", "TestSupport"],
8799
swiftSettings: [
88-
.unsafeFlags(["-Xfrontend", "-disable-availability-checking"]),
100+
availabilityDefinition
89101
]),
90102
.testTarget(
91103
name: "RegexBuilderTests",
@@ -128,7 +140,8 @@ let package = Package(
128140
.product(name: "ArgumentParser", package: "swift-argument-parser"),
129141
"_RegexParser",
130142
"_StringProcessing"
131-
]),
143+
],
144+
swiftSettings: [availabilityDefinition]),
132145
.executableTarget(
133146
name: "RegexBenchmark",
134147
dependencies: [

Sources/RegexBenchmark/Benchmark.swift

Lines changed: 35 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ struct NSBenchmark: RegexBenchmark {
7171
enum NSMatchType {
7272
case allMatches
7373
case first
74+
75+
init(_ type: Benchmark.MatchType) {
76+
switch type {
77+
case .whole, .first: self = .first
78+
case .allMatches: self = .allMatches
79+
}
80+
}
7481
}
7582

7683
func run() {
@@ -126,7 +133,7 @@ struct CrossBenchmark {
126133
/// The base name of the benchmark
127134
var baseName: String
128135

129-
/// The string to compile in differnet engines
136+
/// The string to compile in different engines
130137
var regex: String
131138

132139
/// The text to search
@@ -143,57 +150,32 @@ struct CrossBenchmark {
143150
/// Whether or not to do firstMatch as well or just allMatches
144151
var includeFirst: Bool = false
145152

153+
/// Whether to also run scalar-semantic mode
154+
var alsoRunScalarSemantic: Bool = true
155+
146156
func register(_ runner: inout BenchmarkRunner) {
147-
let swiftRegex = try! Regex(regex)
148-
let nsRegex: NSRegularExpression
149157
if isWhole {
150-
nsRegex = try! NSRegularExpression(pattern: "^" + regex + "$")
158+
runner.registerCrossBenchmark(
159+
nameBase: baseName,
160+
input: input,
161+
pattern: regex,
162+
.whole,
163+
alsoRunScalarSemantic: alsoRunScalarSemantic)
151164
} else {
152-
nsRegex = try! NSRegularExpression(pattern: regex)
153-
}
165+
runner.registerCrossBenchmark(
166+
nameBase: baseName,
167+
input: input,
168+
pattern: regex,
169+
.allMatches,
170+
alsoRunScalarSemantic: alsoRunScalarSemantic)
154171

155-
if isWhole {
156-
runner.register(
157-
Benchmark(
158-
name: baseName + "Whole",
159-
regex: swiftRegex,
160-
pattern: regex,
161-
type: .whole,
162-
target: input))
163-
runner.register(
164-
NSBenchmark(
165-
name: baseName + "Whole" + CrossBenchmark.nsSuffix,
166-
regex: nsRegex,
167-
type: .first,
168-
target: input))
169-
} else {
170-
runner.register(
171-
Benchmark(
172-
name: baseName + "All",
173-
regex: swiftRegex,
174-
pattern: regex,
175-
type: .allMatches,
176-
target: input))
177-
runner.register(
178-
NSBenchmark(
179-
name: baseName + "All" + CrossBenchmark.nsSuffix,
180-
regex: nsRegex,
181-
type: .allMatches,
182-
target: input))
183172
if includeFirst || runner.includeFirstOverride {
184-
runner.register(
185-
Benchmark(
186-
name: baseName + "First",
187-
regex: swiftRegex,
188-
pattern: regex,
189-
type: .first,
190-
target: input))
191-
runner.register(
192-
NSBenchmark(
193-
name: baseName + "First" + CrossBenchmark.nsSuffix,
194-
regex: nsRegex,
195-
type: .first,
196-
target: input))
173+
runner.registerCrossBenchmark(
174+
nameBase: baseName,
175+
input: input,
176+
pattern: regex,
177+
.first,
178+
alsoRunScalarSemantic: alsoRunScalarSemantic)
197179
}
198180
}
199181
}
@@ -209,20 +191,16 @@ struct CrossInputListBenchmark {
209191

210192
/// The list of strings to search
211193
var inputs: [String]
194+
195+
/// Also run in scalar-semantic mode
196+
var alsoRunScalarSemantic: Bool = true
212197

213198
func register(_ runner: inout BenchmarkRunner) {
214-
let swiftRegex = try! Regex(regex)
215-
runner.register(InputListBenchmark(
199+
runner.registerCrossBenchmark(
216200
name: baseName,
217-
regex: swiftRegex,
201+
inputList: inputs,
218202
pattern: regex,
219-
targets: inputs
220-
))
221-
runner.register(InputListNSBenchmark(
222-
name: baseName + CrossBenchmark.nsSuffix,
223-
regex: regex,
224-
targets: inputs
225-
))
203+
alsoRunScalarSemantic: alsoRunScalarSemantic)
226204
}
227205
}
228206

Sources/RegexBenchmark/BenchmarkRunner.swift

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ import Foundation
44
/// The number of times to re-run the benchmark if results are too varying
55
private var rerunCount: Int { 3 }
66

7+
extension Benchmark.MatchType {
8+
fileprivate var nameSuffix: String {
9+
switch self {
10+
case .whole: return "_Whole"
11+
case .first: return "_First"
12+
case .allMatches: return "_All"
13+
}
14+
}
15+
}
16+
717
struct BenchmarkRunner {
818
let suiteName: String
919
var suite: [any RegexBenchmark] = []
@@ -16,12 +26,141 @@ struct BenchmarkRunner {
1626

1727
// Forcibly include firstMatch benchmarks for all CrossBenchmarks
1828
let includeFirstOverride: Bool
29+
30+
// Register a cross-benchmark
31+
mutating func registerCrossBenchmark(
32+
nameBase: String,
33+
input: String,
34+
pattern: String,
35+
_ type: Benchmark.MatchType,
36+
alsoRunScalarSemantic: Bool = true
37+
) {
38+
let swiftRegex = try! Regex(pattern)
39+
let nsRegex: NSRegularExpression
40+
if type == .whole {
41+
nsRegex = try! NSRegularExpression(pattern: "^" + pattern + "$")
42+
} else {
43+
nsRegex = try! NSRegularExpression(pattern: pattern)
44+
}
45+
let nameSuffix = type.nameSuffix
46+
47+
register(
48+
Benchmark(
49+
name: nameBase + nameSuffix,
50+
regex: swiftRegex,
51+
pattern: pattern,
52+
type: type,
53+
target: input))
54+
register(
55+
NSBenchmark(
56+
name: nameBase + nameSuffix + CrossBenchmark.nsSuffix,
57+
regex: nsRegex,
58+
type: .init(type),
59+
target: input))
60+
61+
if alsoRunScalarSemantic {
62+
register(
63+
Benchmark(
64+
name: nameBase + nameSuffix + "_Scalar",
65+
regex: swiftRegex.matchingSemantics(.unicodeScalar),
66+
pattern: pattern,
67+
type: type,
68+
target: input))
69+
register(
70+
NSBenchmark(
71+
name: nameBase + nameSuffix + "_Scalar" + CrossBenchmark.nsSuffix,
72+
regex: nsRegex,
73+
type: .init(type),
74+
target: input))
75+
}
76+
}
77+
78+
// Register a cross-benchmark list
79+
mutating func registerCrossBenchmark(
80+
name: String,
81+
inputList: [String],
82+
pattern: String,
83+
alsoRunScalarSemantic: Bool = true
84+
) {
85+
let swiftRegex = try! Regex(pattern)
86+
register(InputListBenchmark(
87+
name: name,
88+
regex: swiftRegex,
89+
pattern: pattern,
90+
targets: inputList
91+
))
92+
register(InputListNSBenchmark(
93+
name: name + CrossBenchmark.nsSuffix,
94+
regex: pattern,
95+
targets: inputList
96+
))
97+
98+
if alsoRunScalarSemantic {
99+
register(InputListBenchmark(
100+
name: name + "_Scalar",
101+
regex: swiftRegex.matchingSemantics(.unicodeScalar),
102+
pattern: pattern,
103+
targets: inputList
104+
))
105+
register(InputListNSBenchmark(
106+
name: name + "_Scalar" + CrossBenchmark.nsSuffix,
107+
regex: pattern,
108+
targets: inputList
109+
))
110+
}
111+
112+
}
113+
114+
// Register a swift-only benchmark
115+
mutating func register(
116+
nameBase: String,
117+
input: String,
118+
pattern: String,
119+
_ swiftRegex: Regex<AnyRegexOutput>,
120+
_ type: Benchmark.MatchType,
121+
alsoRunScalarSemantic: Bool = true
122+
) {
123+
let nameSuffix = type.nameSuffix
124+
125+
register(
126+
Benchmark(
127+
name: nameBase + nameSuffix,
128+
regex: swiftRegex,
129+
pattern: pattern,
130+
type: type,
131+
target: input))
132+
133+
if alsoRunScalarSemantic {
134+
register(
135+
Benchmark(
136+
name: nameBase + nameSuffix + "_Scalar",
137+
regex: swiftRegex,
138+
pattern: pattern,
139+
type: type,
140+
target: input))
141+
}
142+
}
19143

20-
mutating func register(_ benchmark: some RegexBenchmark) {
144+
private mutating func register(_ benchmark: NSBenchmark) {
21145
suite.append(benchmark)
22146
}
23147

24-
mutating func register(_ benchmark: some SwiftRegexBenchmark) {
148+
private mutating func register(_ benchmark: Benchmark) {
149+
var benchmark = benchmark
150+
if enableTracing {
151+
benchmark.enableTracing()
152+
}
153+
if enableMetrics {
154+
benchmark.enableMetrics()
155+
}
156+
suite.append(benchmark)
157+
}
158+
159+
private mutating func register(_ benchmark: InputListNSBenchmark) {
160+
suite.append(benchmark)
161+
}
162+
163+
private mutating func register(_ benchmark: InputListBenchmark) {
25164
var benchmark = benchmark
26165
if enableTracing {
27166
benchmark.enableTracing()

0 commit comments

Comments
 (0)