[Issue 9088] New: static static

d-bugmail at puremagic.com d-bugmail at puremagic.com
Tue Nov 27 19:20:48 PST 2012


http://d.puremagic.com/issues/show_bug.cgi?id=9088

           Summary: static static
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: nobody at puremagic.com
        ReportedBy: bearophile_hugs at eml.cc


--- Comment #0 from bearophile_hugs at eml.cc 2012-11-27 19:20:05 PST ---
Here I suggest an enhancement for D language (that is pure an addition, it
should cause no breaking changes).

The introduction of "static static", it roughly means "static regarding to the
template". This means that if a template contains a "static static" item, it is
shared among all instantiations of the template.

Here are some use cases:

- - - - - - - - - - - - - -

Templated classes or templated structs sometimes have member functions that are
meant to be shared among all the instantiations of the template.

struct Foo(T) {
    T x;
    static static int sqr(int x) { return x ^^ 2; }
}


Here static static allows to reduce template bloat, because only one sqr()
function is generated regardless the T type. Putting sqr() outside Foo is an
alternative solution, but it loses the packaging given by Foo itself (despite
the usefulness of universal call syntax).

A third solution is to put inside Foo() just a stub function that calls an
external private _sqr() function. This has both the advantage of keeping sqr()
in the the namespace, and keeps the template bloat low because only very little
sqr() are generated for each instantiation of Foo. But this requires parameter
fowarding and increases code complexity a little.

- - - - - - - - - - - - - -

There are cases where templated functions need a static variable that is shared
among all instantiations of the template:

int foo(T)() if (is(T == char) || is(T == dchar) || is(T == wchar)) {
    static static dchar[] table = ['a', 'b', 'c'];
    static static immutable val = someHeavyCTFE(10);
    // uses table and val here
    return 0;
}



In this case static static is useful to save memory, because only one table is
present for all instantiations of Foo. And only one val is computed, saving
compilation time.

An alternative design is to put both table and val outside foo(), but this adds
more global names that are better kept inside foo(), just like a static
variable in a function avoids names at module level.


This example program computes some numbers:


uint topswops(size_t nMax = 16)(in size_t n) nothrow
in {
    assert(n > 0 && n < nMax);
} body {
    size_t d = 0;
    __gshared uint[nMax] best;

    alias T = byte;
    alias Deck = T[nMax];

    void trySwaps(in ref Deck deck, in uint f) nothrow {
        if (d > best[n])
            best[n] = d;

        foreach_reverse (immutable i; 0 .. n) {
            if (deck[i] == -1 || deck[i] == i)
                break;
            if (d + best[i] <= best[n])
                return;
        }

        Deck deck2 = deck;

        d++;
        uint k = 1;
        foreach (immutable i; 1 .. n) {
            k <<= 1;
            if (deck2[i] == -1) {
                if (f & k)
                    continue;
            } else if (deck2[i] != i)
                continue;

            deck2[0] = cast(T)i;
            foreach_reverse (immutable j; 0 .. i)
                deck2[i - j] = deck[j];
            trySwaps(deck2, f | k);
        }
        d--;
    }

    best[n] = 0;
    Deck deck0 = -1;
    deck0[0] = 0;
    trySwaps(deck0, 1);
    return best[n];
}

import std.stdio;

void main() {
    foreach (i; 1 .. 13)
        writefln("%2d: %d", i, topswops(i));
}





To speed up the computation the n argument is now a compile-time value, and
topswops() is a template:


import std.stdio, std.typetuple;

template Range(int start, int stop) {
    static if (stop <= start)
        alias TypeTuple!() Range;
    else
        alias TypeTuple!(Range!(start, stop - 1), stop - 1) Range;
}

__gshared uint[32] best;

uint topswops(size_t n)() nothrow {
    static assert(n > 0 && n < best.length);
    size_t d = 0;

    alias T = byte;
    alias Deck = T[n];

    void trySwaps(in ref Deck deck, in uint f) nothrow {
        if (d > best[n])
            best[n] = d;

        foreach_reverse (immutable i; Range!(0, n)) {
            if (deck[i] == -1 || deck[i] == i)
                break;
            if (d + best[i] <= best[n])
                return;
        }

        Deck deck2 = void;
        foreach (immutable i; Range!(0, n)) // Copy.
            deck2[i] = deck[i];

        d++;
        foreach (immutable i; Range!(1, n)) {
            enum uint k = 1U << i;
            if (deck2[i] == -1) {
                if (f & k)
                    continue;
            } else if (deck2[i] != i)
                continue;

            deck2[0] = cast(T)i;
            foreach_reverse (immutable j; Range!(0, i))
                deck2[i - j] = deck[j]; // Reverse copy.
            trySwaps(deck2, f | k);
        }
        d--;
    }

    best[n] = 0;
    Deck deck0 = -1;
    deck0[0] = 0;
    trySwaps(deck0, 1);
    return best[n];
}

void main() {
    foreach (i; Range!(1, 13))
        writefln("%2d: %d", i, topswops!i());
}



To work correctly this program requires a static variable "best". Once
topswops() becomes a template, "best" must be moved to module scope. This is
avoided by static static:

...
uint topswops(size_t n)() nothrow {
    static assert(n > 0 && n < best.length);
    size_t d = 0;
    static static __gshared uint[32] best;
...

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------


More information about the Digitalmars-d-bugs mailing list