1 /** 2 Multi-dimensional slices. 3 4 Copyright: 5 Copyright © 2020-2026, Inochi2D Project 6 7 License: 8 $(LINK2 https://github.com/Inochi2D/inochi2d/blob/main/LICENSE, BSD 2-clause License) 9 10 Authors: 11 Luna Nielsen 12 Mireille Arseneault 13 */ 14 module inochi2d.core.slice2d; 15 import numem; 16 17 /** 18 A contiguous 2D slice. 19 20 The data is stored row-major. 21 */ 22 struct slice2d(T) { 23 private: 24 @nogc: 25 T[] data = null; 26 size_t stride = 0; 27 size_t _rows = 0; 28 size_t _columns = 0; 29 30 public: 31 /** 32 The number of rows in this slice. 33 */ 34 @property size_t rows() const => _rows; 35 36 /** 37 The number of columns in this slice. 38 */ 39 @property size_t columns() const => _columns; 40 41 /** 42 Construct a new slice of the given data with the given size. 43 44 Params: 45 data = The data of this slice. 46 stride = The data stride of this slice. 47 rows = The number of rows in the slice. 48 columns = The number of columns in the slice. 49 */ 50 this(T[] data, size_t stride, size_t rows, size_t columns) { 51 this.data = data; 52 this.stride = stride; 53 _rows = rows; 54 _columns = columns; 55 } 56 57 /** 58 Index this slice. 59 60 Params: 61 row = The row to index. 62 column = The column to index. 63 64 Returns: 65 The item at the given row and column index. 66 */ 67 ref T opIndex(size_t row, size_t column) { 68 assert(row <= _rows, "Row index outside bounds of array."); 69 assert(column <= _columns, "Column index outside bounds of array."); 70 return data[(stride * row) + column]; 71 } 72 73 slice2d!T opIndex(size_t row, size_t[2] columns) { 74 const a = (stride * row) + columns[0]; 75 const b = (stride * (row + 1)) + columns[1]; 76 return slice2d!T(data[a .. b], stride, 1, columns[1] - columns[0]); 77 } 78 79 slice2d!T opIndex(size_t[2] rows, size_t column) { 80 const a = (stride * rows[0]) + column; 81 const b = (stride * rows[1]) + column + 1; 82 return slice2d!T(data[a .. b], stride, rows[1] - rows[0], 1); 83 } 84 85 slice2d!T opIndex(size_t[2] rows, size_t[2] columns) { 86 const a = (stride * rows[0]) + columns[0]; 87 const b = (stride * rows[1]) + columns[1]; 88 return slice2d!T(data[a .. b], stride, rows[1] - rows[0], columns[1] - columns[0]); 89 } 90 91 slice2d!T opIndex() { 92 return slice2d!T(data, stride, _rows, _columns); 93 } 94 95 auto opIndexAssign(T value) { 96 foreach (row; 0 .. _rows) { 97 auto dest = &data.ptr[row * stride]; 98 dest[0 .. _columns] = value; 99 } 100 return value; 101 } 102 103 auto opIndexAssign(T value, size_t row, size_t column) { 104 assert(row <= _rows, "Row index outside bounds of array."); 105 assert(column <= _columns, "Column index outside bounds of array."); 106 return data[(stride * row) + column] = value; 107 } 108 109 auto opIndexAssign(slice2d!T value) { 110 assert(_rows == value._rows); 111 assert(_columns == value._columns); 112 foreach (row; 0 .. _rows) { 113 auto dest = &data.ptr[row * stride]; 114 auto src = &value.data.ptr[row * value.stride]; 115 dest[0 .. _columns] = src[0 .. _columns]; 116 } 117 return value; 118 } 119 120 auto opIndexAssign(slice2d!T value, size_t[2] rows, size_t[2] columns) { 121 auto slice = this[rows, columns]; 122 return slice = value; 123 } 124 125 /** 126 Obtain a pair of indices describing a span of rows. 127 128 Params: 129 a = The lower bound. 130 b = The upper bound. 131 132 Returns: 133 A "tuple" of our bounds. 134 */ 135 size_t[2] opSlice(size_t dim : 0)(size_t a, size_t b) const { 136 return [a, b]; 137 } 138 139 /** 140 Obtain a pair of indices describing a span of columns. 141 142 Params: 143 a = The lower bound. 144 b = The upper bound. 145 146 Returns: 147 A "tuple" of our bounds. 148 */ 149 size_t[2] opSlice(size_t dim : 1)(size_t a, size_t b) const { 150 return [a, b]; 151 } 152 153 /** 154 Obtain the number of rows in this vector using the dollar operator. 155 156 Returns: 157 The number of rows in this vector. 158 */ 159 size_t opDollar(size_t dim : 0)() const { 160 return _rows; 161 } 162 163 /** 164 Obtain the number of columns in this vector using the dollar operator. 165 166 Returns: 167 The number of columns in this vector. 168 */ 169 size_t opDollar(size_t dim : 1)() const { 170 return _columns; 171 } 172 }