Fixed the iterator
This commit is contained in:
+91
-49
@@ -2,6 +2,21 @@ const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
pub const Error = error{
|
||||
OutOfBounds,
|
||||
};
|
||||
|
||||
/// Rowable is a type which can return a row at a time.
|
||||
fn Rowable(comptime T: type) type {
|
||||
return struct {
|
||||
rowFn: *const fn (self: *@This(), line: usize) Error![]T,
|
||||
|
||||
pub fn row(self: *@This(), line: usize) Error![]T {
|
||||
return self.rowFn(self, line);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Point is a location within the matrix, (x,y)
|
||||
pub const Point = struct {
|
||||
x: usize,
|
||||
@@ -13,6 +28,14 @@ pub const Point = struct {
|
||||
return (self.y * width) + self.x;
|
||||
}
|
||||
|
||||
// add two points together and return the subsiquent point
|
||||
pub fn add(self: *const Point, b: Point) Point {
|
||||
return .{
|
||||
.x = self.x + b.x,
|
||||
.y = self.y + b.y,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bottom_right(self: *const Point, area: Rect) Point {
|
||||
return .{
|
||||
.x = self.x + area.width,
|
||||
@@ -37,21 +60,23 @@ pub fn Matrix(comptime T: type) type {
|
||||
/// data is the game board itself.
|
||||
data: []T,
|
||||
|
||||
///
|
||||
/// defines the size of the matrix
|
||||
size: Rect,
|
||||
|
||||
rowable: Rowable(T),
|
||||
|
||||
/// init creates the chunk, storing the bytes in memory.
|
||||
pub fn initZero(gpa: Allocator, size: Rect) !@This() {
|
||||
const data = try gpa.alloc(T, size.area());
|
||||
@memset(data, mem.zeroes(T));
|
||||
return .{ .data = data, .size = size };
|
||||
return .{ .data = data, .size = size, .rowable = .{ .rowFn = Matrix(T).row } };
|
||||
}
|
||||
|
||||
/// init creates the chunk, storing the bytes in memory.
|
||||
pub fn init(gpa: Allocator, zero: T, size: Rect) !@This() {
|
||||
const data = try gpa.alloc(T, size.area());
|
||||
@memset(data, zero);
|
||||
return .{ .data = data, .size = size };
|
||||
return .{ .data = data, .size = size, .rowable = .{ .rowFn = Matrix(T).row } };
|
||||
}
|
||||
|
||||
/// deinit frees the memory utilized to create the chunk
|
||||
@@ -60,25 +85,44 @@ pub fn Matrix(comptime T: type) type {
|
||||
}
|
||||
|
||||
// set sets the value of the specified location in memory
|
||||
pub fn set(self: *@This(), loc: Point, val: T) void {
|
||||
pub fn set(self: *@This(), loc: Point, val: T) !void {
|
||||
if (loc.x >= self.size.width or loc.y >= self.size.height) {
|
||||
return Error.OutOfBounds;
|
||||
}
|
||||
|
||||
const index = (self.size.width * loc.y) + loc.x;
|
||||
self.data[index] = val;
|
||||
}
|
||||
|
||||
// set sets the value of the specified location in memory
|
||||
pub fn get(self: *const @This(), loc: Point) T {
|
||||
pub fn get(self: *const @This(), loc: Point) !T {
|
||||
if (loc.x >= self.size.width or loc.y >= self.size.height) {
|
||||
return Error.OutOfBounds;
|
||||
}
|
||||
|
||||
const index = (self.size.width * loc.y) + loc.x;
|
||||
return self.data[index];
|
||||
}
|
||||
|
||||
pub fn row_iterator(self: *@This()) RowIterator(T) {
|
||||
return .init(self);
|
||||
}
|
||||
|
||||
/// submatrix returns a [SubMatrix]
|
||||
pub fn submatrix(self: *@This(), loc: Point, area: Rect) SubMatrix(T) {
|
||||
return SubMatrix(T).init(self, loc, area);
|
||||
}
|
||||
|
||||
// TODO: you were in the middle of debugging this
|
||||
pub fn row(interface: *Rowable(T), line: usize) ![]T {
|
||||
var self: *@This() = @fieldParentPtr("rowable", interface);
|
||||
const index = line * self.size.width;
|
||||
if (index >= self.data.len) {
|
||||
return Error.OutOfBounds;
|
||||
}
|
||||
|
||||
return self.data[index .. index + self.size.width];
|
||||
}
|
||||
|
||||
pub fn row_iterator(self: *@This()) RowIterator(T) {
|
||||
return .init(&self.rowable);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -88,33 +132,26 @@ test "TestMatrix" {
|
||||
var mat = try Matrix(u64).initZero(testing.allocator, Rect{ .width = 10, .height = 10 });
|
||||
defer mat.deinit(testing.allocator);
|
||||
|
||||
mat.set(Point{ .x = 1, .y = 1 }, 100);
|
||||
try testing.expectEqual(100, mat.get(Point{ .x = 1, .y = 1 }));
|
||||
try mat.set(Point{ .x = 1, .y = 1 }, 100);
|
||||
try testing.expectEqualSlices(u64, ([_]u64{ 0, 100 } ++ ([_]u64{0} ** 8))[0..], try mat.rowable.row(1));
|
||||
try testing.expectEqual(100, try mat.get(Point{ .x = 1, .y = 1 }));
|
||||
}
|
||||
|
||||
pub fn RowIterator(comptime T: type) type {
|
||||
return struct {
|
||||
_index: usize,
|
||||
current: usize,
|
||||
/// data is a reference to the board game data, now we will return it as
|
||||
/// each row
|
||||
_data: []T,
|
||||
rows: *Rowable(T),
|
||||
|
||||
// The width of each row of data
|
||||
_width: usize,
|
||||
|
||||
fn init(m: *Matrix(T)) @This() {
|
||||
return .{ ._index = 0, ._data = m.data, ._width = m.size.width };
|
||||
fn init(rowable: *Rowable(T)) @This() {
|
||||
return .{ .rows = rowable, .current = 0 };
|
||||
}
|
||||
|
||||
/// next returns the next row until we have exhausted the slice
|
||||
/// next returns the next row until we have exhausted the Rowable
|
||||
pub fn next(self: *@This()) ?[]T {
|
||||
if (self._index >= self._data.len) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// increment a line at a time
|
||||
defer self._index += self._width;
|
||||
return self._data[self._index .. self._index + self._width];
|
||||
defer self.current += 1;
|
||||
return self.rows.row(self.current) catch null;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -126,7 +163,7 @@ test "TestRowIterator" {
|
||||
defer chunk.deinit(testing.allocator);
|
||||
|
||||
for (0..10) |x| {
|
||||
chunk.set(Point{ .x = x, .y = x }, x);
|
||||
try chunk.set(Point{ .x = x, .y = x }, x);
|
||||
}
|
||||
|
||||
var iter = chunk.row_iterator();
|
||||
@@ -143,34 +180,43 @@ pub fn SubMatrix(comptime T: type) type {
|
||||
return struct {
|
||||
// Data is made up of different sections of the
|
||||
_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,
|
||||
_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, ._index = loc.index(m.size.width), ._endingIndex = loc.bottom_right(size).index(m.size.width), ._width = size.width };
|
||||
return .{ ._m = m, ._offset = loc, ._mask = size, .rowable = Rowable(T){ .rowFn = @This().row } };
|
||||
}
|
||||
|
||||
// jump moves the pointer forward
|
||||
pub fn skip(self: *@This(), rows: usize) void {
|
||||
self._index += self._m.size.width * rows;
|
||||
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 next(self: *@This()) ?[]T {
|
||||
if (self._endingIndex <= self._index) {
|
||||
return null;
|
||||
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;
|
||||
}
|
||||
|
||||
defer {
|
||||
self._index += self._m.size.width;
|
||||
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;
|
||||
}
|
||||
|
||||
return self._m.data[self._index .. self._index + self._width];
|
||||
// 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];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -182,12 +228,8 @@ test "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 });
|
||||
|
||||
// set the value
|
||||
if (sub.next()) |row| {
|
||||
row[0] = 'a';
|
||||
}
|
||||
try sub.set(.{ .x = 0, .y = 0 }, 'a');
|
||||
|
||||
// we should see the value updated in the Matrix
|
||||
try testing.expectEqual('a', m.get(.{ .x = 4, .y = 4 }));
|
||||
try testing.expectEqual('a', try m.get(.{ .x = 4, .y = 4 }));
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ pub const DoubleBuffer = struct {
|
||||
|
||||
pub fn init(gpa: Allocator, size: Rect) !DoubleBuffer {
|
||||
const display = try gpa.alloc(Cell, size.area());
|
||||
errdefer gpa.free(display);
|
||||
|
||||
const write = try gpa.alloc(Cell, size.area());
|
||||
|
||||
return .{
|
||||
|
||||
Reference in New Issue
Block a user