Skip to content

Commit 00d2298

Browse files
committed
Refactoring to improve readability.
1 parent f27385e commit 00d2298

File tree

10 files changed

+124
-52
lines changed

10 files changed

+124
-52
lines changed

src/main/java/org/javimmutable/collections/array/TrieArrayNode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ public GenericIterator.State<V> iterateOverRange(@Nullable GenericIterator.State
811811
final int valueIndex = indexForBit(bit);
812812
final int arrayIndex = arrayIndexForBit(valuesBitmask, bit);
813813
final int entryIndex = baseIndex + shift(shiftCount, valueIndex);
814-
iterables.add(GenericIterator.valueIterable(valueFunction.apply(valueIndex, arrayIndex)));
814+
iterables.add(GenericIterator.singleValueIterable(valueFunction.apply(valueIndex, arrayIndex)));
815815
}
816816
if (bitIsPresent(nodesBitmask, bit)) {
817817
final int nodeIndex = arrayIndexForBit(nodesBitmask, bit);
@@ -820,7 +820,7 @@ public GenericIterator.State<V> iterateOverRange(@Nullable GenericIterator.State
820820
combinedBitmask = removeBit(combinedBitmask, bit);
821821
}
822822
assert iterables.size() == (values.length + nodes.length);
823-
return GenericIterator.indexedState(parent, IndexedList.retained(iterables), offset, limit);
823+
return GenericIterator.multiIterableState(parent, IndexedList.retained(iterables), offset, limit);
824824
}
825825

826826
@Override
@@ -857,7 +857,7 @@ public GenericIterator.State<V> iterateOverRange(@Nullable GenericIterator.State
857857
combinedBitmask = removeBit(combinedBitmask, bit);
858858
}
859859
assert iterables.size() == (values.length + nodes.length);
860-
return GenericIterator.indexedState(parent, IndexedList.retained(iterables), offset, limit);
860+
return GenericIterator.multiIterableState(parent, IndexedList.retained(iterables), offset, limit);
861861
}
862862

863863
@Override

src/main/java/org/javimmutable/collections/hash/map/ArraySingleValueMapNode.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,21 +140,21 @@ public ArrayMapNode<K, V> delete(@Nonnull CollisionMap<K, V> collisionMap,
140140
@Override
141141
public GenericIterator.Iterable<K> keys(@Nonnull CollisionMap<K, V> collisionMap)
142142
{
143-
return GenericIterator.valueIterable(key);
143+
return GenericIterator.singleValueIterable(key);
144144
}
145145

146146
@Nonnull
147147
@Override
148148
public GenericIterator.Iterable<V> values(@Nonnull CollisionMap<K, V> collisionMap)
149149
{
150-
return GenericIterator.valueIterable(value);
150+
return GenericIterator.singleValueIterable(value);
151151
}
152152

153153
@Nonnull
154154
@Override
155155
public GenericIterator.Iterable<JImmutableMap.Entry<K, V>> entries(@Nonnull CollisionMap<K, V> collisionMap)
156156
{
157-
return GenericIterator.valueIterable(MapEntry.entry(key, value));
157+
return GenericIterator.singleValueIterable(MapEntry.entry(key, value));
158158
}
159159

160160
@Override

src/main/java/org/javimmutable/collections/hash/set/ArraySingleValueSetNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public ArraySetNode<T> delete(@Nonnull CollisionSet<T> collisionSet,
9393
@Override
9494
public GenericIterator.Iterable<T> values(@Nonnull CollisionSet<T> collisionSet)
9595
{
96-
return GenericIterator.valueIterable(value);
96+
return GenericIterator.singleValueIterable(value);
9797
}
9898

9999
@Override

src/main/java/org/javimmutable/collections/inorder/token_list/TrieNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ public GenericIterator.State<V> iterateOverRange(@Nullable GenericIterator.State
379379
if (bitIsPresent(valuesBitmask, bit)) {
380380
final int valueIndex = indexForBit(bit);
381381
final int arrayIndex = arrayIndexForBit(valuesBitmask, bit);
382-
iterables.add(GenericIterator.valueIterable(valueFunction.apply(valueIndex, arrayIndex)));
382+
iterables.add(GenericIterator.singleValueIterable(valueFunction.apply(valueIndex, arrayIndex)));
383383
}
384384
if (bitIsPresent(nodesBitmask, bit)) {
385385
final int nodeIndex = arrayIndexForBit(nodesBitmask, bit);
@@ -388,7 +388,7 @@ public GenericIterator.State<V> iterateOverRange(@Nullable GenericIterator.State
388388
combinedBitmask = removeBit(combinedBitmask, bit);
389389
}
390390
assert iterables.size() == (values.length + nodes.length);
391-
return GenericIterator.indexedState(parent, IndexedList.retained(iterables), offset, limit);
391+
return GenericIterator.multiIterableState(parent, IndexedList.retained(iterables), offset, limit);
392392
}
393393

394394
@Override

src/main/java/org/javimmutable/collections/iterators/GenericIterator.java

Lines changed: 109 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,25 @@
4747
import javax.annotation.concurrent.ThreadSafe;
4848
import 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
5159
public 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;

src/main/java/org/javimmutable/collections/list/BranchNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ public GenericIterator.State<T> iterateOverRange(@Nullable GenericIterator.State
427427
int limit)
428428
{
429429
assert offset >= 0 && limit <= size && offset <= limit;
430-
return GenericIterator.indexedState(parent, IndexedHelper.indexed(left, right), offset, limit);
430+
return GenericIterator.multiIterableState(parent, IndexedHelper.indexed(left, right), offset, limit);
431431
}
432432

433433
@Override

src/main/java/org/javimmutable/collections/list/OneValueNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ public GenericIterator.State<T> iterateOverRange(@Nullable GenericIterator.State
245245
int offset,
246246
int limit)
247247
{
248-
return GenericIterator.valueState(parent, value);
248+
return GenericIterator.singleValueState(parent, value);
249249
}
250250

251251
@Override

src/main/java/org/javimmutable/collections/tree/LeafNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ public GenericIterator.State<JImmutableMap.Entry<K, V>> iterateOverRange(@Nullab
260260
int offset,
261261
int limit)
262262
{
263-
return GenericIterator.valueState(parent, asEntry());
263+
return GenericIterator.singleValueState(parent, asEntry());
264264
}
265265

266266
@Override

0 commit comments

Comments
 (0)