1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.collect;
18
19 import static com.google.common.base.Preconditions.checkNotNull;
20
21 import com.google.common.annotations.GwtCompatible;
22 import com.google.common.annotations.GwtIncompatible;
23 import com.google.common.collect.Multiset.Entry;
24 import com.google.common.primitives.Ints;
25
26 import java.io.Serializable;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.Iterator;
30
31 import javax.annotation.Nullable;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 @GwtCompatible(serializable = true, emulated = true)
50 @SuppressWarnings("serial")
51
52 public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
53 implements Multiset<E> {
54
55 private static final ImmutableMultiset<Object> EMPTY =
56 new RegularImmutableMultiset<Object>(ImmutableMap.<Object, Integer>of(), 0);
57
58
59
60
61 @SuppressWarnings("unchecked")
62 public static <E> ImmutableMultiset<E> of() {
63 return (ImmutableMultiset<E>) EMPTY;
64 }
65
66
67
68
69
70
71
72 @SuppressWarnings("unchecked")
73 public static <E> ImmutableMultiset<E> of(E element) {
74 return copyOfInternal(element);
75 }
76
77
78
79
80
81
82
83 @SuppressWarnings("unchecked")
84 public static <E> ImmutableMultiset<E> of(E e1, E e2) {
85 return copyOfInternal(e1, e2);
86 }
87
88
89
90
91
92
93
94 @SuppressWarnings("unchecked")
95 public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3) {
96 return copyOfInternal(e1, e2, e3);
97 }
98
99
100
101
102
103
104
105 @SuppressWarnings("unchecked")
106 public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3, E e4) {
107 return copyOfInternal(e1, e2, e3, e4);
108 }
109
110
111
112
113
114
115
116 @SuppressWarnings("unchecked")
117 public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3, E e4, E e5) {
118 return copyOfInternal(e1, e2, e3, e4, e5);
119 }
120
121
122
123
124
125
126
127 @SuppressWarnings("unchecked")
128 public static <E> ImmutableMultiset<E> of(
129 E e1, E e2, E e3, E e4, E e5, E e6, E... others) {
130 return new Builder<E>()
131 .add(e1)
132 .add(e2)
133 .add(e3)
134 .add(e4)
135 .add(e5)
136 .add(e6)
137 .add(others)
138 .build();
139 }
140
141
142
143
144
145
146
147
148
149
150
151 public static <E> ImmutableMultiset<E> copyOf(E[] elements) {
152 return copyOf(Arrays.asList(elements));
153 }
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172 public static <E> ImmutableMultiset<E> copyOf(
173 Iterable<? extends E> elements) {
174 if (elements instanceof ImmutableMultiset) {
175 @SuppressWarnings("unchecked")
176 ImmutableMultiset<E> result = (ImmutableMultiset<E>) elements;
177 if (!result.isPartialView()) {
178 return result;
179 }
180 }
181
182 Multiset<? extends E> multiset = (elements instanceof Multiset)
183 ? Multisets.cast(elements)
184 : LinkedHashMultiset.create(elements);
185
186 return copyOfInternal(multiset);
187 }
188
189 private static <E> ImmutableMultiset<E> copyOfInternal(E... elements) {
190 return copyOf(Arrays.asList(elements));
191 }
192
193 private static <E> ImmutableMultiset<E> copyOfInternal(
194 Multiset<? extends E> multiset) {
195 return copyFromEntries(multiset.entrySet());
196 }
197
198 static <E> ImmutableMultiset<E> copyFromEntries(
199 Collection<? extends Entry<? extends E>> entries) {
200 long size = 0;
201 ImmutableMap.Builder<E, Integer> builder = ImmutableMap.builder();
202 for (Entry<? extends E> entry : entries) {
203 int count = entry.getCount();
204 if (count > 0) {
205
206
207 builder.put(entry.getElement(), count);
208 size += count;
209 }
210 }
211
212 if (size == 0) {
213 return of();
214 }
215 return new RegularImmutableMultiset<E>(
216 builder.build(), Ints.saturatedCast(size));
217 }
218
219
220
221
222
223
224
225
226
227
228
229 public static <E> ImmutableMultiset<E> copyOf(
230 Iterator<? extends E> elements) {
231 Multiset<E> multiset = LinkedHashMultiset.create();
232 Iterators.addAll(multiset, elements);
233 return copyOfInternal(multiset);
234 }
235
236 ImmutableMultiset() {}
237
238 @Override public UnmodifiableIterator<E> iterator() {
239 final Iterator<Entry<E>> entryIterator = entrySet().iterator();
240 return new UnmodifiableIterator<E>() {
241 int remaining;
242 E element;
243
244 @Override
245 public boolean hasNext() {
246 return (remaining > 0) || entryIterator.hasNext();
247 }
248
249 @Override
250 public E next() {
251 if (remaining <= 0) {
252 Entry<E> entry = entryIterator.next();
253 element = entry.getElement();
254 remaining = entry.getCount();
255 }
256 remaining--;
257 return element;
258 }
259 };
260 }
261
262 @Override
263 public boolean contains(@Nullable Object object) {
264 return count(object) > 0;
265 }
266
267 @Override
268 public boolean containsAll(Collection<?> targets) {
269 return elementSet().containsAll(targets);
270 }
271
272
273
274
275
276
277
278 @Deprecated
279 @Override
280 public final int add(E element, int occurrences) {
281 throw new UnsupportedOperationException();
282 }
283
284
285
286
287
288
289
290 @Deprecated
291 @Override
292 public final int remove(Object element, int occurrences) {
293 throw new UnsupportedOperationException();
294 }
295
296
297
298
299
300
301
302 @Deprecated
303 @Override
304 public final int setCount(E element, int count) {
305 throw new UnsupportedOperationException();
306 }
307
308
309
310
311
312
313
314 @Deprecated
315 @Override
316 public final boolean setCount(E element, int oldCount, int newCount) {
317 throw new UnsupportedOperationException();
318 }
319
320 @GwtIncompatible("not present in emulated superclass")
321 @Override
322 int copyIntoArray(Object[] dst, int offset) {
323 for (Multiset.Entry<E> entry : entrySet()) {
324 Arrays.fill(dst, offset, offset + entry.getCount(), entry.getElement());
325 offset += entry.getCount();
326 }
327 return offset;
328 }
329
330 @Override public boolean equals(@Nullable Object object) {
331 return Multisets.equalsImpl(this, object);
332 }
333
334 @Override public int hashCode() {
335 return Sets.hashCodeImpl(entrySet());
336 }
337
338 @Override public String toString() {
339 return entrySet().toString();
340 }
341
342 private transient ImmutableSet<Entry<E>> entrySet;
343
344 @Override
345 public ImmutableSet<Entry<E>> entrySet() {
346 ImmutableSet<Entry<E>> es = entrySet;
347 return (es == null) ? (entrySet = createEntrySet()) : es;
348 }
349
350 private final ImmutableSet<Entry<E>> createEntrySet() {
351 return isEmpty() ? ImmutableSet.<Entry<E>>of() : new EntrySet();
352 }
353
354 abstract Entry<E> getEntry(int index);
355
356 private final class EntrySet extends ImmutableSet<Entry<E>> {
357 @Override
358 boolean isPartialView() {
359 return ImmutableMultiset.this.isPartialView();
360 }
361
362 @Override
363 public UnmodifiableIterator<Entry<E>> iterator() {
364 return asList().iterator();
365 }
366
367 @Override
368 ImmutableList<Entry<E>> createAsList() {
369 return new ImmutableAsList<Entry<E>>() {
370 @Override
371 public Entry<E> get(int index) {
372 return getEntry(index);
373 }
374
375 @Override
376 ImmutableCollection<Entry<E>> delegateCollection() {
377 return EntrySet.this;
378 }
379 };
380 }
381
382 @Override
383 public int size() {
384 return elementSet().size();
385 }
386
387 @Override
388 public boolean contains(Object o) {
389 if (o instanceof Entry) {
390 Entry<?> entry = (Entry<?>) o;
391 if (entry.getCount() <= 0) {
392 return false;
393 }
394 int count = count(entry.getElement());
395 return count == entry.getCount();
396 }
397 return false;
398 }
399
400 @Override
401 public int hashCode() {
402 return ImmutableMultiset.this.hashCode();
403 }
404
405
406
407
408 Object writeReplace() {
409 return new EntrySetSerializedForm<E>(ImmutableMultiset.this);
410 }
411
412 private static final long serialVersionUID = 0;
413 }
414
415 static class EntrySetSerializedForm<E> implements Serializable {
416 final ImmutableMultiset<E> multiset;
417
418 EntrySetSerializedForm(ImmutableMultiset<E> multiset) {
419 this.multiset = multiset;
420 }
421
422 Object readResolve() {
423 return multiset.entrySet();
424 }
425 }
426
427 private static class SerializedForm implements Serializable {
428 final Object[] elements;
429 final int[] counts;
430
431 SerializedForm(Multiset<?> multiset) {
432 int distinct = multiset.entrySet().size();
433 elements = new Object[distinct];
434 counts = new int[distinct];
435 int i = 0;
436 for (Entry<?> entry : multiset.entrySet()) {
437 elements[i] = entry.getElement();
438 counts[i] = entry.getCount();
439 i++;
440 }
441 }
442
443 Object readResolve() {
444 LinkedHashMultiset<Object> multiset =
445 LinkedHashMultiset.create(elements.length);
446 for (int i = 0; i < elements.length; i++) {
447 multiset.add(elements[i], counts[i]);
448 }
449 return ImmutableMultiset.copyOf(multiset);
450 }
451
452 private static final long serialVersionUID = 0;
453 }
454
455
456
457 Object writeReplace() {
458 return new SerializedForm(this);
459 }
460
461
462
463
464
465 public static <E> Builder<E> builder() {
466 return new Builder<E>();
467 }
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487 public static class Builder<E> extends ImmutableCollection.Builder<E> {
488 final Multiset<E> contents;
489
490
491
492
493
494 public Builder() {
495 this(LinkedHashMultiset.<E>create());
496 }
497
498 Builder(Multiset<E> contents) {
499 this.contents = contents;
500 }
501
502
503
504
505
506
507
508
509 @Override public Builder<E> add(E element) {
510 contents.add(checkNotNull(element));
511 return this;
512 }
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527 public Builder<E> addCopies(E element, int occurrences) {
528 contents.add(checkNotNull(element), occurrences);
529 return this;
530 }
531
532
533
534
535
536
537
538
539
540
541
542 public Builder<E> setCount(E element, int count) {
543 contents.setCount(checkNotNull(element), count);
544 return this;
545 }
546
547
548
549
550
551
552
553
554
555 @Override public Builder<E> add(E... elements) {
556 super.add(elements);
557 return this;
558 }
559
560
561
562
563
564
565
566
567
568
569 @Override public Builder<E> addAll(Iterable<? extends E> elements) {
570 if (elements instanceof Multiset) {
571 Multiset<? extends E> multiset = Multisets.cast(elements);
572 for (Entry<? extends E> entry : multiset.entrySet()) {
573 addCopies(entry.getElement(), entry.getCount());
574 }
575 } else {
576 super.addAll(elements);
577 }
578 return this;
579 }
580
581
582
583
584
585
586
587
588
589 @Override public Builder<E> addAll(Iterator<? extends E> elements) {
590 super.addAll(elements);
591 return this;
592 }
593
594
595
596
597
598 @Override public ImmutableMultiset<E> build() {
599 return copyOf(contents);
600 }
601 }
602 }