root/trunk/iterators/iterators.d

Revision 13, 6.6 kB (checked in by BCS, 2 years ago)

added Witold Baryluk's iterators

Line 
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 }
Note: See TracBrowser for help on using the browser.