diff --git a/src/grome/matrix.zig b/src/grome/matrix.zig index d9411be..f80378a 100644 --- a/src/grome/matrix.zig +++ b/src/grome/matrix.zig @@ -137,6 +137,69 @@ test "TestMatrix" { try testing.expectEqual(100, try mat.get(Point{ .x = 1, .y = 1 })); } +// SubMatrix is a subset of a matrix which you can traverse to +pub fn SubMatrix(comptime T: type) type { + return struct { + // Data is made up of different sections of the + _m: *Matrix(T), + _offset: Point, + _mask: Rect, + //_width: usize, + rowable: Rowable(T), + + /// init takes the underlying data from the upstream matrix and creates + /// a submatrix of it + pub fn init(m: *Matrix(T), loc: Point, size: Rect) @This() { + return .{ ._m = m, ._offset = loc, ._mask = size, .rowable = Rowable(T){ .rowFn = SubMatrix(T).row } }; + } + + pub fn get(self: *const @This(), loc: Point) !T { + if (loc.x >= self._mask.width or loc.y >= self._mask.width) { + return Error.OutOfBounds; + } + + try self._m.get(self._offset.add(loc)); + } + + pub fn set(self: *@This(), loc: Point, val: T) !void { + if (loc.x >= self._mask.width or loc.y >= self._mask.width) { + return Error.OutOfBounds; + } + + try self._m.set(self._offset.add(loc), val); + } + + pub fn row(interface: *Rowable(T), line: usize) ![]T { + var self: *@This() = @fieldParentPtr("rowable", interface); + if (line >= self._mask.height) { + return Error.OutOfBounds; + } + + // TODO: This can index out of bound + // we need to checkt to make sure everything is copesedic + var r = try self._m.rowable.row(line + self._offset.y); + return r[self._offset.x .. self._offset.x + self._mask.width]; + } + + pub fn row_iterator(self: *@This()) RowIterator(T) { + return .init(&self.rowable); + } + }; +} + +test "SubMatrix" { + const testing = std.testing; + + // create our matrix and submatrix + var m = try Matrix(u8).initZero(testing.allocator, .{ .height = 10, .width = 10 }); + defer m.deinit(testing.allocator); + var sub = m.submatrix(.{ .x = 4, .y = 4 }, .{ .height = 5, .width = 5 }); + try sub.set(.{ .x = 0, .y = 0 }, 'a'); + + // we should see the value updated in the Matrix + try testing.expectEqual('a', try m.get(.{ .x = 4, .y = 4 })); +} + pub fn RowIterator(comptime T: type) type { return struct { current: usize, @@ -159,77 +222,29 @@ pub fn RowIterator(comptime T: type) type { test "TestRowIterator" { const testing = std.testing; - var chunk = try Matrix(usize).initZero(testing.allocator, Rect{ .height = 10, .width = 10 }); - defer chunk.deinit(testing.allocator); + var m = try Matrix(usize).initZero(testing.allocator, Rect{ .height = 10, .width = 10 }); + defer m.deinit(testing.allocator); for (0..10) |x| { - try chunk.set(Point{ .x = x, .y = x }, x); + try m.set(.{ .x = x, .y = x }, x); } - var iter = chunk.row_iterator(); + var iter = m.row_iterator(); var x: usize = 0; while (iter.next()) |row| { const v: @Vector(10, usize) = row[0..10].*; try testing.expectEqual(x, @reduce(.Add, v)); x += 1; } -} - -// SubMatrix is a subset of a matrix which you can traverse to -pub fn SubMatrix(comptime T: type) type { - return struct { - // Data is made up of different sections of the - _m: *Matrix(T), - _offset: Point, - _mask: Rect, - //_width: usize, - rowable: Rowable(T), - - /// init takes the underlying data from the upstream matrix and creates - /// a submatrix of it - pub fn init(m: *Matrix(T), loc: Point, size: Rect) @This() { - return .{ ._m = m, ._offset = loc, ._mask = size, .rowable = Rowable(T){ .rowFn = @This().row } }; - } - - pub fn get(self: *const @This(), loc: Point) !T { - if (loc.x >= self._mask.width or loc.y >= self._mask.width) { - return Error.OutOfBounds; - } - - try self._m.get(self._offset.add(loc)); - } - - pub fn set(self: *@This(), loc: Point, val: T) !void { - if (loc.x >= self._mask.width or loc.y >= self._mask.width) { - return Error.OutOfBounds; - } - - try self._m.set(self._offset.add(loc), val); - } - - pub fn row(interface: *Rowable(T), line: usize) ![]T { - var self: *SubMatrix(T) = @fieldParentPtr("rowable", interface); - if (line >= self._mask.height) { - return Error.OutOfBounds; - } - - // TODO: This can index out of bound - // we need to checkt to make sure everything is copesedic - var r = try self.rowable.row(line + self._offset.y); - return r[self._offset.x .. self._offset.x + self._mask.width]; - } - }; -} - -test "SubMatrix" { - const testing = std.testing; - - // create our matrix and submatrix - var m = try Matrix(u8).initZero(testing.allocator, .{ .height = 10, .width = 10 }); - defer m.deinit(testing.allocator); - var sub = m.submatrix(.{ .x = 4, .y = 4 }, .{ .height = 5, .width = 5 }); - try sub.set(.{ .x = 0, .y = 0 }, 'a'); - - // we should see the value updated in the Matrix - try testing.expectEqual('a', try m.get(.{ .x = 4, .y = 4 })); + try testing.expectEqual(10, x); + + var sub = m.submatrix(.{ .x = 5, .y = 5 }, .{ .width = 5, .height = 5 }); + var sub_iter = sub.row_iterator(); + x = 0; + while (sub_iter.next()) |row| { + const v: @Vector(5, usize) = row[0..5].*; + try testing.expectEqual(x + 5, @reduce(.Add, v)); + x += 1; + } + try testing.expectEqual(5, x); }