Am Tue, 31 May 2016 15:53:44 +0000
schrieb Basile B. <b2.t...@gmx.com>:

> This solution seems smarter than using the existing '@nogc' 
> attribute. Plus one also for the fact that nothing has to be done 
> in DMD.

I just constrained myself to what can be done in user code
from the start. :)

> Did you encounter the issue with protected and private members ?
> 
> For me when i've tested the template i've directly got some 
> warnings. DMD interprets my 'getMember' calls as a deprecated 
> abuse of bug 314 but in dmd 2.069 I would get true errors.

Actually it is in a large half-ported code base from C++ and I
haven't ever had a running executable, nor did I test it with
recent dmd versions. My idea was to mostly have @nogc code,
but allow it for a transition time or places where GC use
does not have an impact. Here is the code, free to use for
all purposes.


enum GcScan { no, yes, automatic }
enum noScan = GcScan.no;

template gcScanOf(T)
{
        import std.typetuple;

        static if (is(T == struct) || is(T == union))
        {
                enum isGcScan(alias uda) = is(typeof(uda) == GcScan);

                GcScan findGcScan(List...)()
                {
                        auto result = GcScan.automatic;
                        foreach (attr; List) if (is(typeof(attr) == GcScan))
                                result = attr;
                        return result;
                }

                enum gcScanOf()
                {
                        auto result = GcScan.no;
                        foreach (i; Iota!(T.tupleof.length))
                        {
                                enum memberGcScan = 
findMatchingUda!(T.tupleof[i], isGcScan, true);
                                static if (memberGcScan.length == 0)
                                        enum eval = 
gcScanOf!(typeof(T.tupleof[i]));
                                else
                                        enum eval = evalGcScan!(memberGcScan, 
typeof(T.tupleof[i]));

                                static if (eval)
                                {
                                        result = eval;
                                        break;
                                }
                        }
                        return result;
                }
        }
        else
        {
                static if (isStaticArray!T && is(T : E[N], E, size_t N))
                        enum gcScanOf = is(E == void) ? GcScan.yes : gcScanOf!E;
                else
                        enum gcScanOf = hasIndirections!T ? GcScan.yes : 
GcScan.no;
        }
}

enum evalGcScan(GcScan gc, T) = (gc == GcScan.automatic) ? gcScanOf!T : gc;

template findMatchingUda(alias symbol, alias func, bool optional = false, bool 
multiple = false)
{
        import std.typetuple;

        enum symbolName = __traits(identifier, symbol);
        enum funcName   = __traits(identifier, func);
        
        template Filter(List...)
        {
                static if (List.length == 0)
                        alias Filter = TypeTuple!();
                else static if (__traits(compiles, func!(List[0])) && 
func!(List[0]))
                        alias Filter = TypeTuple!(List[0], Filter!(List[1 .. 
$]));
                else
                        alias Filter = Filter!(List[1 .. $]);
        }
        
        alias filtered = Filter!(__traits(getAttributes, symbol));
        static assert(filtered.length <= 1 || multiple,
                      symbolName ~ " may only have one UDA matching " ~ 
funcName ~ ".");
        static assert(filtered.length >= 1 || optional,
                      symbolName ~ " requires a UDA matching " ~ funcName ~ 
".");

        static if (multiple || optional)
                alias findMatchingUda = filtered;
        else static if (filtered.length == 1)
                alias findMatchingUda = filtered[0];
}

-- 
Marco

Reply via email to