authorgravatar for john@whatisaph.oneJohn Simon <john@whatisaph.one> 2023-07-03 13:58:03-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-03 13:58:03-04:00
logcb5a6be41ae0efc30d0b59a41b0763db966e5bf4
treede3aab2fde99c566c05865e57cbc0b4b7ad71471
parent28ad74e8a6ed3484d632a6a615f5d0935c03676a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Smaller memory footprint for BoundedArray (#16299)

Store BoundedArray's length using the smallest possible integer Co-authored-by: zooster <r00ster91@proton.me>

1 files changed, 22 insertions(+), 8 deletions(-)

lib/std/bounded_array.zig+22-8
...@@ -39,14 +39,16 @@ pub fn BoundedArrayAligned(...@@ -39,14 +39,16 @@ pub fn BoundedArrayAligned(
39) type {39) type {
40 return struct {40 return struct {
41 const Self = @This();41 const Self = @This();
42 const Len = std.math.IntFittingRange(0, buffer_capacity);
43
42 buffer: [buffer_capacity]T align(alignment) = undefined,44 buffer: [buffer_capacity]T align(alignment) = undefined,
43 len: usize = 0,45 len: Len = 0,
4446
45 /// Set the actual length of the slice.47 /// Set the actual length of the slice.
46 /// Returns error.Overflow if it exceeds the length of the backing array.48 /// Returns error.Overflow if it exceeds the length of the backing array.
47 pub fn init(len: usize) error{Overflow}!Self {49 pub fn init(len: usize) error{Overflow}!Self {
48 if (len > buffer_capacity) return error.Overflow;50 if (len > buffer_capacity) return error.Overflow;
49 return Self{ .len = len };51 return Self{ .len = @intCast(len) };
50 }52 }
5153
52 /// View the internal array as a slice whose size was previously set.54 /// View the internal array as a slice whose size was previously set.
...@@ -67,7 +69,7 @@ pub fn BoundedArrayAligned(...@@ -67,7 +69,7 @@ pub fn BoundedArrayAligned(
67 /// Does not initialize added items if any.69 /// Does not initialize added items if any.
68 pub fn resize(self: *Self, len: usize) error{Overflow}!void {70 pub fn resize(self: *Self, len: usize) error{Overflow}!void {
69 if (len > buffer_capacity) return error.Overflow;71 if (len > buffer_capacity) return error.Overflow;
70 self.len = len;72 self.len = @intCast(len);
71 }73 }
7274
73 /// Copy the content of an existing slice.75 /// Copy the content of an existing slice.
...@@ -163,7 +165,7 @@ pub fn BoundedArrayAligned(...@@ -163,7 +165,7 @@ pub fn BoundedArrayAligned(
163 /// This operation is O(N).165 /// This operation is O(N).
164 pub fn insertSlice(self: *Self, i: usize, items: []const T) error{Overflow}!void {166 pub fn insertSlice(self: *Self, i: usize, items: []const T) error{Overflow}!void {
165 try self.ensureUnusedCapacity(items.len);167 try self.ensureUnusedCapacity(items.len);
166 self.len += items.len;168 self.len = @intCast(self.len + items.len);
167 mem.copyBackwards(T, self.slice()[i + items.len .. self.len], self.constSlice()[i .. self.len - items.len]);169 mem.copyBackwards(T, self.slice()[i + items.len .. self.len], self.constSlice()[i .. self.len - items.len]);
168 @memcpy(self.slice()[i..][0..items.len], items);170 @memcpy(self.slice()[i..][0..items.len], items);
169 }171 }
...@@ -193,7 +195,7 @@ pub fn BoundedArrayAligned(...@@ -193,7 +195,7 @@ pub fn BoundedArrayAligned(
193 for (self.constSlice()[after_range..], 0..) |item, i| {195 for (self.constSlice()[after_range..], 0..) |item, i| {
194 self.slice()[after_subrange..][i] = item;196 self.slice()[after_subrange..][i] = item;
195 }197 }
196 self.len -= len - new_items.len;198 self.len = @intCast(self.len - len + new_items.len);
197 }199 }
198 }200 }
199201
...@@ -244,7 +246,7 @@ pub fn BoundedArrayAligned(...@@ -244,7 +246,7 @@ pub fn BoundedArrayAligned(
244 /// enough to store the new items.246 /// enough to store the new items.
245 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {247 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
246 const old_len = self.len;248 const old_len = self.len;
247 self.len += items.len;249 self.len = @intCast(self.len + items.len);
248 @memcpy(self.slice()[old_len..][0..items.len], items);250 @memcpy(self.slice()[old_len..][0..items.len], items);
249 }251 }
250252
...@@ -260,8 +262,8 @@ pub fn BoundedArrayAligned(...@@ -260,8 +262,8 @@ pub fn BoundedArrayAligned(
260 /// Asserts the capacity is enough.262 /// Asserts the capacity is enough.
261 pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {263 pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
262 const old_len = self.len;264 const old_len = self.len;
263 self.len += n;265 assert(self.len + n <= buffer_capacity);
264 assert(self.len <= buffer_capacity);266 self.len = @intCast(self.len + n);
265 @memset(self.slice()[old_len..self.len], value);267 @memset(self.slice()[old_len..self.len], value);
266 }268 }
267269
...@@ -387,6 +389,18 @@ test "BoundedArray" {...@@ -387,6 +389,18 @@ test "BoundedArray" {
387 try testing.expectEqualStrings(s, a.constSlice());389 try testing.expectEqualStrings(s, a.constSlice());
388}390}
389391
392test "BoundedArray sizeOf" {
393 // Just sanity check size on one CPU
394 if (@import("builtin").cpu.arch != .x86_64)
395 return;
396
397 try testing.expectEqual(@sizeOf(BoundedArray(u8, 3)), 4);
398
399 // `len` is the minimum required size to hold the maximum capacity
400 try testing.expectEqual(@TypeOf(@as(BoundedArray(u8, 15), undefined).len), u4);
401 try testing.expectEqual(@TypeOf(@as(BoundedArray(u8, 16), undefined).len), u5);
402}
403
390test "BoundedArrayAligned" {404test "BoundedArrayAligned" {
391 var a = try BoundedArrayAligned(u8, 16, 4).init(0);405 var a = try BoundedArrayAligned(u8, 16, 4).init(0);
392 try a.append(0);406 try a.append(0);