From 0074d24c6a00ecfc840d697564184d0d1d203a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20=C3=87ehreli?= Date: Wed, 20 Dec 2017 22:14:40 -0800 Subject: [PATCH 1/8] Fix a couple of tuple links --- std/algorithm/iteration.d | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/std/algorithm/iteration.d b/std/algorithm/iteration.d index 658a345ac09..3a8d70def7c 100644 --- a/std/algorithm/iteration.d +++ b/std/algorithm/iteration.d @@ -2747,9 +2747,9 @@ Params: See_Also: $(HTTP en.wikipedia.org/wiki/Fold_(higher-order_function), Fold (higher-order function)) - $(LREF fold) is functionally equivalent to $(LREF _reduce) with the argument order reversed, - and without the need to use $(LREF tuple) for multiple seeds. This makes it easier - to use in UFCS chains. + $(LREF fold) is functionally equivalent to $(LREF _reduce) with the argument + order reversed, and without the need to use $(REF_ALTTEXT $(D tuple),tuple,std,typecons) + for multiple seeds. This makes it easier to use in UFCS chains. $(LREF sum) is similar to $(D reduce!((a, b) => a + b)) that offers pairwise summing of floating point numbers. @@ -3206,8 +3206,9 @@ See_Also: $(LREF sum) is similar to $(D fold!((a, b) => a + b)) that offers precise summing of floating point numbers. - This is functionally equivalent to $(LREF reduce) with the argument order reversed, - and without the need to use $(LREF tuple) for multiple seeds. + This is functionally equivalent to $(LREF reduce) with the argument order + reversed, and without the need to use $(REF_ALTTEXT $(D tuple),tuple,std,typecons) + for multiple seeds. +/ template fold(fun...) if (fun.length >= 1) From c472b2303d172226b9bf250d0d0567561c766e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20=C3=87ehreli?= Date: Wed, 20 Dec 2017 22:15:08 -0800 Subject: [PATCH 2/8] Fix Issue 18096 - Add fold() to std.parallelism --- std/parallelism.d | 135 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 6 deletions(-) diff --git a/std/parallelism.d b/std/parallelism.d index 2f2c0e33053..371f91a27b3 100644 --- a/std/parallelism.d +++ b/std/parallelism.d @@ -2421,12 +2421,15 @@ public: { /** Parallel reduce on a random access range. Except as otherwise noted, - usage is similar to $(REF _reduce, std,algorithm,iteration). This - function works by splitting the range to be reduced into work units, - which are slices to be reduced in parallel. Once the results from all - work units are computed, a final serial reduction is performed on these - results to compute the final answer. Therefore, care must be taken to - choose the seed value appropriately. + usage is similar to $(REF _reduce, std,algorithm,iteration). There is + also $(LREF fold) which does the same thing with a different parameter + order. + + This function works by splitting the range to be reduced into work + units, which are slices to be reduced in parallel. Once the results + from all work units are computed, a final serial reduction is performed + on these results to compute the final answer. Therefore, care must be + taken to choose the seed value appropriately. Because the reduction is being performed in parallel, $(D functions) must be associative. For notational simplicity, let # be an @@ -2502,6 +2505,12 @@ public: After this function is finished executing, any exceptions thrown are chained together via $(D Throwable.next) and rethrown. The chaining order is non-deterministic. + + See_Also: + + $(LREF fold) is functionally equivalent to $(LREF _reduce) except the + range parameter comes first and there is no need to use + $(REF_ALTTEXT $(D tuple),tuple,std,typecons) for multiple seeds. */ auto reduce(Args...)(Args args) { @@ -2803,6 +2812,120 @@ public: } } + /** Implements the homonym function (also known as $(D accumulate), $(D + compress), $(D inject), or $(D foldl)) present in various programming + languages of functional flavor. + + This is functionally equivalent to $(LREF reduce) except the range + parameter comes first and there is no need to use $(REF_ALTTEXT + $(D tuple),tuple,std,typecons) for multiple seeds. + + Params: + functions = One or more functions + + Returns: + The accumulated result as a single value for single function and as a tuple of values for multiple functions + + See_Also: + $(LREF reduce) + */ + template fold(functions...) + { + auto fold(Args...)(Args args) + { + import std.string : format; + static assert(isInputRange!(Args[0]), "First argument must be an InputRange"); + static assert(args.length == 1 || // just the range + args.length == 1 + functions.length || // range and seeds + args.length == 1 + functions.length + 1, // range, seeds, and workUnitSize + format("Invalid number of arguments (%s): Should be an input range, %s optional seed(s)," ~ + " and an optional work unit size", Args.length, functions.length)); + return fold(args[0], args[1..$]); + } + + /** This is the overload that uses implicit seeds. (See important notes + on implicit seeds under $(LREF reduce).) + + Params: + range = The range of values to _fold over + */ + auto fold(R)(R range) + { + return reduce!functions(range); + } + + /// + unittest + { + auto result = taskPool.fold!"a+b"([1, 2, 3, 4]); + assert(result == 10); + } + + /** This is the overload that uses explicit _seeds. (See important notes + on explicit _seeds under $(LREF reduce).) + + Params: + range = The range of values to _fold over + seeds = One seed per function + */ + auto fold(R, Seeds...)(R range, Seeds seeds) + if (Seeds.length == functions.length) + { + static if (Seeds.length == 1) + { + return reduce!functions(seeds, range); + } + else + { + import std.typecons : tuple; + return reduce!functions(tuple(seeds), range); + } + } + + /// + unittest + { + auto result = taskPool.fold!("a+b", "a*b")([1, 2, 3, 4], 0, 1); + assert(result[0] == 10); + assert(result[1] == 24); + } + + /** This is the overload that uses explicit seeds and work unit size. + (See important notes on explicit seeds and work unit size under + $(LREF reduce).) + + Params: + range = The range of values to _fold over + args = One seed per function ($(D args[0..$-1])) and the work unit size ($(D args[$-1])) + */ + auto fold(R, Args...)(R range, Args args) + if (Args.length == functions.length + 1) + { + static assert(isIntegral!(Args[$-1]), "Work unit size must be an integral type"); + + static if (Args.length == 2) + { + return reduce!functions(args[0], range, args[1]); + } + else + { + import std.typecons : tuple; + return reduce!functions(tuple(args[0..$-1]), range, args[$-1]); + } + } + + /// + unittest + { + auto x = taskPool.fold!"a+b"([1, 2, 3, 4], 0, 20); // Single function + assert(x == 10); + + auto y = taskPool.fold!("a+b", "a*b")([1, 2, 3, 4], 0, 1, 30); // Multiple functions + assert(y[0] == 10); + assert(y[1] == 24); + } + } + /** Gets the index of the current thread relative to this $(D TaskPool). Any thread not in this pool will receive an index of 0. The worker threads in From 673c4e959d115603e6b7764ae08453b236fb72af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20=C3=87ehreli?= Date: Sun, 24 Dec 2017 23:44:05 -0800 Subject: [PATCH 3/8] Apply review comments: Backticks for inline code, StdUnittest, etc. --- std/parallelism.d | 60 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/std/parallelism.d b/std/parallelism.d index 371f91a27b3..2c936d83d07 100644 --- a/std/parallelism.d +++ b/std/parallelism.d @@ -2812,22 +2812,23 @@ public: } } - /** Implements the homonym function (also known as $(D accumulate), $(D - compress), $(D inject), or $(D foldl)) present in various programming - languages of functional flavor. + /** Implements the homonym function (also known as `accumulate`, `compress`, + `inject`, or `foldl`) present in various programming languages of + functional flavor. This is functionally equivalent to $(LREF reduce) except the range parameter comes first and there is no need to use $(REF_ALTTEXT - $(D tuple),tuple,std,typecons) for multiple seeds. + `tuple`,tuple,std,typecons) for multiple seeds. Params: functions = One or more functions Returns: - The accumulated result as a single value for single function and as a tuple of values for multiple functions + The accumulated result as a single value for single function and as + a tuple of values for multiple functions See_Also: - $(LREF reduce) + Similar to $(REF _fold, std,algorithm,iteration), `fold` is a wrapper around $(LREF reduce). */ template fold(functions...) { @@ -2855,9 +2856,11 @@ public: } /// + version(StdUnittest) unittest { - auto result = taskPool.fold!"a+b"([1, 2, 3, 4]); + static int adder(int a, int b) { return a + b; } + auto result = taskPool.fold!adder([1, 2, 3, 4]); assert(result == 10); } @@ -2883,9 +2886,13 @@ public: } /// + version(StdUnittest) unittest { - auto result = taskPool.fold!("a+b", "a*b")([1, 2, 3, 4], 0, 1); + static int adder (int a, int b) { return a + b; } + static int multiplier(int a, int b) { return a * b; } + + auto result = taskPool.fold!(adder, multiplier)([1, 2, 3, 4], 0, 1); assert(result[0] == 10); assert(result[1] == 24); } @@ -2896,7 +2903,8 @@ public: Params: range = The range of values to _fold over - args = One seed per function ($(D args[0..$-1])) and the work unit size ($(D args[$-1])) + args = One seed per function (`args[0..$-1]`) and the work unit + size (`args[$-1]`) */ auto fold(R, Args...)(R range, Args args) if (Args.length == functions.length + 1) @@ -2915,14 +2923,20 @@ public: } /// + version(StdUnittest) unittest { - auto x = taskPool.fold!"a+b"([1, 2, 3, 4], 0, 20); // Single function - assert(x == 10); + static int adder (int a, int b) { return a + b; } + static int multiplier(int a, int b) { return a * b; } + + // Single function produces single result + auto result = taskPool.fold!adder([1, 2, 3, 4], 0, 20); + assert(result == 10); - auto y = taskPool.fold!("a+b", "a*b")([1, 2, 3, 4], 0, 1, 30); // Multiple functions - assert(y[0] == 10); - assert(y[1] == 24); + // Multiple functions produce a tuple of results + auto results = taskPool.fold!(adder, multiplier)([1, 2, 3, 4], 0, 1, 30); + assert(results[0] == 10); + assert(results[1] == 24); } } @@ -3458,6 +3472,24 @@ public: } } +version(StdUnittest) +unittest +{ + import std.algorithm : sum; + import std.range : iota; + enum N = 100; + auto r = iota(1, N + 1); + const expected = r.sum(); + + static auto adder(int a, int b) { + return a + b; + } + + assert(taskPool.fold!adder(r) == expected); + assert(taskPool.fold!adder(r, 0) == expected); + assert(taskPool.fold!adder(r, 0, 42) == expected); +} + /** Returns a lazily initialized global instantiation of $(D TaskPool). This function can safely be called concurrently from multiple non-worker From 665e4adbce0899586dbbc3ee5f93b55b43448e58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20=C3=87ehreli?= Date: Mon, 25 Dec 2017 15:36:06 -0800 Subject: [PATCH 4/8] Implement std.parallelism.fold with static if branches instead of with template specializations --- std/parallelism.d | 224 +++++++++++++++++++++++++--------------------- 1 file changed, 120 insertions(+), 104 deletions(-) diff --git a/std/parallelism.d b/std/parallelism.d index 2c936d83d07..cafb38ce4df 100644 --- a/std/parallelism.d +++ b/std/parallelism.d @@ -2812,26 +2812,59 @@ public: } } - /** Implements the homonym function (also known as `accumulate`, `compress`, - `inject`, or `foldl`) present in various programming languages of - functional flavor. + /// + template fold(functions...) + { + /** Implements the homonym function (also known as `accumulate`, `compress`, + `inject`, or `foldl`) present in various programming languages of + functional flavor. - This is functionally equivalent to $(LREF reduce) except the range - parameter comes first and there is no need to use $(REF_ALTTEXT - `tuple`,tuple,std,typecons) for multiple seeds. + `fold` is functionally equivalent to $(LREF reduce) except the range + parameter comes first and there is no need to use $(REF_ALTTEXT + `tuple`,tuple,std,typecons) for multiple seeds. - Params: - functions = One or more functions + There may be one or more callable entities (`functions` argument) to + apply. + + Params: - Returns: - The accumulated result as a single value for single function and as - a tuple of values for multiple functions + args = Just the range to _fold over; or the range and one seed + per function; or the range, one seed per function, and + the work unit size - See_Also: + Returns: + The accumulated result as a single value for single function and + as a tuple of values for multiple functions + + See_Also: Similar to $(REF _fold, std,algorithm,iteration), `fold` is a wrapper around $(LREF reduce). - */ - template fold(functions...) - { + + Example: + --- + static int adder(int a, int b) + { + return a + b; + } + static int multiplier(int a, int b) + { + return a * b; + } + + // Just the range + auto x = taskPool.fold!adder([1, 2, 3, 4]); + assert(x == 10); + + // The range and the seeds (0 and 1 below; also note multiple + // functions in this example) + auto y = taskPool.fold!(adder, multiplier)([1, 2, 3, 4], 0, 1); + assert(y[0] == 10); + assert(y[1] == 24); + + // The range, the seed (0), and the work unit size (20) + auto z = taskPool.fold!adder([1, 2, 3, 4], 0, 20); + assert(z == 10); + --- + */ auto fold(Args...)(Args args) { import std.string : format; @@ -2841,105 +2874,85 @@ public: args.length == 1 + functions.length + 1, // range, seeds, and workUnitSize format("Invalid number of arguments (%s): Should be an input range, %s optional seed(s)," ~ " and an optional work unit size", Args.length, functions.length)); - return fold(args[0], args[1..$]); - } - - /** This is the overload that uses implicit seeds. (See important notes - on implicit seeds under $(LREF reduce).) - - Params: - range = The range of values to _fold over - */ - auto fold(R)(R range) - { - return reduce!functions(range); - } - - /// - version(StdUnittest) - unittest - { - static int adder(int a, int b) { return a + b; } - auto result = taskPool.fold!adder([1, 2, 3, 4]); - assert(result == 10); - } - /** This is the overload that uses explicit _seeds. (See important notes - on explicit _seeds under $(LREF reduce).) + auto range() + { + return args[0]; + } - Params: - range = The range of values to _fold over - seeds = One seed per function - */ - auto fold(R, Seeds...)(R range, Seeds seeds) - if (Seeds.length == functions.length) - { - static if (Seeds.length == 1) + static if (Args.length == 1) { - return reduce!functions(seeds, range); + // Just the range + return reduce!functions(range); } else { - import std.typecons : tuple; - return reduce!functions(tuple(seeds), range); + static if (functions.length == 1) + { + auto seeds() + { + return args[1]; + } + } + else + { + auto seeds() + { + import std.typecons : tuple; + return tuple(args[1 .. functions.length+1]); + } + } + + static if (Args.length == 1 + functions.length) + { + // The range and the seeds + return reduce!functions(seeds, range); + } + else static if (Args.length == 1 + functions.length + 1) + { + // The range, the seeds, and the work unit size + static assert(isIntegral!(Args[$-1]), "Work unit size must be an integral type"); + return reduce!functions(seeds, range, args[$-1]); + } + else + { + static assert(0); + } } } + } - /// - version(StdUnittest) - unittest + // This test is not included in the documentation because even though these + // examples are for the inner fold() template, with their current location, + // they would appear under the outer one. (We can't move this inside the + // outer fold() template because then dmd runs out of memory possibly due to + // recursive template instantiation, which is surprisingly not caught.) + version(StdUnittest) + @system unittest + { + static int adder(int a, int b) { - static int adder (int a, int b) { return a + b; } - static int multiplier(int a, int b) { return a * b; } - - auto result = taskPool.fold!(adder, multiplier)([1, 2, 3, 4], 0, 1); - assert(result[0] == 10); - assert(result[1] == 24); + return a + b; } - - /** This is the overload that uses explicit seeds and work unit size. - (See important notes on explicit seeds and work unit size under - $(LREF reduce).) - - Params: - range = The range of values to _fold over - args = One seed per function (`args[0..$-1]`) and the work unit - size (`args[$-1]`) - */ - auto fold(R, Args...)(R range, Args args) - if (Args.length == functions.length + 1) + static int multiplier(int a, int b) { - static assert(isIntegral!(Args[$-1]), "Work unit size must be an integral type"); - - static if (Args.length == 2) - { - return reduce!functions(args[0], range, args[1]); - } - else - { - import std.typecons : tuple; - return reduce!functions(tuple(args[0..$-1]), range, args[$-1]); - } + return a * b; } - /// - version(StdUnittest) - unittest - { - static int adder (int a, int b) { return a + b; } - static int multiplier(int a, int b) { return a * b; } + // Just the range + auto x = taskPool.fold!adder([1, 2, 3, 4]); + assert(x == 10); - // Single function produces single result - auto result = taskPool.fold!adder([1, 2, 3, 4], 0, 20); - assert(result == 10); + // The range and the seeds (0 and 1 below; also note multiple + // functions in this example) + auto y = taskPool.fold!(adder, multiplier)([1, 2, 3, 4], 0, 1); + assert(y[0] == 10); + assert(y[1] == 24); - // Multiple functions produce a tuple of results - auto results = taskPool.fold!(adder, multiplier)([1, 2, 3, 4], 0, 1, 30); - assert(results[0] == 10); - assert(results[1] == 24); - } + // The range, the seed (0), and the work unit size (20) + auto z = taskPool.fold!adder([1, 2, 3, 4], 0, 20); + assert(z == 10); } - /** Gets the index of the current thread relative to this $(D TaskPool). Any thread not in this pool will receive an index of 0. The worker threads in @@ -3473,21 +3486,24 @@ public: } version(StdUnittest) -unittest +@system unittest { - import std.algorithm : sum; + import std.algorithm.iteration : sum; import std.range : iota; - enum N = 100; - auto r = iota(1, N + 1); - const expected = r.sum(); + import std.typecons : tuple; - static auto adder(int a, int b) { + static int adder(int a, int b) + { return a + b; } + enum N = 100; + auto r = iota(1, N + 1); + const expected = r.sum(); + assert(taskPool.fold!adder(r) == expected); assert(taskPool.fold!adder(r, 0) == expected); - assert(taskPool.fold!adder(r, 0, 42) == expected); + assert(taskPool.fold!(adder, adder)(r, 0, 0, 42) == tuple(expected, expected)); } /** From 7519d931f470671fa0731d61b7ff05f41b3bface Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20=C3=87ehreli?= Date: Tue, 26 Dec 2017 22:58:02 -0800 Subject: [PATCH 5/8] Add the changelog entry --- changelog/std-parallelism-fold.dd | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 changelog/std-parallelism-fold.dd diff --git a/changelog/std-parallelism-fold.dd b/changelog/std-parallelism-fold.dd new file mode 100644 index 00000000000..e12bd7ad6a8 --- /dev/null +++ b/changelog/std-parallelism-fold.dd @@ -0,0 +1,31 @@ +`fold` is added to `std.parallelism.TaskPool` + +$(REF fold, std, parallelism, TaskPool) is functionally equivalent to +$(REF_ALTTEXT `reduce`, reduce, std, parallelism, TaskPool) except the range +parameter comes first and there is no need to use $(REF_ALTTEXT +`tuple`,tuple,std,typecons) for multiple seeds. + +--- +static int adder(int a, int b) +{ + return a + b; +} +static int multiplier(int a, int b) +{ + return a * b; +} + +// Just the range +auto x = taskPool.fold!adder([1, 2, 3, 4]); +assert(x == 10); + +// The range and the seeds (0 and 1 below; also note multiple +// functions in this example) +auto y = taskPool.fold!(adder, multiplier)([1, 2, 3, 4], 0, 1); +assert(y[0] == 10); +assert(y[1] == 24); + +// The range, the seed (0), and the work unit size (20) +auto z = taskPool.fold!adder([1, 2, 3, 4], 0, 20); +assert(z == 10); +--- From 8cfff5e81056eab456cc0125bbd90de632ce5570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20=C3=87ehreli?= Date: Tue, 26 Dec 2017 23:47:12 -0800 Subject: [PATCH 6/8] Use message with static assert(0), use aliases instead of nested functions, do not use format in CTFE, add more unit tests. --- std/parallelism.d | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/std/parallelism.d b/std/parallelism.d index cafb38ce4df..656e08b6c18 100644 --- a/std/parallelism.d +++ b/std/parallelism.d @@ -2867,32 +2867,21 @@ public: */ auto fold(Args...)(Args args) { - import std.string : format; static assert(isInputRange!(Args[0]), "First argument must be an InputRange"); - static assert(args.length == 1 || // just the range - args.length == 1 + functions.length || // range and seeds - args.length == 1 + functions.length + 1, // range, seeds, and workUnitSize - format("Invalid number of arguments (%s): Should be an input range, %s optional seed(s)," ~ - " and an optional work unit size", Args.length, functions.length)); - auto range() - { - return args[0]; - } + alias range = args[0]; static if (Args.length == 1) { // Just the range return reduce!functions(range); } - else + else static if (Args.length == 1 + functions.length || + Args.length == 1 + functions.length + 1) { static if (functions.length == 1) { - auto seeds() - { - return args[1]; - } + alias seeds = args[1]; } else { @@ -2914,10 +2903,12 @@ public: static assert(isIntegral!(Args[$-1]), "Work unit size must be an integral type"); return reduce!functions(seeds, range, args[$-1]); } - else - { - static assert(0); - } + } + else + { + import std.conv : text; + static assert(0, "Invalid number of arguments (" ~ Args.length.text ~ "): Should be an input range, " + ~ functions.length.text ~ " optional seed(s), and an optional work unit size."); } } } @@ -2927,7 +2918,6 @@ public: // they would appear under the outer one. (We can't move this inside the // outer fold() template because then dmd runs out of memory possibly due to // recursive template instantiation, which is surprisingly not caught.) - version(StdUnittest) @system unittest { static int adder(int a, int b) @@ -2953,6 +2943,7 @@ public: auto z = taskPool.fold!adder([1, 2, 3, 4], 0, 20); assert(z == 10); } + /** Gets the index of the current thread relative to this $(D TaskPool). Any thread not in this pool will receive an index of 0. The worker threads in @@ -3485,7 +3476,6 @@ public: } } -version(StdUnittest) @system unittest { import std.algorithm.iteration : sum; @@ -3501,8 +3491,15 @@ version(StdUnittest) auto r = iota(1, N + 1); const expected = r.sum(); + // Just the range assert(taskPool.fold!adder(r) == expected); + + // Range and seeds assert(taskPool.fold!adder(r, 0) == expected); + assert(taskPool.fold!(adder, adder)(r, 0, 0) == tuple(expected, expected)); + + // Range, seeds, and work unit size + assert(taskPool.fold!adder(r, 0, 42) == expected); assert(taskPool.fold!(adder, adder)(r, 0, 0, 42) == tuple(expected, expected)); } From f9e3dde2bb46ee31e0f3db4f5ac921e6fc606aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20=C3=87ehreli?= Date: Thu, 28 Dec 2017 22:56:23 -0800 Subject: [PATCH 7/8] Use string lambdas in non-documentation unittests to reduce memory usage of dmd --- std/parallelism.d | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/std/parallelism.d b/std/parallelism.d index 656e08b6c18..f99c18c2fa0 100644 --- a/std/parallelism.d +++ b/std/parallelism.d @@ -2920,27 +2920,18 @@ public: // recursive template instantiation, which is surprisingly not caught.) @system unittest { - static int adder(int a, int b) - { - return a + b; - } - static int multiplier(int a, int b) - { - return a * b; - } - // Just the range - auto x = taskPool.fold!adder([1, 2, 3, 4]); + auto x = taskPool.fold!"a + b"([1, 2, 3, 4]); assert(x == 10); // The range and the seeds (0 and 1 below; also note multiple // functions in this example) - auto y = taskPool.fold!(adder, multiplier)([1, 2, 3, 4], 0, 1); + auto y = taskPool.fold!("a + b", "a * b")([1, 2, 3, 4], 0, 1); assert(y[0] == 10); assert(y[1] == 24); // The range, the seed (0), and the work unit size (20) - auto z = taskPool.fold!adder([1, 2, 3, 4], 0, 20); + auto z = taskPool.fold!"a + b"([1, 2, 3, 4], 0, 20); assert(z == 10); } @@ -3482,25 +3473,20 @@ public: import std.range : iota; import std.typecons : tuple; - static int adder(int a, int b) - { - return a + b; - } - enum N = 100; auto r = iota(1, N + 1); const expected = r.sum(); // Just the range - assert(taskPool.fold!adder(r) == expected); + assert(taskPool.fold!"a + b"(r) == expected); // Range and seeds - assert(taskPool.fold!adder(r, 0) == expected); - assert(taskPool.fold!(adder, adder)(r, 0, 0) == tuple(expected, expected)); + assert(taskPool.fold!"a + b"(r, 0) == expected); + assert(taskPool.fold!("a + b", "a + b")(r, 0, 0) == tuple(expected, expected)); // Range, seeds, and work unit size - assert(taskPool.fold!adder(r, 0, 42) == expected); - assert(taskPool.fold!(adder, adder)(r, 0, 0, 42) == tuple(expected, expected)); + assert(taskPool.fold!"a + b"(r, 0, 42) == expected); + assert(taskPool.fold!("a + b", "a + b")(r, 0, 0, 42) == tuple(expected, expected)); } /** From c1c8e8681e76638a39dda0ae6479c466c5f44b8d Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Tue, 16 Jan 2018 11:58:56 -0500 Subject: [PATCH 8/8] remove surprising emtpy line --- std/parallelism.d | 1 - 1 file changed, 1 deletion(-) diff --git a/std/parallelism.d b/std/parallelism.d index f99c18c2fa0..e247c786c61 100644 --- a/std/parallelism.d +++ b/std/parallelism.d @@ -2827,7 +2827,6 @@ public: apply. Params: - args = Just the range to _fold over; or the range and one seed per function; or the range, one seed per function, and the work unit size