use arena allocator for cli commands
This commit is contained in:
parent
f5432c83b8
commit
72632344ee
1 changed files with 30 additions and 8 deletions
38
src/main.zig
38
src/main.zig
|
|
@ -145,12 +145,15 @@ fn resolveUserPath(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() !u8 {
|
pub fn main() !u8 {
|
||||||
|
// Long-lived allocator for things that span the whole process. Only
|
||||||
|
// actually used for the early argsAlloc and the TUI path — CLI
|
||||||
|
// commands run under a per-invocation arena (see below).
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
defer _ = gpa.deinit();
|
defer _ = gpa.deinit();
|
||||||
const allocator = gpa.allocator();
|
const gpa_alloc = gpa.allocator();
|
||||||
|
|
||||||
const args = try std.process.argsAlloc(allocator);
|
const args = try std.process.argsAlloc(gpa_alloc);
|
||||||
defer std.process.argsFree(allocator, args);
|
defer std.process.argsFree(gpa_alloc, args);
|
||||||
|
|
||||||
// Single buffered writer for all stdout output
|
// Single buffered writer for all stdout output
|
||||||
var stdout_buf: [4096]u8 = undefined;
|
var stdout_buf: [4096]u8 = undefined;
|
||||||
|
|
@ -194,19 +197,38 @@ pub fn main() !u8 {
|
||||||
|
|
||||||
const color = @import("format.zig").shouldUseColor(globals.no_color);
|
const color = @import("format.zig").shouldUseColor(globals.no_color);
|
||||||
|
|
||||||
var config = zfin.Config.fromEnv(allocator);
|
|
||||||
defer config.deinit();
|
|
||||||
|
|
||||||
const command = args[globals.cursor];
|
const command = args[globals.cursor];
|
||||||
const cmd_args = args[globals.cursor + 1 ..];
|
const cmd_args = args[globals.cursor + 1 ..];
|
||||||
|
|
||||||
// Interactive TUI -- delegates to the TUI module (owns its own DataService).
|
// Interactive TUI: long-lived, per-frame allocations benefit from a
|
||||||
|
// real (non-arena) allocator. Runs against `gpa` directly.
|
||||||
if (std.mem.eql(u8, command, "interactive") or std.mem.eql(u8, command, "i")) {
|
if (std.mem.eql(u8, command, "interactive") or std.mem.eql(u8, command, "i")) {
|
||||||
|
var tui_config = zfin.Config.fromEnv(gpa_alloc);
|
||||||
|
defer tui_config.deinit();
|
||||||
try out.flush();
|
try out.flush();
|
||||||
try tui.run(allocator, config, globals.portfolio_path, globals.watchlist_path, cmd_args);
|
try tui.run(gpa_alloc, tui_config, globals.portfolio_path, globals.watchlist_path, cmd_args);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Per-invocation arena ─────────────────────────────────────
|
||||||
|
//
|
||||||
|
// CLI commands do a batch of work then exit. Almost every allocation
|
||||||
|
// they make has the same lifetime (the invocation). An arena matched
|
||||||
|
// to that unit gives us three wins: skip per-allocation bookkeeping,
|
||||||
|
// ignore all the per-object `defer X.deinit()` calls (they become
|
||||||
|
// no-ops but remain correct code if the function is ever called from
|
||||||
|
// a non-arena context), and avoid gpa's leak-checking overhead for
|
||||||
|
// ephemeral state we're about to discard anyway.
|
||||||
|
//
|
||||||
|
// See models/portfolio.zig for the "match the arena to the unit of
|
||||||
|
// work" principle. Here the unit is one `zfin <subcommand>`.
|
||||||
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
|
var config = zfin.Config.fromEnv(allocator);
|
||||||
|
defer config.deinit();
|
||||||
|
|
||||||
// Version: doesn't need DataService; uses build_info + Config paths.
|
// Version: doesn't need DataService; uses build_info + Config paths.
|
||||||
if (std.mem.eql(u8, command, "version")) {
|
if (std.mem.eql(u8, command, "version")) {
|
||||||
commands.version.run(config, cmd_args, out) catch |err| switch (err) {
|
commands.version.run(config, cmd_args, out) catch |err| switch (err) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue