I have an ArrayList([]const u8). I pass a pointer to it into functions that append to it. They append the results of calls to std.fmt.allocPrint(). To free everything up, the top-level function deinits the ArrayList after it frees all the items:
var typeLines = std.ArrayList([]const u8).init(allocator);
defer typeLines.deinit();
defer for (typeLines.items) |line| {
allocator.free(line);
};
This works. But I have some cases now where the called functions should append constant strings. So I can't simply loop through the items and free them all.
I've thought about checking each item's type to see if I need to free it, or maybe keeping a separate ArrayList of just the items that need to be freed. What's the idiomatic way to identify which items need to be freed?
I think an ArenaAllocator
would be the best solution here.
It essentially stores all allocations in bigger buffers and can free these all at once. So you don't need to free elements individually, and you don't need to check if you allocated them.
var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit();
var typeLines = std.ArrayList(Line).init(allocator);
defer typeLines.deinit();
...
var s = try std.fmt.allocPrint(arena.allocator(), "\npub const {s} = struct {{\n", .{typeName});
try typeLines.append(s);
try typeLines.append("\n};\n");