1 module mutils.view2d;
2 
3 import std.traits : ForeachType;
4 
5 struct View2D(Slice) {
6 	alias T = ForeachType!Slice;
7 	Slice slice;
8 	size_t columnsNum = 1;
9 
10 	Slice opIndex(size_t y) {
11 		return slice[y * columnsNum .. (y + 1) * columnsNum];
12 	}
13 
14 	ref T opIndex(size_t y, size_t x) {
15 		assert(x < columnsNum);
16 		return slice[y * columnsNum + x];
17 	}
18 
19 	Slice opIndex(size_t y, size_t[2] x) {
20 		assert(x[0] <= x[1]);
21 		assert(x[1] <= columnsNum);
22 		size_t start = y * columnsNum;
23 		return slice[start + x[0] .. start + x[1]];
24 	}
25 
26 	size_t[2] opSlice(size_t dim)(size_t start, size_t end) {
27 		return [start, end];
28 	}
29 
30 	size_t opDollar(size_t dim)() {
31 		static assert(dim < 2);
32 		static if (dim == 0) {
33 			return columnsNum;
34 		} else {
35 			return cast(size_t)(slice.length / columnsNum);
36 		}
37 	}
38 
39 	// foreach support
40 	int opApply(scope int delegate(Slice) dg) {
41 		int result;
42 		foreach (y; 0 .. cast(size_t)(slice.length / columnsNum)) {
43 			result = dg(opIndex(y));
44 			if (result)
45 				break;
46 		}
47 
48 		return result;
49 	}
50 
51 	// foreach support
52 	int opApply(scope int delegate(size_t, Slice) dg) {
53 		int result;
54 		foreach (y; 0 .. cast(size_t)(slice.length / columnsNum)) {
55 			result = dg(y, opIndex(y));
56 			if (result)
57 				break;
58 		}
59 
60 		return result;
61 	}
62 }
63 
64 // Helper to avoid GC
65 private T[n] s(T, size_t n)(auto ref T[n] array) pure nothrow @nogc @safe {
66 	return array;
67 }
68 
69 unittest {
70 	int[9] arr = [0, 1, 2, 3, 4, 5, 6, 7, 8].s;
71 	View2D!(int[]) view;
72 	view.slice = arr[];
73 	view.columnsNum = 3;
74 
75 	// opIndex[y]
76 	assert(view[0] == [0, 1, 2].s);
77 	assert(view[1] == [3, 4, 5].s);
78 	assert(view[2] == [6, 7, 8].s);
79 
80 	// opIndex[y, x]
81 	assert(view[0, 0] == 0);
82 	assert(view[0, 1] == 1);
83 	assert(view[0, 2] == 2);
84 	assert(view[1, 0] == 3);
85 	assert(view[1, 1] == 4);
86 	assert(view[1, 2] == 5);
87 	assert(view[2, 0] == 6);
88 	assert(view[2, 1] == 7);
89 	assert(view[2, 2] == 8);
90 	// opIndex[y,x1..x2]
91 	assert(view[0, 1 .. $] == [1, 2].s);
92 	// opDollar
93 	assert(view[$ - 1] == [6, 7, 8].s);
94 	assert(view[$ - 1, $ - 2] == 7);
95 	// Foreach
96 	foreach (row; view) {
97 	}
98 	foreach (i, row; view) {
99 		assert(row == [i * 3 + 0, i * 3 + 1, i * 3 + 2].s);
100 	}
101 	// Assigment
102 	view[2, 2] = 123;
103 	assert(view[2, 2] == 123);
104 }