diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-04-04 19:22:04 +0300 |
|---|---|---|
| committer | Can Celik <ogulcancelik@gmail.com> | 2026-04-05 01:23:06 +0300 |
| commit | 41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch) | |
| tree | 3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/datastruct/segmented_pool.zig | |
| parent | 55c138263e190a1e79d4b997bfb9397306c0ec1f (diff) | |
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/datastruct/segmented_pool.zig')
| -rw-r--r-- | vendor/libghostty-vt/src/datastruct/segmented_pool.zig | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/datastruct/segmented_pool.zig b/vendor/libghostty-vt/src/datastruct/segmented_pool.zig new file mode 100644 index 00000000..328eb239 --- /dev/null +++ b/vendor/libghostty-vt/src/datastruct/segmented_pool.zig @@ -0,0 +1,95 @@ +const std = @import("std"); +const assert = @import("../quirks.zig").inlineAssert; +const Allocator = std.mem.Allocator; +const testing = std.testing; + +/// A data structure where you can get stable (never copied) pointers to +/// a type that automatically grows if necessary. The values can be "put back" +/// but are expected to be put back IN ORDER. +/// +/// This is implemented specifically for libuv write requests, since the +/// write requests must have a stable pointer and are guaranteed to be processed +/// in order for a single stream. +/// +/// This is NOT thread safe. +pub fn SegmentedPool(comptime T: type, comptime prealloc: usize) type { + return struct { + const Self = @This(); + + i: usize = 0, + available: usize = prealloc, + list: std.SegmentedList(T, prealloc) = .{ .len = prealloc }, + + pub fn deinit(self: *Self, alloc: Allocator) void { + self.list.deinit(alloc); + self.* = undefined; + } + + /// Get the next available value out of the list. This will not + /// grow the list. + pub fn get(self: *Self) !*T { + // Error to not have any + if (self.available == 0) return error.OutOfValues; + + // The index we grab is just i % len, so we wrap around to the front. + const i = @mod(self.i, self.list.len); + self.i +%= 1; // Wrapping addition to swe go back to 0 + self.available -= 1; + return self.list.at(i); + } + + /// Get the next available value out of the list and grow the list + /// if necessary. + pub fn getGrow(self: *Self, alloc: Allocator) !*T { + if (self.available == 0) try self.grow(alloc); + return try self.get(); + } + + fn grow(self: *Self, alloc: Allocator) !void { + try self.list.growCapacity(alloc, self.list.len * 2); + self.i = self.list.len; + self.available = self.list.len; + self.list.len *= 2; + } + + /// Put a value back. The value put back is expected to be the + /// in order of get. + pub fn put(self: *Self) void { + self.available += 1; + assert(self.available <= self.list.len); + } + }; +} + +test "SegmentedPool" { + var list: SegmentedPool(u8, 2) = .{}; + defer list.deinit(testing.allocator); + try testing.expectEqual(@as(usize, 2), list.available); + + // Get to capacity + const v1 = try list.get(); + const v2 = try list.get(); + try testing.expect(v1 != v2); + try testing.expectError(error.OutOfValues, list.get()); + + // Test writing for later + v1.* = 42; + + // Put a value back + list.put(); + const temp = try list.get(); + try testing.expect(v1 == temp); + try testing.expect(temp.* == 42); + try testing.expectError(error.OutOfValues, list.get()); + + // Grow + const v3 = try list.getGrow(testing.allocator); + try testing.expect(v1 != v3 and v2 != v3); + _ = try list.get(); + try testing.expectError(error.OutOfValues, list.get()); + + // Put a value back + list.put(); + try testing.expect(v1 == try list.get()); + try testing.expectError(error.OutOfValues, list.get()); +} |
