Skip to content

Instantly share code, notes, and snippets.

@Hackerpilot
Last active April 18, 2016 23:31
Show Gist options
  • Save Hackerpilot/d10880171ee92194087897fd02fe7379 to your computer and use it in GitHub Desktop.
Save Hackerpilot/d10880171ee92194087897fd02fe7379 to your computer and use it in GitHub Desktop.
Route an input range to an output range based on function return value
import std.range.primitives : isInputRange, isOutputRange, ElementType;
import std.meta : ApplyLeft, allSatisfy, staticMap;
import std.functional : unaryFun;
import std.traits : Unqual;
/**
* Copy values from an input range to one of several output ranges based
* on a routing function.
*
* The function must return an integer between 0 and the number of outputs.
*
* Params:
* Decider = the decision function
* I = the input range type
* O = the output range types
* input = the input range
* outputs = the output ranges
*/
void route(alias Decider, I, O...)(auto ref I input, auto ref O outputs)
if (isInputRange!(Unqual!I) && is(typeof(unaryFun!Decider))
&& allSatisfy!(ApplyLeft!(isOutputRange, ElementType!(Unqual!I),
staticMap!(Unqual, O))))
{
import std.range.primitives : put;
alias _f = unaryFun!Decider;
foreach (i; input)
{
immutable size_t index = _f(i);
assert(index < O.length, "Index returned by decision function out of range");
foreach (Index, _; O)
if (Index == index)
outputs[Index].put(i);
}
}
///
unittest
{
import std.array : appender;
import std.algorithm.comparison : equal;
int[] arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
auto r1 = appender!(int[]);
auto r2 = appender!(int[]);
auto r3 = appender!(int[]);
arr.route!(a => a % 3)(r1, r2, r3);
assert(equal(r1.data, [0, 3, 6, 9, 12]));
assert(equal(r2.data, [1, 4, 7, 10]));
assert(equal(r3.data, [2, 5, 8, 11]));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment