aboutsummaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
authorAnhgelus Morhtuuzh <william@herges.fr>2026-04-27 17:45:13 +0200
committerAnhgelus Morhtuuzh <william@herges.fr>2026-04-27 17:45:13 +0200
commit3b0e9424a66058da82d11d432da886ec7b6ce7eb (patch)
tree0ad906e3b7d945405cdfeb9ff95b02546e1ed4bb /src/eval
parentef5c0341ca15f6862294802103b02992b29609e8 (diff)
perf(eval): reduce memory syscall
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/Element.zig43
-rw-r--r--src/eval/Image.zig16
-rw-r--r--src/eval/Root.zig53
-rw-r--r--src/eval/Title.zig12
-rw-r--r--src/eval/blocks.zig26
-rw-r--r--src/eval/list.zig15
-rw-r--r--src/eval/paragraph.zig17
7 files changed, 70 insertions, 112 deletions
diff --git a/src/eval/Element.zig b/src/eval/Element.zig
index 265ccf1..72b6d7d 100644
--- a/src/eval/Element.zig
+++ b/src/eval/Element.zig
@@ -5,6 +5,7 @@ pub const paragraph = @import("paragraph.zig");
pub const Title = @import("Title.zig");
pub const list = @import("list.zig");
pub const Image = @import("Image.zig");
+pub const Root = @import("Root.zig");
const blocks = @import("blocks.zig");
pub const Code = blocks.Code;
pub const Figure = blocks.Figure;
@@ -12,7 +13,6 @@ pub const Figure = blocks.Figure;
const Element = @This();
vtable: struct {
- deinit: *const fn (*anyopaque, Allocator) void,
html: *const fn (*anyopaque, Allocator) HTML.Error!HTML,
},
ptr: *anyopaque,
@@ -24,10 +24,6 @@ pub fn renderHTML(self: Element, alloc: Allocator) HTML.Error![]const u8 {
return el.render(alloc);
}
-pub fn deinit(self: Element, alloc: Allocator) void {
- self.vtable.deinit(self.ptr, alloc);
-}
-
pub fn html(self: Element, alloc: Allocator) HTML.Error!HTML {
return self.vtable.html(self.ptr, alloc);
}
@@ -44,18 +40,7 @@ pub const Empty = struct {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = Self.html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- const self: *Self = @ptrCast(@alignCast(context));
- for (self.content.items) |it| it.deinit(alloc);
- self.content.deinit(alloc);
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = Self.html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
@@ -79,16 +64,7 @@ pub const Literal = struct {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = Self.html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- const self: *Self = @ptrCast(@alignCast(context));
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = Self.html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
@@ -110,11 +86,7 @@ pub fn Simple(comptime tag: []const u8) type {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = Self.html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
+ return .{ .ptr = self, .vtable = .{ .html = Self.html } };
}
pub fn toTag(self: *Self, alloc: Allocator, comptime target: []const u8) !*Simple(target) {
@@ -135,13 +107,6 @@ pub fn Simple(comptime tag: []const u8) type {
alloc.destroy(self);
}
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- var self: *Self = @ptrCast(@alignCast(context));
- for (self.content.items) |it| it.deinit(alloc);
- self.content.deinit(alloc);
- alloc.destroy(self);
- }
-
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
const self: *Self = @ptrCast(@alignCast(context));
var el = try HTML.Content.init(alloc, tag);
diff --git a/src/eval/Image.zig b/src/eval/Image.zig
index aa30585..53478b6 100644
--- a/src/eval/Image.zig
+++ b/src/eval/Image.zig
@@ -17,16 +17,7 @@ pub fn init(alloc: Allocator, src: []const u8) !*Self {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = html } };
-}
-
-pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
-}
-
-fn destroy(context: *anyopaque, alloc: Allocator) void {
- const self: *Self = @ptrCast(@alignCast(context));
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
@@ -38,12 +29,13 @@ fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
}
test "html" {
- const alloc = std.testing.allocator;
+ var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena.deinit();
+ var alloc = arena.allocator();
const expect = std.testing.expect;
const eql = std.mem.eql;
var img = try init(alloc, "foo");
- defer img.deinit(alloc);
const h = try img.element().renderHTML(alloc);
defer alloc.free(h);
try expect(eql(u8, h, "<img src=\"foo\">"));
diff --git a/src/eval/Root.zig b/src/eval/Root.zig
new file mode 100644
index 0000000..1834dd0
--- /dev/null
+++ b/src/eval/Root.zig
@@ -0,0 +1,53 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const Arena = std.heap.ArenaAllocator;
+const HTML = @import("html/Element.zig");
+const Element = @import("Element.zig");
+
+const Self = @This();
+
+content: std.ArrayList(Element),
+arena: Arena,
+
+pub fn init(parent: Allocator) !*Self {
+ var s = Self{
+ .content = undefined,
+ .arena = .init(parent),
+ };
+ var alloc = s.arena.allocator();
+ s.content = try .initCapacity(alloc, 2);
+ const v = try alloc.create(Self);
+ v.* = s;
+ return v;
+}
+
+pub fn deinit(self: *Self) void {
+ self.arena.deinit();
+}
+
+pub fn allocator(self: *Self) Allocator {
+ return self.arena.allocator();
+}
+
+pub fn append(self: *Self, el: Element) !void {
+ try self.content.append(self.allocator(), el);
+}
+
+pub fn element(self: *Self) Element {
+ return .{ .vtable = .{ .html = html }, .ptr = self };
+}
+
+pub fn renderHTML(self: *Self, alloc: Allocator) HTML.Error![]const u8 {
+ return try self.element().renderHTML(alloc);
+}
+
+fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
+ const self: *Self = @ptrCast(@alignCast(context));
+ const el = try HTML.Root.init(alloc);
+ errdefer el.deinit();
+ if (self.content.items.len == 0) return el.element();
+ for (self.content.items) |it| {
+ try el.append(try it.html(el.allocator()));
+ }
+ return el.element();
+}
diff --git a/src/eval/Title.zig b/src/eval/Title.zig
index 2e89953..ebb7fa2 100644
--- a/src/eval/Title.zig
+++ b/src/eval/Title.zig
@@ -15,17 +15,7 @@ pub fn init(alloc: Allocator, level: u3, content: Parent) !*Self {
}
pub fn element(self: *Self) Parent {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = html } };
-}
-
-pub fn deinit(self: *Self, alloc: Allocator) void {
- self.element().deinit(alloc);
-}
-
-fn destroy(context: *anyopaque, alloc: Allocator) void {
- var self: *Self = @ptrCast(@alignCast(context));
- self.content.deinit(alloc);
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
diff --git a/src/eval/blocks.zig b/src/eval/blocks.zig
index 63a8f12..63c0291 100644
--- a/src/eval/blocks.zig
+++ b/src/eval/blocks.zig
@@ -16,18 +16,7 @@ pub const Code = struct {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = Self.html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- var self: *Self = @ptrCast(@alignCast(context));
- for (self.content.items) |it| it.deinit(alloc);
- self.content.deinit(alloc);
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = Self.html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
@@ -54,18 +43,7 @@ pub const Figure = struct {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = Self.html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- const self: *Self = @ptrCast(@alignCast(context));
- self.content.deinit(alloc);
- if (self.caption) |cap| cap.deinit(alloc);
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = Self.html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
diff --git a/src/eval/list.zig b/src/eval/list.zig
index 08f180a..06b7af7 100644
--- a/src/eval/list.zig
+++ b/src/eval/list.zig
@@ -18,21 +18,10 @@ fn List(comptime tag: []const u8) type {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = html } };
+ return .{ .ptr = self, .vtable = .{ .html = html } };
}
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- var self: *Self = @ptrCast(@alignCast(context));
- for (self.content.items) |it| it.deinit(alloc);
- self.content.deinit(alloc);
- alloc.destroy(self);
- }
-
- fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
+ fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
const self: *Self = @ptrCast(@alignCast(context));
var el = try HTML.Content.init(alloc, tag);
for (self.content.items) |it| {
diff --git a/src/eval/paragraph.zig b/src/eval/paragraph.zig
index b076081..e57f995 100644
--- a/src/eval/paragraph.zig
+++ b/src/eval/paragraph.zig
@@ -26,17 +26,7 @@ pub const Link = struct {
}
pub fn element(self: *Self) Element {
- return .{ .ptr = self, .vtable = .{ .deinit = destroy, .html = html } };
- }
-
- pub fn deinit(self: *Self, alloc: Allocator) void {
- destroy(self, alloc);
- }
-
- fn destroy(context: *anyopaque, alloc: Allocator) void {
- var self: *Self = @ptrCast(@alignCast(context));
- self.content.deinit(alloc);
- alloc.destroy(self);
+ return .{ .ptr = self, .vtable = .{ .html = html } };
}
fn html(context: *anyopaque, alloc: Allocator) HTML.Error!HTML {
@@ -59,14 +49,15 @@ fn doTest(alloc: Allocator, el: Element, exp: []const u8) !void {
}
test "paragraph" {
- const alloc = std.testing.allocator;
+ var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena.deinit();
+ const alloc = arena.allocator();
const lit = (try Element.Literal.init(alloc, "hello world")).element();
try doTest(alloc, lit, "hello world");
var p = try Block.init(alloc);
try p.content.append(alloc, lit);
- defer p.deinit(alloc);
try doTest(alloc, p.element(), "<p>hello world</p>");
const link = (try Link.init(alloc, (try Element.Literal.init(alloc, "foo")).element(), "example.org")).element();