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 <ae@cy.md> 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 } /// ditto 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)() 108 { 109 ChainFunctor!fun s; 110 return s; 111 } /// ditto 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) 140 { 141 auto chainFilter(Next)(Next next) 142 { 143 return ChainFilter!(pred, Next)(next); 144 } 145 } /// ditto 146 147 /// Iteration control. 148 struct ChainControl(bool result, Next) 149 { 150 Next next; /// 151 152 this(Next next) { this.next = next; } /// 153 154 bool opCall(T)(auto ref T v) 155 { 156 cast(void)next(v); 157 return result; 158 } /// 159 } 160 template chainControl(bool result) 161 { 162 auto chainControl(Next)(Next next) 163 { 164 return ChainControl!(result, Next)(next); 165 } 166 } /// 167 alias chainAll = chainControl!false; /// Always continue iteration 168 alias chainFirst = chainControl!true; /// Stop iteration after this element 169 170 /// 171 static if (haveAliasStructBinding) 172 unittest 173 { 174 int a = 2; 175 int b = 3; 176 int[] results; 177 foreach (i; 0..10) 178 chainFilter!(n => n % a == 0)( 179 chainFilter!(n => n % b == 0)( 180 (int n) { results ~= n; return false; }))(i); 181 assert(results == [0, 6]); 182 } 183 184 /// Calls next with pred(value). 185 struct ChainMap(alias pred, Next) 186 { 187 Next next; /// 188 189 this(Next next) { this.next = next; } /// 190 191 bool opCall(T)(auto ref T v) 192 { 193 return next(pred(v)); 194 } /// 195 } 196 template chainMap(alias pred) 197 { 198 auto chainMap(Next)(Next next) 199 { 200 return ChainMap!(pred, Next)(next); 201 } 202 } /// ditto 203 204 /// 205 unittest 206 { 207 int result; 208 chainMap!(n => n+1)(chainMap!(n => n * 2)((int n) { result = n; return false; }))(2); 209 assert(result == 6); 210 }