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
355 @Override
356 protected void doReadObject(final ObjectInputStream in)
357 throws IOException, ClassNotFoundException {
358 final int entrySize = in.readInt();
359 for (int i = 0; i < entrySize; i++) {
360 @SuppressWarnings("unchecked")
361 final E obj = (E) in.readObject();
362 final int count = in.readInt();
363 map.put(obj, new MutableInteger(count));
364 size += count;
365 }
366 }
367
368
369
370
371
372
373
374 @Override
375 protected void doWriteObject(final ObjectOutputStream out) throws IOException {
376 out.writeInt(map.size());
377 for (final Map.Entry<E, MutableInteger> entry : map.entrySet()) {
378 out.writeObject(entry.getKey());
379 out.writeInt(entry.getValue().value);
380 }
381 }
382
383 @Override
384 public boolean equals(final Object object) {
385 if (object == this) {
386 return true;
387 }
388 if (!(object instanceof MultiSet)) {
389 return false;
390 }
391 final MultiSet<?> other = (MultiSet<?>) object;
392 if (other.size() != size()) {
393 return false;
394 }
395 for (final E element : map.keySet()) {
396 if (other.getCount(element) != getCount(element)) {
397 return false;
398 }
399 }
400 return true;
401 }
402
403
404
405
406
407
408
409
410 @Override
411 public int getCount(final Object object) {
412 final MutableInteger count = map.get(object);
413 if (count != null) {
414 return count.value;
415 }
416 return 0;
417 }
418
419
420
421
422
423
424
425 protected Map<E, MutableInteger> getMap() {
426 return map;
427 }
428
429 @Override
430 public int hashCode() {
431 int total = 0;
432 for (final Map.Entry<E, MutableInteger> entry : map.entrySet()) {
433 final E element = entry.getKey();
434 final MutableInteger count = entry.getValue();
435 total += (element == null ? 0 : element.hashCode()) ^ count.value;
436 }
437 return total;
438 }
439
440
441
442
443
444
445 @Override
446 public boolean isEmpty() {
447 return map.isEmpty();
448 }
449
450
451
452
453
454
455
456 @Override
457 public Iterator<E> iterator() {
458 return new MapBasedMultiSetIterator<>(this);
459 }
460
461 @Override
462 public int remove(final Object object, final int occurrences) {
463 if (occurrences < 0) {
464 throw new IllegalArgumentException("Occurrences must not be negative.");
465 }
466
467 final MutableInteger mut = map.get(object);
468 if (mut == null) {
469 return 0;
470 }
471 final int oldCount = mut.value;
472 if (occurrences > 0) {
473 modCount++;
474 if (occurrences < mut.value) {
475 mut.value -= occurrences;
476 size -= occurrences;
477 } else {
478 map.remove(object);
479 size -= mut.value;
480 mut.value = 0;
481 }
482 }
483 return oldCount;
484 }
485
486
487
488
489
490
491
492
493
494 protected void setMap(final Map<E, MutableInteger> map) {
495 this.map = map;
496 }
497
498
499
500
501
502
503 @Override
504 public int size() {
505 return size;
506 }
507
508
509
510
511
512
513 @Override
514 public Object[] toArray() {
515 final Object[] result = new Object[size()];
516 int i = 0;
517 for (final Map.Entry<E, MutableInteger> entry : map.entrySet()) {
518 final E current = entry.getKey();
519 final MutableInteger count = entry.getValue();
520 for (int index = count.value; index > 0; index--) {
521 result[i++] = current;
522 }
523 }
524 return result;
525 }
526
527
528
529
530
531
532
533
534
535
536
537
538
539 @Override
540 public <T> T[] toArray(T[] array) {
541 final int size = size();
542 if (array.length < size) {
543 @SuppressWarnings("unchecked")
544 final T[] unchecked = (T[]) Array.newInstance(array.getClass().getComponentType(), size);
545 array = unchecked;
546 }
547
548 int i = 0;
549 for (final Map.Entry<E, MutableInteger> entry : map.entrySet()) {
550 final E current = entry.getKey();
551 final MutableInteger count = entry.getValue();
552 for (int index = count.value; index > 0; index--) {
553
554 @SuppressWarnings("unchecked")
555 final T unchecked = (T) current;
556 array[i++] = unchecked;
557 }
558 }
559 while (i < array.length) {
560 array[i++] = null;
561 }
562 return array;
563 }
564
565 @Override
566 protected int uniqueElements() {
567 return map.size();
568 }
569 }