Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 0f7594f115c366703fa422f8af02480d4e76587d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*******************************************************************************
 * Copyright (c) 2005, 2007 Oracle. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0, which accompanies this distribution
 * and is available at http://www.eclipse.org/legal/epl-v10.html.
 * 
 * Contributors:
 *     Oracle - initial API and implementation
 ******************************************************************************/
package org.eclipse.jpt.utility.internal.iterators;

import java.util.Iterator;
import java.util.NoSuchElementException;
import org.eclipse.jpt.utility.internal.StringTools;

/**
 * A <code>ChainIterator</code> provides a pluggable <code>Iterator</code>
 * that loops over a chain of arbitrarily linked objects. The chain
 * should be null-terminated (i.e. a call to the <code>nextLink(Object)</code>
 * method should return <code>null</code> when it is passed the last
 * link of the chain).
 * To use, supply a starting link and supply a <code>Linker</code> or 
 * subclass <code>ChainIterator</code> and override the
 * <code>nextLink(Object)</code> method.
 * The starting link will be the first object returned by the iterator.
 * If the starting link is <code>null</code>, the iterator will be empty.
 * Note that the iterator does not support <code>null</code> elements.
 */
public class ChainIterator<E>
	implements Iterator<E>
{
	private E nextLink;
	private final Linker<E> linker;


	/**
	 * Construct an iterator with the specified starting link
	 * and a linker that simply returns null, indicating the end of the chain.
	 * Use this constructor if you want to override the
	 * <code>nextLink(Object)</code> method instead of building
	 * a <code>Linker</code>.
	 */
	public ChainIterator(E startLink) {
		this(startLink, Linker.Null.<E>instance());
	}
	
	/**
	 * Construct an iterator with the specified starting link
	 * and linker.
	 */
	public ChainIterator(E startLink, Linker<E> linker) {
		super();
		this.nextLink = startLink;
		this.linker = linker;
	}
	
	public boolean hasNext() {
		return this.nextLink != null;
	}
	
	public E next() {
		if (this.nextLink == null) {
			throw new NoSuchElementException();
		}
		E result = this.nextLink;
		this.nextLink = this.nextLink(this.nextLink);
		return result;
	}
	
	public void remove() {
		throw new UnsupportedOperationException();
	}
	
	/**
	 * Return the next link in the chain.
	 */
	protected E nextLink(E currentLink) {
		return this.linker.nextLink(currentLink);
	}
	
	@Override
	public String toString() {
		return StringTools.buildToStringFor(this, this.nextLink);
	}
	

	//********** inner classes **********

	/**
	 * Used by <code>ChainIterator</code> to link
	 * the elements in the chain.
	 */
	public interface Linker<T> {

		/**
		 * Return the next link in the chain.
		 */
		T nextLink(T currentLink);


		final class Null<S> implements Linker<S> {
			@SuppressWarnings("unchecked")
			public static final Linker INSTANCE = new Null();
			@SuppressWarnings("unchecked")
			public static <R> Linker<R> instance() {
				return INSTANCE;
			}
			// ensure single instance
			private Null() {
				super();
			}
			// simply return null, indicating the chain is ended
			public S nextLink(S currentLink) {
				return null;
			}
			@Override
			public String toString() {
				return "ChainIterator.Linker.Null";
			}
		}

	}

}

Back to the top