1 /** 2 Copyright: Copyright (c) 2018 Frank McSherry 3 License: MIT 4 Author: Joakim BrännströmJoakim Brännström (joakim.brannstrom@gmx.com) 5 6 Port of DataFrog to D. 7 8 Functionality for mapping a function on a variable. 9 */ 10 module datacat.map; 11 12 import std.traits : hasMember; 13 14 version (unittest) { 15 import unit_threaded; 16 import datacat : Relation, ThreadStrategy; 17 } 18 19 // TODO: add constraint on Fn that the param is T1 returning T2. 20 /** 21 * 22 * The task pool from `output` is used if the `ThreadStrategy` is parallel. 23 * 24 * Params: 25 * output = the result of the join 26 */ 27 private void mapInto(alias logicFn, InputT, OutputT)(InputT input, OutputT output) { 28 import std.array : appender; 29 30 auto results = appender!(OutputT.TT[])(); 31 32 foreach (v; input.recent) 33 results.put(logicFn(v)); 34 35 output.insert(results.data); 36 } 37 38 /** Adds tuples that result from mapping `input`. 39 */ 40 template fromMap(Args...) if (Args.length == 1) { 41 auto fromMap(Self, I1)(Self self, I1 i1) if (is(Self == class)) { 42 import std.functional : unaryFun; 43 44 alias fn_ = unaryFun!(Args[0]); 45 return mapInto!(fn_)(i1, self); 46 } 47 } 48 49 /** 50 * This example starts a collection with the pairs (x, x) for x in 0 .. 10. It then 51 * repeatedly adds any pairs (x, z) for (x, y) in the collection, where z is the Collatz 52 * step for y: it is y/2 if y is even, and 3*y + 1 if y is odd. This produces all of the 53 * pairs (x, y) where x visits y as part of its Collatz journey. 54 */ 55 @("shall be the tuples that result from applying a function on the input") 56 unittest { 57 import std.algorithm : map, filter; 58 import std.range : iota; 59 import datacat : Iteration, kvTuple; 60 61 // arrange 62 Iteration iter; 63 auto variable = iter.variable!(int, int)("source"); 64 variable.insert(iota(10).map!(x => kvTuple(x, x))); 65 66 // act 67 while (iter.changed) { 68 variable.fromMap!((a) => a.value % 2 == 0 ? kvTuple(a.key, a.value / 2) 69 : kvTuple(a.key, 3 * a.value + 1))(variable); 70 } 71 72 auto result = variable.complete; 73 74 // assert 75 result.length.should == 74; 76 }