1
1
import _StringProcessing
2
2
import Foundation
3
3
4
- public protocol RegexBenchmark {
4
+ protocol RegexBenchmark {
5
5
var name : String { get }
6
6
func run( )
7
7
func debug( )
8
8
}
9
9
10
- public struct Benchmark : RegexBenchmark {
11
- public let name : String
10
+ struct Benchmark : RegexBenchmark {
11
+ let name : String
12
12
let regex : Regex < AnyRegexOutput >
13
13
let type : MatchType
14
14
let target : String
15
15
16
- public enum MatchType {
16
+ enum MatchType {
17
17
case whole
18
18
case first
19
19
case allMatches
20
20
}
21
21
22
- public func run( ) {
22
+ func run( ) {
23
23
switch type {
24
24
case . whole: blackHole ( target. wholeMatch ( of: regex) )
25
25
case . allMatches: blackHole ( target. matches ( of: regex) )
@@ -28,8 +28,8 @@ public struct Benchmark: RegexBenchmark {
28
28
}
29
29
}
30
30
31
- public struct NSBenchmark : RegexBenchmark {
32
- public let name : String
31
+ struct NSBenchmark : RegexBenchmark {
32
+ let name : String
33
33
let regex : NSRegularExpression
34
34
let type : NSMatchType
35
35
let target : String
@@ -38,19 +38,55 @@ public struct NSBenchmark: RegexBenchmark {
38
38
NSRange ( target. startIndex..< target. endIndex, in: target)
39
39
}
40
40
41
- public enum NSMatchType {
41
+ enum NSMatchType {
42
42
case allMatches
43
43
case first
44
44
}
45
45
46
- public func run( ) {
46
+ func run( ) {
47
47
switch type {
48
48
case . allMatches: blackHole ( regex. matches ( in: target, range: range) )
49
49
case . first: blackHole ( regex. firstMatch ( in: target, range: range) )
50
50
}
51
51
}
52
52
}
53
53
54
+ /// A benchmark running a regex on strings in input set
55
+ struct InputListBenchmark : RegexBenchmark {
56
+ let name : String
57
+ let regex : Regex < AnyRegexOutput >
58
+ let targets : [ String ]
59
+
60
+ func run( ) {
61
+ for target in targets {
62
+ blackHole ( target. wholeMatch ( of: regex) )
63
+ }
64
+ }
65
+ }
66
+
67
+ struct InputListNSBenchmark : RegexBenchmark {
68
+ let name : String
69
+ let regex : NSRegularExpression
70
+ let targets : [ String ]
71
+
72
+ init ( name: String , regex: String , targets: [ String ] ) {
73
+ self . name = name
74
+ self . regex = try ! NSRegularExpression ( pattern: " ^ " + regex + " $ " )
75
+ self . targets = targets
76
+ }
77
+
78
+ func range( in target: String ) -> NSRange {
79
+ NSRange ( target. startIndex..< target. endIndex, in: target)
80
+ }
81
+
82
+ func run( ) {
83
+ for target in targets {
84
+ let range = range ( in: target)
85
+ blackHole ( regex. firstMatch ( in: target, range: range) )
86
+ }
87
+ }
88
+ }
89
+
54
90
/// A benchmark meant to be ran across multiple engines
55
91
struct CrossBenchmark {
56
92
/// The base name of the benchmark
@@ -69,11 +105,12 @@ struct CrossBenchmark {
69
105
/// TODO: Probably better ot have a whole-line vs search anywhere, maybe
70
106
/// accomodate multi-line matching, etc.
71
107
var isWhole : Bool = false
108
+
109
+ /// Whether or not to do firstMatch as well or just allMatches
110
+ var includeFirst : Bool = false
72
111
73
112
func register( _ runner: inout BenchmarkRunner ) {
74
113
let swiftRegex = try ! Regex ( regex)
75
-
76
- let nsPattern = isWhole ? " ^ " + regex + " $ " : regex
77
114
let nsRegex : NSRegularExpression
78
115
if isWhole {
79
116
nsRegex = try ! NSRegularExpression ( pattern: " ^ " + regex + " $ " )
@@ -95,37 +132,65 @@ struct CrossBenchmark {
95
132
type: . first,
96
133
target: input) )
97
134
} else {
98
- runner. register (
99
- Benchmark (
100
- name: baseName + " First " ,
101
- regex: swiftRegex,
102
- type: . first,
103
- target: input) )
104
135
runner. register (
105
136
Benchmark (
106
137
name: baseName + " All " ,
107
138
regex: swiftRegex,
108
139
type: . allMatches,
109
140
target: input) )
110
- runner. register (
111
- NSBenchmark (
112
- name: baseName + " First_NS " ,
113
- regex: nsRegex,
114
- type: . first,
115
- target: input) )
116
141
runner. register (
117
142
NSBenchmark (
118
143
name: baseName + " All_NS " ,
119
144
regex: nsRegex,
120
145
type: . allMatches,
121
146
target: input) )
147
+ if includeFirst {
148
+ runner. register (
149
+ Benchmark (
150
+ name: baseName + " First " ,
151
+ regex: swiftRegex,
152
+ type: . first,
153
+ target: input) )
154
+ runner. register (
155
+ NSBenchmark (
156
+ name: baseName + " First_NS " ,
157
+ regex: nsRegex,
158
+ type: . first,
159
+ target: input) )
160
+ }
122
161
}
123
162
}
124
163
}
125
164
165
+ /// A benchmark running a regex on strings in input list, run across multiple engines
166
+ struct CrossInputListBenchmark {
167
+ /// The base name of the benchmark
168
+ var baseName : String
169
+
170
+ /// The string to compile in differnet engines
171
+ var regex : String
172
+
173
+ /// The list of strings to search
174
+ var inputs : [ String ]
175
+
176
+ func register( _ runner: inout BenchmarkRunner ) {
177
+ let swiftRegex = try ! Regex ( regex)
178
+ runner. register ( InputListBenchmark (
179
+ name: baseName,
180
+ regex: swiftRegex,
181
+ targets: inputs
182
+ ) )
183
+ runner. register ( InputListNSBenchmark (
184
+ name: baseName + " NS " ,
185
+ regex: regex,
186
+ targets: inputs
187
+ ) )
188
+ }
189
+ }
190
+
126
191
// TODO: Capture-containing benchmarks
127
192
128
193
// nom nom nom, consume the argument
129
194
@inline ( never)
130
- public func blackHole< T> ( _ x: T ) {
195
+ func blackHole< T> ( _ x: T ) {
131
196
}
0 commit comments