Duplicating multidimensional array

Ali Çehreli acehreli at yahoo.com
Thu May 30 00:36:51 PDT 2013


On 05/29/2013 10:22 AM, Joseph Rushton Wakeling wrote:

 > I've been having some trouble trying to work out how to effectively
 > duplicate a multidimensional array in a way that preserves type 
qualifiers.

Templates preserve type qualifiers. So, as long as the return type is 
the same as the parameter type, then the type qualifiers should be 
preserved:

T foo(T)(T x)
{
     // ...
}

 >     immutable int[][] x = [[10, 0, 0, 0],
 >                            [0, 10, 0, 0],
 >                            [0, 0, 10, 0],
 >                            [0, 0, 0, 10]];
 >     int[][] y = multidup(x);

As long as it is a conversion, std.conv.to handles that case for you:

import std.conv;
// ...
	int[][] y = x.to!(int[][]);

Done! :)

Unfortunately, std.conv.to is not a general copy tool. It does not do 
anything when converting to the same type. In other words, when the 
target type is the same as the source type it is a no-op, not a copy.

What do you think about the following recursive template solution? I 
have tested it only with arrays of int. :/

import std.stdio;
import std.traits;
import std.conv;

// This is for one-dimensional arrays
T multidup(T : E[], E)(T arr)
     if (!isArray!E)
{
     T result;

     static if (is (E == immutable)) {
         // No need to copy immutable elements
         result = arr;

     } else {
         // Otherwise, we must make a copy
         result = arr.dup;
     }

     return result;
}

// This is for array of array types
T multidup(T : E[], E)(T arr)
     if(isArray!E)
{
     T result;

     static if (is (E == immutable)) {
         // No need to go deeper than an immutable layer
         result == arr;

     } else {
         foreach(row; arr) {
             result ~= multidup(row);
         }
     }

     return result;
}

unittest
{
     {
         int[] a = [ 1, 2, 3 ];
         auto b = multidup(a);
         assert(typeid(b) is typeid(a));
         assert(a == b);
     }

     {
         immutable(int[]) a = [ 1, 2 ];
         auto b = multidup(a);
         assert(typeid(b) == typeid(immutable(int)[]));
         assert(a == b);
         assert(a.ptr == b.ptr);
     }

     {
         immutable(int)[] a = [ 1, 2, 3 ];
         auto b = multidup(a);
         assert(typeid(b) == typeid(a));
         assert(a == b);
         assert(a.ptr == b.ptr);
         // assert(a[0].ptr == b[0].ptr);
     }

     {
         immutable(int)[][] a = [ [ 1, 2, 3 ],
                                  [ 4, 5, 6 ],
                                  [ 7, 8, 9 ] ];
         auto b = multidup(a);
         assert(typeid(b) == typeid(a));
         assert(a == b);
         assert(a.ptr != b.ptr);
         foreach (i; 0 .. a.length) {
             assert(a[i].ptr == b[i].ptr);
         }
     }

     {
         alias Elem = const(int[])[];
         const(int[])[][]a = [ [ [ 1, 2, 3 ],
                                 [ 4, 5, 6 ],
                                 [ 7, 8, 9 ] ],

                               [ [ 1, 2, 3 ],
                                 [ 4, 5, 6 ],
                                 [ 7, 8, 9 ] ] ];

         auto b = multidup(a);
         assert(typeid(b) == typeid(a));
         assert(a == b);
         assert(a.ptr != b.ptr);
         foreach (i; 0 .. a.length) {
             assert(a[i].ptr != b[i].ptr);
         }
     }
}

void main()
{}

Is it usable in your situation?

Ali



More information about the Digitalmars-d-learn mailing list