1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.multiset;
18
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.ObjectOutputStream;
22 import java.lang.reflect.Array;
23 import java.util.ConcurrentModificationException;
24 import java.util.Iterator;
25 import java.util.Map;
26
27 import org.apache.commons.collections4.MultiSet;
28 import org.apache.commons.collections4.iterators.AbstractIteratorDecorator;
29
30
31
32
33
34
35
36
37
38
39
40
41
42 public abstract class AbstractMapMultiSet<E> extends AbstractMultiSet<E> {
43
44
45
46
47
48
49 protected static class EntrySetIterator<E> implements Iterator<Entry<E>> {
50
51
52 protected final AbstractMapMultiSet<E> parent;
53
54
55
56
57 protected final Iterator<Map.Entry<E, MutableInteger>> decorated;
58
59
60 protected Entry<E> last;
61
62
63 protected boolean canRemove;
64
65
66
67
68
69
70 protected EntrySetIterator(final Iterator<Map.Entry<E, MutableInteger>> decorated,
71 final AbstractMapMultiSet<E> parent) {
72 this.decorated = decorated;
73 this.parent = parent;
74 }
75
76 @Override
77 public boolean hasNext() {
78 return decorated.hasNext();
79 }
80
81 @Override
82 public Entry<E> next() {
83 last = new MultiSetEntry<>(decorated.next());
84 canRemove = true;
85 return last;
86 }
87
88 @Override
89 public void remove() {
90 if (!canRemove) {
91 throw new IllegalStateException("Iterator remove() can only be called once after next()");
92 }
93 decorated.remove();
94 last = null;
95 canRemove = false;
96 }
97 }
98
99
100
101 private static final class MapBasedMultiSetIterator<E> implements Iterator<E> {
102 private final AbstractMapMultiSet<E> parent;
103 private final Iterator<Map.Entry<E, MutableInteger>> entryIterator;
104 private Map.Entry<E, MutableInteger> current;
105 private int itemCount;
106 private final int mods;
107 private boolean canRemove;
108
109
110
111
112
113
114 MapBasedMultiSetIterator(final AbstractMapMultiSet<E> parent) {
115 this.parent = parent;
116 this.entryIterator = parent.map.entrySet().iterator();
117 this.current = null;
118 this.mods = parent.modCount;
119 this.canRemove = false;
120 }
121
122
123 @Override
124 public boolean hasNext() {
125 return itemCount > 0 || entryIterator.hasNext();
126 }
127
128
129 @Override
130 public E next() {
131 if (parent.modCount != mods) {
132 throw new ConcurrentModificationException();
133 }
134 if (itemCount == 0) {
135 current = entryIterator.next();
136 itemCount = current.getValue().value;
137 }
138 canRemove = true;
139 itemCount--;
140 return current.getKey();
141 }
142
143
144 @Override
145 public void remove() {
146 if (parent.modCount != mods) {
147 throw new ConcurrentModificationException();
148 }
149 if (!canRemove) {
150 throw new IllegalStateException();
151 }
152 final MutableInteger mut = current.getValue();
153 if (mut.value > 1) {
154 mut.value--;
155 } else {
156 entryIterator.remove();
157 }
158 parent.size--;
159 canRemove = false;
160 }
161 }
162
163
164
165
166
167
168 protected static class MultiSetEntry<E> extends AbstractEntry<E> {
169
170
171
172
173 protected final Map.Entry<E, MutableInteger> parentEntry;
174
175
176
177
178
179 protected MultiSetEntry(final Map.Entry<E, MutableInteger> parentEntry) {
180 this.parentEntry = parentEntry;
181 }
182
183 @Override
184 public int getCount() {
185 return parentEntry.getValue().value;
186 }
187
188 @Override
189 public E getElement() {
190 return parentEntry.getKey();
191 }
192 }
193
194
195
196
197 protected static class MutableInteger {
198
199 protected int value;
200
201
202
203
204
205 MutableInteger(final int value) {
206 this.value = value;
207 }
208
209 @Override
210 public boolean equals(final Object obj) {
211 if (!(obj instanceof MutableInteger)) {
212 return false;
213 }
214 return ((MutableInteger) obj).value == value;
215 }
216
217 @Override
218 public int hashCode() {
219 return value;
220 }
221 }
222
223
224
225
226
227
228 protected static class UniqueSetIterator<E> extends AbstractIteratorDecorator<E> {
229
230
231 protected final AbstractMapMultiSet<E> parent;
232
233
234 protected E lastElement;
235
236
237 protected boolean canRemove;
238
239
240
241
242
243
244 protected UniqueSetIterator(final Iterator<E> iterator, final AbstractMapMultiSet<E> parent) {
245 super(iterator);
246 this.parent = parent;
247 }
248
249 @Override
250 public E next() {
251 lastElement = super.next();
252 canRemove = true;
253 return lastElement;
254 }
255
256 @Override
257 public void remove() {
258 if (!canRemove) {
259 throw new IllegalStateException("Iterator remove() can only be called once after next()");
260 }
261 final int count = parent.getCount(lastElement);
262 super.remove();
263 parent.remove(lastElement, count);
264 lastElement = null;
265 canRemove = false;
266 }
267 }
268
269
270 private transient Map<E, MutableInteger> map;
271
272
273 private transient int size;
274
275
276 private transient int modCount;
277
278
279
280
281 protected AbstractMapMultiSet() {
282 }
283
284
285
286
287
288
289
290 protected AbstractMapMultiSet(final Map<E, MutableInteger> map) {
291 this.map = map;
292 }
293
294 @Override
295 public int add(final E object, final int occurrences) {
296 if (occurrences < 0) {
297 throw new IllegalArgumentException("Occurrences must not be negative.");
298 }
299
300 final MutableInteger mut = map.get(object);
301 final int oldCount = mut != null ? mut.value : 0;
302
303 if (occurrences > 0) {
304 modCount++;
305 size += occurrences;
306 if (mut == null) {
307 map.put(object, new MutableInteger(occurrences));
308 } else {
309 mut.value += occurrences;
310 }
311 }
312 return oldCount;
313 }
314
315
316
317
318 @Override
319 public void clear() {
320 modCount++;
321 map.clear();
322 size = 0;
323 }
324
325
326
327
328
329
330
331
332 @Override
333 public boolean contains(final Object object) {
334 return map.containsKey(object);
335 }
336
337 @Override
338 protected Iterator<Entry<E>> createEntrySetIterator() {
339 return new EntrySetIterator<>(map.entrySet().iterator(), this);
340 }
341
342 @Override
343 protected Iterator<E> createUniqueSetIterator() {
344 return new UniqueSetIterator<>(getMap().keySet().iterator(), this);
345 }
346
347
348
349
350
351
352
353
354 @Override
355 protected void doReadObject(final ObjectInputStream in)
356 throws IOException, ClassNotFoundException {
357 final int entrySize = in.readInt();
358 for (int i = 0; i < entrySize; i++) {
359 @SuppressWarnings("unchecked")
360 final E obj = (E) in.readObject();
361 final int count = in.readInt();
362 map.put(obj, new MutableInteger(count));
363 size += count;
364 }
365 }
366
367
368
369
370
371
372 @Override
373 protected void doWriteObject(final ObjectOutputStream out) throws IOException {
374 out.writeInt(map.size());
375 for (final Map.Entry<E, MutableInteger> entry : map.entrySet()) {
376 out.writeObject(entry.getKey());
377 out.writeInt(entry.getValue().value);
378 }
379 }
380
381 @Override
382 public boolean equals(final Object object) {
383 if (object == this) {
384 return true;
385 }
386 if (!(object instanceof MultiSet)) {
387 return false;
388 }
389 final MultiSet<?> other = (MultiSet<?>) object;
390 if (other.size() != size()) {
391 return false;
392 }
393 for (final E element : map.keySet()) {
394 if (other.getCount(element) != getCount(element)) {
395 return false;
396 }
397 }
398 return true;
399 }
400
401
402
403
404
405
406
407
408 @Override
409 public int getCount(final Object object) {
410 final MutableInteger count = map.get(object);
411 if (count != null) {
412 return count.value;
413 }
414 return 0;
415 }
416
417
418
419
420
421
422
423 protected Map<E, MutableInteger> getMap() {
424 return map;
425 }
426
427 @Override
428 public int hashCode() {
429 int total = 0;
430 for (final Map.Entry<E, MutableInteger> entry : map.entrySet()) {
431 final E element = entry.getKey();
432 final MutableInteger count = entry.getValue();
433 total += (element == null ? 0 : element.hashCode()) ^ count.value;
434 }
435 return total;
436 }
437
438
439
440
441
442
443 @Override
444 public boolean isEmpty() {
445 return map.isEmpty();
446 }
447
448
449
450
451
452
453
454 @Override
455 public Iterator<E> iterator() {
456 return new MapBasedMultiSetIterator<>(this);
457 }
458
459 @Override
460 public int remove(final Object object, final int occurrences) {
461 if (occurrences < 0) {
462 throw new IllegalArgumentException("Occurrences must not be negative.");
463 }
464
465 final MutableInteger mut = map.get(object);
466 if (mut == null) {
467 return 0;
468 }
469 final int oldCount = mut.value;
470 if (occurrences > 0) {
471 modCount++;
472 if (occurrences < mut.value) {
473 mut.value -= occurrences;
474 size -= occurrences;
475 } else {
476 map.remove(object);
477 size -= mut.value;
478 mut.value = 0;
479 }
480 }
481 return oldCount;
482 }
483
484
485
486
487
488
489
490
491
492 protected void setMap(final Map<E, MutableInteger> map) {
493 this.map = map;
494 }
495
496
497
498
499
500
501 @Override
502 public int size() {
503 return size;
504 }
505
506
507
508
509
510
511 @Override
512 public Object[] toArray() {
513 final Object[] result = new Object[size()];
514 int i = 0;
515 for (final Map.Entry<E, MutableInteger> entry : map.entrySet()) {
516 final E current = entry.getKey();
517 final MutableInteger count = entry.getValue();
518 for (int index = count.value; index > 0; index--) {
519 result[i++] = current;
520 }
521 }
522 return result;
523 }
524
525
526
527
528
529
530
531
532
533
534
535
536
537 @Override
538 public <T> T[] toArray(T[] array) {
539 final int size = size();
540 if (array.length < size) {
541 @SuppressWarnings("unchecked")
542 final T[] unchecked = (T[]) Array.newInstance(array.getClass().getComponentType(), size);
543 array = unchecked;
544 }
545
546 int i = 0;
547 for (final Map.Entry<E, MutableInteger> entry : map.entrySet()) {
548 final E current = entry.getKey();
549 final MutableInteger count = entry.getValue();
550 for (int index = count.value; index > 0; index--) {
551
552 @SuppressWarnings("unchecked")
553 final T unchecked = (T) current;
554 array[i++] = unchecked;
555 }
556 }
557 while (i < array.length) {
558 array[i++] = null;
559 }
560 return array;
561 }
562
563 @Override
564 protected int uniqueElements() {
565 return map.size();
566 }
567 }