javadoc.src-html.com.google.common.collect.ImmutableMultiset.Builder.html Maven / Gradle / Ivy
The newest version!
001 /*
002 * Copyright (C) 2008 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package com.google.common.collect;
018
019 import static com.google.common.base.Preconditions.checkNotNull;
020
021 import com.google.common.annotations.GwtCompatible;
022 import com.google.common.collect.Multiset.Entry;
023 import com.google.common.primitives.Ints;
024
025 import java.io.Serializable;
026 import java.util.ArrayList;
027 import java.util.Arrays;
028 import java.util.Collection;
029 import java.util.Collections;
030 import java.util.Iterator;
031 import java.util.List;
032 import java.util.Set;
033
034 import javax.annotation.Nullable;
035
036 /**
037 * An immutable hash-based multiset. Does not permit null elements.
038 *
039 * <p>Its iterator orders elements according to the first appearance of the
040 * element among the items passed to the factory method or builder. When the
041 * multiset contains multiple instances of an element, those instances are
042 * consecutive in the iteration order.
043 *
044 * @author Jared Levy
045 * @author Louis Wasserman
046 * @since 2.0 (imported from Google Collections Library)
047 */
048 @GwtCompatible(serializable = true)
049 @SuppressWarnings("serial") // we're overriding default serialization
050 // TODO(user): write an efficient asList() implementation
051 public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
052 implements Multiset<E> {
053
054 /**
055 * Returns the empty immutable multiset.
056 */
057 @SuppressWarnings("unchecked") // all supported methods are covariant
058 public static <E> ImmutableMultiset<E> of() {
059 return (ImmutableMultiset<E>) EmptyImmutableMultiset.INSTANCE;
060 }
061
062 /**
063 * Returns an immutable multiset containing a single element.
064 *
065 * @throws NullPointerException if {@code element} is null
066 * @since 6.0 (source-compatible since 2.0)
067 */
068 @SuppressWarnings("unchecked") // generic array created but never written
069 public static <E> ImmutableMultiset<E> of(E element) {
070 return copyOfInternal(element);
071 }
072
073 /**
074 * Returns an immutable multiset containing the given elements, in order.
075 *
076 * @throws NullPointerException if any element is null
077 * @since 6.0 (source-compatible since 2.0)
078 */
079 @SuppressWarnings("unchecked") //
080 public static <E> ImmutableMultiset<E> of(E e1, E e2) {
081 return copyOfInternal(e1, e2);
082 }
083
084 /**
085 * Returns an immutable multiset containing the given elements, in order.
086 *
087 * @throws NullPointerException if any element is null
088 * @since 6.0 (source-compatible since 2.0)
089 */
090 @SuppressWarnings("unchecked") //
091 public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3) {
092 return copyOfInternal(e1, e2, e3);
093 }
094
095 /**
096 * Returns an immutable multiset containing the given elements, in order.
097 *
098 * @throws NullPointerException if any element is null
099 * @since 6.0 (source-compatible since 2.0)
100 */
101 @SuppressWarnings("unchecked") //
102 public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3, E e4) {
103 return copyOfInternal(e1, e2, e3, e4);
104 }
105
106 /**
107 * Returns an immutable multiset containing the given elements, in order.
108 *
109 * @throws NullPointerException if any element is null
110 * @since 6.0 (source-compatible since 2.0)
111 */
112 @SuppressWarnings("unchecked") //
113 public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3, E e4, E e5) {
114 return copyOfInternal(e1, e2, e3, e4, e5);
115 }
116
117 /**
118 * Returns an immutable multiset containing the given elements, in order.
119 *
120 * @throws NullPointerException if any element is null
121 * @since 6.0 (source-compatible since 2.0)
122 */
123 @SuppressWarnings("unchecked") //
124 public static <E> ImmutableMultiset<E> of(
125 E e1, E e2, E e3, E e4, E e5, E e6, E... others) {
126 int size = others.length + 6;
127 List<E> all = new ArrayList<E>(size);
128 Collections.addAll(all, e1, e2, e3, e4, e5, e6);
129 Collections.addAll(all, others);
130 return copyOf(all);
131 }
132
133 /**
134 * Returns an immutable multiset containing the given elements.
135 *
136 * <p>The multiset is ordered by the first occurrence of each element. For
137 * example, {@code ImmutableMultiset.of(2, 3, 1, 3)} yields a multiset with
138 * elements in the order {@code 2, 3, 3, 1}.
139 *
140 * @throws NullPointerException if any of {@code elements} is null
141 * @deprecated use {@link #copyOf(Object[])}. <b>This method is scheduled for
142 * deletion in January 2012.</b>
143 * @since 2.0 (changed from varargs in 6.0)
144 */
145 @Deprecated
146 public static <E> ImmutableMultiset<E> of(E[] elements) {
147 return copyOf(Arrays.asList(elements));
148 }
149
150 /**
151 * Returns an immutable multiset containing the given elements.
152 *
153 * <p>The multiset is ordered by the first occurrence of each element. For
154 * example, {@code ImmutableMultiset.copyOf([2, 3, 1, 3])} yields a multiset
155 * with elements in the order {@code 2, 3, 3, 1}.
156 *
157 * @throws NullPointerException if any of {@code elements} is null
158 * @since 6.0
159 */
160 public static <E> ImmutableMultiset<E> copyOf(E[] elements) {
161 return copyOf(Arrays.asList(elements));
162 }
163
164 /**
165 * Returns an immutable multiset containing the given elements.
166 *
167 * <p>The multiset is ordered by the first occurrence of each element. For
168 * example, {@code ImmutableMultiset.copyOf(Arrays.asList(2, 3, 1, 3))} yields
169 * a multiset with elements in the order {@code 2, 3, 3, 1}.
170 *
171 * <p>Despite the method name, this method attempts to avoid actually copying
172 * the data when it is safe to do so. The exact circumstances under which a
173 * copy will or will not be performed are undocumented and subject to change.
174 *
175 * <p><b>Note:</b> Despite what the method name suggests, if {@code elements}
176 * is an {@code ImmutableMultiset}, no copy will actually be performed, and
177 * the given multiset itself will be returned.
178 *
179 * @throws NullPointerException if any of {@code elements} is null
180 */
181 public static <E> ImmutableMultiset<E> copyOf(
182 Iterable<? extends E> elements) {
183 if (elements instanceof ImmutableMultiset) {
184 @SuppressWarnings("unchecked") // all supported methods are covariant
185 ImmutableMultiset<E> result = (ImmutableMultiset<E>) elements;
186 if (!result.isPartialView()) {
187 return result;
188 }
189 }
190
191 Multiset<? extends E> multiset = (elements instanceof Multiset)
192 ? Multisets.cast(elements)
193 : LinkedHashMultiset.create(elements);
194
195 return copyOfInternal(multiset);
196 }
197
198 private static <E> ImmutableMultiset<E> copyOfInternal(E... elements) {
199 return copyOf(Arrays.asList(elements));
200 }
201
202 private static <E> ImmutableMultiset<E> copyOfInternal(
203 Multiset<? extends E> multiset) {
204 return copyFromEntries(multiset.entrySet());
205 }
206
207 static <E> ImmutableMultiset<E> copyFromEntries(
208 Collection<? extends Entry<? extends E>> entries) {
209 long size = 0;
210 ImmutableMap.Builder<E, Integer> builder = ImmutableMap.builder();
211 for (Entry<? extends E> entry : entries) {
212 int count = entry.getCount();
213 if (count > 0) {
214 // Since ImmutableMap.Builder throws an NPE if an element is null, no
215 // other null checks are needed.
216 builder.put(entry.getElement(), count);
217 size += count;
218 }
219 }
220
221 if (size == 0) {
222 return of();
223 }
224 return new RegularImmutableMultiset<E>(builder.build(), Ints.saturatedCast(size));
225 }
226
227 /**
228 * Returns an immutable multiset containing the given elements.
229 *
230 * <p>The multiset is ordered by the first occurrence of each element. For
231 * example,
232 * {@code ImmutableMultiset.copyOf(Arrays.asList(2, 3, 1, 3).iterator())}
233 * yields a multiset with elements in the order {@code 2, 3, 3, 1}.
234 *
235 * @throws NullPointerException if any of {@code elements} is null
236 */
237 public static <E> ImmutableMultiset<E> copyOf(
238 Iterator<? extends E> elements) {
239 Multiset<E> multiset = LinkedHashMultiset.create();
240 Iterators.addAll(multiset, elements);
241 return copyOfInternal(multiset);
242 }
243
244 ImmutableMultiset() {}
245
246 @Override public UnmodifiableIterator<E> iterator() {
247 final Iterator<Entry<E>> entryIterator = entryIterator();
248
249 return new UnmodifiableIterator<E>() {
250 int remaining;
251 E element;
252
253 @Override
254 public boolean hasNext() {
255 return (remaining > 0) || entryIterator.hasNext();
256 }
257
258 @Override
259 public E next() {
260 if (remaining <= 0) {
261 Entry<E> entry = entryIterator.next();
262 element = entry.getElement();
263 remaining = entry.getCount();
264 }
265 remaining--;
266 return element;
267 }
268 };
269 }
270
271 @Override
272 public boolean contains(@Nullable Object object) {
273 return count(object) > 0;
274 }
275
276 @Override
277 public boolean containsAll(Collection<?> targets) {
278 return elementSet().containsAll(targets);
279 }
280
281 /**
282 * Guaranteed to throw an exception and leave the collection unmodified.
283 *
284 * @throws UnsupportedOperationException always
285 */
286 @Override
287 public final int add(E element, int occurrences) {
288 throw new UnsupportedOperationException();
289 }
290
291 /**
292 * Guaranteed to throw an exception and leave the collection unmodified.
293 *
294 * @throws UnsupportedOperationException always
295 */
296 @Override
297 public final int remove(Object element, int occurrences) {
298 throw new UnsupportedOperationException();
299 }
300
301 /**
302 * Guaranteed to throw an exception and leave the collection unmodified.
303 *
304 * @throws UnsupportedOperationException always
305 */
306 @Override
307 public final int setCount(E element, int count) {
308 throw new UnsupportedOperationException();
309 }
310
311 /**
312 * Guaranteed to throw an exception and leave the collection unmodified.
313 *
314 * @throws UnsupportedOperationException always
315 */
316 @Override
317 public final boolean setCount(E element, int oldCount, int newCount) {
318 throw new UnsupportedOperationException();
319 }
320
321 @Override public boolean equals(@Nullable Object object) {
322 if (object == this) {
323 return true;
324 }
325 if (object instanceof Multiset) {
326 Multiset<?> that = (Multiset<?>) object;
327 if (this.size() != that.size()) {
328 return false;
329 }
330 for (Entry<?> entry : that.entrySet()) {
331 if (count(entry.getElement()) != entry.getCount()) {
332 return false;
333 }
334 }
335 return true;
336 }
337 return false;
338 }
339
340 @Override public int hashCode() {
341 return Sets.hashCodeImpl(entrySet());
342 }
343
344 @Override public String toString() {
345 return entrySet().toString();
346 }
347
348 private transient ImmutableSet<Entry<E>> entrySet;
349
350 @Override
351 public Set<Entry<E>> entrySet() {
352 ImmutableSet<Entry<E>> es = entrySet;
353 return (es == null) ? (entrySet = createEntrySet()) : es;
354 }
355
356 abstract UnmodifiableIterator<Entry<E>> entryIterator();
357
358 abstract int distinctElements();
359
360 ImmutableSet<Entry<E>> createEntrySet() {
361 return new EntrySet<E>(this);
362 }
363
364 static class EntrySet<E> extends ImmutableSet<Entry<E>> {
365 transient final ImmutableMultiset<E> multiset;
366
367 public EntrySet(ImmutableMultiset<E> multiset) {
368 this.multiset = multiset;
369 }
370
371 @Override
372 public UnmodifiableIterator<Entry<E>> iterator() {
373 return multiset.entryIterator();
374 }
375
376 @Override
377 public int size() {
378 return multiset.distinctElements();
379 }
380
381 @Override
382 boolean isPartialView() {
383 return multiset.isPartialView();
384 }
385
386 @Override
387 public boolean contains(Object o) {
388 if (o instanceof Entry) {
389 Entry<?> entry = (Entry<?>) o;
390 if (entry.getCount() <= 0) {
391 return false;
392 }
393 int count = multiset.count(entry.getElement());
394 return count == entry.getCount();
395 }
396 return false;
397 }
398
399 /*
400 * TODO(hhchan): Revert once we have a separate, manual emulation of this
401 * class.
402 */
403 @Override
404 public Object[] toArray() {
405 Object[] newArray = new Object[size()];
406 return toArray(newArray);
407 }
408
409 /*
410 * TODO(hhchan): Revert once we have a separate, manual emulation of this
411 * class.
412 */
413 @Override
414 public <T> T[] toArray(T[] other) {
415 int size = size();
416 if (other.length < size) {
417 other = ObjectArrays.newArray(other, size);
418 } else if (other.length > size) {
419 other[size] = null;
420 }
421
422 // Writes will produce ArrayStoreException when the toArray() doc requires
423 Object[] otherAsObjectArray = other;
424 int index = 0;
425 for (Entry<?> element : this) {
426 otherAsObjectArray[index++] = element;
427 }
428 return other;
429 }
430
431 @Override
432 public int hashCode() {
433 return multiset.hashCode();
434 }
435
436 // We can't label this with @Override, because it doesn't override anything
437 // in the GWT emulated version.
438 Object writeReplace() {
439 return new EntrySetSerializedForm<E>(multiset);
440 }
441
442 static class EntrySetSerializedForm<E> implements Serializable {
443 final ImmutableMultiset<E> multiset;
444
445 EntrySetSerializedForm(ImmutableMultiset<E> multiset) {
446 this.multiset = multiset;
447 }
448
449 Object readResolve() {
450 return multiset.entrySet();
451 }
452 }
453
454 private static final long serialVersionUID = 0;
455 }
456
457 private static class SerializedForm implements Serializable {
458 final Object[] elements;
459 final int[] counts;
460
461 SerializedForm(Multiset<?> multiset) {
462 int distinct = multiset.entrySet().size();
463 elements = new Object[distinct];
464 counts = new int[distinct];
465 int i = 0;
466 for (Entry<?> entry : multiset.entrySet()) {
467 elements[i] = entry.getElement();
468 counts[i] = entry.getCount();
469 i++;
470 }
471 }
472
473 Object readResolve() {
474 LinkedHashMultiset<Object> multiset =
475 LinkedHashMultiset.create(elements.length);
476 for (int i = 0; i < elements.length; i++) {
477 multiset.add(elements[i], counts[i]);
478 }
479 return ImmutableMultiset.copyOf(multiset);
480 }
481
482 private static final long serialVersionUID = 0;
483 }
484
485 // We can't label this with @Override, because it doesn't override anything
486 // in the GWT emulated version.
487 Object writeReplace() {
488 return new SerializedForm(this);
489 }
490
491 /**
492 * Returns a new builder. The generated builder is equivalent to the builder
493 * created by the {@link Builder} constructor.
494 */
495 public static <E> Builder<E> builder() {
496 return new Builder<E>();
497 }
498
499 /**
500 * A builder for creating immutable multiset instances, especially {@code
501 * public static final} multisets ("constant multisets"). Example:
502 * <pre> {@code
503 *
504 * public static final ImmutableMultiset<Bean> BEANS =
505 * new ImmutableMultiset.Builder<Bean>()
506 * .addCopies(Bean.COCOA, 4)
507 * .addCopies(Bean.GARDEN, 6)
508 * .addCopies(Bean.RED, 8)
509 * .addCopies(Bean.BLACK_EYED, 10)
510 * .build();}</pre>
511 *
512 * Builder instances can be reused; it is safe to call {@link #build} multiple
513 * times to build multiple multisets in series.
514 *
515 * @since 2.0 (imported from Google Collections Library)
516 */
517 public static class Builder<E> extends ImmutableCollection.Builder<E> {
518 final Multiset<E> contents;
519
520 /**
521 * Creates a new builder. The returned builder is equivalent to the builder
522 * generated by {@link ImmutableMultiset#builder}.
523 */
524 public Builder() {
525 this(LinkedHashMultiset.<E>create());
526 }
527
528 Builder(Multiset<E> contents) {
529 this.contents = contents;
530 }
531
532 /**
533 * Adds {@code element} to the {@code ImmutableMultiset}.
534 *
535 * @param element the element to add
536 * @return this {@code Builder} object
537 * @throws NullPointerException if {@code element} is null
538 */
539 @Override public Builder<E> add(E element) {
540 contents.add(checkNotNull(element));
541 return this;
542 }
543
544 /**
545 * Adds a number of occurrences of an element to this {@code
546 * ImmutableMultiset}.
547 *
548 * @param element the element to add
549 * @param occurrences the number of occurrences of the element to add. May
550 * be zero, in which case no change will be made.
551 * @return this {@code Builder} object
552 * @throws NullPointerException if {@code element} is null
553 * @throws IllegalArgumentException if {@code occurrences} is negative, or
554 * if this operation would result in more than {@link Integer#MAX_VALUE}
555 * occurrences of the element
556 */
557 public Builder<E> addCopies(E element, int occurrences) {
558 contents.add(checkNotNull(element), occurrences);
559 return this;
560 }
561
562 /**
563 * Adds or removes the necessary occurrences of an element such that the
564 * element attains the desired count.
565 *
566 * @param element the element to add or remove occurrences of
567 * @param count the desired count of the element in this multiset
568 * @return this {@code Builder} object
569 * @throws NullPointerException if {@code element} is null
570 * @throws IllegalArgumentException if {@code count} is negative
571 */
572 public Builder<E> setCount(E element, int count) {
573 contents.setCount(checkNotNull(element), count);
574 return this;
575 }
576
577 /**
578 * Adds each element of {@code elements} to the {@code ImmutableMultiset}.
579 *
580 * @param elements the elements to add
581 * @return this {@code Builder} object
582 * @throws NullPointerException if {@code elements} is null or contains a
583 * null element
584 */
585 @Override public Builder<E> add(E... elements) {
586 super.add(elements);
587 return this;
588 }
589
590 /**
591 * Adds each element of {@code elements} to the {@code ImmutableMultiset}.
592 *
593 * @param elements the {@code Iterable} to add to the {@code
594 * ImmutableMultiset}
595 * @return this {@code Builder} object
596 * @throws NullPointerException if {@code elements} is null or contains a
597 * null element
598 */
599 @Override public Builder<E> addAll(Iterable<? extends E> elements) {
600 if (elements instanceof Multiset) {
601 Multiset<? extends E> multiset = Multisets.cast(elements);
602 for (Entry<? extends E> entry : multiset.entrySet()) {
603 addCopies(entry.getElement(), entry.getCount());
604 }
605 } else {
606 super.addAll(elements);
607 }
608 return this;
609 }
610
611 /**
612 * Adds each element of {@code elements} to the {@code ImmutableMultiset}.
613 *
614 * @param elements the elements to add to the {@code ImmutableMultiset}
615 * @return this {@code Builder} object
616 * @throws NullPointerException if {@code elements} is null or contains a
617 * null element
618 */
619 @Override public Builder<E> addAll(Iterator<? extends E> elements) {
620 super.addAll(elements);
621 return this;
622 }
623
624 /**
625 * Returns a newly-created {@code ImmutableMultiset} based on the contents
626 * of the {@code Builder}.
627 */
628 @Override public ImmutableMultiset<E> build() {
629 return copyOf(contents);
630 }
631 }
632 }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy