www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Difficulty copying multi dimensional static array to dynamic array.

reply Spacen Jasset <spacen yahoo.co.uk> writes:
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
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
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 f
matrix.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
parent reply Spacen Jasset <spacenjasset yahoo.co.uk> writes:
Bill Baxter wrote:
 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 f
matrix.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
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.
Feb 25 2008
parent reply Derek Parnell <derek psych.ward> writes:
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
parent reply "Saaa" <empty needmail.com> writes:
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
parent reply Derek Parnell <derek nomail.afraid.org> writes:
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
parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Tue, 26 Feb 2008 09:39:49 +1100, Derek Parnell wrote:

 On Mon, 25 Feb 2008 23:11:11 +0100, Saaa wrote:
 
 Using ref should do the trick without pointers.
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 AM
Feb 25 2008
parent reply Spacen Jasset <spacen yahoo.co.uk> writes:
Derek Parnell wrote:
 On Tue, 26 Feb 2008 09:39:49 +1100, Derek Parnell wrote:
 
 On Mon, 25 Feb 2008 23:11:11 +0100, Saaa wrote:

 Using ref should do the trick without pointers.
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.
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) }
Feb 25 2008
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Spacen Jasset wrote:
 Derek Parnell wrote:
 On Tue, 26 Feb 2008 09:39:49 +1100, Derek Parnell wrote:

 On Mon, 25 Feb 2008 23:11:11 +0100, Saaa wrote:

 Using ref should do the trick without pointers.
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.
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) }
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. --bb
Feb 25 2008
prev sibling parent reply Derek Parnell <derek nomail.afraid.org> writes:
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
parent Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Derek Parnell wrote:
 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.
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. -- Oskar
Feb 26 2008