dranges.rangeについて-その1-

前回のdranges.algorithmの続きとして、dranges.rangeについて書きます。
ただ、めちゃくちゃ長いので2回くらいに分けます。
今回はその1番目です。
drangesについては[dranges.algorithm](http://qiita.com/items/080b4bbf7a794d4ace3c)を見てください。
ちなみにdrangesについてはすべてのunittestがコンパイルできるようになり、
かつ、unittestもすべて通るようになりました。


###dranges.range.minLength

```d
size_t minLength(R...)(R ranges) if (allSatisfy!(isForwardRange, R) && allHaveLength!R && !allAreInfinite!R)
```

受け取ったレンジの最小の長さを返します。受け取るレンジはすべて前進レンジで、長さを持っているか無限レンジである必要があります。

```d
auto s = ["a", "b", "c", "d", "e", "f"];
int[] r = [0, 1, 2, 3];
auto c = repeat(5); //無限

auto ml = minLength(s, r, c);
assert(ml == 4);    //rの長さ
```


###dranges.range.slice

```d
Take!R slice(R)(R range, int begin, int end)
```

hasSlicing!Rがtrueでないものに対してもスライスするための関数です。

###dranges.range.dropLast

```d
R dropLast(R)(R range, size_t n) if (isBidirectionalRange!R)
```

双方向レンジを受け取り、レンジの後からn要素をけしたレンジを返します。

```d
auto r1 = [0, 1, 2, 3, 4, 5];
auto d = dropLast(r1, 3);

assert(equal(d, [0,1,2][]));
assert(equal(dropLast(r1, 0), r1));
assert(dropLast(r1, 6).empty);
assert(dropLast(r1, 100).empty);
```


###dranges.range.templateFunctionAnalysis

```d
template templateFunctionAnalysis(alias templateFun, alias ParameterGenerator, size_t startN = 0, size_t limittedN = 10){
    enum endN;
    alias ... ArgumentTypes;
    enum arity;
    alias ... ReturnType;
}
```

このテンプレートは私が作ったものですが、そのうちdranges.traitsにいれようかと思います。
各パラメータを説明すると、
・templateFun : 解析したいテンプレート関数
・ParameterGenerator : [startN ~ limittedN]までの非負の整数を取り、templateFunの引数の型を生成するテンプレート
・startN : ParameterGeneratorを最初にインスタンス化する数
・limittedN : ParameterGeneratorをインスタンス化する場合の最終の数
となります。このとき、次のコードがコンパイル可能になるまでNをstartNからlimittedNまで増加させていきます。

```d
templateFun(ParameterGenerator!(N).init)
```

使い方の例を挙げてくと、

```d
template Generator(size_t N){alias TypeNuple!(int, N) Generator;}

alias templateFunctionAnalysis!(( (a, b, c) => a) , Generator) Result0;

static assert(Result0.arity == 3);
static assert(Result0.endN == 3);
static assert(is(Result0.ArgumentTypes == Generator!3));
static assert(is(Result0.ReturnType == int));
```

というようになります。
このテンプレートは、特殊な場面で使われ、naryFun!"a+b+c"などの引数の数を解析したりするのに使います。


###dranges.range.dropWhile

```d
template dropWhile(alias pred, size_t step = 1){
    template dropWhile(R, T...)if(isForwardRange!R){
        R dropWhile(R r, auto ref T subParam)
    }
}
```

predがtrueの間だけ要素を削除したレンジを返します。stepは1回に進める量です。
predは0以上の引数の個数に対応します。

```d
string s = "  , abcd  efg";
auto d1 = dropWhile!(isOneOf!" ,")(s);  //' ' か ','をスキップ
assert(d1 == "abcd  efg");

auto r1 = [0, 1, 2, 3, 3, 4, 5];
auto d2 = dropWhile!"a<4"(r1);          //4未満の要素をスキップ
assert(equal(d2, [4, 5]));

auto d3 = dropWhile!"a<b"(r1);          //増加している部分を削除
assert(equal(d3, [3, 3, 4, 5]));        //(3,3)は増加していない

auto d4 = dropWhile!("a<b",2)(r1);      //[(0, 1),(2, 3),(3, 4)]
assert(equal(d4, [5]));                 //"a<b"を満たし消される

auto d5 = dropWhile!("a<b && b<c")(r1); //[(0, 1, 2), (1, 2, 3), (2, 3, 3), ...]
assert(equal(d5, [2, 3, 3, 4, 5]));     //(2, 3, 3)はpredを満たさない

auto d7 = dropWhile!"true"(r1);         //常にtrueなpred
assert(d7.empty);                       //もちろんempty

auto d7_d = dropWhile!("true", 2)(r1);  //stepが2でも
assert(d7_d.empty);                     //[5]が余るわけではない。
//[5]が余らない理由は、step=2でpredは0個の引数であるから、[0, 1, 2, 3, 3, 4, 5]の場合には
//[0, 2, 3, 5]が検査に使われ、すべての要素でtrueとなるから[5]まですべて消される。

auto r2 = [1];
auto d8 = dropWhile!"a<b"(r2);
//最初から1要素しかないのにbinary関数である場合には、そもそもpredを呼べないので検査できない
assert(equal(d8, [1][]));

auto d9 = dropWhile!"a < b"(r1, 4);     //bには4が入る。よってレンジからは1つずつ検査されていく
assert(equal(d9, [4, 5]));              //a < 4を満たす間drop

auto d10 = dropWhile!"a == b-c"(r1, 1); //cには1が入るため a == b-1が満たされるまでdrop
assert(equal(d10, [3, 3, 4, 5]));

auto d12 = dropWhile!((a, b, c) => a < b, 2)(r1, 1);
//実際にはcに1が入るが、検査にはa,bしか関わっておらず、これはd4と同じ結果[5]となる
assert(equal(d12, [5][]));

size_t cnt;
bool counter(){return cnt++ < 3;}       //0引数で3回目まではtrue

auto d16 = dropWhile!(counter)(r1);
assert(equal(d16, [3, 3, 4, 5]));       //3回目までtrueなので最初の3要素がなくなる
```


###dranges.range.popFrontWhile

```d
template popFrontWhile(alias pred, size_t step = 1){
    template popFrontWhile(R, T...){
        size_t popFrontWhile(ref R r, T subArgs)
    }
}
```

dropWhileのpopFrontバージョンです。


###dranges.range.takeWhile

```d
template takeWhile(alias pred){
    template takeWhile(R, T...)if(isForwardRange!R){
        TakeWhile takeWhile(R range, T args)
    }
}
```

dropWhileやpopFrontWhileのtakeバージョンです。


###dranges.range.takeUntil
###dranges.range.rotateWhile

実装されてない…？


###dranges.range.tail

```d
R tail(R)(R range) if (isInputRange!R)
```

Haskellのtailと同じです。が、emptyな場合にはそのまま返します。
Haskellの場合は空リストを渡すと例外が出るはずです。


###dranges.range.tails

```d
Tails!R tails(R)(R range) if (isForwardRange!R)
```

Haskellのtailsとすこし違いますが、ほとんど同じです。

```d
auto r = [0,1,2,3];
auto t = tails(r);
assert(equal(t, [[1,2,3], [2,3], [3], [] ]));
```


###dranges.range.heads

```d
Heads!R heads(R)(R range) if (isForwardRange!R)
```

tailsのheadバージョンです。

```d
auto r = [0,1,2,3];
auto h = heads(r);
auto witness = [ [], [0], [0,1], [0,1,2], [0,1,2,3] ][];
foreach(elem; h) {
    assert(equal(elem, witness.front));
    witness.popFront;
}
```


###dranges.range.insertAt

```d
auto insertAt(R1, R2)(size_t n, R1 range1, R2 range2) if (allSatisfy!(isForwardRange, R1, R2))
//または
auto insertAt(R, E)(size_t n, R range, E element) if (isForwardRange!R && is(ElementType!R == E))
```

次を返します。

```d
return chain(take(range1, n), range2, drop(range1, n));
//または
return chain(take(range, n), [element][], drop(range, n));
```

例として、

```d
auto r1 = [0,1,2,3];
auto m = map!"a*a"(r1);
auto ia0 = insertAt(0, r1, m);
auto ia2 = insertAt(2, r1, m);
auto ia10 = insertAt(10, r1, m);
assert(equal(ia0, [0,1,4,9,  0,1,2,3][]));
assert(equal(ia2, [0,1,  0,1,4,9,  2,3][]));
assert(equal(ia10,[0,1,2,3,  0,1,4,9][]));

auto ia1 = insertAt(1, r1, 99);
assert(equal(ia1, [0,99,1,2,3][]));
```


###dranges.range.cutAt

```d
Tuple!(R, R) cutAt(R)(size_t index, R range) if (isForwardRange!R && hasSlicing!R && hasLength!R)
Tuple!(ElementType!R[], R) cutAt(R)(size_t index, R range) if (isForwardRange!R && (!hasSlicing!(R) || !hasLength!(R)))
```

[0, index)までの要素(index個)を返り値の最初の要素に、残りを2番目に格納したものを返します。

```d
auto r1 = [0,1,2,3,4,5];
auto c1 = cutAt(3, r1);
assert(first(c1) == [0,1,2][]);
assert(second(c1) == [3,4,5][]);
```


###dranges.range.cutWhen

```d
Tuple!(ElementType!(R)[], R) cutWhen(alias pred, R)(R range) if (isForwardRange!R)
```

predはunary関数です。
predがtrueな間だけのものを集めたのを先頭要素に、のこりを次の要素に入れ込みます。

```d
auto r1 = [0, 1, 2, 3, 4, 1, 2];
auto cut = cutWhen!"a<3"(r1);
assert(equal(cut.field[0], [0, 1, 2]));
assert(equal(cut.field[1], [3, 4]));
```


###dranges.range.knit

```d
Knit!(R) knit(R...)(R ranges) if (allSatisfy!(isInputRange, R))
```

std.range.zipの弱いバージョンです。std.range.zipのほうがいいので、deprecatedになってもいいと思う。


###dranges.range.stitch

```d
StitchType!R stitch(R...)(R ranges) if (allSatisfy!(isTupleRange, R))
```

要素がtupleなレンジを複数個受け取り、tuple(a.field, b.field, ...)としたようなレンジを返します。

```d
auto r1 = [0,     1,     2,   3,   4,   5];
auto r2 = [0.1,   0.2,   0.3, 0.4];
auto r3 = ["abc", "def", "",  "g"];
auto r4 = ["a",   "b",   "c", "d", "e", "f"];

auto k1 = knit(r1, r2); // returns Tuple!(int, double)
auto k2 = knit(r3,r4);  // returns Tuple!(string, char)
auto tf = tfilter!"b<2"(r3,r1); // returns Tuple!(string, int)

auto s = stitch(k1,k2,tf); // returns Tuple!(int,double,string,char,string,int)

assert(s.front == tuple(0, 0.1, "abc", "a", "abc", 0));
s.popFront;
assert(s.front == tuple(1, 0.2, "def", "b", "def", 1));
s.popFront;
assert(s.empty); //tfがemptyとなる。
```


###dranges.range.twist

```d
auto twist(int n, R)(R range) if (isTupleRange!R)
```

要素がtupleなレンジを受け取り、左方向にn要素回したようなレンジを返します。

```d
auto r1 = [0,    1,    2,    3, 4];
auto r2 = [3.14, 2.78, 1.414];
auto s =  ["a",  "b",  "c",  "d","e","f"];

auto k = knit(r1,r2,s);
assert(is(ElementType!(typeof(k)) == Tuple!(int,double,string)));
assert(equal(k, [tuple(0,3.14,"a"), tuple(1,2.78,"b"), tuple(2,1.414,"c")][]));

auto rot1 = twist!1(k);
assert(is(ElementType!(typeof(rot1)) == Tuple!(double,string,int)));
assert(equal(rot1, [tuple(3.14,"a",0), tuple(2.78,"b",1), tuple(1.414,"c",2)][]));

auto rot_1 = twist!(-1)(k);
assert(is(ElementType!(typeof(rot_1)) == Tuple!(string,int,double)));
assert(equal(rot_1, [tuple("a",0,3.14), tuple("b",1,2.78), tuple("c",2,1.414)][]));
```


###dranges.range.reverse

```d
auto reverse(R)(R range) if (isTupleRange!R)
```

要素がtupleなレンジを受け取り、その順序を逆転させます。
つまり、tuple(a[n-1], a[n-2], ..., a[1], a[0])を作ります。

```d
auto r1 = [0,    1,    2,3,  4];
auto r2 = [3.14, 2.78, 1.414];
auto s =  ["a",  "b",  "c",  "d", "e", "f"];

auto k = knit(r1, r2, s);
assert(is(ElementType!(typeof(k)) == Tuple!(int,double,string)));
assert(equal(k, [tuple(0, 3.14, "a"), tuple(1, 2.78, "b"), tuple(2, 1.414, "c")]));

auto rev = reverse(k);
assert(is(ElementType!(typeof(rev)) == Tuple!(string,double,int)));
assert(equal(rev, [tuple("a", 3.14, 0), tuple("b", 2.78, 1), tuple("c", 1.414, 2)]));
```


###dranges.range.splice

```d
auto splice(size_t n, R1, R2)(R1 range1, R2 range2)
if (allSatisfy!(isForwardRange, R1, R2) && is(ElementType!R1.Types) && (n <= ElementType!R1.Types.length))
```

range1は要素がtupleなレンジでなくてはいけず、
range1のn要素にrange2を割り込ませます。

```d
auto r1 = [0,  1,  2,  3,  4];
auto s =  ["a","b","c","d","e","f"];
auto k = knit(r1, s);

auto r2 = [-2.1, 0.0, 3.14];

auto spl = splice!1(k, r2);     //tuple(k.front[0], r2.front, k.front[1])
assert(is(ElementType!(typeof(spl)) == Tuple!(int, double, string)));
assert(equal(spl, [tuple(0, -2.1, "a"), tuple(1, 0.0, "b"), tuple(2, 3.14, "c")]));

auto spl2 = splice!0(spl,k);    //tuple(k.front, spl.front[0], spl.front[1])
assert(is(ElementType!(typeof(spl2)) == Tuple!(Tuple!(int,string), int,double,string))); 
assert(equal(spl2, [tuple(tuple(0, "a"), 0, -2.1, "a"), tuple(tuple(1, "b"), 1, 0.0, "b"), tuple(tuple(2,"c"),2, 3.14, "c")]));
```


###dranges.range.shred

```d
template shred(idx...){
    auto shred(R)(R range)if(isTupleRange!R)
}
```

要素がtupleなレンジを受け取って、idxの順番に並べ替えます。

```d
auto r1 = [0,    1,    2,    3,    4];
auto r2 = [3.14, 2.78, 1.414];
auto s =  ["a",  "b",  "c",  "d", "e", "f"];

auto k = knit(r1, r2, s);
auto shr1 = shred!(1,0)(k); //反転
assert(equal(shr1, [tuple(3.14, 0), tuple(2.78, 1), tuple(1.414, 2)]));

auto shr2 = shred!(1)(k); //e[1]のみを取得
assert(equal(shr2, [3.14, 2.78, 1.414]));

auto shr3 = shred!(2,0,1,1)(k); //重複もOK
assert(equal(shr3, [tuple("a", 0, 3.14, 3.14),
                    tuple("b", 1, 2.78, 2.78),
                    tuple("c", 2, 1.414, 1.414)]));
```


###dranges.range.untuplify

```d
TMapType!("a", R) untuplify(R)(R range) if (isTupleRange!R && ElementType!R.Types.length == 1)
```

要素が1要素からなるtupleなレンジを受け取って、tupleでなくします。

```d
auto r1 = [0,1,2,3,4];

auto k = knit(r1);      //Tuple!(int)
assert(equal(k, [tuple(0), tuple(1), tuple(2), tuple(3), tuple(4)]));
auto u = untuplify(k);  //int[]
assert(equal(u, r1));
```


###dranges.range.transverse

```d
Transverse!R transverse(R...)(R ranges)
```

複数のレンジを順番にたどっていきます。

```d
auto r1 = [0,1,2,3,4];
auto r2 = repeat(5);
auto r3 = [-2.0, -1.0, 0.0, 1.0];

auto t = transverse(r1, r2, r3);
assert(is(ElementType!(typeof(t)) == double));          //全要素はdoubleに暗黙変換される
assert(equal(t, [0.0, 5, -2, 1, 5, -1, 2, 5, 0, 3, 5, 1, 4, 5]));   //r3がemptyになり終わる

auto t2 = transverse(r1, emptyRange!double, emptyRange!short);
assert(is(ElementType!(typeof(t2)) == double));
assert(equal(t2, [0][]));   //emptyRange!doubleにより[0]だけで終わる
```


###dranges.range.interleave

```d
Transverse!(B,Cycle!S) interleave(B, S)(B bigRange, S smallRange)
```

bigRangeとsmallRangeを受け取り、
[b[0], s[0], b[1], s[1], ... , b[n], s[n % s.length]]
というようなレンジを返します。

```d
auto i = interleave("abcdef", ",");
assert(asString(i) == "a,b,c,d,e,f,");
auto i2 = interleave("abcdef", ",;.");
assert(asString(i2) == "a,b;c.d,e;f.");
auto r1 = [0, 1, 2, 3, 4];
auto i3 = interleave(r1, r1);
assert(equal(i3, [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]));
```


###dranges.range.segment

```d
template segment(size_t N : 1, Range)
if(isInputRange!(Unqual!Range))
{
    Segment segment(Range range)
}


template segment(size_t N, Range)
if (isInputRange!(Unqual!Range) 
&& (isForwardRange!(Unqual!Range) ? (!isBidirectionalRange!(Unqual!Range)
                                      && !isRandomAccessRange!(Unqual!Range)) : true))
{
    Segment segment(Range range)
}


template segment(size_t N, Range)
if(isRandomAccessRange!(Unqual!Range)
&& isBidirectionalRange!(Unqual!Range)
&& hasLength!(Unqual!Range))
{
    Segment segment(Range range)
}


template segment(size_t N, Range)
if(isRandomAccessRange!(Unqual!Range)
&& !isBidirectionalRange!(Unqual!Range)
&& isInfinite!(Unqual!Range))
{
    Segment segment(Range range)
}


template segment(size_t N, Range)
if(isBidirectionalRange!(Unqual!Range)
&& (isRandomAccessRange!(Unqual!Range) ? (!hasLength!(Unqual!Range) && isInfinite!(Unqual!Range)) : true))
{
    Segment segment(Range range)
}
```

segmentは、drangesの至る所で使われているレンジです。
重要であるにもかかわらず、実装が貧弱で、InputRangeにも対応していなかったために私が書き直しました。
簡単な例を示しましょう。

```d
int[] a = [0, 1, 2, 3, 4, 5];

auto s1 = segment!1(r1);
assert(equal(s1, [tuple(0), tuple(1), tuple(2), tuple(3), tuple(4), tuple(5)]));

auto s2 = segment!2(r1);
assert(equal(s2, [tuple(0, 1), tuple(1, 2), tuple(2, 3), tuple(3, 4), tuple(4, 5)]));

auto s3 = segment!3(r2);
assert(equal(s3, [tuple(0, 1, 2), tuple(1, 2, 3), tuple(2, 3, 4), tuple(3, 4, 5)]));

s3[1] = tuple(-1, -2, -3);
assert(equal(s3, [tuple(0, -1, -2), tuple(-1, -2, -3), tuple(-2, -3, 4), tuple(-3, 4, 5)]));
```


###dranges.range.delay

```d
template delay(alias array)if(isArray!(typeof(array)) && array.length != 0)
{
    auto delay(R)(R range)if(isInputRange!R)
}
```

delayはarrayが[[a, a, ...]](aは任意の非負の整数)の場合には、popFrontNと後に説明するparallelによって実装されています。
上記以外の場合にはsegmentとshredを用いています。
delayはsegmentに似ていますが、segmentとは少し違います。
返り値がtupleな要素なレンジであることは同じですが、
要素eのさらに要素であるe[i]はレンジrangeをpopFrontN(range, array[i])の要素となります。

```d
auto r1 = [0, 1, 2, 3, 4, 5];

auto d = delay!([4,1,3,2])(r1);
assert(d.front == tuple(4,1,3,2));
assert(d.length == 2);              //[(4,1,3,2), (5,2,4,3)]
```


###dranges.range.parallel

```d
auto parallel(size_t n, R)(R range)if(n > 0 && isInputRange!R)
```

parallelはレンジをn個並列にtupleに入れ込んだものを返します。

```d
auto r1 = [0, 1, 2, 3, 4, 5];
auto p = parallel!4(r1);
assert(equal(p, [tuple(0,0,0,0), tuple(1,1,1,1), tuple(2,2,2,2), tuple(3,3,3,3), tuple(4,4,4,4), tuple(5,5,5,5)][]));
```