diff --git a/std/algorithm/package.d b/std/algorithm/package.d index 811c9cdb5..0ba523606 100644 --- a/std/algorithm/package.d +++ b/std/algorithm/package.d @@ -183,115 +183,6 @@ public import std.algorithm.setops; public import std.algorithm.searching; public import std.algorithm.sorting; -// FIXME -import std.functional; // : unaryFun, binaryFun; -import std.range.primitives; -// FIXME -import std.range; // : SortedRange; -import std.traits; -// FIXME -import std.typecons; // : tuple, Tuple; -// FIXME -import std.typetuple; // : TypeTuple, staticMap, allSatisfy, anySatisfy; - -version(unittest) debug(std_algorithm) import std.stdio; - -/** -Forwards function arguments with saving ref-ness. -*/ -template forward(args...) -{ - import std.typetuple; - - static if (args.length) - { - alias arg = args[0]; - static if (__traits(isRef, arg)) - alias fwd = arg; - else - @property fwd()(){ return move(arg); } - alias forward = TypeTuple!(fwd, forward!(args[1..$])); - } - else - alias forward = TypeTuple!(); -} - -/// -@safe unittest -{ - class C - { - static int foo(int n) { return 1; } - static int foo(ref int n) { return 2; } - } - int bar()(auto ref int x) { return C.foo(forward!x); } - - assert(bar(1) == 1); - int i; - assert(bar(i) == 2); -} - -/// -@safe unittest -{ - void foo(int n, ref string s) { s = null; foreach (i; 0..n) s ~= "Hello"; } - - // forwards all arguments which are bound to parameter tuple - void bar(Args...)(auto ref Args args) { return foo(forward!args); } - - // forwards all arguments with swapping order - void baz(Args...)(auto ref Args args) { return foo(forward!args[$/2..$], forward!args[0..$/2]); } - - string s; - bar(1, s); - assert(s == "Hello"); - baz(s, 2); - assert(s == "HelloHello"); -} - -@safe unittest -{ - auto foo(TL...)(auto ref TL args) - { - string result = ""; - foreach (i, _; args) - { - //pragma(msg, "[",i,"] ", __traits(isRef, args[i]) ? "L" : "R"); - result ~= __traits(isRef, args[i]) ? "L" : "R"; - } - return result; - } - - string bar(TL...)(auto ref TL args) - { - return foo(forward!args); - } - string baz(TL...)(auto ref TL args) - { - int x; - return foo(forward!args[3], forward!args[2], 1, forward!args[1], forward!args[0], x); - } - - struct S {} - S makeS(){ return S(); } - int n; - string s; - assert(bar(S(), makeS(), n, s) == "RRLL"); - assert(baz(S(), makeS(), n, s) == "LLRRRL"); -} - -@safe unittest -{ - ref int foo(return ref int a) { return a; } - ref int bar(Args)(auto ref Args args) - { - return foo(forward!args); - } - static assert(!__traits(compiles, { auto x1 = bar(3); })); // case of NG - int value = 3; - auto x2 = bar(value); // case of OK -} - /** Specifies whether the output of certain algorithm is desired in sorted format. diff --git a/std/functional.d b/std/functional.d index fbc4d97bd..15dba17b3 100644 --- a/std/functional.d +++ b/std/functional.d @@ -1359,3 +1359,102 @@ unittest { static assert(! is(typeof(dg_xtrnC) == typeof(dg_xtrnD))); } } + +/** +Forwards function arguments with saving ref-ness. +*/ +template forward(args...) +{ + import std.typetuple; + + static if (args.length) + { + import std.algorithm.mutation : move; + + alias arg = args[0]; + static if (__traits(isRef, arg)) + alias fwd = arg; + else + @property fwd()(){ return move(arg); } + alias forward = TypeTuple!(fwd, forward!(args[1..$])); + } + else + alias forward = TypeTuple!(); +} + +/// +@safe unittest +{ + class C + { + static int foo(int n) { return 1; } + static int foo(ref int n) { return 2; } + } + int bar()(auto ref int x) { return C.foo(forward!x); } + + assert(bar(1) == 1); + int i; + assert(bar(i) == 2); +} + +/// +@safe unittest +{ + void foo(int n, ref string s) { s = null; foreach (i; 0..n) s ~= "Hello"; } + + // forwards all arguments which are bound to parameter tuple + void bar(Args...)(auto ref Args args) { return foo(forward!args); } + + // forwards all arguments with swapping order + void baz(Args...)(auto ref Args args) { return foo(forward!args[$/2..$], forward!args[0..$/2]); } + + string s; + bar(1, s); + assert(s == "Hello"); + baz(s, 2); + assert(s == "HelloHello"); +} + +@safe unittest +{ + auto foo(TL...)(auto ref TL args) + { + string result = ""; + foreach (i, _; args) + { + //pragma(msg, "[",i,"] ", __traits(isRef, args[i]) ? "L" : "R"); + result ~= __traits(isRef, args[i]) ? "L" : "R"; + } + return result; + } + + string bar(TL...)(auto ref TL args) + { + return foo(forward!args); + } + string baz(TL...)(auto ref TL args) + { + int x; + return foo(forward!args[3], forward!args[2], 1, forward!args[1], forward!args[0], x); + } + + struct S {} + S makeS(){ return S(); } + int n; + string s; + assert(bar(S(), makeS(), n, s) == "RRLL"); + assert(baz(S(), makeS(), n, s) == "LLRRRL"); +} + +@safe unittest +{ + ref int foo(return ref int a) { return a; } + ref int bar(Args)(auto ref Args args) + { + return foo(forward!args); + } + static assert(!__traits(compiles, { auto x1 = bar(3); })); // case of NG + int value = 3; + auto x2 = bar(value); // case of OK +} +