Fix parallel stack bugs

This commit is contained in:
kayomn 2025-08-27 17:51:22 +01:00
parent 9b0368a568
commit 3ddf351a08

View File

@ -61,7 +61,10 @@ fn Generic(comptime Item: type, comptime Storage: type) type {
pub fn pushAll(self: *Self, items: []const Item) bool {
const new_len = self.items.len + items.len;
if (new_len < self.cap) {
if (new_len > self.items.cap) {
return false;
}
const index = self.items.len;
self.items.len = new_len;
@ -71,9 +74,6 @@ fn Generic(comptime Item: type, comptime Storage: type) type {
return true;
}
return false;
}
pub fn pushGrow(self: *Self, allocator: std.mem.Allocator, item: Item) std.mem.Allocator.Error!void {
if (self.isFull()) {
try self.items.grow(allocator, @max(1, self.items.cap));
@ -99,6 +99,16 @@ fn Generic(comptime Item: type, comptime Storage: type) type {
return true;
}
pub fn set(self: *Self, item: Item) bool {
if (self.isEmpty()) {
return false;
}
std.debug.assert(self.items.set(self.items.len - 1, item));
return true;
}
};
}
@ -109,8 +119,7 @@ pub fn Parallel(comptime Item: type) type {
};
const item_align = @alignOf(Item);
const item_size = @sizeOf(usize);
const byte_size = @sizeOf(u8);
const item_size = @sizeOf(Item);
return Generic(Item, struct {
ptr: [*]align(item_align) u8 = undefined,
@ -130,7 +139,7 @@ pub fn Parallel(comptime Item: type) type {
}
pub fn get(self: Self, index: usize) ?Item {
if (index >= self.cap) {
if (index >= self.len) {
return null;
}
@ -139,29 +148,52 @@ pub fn Parallel(comptime Item: type) type {
inline for (item_fields) |item_field| {
@field(item, item_field.name) = @as([*]item_field.type, @ptrCast(@alignCast(ptr)))[index];
ptr += @sizeOf(item_field.type) * self.len;
ptr += @sizeOf(item_field.type) * self.cap;
}
return item;
}
pub fn grow(self: *Self, allocator: std.mem.Allocator, amount: usize) std.mem.Allocator.Error!void {
const new_cap = std.math.cast(u32, @as(usize, self.cap + amount)) orelse {
const old_cap = self.cap;
const new_cap = std.math.cast(u32, @as(usize, old_cap) + amount) orelse {
return error.OutOfMemory;
};
const reallocation = try allocator.alignedAlloc(u8, item_align, byte_size * new_cap);
const len_in_bytes = byte_size * self.len;
if (new_cap != 0) {
const new_allocation = try allocator.alignedAlloc(u8, item_align, item_size * new_cap);
@memcpy(reallocation[0..len_in_bytes], self.ptr[0..len_in_bytes]);
allocator.free(self.ptr[0 .. byte_size * self.cap]);
errdefer {
allocator.free(new_allocation);
}
self.ptr = reallocation.ptr;
self.cap = @intCast(new_cap);
if (old_cap != 0) {
var old_ptr_offset: usize = 0;
var new_ptr_offset: usize = 0;
inline for (item_fields) |field| {
const FieldType = field.type;
const old_field_ptr: [*]const FieldType = @ptrCast(@alignCast(self.ptr + old_ptr_offset));
const new_field_ptr: [*]FieldType = @ptrCast(@alignCast(new_allocation.ptr + new_ptr_offset));
@memcpy(new_field_ptr[0..self.len], old_field_ptr[0..self.len]);
old_ptr_offset += @sizeOf(FieldType) * old_cap;
new_ptr_offset += @sizeOf(FieldType) * new_cap;
}
// Free the old allocation
allocator.free(self.ptr[0 .. item_size * old_cap]);
}
self.ptr = new_allocation.ptr;
self.cap = new_cap;
}
}
pub fn set(self: Self, index: usize, item: Item) bool {
if (index >= self.cap) {
if (index >= self.len) {
return false;
}
@ -169,7 +201,7 @@ pub fn Parallel(comptime Item: type) type {
inline for (item_fields) |item_field| {
@as([*]item_field.type, @ptrCast(@alignCast(ptr)))[index] = @field(item, item_field.name);
ptr += @sizeOf(item_field.type) * self.len;
ptr += @sizeOf(item_field.type) * self.cap;
}
return true;
@ -180,7 +212,7 @@ pub fn Parallel(comptime Item: type) type {
var ptr: [*]u8 = self.ptr;
inline for (item_fields[0..field_index]) |item_field| {
ptr += @sizeOf(item_field.type) * self.len;
ptr += @sizeOf(item_field.type) * self.cap;
}
return @as([*]item_fields[field_index].type, @ptrCast(@alignCast(ptr)))[0..self.len];