KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > ext > Generator


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2006 Ola Bini <ola@ologix.com>
15  *
16  * Alternatively, the contents of this file may be used under the terms of
17  * either of the GNU General Public License Version 2 or later (the "GPL"),
18  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19  * in which case the provisions of the GPL or the LGPL are applicable instead
20  * of those above. If you wish to allow use of your version of this file only
21  * under the terms of either the GPL or the LGPL, and not to allow others to
22  * use your version of this file under the terms of the CPL, indicate your
23  * decision by deleting the provisions above and replace them with the notice
24  * and other provisions required by the GPL or the LGPL. If you do not delete
25  * the provisions above, a recipient may use your version of this file under
26  * the terms of any one of the CPL, the GPL or the LGPL.
27  ***** END LICENSE BLOCK *****/

28 package org.jruby.ext;
29
30 import java.io.IOException JavaDoc;
31
32 import org.jruby.Ruby;
33 import org.jruby.RubyClass;
34 import org.jruby.RubyObject;
35 import org.jruby.RubyProc;
36
37 import org.jruby.runtime.Arity;
38 import org.jruby.runtime.Block;
39 import org.jruby.runtime.CallBlock;
40 import org.jruby.runtime.BlockCallback;
41 import org.jruby.runtime.ThreadContext;
42 import org.jruby.runtime.Visibility;
43 import org.jruby.runtime.load.Library;
44 import org.jruby.runtime.builtin.IRubyObject;
45
46 import org.jruby.internal.runtime.methods.MultiStub;
47 import org.jruby.internal.runtime.methods.MultiStubMethod;
48
49 /**
50  * @author <a HREF="mailto:ola.bini@ki.se">Ola Bini</a>
51  */

52 public class Generator {
53     public static class Service implements Library {
54         public void load(final Ruby runtime) throws IOException JavaDoc {
55             createGenerator(runtime);
56         }
57     }
58
59     public static void createGenerator(Ruby runtime) throws IOException JavaDoc {
60         RubyClass cGen = runtime.defineClass("Generator",runtime.getObject(), runtime.getObject().getAllocator());
61         cGen.includeModule(runtime.getModule("Enumerable"));
62
63         GenStub0 gstub = new GenStub0();
64         gstub.gen_new = new MultiStubMethod(gstub,0,cGen,Arity.optional(),Visibility.PUBLIC);
65         gstub.gen_initialize = new MultiStubMethod(gstub,1,cGen,Arity.optional(),Visibility.PUBLIC);
66         gstub.gen_yield = new MultiStubMethod(gstub,2,cGen,Arity.singleArgument(),Visibility.PUBLIC);
67         gstub.gen_end_p = new MultiStubMethod(gstub,3,cGen,Arity.noArguments(),Visibility.PUBLIC);
68         gstub.gen_next_p = new MultiStubMethod(gstub,4,cGen,Arity.noArguments(),Visibility.PUBLIC);
69         gstub.gen_index = new MultiStubMethod(gstub,5,cGen,Arity.noArguments(),Visibility.PUBLIC);
70         gstub.gen_next = new MultiStubMethod(gstub,6,cGen,Arity.noArguments(),Visibility.PUBLIC);
71         gstub.gen_current = new MultiStubMethod(gstub,7,cGen,Arity.noArguments(),Visibility.PUBLIC);
72         gstub.gen_rewind = new MultiStubMethod(gstub,8,cGen,Arity.noArguments(),Visibility.PUBLIC);
73         gstub.gen_each = new MultiStubMethod(gstub,9,cGen,Arity.noArguments(),Visibility.PUBLIC);
74        
75         cGen.getMetaClass().addMethod("new",gstub.gen_new);
76         cGen.addMethod("initialize",gstub.gen_initialize);
77         cGen.addMethod("yield",gstub.gen_yield);
78         cGen.addMethod("end?",gstub.gen_end_p);
79         cGen.addMethod("next?",gstub.gen_next_p);
80         cGen.addMethod("index",gstub.gen_index);
81         cGen.defineAlias("pos","index");
82         cGen.addMethod("next",gstub.gen_next);
83         cGen.addMethod("current",gstub.gen_current);
84         cGen.addMethod("rewind",gstub.gen_rewind);
85         cGen.addMethod("each",gstub.gen_each);
86     }
87
88     static class GeneratorData implements Runnable JavaDoc {
89         private IRubyObject gen;
90         private Object JavaDoc mutex = new Object JavaDoc();
91
92         private IRubyObject enm;
93         private RubyProc proc;
94
95         private Thread JavaDoc t;
96         private boolean end;
97         private IterBlockCallback ibc;
98
99         public GeneratorData(IRubyObject gen) {
100             this.gen = gen;
101         }
102
103         public void setEnum(IRubyObject enm) {
104             this.proc = null;
105             this.enm = enm;
106             start();
107         }
108
109         public void setProc(RubyProc proc) {
110             this.proc = proc;
111             this.enm = null;
112             start();
113         }
114
115         public void start() {
116             end = false;
117             ibc = new IterBlockCallback();
118             t = new Thread JavaDoc(this);
119             t.setDaemon(true);
120             t.start();
121             generate();
122         }
123
124         public boolean isEnd() {
125             return end;
126         }
127
128         private boolean available = false;
129
130         public void doWait() {
131             available = true;
132             if(proc != null) {
133                 boolean inter = true;
134                 synchronized(mutex) {
135                     mutex.notifyAll();
136                     while(inter) {
137                         try {
138                             mutex.wait();
139                             inter = false;
140                         } catch(InterruptedException JavaDoc e) {
141                         }
142                     }
143                 }
144             }
145         }
146
147         public void generate() {
148             if(proc == null) {
149                 boolean inter = true;
150                 synchronized(mutex) {
151                     while(!ibc.haveValue() && !end) {
152                         mutex.notifyAll();
153                         inter = true;
154                         while(inter) {
155                             try {
156                                 mutex.wait();
157                                 inter = false;
158                             } catch(InterruptedException JavaDoc e) {
159                             }
160                         }
161                     }
162                     if(!end && proc == null) {
163                         gen.callMethod(gen.getRuntime().getCurrentContext(),"yield",ibc.pop());
164                     }
165                 }
166             } else {
167                 synchronized(mutex) {
168                     while(!available && !end) {
169                         boolean inter = true;
170                         mutex.notifyAll();
171                         while(inter) {
172                             try {
173                                 mutex.wait(20);
174                                 inter = false;
175                             } catch(InterruptedException JavaDoc e) {
176                             }
177                         }
178                     }
179                     available = false;
180                 }
181             }
182
183         }
184
185         private class IterBlockCallback implements BlockCallback {
186             private IRubyObject obj;
187             public IRubyObject call(ThreadContext context, IRubyObject[] iargs, IRubyObject iself, Block block) {
188                 boolean inter = true;
189                 synchronized(mutex) {
190                     mutex.notifyAll();
191                     while(inter) {
192                         try {
193                             mutex.wait();
194                             inter = false;
195                         } catch(InterruptedException JavaDoc e) {
196                         }
197                     }
198                     if(iargs.length > 1) {
199                         obj = gen.getRuntime().newArrayNoCopy(iargs);
200                     } else {
201                         obj = iargs[0];
202                     }
203                     mutex.notifyAll();
204                     return gen.getRuntime().getNil();
205                 }
206             }
207             public boolean haveValue() {
208                 return obj != null;
209             }
210             public IRubyObject pop() {
211                 IRubyObject a = obj;
212                 obj = null;
213                 return a;
214             }
215         }
216
217         public void run() {
218             if(enm != null) {
219                 ThreadContext context = gen.getRuntime().getCurrentContext();
220                 enm.callMethod(context, "each", new CallBlock(enm,enm.getMetaClass().getRealClass(),Arity.noArguments(),ibc,context));
221             } else {
222                 proc.call(new IRubyObject[]{gen});
223             }
224             end = true;
225         }
226     }
227
228     public static class GenStub0 implements MultiStub {
229         public MultiStubMethod gen_new;
230         public MultiStubMethod gen_initialize;
231         public MultiStubMethod gen_yield;
232         public MultiStubMethod gen_end_p;
233         public MultiStubMethod gen_next_p;
234         public MultiStubMethod gen_index;
235         public MultiStubMethod gen_next;
236         public MultiStubMethod gen_current;
237         public MultiStubMethod gen_rewind;
238         public MultiStubMethod gen_each;
239
240         public IRubyObject method0(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
241             // Generator#new
242
IRubyObject result = new RubyObject(self.getRuntime(),(RubyClass)self);
243             result.dataWrapStruct(new GeneratorData(result));
244             result.callInit(args, block);
245             return result;
246         }
247
248         public IRubyObject method1(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
249             // Generator#initialize
250
GeneratorData d = (GeneratorData)self.dataGetStruct();
251
252             self.setInstanceVariable("@queue",self.getRuntime().newArray());
253             self.setInstanceVariable("@index",self.getRuntime().newFixnum(0));
254
255             if(self.checkArgumentCount(args,0,1) == 1) {
256                 d.setEnum(args[0]);
257             } else {
258                 d.setProc(self.getRuntime().newProc(false, Block.NULL_BLOCK));
259             }
260             return self;
261         }
262
263         public IRubyObject method2(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
264             // Generator#yield
265
self.getInstanceVariable("@queue").callMethod(context,"<<",args[0]);
266             GeneratorData d = (GeneratorData)self.dataGetStruct();
267             d.doWait();
268             return self;
269         }
270
271         public IRubyObject method3(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
272             // Generator#end_p
273
GeneratorData d = (GeneratorData)self.dataGetStruct();
274             return d.isEnd() ? self.getRuntime().getTrue() : self.getRuntime().getFalse();
275         }
276
277         public IRubyObject method4(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
278             // Generator#next_p
279
GeneratorData d = (GeneratorData)self.dataGetStruct();
280             return !d.isEnd() ? self.getRuntime().getTrue() : self.getRuntime().getFalse();
281         }
282
283         public IRubyObject method5(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
284             // Generator#index
285
return self.getInstanceVariable("@index");
286         }
287
288         public IRubyObject method6(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
289             // Generator#next
290
GeneratorData d = (GeneratorData)self.dataGetStruct();
291             if(d.isEnd()) {
292                 throw self.getRuntime().newEOFError();
293             }
294             d.generate();
295             self.setInstanceVariable("@index",self.getInstanceVariable("@index").callMethod(context,"+",self.getRuntime().newFixnum(1)));
296             return self.getInstanceVariable("@queue").callMethod(context,"shift");
297         }
298
299         public IRubyObject method7(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
300             // Generator#current
301
if(self.getInstanceVariable("@queue").callMethod(context,"empty?").isTrue()) {
302                 throw self.getRuntime().newEOFError();
303             }
304             return self.getInstanceVariable("@queue").callMethod(context,"first");
305         }
306
307         public IRubyObject method8(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
308             // Generator#rewind
309
if(self.getInstanceVariable("@index").callMethod(context,"nonzero?").isTrue()) {
310                 GeneratorData d = (GeneratorData)self.dataGetStruct();
311
312                 self.setInstanceVariable("@queue",self.getRuntime().newArray());
313                 self.setInstanceVariable("@index",self.getRuntime().newFixnum(0));
314             
315                 d.start();
316             }
317
318             return self;
319         }
320
321         public IRubyObject method9(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
322             // Generator#each
323
self.callMethod(context,"rewind");
324             while(self.callMethod(context,"next?").isTrue()) {
325                 context.yield(self.callMethod(context,"next"), block);
326             }
327             return self;
328         }
329     }
330 }// Generator
331
Popular Tags