...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

stdex.bind (3) - dmd 2.018

次は型の調整に挑戦してみるよー.

http://d.hatena.ne.jp/haru-s/20080707/1215425417

ということで,時間ができたのでやりました.
フルスクラッチD言語用bindがここまで動いたよ!

import std.stdio;
import stdex.bind;

T[] removeIf(alias cond, T)(T[] arr)
{
    T[] ret;
    foreach (v; arr)
        if (!cond(v)) ret ~= v;
    return ret;
}

void main()
{
    int[] arr = [1,2,3,4,5,6,7,8,9];
    auto less = (int i, int j){return i<j;};
    auto lessThan6 = bindAlias!(less)(_0, 6);
    auto greaterThan5 = bindAlias!(less)(5, _0);
    writefln(removeIf!(lessThan6)(arr));
    writefln(removeIf!(greaterThan5)(arr));
    
    static int sub(int a, int b){return a-b;};
    auto a = bindAlias!(sub)(_0, _1);
    auto b = bindAlias!(sub)(_1, _0);
    auto c = bindAlias!(sub)(_0, 5);
    auto d = bindAlias!(sub)(10, _0);
    auto e = bindAlias!(sub)(10, 5);
    auto f = bindAlias!(sub)(_0, _0);
    writefln(a(10,5)); // 5
    writefln(b(10,5)); // -5
    writefln(c(10)); // 5
    writefln(d(5)); // 5
    writefln(e()); // 5
    writefln(f(10)); // 0
    
    // 型の調整(new!)
    auto n = (int x, long y){return x*y;};
    auto m = (int x, double y){return x*y;};
    writefln(bindAlias!(n)(_0,_0)(3));//9; opCall(long)を作って呼ぶ
    writefln(bindAlias!(m)(_0,_0)(4));//16; opCall(int)を作って呼ぶ
    //writefln(bindAlias!(m)(_0,_0)(4.0));//opCall(int)にはdoubleを渡せずエラー
    
    //////////////////////////////////////////////
    // 現在の制限
    //
    
    /+ // out/ref引数は扱えない
    auto f = (ref int a){a = 1;};
    int x = 2;
    f(x);
    writefln(x); // 2
    x = 3;
    auto fx = bindAlias!(f)(&x);
    fx();
    writefln(x); // 3
    +/
    
    /+ // 関数合成はできない
    auto g = (int x, int y){return x*y;}; // g(x, y) = x * y
    auto h = (int x){return 2*x;};  // h(x) = 2 * x
    auto gh = bindAlias!(h)( bindAlias!(g)(_0, 3) );
        // h(g(x, 3)) = h(x * 3) == 2 * (x * 3)
    writefln(gh(5)); // 30
    +/
}

相変わらず同じようなコードが氾濫してるstdex.bindは続きをどうぞ.

module stdex.bind;

import std.traits;
import std.typetuple;

struct DynArg(int i){static invariant uint id = i;}
DynArg!(0) _0;
DynArg!(1) _1;
DynArg!(2) _2;
DynArg!(3) _3;
DynArg!(4) _4;
DynArg!(5) _5;
DynArg!(6) _6;
DynArg!(7) _7;
DynArg!(8) _8;
DynArg!(9) _9;

//TLの中にTがいくつあるか
template numType(T, TL...)
{
    template loop(int i, TList...)
    {
        alias Erase!(T, TList) ErasedTL;
        static if (is(ErasedTL == TList))
            alias i pre;
        else
            alias loop!(i+1, ErasedTL).pre pre;
    }
    enum numType = loop!(0,TL).pre;
}

//TLの中のTがあるすべてのインデックス番号を得る
template AllIndexesOf(T, TL...)
{
    template loop(int i, IndexList...)
    {
        enum index = indexOf!(T, TL[i..$]);
        static if (index == -1)
            alias IndexList pre; //もうない
        else
            alias loop!(i+index+1, TypeTuple!(IndexList, i+index)).pre pre; //あった
    }
    alias loop!(0).pre AllIndexesOf;
}

template NewParameterTuple(alias func, TL...)
{
    // 生関数の引数
    alias ParameterTypeTuple!(func) FuncParams;
    //pragma(msg, Params[indexDyn0]);
    //pragma(msg, Params[0]);
    //pragma(msg, Params[1]);
    
    // DynArgが使われているパラメータの共通の型を得る
    mixin DynArgNType!(0) DynArg0Type;
    //pragma(msg, DynArg0Type.result);
    mixin DynArgNType!(1) DynArg1Type;
    //pragma(msg, DynArg1Type.result);
    mixin DynArgNType!(2) DynArg2Type;
    mixin DynArgNType!(3) DynArg3Type;
    mixin DynArgNType!(4) DynArg4Type;
    mixin DynArgNType!(5) DynArg5Type;
    mixin DynArgNType!(6) DynArg6Type;
    mixin DynArgNType!(7) DynArg7Type;
    mixin DynArgNType!(8) DynArg8Type;
    mixin DynArgNType!(9) DynArg9Type;

    alias ReplaceAll!(DynArg!(0), DynArg0Type.result, TL) T0;
    alias ReplaceAll!(DynArg!(1), DynArg1Type.result, T0) T1;
    alias ReplaceAll!(DynArg!(2), DynArg2Type.result, T1) T2;
    alias ReplaceAll!(DynArg!(3), DynArg3Type.result, T2) T3;
    alias ReplaceAll!(DynArg!(4), DynArg4Type.result, T3) T4;
    alias ReplaceAll!(DynArg!(5), DynArg5Type.result, T4) T5;
    alias ReplaceAll!(DynArg!(6), DynArg6Type.result, T5) T6;
    alias ReplaceAll!(DynArg!(7), DynArg7Type.result, T6) T7;
    alias ReplaceAll!(DynArg!(8), DynArg8Type.result, T7) T8;
    alias ReplaceAll!(DynArg!(9), DynArg9Type.result, T8) T9;
    alias T9 Params;
    //pragma(msg, Params);
    
    // 引数リストの何番目に(最初の)DynArgがあるか
    enum indexDyn0 = indexOf!(DynArg!(0),TL);
    enum indexDyn1 = indexOf!(DynArg!(1),TL);
    enum indexDyn2 = indexOf!(DynArg!(2),TL);
    enum indexDyn3 = indexOf!(DynArg!(3),TL);
    enum indexDyn4 = indexOf!(DynArg!(4),TL);
    enum indexDyn5 = indexOf!(DynArg!(5),TL);
    enum indexDyn6 = indexOf!(DynArg!(6),TL);
    enum indexDyn7 = indexOf!(DynArg!(7),TL);
    enum indexDyn8 = indexOf!(DynArg!(8),TL);
    enum indexDyn9 = indexOf!(DynArg!(9),TL);
    
    // DynArgを使っている部分に対応するfuncの引数の型だけを得る
    static if (indexDyn0 == -1)
        alias void NewParams;
    else static if (indexDyn1 == -1)
        alias TypeTuple!(Params[indexDyn0]) NewParams;
    else static if (indexDyn2 == -1)
        alias TypeTuple!(Params[indexDyn0], Params[indexDyn1]) NewParams;
    else static if (indexDyn3 == -1)
        alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2]) NewParams;
    else static if (indexDyn4 == -1)
        alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3]) NewParams;
    else static if (indexDyn5 == -1)
        alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4]) NewParams;
    else static if (indexDyn6 == -1)
        alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4], Params[indexDyn5]) NewParams;
    else static if (indexDyn7 == -1)
        alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4], Params[indexDyn5], Params[indexDyn6]) NewParams;
    else static if (indexDyn8 == -1)
        alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4], Params[indexDyn5], Params[indexDyn6], Params[indexDyn7]) NewParams;
    else static if (indexDyn9 == -1)
        alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4], Params[indexDyn5], Params[indexDyn6], Params[indexDyn7], Params[indexDyn8]) NewParams;
    else
        alias TypeTuple!(Params[indexDyn0], Params[indexDyn1], Params[indexDyn2], Params[indexDyn3], Params[indexDyn4], Params[indexDyn5], Params[indexDyn6], Params[indexDyn7], Params[indexDyn8], Params[indexDyn9]) NewParams;
    //
    //pragma(msg, NewParams);
    //pragma(msg,numType!(int, TL).numType); // 2
    //pragma(msg,AllIndexesOf!(int, TL).AllIndexesOf); // (1, 3)
}

template DynArgNType(int N)
{
    alias AllIndexesOf!(DynArg!(N),TL).AllIndexesOf indexesDynN;
    enum len = indexesDynN.length;
    alias Sort!(len, indexesDynN, FuncParams).result[0] result;
}

template Sort(int lenIndexes, TL...)
{
    alias TL[0..lenIndexes] indexes;
    alias TL[lenIndexes..$] Params;
    //pragma(msg, indexes);
    //pragma(msg, indexes.length);
    //pragma(msg, Params);
    
    static if (indexes.length == 0)
        alias void result;
    else static if (indexes.length == 1)
        alias DerivedToFront!(Params[indexes[0]]) result;
    else static if (indexes.length == 2)
        alias DerivedToFront!(Params[indexes[0]], Params[indexes[1]]) result;
    else static if (indexes.length == 3)
        alias DerivedToFront!(Params[indexes[0]], Params[indexes[1]], Params[indexes[2]]) result;
    else static if (indexes.length == 4)
        alias DerivedToFront!(Params[indexes[0]], Params[indexes[1]], Params[indexes[2]], Params[indexes[3]]) result;
    else static if (indexes.length == 5)
        alias DerivedToFront!(Params[indexes[0]], Params[indexes[1]], Params[indexes[2]], Params[indexes[3]], Params[indexes[4]]) result;
    else static if (indexes.length == 6)
        alias DerivedToFront!(Params[indexes[0]], Params[indexes[1]], Params[indexes[2]], Params[indexes[3]], Params[indexes[4]], Params[indexes[5]]) result;
    else static if (indexes.length == 7)
        alias DerivedToFront!(Params[indexes[0]], Params[indexes[1]], Params[indexes[2]], Params[indexes[3]], Params[indexes[4]], Params[indexes[5]], Params[indexes[6]]) result;
    else static if (indexes.length == 8)
        alias DerivedToFront!(Params[indexes[0]], Params[indexes[1]], Params[indexes[2]], Params[indexes[3]], Params[indexes[4]], Params[indexes[5]], Params[indexes[6]], Params[indexes[7]]) result;
    else static if (indexes.length == 9)
        alias DerivedToFront!(Params[indexes[0]], Params[indexes[1]], Params[indexes[2]], Params[indexes[3]], Params[indexes[4]], Params[indexes[5]], Params[indexes[6]], Params[indexes[7]], Params[indexes[8]]) result;
    else static if (indexes.length == 10)
        alias DerivedToFront!(Params[indexes[0]], Params[indexes[1]], Params[indexes[2]], Params[indexes[3]], Params[indexes[4]], Params[indexes[5]], Params[indexes[6]], Params[indexes[7]], Params[indexes[8]], Params[indexes[9]]) result;
    else
        static assert(false);
}

class BoundFunc(alias func, TL...)
{
    alias ReturnType!(func) RetValue;
    alias NewParameterTuple!(func, TL).NewParams NewParams;
    //pragma(msg,TL);
    //pragma(msg,RetValue);
    //pragma(msg,Params);

    TL args;
    this(TL args)
    {
        this.args = args;
    }
    
    static if (is(NewParams == void))
    {
        RetValue opCall()
        {
            return func(args);
        }
    }
    else
    {
        RetValue opCall(NewParams params)
        {
            static if (0 < TL.length)
            {
                static if (isDynArg!(TL[0]))
                    enum Arg0 = params[TL[0].id];
                else
                    enum Arg0 = args[0];
                //pragma(msg,typeof(args)[0].id);
                //pragma(msg,NewParameterTuple!(func, TL).indexDyn0);
            }
            static if (1 < TL.length)
            {
                static if (isDynArg!(TL[1]))
                    enum Arg1 = params[TL[1].id];
                else
                    enum Arg1 = args[1];
                //pragma(msg,typeof(args)[0].id);
                //pragma(msg,typeof(args)[1].id);
                //pragma(msg,Arg0);
                //pragma(msg,Arg1);
                //pragma(msg,NewParameterTuple!(func, TL).indexDyn1);
            }
            static if (2 < TL.length)
            {
                static if (isDynArg!(TL[2]))
                    enum Arg2 = params[TL[2].id];
                else
                    enum Arg2 = args[2];
            }
            static if (3 < TL.length)
            {
                static if (isDynArg!(TL[3]))
                    enum Arg3 = params[TL[3].id];
                else
                    enum Arg3 = args[3];
            }
            static if (4 < TL.length)
            {
                static if (isDynArg!(TL[4]))
                    enum Arg4 = params[TL[4].id];
                else
                    enum Arg4 = args[4];
            }
            static if (5 < TL.length)
            {
                static if (isDynArg!(TL[5]))
                    enum Arg5 = params[TL[5].id];
                else
                    enum Arg5 = args[5];
            }
            static if (6 < TL.length)
            {
                static if (isDynArg!(TL[6]))
                    enum Arg6 = params[TL[6].id];
                else
                    enum Arg6 = args[6];
            }
            static if (7 < TL.length)
            {
                static if (isDynArg!(TL[7]))
                    enum Arg7 = params[TL[7].id];
                else
                    enum Arg7 = args[7];
            }
            static if (8 < TL.length)
            {
                static if (isDynArg!(TL[8]))
                    enum Arg8 = params[TL[8].id];
                else
                    enum Arg8 = args[8];
            }
            static if (9 < TL.length)
            {
                static if (isDynArg!(TL[9]))
                    enum Arg9 = params[TL[9].id];
                else
                    enum Arg9 = args[9];
            }
            
            static if (TL.length == 1)
                return func(Arg0);
            else static if (TL.length == 2)
                return func(Arg0, Arg1);
            else static if (TL.length == 3)
                return func(Arg0, Arg1, Arg2, Arg3);
            else static if (TL.length == 4)
                return func(Arg0, Arg1, Arg2, Arg3, Arg4);
            else static if (TL.length == 5)
                return func(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5);
            else static if (TL.length == 6)
                return func(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6);
            else static if (TL.length == 7)
                return func(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7);
            else static if (TL.length == 8)
                return func(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8);
            else static if (TL.length == 9)
                return func(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9);
            else
                static assert(false);// 生関数の引数が多すぎます
        }
    }
}

template isDynArg(T)
{
    static if (is(T == DynArg!(0)) || is(T == DynArg!(1)) || is(T == DynArg!(2)) ||
        is(T == DynArg!(3)) || is(T == DynArg!(4)) || is(T == DynArg!(5)) ||
        is(T == DynArg!(6)) || is(T == DynArg!(7)) || is(T == DynArg!(8)) || is(T == DynArg!(9)))
    {
        enum isDynArg = true;
    }
    else
    {
        enum isDynArg = false;
    }
}

template bindAlias(alias func)
{
    BoundFunc!(func, TL) bindAlias(TL...)(TL args)
    {
        return new BoundFunc!(func, TL)(args);
    }
}