1 /** 2 * Experimental! 3 * 4 * std.algorithm alternative which accepts predicates as functors 5 * https://forum.dlang.org/post/qnigarkuxxnqwdernhzv@forum.dlang.org 6 * 7 * License: 8 * This Source Code Form is subject to the terms of 9 * the Mozilla Public License, v. 2.0. If a copy of 10 * the MPL was not distributed with this file, You 11 * can obtain one at http://mozilla.org/MPL/2.0/. 12 * 13 * Authors: 14 * Vladimir Panteleev <ae@cy.md> 15 */ 16 17 module ae.utils.pred.algorithm; 18 19 import std.range.primitives : isInputRange; 20 import std.traits : Unqual; 21 22 import std.range; // array range primitives 23 24 /// Functor predicate constructor from static lambda 25 auto pred(alias fun, State...)(State state) 26 { 27 struct Pred 28 { 29 State state; 30 31 auto opCall(Args...)(auto ref Args args) 32 { 33 return fun(state, args); 34 } 35 } 36 Pred pred; 37 pred.state = state; 38 return pred; 39 } 40 41 /// `map` variant with functor predicate 42 auto pmap(Range, P)(Range r, P pred) 43 if (isInputRange!(Unqual!Range)) 44 { 45 return PMapResult!(Range, P)(r, pred); 46 } 47 48 private struct PMapResult(R, P) 49 { 50 bool empty() { return r.empty; } 51 auto front() { return pred(r.front); } 52 static if (__traits(hasMember, R, "back")) 53 auto back() { return pred(r.back); } 54 void popFront() { r.popFront; } 55 56 private: 57 R r; 58 P pred; 59 } 60 61 /// 62 @nogc unittest 63 { 64 import std.algorithm.comparison : equal; 65 import std.range : iota, only; 66 import std.typecons : tuple; 67 68 // Simple map 69 assert(5.iota.pmap((int n) => n + 1).equal(only(1, 2, 3, 4, 5))); 70 71 // With state (in @nogc !!!) 72 int addend = 1; 73 assert(5.iota.pmap(pred!((addend, n) => n + addend)(addend)).equal(only(1, 2, 3, 4, 5))); 74 75 // Aggregate state with tuples 76 auto p = pred!((state, n) => (n + state.addend) * state.factor)( 77 tuple!("addend", "factor")(1, 2) 78 ); 79 assert(5.iota.pmap(p).equal(only(2, 4, 6, 8, 10))); 80 } 81 82 /// `filter` variant with functor predicate 83 auto pfilter(Range, P)(Range r, P pred) 84 if (isInputRange!(Unqual!Range)) 85 { 86 return PFilterResult!(Range, P)(r, pred); 87 } 88 89 private struct PFilterResult(R, P) 90 { 91 bool empty() { return r.empty; } 92 auto front() { return pred(r.front); } 93 void popFront() { r.popFront(); advance(); } 94 95 this(R r, P pred) 96 { 97 this.r = r; 98 this.pred = pred; 99 advance(); 100 } 101 102 private: 103 R r; 104 P pred; 105 106 void advance() 107 { 108 while (!r.empty && !pred(r.front)) 109 r.popFront(); 110 } 111 }