diff --git a/src/grome/matrix.zig b/src/grome/matrix.zig index 2ee7588..f0915c7 100644 --- a/src/grome/matrix.zig +++ b/src/grome/matrix.zig @@ -12,6 +12,13 @@ pub const Point = struct { pub fn index(self: *const Point, width: usize) usize { return (self.y * width) + self.x; } + + pub fn bottom_right(self: *const Point, area: Rect) Point { + return .{ + .x = self.x + area.width, + .y = self.y + area.height, + }; + } }; /// Rect is a rectangle @@ -69,8 +76,8 @@ pub fn Matrix(comptime T: type) type { } /// submatrix returns a [SubMatrix] - pub fn submatrix(self: *@This(), gpa: Allocator, loc: Point, area: Rect) !SubMatrix(T) { - return SubMatrix(T).init(gpa, self, loc, area); + pub fn submatrix(self: *@This(), loc: Point, area: Rect) SubMatrix(T) { + return SubMatrix(T).init(self, loc, area); } }; } @@ -135,37 +142,35 @@ test "TestRowIterator" { pub fn SubMatrix(comptime T: type) type { return struct { // Data is made up of different sections of the - _data: [][]T, + _m: *Matrix(T), + // the width of the submatrix + _width: usize, + // _index defines where we are in the byte slice + _index: usize, + // Where we stop iterating + _endingIndex: usize, /// init takes the underlying data from the upstream matrix and creates /// a submatrix of it - pub fn init(gpa: Allocator, m: *Matrix(T), loc: Point, size: Rect) !@This() { - var subData = try gpa.alloc([]T, size.height); - var index = loc.index(m.size.width); + pub fn init(m: *Matrix(T), loc: Point, size: Rect) @This() { + return .{ ._m = m, ._index = loc.index(m.size.width), ._endingIndex = loc.bottom_right(size).index(m.size.width), ._width = size.width }; + } - for (0..size.height) |x| { - const ending_index = index + size.width; - subData[x] = m.data[index..ending_index]; - index += m.size.width; + // jump moves the pointer forward + pub fn skip(self: *@This(), rows: usize) void { + self._index += self._m.size.width * rows; + } + + pub fn next(self: *@This()) ?[]T { + if (self._endingIndex <= self._index) { + return null; } - return .{ - ._data = subData, - }; - } + defer { + self._index += self._m.size.width; + } - pub fn deinit(self: *@This(), gpa: Allocator) void { - gpa.free(self._data); - } - - /// get returns the type in the specified point - pub fn get(self: *const @This(), loc: Point) T { - return self._data[loc.y][loc.x]; - } - - /// set sets the value of the specified point - pub fn set(self: *@This(), loc: Point, val: T) void { - self._data[loc.y][loc.x] = val; + return self._m.data[self._index .. self._index + self._width]; } }; } @@ -174,15 +179,15 @@ test "SubMatrix" { const testing = std.testing; // create our matrix and submatrix - var m = try Matrix(u64).initZero(testing.allocator, .{ .height = 10, .width = 10 }); + var m = try Matrix(u8).initZero(testing.allocator, .{ .height = 10, .width = 10 }); defer m.deinit(testing.allocator); - var sub = try m.submatrix(testing.allocator, .{ .x = 4, .y = 4 }, .{ .height = 5, .width = 5 }); - defer sub.deinit(testing.allocator); + var sub = m.submatrix(.{ .x = 4, .y = 4 }, .{ .height = 5, .width = 5 }); // set the value - sub.set(.{ .x = 0, .y = 0 }, 100); + if (sub.next()) |row| { + row[0] = 'a'; + } - // it should be set in both locations - try testing.expectEqual(100, sub.get(.{ .x = 0, .y = 0 })); - try testing.expectEqual(100, m.get(.{ .x = 4, .y = 4 })); + // we should see the value updated in the Matrix + try testing.expectEqual('a', m.get(.{ .x = 4, .y = 4 })); }