Hello all, I've been having some trouble trying to work out how to effectively duplicate a multidimensional array in a way that preserves type qualifiers.
Now, obviously if we have a multidimensional array such as T[][] then calling .dup will duplicate only the base array; so if we do something like, int[][] x = [[10, 0, 0, 0], [0, 10, 0, 0], [0, 0, 10, 0], [0, 0, 0, 10]]; int[][] y = x.dup; then y[i][j] will still be pointing to the same memory location as x[i][j]. We can write a "multidimensional duplication" function like this: T[][] multidup(T)(T[][] x) { T[][] tmp; foreach(row; x) { tmp ~= row.dup; } return tmp; } ... which works for mutable T, but fails with const or immutable. I had a go at implementing a version for const/immutable use: inout(T)[][] multidup(T)(T[][] x) inout if(!isMutable!T) { Unqual!T[][] tmp; foreach(row; x) { tmp ~= row.dup; } return assumeUnique(tmp); } ... but this actually doesn't work for const (as assumeUnique only works with immutable) and even with immutable input falls over: dupmatrix.d(20): Error: cannot implicitly convert expression (assumeUnique(tmp)) of type immutable(int[])[] to const(int)[][] dupmatrix.d(26): Error: template instance dupmatrix.multidup!(const(int)) error instantiating dupmatrix.d(26): Error: multidup (const(int)[][] x) is not callable using argument types (const(int[][])) /opt/ldc/include/d/std/range.d(611): Error: static assert "Cannot put a char[] into a Appender!(string)" instantiatied in /opt/ldc/include/d/std/format.d(1439): put!(Appender!(string), char[]) instantiatied in /opt/ldc/include/d/std/format.d(1341): formatUnsigned!(Appender!(string), char) instantiatied in /opt/ldc/include/d/std/format.d(1315): formatIntegral!(Appender!(string), ulong, char) ... (12 instantiations, -v to show) ... instantiatied in /opt/ldc/include/d/std/stdio.d(822): formattedWrite!(LockingTextWriter, char, const(int[])[]) instantiatied in /opt/ldc/include/d/std/stdio.d(1707): write!(string,const(int[])[],char) instantiatied in dupmatrix.d(28): writeln!(string,const(int[])[]) joseph@wakeling:~/code/test/D$ vi dupmatrix.d joseph@wakeling:~/code/test/D$ ldmd2 dupmatrix.d dupmatrix.d(20): Error: cannot implicitly convert expression (assumeUnique(tmp)) of type immutable(int[])[] to immutable(int)[][] dupmatrix.d(26): Error: template instance dupmatrix.multidup!(immutable(int)) error instantiating dupmatrix.d(26): Error: multidup (immutable(int)[][] x) is not callable using argument types (immutable(int[][])) /opt/ldc/include/d/std/range.d(611): Error: static assert "Cannot put a char[] into a Appender!(string)" instantiatied in /opt/ldc/include/d/std/format.d(1439): put!(Appender!(string), char[]) instantiatied in /opt/ldc/include/d/std/format.d(1341): formatUnsigned!(Appender!(string), char) instantiatied in /opt/ldc/include/d/std/format.d(1315): formatIntegral!(Appender!(string), ulong, char) ... (12 instantiations, -v to show) ... instantiatied in /opt/ldc/include/d/std/stdio.d(822): formattedWrite!(LockingTextWriter, char, immutable(int[])[]) instantiatied in /opt/ldc/include/d/std/stdio.d(1707): write!(string,immutable(int[])[],char) instantiatied in dupmatrix.d(28): writeln!(string,immutable(int[])[]) ... at which point I feel that I really don't understand the type (and type conversion) system well enough to proceed without advice :-( Complete code attached. Ideally I'd really like to have a solution that would recursively extend to multidimensional arrays of _any_ dimension, just because I guess that would be generally useful to everyone. It strikes me that as the copy is scoped, I might be able to just do a cast from Unqual!T[][] to T[][] safely, but it doesn't feel good to do so. I remember Dan Davidson had some code for a "generic dup" function for structs [1] that might be relevant here (and might already provide a general solution for multidimensional arrays), but I thought I'd ask if anyone else has any ideas. [1] http://www.digitalmars.com/d/archives/digitalmars/D/proposal_for_general_dup_function_182985.html
import std.exception, std.stdio, std.traits; T[][] multidup(T)(T[][] x) if(isMutable!T) { T[][] tmp; foreach(row; x) { tmp ~= row.dup; } return tmp; } inout(T)[][] multidup(T)(T[][] x) inout if(!isMutable!T) { Unqual!T[][] tmp; foreach(row; x) { tmp ~= row.dup; } return assumeUnique(tmp); } void main() { immutable int[][] x = [[10, 0, 0, 0], [0, 10, 0, 0], [0, 0, 10, 0], [0, 0, 0, 10]]; int[][] y = multidup(x); writeln("x = ", x); writeln("y = ", y); y[0][1] = 5; writeln("x = ", x); writeln("y = ", y); }