1 /*******************************************************************************
2  * Copyright (c) 2009, 2017 Cloudsmith Inc. and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     Cloudsmith Inc. - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.equinox.internal.p2.metadata.expression;
15 
16 import java.util.*;
17 import org.eclipse.equinox.p2.metadata.index.IIndexProvider;
18 import org.eclipse.equinox.p2.query.IQueryResult;
19 
20 public class RepeatableIterator<T> implements IRepeatableIterator<T> {
21 	private final Collection<T> values;
22 	private final Iterator<T> iterator;
23 
24 	@SuppressWarnings("unchecked")
create(Object unknown)25 	public static <T> IRepeatableIterator<T> create(Object unknown) {
26 		if (unknown.getClass().isArray())
27 			return create((T[]) unknown);
28 		if (unknown instanceof Iterator<?>)
29 			return create((Iterator<T>) unknown);
30 		if (unknown instanceof List<?>)
31 			return create((List<T>) unknown);
32 		if (unknown instanceof Collection<?>)
33 			return create((Collection<T>) unknown);
34 		if (unknown instanceof Map<?, ?>)
35 			return create((Set<T>) ((Map<?, ?>) unknown).entrySet());
36 		if (unknown instanceof IQueryResult<?>)
37 			return create((IQueryResult<T>) unknown);
38 		if (unknown instanceof IIndexProvider<?>)
39 			return create((IIndexProvider<T>) unknown);
40 		throw new IllegalArgumentException("Cannot convert a " + unknown.getClass().getName() + " into an iterator"); //$NON-NLS-1$ //$NON-NLS-2$
41 	}
42 
create(Iterator<T> iterator)43 	public static <T> IRepeatableIterator<T> create(Iterator<T> iterator) {
44 		return iterator instanceof IRepeatableIterator<?> ? ((IRepeatableIterator<T>) iterator).getCopy() : new RepeatableIterator<>(iterator);
45 	}
46 
create(Collection<T> values)47 	public static <T> IRepeatableIterator<T> create(Collection<T> values) {
48 		return new RepeatableIterator<>(values);
49 	}
50 
create(IQueryResult<T> values)51 	public static <T> IRepeatableIterator<T> create(IQueryResult<T> values) {
52 		return new QueryResultIterator<>(values);
53 	}
54 
create(T[] values)55 	public static <T> IRepeatableIterator<T> create(T[] values) {
56 		return new ArrayIterator<>(values);
57 	}
58 
create(IIndexProvider<T> values)59 	public static <T> IRepeatableIterator<T> create(IIndexProvider<T> values) {
60 		return new IndexProviderIterator<>(values);
61 	}
62 
RepeatableIterator(Iterator<T> iterator)63 	RepeatableIterator(Iterator<T> iterator) {
64 		HashSet<T> v = new HashSet<>();
65 		while (iterator.hasNext())
66 			v.add(iterator.next());
67 		values = v;
68 		this.iterator = v.iterator();
69 	}
70 
RepeatableIterator(Collection<T> values)71 	RepeatableIterator(Collection<T> values) {
72 		this.values = values;
73 		this.iterator = values.iterator();
74 	}
75 
76 	@Override
getCopy()77 	public IRepeatableIterator<T> getCopy() {
78 		return new RepeatableIterator<>(values);
79 	}
80 
81 	@Override
hasNext()82 	public boolean hasNext() {
83 		return iterator.hasNext();
84 	}
85 
86 	@Override
next()87 	public T next() {
88 		return iterator.next();
89 	}
90 
91 	@Override
remove()92 	public void remove() {
93 		throw new UnsupportedOperationException();
94 	}
95 
96 	@Override
getIteratorProvider()97 	public Object getIteratorProvider() {
98 		return values;
99 	}
100 
101 	static class ArrayIterator<T> implements IRepeatableIterator<T> {
102 		private final T[] array;
103 		private int position = -1;
104 
ArrayIterator(T[] array)105 		public ArrayIterator(T[] array) {
106 			this.array = array;
107 		}
108 
109 		@Override
getIteratorProvider()110 		public Object getIteratorProvider() {
111 			return array;
112 		}
113 
114 		@Override
hasNext()115 		public boolean hasNext() {
116 			return position + 1 < array.length;
117 		}
118 
119 		@Override
next()120 		public T next() {
121 			if (++position >= array.length)
122 				throw new NoSuchElementException();
123 			return array[position];
124 		}
125 
126 		@Override
remove()127 		public void remove() {
128 			throw new UnsupportedOperationException();
129 		}
130 
131 		@Override
getCopy()132 		public IRepeatableIterator<T> getCopy() {
133 			return new ArrayIterator<>(array);
134 		}
135 	}
136 
137 	static class IndexProviderIterator<T> implements IRepeatableIterator<T> {
138 		private final IIndexProvider<T> indexProvider;
139 		private final Iterator<T> iterator;
140 
IndexProviderIterator(IIndexProvider<T> indexProvider)141 		IndexProviderIterator(IIndexProvider<T> indexProvider) {
142 			this.iterator = indexProvider.everything();
143 			this.indexProvider = indexProvider;
144 		}
145 
146 		@Override
getCopy()147 		public IRepeatableIterator<T> getCopy() {
148 			return new IndexProviderIterator<>(indexProvider);
149 		}
150 
151 		@Override
getIteratorProvider()152 		public Object getIteratorProvider() {
153 			return indexProvider;
154 		}
155 
156 		@Override
hasNext()157 		public boolean hasNext() {
158 			return iterator.hasNext();
159 		}
160 
161 		@Override
next()162 		public T next() {
163 			return iterator.next();
164 		}
165 
166 		@Override
remove()167 		public void remove() {
168 			throw new UnsupportedOperationException();
169 		}
170 	}
171 
172 	static class QueryResultIterator<T> implements IRepeatableIterator<T> {
173 		private final IQueryResult<T> queryResult;
174 
175 		private final Iterator<T> iterator;
176 
QueryResultIterator(IQueryResult<T> queryResult)177 		QueryResultIterator(IQueryResult<T> queryResult) {
178 			this.queryResult = queryResult;
179 			this.iterator = queryResult.iterator();
180 		}
181 
182 		@Override
getCopy()183 		public IRepeatableIterator<T> getCopy() {
184 			return new QueryResultIterator<>(queryResult);
185 		}
186 
187 		@Override
getIteratorProvider()188 		public Object getIteratorProvider() {
189 			return queryResult;
190 		}
191 
192 		@Override
hasNext()193 		public boolean hasNext() {
194 			return iterator.hasNext();
195 		}
196 
197 		@Override
next()198 		public T next() {
199 			return iterator.next();
200 		}
201 
202 		@Override
remove()203 		public void remove() {
204 			throw new UnsupportedOperationException();
205 		}
206 	}
207 }
208