blob: f29fb65c6ce473b8f5fd44850a1738d9dba0a10e [file] [log] [blame]
Dianne Hackbornf4bf0ae2013-05-20 18:42:16 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.util;
18
19import libcore.util.Objects;
20
21import java.lang.reflect.Array;
22import java.util.Collection;
23import java.util.Iterator;
24import java.util.Map;
25import java.util.Set;
26
27/**
28 * Helper for writing standard Java collection interfaces to a data
29 * structure like {@link ArrayMap}.
30 * @hide
31 */
32abstract class MapCollections<K, V> {
33 EntrySet mEntrySet;
34 KeySet mKeySet;
35 ValuesCollection mValues;
36
37 final class ArrayIterator<T> implements Iterator<T> {
38 final int mOffset;
39 int mSize;
40 int mIndex;
41 boolean mCanRemove = false;
42
43 ArrayIterator(int offset) {
44 mOffset = offset;
45 mSize = colGetSize();
46 }
47
48 @Override
49 public boolean hasNext() {
50 return mIndex < mSize;
51 }
52
53 @Override
54 public T next() {
55 Object res = colGetEntry(mIndex, mOffset);
56 mIndex++;
57 mCanRemove = true;
58 return (T)res;
59 }
60
61 @Override
62 public void remove() {
63 if (!mCanRemove) {
64 throw new IllegalStateException();
65 }
66 mIndex--;
67 mSize--;
68 mCanRemove = false;
69 colRemoveAt(mIndex);
70 }
71 }
72
73 final class MapIterator implements Iterator<Map.Entry<K, V>>, Map.Entry<K, V> {
74 int mEnd;
75 int mIndex;
76 boolean mEntryValid = false;
77
78 MapIterator() {
79 mEnd = colGetSize() - 1;
80 mIndex = -1;
81 }
82
83 @Override
84 public boolean hasNext() {
85 return mIndex < mEnd;
86 }
87
88 @Override
89 public Map.Entry<K, V> next() {
90 mIndex++;
91 mEntryValid = true;
92 return this;
93 }
94
95 @Override
96 public void remove() {
97 if (!mEntryValid) {
98 throw new IllegalStateException();
99 }
100 mIndex--;
101 mEnd--;
102 mEntryValid = false;
103 colRemoveAt(mIndex);
104 }
105
106 @Override
107 public K getKey() {
108 if (!mEntryValid) {
109 throw new IllegalStateException(
110 "This container does not support retaining Map.Entry objects");
111 }
112 return (K)colGetEntry(mIndex, 0);
113 }
114
115 @Override
116 public V getValue() {
117 if (!mEntryValid) {
118 throw new IllegalStateException(
119 "This container does not support retaining Map.Entry objects");
120 }
121 return (V)colGetEntry(mIndex, 1);
122 }
123
124 @Override
125 public V setValue(V object) {
126 if (!mEntryValid) {
127 throw new IllegalStateException(
128 "This container does not support retaining Map.Entry objects");
129 }
130 return colSetValue(mIndex, object);
131 }
132
133 @Override
134 public final boolean equals(Object o) {
135 if (!mEntryValid) {
136 throw new IllegalStateException(
137 "This container does not support retaining Map.Entry objects");
138 }
139 if (!(o instanceof Map.Entry)) {
140 return false;
141 }
142 Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
143 return Objects.equal(e.getKey(), colGetEntry(mIndex, 0))
144 && Objects.equal(e.getValue(), colGetEntry(mIndex, 1));
145 }
146
147 @Override
148 public final int hashCode() {
149 if (!mEntryValid) {
150 throw new IllegalStateException(
151 "This container does not support retaining Map.Entry objects");
152 }
153 final Object key = colGetEntry(mIndex, 0);
154 final Object value = colGetEntry(mIndex, 1);
155 return (key == null ? 0 : key.hashCode()) ^
156 (value == null ? 0 : value.hashCode());
157 }
158
159 @Override
160 public final String toString() {
161 return getKey() + "=" + getValue();
162 }
163 }
164
165 final class EntrySet implements Set<Map.Entry<K, V>> {
166 @Override
167 public boolean add(Map.Entry<K, V> object) {
168 throw new UnsupportedOperationException();
169 }
170
171 @Override
172 public boolean addAll(Collection<? extends Map.Entry<K, V>> collection) {
173 int oldSize = colGetSize();
174 for (Map.Entry<K, V> entry : collection) {
175 colPut(entry.getKey(), entry.getValue());
176 }
177 return oldSize != colGetSize();
178 }
179
180 @Override
181 public void clear() {
182 colClear();
183 }
184
185 @Override
186 public boolean contains(Object object) {
187 throw new UnsupportedOperationException();
188 }
189
190 @Override
191 public boolean containsAll(Collection<?> collection) {
192 throw new UnsupportedOperationException();
193 }
194
195 @Override
196 public boolean isEmpty() {
197 return colGetSize() == 0;
198 }
199
200 @Override
201 public Iterator<Map.Entry<K, V>> iterator() {
202 return new MapIterator();
203 }
204
205 @Override
206 public boolean remove(Object object) {
207 throw new UnsupportedOperationException();
208 }
209
210 @Override
211 public boolean removeAll(Collection<?> collection) {
212 throw new UnsupportedOperationException();
213 }
214
215 @Override
216 public boolean retainAll(Collection<?> collection) {
217 throw new UnsupportedOperationException();
218 }
219
220 @Override
221 public int size() {
222 return colGetSize();
223 }
224
225 @Override
226 public Object[] toArray() {
227 throw new UnsupportedOperationException();
228 }
229
230 @Override
231 public <T> T[] toArray(T[] array) {
232 throw new UnsupportedOperationException();
233 }
234 };
235
236 final class KeySet implements Set<K> {
237
238 @Override
239 public boolean add(K object) {
240 throw new UnsupportedOperationException();
241 }
242
243 @Override
244 public boolean addAll(Collection<? extends K> collection) {
245 throw new UnsupportedOperationException();
246 }
247
248 @Override
249 public void clear() {
250 colClear();
251 }
252
253 @Override
254 public boolean contains(Object object) {
255 return colIndexOfKey(object) >= 0;
256 }
257
258 @Override
259 public boolean containsAll(Collection<?> collection) {
260 return removeAllHelper(colGetMap(), collection);
261 }
262
263 @Override
264 public boolean isEmpty() {
265 return colGetSize() == 0;
266 }
267
268 @Override
269 public Iterator<K> iterator() {
270 return new ArrayIterator<K>(0);
271 }
272
273 @Override
274 public boolean remove(Object object) {
275 int index = colIndexOfKey(object);
276 if (index >= 0) {
277 colRemoveAt(index);
278 return true;
279 }
280 return false;
281 }
282
283 @Override
284 public boolean removeAll(Collection<?> collection) {
285 return removeAllHelper(colGetMap(), collection);
286 }
287
288 @Override
289 public boolean retainAll(Collection<?> collection) {
290 return retainAllHelper(colGetMap(), collection);
291 }
292
293 @Override
294 public int size() {
295 return colGetSize();
296 }
297
298 @Override
299 public Object[] toArray() {
300 return toArrayHelper(1);
301 }
302
303 @Override
304 public <T> T[] toArray(T[] array) {
305 return toArrayHelper(array, 1);
306 }
307 };
308
309 final class ValuesCollection implements Collection<V> {
310
311 @Override
312 public boolean add(V object) {
313 throw new UnsupportedOperationException();
314 }
315
316 @Override
317 public boolean addAll(Collection<? extends V> collection) {
318 throw new UnsupportedOperationException();
319 }
320
321 @Override
322 public void clear() {
323 colClear();
324 }
325
326 @Override
327 public boolean contains(Object object) {
328 return colIndexOfValue(object) >= 0;
329 }
330
331 @Override
332 public boolean containsAll(Collection<?> collection) {
333 Iterator<?> it = collection.iterator();
334 while (it.hasNext()) {
335 if (!contains(it.next())) {
336 return false;
337 }
338 }
339 return true;
340 }
341
342 @Override
343 public boolean isEmpty() {
344 return colGetSize() == 0;
345 }
346
347 @Override
348 public Iterator<V> iterator() {
349 return new ArrayIterator<V>(1);
350 }
351
352 @Override
353 public boolean remove(Object object) {
354 int index = colIndexOfValue(object);
355 if (index >= 0) {
356 colRemoveAt(index);
357 return true;
358 }
359 return false;
360 }
361
362 @Override
363 public boolean removeAll(Collection<?> collection) {
364 int N = colGetSize();
365 boolean changed = false;
366 for (int i=0; i<N; i++) {
367 Object cur = colGetEntry(i, 1);
368 if (collection.contains(cur)) {
369 colRemoveAt(i);
370 i--;
371 N--;
372 changed = true;
373 }
374 }
375 return changed;
376 }
377
378 @Override
379 public boolean retainAll(Collection<?> collection) {
380 int N = colGetSize();
381 boolean changed = false;
382 for (int i=0; i<N; i++) {
383 Object cur = colGetEntry(i, 1);
384 if (!collection.contains(cur)) {
385 colRemoveAt(i);
386 i--;
387 N--;
388 changed = true;
389 }
390 }
391 return changed;
392 }
393
394 @Override
395 public int size() {
396 return colGetSize();
397 }
398
399 @Override
400 public Object[] toArray() {
401 return toArrayHelper(1);
402 }
403
404 @Override
405 public <T> T[] toArray(T[] array) {
406 return toArrayHelper(array, 1);
407 }
408 };
409
410 public static <K, V> boolean containsAllHelper(Map<K, V> map, Collection<?> collection) {
411 Iterator<?> it = collection.iterator();
412 while (it.hasNext()) {
413 if (!map.containsKey(it.next())) {
414 return false;
415 }
416 }
417 return true;
418 }
419
420 public static <K, V> boolean removeAllHelper(Map<K, V> map, Collection<?> collection) {
421 int oldSize = map.size();
422 Iterator<?> it = collection.iterator();
423 while (it.hasNext()) {
424 map.remove(it.next());
425 }
426 return oldSize != map.size();
427 }
428
429 public static <K, V> boolean retainAllHelper(Map<K, V> map, Collection<?> collection) {
430 int oldSize = map.size();
431 Iterator<K> it = map.keySet().iterator();
432 while (it.hasNext()) {
433 if (!collection.contains(it.next())) {
434 it.remove();
435 }
436 }
437 return oldSize != map.size();
438 }
439
440
441 public Object[] toArrayHelper(int offset) {
442 final int N = colGetSize();
443 Object[] result = new Object[N];
444 for (int i=0; i<N; i++) {
445 result[i] = colGetEntry(i, offset);
446 }
447 return result;
448 }
449
450 public <T> T[] toArrayHelper(T[] array, int offset) {
451 final int N = colGetSize();
452 if (array.length < N) {
453 @SuppressWarnings("unchecked") T[] newArray
454 = (T[]) Array.newInstance(array.getClass().getComponentType(), N);
455 array = newArray;
456 }
457 for (int i=0; i<N; i++) {
458 array[i] = (T)colGetEntry(i, offset);
459 }
460 if (array.length > N) {
461 array[N] = null;
462 }
463 return array;
464 }
465
466 public Set<Map.Entry<K, V>> getEntrySet() {
467 if (mEntrySet == null) {
468 mEntrySet = new EntrySet();
469 }
470 return mEntrySet;
471 }
472
473 public Set<K> getKeySet() {
474 if (mKeySet == null) {
475 mKeySet = new KeySet();
476 }
477 return mKeySet;
478 }
479
480 public Collection<V> getValues() {
481 if (mValues == null) {
482 mValues = new ValuesCollection();
483 }
484 return mValues;
485 }
486
487 protected abstract int colGetSize();
488 protected abstract Object colGetEntry(int index, int offset);
489 protected abstract int colIndexOfKey(Object key);
490 protected abstract int colIndexOfValue(Object key);
491 protected abstract Map<K, V> colGetMap();
492 protected abstract void colPut(K key, V value);
493 protected abstract V colSetValue(int index, V value);
494 protected abstract void colRemoveAt(int index);
495 protected abstract void colClear();
496}