www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - a struct as an multidimensional array index

reply Chris Katko <ckatko gmail.com> writes:
Is it somehow possible to use a struct as a [multidimensional] 
array index:

````D

struct indexedPair
{
size_t x, y;
}

bool isMapPassable[100][100];
auto p = indexedPair(50, 50);

if(isMapPassable[p]) return true;

````

Probably not, but I'm curious.
Jun 10 2022
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/10/22 01:08, Chris Katko wrote:
 Is it somehow possible to use a struct as a [multidimensional] array 
index: You can define an opIndex that takes any index type if the array is defined by you: import std.stdio; import std.format; struct indexedPair { size_t x, y; } struct MyArray { bool[3][3] elements; ref opIndex(indexedPair i) { return elements[i.y][i.x]; } // void toString(scope void delegate(in char[]) sink) const { // import std.algorithm; // sink.formattedWrite!"%-(%-(%s %)\n%)"( // elements[].map!(row => row[].map!(column => column ? 'T' : 'f'))); // } } void main() { auto arr = MyArray(); auto p = indexedPair(1, 1); arr[p] = true; writeln(arr); } I played with that toString function but for some reason it prints all Ts. (?) Ali
Jun 10 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/10/22 07:38, Ali Çehreli wrote:

 I played with that toString function but for some reason it prints all
 Ts. (?)
Fixed it by changing one of the lambdas to take by reference: void toString(scope void delegate(in char[]) sink) const { import std.algorithm; sink.formattedWrite!"%-(%-(%s %)\n%)"( elements[].map!((ref row) => row[].map!(column => column ? 'T' : 'f'))); // ^^^ } I still don't understand the reason though. The rows would be copied without ref but should retain their type as bool[3], a static array. (?) Ali
Jun 10 2022
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/10/22 08:01, Ali Çehreli wrote:

 I still don't understand the reason though. The rows would be copied
 without ref but should retain their type as bool[3], a static array. (?)
Ok, now I see the very sinister problem: It is a disaster to combine static array lambda parameters with the laziness of range algorithms. The following program prints garbage because by the time writeln prints the elements, those elements are on invalid places on the stack: import std; void main() { int[3][3] arr; writeln( arr[] // Have to slice .map!(row => row[] // Have to slice .map!(element => element)) ); } The output is garbage element values. The programmer must take the parameter of the outer map by reference so that the elements are referring to actual elements in 'arr': .map!((ref row) => /* ... */ I don't think I realized this issue before, which may be caught by various combinations of safety compiler switches, which I haven't tried yet. Ali
Jun 10 2022
prev sibling next sibling parent "H. S. Teoh" <hsteoh qfbox.info> writes:
On Fri, Jun 10, 2022 at 08:08:45AM +0000, Chris Katko via Digitalmars-d-learn
wrote:
 Is it somehow possible to use a struct as a [multidimensional] array index:
 
 ````D
 
 struct indexedPair
 {
 size_t x, y;
 }
 
 bool isMapPassable[100][100];
 auto p = indexedPair(50, 50);
 
 if(isMapPassable[p]) return true;
 
 ````
 
 Probably not, but I'm curious.
See: https://dlang.org/spec/operatoroverloading.html#array-ops T -- It won't be covered in the book. The source code has to be useful for something, after all. -- Larry Wall
Jun 10 2022
prev sibling parent reply z <z z.com> writes:
On Friday, 10 June 2022 at 08:08:45 UTC, Chris Katko wrote:
 Is it somehow possible to use a struct as a [multidimensional] 
 array index:

 ````D

 struct indexedPair
 {
 size_t x, y;
 }

 bool isMapPassable[100][100];
 auto p = indexedPair(50, 50);

 if(isMapPassable[p]) return true;

 ````

 Probably not, but I'm curious.
AFAIK no. I admit it's an area D could improve on, it creates a lot of confusion because of the ordering and the lack of an integrated solution. (arrays of arrays has different order for declaration and addressing, and declaring array of arrays has different order depending on how you declare it and wether it's static or dynamic array, *oof*) To give you an idea of the situation : ```D int[3][1] a;//one array of 3 int writeln(a[0][2]);//first "column", third "row" ``` One thing you could do however is make the array accept a multidimensional argument through operator overloading(opIndex) if it is the only array from a struct, but that gets unviable when you have multiple arrays that would benefit from it. To summarize, there does not appear to be an easy solution that has no drawbacks. I'd recommend saving yourself the trouble of array of arrays(of arrays?) and using a single array of length x*y with a function to index into it `(x+(xlength*y)` or `( (x+(xlength*y)) + ((xlength*ylength)*z)) )` if that is desirable.
Jun 10 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/10/22 08:13, z wrote:

 arrays of arrays has different order for declaration and addressing,
 and declaring array of arrays has different order depending on how you
 declare it and wether it's static or dynamic array, *oof*)

 To give you an idea of the situation :
 ```D
      int[3][1] a;//one array of 3 int
      writeln(a[0][2]);//first "column", third "row"
 ```
I've written about this multiple times in the past but D's way is consistent for me. That must be because I always found C's syntax to be very illogical on this. To me, C's problem starts with putting the variable name in the middle: // C code: int a[1][3]; // Why? So, first, D moves the variable to its consistent place: after the type: int i; int[N] arr; Both of those are in the form of "type and then name". Good... And then, here is the consistency with arrays: "type and then square brackets". int[] dynamicArray; int[N] staticArray; So, here is where you and I differ: int[3][1] arr; // Ali likes int[1][3] arr; // z wants I like it because it is consistently "type and then square brackets". (It so happens that the type of each element is int[N] in this case.) If it were the other way, than array syntax would be inconsistent with itself. :) Or, we would have to accept that it is inside-out like in C. But of course I understand how it is seen as consistent from C's point of view. :) And this is consistent with static vs dynamic as well because again it's "type and then square brackets": int[1][] a; // A dynamic array of int[1] int[][3] b; // A static array of 3 int[]s Ali
Jun 10 2022
next sibling parent reply Chris Katko <ckatko gmail.com> writes:
On Friday, 10 June 2022 at 17:26:48 UTC, Ali Çehreli wrote:
 On 6/10/22 08:13, z wrote:

 arrays of arrays has different order for declaration and
addressing,
 and declaring array of arrays has different order depending
on how you
 declare it and wether it's static or dynamic array, *oof*)

 To give you an idea of the situation :
 ```D
      int[3][1] a;//one array of 3 int
      writeln(a[0][2]);//first "column", third "row"
 ```
I've written about this multiple times in the past but D's way is consistent for me. That must be because I always found C's syntax to be very illogical on this. To me, C's problem starts with putting the variable name in the middle: // C code: int a[1][3]; // Why? So, first, D moves the variable to its consistent place: after the type: int i; int[N] arr; Both of those are in the form of "type and then name". Good... And then, here is the consistency with arrays: "type and then square brackets". int[] dynamicArray; int[N] staticArray; So, here is where you and I differ: int[3][1] arr; // Ali likes int[1][3] arr; // z wants I like it because it is consistently "type and then square brackets". (It so happens that the type of each element is int[N] in this case.) If it were the other way, than array syntax would be inconsistent with itself. :) Or, we would have to accept that it is inside-out like in C. But of course I understand how it is seen as consistent from C's point of view. :) And this is consistent with static vs dynamic as well because again it's "type and then square brackets": int[1][] a; // A dynamic array of int[1] int[][3] b; // A static array of 3 int[]s Ali
This is an interesting discussion. I had noticed multi-dim arrays seemed backwards but I assumed I was doing something wrong and had other thing to worry about. I had no idea it was DIFFERENT for static vs dynamic arrays? That's horrifying! Also you reminded me of a possible D bug that I ran into. I had classes that had circular dependencies. One had to know about the other, and vice-versa. And I had derived classes. But somehow, they would explode. I would send one reference to the others constructor to 'link' them together, but the reference would be NULL. But if I accessed the exact same variable through a global reference, it worked fine. I tried ripping the affected code into a new file but the bug wasn't replicated. Even if I matched the compiler/linker options. It was super frustrating.
Jun 10 2022
parent reply z <z z.com> writes:
On Saturday, 11 June 2022 at 03:56:32 UTC, Chris Katko wrote:
 On Friday, 10 June 2022 at 17:26:48 UTC, Ali Çehreli wrote:
 On 6/10/22 08:13, z wrote:

 arrays of arrays has different order for declaration and
addressing,
 and declaring array of arrays has different order depending
on how you
 declare it and wether it's static or dynamic array, *oof*)

 To give you an idea of the situation :
 ```D
      int[3][1] a;//one array of 3 int
      writeln(a[0][2]);//first "column", third "row"
 ```
I've written about this multiple times in the past but D's way is consistent for me. That must be because I always found C's syntax to be very illogical on this. To me, C's problem starts with putting the variable name in the middle: // C code: int a[1][3]; // Why? So, first, D moves the variable to its consistent place: after the type: int i; int[N] arr; Both of those are in the form of "type and then name". Good... And then, here is the consistency with arrays: "type and then square brackets". int[] dynamicArray; int[N] staticArray; So, here is where you and I differ: int[3][1] arr; // Ali likes int[1][3] arr; // z wants I like it because it is consistently "type and then square brackets". (It so happens that the type of each element is int[N] in this case.) If it were the other way, than array syntax would be inconsistent with itself. :) Or, we would have to accept that it is inside-out like in C. But of course I understand how it is seen as consistent from C's point of view. :) And this is consistent with static vs dynamic as well because again it's "type and then square brackets": int[1][] a; // A dynamic array of int[1] int[][3] b; // A static array of 3 int[]s Ali
This is an interesting discussion. I had noticed multi-dim arrays seemed backwards but I assumed I was doing something wrong and had other thing to worry about. I had no idea it was DIFFERENT for static vs dynamic arrays? That's horrifying! Also you reminded me of a possible D bug that I ran into. I had classes that had circular dependencies. One had to know about the other, and vice-versa. And I had derived classes. But somehow, they would explode. I would send one reference to the others constructor to 'link' them together, but the reference would be NULL. But if I accessed the exact same variable through a global reference, it worked fine. I tried ripping the affected code into a new file but the bug wasn't replicated. Even if I matched the compiler/linker options. It was super frustrating.
I rechecked and it should be `X Y Z` for static array, but `Z Y X` for indexing/dynamic array creating with `new` (e.g. `float[][][] arr = new float[][][](third_dimension,second_dimension,first_dimension;`) The dillema is that alone, the orders are sound byproducts of the language rules, it's when they are put in relation to each other that it can become weird. The bug could also be one of those implementation-specific bugs that are seemingly impossible to reproduce minimally because they require unknown very specific conditions to occur. Self and inter referencing appears unstable whenever it is not in the module/global scope.
Jun 11 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/11/22 00:09, z wrote:

 I rechecked and it should be `X Y Z` for static array, but `Z Y X` for
 indexing/dynamic array creating with `new`
How so? I wrote the following program: import std.stdio; void main() { enum X = 2; enum Y = 3; enum Z = 4; int[X][Y][Z] s; int[X][Y][] d = new int[X][Y][Z]; pragma(msg, typeof(s)); pragma(msg, typeof(d)); } It outputs the following for the static and the dynamic arrays: int[2][3][4] int[2][3][] Consistent elements, except the static array has a compile-time known length. Ali
Jun 11 2022
parent reply z <z z.com> writes:
On Saturday, 11 June 2022 at 15:01:05 UTC, Ali Çehreli wrote:
 On 6/11/22 00:09, z wrote:

 I rechecked and it should be `X Y Z` for static array, but `Z
Y X` for
 indexing/dynamic array creating with `new`
How so?
i meant with the syntax in (1), the spec's documentation appears to say they are equivalent in result with `new *type*[X][Y]` form. (1) https://dlang.org/spec/expression#new_multidimensional (3. multiple argument form)
Jun 11 2022
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/11/22 13:36, z wrote:

 i meant with the syntax in (1), the spec's documentation appears to say
 they are equivalent in result with `new *type*[X][Y]` form.

 (1) https://dlang.org/spec/expression#new_multidimensional (3. multiple
 argument form)
Thank you. I see now: The values in parentheses are the lengths from the outermost to the innermost: new int[][][](5, 20, 30) // The equivalent of int[30][20][5] Although, I can see how it had to be that way so that when one used less number of lengths, the syntax always works from outer to inner in that new expression: new int[][][](5) // The equivalent of int[][][5] Ali
Jun 11 2022
prev sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Friday, 10 June 2022 at 17:26:48 UTC, Ali Çehreli wrote:
 I've written about this multiple times in the past but D's way 
 is consistent for me. That must be because I always found C's 
 syntax to be very illogical on this. [...]
I think so too... I think D is very consistent with our feelings. That is, the order in memory is in the form of rows x columns. But yes, in reverse(column x row) when you set it up statically. This sample code working on pointers can be a proof: ```d void main() { enum { Row = 2, Column = 3 } size_t cal = Row * Column * int.sizeof; auto alloc = new ubyte[cal]; size_t m = Column * int.sizeof; int[][] aSlice; foreach (i; 0 .. Row) { size_t n = i * m; aSlice ~= cast(int[])alloc[n .. n + m]; } auto row = 2; auto column = 3; aSlice[row-1][column-1] = 1; // last element assert( *( &aSlice[0][0] // first element pointer + (row * column - 1) ) ); // no error... //If you want to see it with your eyes: import std.stdio; aSlice.writefln!"%-(%-(%s %)\n%)"; } ``` SDB 79
Jun 11 2022
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 6/11/22 04:16, Salih Dincer wrote:

 I think D is very consistent with our feelings. That is, the order in
 memory is in the form of rows x columns.
Yet, there are no rows or columns because neither D nor C (nor C++) have multip-dimensional arrays. They all have arrays where elements are layed out in memory consecutively. The type of the elements and what they represent is entilery up to the programmer.
 But yes, in reverse(column x
 row) when you set it up statically.
If you mean we can set up the memory in any way we want, I agree but again, since there are no mult-dimensional arrays, there cannot be the reverse of the order.
 This sample code working on pointers
 can be a proof:
If it's prooving that elemets are side-by-side, then it's by spec. Here is an example where I have array where each element is a column: import std.stdio; import std.range; import std.algorithm; void main() { // I decide that this array represents // Three rows of two columns. int[][] arr; arr.length = 2; foreach (ref column; arr) { column.length = 3; } setFirstColumn(arr, 1); printArray(arr); } void setFirstColumn(int[][] arr, int value) { // The first element is my first column. arr[0][] = value; } void printArray(int[][] arr) { // Because stdout takes line-by-line, // we print a transposition. arr.transposed.writefln!"%-(%-(%s %)\n%)"; } You may think that the final transposition is a trick. No, it was needed only because stdout takes line-by-line. If I used a library like ncurses, I could have printed my array exactly the way I used it. The point is, there are no multi-dimensional arrays. Programmers use arrays as they need and sometimes the elements are arrays. Ali
Jun 11 2022