4747import javax .annotation .concurrent .ThreadSafe ;
4848import java .util .NoSuchElementException ;
4949
50+ /**
51+ * A mutable class implementing the SplitableIterator interface in a reusable way.
52+ * Maintains a current position in the collection it iterates over and delegates
53+ * to a "state" object provided by the collection to move forward inside the collection.
54+ * To implement spliterator functionality for parallel streams it limits itself to
55+ * a specific subset of the collection by way of an offset (current position) and
56+ * limit (stopping position).
57+ */
5058@ ThreadSafe
5159public class GenericIterator <T >
5260 extends AbstractSplitableIterator <T >
5361{
5462 static final int MIN_SIZE_FOR_SPLIT = 32 ;
5563
56- private final Iterable <T > root ;
57- private final int limit ;
58- private int offset ;
59- private boolean uninitialized ;
60- private State <T > state ;
64+ private final Iterable <T > root ; // the collection we are iterating over
65+ private final int limit ; // stopping position in our allowed range
66+ private int offset ; // current position in our allowed range
67+ private boolean uninitialized ; // true until next or hasNext has been called first time
68+ private State <T > state ; // tracks the next available position in the collection
6169
6270 public GenericIterator (@ Nonnull Iterable <T > root ,
6371 int offset ,
@@ -70,9 +78,24 @@ public GenericIterator(@Nonnull Iterable<T> root,
7078 uninitialized = true ;
7179 }
7280
81+ /**
82+ * Interface for collections that can be iterated over by GenericIterator using State objects
83+ * to track the progress of the iteration. These do not need to be thread safe.
84+ */
7385 public interface Iterable <T >
7486 extends SplitableIterable <T >
7587 {
88+ /**
89+ * Create a State to iterate over the specified range of values if possible.
90+ * Can return null if no more values are available. The range must be valid
91+ * for the collection being iterated over. The returned State will return the
92+ * parent as its result when iteration over the range is completed.
93+ *
94+ * @param parent State to return to once the request iteration completes
95+ * @param offset starting point for iteration
96+ * @param limit stopping point for iteration
97+ * @return null or a valid state
98+ */
7699 @ Nullable
77100 State <T > iterateOverRange (@ Nullable State <T > parent ,
78101 int offset ,
@@ -107,6 +130,13 @@ public int getSpliteratorCharacteristics()
107130 }
108131 }
109132
133+ /**
134+ * Interface for objects that track the current position of an iteration in progress.
135+ * Unlike an Iterator which "looks ahead" to the next position (hasNext/next) a
136+ * State object "lives in the moment" and knows the current position (hasValue/value)
137+ * and doesn't know if a next value exists until told to go there (advance).
138+ * These do not need to be thread safe.
139+ */
110140 public interface State <T >
111141 {
112142 default boolean hasValue ()
@@ -119,19 +149,26 @@ default T value()
119149 throw new NoSuchElementException ();
120150 }
121151
152+ /**
153+ * Try to move forward to the next position. Returns either a valid state (if next position exists)
154+ * or null (if there is no next position). The returned State might be this State object or a new
155+ * State, or null. The returned State might have a value or it might be empty.
156+ */
122157 State <T > advance ();
123158 }
124159
125160 @ Override
126161 public synchronized boolean hasNext ()
127162 {
128- return prepare ();
163+ advanceStateToStartingPositionIfNecessary ();
164+ return stateHasValue ();
129165 }
130166
131167 @ Override
132168 public synchronized T next ()
133169 {
134- if (!prepare ()) {
170+ advanceStateToStartingPositionIfNecessary ();
171+ if (!stateHasValue ()) {
135172 throw new NoSuchElementException ();
136173 }
137174 final T answer = state .value ();
@@ -160,28 +197,40 @@ public synchronized SplitIterator<T> splitIterator()
160197 new GenericIterator <>(root , splitIndex , limit ));
161198 }
162199
163- private boolean prepare ()
200+ /**
201+ * Ensures that state is on a valid position if possible. Gets a starting state if we are
202+ * starting a new iteration otherwise it calls advance if necessary to move to the first
203+ * available position.
204+ */
205+ private void advanceStateToStartingPositionIfNecessary ()
164206 {
165207 if (uninitialized ) {
166208 state = root .iterateOverRange (null , offset , limit );
167209 uninitialized = false ;
168210 }
169- while (state != null ) {
170- if (state .hasValue ()) {
171- return true ;
172- }
211+ while (state != null && !state .hasValue ()) {
173212 state = state .advance ();
174213 }
175- return false ;
176214 }
177215
178- public static <T > State <T > valueState (State <T > parent ,
179- T value )
216+ private boolean stateHasValue ()
217+ {
218+ return state != null && state .hasValue ();
219+ }
220+
221+ /**
222+ * Returns a State for iterating a single value.
223+ */
224+ public static <T > State <T > singleValueState (State <T > parent ,
225+ T value )
180226 {
181227 return new SingleValueState <>(parent , value );
182228 }
183229
184- public static <T > Iterable <T > valueIterable (T value )
230+ /**
231+ * Returns an Iterable for iterating a single value.
232+ */
233+ public static <T > Iterable <T > singleValueIterable (T value )
185234 {
186235 return new Iterable <T >()
187236 {
@@ -194,7 +243,7 @@ public State<T> iterateOverRange(@Nullable State<T> parent,
194243 if (offset == limit ) {
195244 return parent ;
196245 } else {
197- return new SingleValueState <T >(parent , value );
246+ return new SingleValueState <>(parent , value );
198247 }
199248 }
200249
@@ -206,6 +255,9 @@ public int iterableSize()
206255 };
207256 }
208257
258+ /**
259+ * Returns a State for iterating multiple values stored in an Indexed collection.
260+ */
209261 public static <T > State <T > multiValueState (@ Nullable State <T > parent ,
210262 @ Nonnull Indexed <T > values ,
211263 int offset ,
@@ -215,22 +267,30 @@ public static <T> State<T> multiValueState(@Nullable State<T> parent,
215267 return new MultiValueState <>(parent , values , offset , limit );
216268 }
217269
218- public static <T > State <T > indexedState (State <T > parent ,
219- Indexed <? extends Iterable <T >> children ,
220- int offset ,
221- int limit )
270+ /**
271+ * Returns a State for iterating multiple collections (Iterables) that are themselves
272+ * stored in an Indexed collection.
273+ */
274+ public static <T > State <T > multiIterableState (@ Nullable State <T > parent ,
275+ @ Nonnull Indexed <? extends Iterable <T >> children ,
276+ int offset ,
277+ int limit )
222278 {
223279 assert 0 <= offset && offset <= limit ;
224280 if (offset == limit ) {
225281 return parent ;
226282 } else {
227- return new IndexedState <>(parent , children , offset , limit );
283+ return new MultiIterableState <>(parent , children , offset , limit );
228284 }
229285 }
230286
231- public static <A , B > State <B > transformState (State <B > parent ,
232- State <A > source ,
233- Func1 <A , B > transforminator )
287+ /**
288+ * Returns a State for iterating over another State's values but transforming each of
289+ * those values using a function before returning to its caller.
290+ */
291+ public static <A , B > State <B > transformState (@ Nullable State <B > parent ,
292+ @ Nullable State <A > source ,
293+ @ Nonnull Func1 <A , B > transforminator )
234294 {
235295 if (source == null ) {
236296 return parent ;
@@ -239,6 +299,10 @@ public static <A, B> State<B> transformState(State<B> parent,
239299 }
240300 }
241301
302+ /**
303+ * Returns an Iterable for iterating over another Iterable's values but transforming each of
304+ * those values using a function before returning to its caller.
305+ */
242306 public static <A , B > Iterable <B > transformIterable (@ Nonnull Iterable <A > source ,
243307 @ Nonnull Func1 <A , B > transforminator )
244308 {
@@ -268,7 +332,7 @@ private static class SingleValueState<T>
268332 private final T value ;
269333 private boolean available ;
270334
271- private SingleValueState (State <T > parent ,
335+ private SingleValueState (@ Nullable State <T > parent ,
272336 T value )
273337 {
274338 this .parent = parent ;
@@ -342,22 +406,22 @@ public GenericIterator.State<T> advance()
342406 }
343407 }
344408
345- private static class IndexedState <T >
409+ private static class MultiIterableState <T >
346410 implements State <T >
347411 {
348412 private final State <T > parent ;
349- private final Indexed <? extends Iterable <T >> children ;
413+ private final Indexed <? extends Iterable <T >> collections ;
350414 private int offset ;
351415 private int limit ;
352416 private int index ;
353417
354- public IndexedState ( State <T > parent ,
355- Indexed <? extends Iterable <T >> children ,
356- int offset ,
357- int limit )
418+ private MultiIterableState ( @ Nullable State <T > parent ,
419+ @ Nonnull Indexed <? extends Iterable <T >> collections ,
420+ int offset ,
421+ int limit )
358422 {
359423 this .parent = parent ;
360- this .children = children ;
424+ this .collections = collections ;
361425 this .limit = limit ;
362426 this .offset = offset ;
363427 index = 0 ;
@@ -366,17 +430,25 @@ public IndexedState(State<T> parent,
366430 @ Override
367431 public State <T > advance ()
368432 {
369- final Iterable <T > child = children .get (index );
370- final int size = child .iterableSize ();
433+ final Iterable <T > collection = collections .get (index );
434+ final int size = collection .iterableSize ();
371435 if (offset >= size ) {
436+ // Starting point for iteration is somewhere beyond this collection.
437+ // Advance to the next collection to try again. Offset and limit have
438+ // to be adjusted accordingly for the next collection.
372439 index += 1 ;
373440 offset -= size ;
374441 limit -= size ;
375442 return this ;
376443 } else if (limit <= size ) {
377- return child .iterateOverRange (parent , offset , limit );
444+ // this collection contains all remaining values so pass control to it forever
445+ return collection .iterateOverRange (parent , offset , limit );
378446 } else {
379- final State <T > answer = child .iterateOverRange (this , offset , size );
447+ // This collection contains at least one value. Transfer control to it
448+ // passing us as parent so we can resume control once it's exhausted.
449+ // Offset and limit have to be adjusted to resume at the next collection
450+ // when we get control again.
451+ final State <T > answer = collection .iterateOverRange (this , offset , size );
380452 index += 1 ;
381453 offset = 0 ;
382454 limit -= size ;
0 commit comments