1+ package javaxt .utils ;
2+ import java .util .Iterator ;
3+ import java .util .NoSuchElementException ;
4+
5+ //******************************************************************************
6+ //** Generator
7+ //******************************************************************************
8+ /**
9+ * A custom iterator that yields its values one at a time. This is a great
10+ * alternative to arrays or lists when dealing with large data. By yielding
11+ * one entry at a time, this iterator can help avoid out of memory exceptions.
12+ *
13+ * Subclasses must define a method called {@link #run()} and may call
14+ * {@link yield(T)} to return values one at a time.
15+ *
16+ * @author Adrian Kuhn <akuhn(at)iam.unibe.ch>
17+ * @see http://smallwiki.unibe.ch/adriankuhn/yield4java/
18+ *
19+ ******************************************************************************/
20+
21+ public abstract class Generator <T > implements Iterable <T > {
22+
23+ public abstract void run ();
24+
25+ public Iterator <T > iterator () {
26+ return new Iter ();
27+ }
28+
29+ private static final Object DONE = new Object ();
30+ private static final Object EMPTY = new Object ();
31+ private Object drop = EMPTY ;
32+ private Thread th = null ;
33+
34+ private synchronized Object take () {
35+ while (drop == EMPTY ) {
36+ try {
37+ wait ();
38+ } catch (InterruptedException ex ) {
39+ Thread .currentThread ().interrupt ();
40+ }
41+ }
42+ Object temp = drop ;
43+ if (drop != DONE )
44+ drop = EMPTY ;
45+ notifyAll ();
46+ return temp ;
47+ }
48+
49+ private synchronized void put (Object value ) {
50+ if (drop == DONE )
51+ throw new IllegalStateException ();
52+ if (drop != EMPTY )
53+ throw new IllegalStateException ();
54+ drop = value ;
55+ notifyAll ();
56+ while (drop != EMPTY ) {
57+ try {
58+ wait ();
59+ } catch (InterruptedException ex ) {
60+ Thread .currentThread ().interrupt ();
61+ }
62+ }
63+ }
64+
65+ protected void yield (T value ) {
66+ put (value );
67+ }
68+
69+ public synchronized void done () {
70+ if (drop == DONE )
71+ throw new IllegalStateException ();
72+ if (drop != EMPTY )
73+ throw new IllegalStateException ();
74+ drop = DONE ;
75+ notifyAll ();
76+ }
77+
78+ private class Iter implements Iterator <T >, Runnable {
79+
80+ private Object next = EMPTY ;
81+
82+ public Iter () {
83+ if (th != null )
84+ throw new IllegalStateException ("Can not run coroutine twice" );
85+ th = new Thread (this );
86+ th .setDaemon (true );
87+ th .start ();
88+ }
89+
90+ public void run () {
91+ Generator .this .run ();
92+ done ();
93+ }
94+
95+ public boolean hasNext () {
96+ if (next == EMPTY )
97+ next = take ();
98+ return next != DONE ;
99+ }
100+
101+ @ SuppressWarnings ("unchecked" )
102+ public T next () {
103+ if (next == EMPTY )
104+ next = take ();
105+ if (next == DONE )
106+ throw new NoSuchElementException ();
107+ Object temp = next ;
108+ next = EMPTY ;
109+ return (T ) temp ;
110+ }
111+
112+ public void remove () {
113+ throw new UnsupportedOperationException ();
114+
115+ }
116+
117+ @ SuppressWarnings ("deprecation" )
118+ @ Override
119+ protected void finalize () throws Throwable {
120+ th .stop (); // let's commit suicide
121+ }
122+
123+ }
124+
125+ }
0 commit comments