www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How do I pass multidimensional static arrays to functions expecting

reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Take a look:

void main()
{
    int[2] single;
    // foo(single);  // no
    foo(single[]);   // int[2][] slice, ok

    int[2][2] multi;
    // bar(multi);     // int[2][2] no
    // bar(multi[]);   // int[2][] slice, no
    // bar(multi[][]); // int[2][] slice, no
}

void foo(int[] value) {}
void bar(int[][] value) {}

I can easily slice a one-dimensional static array, but I can only
slice a single dimension. So how do I pass a multidimensional static
array to a function expecting a multidimensional dynamic array?
Aug 29 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/30/2011 01:29 AM, Andrej Mitrovic wrote:
 Take a look:

 void main()
 {
      int[2] single;
      // foo(single);  // no
      foo(single[]);   // int[2][] slice, ok

      int[2][2] multi;
      // bar(multi);     // int[2][2] no
      // bar(multi[]);   // int[2][] slice, no
      // bar(multi[][]); // int[2][] slice, no
 }

 void foo(int[] value) {}
 void bar(int[][] value) {}

 I can easily slice a one-dimensional static array, but I can only
 slice a single dimension. So how do I pass a multidimensional static
 array to a function expecting a multidimensional dynamic array?
D does not have multidimensional dynamic arrays. To solve your problem, you have to manually create an array of 1D-slices: Like this: bar(array(map!((int[] a){return a;})(multi[]))); Or like this: int[][] arg=new int[][](2); foreach(i,ref x;arg) x=multi[i][]; bar(arg);
Aug 29 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Timon Gehr:

 bar(array(map!((int[] a){return a;})(multi[])));
Simpler: bar( array(map!q{ a[] }(multi[])) ); Simpler still when we'll get amap: bar( amap!q{ a[] }(multi[]) ); Bye, bearophile
Aug 29 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/30/2011 03:20 AM, bearophile wrote:
 Timon Gehr:

 bar(array(map!((int[] a){return a;})(multi[])));
Simpler: bar( array(map!q{ a[] }(multi[])) );
And buggy. It returns slices of a local stack frame, because static arrays are value types.
 Simpler still when we'll get amap:
 bar( amap!q{ a[] }(multi[]) );

 Bye,
 bearophile
Aug 30 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Timon Gehr Wrote:

 On 08/30/2011 03:20 AM, bearophile wrote:
 Timon Gehr:

 bar(array(map!((int[] a){return a;})(multi[])));
Simpler: bar( array(map!q{ a[] }(multi[])) );
And buggy. It returns slices of a local stack frame, because static arrays are value types.
q{ a[] } does the same thing as (int[] a){return a;}, both return a slice of memory on the stack. Using a dynamic array (a slice) that uses memory allocated on the stack is correct. You just have to know what you are doing. It's the same as passing a fixed-sized array to a function that expects a dynamic slice. Andrej Mitrovic has said: "I was just trying to temporarily avoid GC allocation so I've used a static array instead of a dynamic ones." If you replace the map function with q{ a.dup } you have heap memory, but Andrej is not happy. Bye, bearophile
Aug 30 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/30/2011 01:06 PM, bearophile wrote:
 Timon Gehr Wrote:

 On 08/30/2011 03:20 AM, bearophile wrote:
 Timon Gehr:

 bar(array(map!((int[] a){return a;})(multi[])));
Simpler: bar( array(map!q{ a[] }(multi[])) );
And buggy. It returns slices of a local stack frame, because static arrays are value types.
q{ a[] } does the same thing as (int[] a){return a;}, both return a slice of memory on the stack. Using a dynamic array (a slice) that uses memory allocated on the stack is correct. You just have to know what you are doing. It's the same as passing a fixed-sized array to a function that expects a dynamic slice.
No, what they do is very different. Yours creates a new stack frame, copies the data into it and then returns invalid slices to the stack frame that has now disappeared. Mine returns slices to the enclosing stack frame, which is perfectly valid. If you are not convinced, just try to pass a 2D static array to the following function using your method: void bar(int[][] a){writeln(a);} It won't work.
Aug 30 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Timon Gehr:

 It won't work.
Thank you, bye, bearophile
Aug 30 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Right, but I was just trying to temporarily avoid GC allocation so
I've used a static array instead of a dynamic ones. Also, I don't know
of another term that is used to describe a int[][] array, other than
multidimensional.

Anyway this works fine for me (int wasn't a requirement in this case):

void foo(T)(T val) if (isArray!T)
void bar(T)(T val) if (isArray!T && isArray!(ElementType!T))
Aug 29 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Hey btw, do you think we could use this in Phobos?

template BaseElementType(R)
{
    static if (isArray!(ElementType!R))
        alias BaseElementType!(ElementType!R) BaseElementType;
    else static if (is(typeof({return R.init.front();}()) T))
        alias T BaseElementType;
    else
        alias void BaseElementType;
}

assert(is(BaseElementType!(int[][]) == int));

Maybe a better name is RootElementType. Not too sure.
Aug 29 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, August 30, 2011 03:43:39 Andrej Mitrovic wrote:
 Right, but I was just trying to temporarily avoid GC allocation so
 I've used a static array instead of a dynamic ones. Also, I don't know
 of another term that is used to describe a int[][] array, other than
 multidimensional.
It _is_ multi-dimensional. I'm not quite sure why Timon is saying that it isn't. Ultimately though, a multi-dimensional dynamic array is an array of arrays (or array of arrays of arrays of ...). When slicing it, you get the a portion of the outermost array. If you index that, you can get at the inner arrays to slice those if you want to, but the inner arrays know nothing about the outer arrays, and actually taking a "slice" of the whole where you get the outer array and some portion of the inner arrays would require creating a new array, so you can't really do it. I can't really think of a clean way of explaining it without diagrams, and even then it's a bit of a pain, but with a slice, it's only a matter of adjusting its ptr and length properties. If you want a multi-dimensional slice, you'd need to adjust the ptr and length properties of the arrays that the slice contained, and you can't do that without affecting the original arrays unless you copy them. So, ultimately, you need to construct a new multi-dimensional array with the pieces that you want if you want a multi- dimensional slice. - Jonathan M Davis
Aug 29 2011