1 /** 2 * ae.utils.meta.chain 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 <vladimir@thecybershadow.net> 12 */ 13 14 /// Chains are a concept a bit like ranges, 15 /// but which operate on heterogenous types 16 /// (e.g. a tuple of values). 17 18 /// Composition is done by a chain of functors. 19 /// To allow state, each functor can be represented 20 /// as a struct. 21 22 /// Functors return a bool (true if iteration should 23 /// stop, false if it should continue). 24 25 deprecated("Use ae.utils.meta.tuplerange") 26 module ae.utils.meta.chain; 27 28 import ae.utils.meta.caps; 29 30 /// 31 static if (haveAliasStructBinding) 32 unittest 33 { 34 int a = 2; 35 int x; 36 chainIterator(chainFilter!(n => n > a)((int n) { x = n; return true; } ))(1, 2, 3); 37 assert(x == 3); 38 } 39 40 static if (haveAliasStructBinding) 41 unittest 42 { 43 static struct X 44 { 45 bool fun(int x) 46 { 47 return chainIterator(chainFunctor!(n => n == x))(this.tupleof); 48 } 49 50 long a; 51 int b; 52 ubyte c; 53 } 54 55 X x; 56 assert(!x.fun(5)); 57 x.c = 5; 58 assert(x.fun(5)); 59 } 60 61 /// Starts the chain by iterating over a tuple. 62 struct ChainIterator(Next) 63 { 64 Next next; 65 66 this(ref Next next) 67 { 68 this.next = next; 69 } 70 71 bool opCall(Args...)(auto ref Args args) 72 { 73 foreach (ref arg; args) 74 if (next(arg)) 75 return true; 76 return false; 77 } 78 } 79 auto chainIterator(Next)(Next next) 80 { 81 return ChainIterator!Next(next); 82 } 83 84 unittest 85 { 86 struct S 87 { 88 int a = 1; 89 long b = 2; 90 ubyte c = 3; 91 } 92 S s; 93 94 int[] results; 95 chainIterator((long n) { results ~= cast(int)n; return false; })(s.tupleof); 96 assert(results == [1, 2, 3]); 97 } 98 99 /// Wraps a function template into a concrete value type functor. 100 struct ChainFunctor(alias fun) 101 { 102 auto opCall(Arg)(auto ref Arg arg) 103 { 104 return fun(arg); 105 } 106 } 107 auto chainFunctor(alias fun)() /// ditto 108 { 109 ChainFunctor!fun s; 110 return s; 111 } 112 113 /// 114 static if (haveAliasStructBinding) 115 unittest 116 { 117 int[] results; 118 auto fn = chainFunctor!(n => results ~= cast(int)n); 119 fn(1); 120 fn(long(2)); 121 fn(ubyte(3)); 122 assert(results == [1, 2, 3]); 123 } 124 125 /// Calls next only if pred(value) is true. 126 struct ChainFilter(alias pred, Next) 127 { 128 Next next; 129 130 this(Next next) { this.next = next; } 131 132 bool opCall(T)(auto ref T v) 133 { 134 if (pred(v)) 135 return next(v); 136 return false; 137 } 138 } 139 template chainFilter(alias pred) /// ditto 140 { 141 auto chainFilter(Next)(Next next) 142 { 143 return ChainFilter!(pred, Next)(next); 144 } 145 } 146 147 struct ChainControl(bool result, Next) 148 { 149 Next next; 150 151 this(Next next) { this.next = next; } 152 153 bool opCall(T)(auto ref T v) 154 { 155 cast(void)next(v); 156 return result; 157 } 158 } 159 template chainControl(bool result) /// ditto 160 { 161 auto chainControl(Next)(Next next) 162 { 163 return ChainControl!(result, Next)(next); 164 } 165 } 166 alias chainAll = chainControl!false; // Always continue iteration 167 alias chainFirst = chainControl!true; // Stop iteration after this element 168 169 /// 170 static if (haveAliasStructBinding) 171 unittest 172 { 173 int a = 2; 174 int b = 3; 175 int[] results; 176 foreach (i; 0..10) 177 chainFilter!(n => n % a == 0)(chainFilter!(n => n % b == 0)((int n) { results ~= n; return false; }))(i); 178 assert(results == [0, 6]); 179 } 180 181 /// Calls next with pred(value). 182 struct ChainMap(alias pred, Next) 183 { 184 Next next; 185 186 this(Next next) { this.next = next; } 187 188 bool opCall(T)(auto ref T v) 189 { 190 return next(pred(v)); 191 } 192 } 193 template chainMap(alias pred) /// ditto 194 { 195 auto chainMap(Next)(Next next) 196 { 197 return ChainMap!(pred, Next)(next); 198 } 199 } 200 201 /// 202 unittest 203 { 204 int result; 205 chainMap!(n => n+1)(chainMap!(n => n * 2)((int n) { result = n; return false; }))(2); 206 assert(result == 6); 207 }