terminal/page: improved capacity adjust logic

This commit is contained in:
Qwerasd
2024-03-14 19:16:17 -06:00
committed by Mitchell Hashimoto
parent fd9280429e
commit 9630c39ea4

View File

@ -15,6 +15,7 @@ const BitmapAllocator = @import("bitmap_allocator.zig").BitmapAllocator;
const hash_map = @import("hash_map.zig"); const hash_map = @import("hash_map.zig");
const AutoOffsetHashMap = hash_map.AutoOffsetHashMap; const AutoOffsetHashMap = hash_map.AutoOffsetHashMap;
const alignForward = std.mem.alignForward; const alignForward = std.mem.alignForward;
const alignBackward = std.mem.alignBackward;
/// The allocator to use for multi-codepoint grapheme data. We use /// The allocator to use for multi-codepoint grapheme data. We use
/// a chunk size of 4 codepoints. It'd be best to set this empirically /// a chunk size of 4 codepoints. It'd be best to set this empirically
@ -587,16 +588,39 @@ pub const Capacity = struct {
pub fn adjust(self: Capacity, req: Adjustment) Allocator.Error!Capacity { pub fn adjust(self: Capacity, req: Adjustment) Allocator.Error!Capacity {
var adjusted = self; var adjusted = self;
if (req.cols) |cols| { if (req.cols) |cols| {
// The calculations below only work if cells/rows match size. // The math below only works if there is no alignment gap between
assert(@sizeOf(Cell) == @sizeOf(Row)); // the end of the rows array and the start of the cells array.
//
// To guarantee this, we assert that Row's size is a multiple of
// Cell's alignment, so that any length array of Rows will end on
// a valid alignment for the start of the Cell array.
assert(@sizeOf(Row) % @alignOf(Cell) == 0);
// total_size = (Nrows * sizeOf(Row)) + (Nrows * Ncells * sizeOf(Cell))
// with some algebra:
// Nrows = total_size / (sizeOf(Row) + (Ncells * sizeOf(Cell)))
const layout = Page.layout(self); const layout = Page.layout(self);
const total_size = layout.rows_size + layout.cells_size;
const denom = @sizeOf(Row) + (@sizeOf(Cell) * @as(usize, @intCast(cols))); // In order to determine the amount of space in the page available
const new_rows = @divFloor(total_size, denom); // for rows & cells (which will allow us to calculate the number of
// rows we can fit at a certain column width) we need to layout the
// "meta" members of the page (i.e. everything else) from the end.
const grapheme_map_start = alignBackward(
usize,
layout.total_size - layout.grapheme_map_layout.total_size,
GraphemeMap.base_align
);
const grapheme_alloc_start = alignBackward(
usize,
grapheme_map_start - layout.grapheme_alloc_layout.total_size,
GraphemeAlloc.base_align
);
const styles_start = alignBackward(
usize,
grapheme_alloc_start - layout.styles_layout.total_size,
style.Set.base_align
);
const available_size = styles_start;
const size_per_row = @sizeOf(Row) + (@sizeOf(Cell) * @as(usize, @intCast(cols)));
const new_rows = @divFloor(available_size, size_per_row);
// If our rows go to zero then we can't fit any row metadata // If our rows go to zero then we can't fit any row metadata
// for the desired number of columns. // for the desired number of columns.
@ -606,24 +630,6 @@ pub const Capacity = struct {
adjusted.rows = @intCast(new_rows); adjusted.rows = @intCast(new_rows);
} }
// Adjust our rows so that we have an exact total size count.
// I think we could do this with basic math but my grade school
// algebra skills are failing me and I'm embarassed so please someone
// fix this. This is tested so you can fiddle around.
const old_size = Page.layout(self).total_size;
var new_size = Page.layout(adjusted).total_size;
while (old_size != new_size) {
// Our math above is usually PRETTY CLOSE (like within 1 row)
// so we can just adjust by 1 row at a time.
if (new_size > old_size) {
adjusted.rows -= 1;
} else {
adjusted.rows += 1;
}
new_size = Page.layout(adjusted).total_size;
}
return adjusted; return adjusted;
} }
}; };