| ... | ... | @@ -19,7 +19,11 @@ const testing = std.testing; |
| 19 | 19 | /// For unions you can call `.items(.tags)` or `.items(.data)`. |
| 20 | 20 | pub fn MultiArrayList(comptime T: type) type { |
| 21 | 21 | return struct { |
| 22 | | bytes: [*]align(@alignOf(T)) u8 = undefined, |
| 22 | /// This pointer is always aligned to the boundary `sizes.big_align`; this is not specified |
| 23 | /// in the type to avoid `MultiArrayList(T)` depending on the alignment of `T` because this |
| 24 | /// can lead to dependency loops. See `allocatedBytes` which `@alignCast`s this pointer to |
| 25 | /// the correct type. |
| 26 | bytes: [*]u8 = undefined, |
| 23 | 27 | len: usize = 0, |
| 24 | 28 | capacity: usize = 0, |
| 25 | 29 | |
| ... | ... | @@ -133,10 +137,8 @@ pub fn MultiArrayList(comptime T: type) type { |
| 133 | 137 | if (self.ptrs.len == 0 or self.capacity == 0) { |
| 134 | 138 | return .{}; |
| 135 | 139 | } |
| 136 | | const unaligned_ptr = self.ptrs[sizes.fields[0]]; |
| 137 | | const aligned_ptr: [*]align(@alignOf(Elem)) u8 = @alignCast(unaligned_ptr); |
| 138 | 140 | return .{ |
| 139 | | .bytes = aligned_ptr, |
| 141 | .bytes = self.ptrs[sizes.fields[0]], |
| 140 | 142 | .len = self.len, |
| 141 | 143 | .capacity = self.capacity, |
| 142 | 144 | }; |
| ... | ... | @@ -179,6 +181,7 @@ pub fn MultiArrayList(comptime T: type) type { |
| 179 | 181 | const fields = meta.fields(Elem); |
| 180 | 182 | /// `sizes.bytes` is an array of @sizeOf each T field. Sorted by alignment, descending. |
| 181 | 183 | /// `sizes.fields` is an array mapping from `sizes.bytes` array index to field index. |
| 184 | /// `sizes.big_align` is the overall alignment of the allocation, which equals the maximum field alignment. |
| 182 | 185 | const sizes = blk: { |
| 183 | 186 | const Data = struct { |
| 184 | 187 | size: usize, |
| ... | ... | @@ -186,12 +189,14 @@ pub fn MultiArrayList(comptime T: type) type { |
| 186 | 189 | alignment: usize, |
| 187 | 190 | }; |
| 188 | 191 | var data: [fields.len]Data = undefined; |
| 192 | var big_align: usize = 1; |
| 189 | 193 | for (fields, 0..) |field_info, i| { |
| 190 | 194 | data[i] = .{ |
| 191 | 195 | .size = @sizeOf(field_info.type), |
| 192 | 196 | .size_index = i, |
| 193 | 197 | .alignment = if (@sizeOf(field_info.type) == 0) 1 else field_info.alignment, |
| 194 | 198 | }; |
| 199 | big_align = @max(big_align, @alignOf(field_info.type)); |
| 195 | 200 | } |
| 196 | 201 | const Sort = struct { |
| 197 | 202 | fn lessThan(context: void, lhs: Data, rhs: Data) bool { |
| ... | ... | @@ -210,6 +215,7 @@ pub fn MultiArrayList(comptime T: type) type { |
| 210 | 215 | break :blk .{ |
| 211 | 216 | .bytes = sizes_bytes, |
| 212 | 217 | .fields = field_indexes, |
| 218 | .big_align = mem.Alignment.fromByteUnits(big_align), |
| 213 | 219 | }; |
| 214 | 220 | }; |
| 215 | 221 | |
| ... | ... | @@ -452,7 +458,7 @@ pub fn MultiArrayList(comptime T: type) type { |
| 452 | 458 | assert(new_len <= self.capacity); |
| 453 | 459 | assert(new_len <= self.len); |
| 454 | 460 | |
| 455 | | const other_bytes = gpa.alignedAlloc(u8, .of(Elem), capacityInBytes(new_len)) catch { |
| 461 | const other_bytes = gpa.alignedAlloc(u8, sizes.big_align, capacityInBytes(new_len)) catch { |
| 456 | 462 | const self_slice = self.slice(); |
| 457 | 463 | inline for (fields, 0..) |field_info, i| { |
| 458 | 464 | if (@sizeOf(field_info.type) != 0) { |
| ... | ... | @@ -533,7 +539,7 @@ pub fn MultiArrayList(comptime T: type) type { |
| 533 | 539 | /// `new_capacity` must be greater or equal to `len`. |
| 534 | 540 | pub fn setCapacity(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void { |
| 535 | 541 | assert(new_capacity >= self.len); |
| 536 | | const new_bytes = try gpa.alignedAlloc(u8, .of(Elem), capacityInBytes(new_capacity)); |
| 542 | const new_bytes = try gpa.alignedAlloc(u8, sizes.big_align, capacityInBytes(new_capacity)); |
| 537 | 543 | if (self.len == 0) { |
| 538 | 544 | gpa.free(self.allocatedBytes()); |
| 539 | 545 | self.bytes = new_bytes.ptr; |
| ... | ... | @@ -650,8 +656,8 @@ pub fn MultiArrayList(comptime T: type) type { |
| 650 | 656 | return elem_bytes * capacity; |
| 651 | 657 | } |
| 652 | 658 | |
| 653 | | fn allocatedBytes(self: Self) []align(@alignOf(Elem)) u8 { |
| 654 | | return self.bytes[0..capacityInBytes(self.capacity)]; |
| 659 | fn allocatedBytes(self: Self) []align(sizes.big_align.toByteUnits()) u8 { |
| 660 | return @alignCast(self.bytes[0..capacityInBytes(self.capacity)]); |
| 655 | 661 | } |
| 656 | 662 | |
| 657 | 663 | fn FieldType(comptime field: Field) type { |