From e0dd20b02ea026e125b36b3674f20aa20ff043e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Fri, 17 Mar 2023 18:50:25 +0200 Subject: [PATCH] add BoundedArrayAligned (#14580) This is useful for creating byte buffers of actually-different-things. Copied the argument order from `Allocator.alignedAlloc` I noted that `ArrayListAligned` is going out of it's way to not set the alignment at comptime when it is not specified. However, I was not able to do that the same way here, and good people on IRC, @ifreund in particular (thanks!) assured me that [N]T align(@alignOf(T)) is equivalent to [N]T --- lib/std/bounded_array.zig | 45 +++++++++++++++++++++++++++++++++------ lib/std/std.zig | 1 + 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/lib/std/bounded_array.zig b/lib/std/bounded_array.zig index 5242470631..8a4c2db64b 100644 --- a/lib/std/bounded_array.zig +++ b/lib/std/bounded_array.zig @@ -16,9 +16,30 @@ const testing = std.testing; /// var a_clone = a; // creates a copy - the structure doesn't use any internal pointers /// ``` pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type { + return BoundedArrayAligned(T, @alignOf(T), buffer_capacity); +} + +/// A structure with an array, length and alignment, that can be used as a +/// slice. +/// +/// Useful to pass around small explicitly-aligned arrays whose exact size is +/// only known at runtime, but whose maximum size is known at comptime, without +/// requiring an `Allocator`. +/// ```zig +// var a = try BoundedArrayAligned(u8, 16, 2).init(0); +// try a.append(255); +// try a.append(255); +// const b = @ptrCast(*const [1]u16, a.constSlice().ptr); +// try testing.expectEqual(@as(u16, 65535), b[0]); +/// ``` +pub fn BoundedArrayAligned( + comptime T: type, + comptime alignment: u29, + comptime buffer_capacity: usize, +) type { return struct { const Self = @This(); - buffer: [buffer_capacity]T = undefined, + buffer: [buffer_capacity]T align(alignment) = undefined, len: usize = 0, /// Set the actual length of the slice. @@ -30,15 +51,15 @@ pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type { /// View the internal array as a slice whose size was previously set. pub fn slice(self: anytype) switch (@TypeOf(&self.buffer)) { - *[buffer_capacity]T => []T, - *const [buffer_capacity]T => []const T, + *align(alignment) [buffer_capacity]T => []align(alignment) T, + *align(alignment) const [buffer_capacity]T => []align(alignment) const T, else => unreachable, } { return self.buffer[0..self.len]; } /// View the internal array as a constant slice whose size was previously set. - pub fn constSlice(self: *const Self) []const T { + pub fn constSlice(self: *const Self) []align(alignment) const T { return self.slice(); } @@ -94,7 +115,7 @@ pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type { /// Resize the slice, adding `n` new elements, which have `undefined` values. /// The return value is a slice pointing to the uninitialized elements. - pub fn addManyAsArray(self: *Self, comptime n: usize) error{Overflow}!*[n]T { + pub fn addManyAsArray(self: *Self, comptime n: usize) error{Overflow}!*align(alignment) [n]T { const prev_len = self.len; try self.resize(self.len + n); return self.slice()[prev_len..][0..n]; @@ -118,7 +139,7 @@ pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type { /// This can be useful for writing directly into it. /// Note that such an operation must be followed up with a /// call to `resize()` - pub fn unusedCapacitySlice(self: *Self) []T { + pub fn unusedCapacitySlice(self: *Self) []align(alignment) T { return self.buffer[self.len..]; } @@ -365,3 +386,15 @@ test "BoundedArray" { try w.writeAll(s); try testing.expectEqualStrings(s, a.constSlice()); } + +test "BoundedArrayAligned" { + var a = try BoundedArrayAligned(u8, 16, 4).init(0); + try a.append(0); + try a.append(0); + try a.append(255); + try a.append(255); + + const b = @ptrCast(*const [2]u16, a.constSlice().ptr); + try testing.expectEqual(@as(u16, 0), b[0]); + try testing.expectEqual(@as(u16, 65535), b[1]); +} diff --git a/lib/std/std.zig b/lib/std/std.zig index 92ebdf595b..ef4a6831d0 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -9,6 +9,7 @@ pub const AutoArrayHashMapUnmanaged = array_hash_map.AutoArrayHashMapUnmanaged; pub const AutoHashMap = hash_map.AutoHashMap; pub const AutoHashMapUnmanaged = hash_map.AutoHashMapUnmanaged; pub const BoundedArray = @import("bounded_array.zig").BoundedArray; +pub const BoundedArrayAligned = @import("bounded_array.zig").BoundedArrayAligned; pub const Build = @import("Build.zig"); pub const BufMap = @import("buf_map.zig").BufMap; pub const BufSet = @import("buf_set.zig").BufSet;