| 1 |
/** Python-like (yield) iterators for Digital Mars D |
|---|
| 2 |
* Version: 1.0 |
|---|
| 3 |
* Author: Witold Baryluk <baryluk@smp.if.uj.edu.pl> |
|---|
| 4 |
* Copyright 2007 |
|---|
| 5 |
* Licence: BSD |
|---|
| 6 |
|
|---|
| 7 |
This package may be redistributed under the terms of the UCB BSD |
|---|
| 8 |
license: |
|---|
| 9 |
|
|---|
| 10 |
Copyright (c) Witold Baryluk |
|---|
| 11 |
All rights reserved. |
|---|
| 12 |
|
|---|
| 13 |
Redistribution and use in source and binary forms, with or without |
|---|
| 14 |
modification, are permitted provided that the following conditions |
|---|
| 15 |
are met: |
|---|
| 16 |
1. Redistributions of source code must retain the above copyright |
|---|
| 17 |
notice, this list of conditions and the following disclaimer. |
|---|
| 18 |
2. Redistributions in binary form must reproduce the above copyright |
|---|
| 19 |
notice, this list of conditions and the following disclaimer in the |
|---|
| 20 |
documentation and/or other materials provided with the distribution. |
|---|
| 21 |
4. Neither the name of the Witold Baryluk nor the names of its contributors |
|---|
| 22 |
may be used to endorse or promote products derived from this software |
|---|
| 23 |
without specific prior written permission. |
|---|
| 24 |
|
|---|
| 25 |
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
|---|
| 26 |
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|---|
| 27 |
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|---|
| 28 |
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
|---|
| 29 |
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|---|
| 30 |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|---|
| 31 |
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|---|
| 32 |
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|---|
| 33 |
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|---|
| 34 |
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|---|
| 35 |
SUCH DAMAGE. |
|---|
| 36 |
|
|---|
| 37 |
*/ |
|---|
| 38 |
|
|---|
| 39 |
/** |
|---|
| 40 |
* TODO: |
|---|
| 41 |
* - Index variables shouldn't be inout. |
|---|
| 42 |
* - Shorter syntax (s.squers(), insted s.squers.ic()) |
|---|
| 43 |
* - Neseting? |
|---|
| 44 |
* - Remove unnacasary types: (mixin mainiter!(iter), |
|---|
| 45 |
* insted mixin mainiter!(int, iter)); |
|---|
| 46 |
* - Reuse mainiter procedures in inneriter, becouse |
|---|
| 47 |
* they are very similar. |
|---|
| 48 |
* - Mayby void iter() , and return 0; is not needed really |
|---|
| 49 |
*/ |
|---|
| 50 |
module iterators; |
|---|
| 51 |
|
|---|
| 52 |
|
|---|
| 53 |
/* |
|---|
| 54 |
class IterNoMore : Exception { |
|---|
| 55 |
this() { super(); } |
|---|
| 56 |
} |
|---|
| 57 |
*/ |
|---|
| 58 |
|
|---|
| 59 |
/** Exception rised when user defined function in |
|---|
| 60 |
* foreach breaks, which cancel iteration |
|---|
| 61 |
* process, catched in opApply. */ |
|---|
| 62 |
class IterBreak : Exception { |
|---|
| 63 |
int ret; |
|---|
| 64 |
this(int ret0) { |
|---|
| 65 |
super("Iterator Break"); |
|---|
| 66 |
ret = ret0; |
|---|
| 67 |
} |
|---|
| 68 |
} |
|---|
| 69 |
/** Similar to IterBreak, used to make last iteration. */ |
|---|
| 70 |
class IterLast : Exception { |
|---|
| 71 |
int ret; |
|---|
| 72 |
this(int ret0) { |
|---|
| 73 |
super("Iterator Last"); |
|---|
| 74 |
ret = ret0; |
|---|
| 75 |
} |
|---|
| 76 |
} |
|---|
| 77 |
|
|---|
| 78 |
/** Mixin this template to use your class as |
|---|
| 79 |
* iterator. |
|---|
| 80 |
* Params: |
|---|
| 81 |
* V = type of iterator (ie. double) |
|---|
| 82 |
* f = name of virtual method implementing iteration. |
|---|
| 83 |
* Example: |
|---|
| 84 |
* ------- |
|---|
| 85 |
* class Naturals(int n) { |
|---|
| 86 |
* int iter() { |
|---|
| 87 |
* for (int i = 1; i <= n; i++) yield(i); // use yield to process next item |
|---|
| 88 |
* return 0; // indicate correct end of iterator |
|---|
| 89 |
* } |
|---|
| 90 |
* mixin mainiter!(int, iter); // mixin iterator's stuff |
|---|
| 91 |
* } |
|---|
| 92 |
* ... |
|---|
| 93 |
* foreach (int x; new Naturals!(10)()) { |
|---|
| 94 |
* ... |
|---|
| 95 |
* } |
|---|
| 96 |
* ------- |
|---|
| 97 |
*/ |
|---|
| 98 |
template mainiter (V, alias f) { |
|---|
| 99 |
/* Curent context of iterator, user's delegate */ |
|---|
| 100 |
private int delegate(inout V) _iter_curctx; |
|---|
| 101 |
private int delegate(inout int, inout V) _iter_curctx2; |
|---|
| 102 |
private int _iter_count = 0; |
|---|
| 103 |
|
|---|
| 104 |
int opApply(int delegate(inout V) fn) { |
|---|
| 105 |
assert(_iter_curctx is null && _iter_curctx2 is null, "Another iteration on this object in progress"); |
|---|
| 106 |
_iter_curctx = fn; |
|---|
| 107 |
try { |
|---|
| 108 |
return f(); |
|---|
| 109 |
} catch (IterBreak ib) { |
|---|
| 110 |
return ib.ret; |
|---|
| 111 |
} catch (IterLast il) { |
|---|
| 112 |
return il.ret; |
|---|
| 113 |
} finally { |
|---|
| 114 |
_iter_curctx = null; |
|---|
| 115 |
} |
|---|
| 116 |
} |
|---|
| 117 |
|
|---|
| 118 |
int opApply(int delegate(inout int, inout V) fn) { |
|---|
| 119 |
assert(_iter_curctx is null && _iter_curctx2 is null, "Another iteration on this object in progress"); |
|---|
| 120 |
_iter_curctx2 = fn; |
|---|
| 121 |
_iter_count = 0; |
|---|
| 122 |
try { |
|---|
| 123 |
return f(); |
|---|
| 124 |
} catch (IterBreak ib) { |
|---|
| 125 |
return ib.ret; |
|---|
| 126 |
} catch (IterLast il) { |
|---|
| 127 |
return il.ret; |
|---|
| 128 |
} finally { |
|---|
| 129 |
_iter_curctx2 = null; |
|---|
| 130 |
} |
|---|
| 131 |
} |
|---|
| 132 |
|
|---|
| 133 |
|
|---|
| 134 |
/** Used to process next iteration. */ |
|---|
| 135 |
void yield(V v) { |
|---|
| 136 |
int ret; |
|---|
| 137 |
if (_iter_curctx !is null) { |
|---|
| 138 |
ret = _iter_curctx(v); |
|---|
| 139 |
} else if (_iter_curctx2 !is null) { |
|---|
| 140 |
int i = ++_iter_count; |
|---|
| 141 |
ret = _iter_curctx2(i, v); |
|---|
| 142 |
assert(i == _iter_count, "Inout index error"); |
|---|
| 143 |
} else { |
|---|
| 144 |
assert(false, "Iterator context not initialized"); |
|---|
| 145 |
} |
|---|
| 146 |
if (ret != 0) { |
|---|
| 147 |
throw new IterBreak(ret); |
|---|
| 148 |
} |
|---|
| 149 |
} |
|---|
| 150 |
|
|---|
| 151 |
/** Used to process last iteration. */ |
|---|
| 152 |
void last(V v) { |
|---|
| 153 |
yield(v); |
|---|
| 154 |
throw new IterLast(0); |
|---|
| 155 |
} |
|---|
| 156 |
} |
|---|
| 157 |
|
|---|
| 158 |
/** V type Iterator for method metoda0 */ |
|---|
| 159 |
class Iterator (V) { |
|---|
| 160 |
private int delegate(Iterator!(V)) metoda; |
|---|
| 161 |
/** */ |
|---|
| 162 |
this(int delegate(Iterator!(V)) metoda0) { |
|---|
| 163 |
metoda = metoda0; |
|---|
| 164 |
} |
|---|
| 165 |
|
|---|
| 166 |
private int delegate(inout V) _iter_curctx; |
|---|
| 167 |
private int delegate(inout int, inout V) _iter_curctx2; |
|---|
| 168 |
private int _iter_count; |
|---|
| 169 |
|
|---|
| 170 |
int opApply(int delegate(inout V) fn) { |
|---|
| 171 |
assert(_iter_curctx is null && _iter_curctx2 is null, "Another iteration on this object in progress"); |
|---|
| 172 |
_iter_curctx = fn; |
|---|
| 173 |
try { |
|---|
| 174 |
return metoda(this); |
|---|
| 175 |
} catch (IterBreak ib) { |
|---|
| 176 |
return ib.ret; |
|---|
| 177 |
} catch (IterLast il) { |
|---|
| 178 |
return il.ret; |
|---|
| 179 |
} finally { |
|---|
| 180 |
_iter_curctx = null; |
|---|
| 181 |
} |
|---|
| 182 |
} |
|---|
| 183 |
|
|---|
| 184 |
int opApply(int delegate(inout int, inout V) fn) { |
|---|
| 185 |
assert(_iter_curctx is null && _iter_curctx2 is null, "Another iteration on this object in progress"); |
|---|
| 186 |
_iter_curctx2 = fn; |
|---|
| 187 |
_iter_count = 0; |
|---|
| 188 |
try { |
|---|
| 189 |
return metoda(this); |
|---|
| 190 |
} catch (IterBreak ib) { |
|---|
| 191 |
return ib.ret; |
|---|
| 192 |
} catch (IterLast il) { |
|---|
| 193 |
return il.ret; |
|---|
| 194 |
} finally { |
|---|
| 195 |
_iter_curctx2 = null; |
|---|
| 196 |
} |
|---|
| 197 |
} |
|---|
| 198 |
|
|---|
| 199 |
/** Used to process next iteration. */ |
|---|
| 200 |
void yield(V v) { |
|---|
| 201 |
int ret; |
|---|
| 202 |
if (_iter_curctx !is null) { |
|---|
| 203 |
ret = _iter_curctx(v); |
|---|
| 204 |
} else if (_iter_curctx2 !is null) { |
|---|
| 205 |
int i = ++_iter_count; |
|---|
| 206 |
ret = _iter_curctx2(i, v); |
|---|
| 207 |
assert(i == _iter_count, "Inout index error"); |
|---|
| 208 |
} else { |
|---|
| 209 |
assert(false, "Iterator context not initialized"); |
|---|
| 210 |
} |
|---|
| 211 |
if (ret != 0) { |
|---|
| 212 |
throw new IterBreak(ret); |
|---|
| 213 |
} |
|---|
| 214 |
} |
|---|
| 215 |
|
|---|
| 216 |
/** Used to process last iteration. */ |
|---|
| 217 |
void last(V v) { |
|---|
| 218 |
yield(v); |
|---|
| 219 |
throw new IterLast(0); |
|---|
| 220 |
} |
|---|
| 221 |
} |
|---|
| 222 |
|
|---|
| 223 |
/** Mixin this template to use subclass as iterator. |
|---|
| 224 |
* Use this when you want multiple iterators. |
|---|
| 225 |
* Example: |
|---|
| 226 |
* ------- |
|---|
| 227 |
* class MNaturals(int n) { |
|---|
| 228 |
* int iter2(Iterator!(double) x) { |
|---|
| 229 |
* for (int i = 1; i <= n; i++) x.yield(i*i); |
|---|
| 230 |
* return 0; |
|---|
| 231 |
* } |
|---|
| 232 |
* mixin inneriter!(double, iter2) squers; |
|---|
| 233 |
* int iter3(Iterator!(double) x) { |
|---|
| 234 |
* for (int i = 1; i <= n; i++) x.yield(i*i*i); |
|---|
| 235 |
* return 0; |
|---|
| 236 |
* } |
|---|
| 237 |
* mixin inneriter!(double, iter3) qubes; |
|---|
| 238 |
* } |
|---|
| 239 |
* ... |
|---|
| 240 |
* auto s = new MNaturals!(10)(); |
|---|
| 241 |
* foreach (int x; s.squers.ic()) { |
|---|
| 242 |
* ... |
|---|
| 243 |
* } |
|---|
| 244 |
* foreach (int x; s.qubes.ic()) { |
|---|
| 245 |
* ... |
|---|
| 246 |
* } |
|---|
| 247 |
* ------- |
|---|
| 248 |
*/ |
|---|
| 249 |
|
|---|
| 250 |
template inneriter (V, alias metoda) { |
|---|
| 251 |
Iterator!(V) ic() { |
|---|
| 252 |
return new Iterator!(V)(&metoda); |
|---|
| 253 |
} |
|---|
| 254 |
} |
|---|