// Written in the D programming language.

/**
This module implements a variety of type constructors, i.e., templates
that allow construction of new, useful general-purpose types.

Source:    $(PHOBOSSRC std/_typecons.d)

Macros:

WIKI = Phobos/StdVariant

Synopsis:

----
// value tuples
alias Coord = Tuple!(float, "x", float, "y", float, "z");
Coord c;
c[1] = 1;       // access by index
c.z = 1;        // access by given name
alias DicEntry = Tuple!(string, string); // names can be omitted

// Rebindable references to const and immutable objects
void bar()
{
    const w1 = new Widget, w2 = new Widget;
    w1.foo();
    // w1 = w2 would not work; can't rebind const object
    auto r = Rebindable!(const Widget)(w1);
    // invoke method as if r were a Widget object
    r.foo();
    // rebind r to refer to another object
    r = w2;
}
----

Copyright: Copyright the respective authors, 2008-
License:   $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors:   $(WEB erdani.org, Andrei Alexandrescu),
           $(WEB bartoszmilewski.wordpress.com, Bartosz Milewski),
           Don Clugston,
           Shin Fujishiro,
           Kenji Hara
 */
module std.typecons;
import std.traits;
// FIXME
import std.typetuple; // : TypeTuple, allSatisfy;

debug(Unique) import std.stdio;

/**
Encapsulates unique ownership of a resource.  Resource of type $(D T) is
deleted at the end of the scope, unless it is transferred.  The
transfer can be explicit, by calling $(D release), or implicit, when
returning Unique from a function. The resource can be a polymorphic
class object, in which case Unique behaves polymorphically too.
*/
struct Unique(T)
{
/** Represents a reference to $(D T). Resolves to $(D T*) if $(D T) is a value type. */
static if (is(T:Object))
    alias RefT = T;
else
    alias RefT = T*;

public:
    // Deferred in case we get some language support for checking uniqueness.
    version(None)
    /**
    Allows safe construction of $(D Unique). It creates the resource and
    guarantees unique ownership of it (unless $(D T) publishes aliases of
    $(D this)).
    Note: Nested structs/classes cannot be created.
    Params:
    args = Arguments to pass to $(D T)'s constructor.
    ---
    static class C {}
    auto u = Unique!(C).create();
    ---
    */
    static Unique!T create(A...)(auto ref A args)
    if (__traits(compiles, new T(args)))
    {
        debug(Unique) writeln("Unique.create for ", T.stringof);
        Unique!T u;
        u._p = new T(args);
        return u;
    }

    /**
    Constructor that takes an rvalue.
    It will ensure uniqueness, as long as the rvalue
    isn't just a view on an lvalue (e.g., a cast).
    Typical usage:
    ----
    Unique!Foo f = new Foo;
    ----
    */
    this(RefT p)
    {
        debug(Unique) writeln("Unique constructor with rvalue");
        _p = p;
    }
    /**
    Constructor that takes an lvalue. It nulls its source.
    The nulling will ensure uniqueness as long as there
    are no previous aliases to the source.
    */
    this(ref RefT p)
    {
        _p = p;
        debug(Unique) writeln("Unique constructor nulling source");
        p = null;
        assert(p is null);
    }
    /**
    Constructor that takes a $(D Unique) of a type that is convertible to our type.

    Typically used to transfer a $(D Unique) rvalue of derived type to
    a $(D Unique) of base type.
    Example:
    ---
    class C : Object {}

    Unique!C uc = new C;
    Unique!Object uo = uc.release;
    ---
    */
    this(U)(Unique!U u)
    if (is(u.RefT:RefT))
    {
        debug(Unique) writeln("Unique constructor converting from ", U.stringof);
        _p = u._p;
        u._p = null;
    }

    /// Transfer ownership from a $(D Unique) of a type that is convertible to our type.
    void opAssign(U)(Unique!U u)
    if (is(u.RefT:RefT))
    {
        debug(Unique) writeln("Unique opAssign converting from ", U.stringof);
        // first delete any resource we own
        destroy(this);
        _p = u._p;
        u._p = null;
    }

    ~this()
    {
        debug(Unique) writeln("Unique destructor of ", (_p is null)? null: _p);
        if (_p !is null) delete _p;
        _p = null;
    }
    /** Returns whether the resource exists. */
    @property bool isEmpty() const
    {
        return _p is null;
    }
    /** Transfer ownership to a $(D Unique) rvalue. Nullifies the current contents. */
    Unique release()
    {
        debug(Unique) writeln("Release");
        auto u = Unique(_p);
        assert(_p is null);
        debug(Unique) writeln("return from Release");
        return u;
    }
    /** Forwards member access to contents. */
    RefT opDot() { return _p; }

    /**
    Postblit operator is undefined to prevent the cloning of $(D Unique) objects.
    */
    @disable this(this);

private:
    RefT _p;
}

///
unittest
{
    static struct S
    {
        int i;
        this(int i){this.i = i;}
    }
    Unique!S produce()
    {
        // Construct a unique instance of S on the heap
        Unique!S ut = new S(5);
        // Implicit transfer of ownership
        return ut;
    }
    // Borrow a unique resource by ref
    void increment(ref Unique!S ur)
    {
        ur.i++;
    }
    void consume(Unique!S u2)
    {
        assert(u2.i == 6);
        // Resource automatically deleted here
    }
    Unique!S u1;
    assert(u1.isEmpty);
    u1 = produce();
    increment(u1);
    assert(u1.i == 6);
    //consume(u1); // Error: u1 is not copyable
    // Transfer ownership of the resource
    consume(u1.release);
    assert(u1.isEmpty);
}

unittest
{
    // test conversion to base ref
    int deleted = 0;
    class C
    {
        ~this(){deleted++;}
    }
    // constructor conversion
    Unique!Object u = Unique!C(new C);
    static assert(!__traits(compiles, {u = new C;}));
    assert(!u.isEmpty);
    destroy(u);
    assert(deleted == 1);

    Unique!C uc = new C;
    static assert(!__traits(compiles, {Unique!Object uo = uc;}));
    Unique!Object uo = new C;
    // opAssign conversion, deleting uo resource first
    uo = uc.release;
    assert(uc.isEmpty);
    assert(!uo.isEmpty);
    assert(deleted == 2);
}

unittest
{
    debug(Unique) writeln("Unique class");
    class Bar
    {
        ~this() { debug(Unique) writeln("    Bar destructor"); }
        int val() const { return 4; }
    }
    alias UBar = Unique!(Bar);
    UBar g(UBar u)
    {
        debug(Unique) writeln("inside g");
        return u.release;
    }
    auto ub = UBar(new Bar);
    assert(!ub.isEmpty);
    assert(ub.val == 4);
    static assert(!__traits(compiles, {auto ub3 = g(ub);}));
    debug(Unique) writeln("Calling g");
    auto ub2 = g(ub.release);
    debug(Unique) writeln("Returned from g");
    assert(ub.isEmpty);
    assert(!ub2.isEmpty);
}

unittest
{
    debug(Unique) writeln("Unique struct");
    struct Foo
    {
        ~this() { debug(Unique) writeln("    Foo destructor"); }
        int val() const { return 3; }
    }
    alias UFoo = Unique!(Foo);

    UFoo f(UFoo u)
    {
        debug(Unique) writeln("inside f");
        return u.release;
    }

    auto uf = UFoo(new Foo);
    assert(!uf.isEmpty);
    assert(uf.val == 3);
    static assert(!__traits(compiles, {auto uf3 = f(uf);}));
    debug(Unique) writeln("Unique struct: calling f");
    auto uf2 = f(uf.release);
    debug(Unique) writeln("Unique struct: returned from f");
    assert(uf.isEmpty);
    assert(!uf2.isEmpty);
}


/**
Tuple of values, for example $(D Tuple!(int, string)) is a record that
stores an $(D int) and a $(D string). $(D Tuple) can be used to bundle
values together, notably when returning multiple values from a
function. If $(D obj) is a tuple, the individual members are
accessible with the syntax $(D obj[0]) for the first field, $(D obj[1])
for the second, and so on.

The choice of zero-based indexing instead of one-base indexing was
motivated by the ability to use value tuples with various compile-time
loop constructs (e.g. type tuple iteration), all of which use
zero-based indexing.

Example:

----
Tuple!(int, int) point;
// assign coordinates
point[0] = 5;
point[1] = 6;
// read coordinates
auto x = point[0];
auto y = point[1];
----

Tuple members can be named. It is legal to mix named and unnamed
members. The method above is still applicable to all fields.

Example:

----
alias Entry = Tuple!(int, "index", string, "value");
Entry e;
e.index = 4;
e.value = "Hello";
assert(e[1] == "Hello");
assert(e[0] == 4);
----

Tuples with named fields are distinct types from tuples with unnamed
fields, i.e. each naming imparts a separate type for the tuple. Two
tuple differing in naming only are still distinct, even though they
might have the same structure.

Example:

----
Tuple!(int, "x", int, "y") point1;
Tuple!(int, int) point2;
assert(!is(typeof(point1) == typeof(point2))); // passes
----
*/
template Tuple(Specs...)
{
    import std.typetuple : staticMap;

    // Parse (type,name) pairs (FieldSpecs) out of the specified
    // arguments. Some fields would have name, others not.
    template parseSpecs(Specs...)
    {
        static if (Specs.length == 0)
        {
            alias parseSpecs = TypeTuple!();
        }
        else static if (is(Specs[0]))
        {
            static if (is(typeof(Specs[1]) : string))
            {
                alias parseSpecs =
                    TypeTuple!(FieldSpec!(Specs[0 .. 2]),
                               parseSpecs!(Specs[2 .. $]));
            }
            else
            {
                alias parseSpecs =
                    TypeTuple!(FieldSpec!(Specs[0]),
                               parseSpecs!(Specs[1 .. $]));
            }
        }
        else
        {
            static assert(0, "Attempted to instantiate Tuple with an "
                            ~"invalid argument: "~ Specs[0].stringof);
        }
    }

    template FieldSpec(T, string s = "")
    {
        alias Type = T;
        alias name = s;
    }

    alias fieldSpecs = parseSpecs!Specs;

    // Used with staticMap.
    alias extractType(alias spec) = spec.Type;
    alias extractName(alias spec) = spec.name;

    // Generates named fields as follows:
    //    alias name_0 = Identity!(field[0]);
    //    alias name_1 = Identity!(field[1]);
    //      :
    // NOTE: field[k] is an expression (which yields a symbol of a
    //       variable) and can't be aliased directly.
    string injectNamedFields()
    {
        string decl = "";
        foreach (i, name; staticMap!(extractName, fieldSpecs))
        {
            import std.format : format;

            decl ~= format("alias _%s = Identity!(field[%s]);", i, i);
            if (name.length != 0)
            {
                decl ~= format("alias %s = _%s;", name, i);
            }
        }
        return decl;
    }

    // Returns Specs for a subtuple this[from .. to] preserving field
    // names if any.
    alias sliceSpecs(size_t from, size_t to) =
        staticMap!(expandSpec, fieldSpecs[from .. to]);

    template expandSpec(alias spec)
    {
        static if (spec.name.length == 0)
        {
            alias expandSpec = TypeTuple!(spec.Type);
        }
        else
        {
            alias expandSpec = TypeTuple!(spec.Type, spec.name);
        }
    }

    enum areCompatibleTuples(Tup1, Tup2, string op) = isTuple!Tup2 && is(typeof(
    {
        Tup1 tup1 = void;
        Tup2 tup2 = void;
        static assert(tup1.field.length == tup2.field.length);
        foreach (i, _; Tup1.Types)
        {
            auto lhs = typeof(tup1.field[i]).init;
            auto rhs = typeof(tup2.field[i]).init;
            static if (op == "=")
                lhs = rhs;
            else
                auto result = mixin("lhs "~op~" rhs");
        }
    }));

    enum areBuildCompatibleTuples(Tup1, Tup2) = isTuple!Tup2 && is(typeof(
    {
        static assert(Tup1.Types.length == Tup2.Types.length);
        foreach (i, _; Tup1.Types)
            static assert(isBuildable!(Tup1.Types[i], Tup2.Types[i]));
    }));

    /+ Returns $(D true) iff a $(D T) can be initialized from a $(D U). +/
    enum isBuildable(T, U) =  is(typeof(
    {
        U u = U.init;
        T t = u;
    }));
    /+ Helper for partial instanciation +/
    template isBuildableFrom(U)
    {
        enum isBuildableFrom(T) = isBuildable!(T, U);
    }

    struct Tuple
    {
        /**
         * The type of the tuple's components.
         */
        alias Types = staticMap!(extractType, fieldSpecs);

        /**
         * The names of the tuple's components. Unnamed fields have empty names.
         *
         * Examples:
         * ----
         * alias Fields = Tuple!(int, "id", string, float);
         * static assert(Fields.fieldNames == TypeTuple!("id", "", ""));
         * ----
         */
        alias fieldNames = staticMap!(extractName, fieldSpecs);

        /**
         * Use $(D t.expand) for a tuple $(D t) to expand it into its
         * components. The result of $(D expand) acts as if the tuple components
         * were listed as a list of values. (Ordinarily, a $(D Tuple) acts as a
         * single value.)
         *
         * Examples:
         * ----
         * auto t = tuple(1, " hello ", 2.3);
         * writeln(t);        // Tuple!(int, string, double)(1, " hello ", 2.3)
         * writeln(t.expand); // 1 hello 2.3
         * ----
         */
        Types expand;
        mixin(injectNamedFields());

        static if (is(Specs))
        {
            // This is mostly to make t[n] work.
            alias expand this;
        }
        else
        {
            @property
            ref inout(Tuple!Types) _Tuple_super() inout @trusted
            {
                foreach (i, _; Types)   // Rely on the field layout
                {
                    static assert(typeof(return).init.tupleof[i].offsetof ==
                                                       expand[i].offsetof);
                }
                return *cast(typeof(return)*) &(field[0]);
            }
            // This is mostly to make t[n] work.
            alias _Tuple_super this;
        }

        // backwards compatibility
        alias field = expand;

        /**
         * Constructor taking one value for each field.
         */
        static if (Types.length > 0)
        {
            this(Types values)
            {
                field[] = values[];
            }
        }

        /**
         * Constructor taking a compatible array.
         *
         * Examples:
         * ----
         * int[2] ints;
         * Tuple!(int, int) t = ints;
         * ----
         */
        this(U, size_t n)(U[n] values)
        if (n == Types.length && allSatisfy!(isBuildableFrom!U, Types))
        {
            foreach (i, _; Types)
            {
                field[i] = values[i];
            }
        }

        /**
         * Constructor taking a compatible tuple.
         */
        this(U)(U another)
        if (areBuildCompatibleTuples!(typeof(this), U))
        {
            field[] = another.field[];
        }

        /**
         * Comparison for equality.
         */
        bool opEquals(R)(R rhs)
        if (areCompatibleTuples!(typeof(this), R, "=="))
        {
            return field[] == rhs.field[];
        }
        /// ditto
        bool opEquals(R)(R rhs) const
        if (areCompatibleTuples!(typeof(this), R, "=="))
        {
            return field[] == rhs.field[];
        }

        /**
         * Comparison for ordering.
         */
        int opCmp(R)(R rhs)
        if (areCompatibleTuples!(typeof(this), R, "<"))
        {
            foreach (i, Unused; Types)
            {
                if (field[i] != rhs.field[i])
                {
                    return field[i] < rhs.field[i] ? -1 : 1;
                }
            }
            return 0;
        }
        /// ditto
        int opCmp(R)(R rhs) const
        if (areCompatibleTuples!(typeof(this), R, "<"))
        {
            foreach (i, Unused; Types)
            {
                if (field[i] != rhs.field[i])
                {
                    return field[i] < rhs.field[i] ? -1 : 1;
                }
            }
            return 0;
        }

        /**
         * Assignment from another tuple. Each element of the source must be
         * implicitly assignable to the respective element of the target.
         */
        void opAssign(R)(auto ref R rhs)
        if (areCompatibleTuples!(typeof(this), R, "="))
        {
            import std.algorithm : swap;

            static if (is(R : Tuple!Types) && !__traits(isRef, rhs))
            {
                if (__ctfe)
                {
                    // Cannot use swap at compile time
                    field[] = rhs.field[];
                }
                else
                {
                    // Use swap-and-destroy to optimize rvalue assignment
                    swap!(Tuple!Types)(this, rhs);
                }
            }
            else
            {
                // Do not swap; opAssign should be called on the fields.
                field[] = rhs.field[];
            }
        }

        /**
         * Takes a slice of the tuple.
         *
         * Examples:
         * ----
         * Tuple!(int, string, float, double) a;
         * a[1] = "abc";
         * a[2] = 4.5;
         * auto s = a.slice!(1, 3);
         * static assert(is(typeof(s) == Tuple!(string, float)));
         * assert(s[0] == "abc" && s[1] == 4.5);
         * ----
         */
        @property
        ref Tuple!(sliceSpecs!(from, to)) slice(size_t from, size_t to)() @trusted
        if (from <= to && to <= Types.length)
        {
            return *cast(typeof(return)*) &(field[from]);
        }

        size_t toHash() const nothrow @trusted
        {
            size_t h = 0;
            foreach (i, T; Types)
                h += typeid(T).getHash(cast(const void*)&field[i]);
            return h;
        }

        /**
         * Converts to string.
         */
        void toString(DG)(scope DG sink)
        {
            enum header = typeof(this).stringof ~ "(",
                 footer = ")",
                 separator = ", ";
            sink(header);
            foreach (i, Type; Types)
            {
                static if (i > 0)
                {
                    sink(separator);
                }
                // TODO: Change this once toString() works for shared objects.
                static if (is(Type == class) && is(typeof(Type.init) == shared))
                {
                    sink(Type.stringof);
                }
                else
                {
                    import std.format : FormatSpec, formatElement;
                    FormatSpec!char f;
                    formatElement(sink, field[i], f);
                }
            }
            sink(footer);
        }

        string toString()()
        {
            import std.conv : to;
            return this.to!string;
        }
    }
}

/**
    Return a copy of a Tuple with its fields in reverse order.
 */
ReverseTupleType!T reverse(T)(T t)
    if (isTuple!T)
{
    import std.typetuple : Reverse;
    // @@@BUG@@@ Cannot be an internal function due to forward reference issues.

    // @@@BUG@@@ 9929 Need 'this' when calling template with expanded tuple
    // return tuple(Reverse!(t.expand));

    typeof(return) result;
    auto tup = t.expand;
    result.expand = Reverse!tup;
    return result;
}

///
unittest
{
    auto tup = tuple(1, "2");
    assert(tup.reverse == tuple("2", 1));
}

/* Get a Tuple type with the reverse specification of Tuple T. */
private template ReverseTupleType(T)
    if (isTuple!T)
{
    static if (is(T : Tuple!A, A...))
        alias ReverseTupleType = Tuple!(ReverseTupleSpecs!A);
}

/* Reverse the Specs of a Tuple. */
private template ReverseTupleSpecs(T...)
{
    static if (T.length > 1)
    {
        static if (is(typeof(T[$-1]) : string))
        {
            alias ReverseTupleSpecs = TypeTuple!(T[$-2], T[$-1], ReverseTupleSpecs!(T[0 .. $-2]));
        }
        else
        {
            alias ReverseTupleSpecs = TypeTuple!(T[$-1], ReverseTupleSpecs!(T[0 .. $-1]));
        }
    }
    else
    {
        alias ReverseTupleSpecs = T;
    }
}

unittest
{
    import std.conv;
    {
        Tuple!(int, "a", int, "b") nosh;
        static assert(nosh.length == 2);
        nosh.a = 5;
        nosh.b = 6;
        assert(nosh.a == 5);
        assert(nosh.b == 6);
    }
    {
        Tuple!(short, double) b;
        static assert(b.length == 2);
        b[1] = 5;
        auto a = Tuple!(int, real)(b);
        assert(a[0] == 0 && a[1] == 5);
        a = Tuple!(int, real)(1, 2);
        assert(a[0] == 1 && a[1] == 2);
        auto c = Tuple!(int, "a", double, "b")(a);
        assert(c[0] == 1 && c[1] == 2);
    }
    {
        Tuple!(int, real) nosh;
        nosh[0] = 5;
        nosh[1] = 0;
        assert(nosh[0] == 5 && nosh[1] == 0);
        assert(nosh.to!string == "Tuple!(int, real)(5, 0)", nosh.to!string);
        Tuple!(int, int) yessh;
        nosh = yessh;
    }
    {
        class A {}
        Tuple!(int, shared A) nosh;
        nosh[0] = 5;
        assert(nosh[0] == 5 && nosh[1] is null);
        assert(nosh.to!string == "Tuple!(int, shared(A))(5, shared(A))");
    }
    {
        Tuple!(int, string) t;
        t[0] = 10;
        t[1] = "str";
        assert(t[0] == 10 && t[1] == "str");
        assert(t.to!string == `Tuple!(int, string)(10, "str")`, t.to!string);
    }
    {
        Tuple!(int, "a", double, "b") x;
        static assert(x.a.offsetof == x[0].offsetof);
        static assert(x.b.offsetof == x[1].offsetof);
        x.b = 4.5;
        x.a = 5;
        assert(x[0] == 5 && x[1] == 4.5);
        assert(x.a == 5 && x.b == 4.5);
    }
    // indexing
    {
        Tuple!(int, real) t;
        static assert(is(typeof(t[0]) == int));
        static assert(is(typeof(t[1]) == real));
        int* p0 = &t[0];
        real* p1 = &t[1];
        t[0] = 10;
        t[1] = -200.0L;
        assert(*p0 == t[0]);
        assert(*p1 == t[1]);
    }
    // slicing
    {
        Tuple!(int, "x", real, "y", double, "z", string) t;
        t[0] = 10;
        t[1] = 11;
        t[2] = 12;
        t[3] = "abc";
        auto a = t.slice!(0, 3);
        assert(a.length == 3);
        assert(a.x == t.x);
        assert(a.y == t.y);
        assert(a.z == t.z);
        auto b = t.slice!(2, 4);
        assert(b.length == 2);
        assert(b.z == t.z);
        assert(b[1] == t[3]);
    }
    // nesting
    {
        Tuple!(Tuple!(int, real), Tuple!(string, "s")) t;
        static assert(is(typeof(t[0]) == Tuple!(int, real)));
        static assert(is(typeof(t[1]) == Tuple!(string, "s")));
        static assert(is(typeof(t[0][0]) == int));
        static assert(is(typeof(t[0][1]) == real));
        static assert(is(typeof(t[1].s) == string));
        t[0] = tuple(10, 20.0L);
        t[1].s = "abc";
        assert(t[0][0] == 10);
        assert(t[0][1] == 20.0L);
        assert(t[1].s == "abc");
    }
    // non-POD
    {
        static struct S
        {
            int count;
            this(this) { ++count; }
            ~this() { --count; }
            void opAssign(S rhs) { count = rhs.count; }
        }
        Tuple!(S, S) ss;
        Tuple!(S, S) ssCopy = ss;
        assert(ssCopy[0].count == 1);
        assert(ssCopy[1].count == 1);
        ssCopy[1] = ssCopy[0];
        assert(ssCopy[1].count == 2);
    }
    // bug 2800
    {
        static struct R
        {
            Tuple!(int, int) _front;
            @property ref Tuple!(int, int) front() return { return _front;  }
            @property bool empty() { return _front[0] >= 10; }
            void popFront() { ++_front[0]; }
        }
        foreach (a; R())
        {
            static assert(is(typeof(a) == Tuple!(int, int)));
            assert(0 <= a[0] && a[0] < 10);
            assert(a[1] == 0);
        }
    }
    // Construction with compatible elements
    {
        auto t1 = Tuple!(int, double)(1, 1);

        // 8702
        auto t8702a = tuple(tuple(1));
        auto t8702b = Tuple!(Tuple!(int))(Tuple!(int)(1));
    }
    // Construction with compatible tuple
    {
        Tuple!(int, int) x;
        x[0] = 10;
        x[1] = 20;
        Tuple!(int, "a", double, "b") y = x;
        assert(y.a == 10);
        assert(y.b == 20);
        // incompatible
        static assert(!__traits(compiles, Tuple!(int, int)(y)));
    }
    // 6275
    {
        const int x = 1;
        auto t1 = tuple(x);
        alias T = Tuple!(const(int));
        auto t2 = T(1);
    }
    // 9431
    {
        alias T = Tuple!(int[1][]);
        auto t = T([[10]]);
    }
    // 7666
    {
        auto tup = tuple(1, "2");
        assert(tup.reverse == tuple("2", 1));
    }
    {
        Tuple!(int, "x", string, "y") tup = tuple(1, "2");
        auto rev = tup.reverse;
        assert(rev == tuple("2", 1));
        assert(rev.x == 1 && rev.y == "2");
    }
    {
        Tuple!(wchar, dchar, int, "x", string, "y", char, byte, float) tup;
        tup = tuple('a', 'b', 3, "4", 'c', cast(byte)0x0D, 0.00);
        auto rev = tup.reverse;
        assert(rev == tuple(0.00, cast(byte)0x0D, 'c', "4", 3, 'b', 'a'));
        assert(rev.x == 3 && rev.y == "4");
    }
}
unittest
{
    // opEquals
    {
        struct Equ1 { bool opEquals(Equ1) { return true; } }
        auto  tm1 = tuple(Equ1.init);
        const tc1 = tuple(Equ1.init);
        static assert( is(typeof(tm1 == tm1)));
        static assert(!is(typeof(tm1 == tc1)));
        static assert(!is(typeof(tc1 == tm1)));
        static assert(!is(typeof(tc1 == tc1)));

        struct Equ2 { bool opEquals(const Equ2) const { return true; } }
        auto  tm2 = tuple(Equ2.init);
        const tc2 = tuple(Equ2.init);
        static assert( is(typeof(tm2 == tm2)));
        static assert( is(typeof(tm2 == tc2)));
        static assert( is(typeof(tc2 == tm2)));
        static assert( is(typeof(tc2 == tc2)));

        struct Equ3 { bool opEquals(T)(T) { return true; } }
        auto  tm3 = tuple(Equ3.init);           // bugzilla 8686
        const tc3 = tuple(Equ3.init);
        static assert( is(typeof(tm3 == tm3)));
        static assert( is(typeof(tm3 == tc3)));
        static assert(!is(typeof(tc3 == tm3)));
        static assert(!is(typeof(tc3 == tc3)));

        struct Equ4 { bool opEquals(T)(T) const { return true; } }
        auto  tm4 = tuple(Equ4.init);
        const tc4 = tuple(Equ4.init);
        static assert( is(typeof(tm4 == tm4)));
        static assert( is(typeof(tm4 == tc4)));
        static assert( is(typeof(tc4 == tm4)));
        static assert( is(typeof(tc4 == tc4)));
    }
    // opCmp
    {
        struct Cmp1 { int opCmp(Cmp1) { return 0; } }
        auto  tm1 = tuple(Cmp1.init);
        const tc1 = tuple(Cmp1.init);
        static assert( is(typeof(tm1 < tm1)));
        static assert(!is(typeof(tm1 < tc1)));
        static assert(!is(typeof(tc1 < tm1)));
        static assert(!is(typeof(tc1 < tc1)));

        struct Cmp2 { int opCmp(const Cmp2) const { return 0; } }
        auto  tm2 = tuple(Cmp2.init);
        const tc2 = tuple(Cmp2.init);
        static assert( is(typeof(tm2 < tm2)));
        static assert( is(typeof(tm2 < tc2)));
        static assert( is(typeof(tc2 < tm2)));
        static assert( is(typeof(tc2 < tc2)));

        struct Cmp3 { int opCmp(T)(T) { return 0; } }
        auto  tm3 = tuple(Cmp3.init);
        const tc3 = tuple(Cmp3.init);
        static assert( is(typeof(tm3 < tm3)));
        static assert( is(typeof(tm3 < tc3)));
        static assert(!is(typeof(tc3 < tm3)));
        static assert(!is(typeof(tc3 < tc3)));

        struct Cmp4 { int opCmp(T)(T) const { return 0; } }
        auto  tm4 = tuple(Cmp4.init);
        const tc4 = tuple(Cmp4.init);
        static assert( is(typeof(tm4 < tm4)));
        static assert( is(typeof(tm4 < tc4)));
        static assert( is(typeof(tc4 < tm4)));
        static assert( is(typeof(tc4 < tc4)));
    }
    {
        int[2] ints = [ 1, 2 ];
        Tuple!(int, int) t = ints;
        assert(t[0] == 1 && t[1] == 2);
        Tuple!(long, uint) t2 = ints;
        assert(t2[0] == 1 && t2[1] == 2);
    }
}
@safe unittest
{
    auto t1 = Tuple!(int, "x", string, "y")(1, "a");
    assert(t1.x == 1);
    assert(t1.y == "a");
    void foo(Tuple!(int, string) t2) {}
    foo(t1);

    Tuple!(int, int)[] arr;
    arr ~= tuple(10, 20); // OK
    arr ~= Tuple!(int, "x", int, "y")(10, 20); // NG -> OK

    static assert(is(typeof(Tuple!(int, "x", string, "y").tupleof) ==
                     typeof(Tuple!(int,      string     ).tupleof)));
}
unittest
{
    // Bugzilla 10686
    immutable Tuple!(int) t1;
    auto r1 = t1[0]; // OK
    immutable Tuple!(int, "x") t2;
    auto r2 = t2[0]; // error
}
unittest
{
    import std.exception : assertCTFEable;

    // Bugzilla 10218
    assertCTFEable!(
    {
        auto t = tuple(1);
        t = tuple(2);   // assignment
    });
}
unittest
{
    class Foo{}
    Tuple!(immutable(Foo)[]) a;
}

unittest
{
    //Test non-assignable
    static struct S
    {
        int* p;
    }
    alias IS = immutable S;
    static assert(!isAssignable!IS);

    auto s = IS.init;

    alias TIS = Tuple!IS;
    TIS a = tuple(s);
    TIS b = a;

    alias TISIS = Tuple!(IS, IS);
    TISIS d = tuple(s, s);
    IS[2] ss;
    TISIS e = TISIS(ss);
}

// Bugzilla #9819
unittest
{
    alias T = Tuple!(int, "x", double, "foo");
    static assert(T.fieldNames[0] == "x");
    static assert(T.fieldNames[1] == "foo");

    alias Fields = Tuple!(int, "id", string, float);
    static assert(Fields.fieldNames == TypeTuple!("id", "", ""));
}

// Bugzilla 13837
unittest
{
    // New behaviour, named arguments.
    static assert(is(
        typeof(tuple!("x")(1)) == Tuple!(int, "x")));
    static assert(is(
        typeof(tuple!("x")(1.0)) == Tuple!(double, "x")));
    static assert(is(
        typeof(tuple!("x")("foo")) == Tuple!(string, "x")));
    static assert(is(
        typeof(tuple!("x", "y")(1, 2.0)) == Tuple!(int, "x", double, "y")));

    auto a = tuple!("a", "b", "c")("1", 2, 3.0f);
    static assert(is(typeof(a.a) == string));
    static assert(is(typeof(a.b) == int));
    static assert(is(typeof(a.c) == float));

    // Old behaviour, but with explicit type parameters.
    static assert(is(
        typeof(tuple!(int, double)(1, 2.0)) == Tuple!(int, double)));
    static assert(is(
        typeof(tuple!(const int)(1)) == Tuple!(const int)));
    static assert(is(
        typeof(tuple()) == Tuple!()));

    // Nonsensical behaviour
    static assert(!__traits(compiles, tuple!(1)(2)));
    static assert(!__traits(compiles, tuple!("x")(1, 2)));
    static assert(!__traits(compiles, tuple!("x", "y")(1)));
    static assert(!__traits(compiles, tuple!("x")()));
    static assert(!__traits(compiles, tuple!("x", int)(2)));
}

unittest
{
    class C {}
    Tuple!(Rebindable!(const C)) a;
    Tuple!(const C) b;
    a = b;
}

@nogc unittest
{
    alias T = Tuple!(string, "s");
    T x;
    x = T.init;
}

/**
Returns a $(D Tuple) object instantiated and initialized according to
the arguments.
*/

template tuple(Names...)
{
    auto tuple(Args...)(Args args)
    {
        static if (Names.length == 0)
        {
            // No specified names, just infer types from Args...
            return Tuple!Args(args);
        }
        else static if (!is(typeof(Names[0]) : string))
        {
            // Names[0] isn't a string, must be explicit types.
            return Tuple!Names(args);
        }
        else
        {
            // Names[0] is a string, so must be specifying names.
            static assert(Names.length == Args.length,
                "Insufficient number of names given.");

            // Interleave(a, b).and(c, d) == (a, c, b, d)
            // This is to get the interleaving of types and names for Tuple
            // e.g. Tuple!(int, "x", string, "y")
            template Interleave(A...)
            {
                template and(B...) if (B.length == 1)
                {
                    alias TypeTuple!(A[0], B[0]) and;
                }

                template and(B...) if (B.length != 1)
                {
                    alias TypeTuple!(A[0], B[0],
                        Interleave!(A[1..$]).and!(B[1..$])) and;
                }
            }
            return Tuple!(Interleave!(Args).and!(Names))(args);
        }
    }
}

///
unittest
{
    auto value = tuple(5, 6.7, "hello");
    assert(value[0] == 5);
    assert(value[1] == 6.7);
    assert(value[2] == "hello");

    // Field names can be provided.
    auto entry = tuple!("index", "value")(4, "Hello");
    assert(entry.index == 4);
    assert(entry.value == "Hello");
}

/**
Returns $(D true) if and only if $(D T) is an instance of the
$(D Tuple) struct template.
 */
template isTuple(T)
{
    static if (is(Unqual!T Unused : Tuple!Specs, Specs...))
    {
        enum isTuple = true;
    }
    else
    {
        enum isTuple = false;
    }
}

///
unittest
{
    static assert(isTuple!(Tuple!()));
    static assert(isTuple!(Tuple!(int)));
    static assert(isTuple!(Tuple!(int, real, string)));
    static assert(isTuple!(Tuple!(int, "x", real, "y")));
    static assert(isTuple!(Tuple!(int, Tuple!(real), string)));
}

unittest
{
    static assert(isTuple!(const Tuple!(int)));
    static assert(isTuple!(immutable Tuple!(int)));

    static assert(!isTuple!(int));
    static assert(!isTuple!(const int));

    struct S {}
    static assert(!isTuple!(S));
}

// used by both Rebindable and UnqualRef
private mixin template RebindableCommon(T, U, alias This)
    if (is(T == class) || is(T == interface))
{
    private union
    {
        T original;
        U stripped;
    }

    @trusted pure nothrow @nogc
    {
        void opAssign(T another)
        {
            stripped = cast(U) another;
        }

        void opAssign(typeof(this) another)
        {
            stripped = another.stripped;
        }

        static if (is(T == const U) && is(T == const shared U))
        {
            // safely assign immutable to const / const shared
            void opAssign(This!(immutable U) another)
            {
                stripped = another.stripped;
            }
        }

        this(T initializer)
        {
            opAssign(initializer);
        }

        @property ref inout(T) get() inout
        {
            return original;
        }
    }

    alias get this;
}

/**
$(D Rebindable!(T)) is a simple, efficient wrapper that behaves just
like an object of type $(D T), except that you can reassign it to
refer to another object. For completeness, $(D Rebindable!(T)) aliases
itself away to $(D T) if $(D T) is a non-const object type. However,
$(D Rebindable!(T)) does not compile if $(D T) is a non-class type.

Regular $(D const) object references cannot be reassigned:

----
class Widget { int x; int y() const { return x; } }
const a = new Widget;
a.y();          // fine
a.x = 5;        // error! can't modify const a
a = new Widget; // error! can't modify const a
----

However, $(D Rebindable!(Widget)) does allow reassignment, while
otherwise behaving exactly like a $(D const Widget):

----
auto a = Rebindable!(const Widget)(new Widget);
a.y();          // fine
a.x = 5;        // error! can't modify const a
a = new Widget; // fine
----

You may want to use $(D Rebindable) when you want to have mutable
storage referring to $(D const) objects, for example an array of
references that must be sorted in place. $(D Rebindable) does not
break the soundness of D's type system and does not incur any of the
risks usually associated with $(D cast).

 */
template Rebindable(T) if (is(T == class) || is(T == interface) || isDynamicArray!T)
{
    static if (is(T == const U, U) || is(T == immutable U, U))
    {
        static if (isDynamicArray!T)
        {
            import std.range.primitives : ElementEncodingType;
            alias Rebindable = const(ElementEncodingType!T)[];
        }
        else
        {
            struct Rebindable
            {
                mixin RebindableCommon!(T, U, Rebindable);
            }
        }
    }
    else
    {
        alias Rebindable = T;
    }
}

/**
Convenience function for creating a $(D Rebindable) using automatic type
inference.
*/
Rebindable!T rebindable(T)(T obj)
if (is(T == class) || is(T == interface) || isDynamicArray!T)
{
    typeof(return) ret;
    ret = obj;
    return ret;
}

/**
This function simply returns the $(D Rebindable) object passed in.  It's useful
in generic programming cases when a given object may be either a regular
$(D class) or a $(D Rebindable).
*/
Rebindable!T rebindable(T)(Rebindable!T obj)
{
    return obj;
}

unittest
{
    interface CI { int foo() const; }
    class C : CI {
      int foo() const { return 42; }
      @property int bar() const { return 23; }
    }
    Rebindable!(C) obj0;
    static assert(is(typeof(obj0) == C));

    Rebindable!(const(C)) obj1;
    static assert(is(typeof(obj1.get) == const(C)), typeof(obj1.get).stringof);
    static assert(is(typeof(obj1.stripped) == C));
    obj1 = new C;
    assert(obj1.get !is null);
    obj1 = new const(C);
    assert(obj1.get !is null);

    Rebindable!(immutable(C)) obj2;
    static assert(is(typeof(obj2.get) == immutable(C)));
    static assert(is(typeof(obj2.stripped) == C));
    obj2 = new immutable(C);
    assert(obj1.get !is null);

    // test opDot
    assert(obj2.foo() == 42);
    assert(obj2.bar == 23);

    interface I { final int foo() const { return 42; } }
    Rebindable!(I) obj3;
    static assert(is(typeof(obj3) == I));

    Rebindable!(const I) obj4;
    static assert(is(typeof(obj4.get) == const I));
    static assert(is(typeof(obj4.stripped) == I));
    static assert(is(typeof(obj4.foo()) == int));
    obj4 = new class I {};

    Rebindable!(immutable C) obj5i;
    Rebindable!(const C) obj5c;
    obj5c = obj5c;
    obj5c = obj5i;
    obj5i = obj5i;
    static assert(!__traits(compiles, obj5i = obj5c));

    // Test the convenience functions.
    auto obj5convenience = rebindable(obj5i);
    assert(obj5convenience is obj5i);

    auto obj6 = rebindable(new immutable(C));
    static assert(is(typeof(obj6) == Rebindable!(immutable C)));
    assert(obj6.foo() == 42);

    auto obj7 = rebindable(new C);
    CI interface1 = obj7;
    auto interfaceRebind1 = rebindable(interface1);
    assert(interfaceRebind1.foo() == 42);

    const interface2 = interface1;
    auto interfaceRebind2 = rebindable(interface2);
    assert(interfaceRebind2.foo() == 42);

    auto arr = [1,2,3,4,5];
    const arrConst = arr;
    assert(rebindable(arr) == arr);
    assert(rebindable(arrConst) == arr);

    // Issue 7654
    immutable(char[]) s7654;
    Rebindable!(typeof(s7654)) r7654 = s7654;

    foreach (T; TypeTuple!(char, wchar, char, int))
    {
        static assert(is(Rebindable!(immutable(T[])) == immutable(T)[]));
        static assert(is(Rebindable!(const(T[])) == const(T)[]));
        static assert(is(Rebindable!(T[]) == T[]));
    }

    // Issue 12046
    static assert(!__traits(compiles, Rebindable!(int[1])));
    static assert(!__traits(compiles, Rebindable!(const int[1])));
}

/**
    Similar to $(D Rebindable!(T)) but strips all qualifiers from the reference as
    opposed to just constness / immutability. Primary intended use case is with
    shared (having thread-local reference to shared class data)
 */
template UnqualRef(T)
    if (is(T == class) || is(T == interface))
{
    static if (is(T == const U, U)
        || is(T == immutable U, U)
        || is(T == shared U, U)
        || is(T == const shared U, U))
    {
        struct UnqualRef
        {
            mixin RebindableCommon!(T, U, UnqualRef);
        }
    }
    else
    {
        alias UnqualRef = T;
    }
}

///
unittest
{
    class Data {}

    static shared(Data) a;
    static UnqualRef!(shared Data) b;

    import core.thread;

    auto thread = new core.thread.Thread({
        a = new shared Data();
        b = new shared Data();
    });

    thread.start();
    thread.join();

    assert(a !is null);
    assert(b is null);
}

unittest
{
    class C { }
    alias T = UnqualRef!(const shared C);
    static assert (is(typeof(T.stripped) == C));
}



/**
  Order the provided members to minimize size while preserving alignment.
  Returns a declaration to be mixed in.
  Alignment is not always optimal for 80-bit reals, nor for structs declared
  as align(1).
*/
string alignForSize(E...)(string[] names...)
{
    // Sort all of the members by .alignof.
    // BUG: Alignment is not always optimal for align(1) structs
    // or 80-bit reals or 64-bit primitives on x86.
    // TRICK: Use the fact that .alignof is always a power of 2,
    // and maximum 16 on extant systems. Thus, we can perform
    // a very limited radix sort.
    // Contains the members with .alignof = 64,32,16,8,4,2,1

    assert(E.length == names.length,
        "alignForSize: There should be as many member names as the types");

    string[7] declaration = ["", "", "", "", "", "", ""];

    foreach (i, T; E)
    {
        auto a = T.alignof;
        auto k = a>=64? 0 : a>=32? 1 : a>=16? 2 : a>=8? 3 : a>=4? 4 : a>=2? 5 : 6;
        declaration[k] ~= T.stringof ~ " " ~ names[i] ~ ";\n";
    }

    auto s = "";
    foreach (decl; declaration)
        s ~= decl;
    return s;
}

///
unittest
{
    struct Banner {
        mixin(alignForSize!(byte[6], double)(["name", "height"]));
    }
}

unittest
{
    enum x = alignForSize!(int[], char[3], short, double[5])("x", "y","z", "w");
    struct Foo { int x; }
    enum y = alignForSize!(ubyte, Foo, cdouble)("x", "y", "z");

    enum passNormalX = x == "double[5] w;\nint[] x;\nshort z;\nchar[3] y;\n";
    enum passNormalY = y == "cdouble z;\nFoo y;\nubyte x;\n";

    enum passAbnormalX = x == "int[] x;\ndouble[5] w;\nshort z;\nchar[3] y;\n";
    enum passAbnormalY = y == "Foo y;\ncdouble z;\nubyte x;\n";
    // ^ blame http://d.puremagic.com/issues/show_bug.cgi?id=231

    static assert(passNormalX || passAbnormalX && double.alignof <= (int[]).alignof);
    static assert(passNormalY || passAbnormalY && double.alignof <= int.alignof);
}

/**
Defines a value paired with a distinctive "null" state that denotes
the absence of a value. If default constructed, a $(D
Nullable!T) object starts in the null state. Assigning it renders it
non-null. Calling $(D nullify) can nullify it again.

Practically $(D Nullable!T) stores a $(D T) and a $(D bool).
 */
struct Nullable(T)
{
    private T _value;
    private bool _isNull = true;

/**
Constructor initializing $(D this) with $(D value).
 */
    this(inout T value) inout
    {
        _value = value;
        _isNull = false;
    }

    template toString()
    {
        import std.format : FormatSpec, formatValue;
        // Needs to be a template because of DMD @@BUG@@ 13737.
        void toString()(scope void delegate(const(char)[]) sink, FormatSpec!char fmt)
        {
            if (isNull)
            {
                sink.formatValue("Nullable.null", fmt);
            }
            else
            {
                sink.formatValue(_value, fmt);
            }
        }
    }

/**
Returns $(D true) if and only if $(D this) is in the null state.
 */
    @property bool isNull() const @safe pure nothrow
    {
        return _isNull;
    }

/**
Forces $(D this) to the null state.
 */
    void nullify()()
    {
        .destroy(_value);
        _isNull = true;
    }

/**
Assigns $(D value) to the internally-held state. If the assignment
succeeds, $(D this) becomes non-null.
 */
    void opAssign()(T value)
    {
        _value = value;
        _isNull = false;
    }

/**
Gets the value. $(D this) must not be in the null state.
This function is also called for the implicit conversion to $(D T).
 */
    @property ref inout(T) get() inout @safe pure nothrow
    {
        enum message = "Called `get' on null Nullable!" ~ T.stringof ~ ".";
        assert(!isNull, message);
        return _value;
    }

/**
Implicitly converts to $(D T).
$(D this) must not be in the null state.
 */
    alias get this;
}

///
unittest
{
    Nullable!int a;
    assert(a.isNull);
    a = 5;
    assert(!a.isNull);
    assert(a == 5);
}

unittest
{
    import std.exception : assertThrown;

    Nullable!int a;
    assert(a.isNull);
    assertThrown!Throwable(a.get);
    a = 5;
    assert(!a.isNull);
    assert(a == 5);
    assert(a != 3);
    assert(a.get != 3);
    a.nullify();
    assert(a.isNull);
    a = 3;
    assert(a == 3);
    a *= 6;
    assert(a == 18);
    a = a;
    assert(a == 18);
    a.nullify();
    assertThrown!Throwable(a += 2);
}
unittest
{
    auto k = Nullable!int(74);
    assert(k == 74);
    k.nullify();
    assert(k.isNull);
}
unittest
{
    static int f(in Nullable!int x) {
        return x.isNull ? 42 : x.get;
    }
    Nullable!int a;
    assert(f(a) == 42);
    a = 8;
    assert(f(a) == 8);
    a.nullify();
    assert(f(a) == 42);
}
unittest
{
    import std.exception : assertThrown;

    static struct S { int x; }
    Nullable!S s;
    assert(s.isNull);
    s = S(6);
    assert(s == S(6));
    assert(s != S(0));
    assert(s.get != S(0));
    s.x = 9190;
    assert(s.x == 9190);
    s.nullify();
    assertThrown!Throwable(s.x = 9441);
}
unittest
{
    // Ensure Nullable can be used in pure/nothrow/@safe environment.
    function() @safe pure nothrow
    {
        Nullable!int n;
        assert(n.isNull);
        n = 4;
        assert(!n.isNull);
        assert(n == 4);
        n.nullify();
        assert(n.isNull);
    }();
}
unittest
{
    // Ensure Nullable can be used when the value is not pure/nothrow/@safe
    static struct S
    {
        int x;
        this(this) @system {}
    }

    Nullable!S s;
    assert(s.isNull);
    s = S(5);
    assert(!s.isNull);
    assert(s.x == 5);
    s.nullify();
    assert(s.isNull);
}
unittest
{
    // Bugzilla 9404
    alias N = Nullable!int;

    void foo(N a)
    {
        N b;
        b = a; // `N b = a;` works fine
    }
    N n;
    foo(n);
}
unittest
{
    //Check nullable immutable is constructable
    {
        auto a1 = Nullable!(immutable int)();
        auto a2 = Nullable!(immutable int)(1);
        auto i = a2.get;
    }
    //Check immutable nullable is constructable
    {
        auto a1 = immutable (Nullable!int)();
        auto a2 = immutable (Nullable!int)(1);
        auto i = a2.get;
    }
}
unittest
{
    alias NInt   = Nullable!int;

    //Construct tests
    {
        //from other Nullable null
        NInt a1;
        NInt b1 = a1;
        assert(b1.isNull);

        //from other Nullable non-null
        NInt a2 = NInt(1);
        NInt b2 = a2;
        assert(b2 == 1);

        //Construct from similar nullable
        auto a3 = immutable(NInt)();
        NInt b3 = a3;
        assert(b3.isNull);
    }

    //Assign tests
    {
        //from other Nullable null
        NInt a1;
        NInt b1;
        b1 = a1;
        assert(b1.isNull);

        //from other Nullable non-null
        NInt a2 = NInt(1);
        NInt b2;
        b2 = a2;
        assert(b2 == 1);

        //Construct from similar nullable
        auto a3 = immutable(NInt)();
        NInt b3 = a3;
        b3 = a3;
        assert(b3.isNull);
    }
}
unittest
{
    //Check nullable is nicelly embedable in a struct
    static struct S1
    {
        Nullable!int ni;
    }
    static struct S2 //inspired from 9404
    {
        Nullable!int ni;
        this(S2 other)
        {
            ni = other.ni;
        }
        void opAssign(S2 other)
        {
            ni = other.ni;
        }
    }
    foreach (S; TypeTuple!(S1, S2))
    {
        S a;
        S b = a;
        S c;
        c = a;
    }
}
unittest
{
    // Bugzilla 10268
    import std.json;
    JSONValue value = null;
    auto na = Nullable!JSONValue(value);

    struct S1 { int val; }
    struct S2 { int* val; }
    struct S3 { immutable int* val; }

    {
        auto sm = S1(1);
        immutable si = immutable S1(1);
        static assert( __traits(compiles, { auto x1 =           Nullable!S1(sm); }));
        static assert( __traits(compiles, { auto x2 = immutable Nullable!S1(sm); }));
        static assert( __traits(compiles, { auto x3 =           Nullable!S1(si); }));
        static assert( __traits(compiles, { auto x4 = immutable Nullable!S1(si); }));
    }

    auto nm = 10;
    immutable ni = 10;

    {
        auto sm = S2(&nm);
        immutable si = immutable S2(&ni);
        static assert( __traits(compiles, { auto x =           Nullable!S2(sm); }));
        static assert(!__traits(compiles, { auto x = immutable Nullable!S2(sm); }));
        static assert(!__traits(compiles, { auto x =           Nullable!S2(si); }));
        static assert( __traits(compiles, { auto x = immutable Nullable!S2(si); }));
    }

    {
        auto sm = S3(&ni);
        immutable si = immutable S3(&ni);
        static assert( __traits(compiles, { auto x =           Nullable!S3(sm); }));
        static assert( __traits(compiles, { auto x = immutable Nullable!S3(sm); }));
        static assert( __traits(compiles, { auto x =           Nullable!S3(si); }));
        static assert( __traits(compiles, { auto x = immutable Nullable!S3(si); }));
    }
}
unittest
{
    // Bugzila 10357
    import std.datetime;
    Nullable!SysTime time = SysTime(0);
}
unittest
{
    import std.conv: to;
    import std.array;

    // Bugzilla 10915
    Appender!string buffer;

    Nullable!int ni;
    assert(ni.to!string() == "Nullable.null");

    struct Test { string s; }
    alias NullableTest = Nullable!Test;

    NullableTest nt = Test("test");
    assert(nt.to!string() == `Test("test")`);

    NullableTest ntn = Test("null");
    assert(ntn.to!string() == `Test("null")`);

    class TestToString
    {
        double d;

        this (double d)
        {
            this.d = d;
        }

        override string toString()
        {
            return d.to!string();
        }
    }
    Nullable!TestToString ntts = new TestToString(2.5);
    assert(ntts.to!string() == "2.5");
}

/**
Just like $(D Nullable!T), except that the null state is defined as a
particular value. For example, $(D Nullable!(uint, uint.max)) is an
$(D uint) that sets aside the value $(D uint.max) to denote a null
state. $(D Nullable!(T, nullValue)) is more storage-efficient than $(D
Nullable!T) because it does not need to store an extra $(D bool).
 */
struct Nullable(T, T nullValue)
{
    private T _value = nullValue;

/**
Constructor initializing $(D this) with $(D value).
 */
    this(T value)
    {
        _value = value;
    }

    template toString()
    {
        import std.format : FormatSpec, formatValue;
        // Needs to be a template because of DMD @@BUG@@ 13737.
        void toString()(scope void delegate(const(char)[]) sink, FormatSpec!char fmt)
        {
            if (isNull)
            {
                sink.formatValue("Nullable.null", fmt);
            }
            else
            {
                sink.formatValue(_value, fmt);
            }
        }
    }

/**
Returns $(D true) if and only if $(D this) is in the null state.
 */
    @property bool isNull() const
    {
        //Need to use 'is' if T is a nullable type and
        //nullValue is null, or it's a compiler error
        static if (is(CommonType!(T, typeof(null)) == T) && nullValue is null)
        {
            return _value is nullValue;
        }
        else
        {
            return _value == nullValue;
        }
    }

/**
Forces $(D this) to the null state.
 */
    void nullify()()
    {
        _value = nullValue;
    }

/**
Assigns $(D value) to the internally-held state. No null checks are
made. Note that the assignment may leave $(D this) in the null state.
 */
    void opAssign()(T value)
    {
        _value = value;
    }

/**
Gets the value. $(D this) must not be in the null state.
This function is also called for the implicit conversion to $(D T).
 */
    @property ref inout(T) get() inout
    {
        //@@@6169@@@: We avoid any call that might evaluate nullValue's %s,
        //Because it might messup get's purity and safety inference.
        enum message = "Called `get' on null Nullable!(" ~ T.stringof ~ ",nullValue).";
        assert(!isNull, message);
        return _value;
    }

/**
Implicitly converts to $(D T).
Gets the value. $(D this) must not be in the null state.
 */
    alias get this;
}

unittest
{
    import std.exception : assertThrown;

    Nullable!(int, int.min) a;
    assert(a.isNull);
    assertThrown!Throwable(a.get);
    a = 5;
    assert(!a.isNull);
    assert(a == 5);
    static assert(a.sizeof == int.sizeof);
}
unittest
{
    auto a = Nullable!(int, int.min)(8);
    assert(a == 8);
    a.nullify();
    assert(a.isNull);
}
unittest
{
    static int f(in Nullable!(int, int.min) x) {
        return x.isNull ? 42 : x.get;
    }
    Nullable!(int, int.min) a;
    assert(f(a) == 42);
    a = 8;
    assert(f(a) == 8);
    a.nullify();
    assert(f(a) == 42);
}
unittest
{
    // Ensure Nullable can be used in pure/nothrow/@safe environment.
    function() @safe pure nothrow
    {
        Nullable!(int, int.min) n;
        assert(n.isNull);
        n = 4;
        assert(!n.isNull);
        assert(n == 4);
        n.nullify();
        assert(n.isNull);
    }();
}
unittest
{
    // Ensure Nullable can be used when the value is not pure/nothrow/@safe
    static struct S
    {
        int x;
        bool opEquals(const S s) const @system { return s.x == x; }
    }

    Nullable!(S, S(711)) s;
    assert(s.isNull);
    s = S(5);
    assert(!s.isNull);
    assert(s.x == 5);
    s.nullify();
    assert(s.isNull);
}
unittest
{
    //Check nullable is nicelly embedable in a struct
    static struct S1
    {
        Nullable!(int, 0) ni;
    }
    static struct S2 //inspired from 9404
    {
        Nullable!(int, 0) ni;
        this(S2 other)
        {
            ni = other.ni;
        }
        void opAssign(S2 other)
        {
            ni = other.ni;
        }
    }
    foreach (S; TypeTuple!(S1, S2))
    {
        S a;
        S b = a;
        S c;
        c = a;
    }
}
unittest
{
    import std.conv: to;

    // Bugzilla 10915
    Nullable!(int, 1) ni = 1;
    assert(ni.to!string() == "Nullable.null");

    struct Test { string s; }
    alias NullableTest = Nullable!(Test, Test("null"));

    NullableTest nt = Test("test");
    assert(nt.to!string() == `Test("test")`);

    NullableTest ntn = Test("null");
    assert(ntn.to!string() == "Nullable.null");

    class TestToString
    {
        double d;

        this(double d)
        {
            this.d = d;
        }

        override string toString()
        {
            return d.to!string();
        }
    }
    alias NullableTestToString = Nullable!(TestToString, null);

    NullableTestToString ntts = new TestToString(2.5);
    assert(ntts.to!string() == "2.5");
}


/**
Just like $(D Nullable!T), except that the object refers to a value
sitting elsewhere in memory. This makes assignments overwrite the
initially assigned value. Internally $(D NullableRef!T) only stores a
pointer to $(D T) (i.e., $(D Nullable!T.sizeof == (T*).sizeof)).
 */
struct NullableRef(T)
{
    private T* _value;

/**
Constructor binding $(D this) with $(D value).
 */
    this(T* value) @safe pure nothrow
    {
        _value = value;
    }

    template toString()
    {
        import std.format : FormatSpec, formatValue;
        // Needs to be a template because of DMD @@BUG@@ 13737.
        void toString()(scope void delegate(const(char)[]) sink, FormatSpec!char fmt)
        {
            if (isNull)
            {
                sink.formatValue("Nullable.null", fmt);
            }
            else
            {
                sink.formatValue(*_value, fmt);
            }
        }
    }

/**
Binds the internal state to $(D value).
 */
    void bind(T* value) @safe pure nothrow
    {
        _value = value;
    }

/**
Returns $(D true) if and only if $(D this) is in the null state.
 */
    @property bool isNull() const @safe pure nothrow
    {
        return _value is null;
    }

/**
Forces $(D this) to the null state.
 */
    void nullify() @safe pure nothrow
    {
        _value = null;
    }

/**
Assigns $(D value) to the internally-held state.
 */
    void opAssign()(T value)
        if (isAssignable!T) //@@@9416@@@
    {
        enum message = "Called `opAssign' on null NullableRef!" ~ T.stringof ~ ".";
        assert(!isNull, message);
        *_value = value;
    }

/**
Gets the value. $(D this) must not be in the null state.
This function is also called for the implicit conversion to $(D T).
 */
    @property ref inout(T) get() inout @safe pure nothrow
    {
        enum message = "Called `get' on null NullableRef!" ~ T.stringof ~ ".";
        assert(!isNull, message);
        return *_value;
    }

/**
Implicitly converts to $(D T).
$(D this) must not be in the null state.
 */
    alias get this;
}

unittest
{
    import std.exception : assertThrown;

    int x = 5, y = 7;
    auto a = NullableRef!(int)(&x);
    assert(!a.isNull);
    assert(a == 5);
    assert(x == 5);
    a = 42;
    assert(x == 42);
    assert(!a.isNull);
    assert(a == 42);
    a.nullify();
    assert(x == 42);
    assert(a.isNull);
    assertThrown!Throwable(a.get);
    assertThrown!Throwable(a = 71);
    a.bind(&y);
    assert(a == 7);
    y = 135;
    assert(a == 135);
}
unittest
{
    static int f(in NullableRef!int x) {
        return x.isNull ? 42 : x.get;
    }
    int x = 5;
    auto a = NullableRef!int(&x);
    assert(f(a) == 5);
    a.nullify();
    assert(f(a) == 42);
}
unittest
{
    // Ensure NullableRef can be used in pure/nothrow/@safe environment.
    function() @safe pure nothrow
    {
        auto storage = new int;
        *storage = 19902;
        NullableRef!int n;
        assert(n.isNull);
        n.bind(storage);
        assert(!n.isNull);
        assert(n == 19902);
        n = 2294;
        assert(n == 2294);
        assert(*storage == 2294);
        n.nullify();
        assert(n.isNull);
    }();
}
unittest
{
    // Ensure NullableRef can be used when the value is not pure/nothrow/@safe
    static struct S
    {
        int x;
        this(this) @system {}
        bool opEquals(const S s) const @system { return s.x == x; }
    }

    auto storage = S(5);

    NullableRef!S s;
    assert(s.isNull);
    s.bind(&storage);
    assert(!s.isNull);
    assert(s.x == 5);
    s.nullify();
    assert(s.isNull);
}
unittest
{
    //Check nullable is nicelly embedable in a struct
    static struct S1
    {
        NullableRef!int ni;
    }
    static struct S2 //inspired from 9404
    {
        NullableRef!int ni;
        this(S2 other)
        {
            ni = other.ni;
        }
        void opAssign(S2 other)
        {
            ni = other.ni;
        }
    }
    foreach (S; TypeTuple!(S1, S2))
    {
        S a;
        S b = a;
        S c;
        c = a;
    }
}
unittest
{
    import std.conv: to;

    // Bugzilla 10915
    NullableRef!int nri;
    assert(nri.to!string() == "Nullable.null");

    struct Test
    {
        string s;
    }
    NullableRef!Test nt = new Test("test");
    assert(nt.to!string() == `Test("test")`);

    class TestToString
    {
        double d;

        this(double d)
        {
            this.d = d;
        }

        override string toString()
        {
            return d.to!string();
        }
    }
    TestToString tts = new TestToString(2.5);
    NullableRef!TestToString ntts = &tts;
    assert(ntts.to!string() == "2.5");
}


/**
$(D BlackHole!Base) is a subclass of $(D Base) which automatically implements
all abstract member functions in $(D Base) as do-nothing functions.  Each
auto-implemented function just returns the default value of the return type
without doing anything.

The name came from
$(WEB search.cpan.org/~sburke/Class-_BlackHole-0.04/lib/Class/_BlackHole.pm, Class::_BlackHole)
Perl module by Sean M. Burke.

Example:
--------------------
abstract class C
{
    int m_value;
    this(int v) { m_value = v; }
    int value() @property { return m_value; }

    abstract real realValue() @property;
    abstract void doSomething();
}

void main()
{
    auto c = new BlackHole!C(42);
    writeln(c.value);     // prints "42"

    // Abstract functions are implemented as do-nothing:
    writeln(c.realValue); // prints "NaN"
    c.doSomething();      // does nothing
}
--------------------

See_Also:
  AutoImplement, generateEmptyFunction
 */
alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction, isAbstractFunction);

unittest
{
    import std.math : isNaN;

    // return default
    {
        interface I_1 { real test(); }
        auto o = new BlackHole!I_1;
        assert(o.test().isNaN()); // NaN
    }
    // doc example
    {
        static class C
        {
            int m_value;
            this(int v) { m_value = v; }
            int value() @property { return m_value; }

            abstract real realValue() @property;
            abstract void doSomething();
        }

        auto c = new BlackHole!C(42);
        assert(c.value == 42);

        assert(c.realValue.isNaN); // NaN
        c.doSomething();
    }

    // Bugzilla 12058
    interface Foo
    {
        inout(Object) foo() inout;
    }
    BlackHole!Foo o;

    // Bugzilla 12464
    import std.stream;
    import std.typecons;
    BlackHole!OutputStream dout;
}


/**
$(D WhiteHole!Base) is a subclass of $(D Base) which automatically implements
all abstract member functions as throw-always functions.  Each auto-implemented
function fails with throwing an $(D Error) and does never return.  Useful for
trapping use of not-yet-implemented functions.

The name came from
$(WEB search.cpan.org/~mschwern/Class-_WhiteHole-0.04/lib/Class/_WhiteHole.pm, Class::_WhiteHole)
Perl module by Michael G Schwern.

Example:
--------------------
class C
{
    abstract void notYetImplemented();
}

void main()
{
    auto c = new WhiteHole!C;
    c.notYetImplemented(); // throws an Error
}
--------------------

See_Also:
  AutoImplement, generateAssertTrap
 */
alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap, isAbstractFunction);

// / ditto
class NotImplementedError : Error
{
    this(string method)
    {
        super(method ~ " is not implemented");
    }
}

unittest
{
    import std.exception : assertThrown;
    // nothrow
    {
        interface I_1
        {
            void foo();
            void bar() nothrow;
        }
        auto o = new WhiteHole!I_1;
        assertThrown!NotImplementedError(o.foo());
        assertThrown!NotImplementedError(o.bar());
    }
    // doc example
    {
        static class C
        {
            abstract void notYetImplemented();
        }

        auto c = new WhiteHole!C;
        try
        {
            c.notYetImplemented();
            assert(0);
        }
        catch (Error e) {}
    }
}


/**
$(D AutoImplement) automatically implements (by default) all abstract member
functions in the class or interface $(D Base) in specified way.

Params:
  how  = template which specifies _how functions will be implemented/overridden.

         Two arguments are passed to $(D how): the type $(D Base) and an alias
         to an implemented function.  Then $(D how) must return an implemented
         function body as a string.

         The generated function body can use these keywords:
         $(UL
            $(LI $(D a0), $(D a1), &hellip;: arguments passed to the function;)
            $(LI $(D args): a tuple of the arguments;)
            $(LI $(D self): an alias to the function itself;)
            $(LI $(D parent): an alias to the overridden function (if any).)
         )

        You may want to use templated property functions (instead of Implicit
        Template Properties) to generate complex functions:
--------------------
// Prints log messages for each call to overridden functions.
string generateLogger(C, alias fun)() @property
{
    import std.traits;
    enum qname = C.stringof ~ "." ~ __traits(identifier, fun);
    string stmt;

    stmt ~= q{ struct Importer { import std.stdio; } };
    stmt ~= `Importer.writeln("Log: ` ~ qname ~ `(", args, ")");`;
    static if (!__traits(isAbstractFunction, fun))
    {
        static if (is(ReturnType!fun == void))
            stmt ~= q{ parent(args); };
        else
            stmt ~= q{
                auto r = parent(args);
                Importer.writeln("--> ", r);
                return r;
            };
    }
    return stmt;
}
--------------------

  what = template which determines _what functions should be
         implemented/overridden.

         An argument is passed to $(D what): an alias to a non-final member
         function in $(D Base).  Then $(D what) must return a boolean value.
         Return $(D true) to indicate that the passed function should be
         implemented/overridden.

--------------------
// Sees if fun returns something.
enum bool hasValue(alias fun) = !is(ReturnType!(fun) == void);
--------------------


Note:

Generated code is inserted in the scope of $(D std.typecons) module.  Thus,
any useful functions outside $(D std.typecons) cannot be used in the generated
code.  To workaround this problem, you may $(D import) necessary things in a
local struct, as done in the $(D generateLogger()) template in the above
example.


BUGS:

$(UL
 $(LI Variadic arguments to constructors are not forwarded to super.)
 $(LI Deep interface inheritance causes compile error with messages like
      "Error: function std.typecons._AutoImplement!(Foo)._AutoImplement.bar
      does not override any function".  [$(BUGZILLA 2525), $(BUGZILLA 3525)] )
 $(LI The $(D parent) keyword is actually a delegate to the super class'
      corresponding member function.  [$(BUGZILLA 2540)] )
 $(LI Using alias template parameter in $(D how) and/or $(D what) may cause
     strange compile error.  Use template tuple parameter instead to workaround
     this problem.  [$(BUGZILLA 4217)] )
)
 */
class AutoImplement(Base, alias how, alias what = isAbstractFunction) : Base
{
    private alias autoImplement_helper_ =
        AutoImplement_Helper!("autoImplement_helper_", "Base", Base, how, what);
    mixin(autoImplement_helper_.code);
}

/*
 * Code-generating stuffs are encupsulated in this helper template so that
 * namespace pollution, which can cause name confliction with Base's public
 * members, should be minimized.
 */
private template AutoImplement_Helper(string myName, string baseName,
        Base, alias generateMethodBody, alias cherrypickMethod)
{
private static:
    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
    // Internal stuffs
    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://

    // Returns function overload sets in the class C, filtered with pred.
    template enumerateOverloads(C, alias pred)
    {
        template Impl(names...)
        {
            import std.typetuple : Filter;
            static if (names.length > 0)
            {
                alias methods = Filter!(pred, MemberFunctionsTuple!(C, names[0]));
                alias next = Impl!(names[1 .. $]);

                static if (methods.length > 0)
                    alias Impl = TypeTuple!(OverloadSet!(names[0], methods), next);
                else
                    alias Impl = next;
            }
            else
                alias Impl = TypeTuple!();
        }

        alias enumerateOverloads = Impl!(__traits(allMembers, C));
    }

    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
    // Target functions
    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://

    // Add a non-final check to the cherrypickMethod.
    enum bool canonicalPicker(fun.../+[BUG 4217]+/) =
        !__traits(isFinalFunction, fun[0]) && cherrypickMethod!(fun);

    /*
     * A tuple of overload sets, each item of which consists of functions to be
     * implemented by the generated code.
     */
    alias targetOverloadSets = enumerateOverloads!(Base, canonicalPicker);

    /*
     * A tuple of the super class' constructors.  Used for forwarding
     * constructor calls.
     */
    static if (__traits(hasMember, Base, "__ctor"))
        alias ctorOverloadSet = OverloadSet!("__ctor", __traits(getOverloads, Base, "__ctor"));
    else
        alias ctorOverloadSet = OverloadSet!("__ctor"); // empty


    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
    // Type information
    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://

    /*
     * The generated code will be mixed into AutoImplement, which will be
     * instantiated in this module's scope.  Thus, any user-defined types are
     * out of scope and cannot be used directly (i.e. by their names).
     *
     * We will use FuncInfo instances for accessing return types and parameter
     * types of the implemented functions.  The instances will be populated to
     * the AutoImplement's scope in a certain way; see the populate() below.
     */

    // Returns the preferred identifier for the FuncInfo instance for the i-th
    // overloaded function with the name.
    template INTERNAL_FUNCINFO_ID(string name, size_t i)
    {
        import std.format : format;

        enum string INTERNAL_FUNCINFO_ID = format("F_%s_%s", name, i);
    }

    /*
     * Insert FuncInfo instances about all the target functions here.  This
     * enables the generated code to access type information via, for example,
     * "autoImplement_helper_.F_foo_1".
     */
    template populate(overloads...)
    {
        static if (overloads.length > 0)
        {
            mixin populate!(overloads[0].name, overloads[0].contents);
            mixin populate!(overloads[1 .. $]);
        }
    }
    template populate(string name, methods...)
    {
        static if (methods.length > 0)
        {
            mixin populate!(name, methods[0 .. $ - 1]);
            //
            alias target = methods[$ - 1];
            enum ith = methods.length - 1;
            mixin("alias " ~ INTERNAL_FUNCINFO_ID!(name, ith) ~ " = FuncInfo!target;");
        }
    }

    public mixin populate!(targetOverloadSets);
    public mixin populate!(  ctorOverloadSet );


    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
    // Code-generating policies
    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://

    /* Common policy configurations for generating constructors and methods. */
    template CommonGeneratingPolicy()
    {
        // base class identifier which generated code should use
        enum string BASE_CLASS_ID = baseName;

        // FuncInfo instance identifier which generated code should use
        template FUNCINFO_ID(string name, size_t i)
        {
            enum string FUNCINFO_ID =
                myName ~ "." ~ INTERNAL_FUNCINFO_ID!(name, i);
        }
    }

    /* Policy configurations for generating constructors. */
    template ConstructorGeneratingPolicy()
    {
        mixin CommonGeneratingPolicy;

        /* Generates constructor body.  Just forward to the base class' one. */
        string generateFunctionBody(ctor.../+[BUG 4217]+/)() @property
        {
            enum varstyle = variadicFunctionStyle!(typeof(&ctor[0]));

            static if (varstyle & (Variadic.c | Variadic.d))
            {
                // the argptr-forwarding problem
                //pragma(msg, "Warning: AutoImplement!(", Base, ") ",
                //        "ignored variadic arguments to the constructor ",
                //        FunctionTypeOf!(typeof(&ctor[0])) );
            }
            return "super(args);";
        }
    }

    /* Policy configurations for genearting target methods. */
    template MethodGeneratingPolicy()
    {
        mixin CommonGeneratingPolicy;

        /* Geneartes method body. */
        string generateFunctionBody(func.../+[BUG 4217]+/)() @property
        {
            return generateMethodBody!(Base, func); // given
        }
    }


    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
    // Generated code
    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://

    alias ConstructorGenerator = MemberFunctionGenerator!(ConstructorGeneratingPolicy!());
    alias MethodGenerator      = MemberFunctionGenerator!(MethodGeneratingPolicy!());

    public enum string code =
        ConstructorGenerator.generateCode!(  ctorOverloadSet ) ~ "\n" ~
             MethodGenerator.generateCode!(targetOverloadSets);

    debug (SHOW_GENERATED_CODE)
    {
        pragma(msg, "-------------------- < ", Base, " >");
        pragma(msg, code);
        pragma(msg, "--------------------");
    }
}

//debug = SHOW_GENERATED_CODE;
unittest
{
    import core.vararg;
    // no function to implement
    {
        interface I_1 {}
        auto o = new BlackHole!I_1;
    }
    // parameters
    {
        interface I_3 { void test(int, in int, out int, ref int, lazy int); }
        auto o = new BlackHole!I_3;
    }
    // use of user-defined type
    {
        struct S {}
        interface I_4 { S test(); }
        auto o = new BlackHole!I_4;
    }
    // overloads
    {
        interface I_5
        {
            void test(string);
            real test(real);
            int  test();
        }
        auto o = new BlackHole!I_5;
    }
    // constructor forwarding
    {
        static class C_6
        {
            this(int n) { assert(n == 42); }
            this(string s) { assert(s == "Deeee"); }
            this(...) {}
        }
        auto o1 = new BlackHole!C_6(42);
        auto o2 = new BlackHole!C_6("Deeee");
        auto o3 = new BlackHole!C_6(1, 2, 3, 4);
    }
    // attributes
    {
        interface I_7
        {
            ref int test_ref();
            int test_pure() pure;
            int test_nothrow() nothrow;
            int test_property() @property;
            int test_safe() @safe;
            int test_trusted() @trusted;
            int test_system() @system;
            int test_pure_nothrow() pure nothrow;
        }
        auto o = new BlackHole!I_7;
    }
    // storage classes
    {
        interface I_8
        {
            void test_const() const;
            void test_immutable() immutable;
            void test_shared() shared;
            void test_shared_const() shared const;
        }
        auto o = new BlackHole!I_8;
    }
    /+ // deep inheritance
    {
    // XXX [BUG 2525,3525]
    // NOTE: [r494] func.c(504-571) FuncDeclaration::semantic()
        interface I { void foo(); }
        interface J : I {}
        interface K : J {}
        static abstract class C_9 : K {}
        auto o = new BlackHole!C_9;
    }+/
}

version(unittest)
{
    // Issue 10647
    private string generateDoNothing(C, alias fun)() @property
    {
        string stmt;

        static if (is(ReturnType!fun == void))
            stmt ~= "";
        else
        {
            string returnType = ReturnType!fun.stringof;
            stmt ~= "return "~returnType~".init;";
        }
        return stmt;
    }

    private template isAlwaysTrue(alias fun)
    {
        enum isAlwaysTrue = true;
    }

    // Do nothing template
    private template DoNothing(Base)
    {
        alias DoNothing = AutoImplement!(Base, generateDoNothing, isAlwaysTrue);
    }

    // A class to be overridden
    private class Foo{
        void bar(int a) { }
    }
}
unittest
{
    auto foo = new DoNothing!Foo();
    foo.bar(13);
}

/*
Used by MemberFunctionGenerator.
 */
package template OverloadSet(string nam, T...)
{
    enum string name = nam;
    alias contents = T;
}

/*
Used by MemberFunctionGenerator.
 */
package template FuncInfo(alias func, /+[BUG 4217 ?]+/ T = typeof(&func))
{
    alias RT =         ReturnType!T;
    alias PT = ParameterTypeTuple!T;
}
package template FuncInfo(Func)
{
    alias RT =         ReturnType!Func;
    alias PT = ParameterTypeTuple!Func;
}

/*
General-purpose member function generator.
--------------------
template GeneratingPolicy()
{
    // [optional] the name of the class where functions are derived
    enum string BASE_CLASS_ID;

    // [optional] define this if you have only function types
    enum bool WITHOUT_SYMBOL;

    // [optional] Returns preferred identifier for i-th parameter.
    template PARAMETER_VARIABLE_ID(size_t i);

    // Returns the identifier of the FuncInfo instance for the i-th overload
    // of the specified name.  The identifier must be accessible in the scope
    // where generated code is mixed.
    template FUNCINFO_ID(string name, size_t i);

    // Returns implemented function body as a string.  When WITHOUT_SYMBOL is
    // defined, the latter is used.
    template generateFunctionBody(alias func);
    template generateFunctionBody(string name, FuncType);
}
--------------------
 */
package template MemberFunctionGenerator(alias Policy)
{
private static:
    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
    // Internal stuffs
    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
    import std.format;

    enum CONSTRUCTOR_NAME = "__ctor";

    // true if functions are derived from a base class
    enum WITH_BASE_CLASS = __traits(hasMember, Policy, "BASE_CLASS_ID");

    // true if functions are specified as types, not symbols
    enum WITHOUT_SYMBOL = __traits(hasMember, Policy, "WITHOUT_SYMBOL");

    // preferred identifier for i-th parameter variable
    static if (__traits(hasMember, Policy, "PARAMETER_VARIABLE_ID"))
    {
        alias PARAMETER_VARIABLE_ID = Policy.PARAMETER_VARIABLE_ID;
    }
    else
    {
        enum string PARAMETER_VARIABLE_ID(size_t i) = format("a%s", i);
            // default: a0, a1, ...
    }

    // Returns a tuple consisting of 0,1,2,...,n-1.  For static foreach.
    template CountUp(size_t n)
    {
        static if (n > 0)
            alias CountUp = TypeTuple!(CountUp!(n - 1), n - 1);
        else
            alias CountUp = TypeTuple!();
    }


    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
    // Code generator
    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://

    /*
     * Runs through all the target overload sets and generates D code which
     * implements all the functions in the overload sets.
     */
    public string generateCode(overloads...)() @property
    {
        string code = "";

        // run through all the overload sets
        foreach (i_; CountUp!(0 + overloads.length)) // workaround
        {
            enum i = 0 + i_; // workaround
            alias oset = overloads[i];

            code ~= generateCodeForOverloadSet!(oset);

            static if (WITH_BASE_CLASS && oset.name != CONSTRUCTOR_NAME)
            {
                // The generated function declarations may hide existing ones
                // in the base class (cf. HiddenFuncError), so we put an alias
                // declaration here to reveal possible hidden functions.
                code ~= format("alias %s = %s.%s;\n",
                            oset.name,
                            Policy.BASE_CLASS_ID, // [BUG 2540] super.
                            oset.name);
            }
        }
        return code;
    }

    // handle each overload set
    private string generateCodeForOverloadSet(alias oset)() @property
    {
        string code = "";

        foreach (i_; CountUp!(0 + oset.contents.length)) // workaround
        {
            enum i = 0 + i_; // workaround
            code ~= generateFunction!(
                    Policy.FUNCINFO_ID!(oset.name, i), oset.name,
                    oset.contents[i]) ~ "\n";
        }
        return code;
    }

    /*
     * Returns D code which implements the function func.  This function
     * actually generates only the declarator part; the function body part is
     * generated by the functionGenerator() policy.
     */
    public string generateFunction(
            string myFuncInfo, string name, func... )() @property
    {
        import std.format : format;

        enum isCtor = (name == CONSTRUCTOR_NAME);

        string code; // the result

        auto paramsRes = generateParameters!(myFuncInfo, func)();
        code ~= paramsRes.imports;

        /*** Function Declarator ***/
        {
            alias Func = FunctionTypeOf!(func);
            alias FA = FunctionAttribute;
            enum atts     = functionAttributes!(func);
            enum realName = isCtor ? "this" : name;

            // FIXME?? Make it so that these aren't CTFE funcs any more, since
            // Format is deprecated, and format works at compile time?
            /* Made them CTFE funcs just for the sake of Format!(...) */

            // return type with optional "ref"
            static string make_returnType()
            {
                string rtype = "";

                if (!isCtor)
                {
                    if (atts & FA.ref_) rtype ~= "ref ";
                    rtype ~= myFuncInfo ~ ".RT";
                }
                return rtype;
            }
            enum returnType = make_returnType();

            // function attributes attached after declaration
            static string make_postAtts()
            {
                string poatts = "";
                if (atts & FA.pure_   ) poatts ~= " pure";
                if (atts & FA.nothrow_) poatts ~= " nothrow";
                if (atts & FA.property) poatts ~= " @property";
                if (atts & FA.safe    ) poatts ~= " @safe";
                if (atts & FA.trusted ) poatts ~= " @trusted";
                return poatts;
            }
            enum postAtts = make_postAtts();

            // function storage class
            static string make_storageClass()
            {
                string postc = "";
                if (is(Func ==    shared)) postc ~= " shared";
                if (is(Func ==     const)) postc ~= " const";
                if (is(Func ==     inout)) postc ~= " inout";
                if (is(Func == immutable)) postc ~= " immutable";
                return postc;
            }
            enum storageClass = make_storageClass();

            //
            if (__traits(isVirtualMethod, func))
                code ~= "override ";
            code ~= format("extern(%s) %s %s(%s) %s %s\n",
                    functionLinkage!(func),
                    returnType,
                    realName,
                    paramsRes.params,
                    postAtts, storageClass );
        }

        /*** Function Body ***/
        code ~= "{\n";
        {
            enum nparams = ParameterTypeTuple!(func).length;

            /* Declare keywords: args, self and parent. */
            string preamble;

            preamble ~= "alias args = TypeTuple!(" ~ enumerateParameters!(nparams) ~ ");\n";
            if (!isCtor)
            {
                preamble ~= "alias self = " ~ name ~ ";\n";
                if (WITH_BASE_CLASS && !__traits(isAbstractFunction, func))
                    //preamble ~= "alias super." ~ name ~ " parent;\n"; // [BUG 2540]
                    preamble ~= "auto parent = &super." ~ name ~ ";\n";
            }

            // Function body
            static if (WITHOUT_SYMBOL)
                enum fbody = Policy.generateFunctionBody!(name, func);
            else
                enum fbody = Policy.generateFunctionBody!(func);

            code ~= preamble;
            code ~= fbody;
        }
        code ~= "}";

        return code;
    }

    /*
     * Returns D code which declares function parameters,
     * and optionally any imports (e.g. core.vararg)
     * "ref int a0, real a1, ..."
     */
    static struct GenParams { string imports, params; }
    private GenParams generateParameters(string myFuncInfo, func...)()
    {
        alias STC = ParameterStorageClass;
        alias stcs = ParameterStorageClassTuple!(func);
        enum nparams = stcs.length;

        string imports = ""; // any imports required
        string params = ""; // parameters

        foreach (i, stc; stcs)
        {
            if (i > 0) params ~= ", ";

            // Parameter storage classes.
            if (stc & STC.scope_) params ~= "scope ";
            if (stc & STC.out_  ) params ~= "out ";
            if (stc & STC.ref_  ) params ~= "ref ";
            if (stc & STC.lazy_ ) params ~= "lazy ";

            // Take parameter type from the FuncInfo.
            params ~= format("%s.PT[%s]", myFuncInfo, i);

            // Declare a parameter variable.
            params ~= " " ~ PARAMETER_VARIABLE_ID!(i);
        }

        // Add some ellipsis part if needed.
        auto style = variadicFunctionStyle!(func);
        final switch (style)
        {
            case Variadic.no:
                break;

            case Variadic.c, Variadic.d:
                imports ~= "import core.vararg;\n";
                // (...) or (a, b, ...)
                params ~= (nparams == 0) ? "..." : ", ...";
                break;

            case Variadic.typesafe:
                params ~= " ...";
                break;
        }

        return typeof(return)(imports, params);
    }

    // Returns D code which enumerates n parameter variables using comma as the
    // separator.  "a0, a1, a2, a3"
    private string enumerateParameters(size_t n)() @property
    {
        string params = "";

        foreach (i_; CountUp!(n))
        {
            enum i = 0 + i_; // workaround
            if (i > 0) params ~= ", ";
            params ~= PARAMETER_VARIABLE_ID!(i);
        }
        return params;
    }
}


/**
Predefined how-policies for $(D AutoImplement).  These templates are used by
$(D BlackHole) and $(D WhiteHole), respectively.
 */
template generateEmptyFunction(C, func.../+[BUG 4217]+/)
{
    static if (is(ReturnType!(func) == void))
        enum string generateEmptyFunction = q{
        };
    else static if (functionAttributes!(func) & FunctionAttribute.ref_)
        enum string generateEmptyFunction = q{
            static typeof(return) dummy;
            return dummy;
        };
    else
        enum string generateEmptyFunction = q{
            return typeof(return).init;
        };
}

/// ditto
template generateAssertTrap(C, func...)
{
    enum string generateAssertTrap =
        `throw new NotImplementedError("` ~ C.stringof ~ "."
                ~ __traits(identifier, func) ~ `");`;
}

private
{
    pragma(mangle, "_d_toObject")
    extern(C) pure nothrow Object typecons_d_toObject(void* p);
}

/*
 * Avoids opCast operator overloading.
 */
private template dynamicCast(T)
if (is(T == class) || is(T == interface))
{
    @trusted
    T dynamicCast(S)(inout S source)
    if (is(S == class) || is(S == interface))
    {
        static if (is(Unqual!S : Unqual!T))
        {
            import std.traits : QualifierOf;
            alias Qual = QualifierOf!S; // SharedOf or MutableOf
            alias TmpT = Qual!(Unqual!T);
            inout(TmpT) tmp = source;   // bypass opCast by implicit conversion
            return *cast(T*)(&tmp);     // + variable pointer cast + dereference
        }
        else
        {
            return cast(T)typecons_d_toObject(*cast(void**)(&source));
        }
    }
}

unittest
{
    class C { @disable opCast(T)() {} }
    auto c = new C;
    static assert(!__traits(compiles, cast(Object)c));
    auto o = dynamicCast!Object(c);
    assert(c is o);

    interface I { @disable opCast(T)() {} Object instance(); }
    interface J { @disable opCast(T)() {} Object instance(); }
    class D : I, J { Object instance() { return this; } }
    I i = new D();
    static assert(!__traits(compiles, cast(J)i));
    J j = dynamicCast!J(i);
    assert(i.instance() is j.instance());
}

/**
 * Supports structural based typesafe conversion.
 *
 * If $(D Source) has structural conformance with the $(D interface) $(D Targets),
 * wrap creates internal wrapper class which inherits $(D Targets) and
 * wrap $(D src) object, then return it.
 */
template wrap(Targets...)
if (Targets.length >= 1 && allSatisfy!(isMutable, Targets))
{
    import std.typetuple : staticMap;

    // strict upcast
    auto wrap(Source)(inout Source src) @trusted pure nothrow
    if (Targets.length == 1 && is(Source : Targets[0]))
    {
        alias T = Select!(is(Source == shared), shared Targets[0], Targets[0]);
        return dynamicCast!(inout T)(src);
    }
    // structural upcast
    template wrap(Source)
    if (!allSatisfy!(Bind!(isImplicitlyConvertible, Source), Targets))
    {
        auto wrap(inout Source src)
        {
            static assert(hasRequireMethods!(),
                          "Source "~Source.stringof~
                          " does not have structural conformance to "~
                          Targets.stringof);

            alias T = Select!(is(Source == shared), shared Impl, Impl);
            return new inout T(src);
        }

        template FuncInfo(string s, F)
        {
            enum name = s;
            alias type = F;
        }

        // Concat all Targets function members into one tuple
        template Concat(size_t i = 0)
        {
            static if (i >= Targets.length)
                alias Concat = TypeTuple!();
            else
            {
                alias Concat = TypeTuple!(GetOverloadedMethods!(Targets[i]), Concat!(i + 1));
            }
        }
        // Remove duplicated functions based on the identifier name and function type covariance
        template Uniq(members...)
        {
            static if (members.length == 0)
                alias Uniq = TypeTuple!();
            else
            {
                alias func = members[0];
                enum  name = __traits(identifier, func);
                alias type = FunctionTypeOf!func;
                template check(size_t i, mem...)
                {
                    static if (i >= mem.length)
                        enum ptrdiff_t check = -1;
                    else
                    {
                        enum ptrdiff_t check =
                            __traits(identifier, func) == __traits(identifier, mem[i]) &&
                            !is(DerivedFunctionType!(type, FunctionTypeOf!(mem[i])) == void)
                          ? i : check!(i + 1, mem);
                    }
                }
                enum ptrdiff_t x = 1 + check!(0, members[1 .. $]);
                static if (x >= 1)
                {
                    alias typex = DerivedFunctionType!(type, FunctionTypeOf!(members[x]));
                    alias remain = Uniq!(members[1 .. x], members[x + 1 .. $]);

                    static if (remain.length >= 1 && remain[0].name == name &&
                               !is(DerivedFunctionType!(typex, remain[0].type) == void))
                    {
                        alias F = DerivedFunctionType!(typex, remain[0].type);
                        alias Uniq = TypeTuple!(FuncInfo!(name, F), remain[1 .. $]);
                    }
                    else
                        alias Uniq = TypeTuple!(FuncInfo!(name, typex), remain);
                }
                else
                {
                    alias Uniq = TypeTuple!(FuncInfo!(name, type), Uniq!(members[1 .. $]));
                }
            }
        }
        alias TargetMembers = Uniq!(Concat!());             // list of FuncInfo
        alias SourceMembers = GetOverloadedMethods!Source;  // list of function symbols

        // Check whether all of SourceMembers satisfy covariance target in TargetMembers
        template hasRequireMethods(size_t i = 0)
        {
            static if (i >= TargetMembers.length)
                enum hasRequireMethods = true;
            else
            {
                enum hasRequireMethods =
                    findCovariantFunction!(TargetMembers[i], Source, SourceMembers) != -1 &&
                    hasRequireMethods!(i + 1);
            }
        }

        // Internal wrapper class
        final class Impl : Structural, Targets
        {
        private:
            Source _wrap_source;

            this(       inout Source s)        inout @safe pure nothrow { _wrap_source = s; }
            this(shared inout Source s) shared inout @safe pure nothrow { _wrap_source = s; }

            // BUG: making private should work with NVI.
            protected final inout(Object) _wrap_getSource() inout @trusted
            {
                return dynamicCast!(inout Object)(_wrap_source);
            }

            import std.conv : to;
            import std.functional : forward;
            template generateFun(size_t i)
            {
                enum name = TargetMembers[i].name;
                enum fa = functionAttributes!(TargetMembers[i].type);
                static @property stc()
                {
                    string r;
                    if (fa & FunctionAttribute.property)    r ~= "@property ";
                    if (fa & FunctionAttribute.ref_)        r ~= "ref ";
                    if (fa & FunctionAttribute.pure_)       r ~= "pure ";
                    if (fa & FunctionAttribute.nothrow_)    r ~= "nothrow ";
                    if (fa & FunctionAttribute.trusted)     r ~= "@trusted ";
                    if (fa & FunctionAttribute.safe)        r ~= "@safe ";
                    return r;
                }
                static @property mod()
                {
                    alias type = TypeTuple!(TargetMembers[i].type)[0];
                    string r;
                    static if (is(type == immutable))       r ~= " immutable";
                    else
                    {
                        static if (is(type == shared))      r ~= " shared";
                        static if (is(type == const))       r ~= " const";
                        else static if (is(type == inout))  r ~= " inout";
                        //else  --> mutable
                    }
                    return r;
                }
                enum n = to!string(i);
                static if (fa & FunctionAttribute.property)
                {
                    static if (ParameterTypeTuple!(TargetMembers[i].type).length == 0)
                        enum fbody = "_wrap_source."~name;
                    else
                        enum fbody = "_wrap_source."~name~" = forward!args";
                }
                else
                {
                        enum fbody = "_wrap_source."~name~"(forward!args)";
                }
                enum generateFun =
                    "override "~stc~"ReturnType!(TargetMembers["~n~"].type) "
                    ~ name~"(ParameterTypeTuple!(TargetMembers["~n~"].type) args) "~mod~
                    "{ return "~fbody~"; }";
            }

        public:
            mixin mixinAll!(
                staticMap!(generateFun, staticIota!(0, TargetMembers.length)));
        }
    }
}
/// ditto
template wrap(Targets...)
if (Targets.length >= 1 && !allSatisfy!(isMutable, Targets))
{
    import std.typetuple : staticMap;

    alias wrap = .wrap!(staticMap!(Unqual, Targets));
}

// Internal class to support dynamic cross-casting
private interface Structural
{
    inout(Object) _wrap_getSource() inout @safe pure nothrow;
}

/**
 * Extract object which wrapped by $(D wrap).
 */
template unwrap(Target)
if (isMutable!Target)
{
    // strict downcast
    auto unwrap(Source)(inout Source src) @trusted pure nothrow
    if (is(Target : Source))
    {
        alias T = Select!(is(Source == shared), shared Target, Target);
        return dynamicCast!(inout T)(src);
    }
    // structural downcast
    auto unwrap(Source)(inout Source src) @trusted pure nothrow
    if (!is(Target : Source))
    {
        alias T = Select!(is(Source == shared), shared Target, Target);
        Object o = dynamicCast!(Object)(src);   // remove qualifier
        do
        {
            if (auto a = dynamicCast!(Structural)(o))
            {
                if (auto d = dynamicCast!(inout T)(o = a._wrap_getSource()))
                    return d;
            }
            else if (auto d = dynamicCast!(inout T)(o))
                return d;
            else
                break;
        } while (o);
        return null;
    }
}
/// ditto
template unwrap(Target)
if (!isMutable!Target)
{
    alias unwrap = .unwrap!(Unqual!Target);
}

///
unittest
{
    interface Quack
    {
        int quack();
        @property int height();
    }
    interface Flyer
    {
        @property int height();
    }
    class Duck : Quack
    {
        int quack() { return 1; }
        @property int height() { return 10; }
    }
    class Human
    {
        int quack() { return 2; }
        @property int height() { return 20; }
    }

    Duck d1 = new Duck();
    Human h1 = new Human();

    interface Refleshable
    {
        int reflesh();
    }
    // does not have structural conformance
    static assert(!__traits(compiles, d1.wrap!Refleshable));
    static assert(!__traits(compiles, h1.wrap!Refleshable));

    // strict upcast
    Quack qd = d1.wrap!Quack;
    assert(qd is d1);
    assert(qd.quack() == 1);    // calls Duck.quack
    // strict downcast
    Duck d2 = qd.unwrap!Duck;
    assert(d2 is d1);

    // structural upcast
    Quack qh = h1.wrap!Quack;
    assert(qh.quack() == 2);    // calls Human.quack
    // structural downcast
    Human h2 = qh.unwrap!Human;
    assert(h2 is h1);

    // structural upcast (two steps)
    Quack qx = h1.wrap!Quack;   // Human -> Quack
    Flyer fx = qx.wrap!Flyer;   // Quack -> Flyer
    assert(fx.height == 20);    // calls Human.height
    // strucural downcast (two steps)
    Quack qy = fx.unwrap!Quack; // Flyer -> Quack
    Human hy = qy.unwrap!Human; // Quack -> Human
    assert(hy is h1);
    // strucural downcast (one step)
    Human hz = fx.unwrap!Human; // Flyer -> Human
    assert(hz is h1);
}
///
unittest
{
    interface A { int run(); }
    interface B { int stop(); @property int status(); }
    class X
    {
        int run() { return 1; }
        int stop() { return 2; }
        @property int status() { return 3; }
    }

    auto x = new X();
    auto ab = x.wrap!(A, B);
    A a = ab;
    B b = ab;
    assert(a.run() == 1);
    assert(b.stop() == 2);
    assert(b.status == 3);
    static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property);
}
unittest
{
    class A
    {
        int draw()              { return 1; }
        int draw(int v)         { return v; }

        int draw() const        { return 2; }
        int draw() shared       { return 3; }
        int draw() shared const { return 4; }
        int draw() immutable    { return 5; }
    }
    interface Drawable
    {
        int draw();
        int draw() const;
        int draw() shared;
        int draw() shared const;
        int draw() immutable;
    }
    interface Drawable2
    {
        int draw(int v);
    }

    auto ma = new A();
    auto sa = new shared A();
    auto ia = new immutable A();
    {
                     Drawable  md = ma.wrap!Drawable;
               const Drawable  cd = ma.wrap!Drawable;
              shared Drawable  sd = sa.wrap!Drawable;
        shared const Drawable scd = sa.wrap!Drawable;
           immutable Drawable  id = ia.wrap!Drawable;
        assert( md.draw() == 1);
        assert( cd.draw() == 2);
        assert( sd.draw() == 3);
        assert(scd.draw() == 4);
        assert( id.draw() == 5);
    }
    {
        Drawable2 d = ma.wrap!Drawable2;
        static assert(!__traits(compiles, d.draw()));
        assert(d.draw(10) == 10);
    }
}
unittest
{
    // Bugzilla 10377
    import std.range, std.algorithm;

    interface MyInputRange(T)
    {
        @property T front();
        void popFront();
        @property bool empty();
    }

    //auto o = iota(0,10,1).inputRangeObject();
    //pragma(msg, __traits(allMembers, typeof(o)));
    auto r = iota(0,10,1).inputRangeObject().wrap!(MyInputRange!int)();
    assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
}
unittest
{
    // Bugzilla 10536
    interface Interface
    {
        int foo();
    }
    class Pluggable
    {
        int foo() { return 1; }
        @disable void opCast(T, this X)();  // !
    }

    Interface i = new Pluggable().wrap!Interface;
    assert(i.foo() == 1);
}
unittest
{
    // Enhancement 10538
    interface Interface
    {
        int foo();
        int bar(int);
    }
    class Pluggable
    {
        int opDispatch(string name, A...)(A args) { return 100; }
    }

    Interface i = wrap!Interface(new Pluggable());
    assert(i.foo() == 100);
    assert(i.bar(10) == 100);
}

// Make a tuple of non-static function symbols
private template GetOverloadedMethods(T)
{
    import std.typetuple : Filter;

    alias allMembers = TypeTuple!(__traits(allMembers, T));
    template follows(size_t i = 0)
    {
        static if (i >= allMembers.length)
        {
            alias follows = TypeTuple!();
        }
        else static if (!__traits(compiles, mixin("T."~allMembers[i])))
        {
            alias follows = follows!(i + 1);
        }
        else
        {
            enum name = allMembers[i];

            template isMethod(alias f)
            {
                static if (is(typeof(&f) F == F*) && is(F == function))
                    enum isMethod = !__traits(isStaticFunction, f);
                else
                    enum isMethod = false;
            }
            alias follows = TypeTuple!(
                std.typetuple.Filter!(isMethod, __traits(getOverloads, T, name)),
                follows!(i + 1));
        }
    }
    alias GetOverloadedMethods = follows!();
}
// find a function from Fs that has same identifier and covariant type with f
private template findCovariantFunction(alias finfo, Source, Fs...)
{
    template check(size_t i = 0)
    {
        static if (i >= Fs.length)
            enum ptrdiff_t check = -1;
        else
        {
            enum ptrdiff_t check =
                (finfo.name == __traits(identifier, Fs[i])) &&
                isCovariantWith!(FunctionTypeOf!(Fs[i]), finfo.type)
              ? i : check!(i + 1);
        }
    }
    enum x = check!();
    static if (x == -1 && is(typeof(Source.opDispatch)))
    {
        alias Params = ParameterTypeTuple!(finfo.type);
        enum ptrdiff_t findCovariantFunction =
            is(typeof((             Source).init.opDispatch!(finfo.name)(Params.init))) ||
            is(typeof((       const Source).init.opDispatch!(finfo.name)(Params.init))) ||
            is(typeof((   immutable Source).init.opDispatch!(finfo.name)(Params.init))) ||
            is(typeof((      shared Source).init.opDispatch!(finfo.name)(Params.init))) ||
            is(typeof((shared const Source).init.opDispatch!(finfo.name)(Params.init)))
          ? ptrdiff_t.max : -1;
    }
    else
        enum ptrdiff_t findCovariantFunction = x;
}

private enum TypeModifier
{
    mutable     = 0,    // type is mutable
    const_      = 1,    // type is const
    immutable_  = 2,    // type is immutable
    shared_     = 4,    // type is shared
    inout_      = 8,    // type is wild
}
private template TypeMod(T)
{
    static if (is(T == immutable))
    {
        enum mod1 = TypeModifier.immutable_;
        enum mod2 = 0;
    }
    else
    {
        enum mod1 = is(T == shared) ? TypeModifier.shared_ : 0;
        static if (is(T == const))
            enum mod2 = TypeModifier.const_;
        else static if (is(T == inout))
            enum mod2 = TypeModifier.inout_;
        else
            enum mod2 = TypeModifier.mutable;
    }
    enum TypeMod = cast(TypeModifier)(mod1 | mod2);
}

version(unittest)
{
    private template UnittestFuncInfo(alias f)
    {
        enum name = __traits(identifier, f);
        alias type = FunctionTypeOf!f;
    }
}
unittest
{
    class A
    {
        int draw() { return 1; }
        @property int value() { return 2; }
        final int run() { return 3; }
    }
    alias methods = GetOverloadedMethods!A;

    alias int F1();
    alias @property int F2();
    alias string F3();
    alias nothrow @trusted uint F4();
    alias int F5(Object);
    alias bool F6(Object);
    static assert(methods.length == 3 + 4);
    static assert(__traits(identifier, methods[0]) == "draw"     && is(typeof(&methods[0]) == F1*));
    static assert(__traits(identifier, methods[1]) == "value"    && is(typeof(&methods[1]) == F2*));
    static assert(__traits(identifier, methods[2]) == "run"      && is(typeof(&methods[2]) == F1*));

    int draw() { return 0; }
    @property int value() { return 0; }
    void opEquals() {}
    int nomatch() { return 0; }
    static assert(findCovariantFunction!(UnittestFuncInfo!draw,     A, methods) == 0);
    static assert(findCovariantFunction!(UnittestFuncInfo!value,    A, methods) == 1);
    static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, A, methods) == -1);
    static assert(findCovariantFunction!(UnittestFuncInfo!nomatch,  A, methods) == -1);

    // considering opDispatch
    class B
    {
        void opDispatch(string name, A...)(A) {}
    }
    alias methodsB = GetOverloadedMethods!B;
    static assert(findCovariantFunction!(UnittestFuncInfo!draw,     B, methodsB) == ptrdiff_t.max);
    static assert(findCovariantFunction!(UnittestFuncInfo!value,    B, methodsB) == ptrdiff_t.max);
    static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, B, methodsB) == ptrdiff_t.max);
    static assert(findCovariantFunction!(UnittestFuncInfo!nomatch,  B, methodsB) == ptrdiff_t.max);
}

private template DerivedFunctionType(T...)
{
    static if (!T.length)
    {
        alias DerivedFunctionType = void;
    }
    else static if (T.length == 1)
    {
        static if (is(T[0] == function))
        {
            alias DerivedFunctionType = T[0];
        }
        else
        {
            alias DerivedFunctionType = void;
        }
    }
    else static if (is(T[0] P0 == function) && is(T[1] P1 == function))
    {
        alias FA = FunctionAttribute;

        alias F0 = T[0], R0 = ReturnType!F0, PSTC0 = ParameterStorageClassTuple!F0;
        alias F1 = T[1], R1 = ReturnType!F1, PSTC1 = ParameterStorageClassTuple!F1;
        enum FA0 = functionAttributes!F0;
        enum FA1 = functionAttributes!F1;

        template CheckParams(size_t i = 0)
        {
            static if (i >= P0.length)
                enum CheckParams = true;
            else
            {
                enum CheckParams = (is(P0[i] == P1[i]) && PSTC0[i] == PSTC1[i]) &&
                                   CheckParams!(i + 1);
            }
        }
        static if (R0.sizeof == R1.sizeof && !is(CommonType!(R0, R1) == void) &&
                   P0.length == P1.length && CheckParams!() && TypeMod!F0 == TypeMod!F1 &&
                   variadicFunctionStyle!F0 == variadicFunctionStyle!F1 &&
                   functionLinkage!F0 == functionLinkage!F1 &&
                   ((FA0 ^ FA1) & (FA.ref_ | FA.property)) == 0)
        {
            alias R = Select!(is(R0 : R1), R0, R1);
            alias FX = FunctionTypeOf!(R function(P0));
            // @system is default
            alias FY = SetFunctionAttributes!(FX, functionLinkage!F0, (FA0 | FA1) & ~FA.system);
            alias DerivedFunctionType = DerivedFunctionType!(FY, T[2 .. $]);
        }
        else
            alias DerivedFunctionType = void;
    }
    else
        alias DerivedFunctionType = void;
}
unittest
{
    // attribute covariance
    alias int F1();
    static assert(is(DerivedFunctionType!(F1, F1) == F1));
    alias int F2() pure nothrow;
    static assert(is(DerivedFunctionType!(F1, F2) == F2));
    alias int F3() @safe;
    alias int F23() @safe pure nothrow;
    static assert(is(DerivedFunctionType!(F2, F3) == F23));

    // return type covariance
    alias long F4();
    static assert(is(DerivedFunctionType!(F1, F4) == void));
    class C {}
    class D : C {}
    alias C F5();
    alias D F6();
    static assert(is(DerivedFunctionType!(F5, F6) == F6));
    alias typeof(null) F7();
    alias int[] F8();
    alias int* F9();
    static assert(is(DerivedFunctionType!(F5, F7) == F7));
    static assert(is(DerivedFunctionType!(F7, F8) == void));
    static assert(is(DerivedFunctionType!(F7, F9) == F7));

    // variadic type equality
    alias int F10(int);
    alias int F11(int...);
    alias int F12(int, ...);
    static assert(is(DerivedFunctionType!(F10, F11) == void));
    static assert(is(DerivedFunctionType!(F10, F12) == void));
    static assert(is(DerivedFunctionType!(F11, F12) == void));

    // linkage equality
    alias extern(C) int F13(int);
    alias extern(D) int F14(int);
    alias extern(Windows) int F15(int);
    static assert(is(DerivedFunctionType!(F13, F14) == void));
    static assert(is(DerivedFunctionType!(F13, F15) == void));
    static assert(is(DerivedFunctionType!(F14, F15) == void));

    // ref & @property equality
    alias int F16(int);
    alias ref int F17(int);
    alias @property int F18(int);
    static assert(is(DerivedFunctionType!(F16, F17) == void));
    static assert(is(DerivedFunctionType!(F16, F18) == void));
    static assert(is(DerivedFunctionType!(F17, F18) == void));
}

package template staticIota(int beg, int end)
{
    static if (beg + 1 >= end)
    {
        static if (beg >= end)
        {
            alias staticIota = TypeTuple!();
        }
        else
        {
            alias staticIota = TypeTuple!(+beg);
        }
    }
    else
    {
        enum mid = beg + (end - beg) / 2;
        alias staticIota = TypeTuple!(staticIota!(beg, mid), staticIota!(mid, end));
    }
}

private template mixinAll(mixins...)
{
    static if (mixins.length == 1)
    {
        static if (is(typeof(mixins[0]) == string))
        {
            mixin(mixins[0]);
        }
        else
        {
            alias it = mixins[0];
            mixin it;
        }
    }
    else static if (mixins.length >= 2)
    {
        mixin mixinAll!(mixins[ 0 .. $/2]);
        mixin mixinAll!(mixins[$/2 .. $ ]);
    }
}

private template Bind(alias Template, args1...)
{
    alias Bind(args2...) = Template!(args1, args2);
}


/**
Options regarding auto-initialization of a $(D RefCounted) object (see
the definition of $(D RefCounted) below).
 */
enum RefCountedAutoInitialize
{
    /// Do not auto-initialize the object
    no,
    /// Auto-initialize the object
    yes,
}

/**
Defines a reference-counted object containing a $(D T) value as
payload. $(D RefCounted) keeps track of all references of an object,
and when the reference count goes down to zero, frees the underlying
store. $(D RefCounted) uses $(D malloc) and $(D free) for operation.

$(D RefCounted) is unsafe and should be used with care. No references
to the payload should be escaped outside the $(D RefCounted) object.

The $(D autoInit) option makes the object ensure the store is
automatically initialized. Leaving $(D autoInit ==
RefCountedAutoInitialize.yes) (the default option) is convenient but
has the cost of a test whenever the payload is accessed. If $(D
autoInit == RefCountedAutoInitialize.no), user code must call either
$(D refCountedStore.isInitialized) or $(D refCountedStore.ensureInitialized)
before attempting to access the payload. Not doing so results in null
pointer dereference.
 */
struct RefCounted(T, RefCountedAutoInitialize autoInit =
        RefCountedAutoInitialize.yes)
if (!is(T == class) && !(is(T == interface)))
{
    /// $(D RefCounted) storage implementation.
    struct RefCountedStore
    {
        private struct Impl
        {
            T _payload;
            size_t _count;
        }

        private Impl* _store;

        private void initialize(A...)(auto ref A args)
        {
            import core.memory : GC;
            import core.stdc.stdlib : malloc;
            import std.conv : emplace;
            import std.exception : enforce;

            _store = cast(Impl*) enforce(malloc(Impl.sizeof));
            static if (hasIndirections!T)
                GC.addRange(&_store._payload, T.sizeof);
            emplace(&_store._payload, args);
            _store._count = 1;
        }

        /**
           Returns $(D true) if and only if the underlying store has been
           allocated and initialized.
        */
        @property nothrow @safe
        bool isInitialized() const
        {
            return _store !is null;
        }

        /**
           Returns underlying reference count if it is allocated and initialized
           (a positive integer), and $(D 0) otherwise.
        */
        @property nothrow @safe
        size_t refCount() const
        {
            return isInitialized ? _store._count : 0;
        }

        /**
           Makes sure the payload was properly initialized. Such a
           call is typically inserted before using the payload.
        */
        void ensureInitialized()
        {
            if (!isInitialized) initialize();
        }

    }
    RefCountedStore _refCounted;

    /// Returns storage implementation struct.
    @property nothrow @safe
    ref inout(RefCountedStore) refCountedStore() inout
    {
        return _refCounted;
    }

/**
Constructor that initializes the payload.

Postcondition: $(D refCountedStore.isInitialized)
 */
    this(A...)(auto ref A args) if (A.length > 0)
    {
        _refCounted.initialize(args);
    }

/**
Constructor that tracks the reference count appropriately. If $(D
!refCountedStore.isInitialized), does nothing.
 */
    this(this)
    {
        if (!_refCounted.isInitialized) return;
        ++_refCounted._store._count;
    }

/**
Destructor that tracks the reference count appropriately. If $(D
!refCountedStore.isInitialized), does nothing. When the reference count goes
down to zero, calls $(D destroy) agaist the payload and calls $(D free)
to deallocate the corresponding resource.
 */
    ~this()
    {
        if (!_refCounted.isInitialized) return;
        assert(_refCounted._store._count > 0);
        if (--_refCounted._store._count)
            return;
        // Done, deallocate
        .destroy(_refCounted._store._payload);
        static if (hasIndirections!T)
        {
            import core.memory : GC;
            GC.removeRange(&_refCounted._store._payload);
        }
        import core.stdc.stdlib : free;
        free(_refCounted._store);
        _refCounted._store = null;
    }

/**
Assignment operators
 */
    void opAssign(typeof(this) rhs)
    {
        import std.algorithm : swap;

        swap(_refCounted._store, rhs._refCounted._store);
    }

/// Ditto
    void opAssign(T rhs)
    {
        import std.algorithm : move;

        static if (autoInit == RefCountedAutoInitialize.yes)
        {
            _refCounted.ensureInitialized();
        }
        else
        {
            assert(_refCounted.isInitialized);
        }
        move(rhs, _refCounted._store._payload);
    }

    //version to have a single properly ddoc'ed function (w/ correct sig)
    version(StdDdoc)
    {
        /**
        Returns a reference to the payload. If (autoInit ==
        RefCountedAutoInitialize.yes), calls $(D
        refCountedStore.ensureInitialized). Otherwise, just issues $(D
        assert(refCountedStore.isInitialized)). Used with $(D alias
        refCountedPayload this;), so callers can just use the $(D RefCounted)
        object as a $(D T).

        $(BLUE The first overload exists only if $(D autoInit == RefCountedAutoInitialize.yes).)
        So if $(D autoInit == RefCountedAutoInitialize.no)
        or called for a constant or immutable object, then
        $(D refCountedPayload) will also be qualified as safe and nothrow
        (but will still assert if not initialized).
         */
        @property
        ref T refCountedPayload();

        /// ditto
        @property nothrow @safe
        ref inout(T) refCountedPayload() inout;
    }
    else
    {
        static if (autoInit == RefCountedAutoInitialize.yes)
        {
            //Can't use inout here because of potential mutation
            @property
            ref T refCountedPayload()
            {
                _refCounted.ensureInitialized();
                return _refCounted._store._payload;
            }
        }

        @property nothrow @safe
        ref inout(T) refCountedPayload() inout
        {
            assert(_refCounted.isInitialized, "Attempted to access an uninitialized payload.");
            return _refCounted._store._payload;
        }
    }

/**
Returns a reference to the payload. If (autoInit ==
RefCountedAutoInitialize.yes), calls $(D
refCountedStore.ensureInitialized). Otherwise, just issues $(D
assert(refCountedStore.isInitialized)).
 */
    alias refCountedPayload this;
}

///
unittest
{
    // A pair of an $(D int) and a $(D size_t) - the latter being the
    // reference count - will be dynamically allocated
    auto rc1 = RefCounted!int(5);
    assert(rc1 == 5);
    // No more allocation, add just one extra reference count
    auto rc2 = rc1;
    // Reference semantics
    rc2 = 42;
    assert(rc1 == 42);
    // the pair will be freed when rc1 and rc2 go out of scope
}

unittest
{
    RefCounted!int* p;
    {
        auto rc1 = RefCounted!int(5);
        p = &rc1;
        assert(rc1 == 5);
        assert(rc1._refCounted._store._count == 1);
        auto rc2 = rc1;
        assert(rc1._refCounted._store._count == 2);
        // Reference semantics
        rc2 = 42;
        assert(rc1 == 42);
        rc2 = rc2;
        assert(rc2._refCounted._store._count == 2);
        rc1 = rc2;
        assert(rc1._refCounted._store._count == 2);
    }
    assert(p._refCounted._store == null);

    // RefCounted as a member
    struct A
    {
        RefCounted!int x;
        this(int y)
        {
            x._refCounted.initialize(y);
        }
        A copy()
        {
            auto another = this;
            return another;
        }
    }
    auto a = A(4);
    auto b = a.copy();
    assert(a.x._refCounted._store._count == 2, "BUG 4356 still unfixed");
}

unittest
{
    import std.algorithm : swap;

    RefCounted!int p1, p2;
    swap(p1, p2);
}

// 6606
unittest
{
    union U {
       size_t i;
       void* p;
    }

    struct S {
       U u;
    }

    alias SRC = RefCounted!S;
}

// 6436
unittest
{
    struct S { this(ref int val) { assert(val == 3); ++val; } }

    int val = 3;
    auto s = RefCounted!S(val);
    assert(val == 4);
}

unittest
{
    RefCounted!int a;
    a = 5; //This should not assert
    assert(a == 5);

    RefCounted!int b;
    b = a; //This should not assert either
    assert(b == 5);
}

/**
Make proxy for $(D a).
 */
mixin template Proxy(alias a)
{
    private alias ValueType = typeof({ return a; }());
    private enum bool accessibleFrom(T) =
        is(typeof((ref T self){ cast(void)mixin("self." ~ a.stringof); }));

    static if (is(typeof(this) == class))
    {
        override bool opEquals(Object o)
        {
            if (auto b = cast(typeof(this))o)
            {
                import std.algorithm : startsWith;
                static assert(startsWith(a.stringof, "this."));
                return a == mixin("b."~a.stringof[5..$]); // remove "this."
            }
            return false;
        }

        bool opEquals(T)(T b)
            if (is(ValueType : T) || is(typeof(a.opEquals(b))) || is(typeof(b.opEquals(a))))
        {
            static if (is(typeof(a.opEquals(b))))
                return a.opEquals(b);
            else static if (is(typeof(b.opEquals(a))))
                return b.opEquals(a);
            else
                return a == b;
        }

        override int opCmp(Object o)
        {
            if (auto b = cast(typeof(this))o)
            {
                import std.algorithm : startsWith;
                static assert(startsWith(a.stringof, "this."));  // remove "this."
                return a < mixin("b."~a.stringof[5..$]) ? -1
                     : a > mixin("b."~a.stringof[5..$]) ? +1 : 0;
            }
            static if (is(ValueType == class))
                return a.opCmp(o);
            else
                throw new Exception("Attempt to compare a "~typeid(this).toString~" and a "~typeid(o).toString);
        }

        int opCmp(T)(auto ref const T b)
            if (is(ValueType : T) || is(typeof(a.opCmp(b))) || is(typeof(b.opCmp(a))))
        {
            static if (is(typeof(a.opCmp(b))))
                return a.opCmp(b);
            else static if (is(typeof(b.opCmp(a))))
                return -b.opCmp(b);
            else
                return a < b ? -1 : a > b ? +1 : 0;
        }

        static if (accessibleFrom!(const typeof(this)))
        {
            override hash_t toHash() const nothrow @trusted
            {
                static if (is(typeof(&a) == ValueType*))
                    alias v = a;
                else
                    auto v = a;     // if a is (property) function
                return typeid(ValueType).getHash(cast(const void*)&v);
            }
        }
    }
    else
    {
        auto ref opEquals(this X, B)(auto ref B b)
        {
            static if (is(immutable B == immutable typeof(this)))
            {
                import std.algorithm : startsWith;
                static assert(startsWith(a.stringof, "this."));
                return a == mixin("b."~a.stringof[5..$]);   // remove "this."
            }
            else
                return a == b;
        }

        auto ref opCmp(this X, B)(auto ref B b)
          if (!is(typeof(a.opCmp(b))) || !is(typeof(b.opCmp(a))))
        {
            static if (is(typeof(a.opCmp(b))))
                return a.opCmp(b);
            else static if (is(typeof(b.opCmp(a))))
                return -b.opCmp(a);
            else
                return a < b ? -1 : a > b ? +1 : 0;
        }

        static if (accessibleFrom!(const typeof(this)))
        {
            hash_t toHash() const nothrow @trusted
            {
                static if (is(typeof(&a) == ValueType*))
                    alias v = a;
                else
                    auto v = a;     // if a is (property) function
                return typeid(ValueType).getHash(cast(const void*)&v);
            }
        }
    }

    auto ref opCall(this X, Args...)(auto ref Args args) { return a(args); }

    auto ref opCast(T, this X)() { return cast(T)a; }

    auto ref opIndex(this X, D...)(auto ref D i)               { return a[i]; }
    auto ref opSlice(this X      )()                           { return a[]; }
    auto ref opSlice(this X, B, E)(auto ref B b, auto ref E e) { return a[b..e]; }

    auto ref opUnary     (string op, this X      )()                           { return mixin(op~"a"); }
    auto ref opIndexUnary(string op, this X, D...)(auto ref D i)               { return mixin(op~"a[i]"); }
    auto ref opSliceUnary(string op, this X      )()                           { return mixin(op~"a[]"); }
    auto ref opSliceUnary(string op, this X, B, E)(auto ref B b, auto ref E e) { return mixin(op~"a[b..e]"); }

    auto ref opBinary(string op, this X, B)(auto ref B b)
    if (op == "in" && is(typeof(a in b)) || op != "in")
    {
        return mixin("a "~op~" b");
    }
    auto ref opBinaryRight(string op, this X, B)(auto ref B b) { return mixin("b "~op~" a"); }

    static if (!is(typeof(this) == class))
    {
        private import std.traits;
        static if (isAssignable!ValueType)
        {
            auto ref opAssign(this X)(auto ref typeof(this) v)
            {
                a = mixin("v."~a.stringof[5..$]);   // remove "this."
                return this;
            }
        }
        else
        {
            @disable void opAssign(this X)(auto ref typeof(this) v);
        }
    }

    auto ref opAssign     (this X, V      )(auto ref V v) if (!is(V == typeof(this))) { return a       = v; }
    auto ref opIndexAssign(this X, V, D...)(auto ref V v, auto ref D i)               { return a[i]    = v; }
    auto ref opSliceAssign(this X, V      )(auto ref V v)                             { return a[]     = v; }
    auto ref opSliceAssign(this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e) { return a[b..e] = v; }

    auto ref opOpAssign     (string op, this X, V      )(auto ref V v)                             { return mixin("a "      ~op~"= v"); }
    auto ref opIndexOpAssign(string op, this X, V, D...)(auto ref V v, auto ref D i)               { return mixin("a[i] "   ~op~"= v"); }
    auto ref opSliceOpAssign(string op, this X, V      )(auto ref V v)                             { return mixin("a[] "    ~op~"= v"); }
    auto ref opSliceOpAssign(string op, this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e) { return mixin("a[b..e] "~op~"= v"); }

    template opDispatch(string name)
    {
        static if (is(typeof(__traits(getMember, a, name)) == function))
        {
            // non template function
            auto ref opDispatch(this X, Args...)(auto ref Args args) { return mixin("a."~name~"(args)"); }
        }
        else static if (is(typeof({ enum x = mixin("a."~name); })))
        {
            // built-in type field, manifest constant, and static non-mutable field
            enum opDispatch = mixin("a."~name);
        }
        else static if (is(typeof(mixin("a."~name))) || __traits(getOverloads, a, name).length != 0)
        {
            // field or property function
            @property auto ref opDispatch(this X)()                { return mixin("a."~name);        }
            @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); }
        }
        else
        {
            // member template
            template opDispatch(T...)
            {
                enum targs = T.length ? "!T" : "";
                auto ref opDispatch(this X, Args...)(auto ref Args args){ return mixin("a."~name~targs~"(args)"); }
            }
        }
    }

    import std.traits : isArray;

    static if (isArray!ValueType)
    {
        auto opDollar() const { return a.length; }
    }
    else static if (is(typeof(a.opDollar!0)))
    {
        auto ref opDollar(size_t pos)() { return a.opDollar!pos(); }
    }
    else static if (is(typeof(a.opDollar) == function))
    {
        auto ref opDollar() { return a.opDollar(); }
    }
    else static if (is(typeof(a.opDollar)))
    {
        alias opDollar = a.opDollar;
    }
}

///
unittest
{
    struct MyInt
    {
        private int value;
        mixin Proxy!value;

        this(int n){ value = n; }
    }

    MyInt n = 10;

    // Enable operations that original type has.
    ++n;
    assert(n == 11);
    assert(n * 2 == 22);

    void func(int n) { }

    // Disable implicit conversions to original type.
    //int x = n;
    //func(n);
}

unittest
{
    static struct MyInt
    {
        private int value;
        mixin Proxy!value;
        this(int n) inout { value = n; }

        enum str = "str";
        static immutable arr = [1,2,3];
    }

    foreach (T; TypeTuple!(MyInt, const MyInt, immutable MyInt))
    {
        T m = 10;
        static assert(!__traits(compiles, { int x = m; }));
        static assert(!__traits(compiles, { void func(int n){} func(m); }));
        assert(m == 10);
        assert(m != 20);
        assert(m < 20);
        assert(+m == 10);
        assert(-m == -10);
        assert(cast(double)m == 10.0);
        assert(m + 10 == 20);
        assert(m - 5 == 5);
        assert(m * 20 == 200);
        assert(m / 2 == 5);
        assert(10 + m == 20);
        assert(15 - m == 5);
        assert(20 * m == 200);
        assert(50 / m == 5);
        static if (is(T == MyInt))  // mutable
        {
            assert(++m == 11);
            assert(m++ == 11); assert(m == 12);
            assert(--m == 11);
            assert(m-- == 11); assert(m == 10);
            m = m;
            m = 20; assert(m == 20);
        }
        static assert(T.max == int.max);
        static assert(T.min == int.min);
        static assert(T.init == int.init);
        static assert(T.str == "str");
        static assert(T.arr == [1,2,3]);
    }
}
unittest
{
    static struct MyArray
    {
        private int[] value;
        mixin Proxy!value;
        this(int[] arr) { value = arr; }
        this(immutable int[] arr) immutable { value = arr; }
    }

    foreach (T; TypeTuple!(MyArray, const MyArray, immutable MyArray))
    {
      static if (is(T == immutable) && !is(typeof({ T a = [1,2,3,4]; })))
        T a = [1,2,3,4].idup;   // workaround until qualified ctor is properly supported
      else
        T a = [1,2,3,4];
        assert(a == [1,2,3,4]);
        assert(a != [5,6,7,8]);
        assert(+a[0]    == 1);
        version (LittleEndian)
            assert(cast(ulong[])a == [0x0000_0002_0000_0001, 0x0000_0004_0000_0003]);
        else
            assert(cast(ulong[])a == [0x0000_0001_0000_0002, 0x0000_0003_0000_0004]);
        assert(a ~ [10,11] == [1,2,3,4,10,11]);
        assert(a[0]    == 1);
        assert(a[]     == [1,2,3,4]);
        assert(a[2..4] == [3,4]);
        static if (is(T == MyArray))    // mutable
        {
            a = a;
            a = [5,6,7,8];  assert(a == [5,6,7,8]);
            a[0]     = 0;   assert(a == [0,6,7,8]);
            a[]      = 1;   assert(a == [1,1,1,1]);
            a[0..3]  = 2;   assert(a == [2,2,2,1]);
            a[0]    += 2;   assert(a == [4,2,2,1]);
            a[]     *= 2;   assert(a == [8,4,4,2]);
            a[0..2] /= 2;   assert(a == [4,2,4,2]);
        }
    }
}
unittest
{
    class Foo
    {
        int field;

        @property int val1() const { return field; }
        @property void val1(int n) { field = n; }

        @property ref int val2() { return field; }

        int func(int x, int y) const { return x; }
        void func1(ref int a) { a = 9; }

        T ifti1(T)(T t) { return t; }
        void ifti2(Args...)(Args args) { }
        void ifti3(T, Args...)(Args args) { }

        T opCast(T)(){ return T.init; }

        T tempfunc(T)() { return T.init; }
    }
    class Hoge
    {
        Foo foo;
        mixin Proxy!foo;
        this(Foo f) { foo = f; }
    }

    auto h = new Hoge(new Foo());
    int n;

    static assert(!__traits(compiles, { Foo f = h; }));

    // field
    h.field = 1;            // lhs of assign
    n = h.field;            // rhs of assign
    assert(h.field == 1);   // lhs of BinExp
    assert(1 == h.field);   // rhs of BinExp
    assert(n == 1);

    // getter/setter property function
    h.val1 = 4;
    n = h.val1;
    assert(h.val1 == 4);
    assert(4 == h.val1);
    assert(n == 4);

    // ref getter property function
    h.val2 = 8;
    n = h.val2;
    assert(h.val2 == 8);
    assert(8 == h.val2);
    assert(n == 8);

    // member function
    assert(h.func(2,4) == 2);
    h.func1(n);
    assert(n == 9);

    // IFTI
    assert(h.ifti1(4) == 4);
    h.ifti2(4);
    h.ifti3!int(4, 3);

    // bug5896 test
    assert(h.opCast!int() == 0);
    assert(cast(int)h == 0);
    const ih = new const Hoge(new Foo());
    static assert(!__traits(compiles, ih.opCast!int()));
    static assert(!__traits(compiles, cast(int)ih));

    // template member function
    assert(h.tempfunc!int() == 0);
}

unittest // about Proxy inside a class
{
    class MyClass
    {
        int payload;
        mixin Proxy!payload;
        this(int i){ payload = i; }
        string opCall(string msg){ return msg; }
        int pow(int i){ return payload ^^ i; }
    }

    class MyClass2
    {
        MyClass payload;
        mixin Proxy!payload;
        this(int i){ payload = new MyClass(i); }
    }

    class MyClass3
    {
        int payload;
        mixin Proxy!payload;
        this(int i){ payload = i; }
    }

    // opEquals
    Object a = new MyClass(5);
    Object b = new MyClass(5);
    Object c = new MyClass2(5);
    Object d = new MyClass3(5);
    assert(a == b);
    assert((cast(MyClass)a) == 5);
    assert(5 == (cast(MyClass)b));
    assert(5 == cast(MyClass2)c);
    assert(a != d);

    assert(c != a);
    // oops! above line is unexpected, isn't it?
    // the reason is below.
    // MyClass2.opEquals knows MyClass but,
    // MyClass.opEquals doesn't know MyClass2.
    // so, c.opEquals(a) is true, but a.opEquals(c) is false.
    // furthermore, opEquals(T) couldn't be invoked.
    assert((cast(MyClass2)c) != (cast(MyClass)a));

    // opCmp
    Object e = new MyClass2(7);
    assert(a < cast(MyClass2)e); // OK. and
    assert(e > a); // OK, but...
    // assert(a < e); // RUNTIME ERROR!
    // assert((cast(MyClass)a) < e); // RUNTIME ERROR!
    assert(3 < cast(MyClass)a);
    assert((cast(MyClass2)e) < 11);

    // opCall
    assert((cast(MyClass2)e)("hello") == "hello");

    // opCast
    assert((cast(MyClass)(cast(MyClass2)c)) == a);
    assert((cast(int)(cast(MyClass2)c)) == 5);

    // opIndex
    class MyClass4
    {
        string payload;
        mixin Proxy!payload;
        this(string s){ payload = s; }
    }
    class MyClass5
    {
        MyClass4 payload;
        mixin Proxy!payload;
        this(string s){ payload = new MyClass4(s); }
    }
    auto f = new MyClass4("hello");
    assert(f[1] == 'e');
    auto g = new MyClass5("hello");
    assert(f[1] == 'e');

    // opSlice
    assert(f[2..4] == "ll");

    // opUnary
    assert(-(cast(MyClass2)c) == -5);

    // opBinary
    assert((cast(MyClass)a) + (cast(MyClass2)c) == 10);
    assert(5 + cast(MyClass)a == 10);

    // opAssign
    (cast(MyClass2)c) = 11;
    assert((cast(MyClass2)c) == 11);
    (cast(MyClass2)c) = new MyClass(13);
    assert((cast(MyClass2)c) == 13);

    // opOpAssign
    assert((cast(MyClass2)c) += 4);
    assert((cast(MyClass2)c) == 17);

    // opDispatch
    assert((cast(MyClass2)c).pow(2) == 289);

    // opDollar
    assert(f[2..$-1] == "ll");

    // toHash
    int[Object] hash;
    hash[a] = 19;
    hash[c] = 21;
    assert(hash[b] == 19);
    assert(hash[c] == 21);
}

unittest
{
    struct MyInt
    {
        int payload;

        mixin Proxy!payload;
    }

    MyInt v;
    v = v;

    struct Foo
    {
        @disable void opAssign(typeof(this));
    }
    struct MyFoo
    {
        Foo payload;

        mixin Proxy!payload;
    }
    MyFoo f;
    static assert(!__traits(compiles, f = f));

    struct MyFoo2
    {
        Foo payload;

        mixin Proxy!payload;

        // override default Proxy behavior
        void opAssign(typeof(this) rhs){}
    }
    MyFoo2 f2;
    f2 = f2;
}
unittest
{
    // bug8613
    static struct Name
    {
        mixin Proxy!val;
        private string val;
        this(string s) { val = s; }
    }

    bool[Name] names;
    names[Name("a")] = true;
    bool* b = Name("a") in names;
}

unittest
{
    // bug14213, using function for the payload
    static struct S
    {
        int foo() { return 12; }
        mixin Proxy!foo;
    }
    static class C
    {
        int foo() { return 12; }
        mixin Proxy!foo;
    }
    S s;
    assert(s + 1 == 13);
    C c = new C();
    assert(s * 2 == 24);
}

/**
$(B Typedef) allows the creation of a unique type which is
based on an existing type. Unlike the $(D alias) feature,
$(B Typedef) ensures the two types are not considered as equals.

Example:
----
alias MyInt = Typedef!int;
static void takeInt(int) { }
static void takeMyInt(MyInt) { }

int i;
takeInt(i);    // ok
takeMyInt(i);  // fails

MyInt myInt;
takeInt(myInt);    // fails
takeMyInt(myInt);  // ok
----

Params:

init = Optional initial value for the new type. For example:

----
alias MyInt = Typedef!(int, 10);
MyInt myInt;
assert(myInt == 10);  // default-initialized to 10
----

cookie = Optional, used to create multiple unique types which are
based on the same origin type $(D T). For example:

----
alias TypeInt1 = Typedef!int;
alias TypeInt2 = Typedef!int;

// The two Typedefs are the same type.
static assert(is(TypeInt1 == TypeInt2));

alias MoneyEuros = Typedef!(float, float.init, "euros");
alias MoneyDollars = Typedef!(float, float.init, "dollars");

// The two Typedefs are _not_ the same type.
static assert(!is(MoneyEuros == MoneyDollars));
----

Note: If a library routine cannot handle the Typedef type,
you can use the $(D TypedefType) template to extract the
type which the Typedef wraps.
 */
struct Typedef(T, T init = T.init, string cookie=null)
{
    private T Typedef_payload = init;

    this(T init)
    {
        Typedef_payload = init;
    }

    this(Typedef tdef)
    {
        this(tdef.Typedef_payload);
    }

    // We need to add special overload for cast(Typedef!X)exp,
    // thus we can't simply inherit Proxy!Typedef_payload
    T2 opCast(T2 : Typedef!(T, Unused), this X, T, Unused...)()
    {
        return T2(cast(T)Typedef_payload);
    }

    auto ref opCast(T2, this X)()
    {
        return cast(T2)Typedef_payload;
    }

    mixin Proxy!Typedef_payload;
}

/**
Get the underlying type which a $(D Typedef) wraps.
If $(D T) is not a $(D Typedef) it will alias itself to $(D T).
*/
template TypedefType(T)
{
    static if (is(T : Typedef!Arg, Arg))
        alias TypedefType = Arg;
    else
        alias TypedefType = T;
}

///
unittest
{
    import std.typecons: Typedef, TypedefType;
    import std.conv: to;

    alias MyInt = Typedef!int;
    static assert(is(TypedefType!MyInt == int));

    /// Instantiating with a non-Typedef will return that type
    static assert(is(TypedefType!int == int));

    string num = "5";

    // extract the needed type
    MyInt myInt = MyInt( num.to!(TypedefType!MyInt) );
    assert(myInt == 5);

    // cast to the underlying type to get the value that's being wrapped
    int x = cast(TypedefType!MyInt)myInt;

    alias MyIntInit = Typedef!(int, 42);
    static assert(is(TypedefType!MyIntInit == int));
    static assert(MyIntInit() == 42);
}

unittest
{
    Typedef!int x = 10;
    static assert(!__traits(compiles, { int y = x; }));
    static assert(!__traits(compiles, { long z = x; }));

    Typedef!int y = 10;
    assert(x == y);

    static assert(Typedef!int.init == int.init);

    Typedef!(float, 1.0) z; // specifies the init
    assert(z == 1.0);

    static assert(typeof(z).init == 1.0);

    alias Dollar = Typedef!(int, 0, "dollar");
    alias Yen    = Typedef!(int, 0, "yen");
    static assert(!is(Dollar == Yen));

    Typedef!(int[3]) sa;
    static assert(sa.length == 3);
    static assert(typeof(sa).length == 3);

    Typedef!(int[3]) dollar1;
    assert(dollar1[0..$] is dollar1[0..3]);

    Typedef!(int[]) dollar2;
    dollar2.length = 3;
    assert(dollar2[0..$] is dollar2[0..3]);

    static struct Dollar1
    {
        static struct DollarToken {}
        enum opDollar = DollarToken.init;
        auto opSlice(size_t, DollarToken) { return 1; }
        auto opSlice(size_t, size_t) { return 2; }
    }

    Typedef!Dollar1 drange1;
    assert(drange1[0..$] == 1);
    assert(drange1[0..1] == 2);

    static struct Dollar2
    {
        size_t opDollar(size_t pos)() { return pos == 0 ? 1 : 100; }
        size_t opIndex(size_t i, size_t j) { return i + j; }
    }

    Typedef!Dollar2 drange2;
    assert(drange2[$, $] == 101);

    static struct Dollar3
    {
        size_t opDollar() { return 123; }
        size_t opIndex(size_t i) { return i; }
    }

    Typedef!Dollar3 drange3;
    assert(drange3[$] == 123);
}

unittest
{
    // bug8655
    import std.typecons;
    import std.bitmanip;
    static import core.stdc.config;

    alias c_ulong = Typedef!(core.stdc.config.c_ulong);

    static struct Foo
    {
        mixin(bitfields!(
            c_ulong, "NameOffset", 31,
            c_ulong, "NameIsString", 1
        ));
    }
}

unittest // Issue 12596
{
    import std.typecons;
    alias TD = Typedef!int;
    TD x = TD(1);
    TD y = TD(x);
    assert(x == y);
}

unittest // about toHash
{
    import std.typecons;
    {
        alias TD = Typedef!int;
        int[TD] td;
        td[TD(1)] = 1;
        assert(td[TD(1)] == 1);
    }

    {
        alias TD = Typedef!(int[]);
        int[TD] td;
        td[TD([1,2,3,4])] = 2;
        assert(td[TD([1,2,3,4])] == 2);
    }

    {
        alias TD = Typedef!(int[][]);
        int[TD] td;
        td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] = 3;
        assert(td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] == 3);
    }

    {
        struct MyStruct{ int x; }
        alias TD = Typedef!MyStruct;
        int[TD] td;
        td[TD(MyStruct(10))] = 4;
        assert(TD(MyStruct(20)) !in td);
        assert(td[TD(MyStruct(10))] == 4);
    }

    {
        static struct MyStruct2
        {
            int x;
            size_t toHash() const nothrow @safe { return x; }
            bool opEquals(ref const MyStruct2 r) const { return r.x == x; }
        }

        alias TD = Typedef!MyStruct2;
        int[TD] td;
        td[TD(MyStruct2(50))] = 5;
        assert(td[TD(MyStruct2(50))] == 5);
    }

    {
        class MyClass{}
        alias TD = Typedef!MyClass;
        int[TD] td;
        auto c = new MyClass;
        td[TD(c)] = 6;
        assert(TD(new MyClass) !in td);
        assert(td[TD(c)] == 6);
    }
}

unittest
{
    alias String = Typedef!(char[]);
    alias CString = Typedef!(const(char)[]);
    CString cs = "fubar";
    String s = cast(String)cs;
    assert(cs == s);
    char[] s2 = cast(char[])cs;
    const(char)[] cs2 = cast(const(char)[])s;
    assert(s2 == cs2);
}

/**
Allocates a $(D class) object right inside the current scope,
therefore avoiding the overhead of $(D new). This facility is unsafe;
it is the responsibility of the user to not escape a reference to the
object outside the scope.

Note: it's illegal to move a class reference even if you are sure there
are no pointers to it. As such, it is illegal to move a scoped object.
 */
template scoped(T)
    if (is(T == class))
{
    // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for
    // small objects). We will just use the maximum of filed alignments.
    alias alignment = classInstanceAlignment!T;
    alias aligned = _alignUp!alignment;

    static struct Scoped
    {
        // Addition of `alignment` is required as `Scoped_store` can be misaligned in memory.
        private void[aligned(__traits(classInstanceSize, T) + size_t.sizeof) + alignment] Scoped_store = void;

        @property inout(T) Scoped_payload() inout
        {
            void* alignedStore = cast(void*) aligned(cast(size_t) Scoped_store.ptr);
            // As `Scoped` can be unaligned moved in memory class instance should be moved accordingly.
            immutable size_t d = alignedStore - Scoped_store.ptr;
            size_t* currD = cast(size_t*) &Scoped_store[$ - size_t.sizeof];
            if(d != *currD)
            {
                import core.stdc.string;
                memmove(alignedStore, Scoped_store.ptr + *currD, __traits(classInstanceSize, T));
                *currD = d;
            }
            return cast(inout(T)) alignedStore;
        }
        alias Scoped_payload this;

        @disable this();
        @disable this(this);

        ~this()
        {
            // `destroy` will also write .init but we have no functions in druntime
            // for deterministic finalization and memory releasing for now.
            .destroy(Scoped_payload);
        }
    }

    /// Returns the scoped object
    @system auto scoped(Args...)(auto ref Args args)
    {
        import std.conv : emplace;

        Scoped result = void;
        void* alignedStore = cast(void*) aligned(cast(size_t) result.Scoped_store.ptr);
        immutable size_t d = alignedStore - result.Scoped_store.ptr;
        *cast(size_t*) &result.Scoped_store[$ - size_t.sizeof] = d;
        emplace!(Unqual!T)(result.Scoped_store[d .. $ - size_t.sizeof], args);
        return result;
    }
}
///
unittest
{
    class A
    {
        int x;
        this()     {x = 0;}
        this(int i){x = i;}
    }

    // Standard usage
    auto a1 = scoped!A();
    auto a2 = scoped!A(1);
    a1.x = 42;
    assert(a1.x == 42);
    assert(a2.x ==  1);

    // Restrictions
    static assert(!is(typeof({
        auto e1 = a1; // illegal, scoped objects can't be copied
        assert([a2][0].x == 42); // ditto
        alias ScopedObject = typeof(a1);
        auto e2 = ScopedObject();  //Illegal, must be built via scoped!A
        auto e3 = ScopedObject(1); //Illegal, must be built via scoped!A
    })));

    // Use as member variable
    struct B
    {
        typeof(scoped!A()) a; // note the trailing parentheses
    }

    // Use with alias
    alias makeScopedA = scoped!A;
    auto a6 = makeScopedA();
    auto a7 = makeScopedA();
}

private size_t _alignUp(size_t alignment)(size_t n)
    if(alignment > 0 && !((alignment - 1) & alignment))
{
    enum badEnd = alignment - 1; // 0b11, 0b111, ...
    return (n + badEnd) & ~badEnd;
}

unittest // Issue 6580 testcase
{
    enum alignment = (void*).alignof;

    static class C0 { }
    static class C1 { byte b; }
    static class C2 { byte[2] b; }
    static class C3 { byte[3] b; }
    static class C7 { byte[7] b; }
    static assert(scoped!C0().sizeof % alignment == 0);
    static assert(scoped!C1().sizeof % alignment == 0);
    static assert(scoped!C2().sizeof % alignment == 0);
    static assert(scoped!C3().sizeof % alignment == 0);
    static assert(scoped!C7().sizeof % alignment == 0);

    enum longAlignment = long.alignof;
    static class C1long
    {
        long long_; byte byte_ = 4;
        this() { }
        this(long _long, ref int i) { long_ = _long; ++i; }
    }
    static class C2long { byte[2] byte_ = [5, 6]; long long_ = 7; }
    static assert(scoped!C1long().sizeof % longAlignment == 0);
    static assert(scoped!C2long().sizeof % longAlignment == 0);

    void alignmentTest()
    {
        int var = 5;
        auto c1long = scoped!C1long(3, var);
        assert(var == 6);
        auto c2long = scoped!C2long();
        assert(cast(size_t)&c1long.long_ % longAlignment == 0);
        assert(cast(size_t)&c2long.long_ % longAlignment == 0);
        assert(c1long.long_ == 3 && c1long.byte_ == 4);
        assert(c2long.byte_ == [5, 6] && c2long.long_ == 7);
    }

    alignmentTest();

    version(DigitalMars)
    {
        void test(size_t size)
        {
            import core.stdc.stdlib;
            alloca(size);
            alignmentTest();
        }
        foreach(i; 0 .. 10)
            test(i);
    }
    else
    {
        void test(size_t size)()
        {
            byte[size] arr;
            alignmentTest();
        }
        foreach(i; TypeTuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
            test!i();
    }
}

unittest // Original Issue 6580 testcase
{
    class C { int i; byte b; }

    auto sa = [scoped!C(), scoped!C()];
    assert(cast(size_t)&sa[0].i % int.alignof == 0);
    assert(cast(size_t)&sa[1].i % int.alignof == 0); // fails
}

unittest
{
    class A { int x = 1; }
    auto a1 = scoped!A();
    assert(a1.x == 1);
    auto a2 = scoped!A();
    a1.x = 42;
    a2.x = 53;
    assert(a1.x == 42);
}

unittest
{
    class A { int x = 1; this() { x = 2; } }
    auto a1 = scoped!A();
    assert(a1.x == 2);
    auto a2 = scoped!A();
    a1.x = 42;
    a2.x = 53;
    assert(a1.x == 42);
}

unittest
{
    class A { int x = 1; this(int y) { x = y; } ~this() {} }
    auto a1 = scoped!A(5);
    assert(a1.x == 5);
    auto a2 = scoped!A(42);
    a1.x = 42;
    a2.x = 53;
    assert(a1.x == 42);
}

unittest
{
    class A { static bool dead; ~this() { dead = true; } }
    class B : A { static bool dead; ~this() { dead = true; } }
    {
        auto b = scoped!B();
    }
    assert(B.dead, "asdasd");
    assert(A.dead, "asdasd");
}

unittest // Issue 8039 testcase
{
    static int dels;
    static struct S { ~this(){ ++dels; } }

    static class A { S s; }
    dels = 0; { scoped!A(); }
    assert(dels == 1);

    static class B { S[2] s; }
    dels = 0; { scoped!B(); }
    assert(dels == 2);

    static struct S2 { S[3] s; }
    static class C { S2[2] s; }
    dels = 0; { scoped!C(); }
    assert(dels == 6);

    static class D: A { S2[2] s; }
    dels = 0; { scoped!D(); }
    assert(dels == 1+6);
}

unittest
{
    // bug4500
    class A
    {
        this() { a = this; }
        this(int i) { a = this; }
        A a;
        bool check() { return this is a; }
    }

    auto a1 = scoped!A();
    assert(a1.check());

    auto a2 = scoped!A(1);
    assert(a2.check());

    a1.a = a1;
    assert(a1.check());
}

unittest
{
    static class A
    {
        static int sdtor;

        this() { ++sdtor; assert(sdtor == 1); }
        ~this() { assert(sdtor == 1); --sdtor; }
    }

    interface Bob {}

    static class ABob : A, Bob
    {
        this() { ++sdtor; assert(sdtor == 2); }
        ~this() { assert(sdtor == 2); --sdtor; }
    }

    A.sdtor = 0;
    scope(exit) assert(A.sdtor == 0);
    auto abob = scoped!ABob();
}

unittest
{
    static class A { this(int) {} }
    static assert(!__traits(compiles, scoped!A()));
}

unittest
{
    static class A { @property inout(int) foo() inout { return 1; } }

    auto a1 = scoped!A();
    assert(a1.foo == 1);
    static assert(is(typeof(a1.foo) == int));

    auto a2 = scoped!(const(A))();
    assert(a2.foo == 1);
    static assert(is(typeof(a2.foo) == const(int)));

    auto a3 = scoped!(immutable(A))();
    assert(a3.foo == 1);
    static assert(is(typeof(a3.foo) == immutable(int)));

    const c1 = scoped!A();
    assert(c1.foo == 1);
    static assert(is(typeof(c1.foo) == const(int)));

    const c2 = scoped!(const(A))();
    assert(c2.foo == 1);
    static assert(is(typeof(c2.foo) == const(int)));

    const c3 = scoped!(immutable(A))();
    assert(c3.foo == 1);
    static assert(is(typeof(c3.foo) == immutable(int)));
}

unittest
{
    class C { this(ref int val) { assert(val == 3); ++val; } }

    int val = 3;
    auto s = scoped!C(val);
    assert(val == 4);
}

unittest
{
    class C
    {
        this(){}
        this(int){}
        this(int, int){}
    }
    alias makeScopedC = scoped!C;

    auto a = makeScopedC();
    auto b = makeScopedC(1);
    auto c = makeScopedC(1, 1);

    static assert(is(typeof(a) == typeof(b)));
    static assert(is(typeof(b) == typeof(c)));
}

/**
Defines a simple, self-documenting yes/no flag. This makes it easy for
APIs to define functions accepting flags without resorting to $(D
bool), which is opaque in calls, and without needing to define an
enumerated type separately. Using $(D Flag!"Name") instead of $(D
bool) makes the flag's meaning visible in calls. Each yes/no flag has
its own type, which makes confusions and mix-ups impossible.

Example:

Code calling $(D getLine) (usually far away from its definition) can't be
understood without looking at the documentation, even by users familiar with
the API:
----
string getLine(bool keepTerminator)
{
    ...
    if (keepTerminator) ...
    ...
}
...
auto line = getLine(false);
----

Assuming the reverse meaning (i.e. "ignoreTerminator") and inserting the wrong
code compiles and runs with erroneous results.

After replacing the boolean parameter with an instantiation of $(D Flag), code
calling $(D getLine) can be easily read and understood even by people not
fluent with the API:

----
string getLine(Flag!"keepTerminator" keepTerminator)
{
    ...
    if (keepTerminator) ...
    ...
}
...
auto line = getLine(Flag!"keepTerminator".yes);
----

Passing categorical data by means of unstructured $(D bool)
parameters is classified under "simple-data coupling" by Steve
McConnell in the $(LUCKY Code Complete) book, along with three other
kinds of coupling. The author argues citing several studies that
coupling has a negative effect on code quality. $(D Flag) offers a
simple structuring method for passing yes/no flags to APIs.

An alias can be used to reduce the verbosity of the flag's type:
----
alias KeepTerminator = Flag!"keepTerminator";
string getline(KeepTerminator keepTerminator)
{
    ...
    if (keepTerminator) ...
    ...
}
...
// Code calling getLine can now refer to flag values using the shorter name:
auto line = getLine(KeepTerminator.yes);
----
 */
template Flag(string name) {
    ///
    enum Flag : bool
    {
        /**
         When creating a value of type $(D Flag!"Name"), use $(D
         Flag!"Name".no) for the negative option. When using a value
         of type $(D Flag!"Name"), compare it against $(D
         Flag!"Name".no) or just $(D false) or $(D 0).  */
        no = false,

        /** When creating a value of type $(D Flag!"Name"), use $(D
         Flag!"Name".yes) for the affirmative option. When using a
         value of type $(D Flag!"Name"), compare it against $(D
         Flag!"Name".yes).
        */
        yes = true
    }
}

/**
Convenience names that allow using e.g. $(D Yes.encryption) instead of
$(D Flag!"encryption".yes) and $(D No.encryption) instead of $(D
Flag!"encryption".no).
*/
struct Yes
{
    template opDispatch(string name)
    {
        enum opDispatch = Flag!name.yes;
    }
}
//template yes(string name) { enum Flag!name yes = Flag!name.yes; }

/// Ditto
struct No
{
    template opDispatch(string name)
    {
        enum opDispatch = Flag!name.no;
    }
}

///
unittest
{
    Flag!"abc" flag1;
    assert(flag1 == Flag!"abc".no);
    assert(flag1 == No.abc);
    assert(!flag1);
    if (flag1) assert(false);
    flag1 = Yes.abc;
    assert(flag1);
    if (!flag1) assert(false);
    if (flag1) {} else assert(false);
    assert(flag1 == Yes.abc);
}

/**
Detect whether an enum is of integral type and has only "flag" values
(i.e. values with a bit count of exactly 1).
Additionally, a zero value is allowed for compatibility with enums including
a "None" value.
*/
template isBitFlagEnum(E)
{
    static if (is(E Base == enum) && isIntegral!Base)
    {
        enum isBitFlagEnum = (E.min >= 0) &&
        {
            foreach (immutable flag; EnumMembers!E)
            {
                Base value = flag;
                value &= value - 1;
                if (value != 0) return false;
            }
            return true;
        }();
    }
    else
    {
        enum isBitFlagEnum = false;
    }
}

///
@safe pure nothrow unittest
{
    enum A
    {
        None,
        A = 1<<0,
        B = 1<<1,
        C = 1<<2,
        D = 1<<3,
    }

    static assert(isBitFlagEnum!A);

    enum B
    {
        A,
        B,
        C,
        D // D == 3
    }

    static assert(!isBitFlagEnum!B);

    enum C: double
    {
        A = 1<<0,
        B = 1<<1
    }

    static assert(!isBitFlagEnum!C);
}

/**
A typesafe structure for storing combination of enum values.

This template defines a simple struct to represent bitwise OR combinations of
enum values. It can be used if all the enum values are integral constants with
a bit count of at most 1, or if the $(D unsafe) parameter is explicitly set to
Yes.
This is much safer than using the enum itself to store
the OR combination, which can produce surprising effects like this:
----
enum E
{
    A = 1<<0,
    B = 1<<1
}
E e = E.A | E.B;
// will throw SwitchError
final switch(e)
{
    case E.A:
        return;
    case E.B:
        return;
}
----
*/
struct BitFlags(E, Flag!"unsafe" unsafe = No.unsafe) if (unsafe || isBitFlagEnum!(E))
{
@safe @nogc pure nothrow:
private:
    enum isBaseEnumType(T) = is(E == T);
    alias Base = OriginalType!E;
    Base mValue;
    static struct Negation
    {
    @safe @nogc pure nothrow:
    private:
        Base mValue;

        // Prevent non-copy construction outside the module.
        @disable this();
        this(Base value)
        {
            mValue = value;
        }
    }

public:
    this(E flag)
    {
        this = flag;
    }

    this(T...)(T flags)
        if (allSatisfy!(isBaseEnumType, T))
    {
        this = flags;
    }

    bool opCast(B: bool)() const
    {
        return mValue != 0;
    }

    Base opCast(B)() const
        if (isImplicitlyConvertible!(Base, B))
    {
        return mValue;
    }

    Negation opUnary(string op)() const
        if (op == "~")
    {
        return Negation(~mValue);
    }

    auto ref opAssign(T...)(T flags)
        if (allSatisfy!(isBaseEnumType, T))
    {
        mValue = 0;
        foreach (E flag; flags)
        {
            mValue |= flag;
        }
        return this;
    }

    auto ref opAssign(E flag)
    {
        mValue = flag;
        return this;
    }

    auto ref opOpAssign(string op: "|")(BitFlags flags)
    {
        mValue |= flags.mValue;
        return this;
    }

    auto ref opOpAssign(string op: "&")(BitFlags  flags)
    {
        mValue &= flags.mValue;
        return this;
    }

    auto ref opOpAssign(string op: "|")(E flag)
    {
        mValue |= flag;
        return this;
    }

    auto ref opOpAssign(string op: "&")(E flag)
    {
        mValue &= flag;
        return this;
    }

    auto ref opOpAssign(string op: "&")(Negation negatedFlags)
    {
        mValue &= negatedFlags.mValue;
        return this;
    }

    auto opBinary(string op)(BitFlags flags) const
        if (op == "|" || op == "&")
    {
        BitFlags result = this;
        result.opOpAssign!op(flags);
        return result;
    }

    auto opBinary(string op)(E flag) const
        if (op == "|" || op == "&")
    {
        BitFlags result = this;
        result.opOpAssign!op(flag);
        return result;
    }

    auto opBinary(string op: "&")(Negation negatedFlags) const
    {
        BitFlags result = this;
        result.opOpAssign!op(negatedFlags);
        return result;
    }

    auto opBinaryRight(string op)(E flag) const
        if (op == "|" || op == "&")
    {
        return opBinary!op(flag);
    }
}

/// BitFlags can be manipulated with the usual operators
@safe @nogc pure nothrow unittest
{
    // You can use such an enum with BitFlags straight away
    enum Enum
    {
        None,
        A = 1<<0,
        B = 1<<1,
        C = 1<<2
    }
    static assert(__traits(compiles, BitFlags!Enum));

    // You need to specify the $(D unsafe) parameter for enum with custom values
    enum UnsafeEnum
    {
        A,
        B,
        C,
        D = B|C
    }
    static assert(!__traits(compiles, BitFlags!UnsafeEnum));
    static assert(__traits(compiles, BitFlags!(UnsafeEnum, Yes.unsafe)));

    immutable BitFlags!Enum flags_empty;
    // A default constructed BitFlags has no value set
    assert(!(flags_empty & Enum.A) && !(flags_empty & Enum.B) && !(flags_empty & Enum.C));

    // Value can be set with the | operator
    immutable BitFlags!Enum flags_A = flags_empty | Enum.A;

    // And tested with the & operator
    assert(flags_A & Enum.A);

    // Which commutes
    assert(Enum.A & flags_A);

    // BitFlags can be variadically initialized
    immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B);
    assert((flags_AB & Enum.A) && (flags_AB & Enum.B) && !(flags_AB & Enum.C));

    // Use the ~ operator for subtracting flags
    immutable BitFlags!Enum flags_B = flags_AB & ~BitFlags!Enum(Enum.A);
    assert(!(flags_B & Enum.A) && (flags_B & Enum.B) && !(flags_B & Enum.C));

    // You can use the EnumMembers template to set all flags
    immutable BitFlags!Enum flags_all = EnumMembers!Enum;

    // use & between BitFlags for intersection
    immutable BitFlags!Enum flags_BC = BitFlags!Enum(Enum.B, Enum.C);
    assert (flags_B == (flags_BC & flags_AB));

    // All the binary operators work in their assignment version
    BitFlags!Enum temp = flags_empty;
    temp |= flags_AB;
    assert(temp == (flags_empty | flags_AB));
    temp = flags_empty;
    temp |= Enum.B;
    assert(temp == (flags_empty | Enum.B));
    temp = flags_empty;
    temp &= flags_AB;
    assert(temp == (flags_empty & flags_AB));
    temp = flags_empty;
    temp &= Enum.A;
    assert(temp == (flags_empty & Enum.A));

    // BitFlags with no value set evaluate to false
    assert(!flags_empty);

    // BitFlags with at least one value set evaluate to true
    assert(flags_A);

    // This can be useful to check intersection between BitFlags
    assert(flags_A & flags_AB);
    assert(flags_AB & Enum.A);

    // Finally, you can of course get you raw value out of flags
    auto value = cast(int)flags_A;
    assert(value == Enum.A);
}
