From 745a029b9e3f1b0dc045067cc3ce5c3883bc430d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 24 Jun 2026 14:09:30 -0700 Subject: [PATCH 1/2] std: move fmt.allocPrint to Allocator.print --- lib/std/fmt.zig | 16 ++++------------ lib/std/mem/Allocator.zig | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index df762e8fbe7a170ea62820a45a97f148c30d5811..5ddac49ecd6a461411c4db4616142d15b9580ecf 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -622,27 +622,19 @@ pub fn count(comptime fmt: []const u8, args: anytype) usize { return @intCast(dw.count + dw.writer.end); } +/// Deprecated in favor of `Allocator.print`. pub fn allocPrint(gpa: Allocator, comptime fmt: []const u8, args: anytype) Allocator.Error![]u8 { - var aw = try Writer.Allocating.initCapacity(gpa, fmt.len); - defer aw.deinit(); - aw.writer.print(fmt, args) catch |err| switch (err) { - error.WriteFailed => return error.OutOfMemory, - }; - return aw.toOwnedSlice(); + return gpa.print(fmt, args); } +/// Deprecated in favor of `Allocator.printSentinel`. pub fn allocPrintSentinel( gpa: Allocator, comptime fmt: []const u8, args: anytype, comptime sentinel: u8, ) Allocator.Error![:sentinel]u8 { - var aw = try Writer.Allocating.initCapacity(gpa, fmt.len); - defer aw.deinit(); - aw.writer.print(fmt, args) catch |err| switch (err) { - error.WriteFailed => return error.OutOfMemory, - }; - return aw.toOwnedSliceSentinel(sentinel); + return gpa.printSentinel(fmt, args, sentinel); } pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args):0]u8 { diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig index 76e5d11cc46e76cd90aa83601735138367b9d4dd..29eb1ab644bf5b77e0d693bd9aa6cf4f15a92be0 100644 --- a/lib/std/mem/Allocator.zig +++ b/lib/std/mem/Allocator.zig @@ -471,6 +471,42 @@ pub fn dupeSentinel( return new_buf[0..m.len :sentinel]; } +/// Allocates a formatted string which is returned on success. +/// +/// Returned slice can be deallocated with `free`. If an arena-style allocator +/// is used instead, such as `std.heap.ArenaAllocator`, then no call to `free` +/// is necessary. +/// +/// See `std.Io.Writer.print`. +pub fn print(a: Allocator, comptime format: []const u8, args: anytype) Error![]u8 { + var aw = try std.Io.Writer.Allocating.initCapacity(a, format.len); + defer aw.deinit(); + aw.writer.print(format, args) catch |err| switch (err) { + error.WriteFailed => return error.OutOfMemory, + }; + return aw.toOwnedSlice(); +} + +/// Like `print` but returned slice has the provided sentinel. +/// +/// Returned slice can be deallocated with `free`. If an arena-style allocator +/// is used instead, such as `std.heap.ArenaAllocator`, then no call to `free` +/// is necessary. Illegal behavior occurs if the returned slice is type-coerced +/// to a slice without the sentinel and then passed to `free`. +pub fn printSentinel( + a: Allocator, + comptime format: []const u8, + args: anytype, + comptime sentinel: u8, +) Allocator.Error![:sentinel]u8 { + var aw = try std.Io.Writer.Allocating.initCapacity(a, format.len); + defer aw.deinit(); + aw.writer.print(format, args) catch |err| switch (err) { + error.WriteFailed => return error.OutOfMemory, + }; + return aw.toOwnedSliceSentinel(sentinel); +} + /// An allocator that always fails to allocate. pub const failing: Allocator = .{ .ptr = undefined, -- 2.54.0 From 243192c60ec4e1f09042ff3cfd0542972c639566 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 24 Jun 2026 14:15:53 -0700 Subject: [PATCH 2/2] std.mem.Allocator: add unit tests for print and printSentinel --- lib/std/mem/Allocator.zig | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig index 29eb1ab644bf5b77e0d693bd9aa6cf4f15a92be0..bd9cde09d57383eb3d0f1ebde234c8239dc58ed1 100644 --- a/lib/std/mem/Allocator.zig +++ b/lib/std/mem/Allocator.zig @@ -1,11 +1,12 @@ //! The standard memory allocation interface. +const Allocator = @This(); + +const builtin = @import("builtin"); const std = @import("../std.zig"); const assert = std.debug.assert; const math = std.math; const mem = std.mem; -const Allocator = @This(); -const builtin = @import("builtin"); const Alignment = std.mem.Alignment; pub const Error = error{OutOfMemory}; @@ -487,6 +488,15 @@ pub fn print(a: Allocator, comptime format: []const u8, args: anytype) Error![]u return aw.toOwnedSlice(); } +test print { + const x: i32 = -1; + const y: []const u8 = "hi"; + const a = std.testing.allocator; + const s = try print(a, "{d}={s}", .{ x, y }); + defer free(a, s); + try std.testing.expectEqualStrings("-1=hi", s); +} + /// Like `print` but returned slice has the provided sentinel. /// /// Returned slice can be deallocated with `free`. If an arena-style allocator @@ -507,6 +517,16 @@ pub fn printSentinel( return aw.toOwnedSliceSentinel(sentinel); } +test printSentinel { + const x: i32 = -1; + const y: []const u8 = "hi"; + const a = std.testing.allocator; + const s = try printSentinel(a, "{d}={s}", .{ x, y }, 0); + defer free(a, s); + try std.testing.expectEqualStrings("-1=hi", s); + try std.testing.expectEqual(0, s[s.len]); +} + /// An allocator that always fails to allocate. pub const failing: Allocator = .{ .ptr = undefined, -- 2.54.0