www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Deep dupping

Hi,

in the "confused about const" thread, some said that we'd need a deep dup, to
recursively dup all members of aggregates. I indeed have such a need, so I
tried to code a quick & dirty version of this, any comment is welcome:

----
template TypeofDeepdup(T)
{
    alias typeof(deepdup(T.init)) TypeofDeepdup;
}

ref Unqual!T deepdup(T)(T t) if (is(T == struct) && !is(T.Types))
{
    staticMap!(TypeofDeepdup, typeof(t.tupleof)) tup;
    foreach(i,Type; tup) { tup[i] = deepdup(t.tupleof[i]);}
    return Unqual!T(tup);
}

Tuple!(staticMap!(TypeofDeepdup, T.Types))
deepdup(T)(T t) if (is(T.Types)) // Tuples
{
    staticMap!(TypeofDeepdup, T.Types) tup;
    foreach(i,Type; tup) { tup[i] = deepdup(t.field[i]);}
    return tuple(tup);
}

Unqual!T deepdup(T)(T t) if (is(T == class))
{
    staticMap!(TypeofDeepdup, typeof(t.tupleof)) tup;
    foreach(i,Type; tup) { tup[i] = deepdup(t.tupleof[i]);}
    return new Unqual!T(tup);
}

TypeofDeepdup!(ElementType!T)[] deepdup(T)(T t) if (isDynamicArray!T)
{
    auto result = new TypeofDeepdup!(ElementType!T)[](t.length);
    foreach(elem; t) result ~= deepdup(elem);
    return result;
}

TypeofDeepdup!(ElementType!T)[T.length] deepdup(T)(T t) if (isStaticArray!T)
{
    TypeofDeepdup!(ElementType!T)[T.length] result = t;
    foreach(ref elem; result) elem = deepdup(elem);
    return result;
}

TypeofDeepdup!T* deepdup(T)(T* t)
{
    return &deepdup(*t);
}

Unqual!T deepdup(T)(T t) if (!is(T == struct) && !is(T == class) &&
!isDynamicArray!T && !is(T.Types) && !isPointer!T)
{
    return cast(Unqual!T)t;
}
----

I have to unqualify everything, getting rid of const and immutable, to be able
to copy what I want. My current problem are strings, for somehow
ElementType!(StringType) returns dchar. I'll probably have to special-case
them, and use std.string.ByCodeUnit.


It seems to work well enough for my needs : structs, pointers to structs,
classes, dynamic and static arrays, all recursively.
One big limit for now: templated structs/class whose type depend on their
internal types. Eg: Tuples.

Tuple!(string, int) should become Tuple!(dchar[], int). That's more or less the
current situation for structs, by I found no way to do this generically for all
templates.


Another limit is that everything is returned unqualified...
Also, I'll wait for auto ref and inout to stabilize before using them in
deepdup.

Any comments/ideas?

  Philippe
Mar 21 2010