Skip to content

Commit 8a2d04a

Browse files
good stuff
- fixed wrong placement of custom renderer text - updated README executed command - `title` value is now dynamic in benchmarks - interpolation detection should now show compiler warning for every usage - tried improving dynamic throughput to no avail
1 parent a13a8c3 commit 8a2d04a

File tree

17 files changed

+189
-101
lines changed

17 files changed

+189
-101
lines changed

Benchmarks/Benchmarks/Elementary/Elementary.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ struct DynamicView {
3939
html {
4040
head {
4141
meta(.custom(name: "charset", value: context.charset))
42-
title { "DynamicView" }
42+
title { context.title }
4343
meta(.content(context.meta_description), .name("description"))
4444
meta(.content(context.keywords_string), .name("keywords"))
4545
}

Benchmarks/Benchmarks/Networking/main.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,9 @@ let libraries:[String:HTMLGenerator] = [
3535
import Hummingbird
3636

3737
struct HeaderMiddleware<Context: RequestContext> : RouterMiddleware {
38-
let output:String
39-
40-
init(_ output: String = "Content-Type") {
41-
self.output = output
42-
}
4338
func handle(_ request: Request, context: Context, next: (Request, Context) async throws -> Response) async throws -> Response {
4439
var response = try await next(request, context)
45-
response.headers[HTTPField.Name(output)!] = "text/html"
40+
response.headers[HTTPField.Name("Content-Type")!] = "text/html"
4641
return response
4742
}
4843
}

Benchmarks/Benchmarks/Plot/Plot.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ package struct PlotTests : HTMLGenerator {
2525
return HTML(
2626
.head(
2727
.meta(.attribute(named: "charset", value: context.charset)),
28-
.element(named: "title", text: "DynamicView"),
28+
.element(named: "title", text: context.title),
2929
.meta(.content(context.meta_description), .name("description")),
3030
.meta(.content(context.keywords_string), .name("keywords"))
3131
),

Benchmarks/Benchmarks/SwiftHTMLBB/SwiftHTMLBB.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ package struct SwiftHTMLBBTests : HTMLGenerator {
3232
Html {
3333
Head {
3434
Meta().charset(context.charset)
35-
Title("DynamicView")
35+
Title(context.title)
3636
Meta().content(context.meta_description).name("description")
3737
Meta().content(context.keywords_string).name("keywords")
3838
}

Benchmarks/Benchmarks/SwiftHTMLKit/SwiftHTMLKit.swift

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ package struct SwiftHTMLKitTests : HTMLGenerator {
1212
package init() {}
1313

1414
package func staticHTML() -> String {
15-
#html([
16-
#head([
17-
#title(["StaticView"])
18-
]),
19-
#body([
20-
#h1(["Swift HTML Benchmarks"])
21-
])
22-
])
15+
#html(
16+
#head(
17+
#title("StaticView")
18+
),
19+
#body(
20+
#h1("Swift HTML Benchmarks")
21+
)
22+
)
2323
}
2424
// performance notes
2525
// - maping makes unneccessary copies and hurts throughput
@@ -30,24 +30,25 @@ package struct SwiftHTMLKitTests : HTMLGenerator {
3030
package func dynamicHTML(_ context: HTMLContext) -> String {
3131
var qualities:String = ""
3232
for quality in context.user.qualities {
33-
qualities += #li(["\(quality)"])
33+
qualities += #li("\(quality)")
3434
}
35-
return #html([
36-
#head([
35+
let string:String = #html(
36+
#head(
3737
#meta(charset: "\(context.charset)"),
38-
#title(["DynamicView"]),
38+
#title("\(context.title)"),
3939
#meta(content: "\(context.meta_description)", name: "description"),
4040
#meta(content: "\(context.keywords_string)", name: "keywords")
41-
]),
42-
#body([
43-
#h1(["\(context.heading)"]),
44-
#div(attributes: [.id(context.desc_id)], [
45-
#p(["\(context.string)"])
46-
]),
47-
#h2(["\(context.user.details_heading)"]),
48-
#h3(["\(context.user.qualities_heading)"]),
49-
#ul(attributes: [.id(context.user.qualities_id)], ["\(qualities)"])
50-
])
51-
])
41+
),
42+
#body(
43+
#h1("\(context.heading)"),
44+
#div(attributes: [.id(context.desc_id)],
45+
#p("\(context.string)")
46+
),
47+
#h2("\(context.user.details_heading)"),
48+
#h3("\(context.user.qualities_heading)"),
49+
#ul(attributes: [.id(context.user.qualities_id)], "\(qualities)")
50+
)
51+
)
52+
return string
5253
}
5354
}

Benchmarks/Benchmarks/SwiftHTMLPF/SwiftHTMLPF.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ package struct SwiftHTMLPFTests : HTMLGenerator {
3030
.html(
3131
.head(
3232
.meta(attributes: [.charset(.utf8)]),
33-
.title("DynamicView"),
33+
.title(context.title),
3434
.meta(attributes: [.init("content", context.meta_description), .init("name", "description")]),
3535
.meta(attributes: [.init("content", context.keywords_string), .init("name", "keywords")])
3636
),

Benchmarks/Benchmarks/Swim/Swim.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ package struct SwimTests : HTMLGenerator {
6161
return html {
6262
head {
6363
meta(charset: context.charset)
64-
title { "DynamicView" }
64+
title { context.title }
6565
meta(customAttributes: ["content":context.meta_description, "name":"description"])
6666
meta(customAttributes: ["content":context.keywords_string, "name":"keywords"])
6767
}

Benchmarks/Benchmarks/UnitTests/UnitTests.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ struct UnitTests {
3131
"Vaux" : VauxTests()
3232
]
3333
@Test func staticHTML() {
34-
let expected_value:String = #html([
35-
#head([
36-
#title(["StaticView"])
37-
]),
38-
#body([
39-
#h1(["Swift HTML Benchmarks"])
40-
])
41-
])
34+
let expected_value:String = #html(
35+
#head(
36+
#title("StaticView")
37+
),
38+
#body(
39+
#h1("Swift HTML Benchmarks")
40+
)
41+
)
4242
for (key, value) in libraries {
4343
var string:String = value.staticHTML()
4444
if key == "Swim" {

Benchmarks/Benchmarks/Utilities/Utilities.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ package actor Cache {
3535

3636
// MARK: HTMLContext
3737
package struct HTMLContext {
38-
package let charset:String, keywords:[String], meta_description:String
38+
package let charset:String, title:String, keywords:[String], meta_description:String
3939
package let heading:String, desc_id:String
4040
package let string:String, integer:Int, double:Double, float:Float, boolean:Bool
4141
package let now:Date
@@ -52,13 +52,24 @@ package struct HTMLContext {
5252

5353
package init() {
5454
charset = "utf-8"
55+
title = "DynamicView"
5556
keywords = ["swift", "html", "benchmark"]
5657
meta_description = "This website is to benchmark the performance of different Swift DSL libraries."
5758

5859
heading = "Dynamic HTML Benchmark"
5960
desc_id = "desc"
60-
// 1 paragraph of lorem ipsum
61-
string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tempor euismod arcu, sed elementum erat lobortis vel. Fusce nec orci purus. Maecenas a rutrum elit, in pellentesque nisl. Cras nec dapibus turpis. Donec finibus auctor arcu, vehicula maximus eros tincidunt et. Praesent nulla urna, imperdiet quis nunc id, auctor varius justo. Integer fringilla tincidunt lectus, et egestas massa molestie ut. Aliquam at augue pulvinar ante dignissim dignissim a at augue. Donec nisi elit, faucibus a ante a, interdum ultrices lacus. Fusce faucibus odio at est imperdiet, id sodales ipsum hendrerit. Nullam vehicula velit non metus malesuada ornare. Proin consequat id nulla sed porttitor."
61+
// 5 paragraphs of lorem ipsum
62+
string = """
63+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eget ornare ligula, sit amet pretium justo. Nunc vestibulum sollicitudin sem sed ultricies. Nullam ultrices mattis rutrum. Quisque venenatis lacus non tortor aliquam elementum. Nullam dictum, dolor vel efficitur semper, metus nisi porta elit, in tincidunt nunc eros quis nunc. Aliquam id eros sed leo feugiat aliquet quis eget augue. Praesent molestie quis libero vulputate cursus. Aenean lobortis cursus lacinia. Quisque imperdiet suscipit mi in rutrum. Suspendisse potenti.
64+
65+
In condimentum non turpis non porta. In vehicula rutrum risus eget placerat. Nulla neque quam, dignissim eu luctus at, elementum at nisl. Cras volutpat mi sem, at congue felis pellentesque sed. Sed maximus orci vel enim iaculis condimentum. Integer maximus consectetur arcu quis aliquet. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas eget feugiat elit. Maecenas pellentesque, urna at iaculis pretium, diam lectus dapibus est, et fermentum nisl ex vel ligula. Aliquam dignissim dapibus est, nec tincidunt tortor sagittis in. Vestibulum id lacus a nunc auctor ultricies. Praesent ante sapien, ultricies vel lorem id, tempus mollis justo. Curabitur sollicitudin, augue hendrerit suscipit tristique, sem lacus consectetur leo, id eleifend diam tellus sit amet nulla. Etiam metus augue, consequat ut dictum a, aliquet nec neque. Vestibulum gravida vel ligula at interdum. Nam cursus sapien non malesuada lobortis.
66+
67+
Nulla in viverra mauris. Pellentesque non sollicitudin lacus, vitae pharetra neque. Praesent sodales odio nisi, quis condimentum orci ornare a. Aliquam erat volutpat. Maecenas purus mauris, aliquet rutrum metus eget, consectetur fringilla felis. Proin pulvinar tellus nulla, nec iaculis neque venenatis sed. In vel dui quam. Integer aliquam ligula ipsum, mattis commodo quam elementum ut. Aenean tortor neque, blandit fermentum velit ut, rutrum gravida ex.
68+
69+
Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec sed diam eget nibh semper varius. Phasellus sed feugiat turpis, sit amet pharetra erat. Integer eleifend tortor ut mauris lobortis consequat. Aliquam fermentum mollis fringilla. Morbi et enim in ligula luctus facilisis quis sed leo. Nullam ut suscipit arcu, eu hendrerit eros. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla maximus tempus dui. In aliquam neque ut urna euismod, vitae ullamcorper nisl fermentum. Integer ac ultricies erat, id volutpat leo. Morbi faucibus tortor at lectus feugiat, quis ultricies lectus dictum. Pellentesque congue blandit ligula, nec convallis lectus volutpat congue. Nam lobortis sapien nec nulla accumsan, a pharetra quam convallis. Donec vulputate rutrum dolor ac cursus. Mauris condimentum convallis malesuada.
70+
71+
Mauris eros quam, dictum id elementum et, pharetra in metus. Quisque fermentum congue risus, accumsan consectetur neque aliquam quis. Vestibulum ipsum massa, euismod faucibus est in, condimentum venenatis risus. Quisque congue vehicula tellus, et dignissim augue accumsan ac. Pellentesque tristique ornare ligula, vitae iaculis dui varius vel. Ut sed sem sed purus facilisis porta quis eu tortor. Donec in vehicula tortor. Sed eget aliquet enim. Mauris tincidunt placerat risus, ut gravida lacus vehicula eget. Curabitur ultrices sapien tortor, eu gravida velit efficitur sed. Suspendisse eu volutpat est, ut bibendum velit. Maecenas mollis sit amet sapien laoreet pulvinar. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi lorem ante, volutpat et accumsan a, fermentum vel metus.
72+
"""
6273
integer = 293785
6374
double = 39848.9348019843
6475
float = 616905.2098238

Benchmarks/Benchmarks/VaporHTMLKit/VaporHTMLKit.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ struct DynamicView : View {
4747
Html {
4848
Head {
4949
Meta().charset(.utf8) // TODO: fix? | not dynamic
50-
Title { "DynamicView" }
50+
Title { context.title }
5151
Meta().content(context.meta_description).name(.description)
5252
Meta().content(context.keywords_string).name(.keywords)
5353
}

Benchmarks/Benchmarks/Vaux/Vaux.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ package struct VauxTests : HTMLGenerator {
8686
html {
8787
head {
8888
meta().attr("charset", context.charset)
89-
title("DynamicView")
89+
title(context.title)
9090
meta().attr("content", context.meta_description).attr("name", "description")
9191
meta().attr("content", context.keywords_string).attr("name", "keywords")
9292
}

Benchmarks/Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ let package = Package(
1212
// dsls
1313
.package(url: "https://github.com/ordo-one/package-benchmark", from: "1.27.0"),
1414
.package(url: "https://github.com/swiftlang/swift-syntax", from: "600.0.0"),
15-
.package(url: "https://github.com/RandomHashTags/swift-htmlkit", from: "0.5.0"),
15+
.package(name: "swift-htmlkit", path: "../"),
16+
//.package(url: "https://github.com/RandomHashTags/swift-htmlkit", from: "0.5.0"),
1617
.package(url: "https://github.com/sliemeobn/elementary", from: "0.3.4"),
1718
.package(url: "https://github.com/vapor-community/HTMLKit", from: "2.8.1"),
1819
.package(url: "https://github.com/pointfreeco/swift-html", from: "0.4.1"),

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,18 +148,18 @@ Use the `HTMLElementAttribute.event(<type>, "<value>")`.
148148

149149
## Benchmarks
150150
- Libraries tested
151-
- [BinaryBuilds/swift-html](https://github.com/BinaryBirds/swift-html) v1.7.0 (patched version [here](https://github.com/RandomHashTags/fork-bb-swift-html); custom renderer [here](https://github.com/RandomHashTags/swift-htmlkit/blob/main/Benchmarks/Benchmarks/Swim/Swim.swift))
151+
- [BinaryBuilds/swift-html](https://github.com/BinaryBirds/swift-html) v1.7.0 (patched version [here](https://github.com/RandomHashTags/fork-bb-swift-html))
152152
- [sliemeobn/elementary](https://github.com/sliemeobn/elementary) v0.3.4
153153
- [JohnSundell/Plot](https://github.com/JohnSundell/Plot) v0.14.0
154154
- [RandomHashTags/swift-htmlkit](https://github.com/RandomHashTags/swift-htmlkit) v0.5.0 (this library)
155155
- [pointfreeco/swift-html](https://github.com/pointfreeco/swift-html) v0.4.1
156-
- [robb/Swim](https://github.com/robb/Swim) v0.4.0 (patched version [here](https://github.com/RandomHashTags/fork-Swim))
156+
- [robb/Swim](https://github.com/robb/Swim) v0.4.0 (patched version [here](https://github.com/RandomHashTags/fork-Swim); custom renderer [here](https://github.com/RandomHashTags/swift-htmlkit/blob/main/Benchmarks/Benchmarks/Swim/Swim.swift))
157157
- [vapor-community/HTMLKit](https://github.com/vapor-community/HTMLKit) v2.8.1
158158
- [dokun1/Vaux](https://github.com/dokun1/Vaux) v0.2.0 (patched version [here](https://github.com/RandomHashTags/fork-Vaux); custom renderer [here](https://github.com/RandomHashTags/swift-htmlkit/blob/main/Benchmarks/Benchmarks/Vaux/Vaux.swift))
159159

160160
Test machine: iMac (i9 9900k, 72GB RAM, 2TB) running macOS 15.0 with the Swift 6 compiler.
161161

162-
Executed command: `swift package -c release --allow-writing-to-package-directory benchmark --metric throughput --format jmh`
162+
Executed command: `swift package -c release --allow-writing-to-package-directory benchmark --target Benchmarks --metric throughput --format jmh`
163163

164164
### Static
165165
<img src="Benchmarks/img/throughput_static.png">

Sources/HTMLKit/HTMLKit.swift

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,64 @@
77

88
import HTMLKitUtilities
99

10+
// MARK: StaticString equality
1011
public extension StaticString {
1112
static func == (left: Self, right: String) -> Bool { left.string == right }
1213

1314
static func == (left: Self, right: Self) -> Bool { left.string == right.string }
1415
static func != (left: Self, right: Self) -> Bool { left.string != right.string }
15-
var string : String { withUTF8Buffer { String(decoding: $0, as: UTF8.self) } }
16+
var string : String {
17+
withUTF8Buffer {
18+
String(decoding: $0, as: UTF8.self)
19+
}
20+
}
21+
/*func string(with replacements: [String]) -> String {
22+
return withUTF8Buffer { p in
23+
let values = p.split(separator: 96)
24+
let last:Int = values.count-1
25+
var amount:Int = p.count - last
26+
for i in 0..<values.count-1 {
27+
amount += replacements[i].count
28+
}
29+
let buffer:UnsafeMutableBufferPointer<UInt8> = .allocate(capacity: amount)
30+
var new_index:Int = 0
31+
for index in 0..<values.count {
32+
let value:UnsafeBufferPointer<UInt8>.SubSequence = values[index]
33+
for i in 0..<value.count {
34+
buffer[new_index] = value[value.index(value.startIndex, offsetBy: i)]
35+
new_index += 1
36+
}
37+
if index != last {
38+
for char in replacements[index] {
39+
buffer[new_index] = char.asciiValue!
40+
new_index += 1
41+
}
42+
}
43+
}
44+
return String(decoding: buffer, as: UTF8.self)
45+
}
46+
}*/
1647
}
1748
public extension String {
1849
static func == (left: Self, right: StaticString) -> Bool { left == right.string }
1950
}
2051

52+
/*
53+
// MARK: DynamicString
54+
public struct DynamicString {
55+
public let string:StaticString
56+
public let values:[String]
57+
58+
public init(string: StaticString, values: [String]) {
59+
self.string = string
60+
self.values = values
61+
}
62+
63+
public var test : String {
64+
return string.string
65+
}
66+
}*/
67+
2168
@freestanding(expression)
2269
public macro escapeHTML<T: ExpressibleByStringLiteral>(_ innerHTML: T...) -> T = #externalMacro(module: "HTMLKitMacros", type: "HTMLElement")
2370

0 commit comments

Comments
 (0)