root/trunk/infrastructure/st/coroutine.d

Revision 37, 14.4 kB (checked in by KirkMcDonald, 2 years ago)

opApply wrapping and various refactoring

Line 
1 /* *** Automatically generated: do not modify *** */
2 /**
3  * This module contains a simple implementation of coroutines, based on the
4  * StackContext module.  It supports both eagerly and non-eagerly evaluating
5  * coroutines, and coroutines with anywhere from zero to five initial
6  * arguments.
7  *
8  * If you define your coroutine as being both eager, and with an input type of
9  * void, then the coroutine will be usable as an iterator in foreach
10  * statements.
11  *
12  * Version:     0.1
13  * Date:        2006-06-05
14  * Copyright:   Copyright © 2006 Daniel Keep.
15  * Authors:     Daniel Keep, daniel.keep+spam@gmail.com
16  * License:     zlib
17  *
18  * Bugs:
19  *   None (yet).  Well, ok; none that I *know* about.
20  *
21  * History:
22  *   0.1 -  Initial version.
23  */
24 module st.coroutine;
25
26 /*
27  * This software is provided 'as-is', without any express or implied
28  * warranty. In no event will the authors be held liable for any damages
29  * arising from the use of this software.
30  *
31  * Permission is granted to anyone to use this software for any purpose,
32  * including commercial applications, and to alter it and redistribute it
33  * freely, subject to the following restrictions:
34  *
35  * 1. The origin of this software must not be misrepresented; you must not
36  *    claim that you wrote the original software. If you use this software in
37  *    a product, an acknowledgement in the product documentation would be
38  *    appreciated but is not required.
39  *
40  * 2. Altered source versions must be plainly marked as such, and must not be
41  *    misrepresented as being the original software.
42  *
43  * 3. This notice may not be removed or altered from any source distribution.
44  */
45
46 private
47 {
48     import st.stackcontext;
49 }
50
51 /**
52  * This enumeration defines what kind of coroutine you want.
53  */
54 enum
55 CoroType
56 {
57     /**
58      * This is the default.  Coroutines evaluate successive values on-demand.
59      */
60     NonEager,
61
62     /**
63      * Eager coroutines will evaluate the next value in the sequence before
64      * being asked.  This is required for iterator support.
65      */
66     Eager
67 }
68
69 private
70 template
71 CoroutinePublicT(Tin, Tout, CoroType TCoroType)
72 {
73     /// Records what kind of coroutine this is.
74     const CoroType coroType = TCoroType;
75
76     static if( is( Tin == void ) )
77     {
78         /**
79          * Resumes the coroutine.
80          *
81          * Params:
82          *  value = This value will be passed into the coroutine.
83          *
84          * Returns:
85          *  The next value from the coroutine.
86          */
87         final
88         Tout
89         opCall()
90         in
91         {
92             static if( coroType == CoroType.Eager )
93                 assert( this.running );
94             else
95                 assert( context.ready );
96         }
97         body
98         {
99             static if( coroType == CoroType.Eager )
100             {
101                 static if( !is( Tout == void ) )
102                     Tout temp = this.cout;
103
104                 context.run();
105                 if( context.dead )
106                     this.running = false;
107
108                 static if( !is( Tout == void ) )
109                     return temp;
110             }
111             else
112             {
113                 context.run();
114                 static if( !is( Tout == void ) )
115                     return this.cout;
116             }
117         }
118     }
119     else
120     {
121         /**
122          * Resumes the coroutine.
123          *
124          * Params:
125          *  value = This value will be passed into the coroutine.
126          *
127          * Returns:
128          *  The next value from the coroutine.
129          */
130         final
131         Tout
132         opCall(Tin value)
133         in
134         {
135             static if( coroType == CoroType.Eager )
136                 assert( this.running );
137             else
138                 assert( context.ready );
139         }
140         body
141         {
142             this.cin = value;
143
144             static if( coroType == CoroType.Eager )
145             {
146                 static if( !is( Tout == void ) )
147                     Tout temp = this.cout;
148
149                 context.run();
150                 if( context.dead )
151                     this.running = false;
152
153                 static if( !is( Tout == void ) )
154                     return temp;
155             }
156             else
157             {
158                 context.run();
159                 static if( !is( Tout == void ) )
160                     return this.cout;
161             }
162         }
163     }
164
165     static if( is( Tin == void ) )
166     {
167         /**
168          * Returns a delegate that can be used to resume the coroutine.
169          *
170          * Returns:
171          *  A delegate that is equivalent to calling the coroutine directly.
172          */
173         Tout delegate()
174         asDelegate()
175         {
176             return &opCall;
177         }
178     }
179     else
180     {
181         /// ditto
182         Tout delegate(Tin)
183         asDelegate()
184         {
185             return &opCall;
186         }
187     }
188
189     // TODO: Work out how to get iteration working with non-eager coroutines.
190     static if( coroType == CoroType.Eager )
191     {
192         static if( is( Tin == void ) && !is( Tout == void ) )
193         {
194             final
195             int
196             opApply(int delegate(inout Tout) dg)
197             {
198                 int result = 0;
199
200                 while( this.running )
201                 {
202                     Tout argTemp = opCall();
203                     result = dg(argTemp);
204                     if( result )
205                         break;
206                 }
207
208                 return result;
209             }
210
211             final
212             int
213             opApply(int delegate(inout Tout, inout uint) dg)
214             {
215                 int result = 0;
216                 uint counter = 0;
217
218                 while( this.running )
219                 {
220                     Tout argTemp = opCall();
221                     uint counterTemp = counter;
222                     result = dg(argTemp, counterTemp);
223                     if( result )
224                         break;
225                 }
226
227                 return result;
228             }
229         }
230     }
231 }
232
233 private
234 template
235 CoroutineProtectedT(Tin, Tout, CoroType TCoroType)
236 {
237     size_t STACK_SIZE = DEFAULT_STACK_SIZE;
238
239     static if( is( Tout == void ) )
240     {
241         final
242         Tin
243         yield()
244         in
245         {
246             assert( StackContext.getRunning is context );
247         }
248         body
249         {
250             StackContext.yield();
251             static if( is( Tin == void ) ) {}
252             else
253                 return this.cin;
254         }
255     }
256     else
257     {
258         final
259         Tin
260         yield(Tout value)
261         in
262         {
263             assert( StackContext.getRunning is context );
264         }
265         body
266         {
267             this.cout = value;
268             StackContext.yield();
269             static if( is( Tin == void ) ) {}
270             else
271                 return this.cin;
272         }
273     }
274 }
275
276 /**
277  * TODO
278  */
279 class
280 Coroutine(Tin, Tout, CoroType TCoroType = CoroType.NonEager)
281 {
282     mixin CoroutinePublicT!(Tin, Tout, TCoroType);
283
284 protected:
285     mixin CoroutineProtectedT!(Tin, Tout, TCoroType);
286
287     this()
288     {
289        
290         context = new StackContext(&startProc, STACK_SIZE);
291         static if( coroType == CoroType.Eager )
292             context.run();
293     }
294
295     abstract
296     void
297     run();
298
299 private:
300     StackContext context;
301    
302     static if( coroType == CoroType.Eager )
303         bool running = true;
304
305     static if( !is( Tout == void ) )
306         Tout cout;
307
308     static if( !is( Tin == void ) )
309         Tin cin;
310
311    
312
313     void
314     startProc()
315     {
316         // Initial call to coroutine proper
317         run();
318     }
319 }
320
321 /**
322  * TODO
323  */
324 class
325 Coroutine(Tin, Tout, Ta1, CoroType TCoroType = CoroType.NonEager)
326 {
327     mixin CoroutinePublicT!(Tin, Tout, TCoroType);
328
329 protected:
330     mixin CoroutineProtectedT!(Tin, Tout, TCoroType);
331
332     this(Ta1 arg1)
333     {
334         this.arg1 = arg1;
335         context = new StackContext(&startProc, STACK_SIZE);
336         static if( coroType == CoroType.Eager )
337             context.run();
338     }
339
340     abstract
341     void
342     run(Ta1);
343
344 private:
345     StackContext context;
346    
347     static if( coroType == CoroType.Eager )
348         bool running = true;
349
350     static if( !is( Tout == void ) )
351         Tout cout;
352
353     static if( !is( Tin == void ) )
354         Tin cin;
355
356     Ta1 arg1;
357
358     void
359     startProc()
360     {
361         // Initial call to coroutine proper
362         run(arg1);
363     }
364 }
365
366 /**
367  * TODO
368  */
369 class
370 Coroutine(Tin, Tout, Ta1, Ta2, CoroType TCoroType = CoroType.NonEager)
371 {
372     mixin CoroutinePublicT!(Tin, Tout, TCoroType);
373
374 protected:
375     mixin CoroutineProtectedT!(Tin, Tout, TCoroType);
376
377     this(Ta1 arg1, Ta2 arg2)
378     {
379         this.arg1 = arg1;
380         this.arg2 = arg2;
381         context = new StackContext(&startProc, STACK_SIZE);
382         static if( coroType == CoroType.Eager )
383             context.run();
384     }
385
386     abstract
387     void
388     run(Ta1, Ta2);
389
390 private:
391     StackContext context;
392    
393     static if( coroType == CoroType.Eager )
394         bool running = true;
395
396     static if( !is( Tout == void ) )
397         Tout cout;
398
399     static if( !is( Tin == void ) )
400         Tin cin;
401
402     Ta1 arg1;
403     Ta2 arg2;
404
405     void
406     startProc()
407     {
408         // Initial call to coroutine proper
409         run(arg1, arg2);
410     }
411 }
412
413 /**
414  * TODO
415  */
416 class
417 Coroutine(Tin, Tout, Ta1, Ta2, Ta3, CoroType TCoroType = CoroType.NonEager)
418 {
419     mixin CoroutinePublicT!(Tin, Tout, TCoroType);
420
421 protected:
422     mixin CoroutineProtectedT!(Tin, Tout, TCoroType);
423
424     this(Ta1 arg1, Ta2 arg2, Ta3 arg3)
425     {
426         this.arg1 = arg1;
427         this.arg2 = arg2;
428         this.arg3 = arg3;
429         context = new StackContext(&startProc, STACK_SIZE);
430         static if( coroType == CoroType.Eager )
431             context.run();
432     }
433
434     abstract
435     void
436     run(Ta1, Ta2, Ta3);
437
438 private:
439     StackContext context;
440    
441     static if( coroType == CoroType.Eager )
442         bool running = true;
443
444     static if( !is( Tout == void ) )
445         Tout cout;
446
447     static if( !is( Tin == void ) )
448         Tin cin;
449
450     Ta1 arg1;
451     Ta2 arg2;
452     Ta3 arg3;
453
454     void
455     startProc()
456     {
457         // Initial call to coroutine proper
458         run(arg1, arg2, arg3);
459     }
460 }
461
462 /**
463  * TODO
464  */
465 class
466 Coroutine(Tin, Tout, Ta1, Ta2, Ta3, Ta4, CoroType TCoroType = CoroType.NonEager)
467 {
468     mixin CoroutinePublicT!(Tin, Tout, TCoroType);
469
470 protected:
471     mixin CoroutineProtectedT!(Tin, Tout, TCoroType);
472
473     this(Ta1 arg1, Ta2 arg2, Ta3 arg3, Ta4 arg4)
474     {
475         this.arg1 = arg1;
476         this.arg2 = arg2;
477         this.arg3 = arg3;
478         this.arg4 = arg4;
479         context = new StackContext(&startProc, STACK_SIZE);
480         static if( coroType == CoroType.Eager )
481             context.run();
482     }
483
484     abstract
485     void
486     run(Ta1, Ta2, Ta3, Ta4);
487
488 private:
489     StackContext context;
490    
491     static if( coroType == CoroType.Eager )
492         bool running = true;
493
494     static if( !is( Tout == void ) )
495         Tout cout;
496
497     static if( !is( Tin == void ) )
498         Tin cin;
499
500     Ta1 arg1;
501     Ta2 arg2;
502     Ta3 arg3;
503     Ta4 arg4;
504
505     void
506     startProc()
507     {
508         // Initial call to coroutine proper
509         run(arg1, arg2, arg3, arg4);
510     }
511 }
512
513 /**
514  * TODO
515  */
516 class
517 Coroutine(Tin, Tout, Ta1, Ta2, Ta3, Ta4, Ta5, CoroType TCoroType = CoroType.NonEager)
518 {
519     mixin CoroutinePublicT!(Tin, Tout, TCoroType);
520
521 protected:
522     mixin CoroutineProtectedT!(Tin, Tout, TCoroType);
523
524     this(Ta1 arg1, Ta2 arg2, Ta3 arg3, Ta4 arg4, Ta5 arg5)
525     {
526         this.arg1 = arg1;
527         this.arg2 = arg2;
528         this.arg3 = arg3;
529         this.arg4 = arg4;
530         this.arg5 = arg5;
531         context = new StackContext(&startProc, STACK_SIZE);
532         static if( coroType == CoroType.Eager )
533             context.run();
534     }
535
536     abstract
537     void
538     run(Ta1, Ta2, Ta3, Ta4, Ta5);
539
540 private:
541     StackContext context;
542    
543     static if( coroType == CoroType.Eager )
544         bool running = true;
545
546     static if( !is( Tout == void ) )
547         Tout cout;
548
549     static if( !is( Tin == void ) )
550         Tin cin;
551
552     Ta1 arg1;
553     Ta2 arg2;
554     Ta3 arg3;
555     Ta4 arg4;
556     Ta5 arg5;
557
558     void
559     startProc()
560     {
561         // Initial call to coroutine proper
562         run(arg1, arg2, arg3, arg4, arg5);
563     }
564 }
565
566
567 /**
568  * This mixin implements the constructor, and static opCall method for your
569  * coroutine.  It is a good idea to mix this into your coroutine subclasses,
570  * so that you need only override the run method.
571  */
572 template
573 CoroutineMixin(Tin, Tout)
574 {
575     this()
576     {
577         super();
578     }
579 }
580
581 /**
582  * This mixin implements the constructor, and static opCall method for your
583  * coroutine.  It is a good idea to mix this into your coroutine subclasses,
584  * so that you need only override the run method.
585  */
586 template
587 CoroutineMixin(Tin, Tout, Ta1)
588 {
589     this(Ta1 arg1)
590     {
591         super(arg1);
592     }
593 }
594
595 /**
596  * This mixin implements the constructor, and static opCall method for your
597  * coroutine.  It is a good idea to mix this into your coroutine subclasses,
598  * so that you need only override the run method.
599  */
600 template
601 CoroutineMixin(Tin, Tout, Ta1, Ta2)
602 {
603     this(Ta1 arg1, Ta2 arg2)
604     {
605         super(arg1, arg2);
606     }
607 }
608
609 /**
610  * This mixin implements the constructor, and static opCall method for your
611  * coroutine.  It is a good idea to mix this into your coroutine subclasses,
612  * so that you need only override the run method.
613  */
614 template
615 CoroutineMixin(Tin, Tout, Ta1, Ta2, Ta3)
616 {
617     this(Ta1 arg1, Ta2 arg2, Ta3 arg3)
618     {
619         super(arg1, arg2, arg3);
620     }
621 }
622
623 /**
624  * This mixin implements the constructor, and static opCall method for your
625  * coroutine.  It is a good idea to mix this into your coroutine subclasses,
626  * so that you need only override the run method.
627  */
628 template
629 CoroutineMixin(Tin, Tout, Ta1, Ta2, Ta3, Ta4)
630 {
631     this(Ta1 arg1, Ta2 arg2, Ta3 arg3, Ta4 arg4)
632     {
633         super(arg1, arg2, arg3, arg4);
634     }
635 }
636
637 /**
638  * This mixin implements the constructor, and static opCall method for your
639  * coroutine.  It is a good idea to mix this into your coroutine subclasses,
640  * so that you need only override the run method.
641  */
642 template
643 CoroutineMixin(Tin, Tout, Ta1, Ta2, Ta3, Ta4, Ta5)
644 {
645     this(Ta1 arg1, Ta2 arg2, Ta3 arg3, Ta4 arg4, Ta5 arg5)
646     {
647         super(arg1, arg2, arg3, arg4, arg5);
648     }
649 }
Note: See TracBrowser for help on using the browser.