digitalmars.D.learn - Difficulty copying multi dimensional static array to dynamic array.
- Spacen Jasset (28/28) Feb 24 2008 I have more than one problem in this class (errors below), but my focus
- Bill Baxter (38/68) Feb 24 2008 matrix.dup is going to only copy the pointers to the 4 sub-arrays.
- Spacen Jasset (9/89) Feb 25 2008 I see what you mean. I will look though helix, perhaps I should be using...
- Derek Parnell (18/20) Feb 25 2008 Because for some mysterious reason, one can't pass the static array by
- Saaa (1/20) Feb 25 2008
- Derek Parnell (23/24) Feb 25 2008 I agree, but the compiler explicitly disallows using ref with static
- Derek Parnell (32/35) Feb 25 2008 Oh and if it's "tricks" you want ;-) this works ...
- Spacen Jasset (33/70) Feb 25 2008 I don't see the mystery. Arrays are *always* passed by reference. You
- Bill Baxter (7/88) Feb 25 2008 You could just store your matrix in the order GL wants, and then do:
- Derek Parnell (10/11) Feb 25 2008 Thanks. I was still under the illusion that fixed length arrays were pas...
- Oskar Linde (6/15) Feb 26 2008 I have long lobbied for it, and Walter has actually said that at some
I have more than one problem in this class (errors below), but my focus it to return a dynamic array of float[4][4] which is copied from a static array of float[4][4]. I am having trouble finding how to do this. class Matrix { float[][] toFloatArray4x4() { float f[4][4] = matrix.dup; return f; } void toFloatArray16(float flat[16]) { flat[]=matrix_flat[]; } private: union { float matrix[4][4]; float matrix_flat[16]; } } matrix.d(74): Error: cannot implicitly convert expression (_adDupT(&_D14TypeInfo_G4G4f6__initZ,cast(float[4u][])(this.matrix))) of type float[4u][] to float[] matrix.d(75): Error: cannot implicitly convert expression (f) of type float[4u][4u] to float[][] matrix.d(75): Error: escaping reference to local f
Feb 24 2008
Spacen Jasset wrote:I have more than one problem in this class (errors below), but my focus it to return a dynamic array of float[4][4] which is copied from a static array of float[4][4]. I am having trouble finding how to do this. class Matrix { float[][] toFloatArray4x4() { float f[4][4] = matrix.dup; return f; } void toFloatArray16(float flat[16]) { flat[]=matrix_flat[]; } private: union { float matrix[4][4]; float matrix_flat[16]; } } matrix.d(74): Error: cannot implicitly convert expression (_adDupT(&_D14TypeInfo_G4G4f6__initZ,cast(float[4u][])(this.matrix))) of type float[4u][] to float[] matrix.d(75): Error: cannot implicitly convert expression (f) of type float[4u][4u] to float[][] matrix.d(75): Error: escaping reference to local fmatrix.dup is going to only copy the pointers to the 4 sub-arrays. Those sub-arrays are float[4u] static arrays. So you get back a dynamic array of static arrays. float[4u][] just like the compiler is telling you. I think if you really want to make a dynamic array of dynamic arrays that still points to the same memory as the original you're going to have to do something like: float f[][] ret; ret.length = 4; foreach(i,ref v; matrix) { ret[i] = matrix[i][0..4]; } return ret; If you intend that to be a copy, then make it matrix[i].dup But is it something you really need to be able to do? You will get back a dynamic array that isn't really dynamic. Resizing it will cause it to become distinct from the original static array's memory. Double indexed arrays aren't really a great representation for matrices anyway, since every access requires a double indirection. Furthermore, the float[][] interface allows you to make ragged arrays, that is, if you have a "float[][] M" you can't really be sure if every row has the same length as M[0] unless you check them all because some silly user might have changed the length of just the 3rd row or something. Finally, for many purposes (OpenGL and and calling Fortran numeric routines) column-major ordering is needed. With column major ordering M[i][j] is the i'th column, j'th row, which just looks wrong to anyone who's done much linear algebra. If you're interested I can point you to two other matrix classes where you can probably find answers most other issues you'll run across: http://www.dsource.org/projects/openmeshd/browser/trunk/Helix/helix/linalgebra.d http://www.dsource.org/projects/openmeshd/browser/trunk/OpenMeshD/OpenMesh/Core/Geometry/MatrixT.d And here are some others I found but can't vouch for because I've never used 'em: http://www.dsource.org/projects/arclib/browser/trunk/arclib/arc/math/matrix.d http://www.dsource.org/projects/yage/browser/trunk/src/yage/core/matrix.d http://www.dsource.org/projects/mathematics/browser/trunk/mathematics/numerical/Matrix.d --bb
Feb 24 2008
Bill Baxter wrote:Spacen Jasset wrote:I see what you mean. I will look though helix, perhaps I should be using that anway. All I am trying to do is 'return' an array so that toFloatArray4x4() can be called to fill in a static array. Something like this: float [4][4] m1; m1 = obj.toFloatArray4x4(); I realize I can pass the array in an have it set as in toFloatArray16(float flat[16]) but I was hoping I could return an array too.I have more than one problem in this class (errors below), but my focus it to return a dynamic array of float[4][4] which is copied from a static array of float[4][4]. I am having trouble finding how to do this. class Matrix { float[][] toFloatArray4x4() { float f[4][4] = matrix.dup; return f; } void toFloatArray16(float flat[16]) { flat[]=matrix_flat[]; } private: union { float matrix[4][4]; float matrix_flat[16]; } } matrix.d(74): Error: cannot implicitly convert expression (_adDupT(&_D14TypeInfo_G4G4f6__initZ,cast(float[4u][])(this.matrix))) of type float[4u][] to float[] matrix.d(75): Error: cannot implicitly convert expression (f) of type float[4u][4u] to float[][] matrix.d(75): Error: escaping reference to local fmatrix.dup is going to only copy the pointers to the 4 sub-arrays. Those sub-arrays are float[4u] static arrays. So you get back a dynamic array of static arrays. float[4u][] just like the compiler is telling you. I think if you really want to make a dynamic array of dynamic arrays that still points to the same memory as the original you're going to have to do something like: float f[][] ret; ret.length = 4; foreach(i,ref v; matrix) { ret[i] = matrix[i][0..4]; } return ret; If you intend that to be a copy, then make it matrix[i].dup But is it something you really need to be able to do? You will get back a dynamic array that isn't really dynamic. Resizing it will cause it to become distinct from the original static array's memory. Double indexed arrays aren't really a great representation for matrices anyway, since every access requires a double indirection. Furthermore, the float[][] interface allows you to make ragged arrays, that is, if you have a "float[][] M" you can't really be sure if every row has the same length as M[0] unless you check them all because some silly user might have changed the length of just the 3rd row or something. Finally, for many purposes (OpenGL and and calling Fortran numeric routines) column-major ordering is needed. With column major ordering M[i][j] is the i'th column, j'th row, which just looks wrong to anyone who's done much linear algebra. If you're interested I can point you to two other matrix classes where you can probably find answers most other issues you'll run across: http://www.dsource.org/projects/openmeshd/browser/trunk/Heli /helix/linalgebra.d http://www.dsource.org/projects/openmeshd/browser/trunk/OpenMeshD/OpenMesh/Cor /Geometry/MatrixT.d And here are some others I found but can't vouch for because I've never used 'em: http://www.dsource.org/projects/arclib/browser/trunk/arclib/arc/math/matrix.d http://www.dsource.org/projects/yage/browser/trunk/src/yage/core/matrix.d http://www.dsource.org/projects/mathematics/browser/trunk/mathematic /numerical/Matrix.d --bb
Feb 25 2008
On Mon, 25 Feb 2008 15:13:45 +0000, Spacen Jasset wrote:All I am trying to do is 'return' an array so that toFloatArray4x4() can be called to fill in a static array.Because for some mysterious reason, one can't pass the static array by reference you probably need to do it the old fashioned way ... void fillArray(float *d, int len) { while (len > 0) { *data = somevalue; data++; len--; } } float[4][4] m1; fillArrary( &m1[0][0], 4 * 4 ); -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Feb 25 2008
Using ref should do the trick without pointers.All I am trying to do is 'return' an array so that toFloatArray4x4() can be called to fill in a static array.Because for some mysterious reason, one can't pass the static array by reference you probably need to do it the old fashioned way ... void fillArray(float *d, int len) { while (len > 0) { *data = somevalue; data++; len--; } } float[4][4] m1; fillArrary( &m1[0][0], 4 * 4 ); -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Feb 25 2008
On Mon, 25 Feb 2008 23:11:11 +0100, Saaa wrote:Using ref should do the trick without pointers.I agree, but the compiler explicitly disallows using ref with static arrays. Try it yourself. Seems unreasonable to me and no one has explained it to me why this must be so. void fillArray(ref float[4][4] data) { for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) data[i][j] = 0.0; } void main() { float[4][4] m1; fillArrary( m1 ); } I get the message "Error: cannot have out or ref parameter of type float[4u][4u]" -- Derek (skype: derek.j.parnell) Melbourne, Australia 26/02/2008 9:33:53 AM
Feb 25 2008
On Tue, 26 Feb 2008 09:39:49 +1100, Derek Parnell wrote:On Mon, 25 Feb 2008 23:11:11 +0100, Saaa wrote:Oh and if it's "tricks" you want ;-) this works ... import std.stdio; struct nastytrick(T) { T m; } alias float[3][5] a2D; alias nastytrick!(a2D) sa2D; void fillArray(ref sa2D data) { invariant int maxi = data.m.length; invariant int maxj = data.m[0].length; for (int i = 0; i < maxi; i++) for (int j = 0; j < maxj; j++) data.m[i][j] = i*maxj + j; } void main() { sa2D x; // declare static array inside its struct wrapper. fillArray( x ); std.stdio.writefln("%s", x.m); } It seems very odd that a struct can be passed using 'ref' but a fixed length array can't be. -- Derek (skype: derek.j.parnell) Melbourne, Australia 26/02/2008 10:27:35 AMUsing ref should do the trick without pointers.
Feb 25 2008
Derek Parnell wrote:On Tue, 26 Feb 2008 09:39:49 +1100, Derek Parnell wrote:I don't see the mystery. Arrays are *always* passed by reference. You can't use ref because can't change a ref to a static array (becuase it's static?) so it doesn't actually make sense, you can [I think] with a class object -- Chanage it's ref using "ref" keyword so that it points to a new object) So that is all fine and makes sense as far as I can see. My beef is returning static arrays which you can't do. You can return dynamic ones only. It makes this impossible: glMatrixMultiply( mymatrix.toFloatArray16() ); Instead you have to do something like this: float[4][4] temp; mymatrix.toFloatArray16ByRef( temp ); glMatrixMultiply( temp ); Or glMatrixMultiply( *temp.toFloatArrayPointer() ); toFloatArrayPointer is: float[16] * toFloatArrayPointer() { static float[16] matrix; return &matrix; } ...and then you can use a wrapping structure and so on. But this isn't 'right' is it? or is it? Can why can I not use something like: glMatrixMultiply( mymatrix.toFloatArray16() ); where toFloatArray16 is: float[4][4] toFloatArray() { float[4][4] a; return a; // a is returned like a struct would be. (i.e. copied onto the stack and copied off on return. (or usually optimsed via a pointer on the stack to the callers object perhaps - whatever dmd currently does) }On Mon, 25 Feb 2008 23:11:11 +0100, Saaa wrote:Oh and if it's "tricks" you want ;-) this works ... import std.stdio; struct nastytrick(T) { T m; } alias float[3][5] a2D; alias nastytrick!(a2D) sa2D; void fillArray(ref sa2D data) { invariant int maxi = data.m.length; invariant int maxj = data.m[0].length; for (int i = 0; i < maxi; i++) for (int j = 0; j < maxj; j++) data.m[i][j] = i*maxj + j; } void main() { sa2D x; // declare static array inside its struct wrapper. fillArray( x ); std.stdio.writefln("%s", x.m); } It seems very odd that a struct can be passed using 'ref' but a fixed length array can't be.Using ref should do the trick without pointers.
Feb 25 2008
Spacen Jasset wrote:Derek Parnell wrote:You could just store your matrix in the order GL wants, and then do: glMultMatrixf( mymatrix.ptr ); Where .ptr returns a float* pointing to the first element. That's going to be hella more efficient than passing around big 16-element float arrays by value. --bbOn Tue, 26 Feb 2008 09:39:49 +1100, Derek Parnell wrote:I don't see the mystery. Arrays are *always* passed by reference. You can't use ref because can't change a ref to a static array (becuase it's static?) so it doesn't actually make sense, you can [I think] with a class object -- Chanage it's ref using "ref" keyword so that it points to a new object) So that is all fine and makes sense as far as I can see. My beef is returning static arrays which you can't do. You can return dynamic ones only. It makes this impossible: glMatrixMultiply( mymatrix.toFloatArray16() ); Instead you have to do something like this: float[4][4] temp; mymatrix.toFloatArray16ByRef( temp ); glMatrixMultiply( temp ); Or glMatrixMultiply( *temp.toFloatArrayPointer() ); toFloatArrayPointer is: float[16] * toFloatArrayPointer() { static float[16] matrix; return &matrix; } ...and then you can use a wrapping structure and so on. But this isn't 'right' is it? or is it? Can why can I not use something like: glMatrixMultiply( mymatrix.toFloatArray16() ); where toFloatArray16 is: float[4][4] toFloatArray() { float[4][4] a; return a; // a is returned like a struct would be. (i.e. copied onto the stack and copied off on return. (or usually optimsed via a pointer on the stack to the callers object perhaps - whatever dmd currently does) }On Mon, 25 Feb 2008 23:11:11 +0100, Saaa wrote:Oh and if it's "tricks" you want ;-) this works ... import std.stdio; struct nastytrick(T) { T m; } alias float[3][5] a2D; alias nastytrick!(a2D) sa2D; void fillArray(ref sa2D data) { invariant int maxi = data.m.length; invariant int maxj = data.m[0].length; for (int i = 0; i < maxi; i++) for (int j = 0; j < maxj; j++) data.m[i][j] = i*maxj + j; } void main() { sa2D x; // declare static array inside its struct wrapper. fillArray( x ); std.stdio.writefln("%s", x.m); } It seems very odd that a struct can be passed using 'ref' but a fixed length array can't be.Using ref should do the trick without pointers.
Feb 25 2008
On Tue, 26 Feb 2008 00:17:10 +0000, Spacen Jasset wrote:I don't see the mystery. Arrays are *always* passed by reference.Thanks. I was still under the illusion that fixed length arrays were passed by value. Maybe this will stick in my head now ;-) On the question of returning fixed-length arrays, it does seem like its something that the compiler should be able to do. Good luck with that one. -- Derek (skype: derek.j.parnell) Melbourne, Australia 26/02/2008 12:58:31 PM
Feb 25 2008
Derek Parnell wrote:On Tue, 26 Feb 2008 00:17:10 +0000, Spacen Jasset wrote:I have long lobbied for it, and Walter has actually said that at some point static arrays in D will become value types. Once they are, heaps of horrible workarounds will become obsolete. -- OskarI don't see the mystery. Arrays are *always* passed by reference.Thanks. I was still under the illusion that fixed length arrays were passed by value. Maybe this will stick in my head now ;-) On the question of returning fixed-length arrays, it does seem like its something that the compiler should be able to do. Good luck with that one.
Feb 26 2008