Skip to content

Commit 7ccbea8

Browse files
committed
New KeyValuePairs view
1 parent 27d96b5 commit 7ccbea8

17 files changed

+7082
-186
lines changed
Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
// Copyright The swift-url Contributors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import Benchmark
16+
import WebURL
17+
18+
#if swift(>=5.7)
19+
20+
/// Benchmarks the WebURL `KeyValuePairs` view.
21+
///
22+
let KeyValuePairs = BenchmarkSuite(name: "KeyValuePairs") { suite in
23+
24+
// Iteration.
25+
26+
suite.benchmark("Iteration.Small.Forwards") { state in
27+
var url = WebURL("http://example.com/?foo=bar&baz=qux&format=json&client=mobile")!
28+
try state.measure {
29+
for component in url.queryParams {
30+
blackHole(component)
31+
}
32+
}
33+
blackHole(url)
34+
}
35+
36+
// Get (non-encoded).
37+
38+
suite.benchmark("Get.NonEncoded") { state in
39+
var url = WebURL("http://example.com/?foo=bar&baz=qux&format=json&client=mobile")!
40+
try state.measure {
41+
blackHole(url.queryParams["format"]!)
42+
}
43+
blackHole(url)
44+
}
45+
46+
// Get2 (non-encoded).
47+
48+
suite.benchmark("Get2.NonEncoded") { state in
49+
var url = WebURL("http://example.com/?foo=bar&baz=qux&format=json&client=mobile")!
50+
try state.measure {
51+
blackHole(url.queryParams["format", "client"])
52+
}
53+
blackHole(url)
54+
}
55+
56+
// Get3 (non-encoded).
57+
58+
suite.benchmark("Get3.NonEncoded") { state in
59+
var url = WebURL("http://example.com/?foo=bar&baz=qux&format=json&client=mobile")!
60+
try state.measure {
61+
blackHole(url.queryParams["format", "client", "baz"])
62+
}
63+
blackHole(url)
64+
}
65+
66+
// Get4 (non-encoded).
67+
68+
suite.benchmark("Get4.NonEncoded") { state in
69+
var url = WebURL("http://example.com/?foo=bar&baz=qux&format=json&client=mobile")!
70+
try state.measure {
71+
blackHole(url.queryParams["format", "client", "baz", "client"])
72+
}
73+
blackHole(url)
74+
}
75+
76+
// Get (encoded).
77+
78+
suite.benchmark("Get.Encoded") { state in
79+
var url = WebURL("http://example.com/?foo=bar&baz=qux&form%61t=json&client=mobile")!
80+
try state.measure {
81+
blackHole(url.queryParams["format"]!)
82+
}
83+
blackHole(url)
84+
}
85+
86+
// Get2 (encoded).
87+
88+
suite.benchmark("Get2.Encoded") { state in
89+
var url = WebURL("http://example.com/?foo=bar&baz=qux&form%61t=json&cli%65nt=mobile")!
90+
try state.measure {
91+
blackHole(url.queryParams["format", "client"])
92+
}
93+
blackHole(url)
94+
}
95+
96+
// Get3 (encoded).
97+
98+
suite.benchmark("Get3.Encoded") { state in
99+
var url = WebURL("http://example.com/?foo=bar&%62az=qux&form%61t=json&cli%65nt=mobile")!
100+
try state.measure {
101+
blackHole(url.queryParams["format", "client", "baz"])
102+
}
103+
blackHole(url)
104+
}
105+
106+
// Get4 (encoded).
107+
108+
suite.benchmark("Get4.Encoded") { state in
109+
var url = WebURL("http://example.com/?foo=bar&%62az=qux&form%61t=json&cli%65nt=mobile")!
110+
try state.measure {
111+
blackHole(url.queryParams["format", "client", "baz", "client"])
112+
}
113+
blackHole(url)
114+
}
115+
116+
// Get (long-keys)(non-encoded).
117+
118+
suite.benchmark("Get.LongKeys.NonEncoded") { state in
119+
var url = WebURL("http://example.com/?foofoofoofoofoofoo=bar&bazbazbazbazbaz=qux&formatformatformatformat=json&clientclientclientclientclient=mobile")!
120+
try state.measure {
121+
blackHole(url.queryParams["formatformatformatformat"]!)
122+
}
123+
blackHole(url)
124+
}
125+
126+
// Get2 (long-keys)(non-encoded).
127+
128+
suite.benchmark("Get2.LongKeys.NonEncoded") { state in
129+
var url = WebURL("http://example.com/?foofoofoofoofoofoo=bar&bazbazbazbazbaz=qux&formatformatformatformat=json&clientclientclientclientclient=mobile")!
130+
try state.measure {
131+
blackHole(url.queryParams["formatformatformatformat", "clientclientclientclientclient"])
132+
}
133+
blackHole(url)
134+
}
135+
136+
// Get (long-keys)(encoded).
137+
138+
suite.benchmark("Get.LongKeys.Encoded") { state in
139+
var url = WebURL("http://example.com/?foofoofoofoofoofoo=bar&bazbazbazbazbaz=qux&form%61tform%61tform%61tform%61t=json&clientclientclientclientclient=mobile")!
140+
try state.measure {
141+
blackHole(url.queryParams["formatformatformatformat"]!)
142+
}
143+
blackHole(url)
144+
}
145+
146+
// Get2 (long-keys)(encoded).
147+
148+
suite.benchmark("Get2.LongKeys.Encoded") { state in
149+
var url = WebURL("http://example.com/?foofoofoofoofoofoo=bar&bazbazbazbazbaz=qux&form%61tform%61tform%61tform%61t=json&client%63lientclientclientclient=mobile")!
150+
try state.measure {
151+
blackHole(url.queryParams["formatformatformatformat", "clientclientclientclientclient"])
152+
}
153+
blackHole(url)
154+
}
155+
156+
// Append One.
157+
158+
suite.benchmark("Append.One.Encoded") { state in
159+
var url = WebURL("http://example.com/#f")!
160+
try state.measure {
161+
url.queryParams.append(key: "format", value: "🦆")
162+
}
163+
blackHole(url)
164+
}
165+
166+
suite.benchmark("Append.One.NonEncoded") { state in
167+
var url = WebURL("http://example.com/#f")!
168+
try state.measure {
169+
url.queryParams.append(key: "format", value: "json")
170+
}
171+
blackHole(url)
172+
}
173+
174+
// Append Many.
175+
176+
suite.benchmark("Append.Many.Encoded") { state in
177+
var url = WebURL("http://example.com/#f")!
178+
try state.measure {
179+
url.queryParams += [
180+
("foo", "bar"),
181+
("format", "🦆"),
182+
("client", "mobile")
183+
]
184+
}
185+
blackHole(url)
186+
}
187+
188+
suite.benchmark("Append.Many.NonEncoded") { state in
189+
var url = WebURL("http://example.com/#f")!
190+
try state.measure {
191+
url.queryParams += [
192+
("foo", "bar"),
193+
("format", "json"),
194+
("client", "mobile")
195+
]
196+
}
197+
blackHole(url)
198+
}
199+
200+
// Remove All Where.
201+
202+
suite.benchmark("RemoveAllWhere") { state in
203+
var url = WebURL("http://example.com/?foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple#f")!
204+
try state.measure {
205+
url.queryParams.removeAll(where: { $0.key.hasPrefix("f") })
206+
}
207+
blackHole(url)
208+
}
209+
210+
suite.benchmark("RemoveAllWhere-2") { state in
211+
var url = WebURL("http://example.com/?foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple&foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple#f")!
212+
try state.measure {
213+
url.queryParams.removeAll(where: { $0.key.hasPrefix("f") })
214+
}
215+
blackHole(url)
216+
}
217+
218+
suite.benchmark("RemoveAllWhere-4") { state in
219+
var url = WebURL("http://example.com/?foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple&foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple&foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple&foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple#f")!
220+
try state.measure {
221+
url.queryParams.removeAll(where: { $0.key.hasPrefix("f") })
222+
}
223+
blackHole(url)
224+
}
225+
226+
suite.benchmark("RemoveAllWhere-8") { state in
227+
var url = WebURL("http://example.com/?foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple&foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple&foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple&foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple&foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple&foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple&foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple&foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple#f")!
228+
try state.measure {
229+
url.queryParams.removeAll(where: { $0.key.hasPrefix("f") })
230+
}
231+
blackHole(url)
232+
}
233+
234+
235+
// Set.
236+
237+
suite.benchmark("Set.Single") { state in
238+
var url = WebURL("http://example.com/?foo=bar&client=mobile&format=json&cream=cheese&fish&chips&fruit=apple#f")!
239+
try state.measure {
240+
url.queryParams.set(key: "format", to: "xml")
241+
}
242+
blackHole(url)
243+
}
244+
245+
suite.benchmark("Set.Multiple") { state in
246+
var url = WebURL("http://example.com/?foo=bar&client=mobile&format=json&cream=cheese&fish&chips&format=plist&format#f")!
247+
try state.measure {
248+
url.queryParams.set(key: "format", to: "xml")
249+
}
250+
blackHole(url)
251+
}
252+
253+
suite.benchmark("Set.Append") { state in
254+
var url = WebURL("http://example.com/?foo=bar&client=mobile&format=json&cream=cheese&fish&chips&format=plist&format#f")!
255+
try state.measure {
256+
url.queryParams.set(key: "new", to: "appended")
257+
}
258+
blackHole(url)
259+
}
260+
261+
suite.benchmark("Set.Remove.Single") { state in
262+
var url = WebURL("http://example.com/?foo=bar&client=mobile&format=json&cream=cheese&fish&chips&format=plist&format#f")!
263+
try state.measure {
264+
url.queryParams["cream"] = nil
265+
}
266+
blackHole(url)
267+
}
268+
269+
suite.benchmark("Set.Remove.Multiple") { state in
270+
var url = WebURL("http://example.com/?foo=bar&client=mobile&format=json&cream=cheese&fish&chips&format=plist&format#f")!
271+
try state.measure {
272+
url.queryParams["format"] = nil
273+
}
274+
blackHole(url)
275+
}
276+
277+
suite.benchmark("Set.Remove.None") { state in
278+
var url = WebURL("http://example.com/?foo=bar&client=mobile&format=json&cream=cheese&fish&chips&format=plist&format#f")!
279+
try state.measure {
280+
url.queryParams["doesNotExist"] = nil
281+
}
282+
blackHole(url)
283+
}
284+
}
285+
286+
#endif

Benchmarks/Sources/WebURLBenchmark/main.swift

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,23 @@ internal func blackHole<T>(_ x: T) {
2727
// - Cannot-be-a-base URLs
2828
// - file: URLs
2929

30-
Benchmark.main([
31-
Constructor.HTTP,
32-
ComponentSetters,
33-
PathComponents,
34-
PercentEncoding,
35-
FoundationCompat.NSURLToWeb,
36-
FoundationCompat.WebToNSURL,
37-
])
30+
#if swift(>=5.7)
31+
Benchmark.main([
32+
Constructor.HTTP,
33+
ComponentSetters,
34+
PathComponents,
35+
PercentEncoding,
36+
KeyValuePairs,
37+
FoundationCompat.NSURLToWeb,
38+
FoundationCompat.WebToNSURL,
39+
])
40+
#else
41+
Benchmark.main([
42+
Constructor.HTTP,
43+
ComponentSetters,
44+
PathComponents,
45+
PercentEncoding,
46+
FoundationCompat.NSURLToWeb,
47+
FoundationCompat.WebToNSURL,
48+
])
49+
#endif

Package.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ let package = Package(
8383
.target(
8484
name: "WebURL",
8585
dependencies: ["IDNA"],
86-
exclude: ["WebURL.docc"]
86+
exclude: ["WebURL.docc", "WebURL+KeyValuePairs.swift"]
8787
),
8888
.target(
8989
name: "WebURLTestSupport",
@@ -92,7 +92,8 @@ let package = Package(
9292
),
9393
.testTarget(
9494
name: "WebURLTests",
95-
dependencies: ["WebURL", "WebURLTestSupport", "Checkit"]
95+
dependencies: ["WebURL", "WebURLTestSupport", "Checkit"],
96+
exclude: ["KeyValuePairsTests.swift"]
9697
),
9798
.testTarget(
9899
name: "WebURLDeprecatedAPITests",

[email protected]

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ let package = Package(
8282

8383
.target(
8484
name: "WebURL",
85-
dependencies: ["IDNA"]
85+
dependencies: ["IDNA"],
86+
exclude: ["WebURL+KeyValuePairs.swift"]
8687
),
8788
.target(
8889
name: "WebURLTestSupport",
@@ -91,7 +92,8 @@ let package = Package(
9192
),
9293
.testTarget(
9394
name: "WebURLTests",
94-
dependencies: ["WebURL", "WebURLTestSupport", "Checkit"]
95+
dependencies: ["WebURL", "WebURLTestSupport", "Checkit"],
96+
exclude: ["KeyValuePairsTests.swift"]
9597
),
9698
.testTarget(
9799
name: "WebURLDeprecatedAPITests",

0 commit comments

Comments
 (0)