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