terminal: clone uses opts struct

This commit is contained in:
Mitchell Hashimoto
2024-03-09 19:21:35 -08:00
parent fdbda5365e
commit 45c38c6d8b
2 changed files with 78 additions and 53 deletions

View File

@ -243,6 +243,21 @@ pub fn deinit(self: *PageList) void {
} }
} }
pub const Clone = struct {
/// The top and bottom (inclusive) points of the region to clone.
/// The x coordinate is ignored; the full row is always cloned.
top: point.Point,
bot: ?point.Point = null,
/// The allocator source for the clone operation. If this is alloc
/// then the cloned pagelist will own and dealloc the memory on deinit.
/// If this is pool then the caller owns the memory.
memory: union(enum) {
alloc: Allocator,
pool: *MemoryPool,
},
};
/// Clone this pagelist from the top to bottom (inclusive). /// Clone this pagelist from the top to bottom (inclusive).
/// ///
/// The viewport is always moved to the top-left. /// The viewport is always moved to the top-left.
@ -252,36 +267,37 @@ pub fn deinit(self: *PageList) void {
/// rows will be added to the bottom of the region to make up the difference. /// rows will be added to the bottom of the region to make up the difference.
pub fn clone( pub fn clone(
self: *const PageList, self: *const PageList,
alloc: Allocator, opts: Clone,
top: point.Point,
bot: ?point.Point,
) !PageList { ) !PageList {
// First, count our pages so our preheat is exactly what we need. var it = self.pageIterator(.right_down, opts.top, opts.bot);
var it = self.pageIterator(.right_down, top, bot);
const page_count: usize = page_count: { // Setup our own memory pool if we have to.
var count: usize = 0; var owned_pool: ?MemoryPool = switch (opts.memory) {
while (it.next()) |_| count += 1; .pool => null,
break :page_count count; .alloc => |alloc| alloc: {
// First, count our pages so our preheat is exactly what we need.
var it_copy = it;
const page_count: usize = page_count: {
var count: usize = 0;
while (it_copy.next()) |_| count += 1;
break :page_count count;
};
// Setup our pools
break :alloc try MemoryPool.init(
alloc,
std.heap.page_allocator,
page_count,
);
},
}; };
errdefer if (owned_pool) |*pool| pool.deinit();
// Setup our pools // Create our memory pool we use
var pool = try MemoryPool.init(alloc, std.heap.page_allocator, page_count); const pool: *MemoryPool = switch (opts.memory) {
errdefer pool.deinit(); .pool => |v| v,
.alloc => &owned_pool.?,
var result = try self.clonePool(&pool, top, bot); };
result.pool_owned = true;
return result;
}
/// Like clone, but specify your own memory pool. This is advanced but
/// lets you avoid expensive syscalls to allocate memory.
pub fn clonePool(
self: *const PageList,
pool: *MemoryPool,
top: point.Point,
bot: ?point.Point,
) !PageList {
var it = self.pageIterator(.right_down, top, bot);
// Copy our pages // Copy our pages
var page_list: List = .{}; var page_list: List = .{};
@ -333,7 +349,10 @@ pub fn clonePool(
var result: PageList = .{ var result: PageList = .{
.pool = pool.*, .pool = pool.*,
.pool_owned = false, .pool_owned = switch (opts.memory) {
.pool => false,
.alloc => true,
},
.pages = page_list, .pages = page_list,
.page_size = PagePool.item_size * page_count, .page_size = PagePool.item_size * page_count,
.max_size = self.max_size, .max_size = self.max_size,
@ -3272,7 +3291,10 @@ test "PageList clone" {
defer s.deinit(); defer s.deinit();
try testing.expectEqual(@as(usize, s.rows), s.totalRows()); try testing.expectEqual(@as(usize, s.rows), s.totalRows());
var s2 = try s.clone(alloc, .{ .screen = .{} }, null); var s2 = try s.clone(.{
.top = .{ .screen = .{} },
.memory = .{ .alloc = alloc },
});
defer s2.deinit(); defer s2.deinit();
try testing.expectEqual(@as(usize, s.rows), s2.totalRows()); try testing.expectEqual(@as(usize, s.rows), s2.totalRows());
} }
@ -3286,11 +3308,11 @@ test "PageList clone partial trimmed right" {
try testing.expectEqual(@as(usize, s.rows), s.totalRows()); try testing.expectEqual(@as(usize, s.rows), s.totalRows());
try s.growRows(30); try s.growRows(30);
var s2 = try s.clone( var s2 = try s.clone(.{
alloc, .top = .{ .screen = .{} },
.{ .screen = .{} }, .bot = .{ .screen = .{ .y = 39 } },
.{ .screen = .{ .y = 39 } }, .memory = .{ .alloc = alloc },
); });
defer s2.deinit(); defer s2.deinit();
try testing.expectEqual(@as(usize, 40), s2.totalRows()); try testing.expectEqual(@as(usize, 40), s2.totalRows());
} }
@ -3304,11 +3326,10 @@ test "PageList clone partial trimmed left" {
try testing.expectEqual(@as(usize, s.rows), s.totalRows()); try testing.expectEqual(@as(usize, s.rows), s.totalRows());
try s.growRows(30); try s.growRows(30);
var s2 = try s.clone( var s2 = try s.clone(.{
alloc, .top = .{ .screen = .{ .y = 10 } },
.{ .screen = .{ .y = 10 } }, .memory = .{ .alloc = alloc },
null, });
);
defer s2.deinit(); defer s2.deinit();
try testing.expectEqual(@as(usize, 40), s2.totalRows()); try testing.expectEqual(@as(usize, 40), s2.totalRows());
} }
@ -3322,11 +3343,11 @@ test "PageList clone partial trimmed both" {
try testing.expectEqual(@as(usize, s.rows), s.totalRows()); try testing.expectEqual(@as(usize, s.rows), s.totalRows());
try s.growRows(30); try s.growRows(30);
var s2 = try s.clone( var s2 = try s.clone(.{
alloc, .top = .{ .screen = .{ .y = 10 } },
.{ .screen = .{ .y = 10 } }, .bot = .{ .screen = .{ .y = 35 } },
.{ .screen = .{ .y = 35 } }, .memory = .{ .alloc = alloc },
); });
defer s2.deinit(); defer s2.deinit();
try testing.expectEqual(@as(usize, 26), s2.totalRows()); try testing.expectEqual(@as(usize, 26), s2.totalRows());
} }
@ -3339,11 +3360,10 @@ test "PageList clone less than active" {
defer s.deinit(); defer s.deinit();
try testing.expectEqual(@as(usize, s.rows), s.totalRows()); try testing.expectEqual(@as(usize, s.rows), s.totalRows());
var s2 = try s.clone( var s2 = try s.clone(.{
alloc, .top = .{ .active = .{ .y = 5 } },
.{ .active = .{ .y = 5 } }, .memory = .{ .alloc = alloc },
null, });
);
defer s2.deinit(); defer s2.deinit();
try testing.expectEqual(@as(usize, s.rows), s2.totalRows()); try testing.expectEqual(@as(usize, s.rows), s2.totalRows());
} }

View File

@ -216,10 +216,15 @@ pub fn clonePool(
top: point.Point, top: point.Point,
bot: ?point.Point, bot: ?point.Point,
) !Screen { ) !Screen {
var pages = if (pool) |p| var pages = try self.pages.clone(.{
try self.pages.clonePool(p, top, bot) .top = top,
else .bot = bot,
try self.pages.clone(alloc, top, bot); .memory = if (pool) |p| .{
.pool = p,
} else .{
.alloc = alloc,
},
});
errdefer pages.deinit(); errdefer pages.deinit();
return .{ return .{