All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.collect.ImmutableMultiset Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * Copyright (C) 2008 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Objects.requireNonNull;

import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.J2ktIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.DoNotCall;
import com.google.errorprone.annotations.concurrent.LazyInit;
import com.google.j2objc.annotations.WeakOuter;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.stream.Collector;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * A {@link Multiset} whose contents will never change, with many other important properties
 * detailed at {@link ImmutableCollection}.
 *
 * 

Grouped iteration. In all current implementations, duplicate elements always appear * consecutively when iterating. Elements iterate in order by the first appearance of that * element when the multiset was created. * *

See the Guava User Guide article on immutable collections. * * @author Jared Levy * @author Louis Wasserman * @since 2.0 */ @GwtCompatible(serializable = true, emulated = true) @SuppressWarnings("serial") // we're overriding default serialization @ElementTypesAreNonnullByDefault public abstract class ImmutableMultiset extends ImmutableMultisetGwtSerializationDependencies implements Multiset { /** * Returns a {@code Collector} that accumulates the input elements into a new {@code * ImmutableMultiset}. Elements iterate in order by the first appearance of that element in * encounter order. * * @since 21.0 */ public static Collector> toImmutableMultiset() { return CollectCollectors.toImmutableMultiset(Function.identity(), e -> 1); } /** * Returns a {@code Collector} that accumulates elements into an {@code ImmutableMultiset} whose * elements are the result of applying {@code elementFunction} to the inputs, with counts equal to * the result of applying {@code countFunction} to the inputs. * *

If the mapped elements contain duplicates (according to {@link Object#equals}), the first * occurrence in encounter order appears in the resulting multiset, with count equal to the sum of * the outputs of {@code countFunction.applyAsInt(t)} for each {@code t} mapped to that element. * * @since 22.0 */ public static Collector> toImmutableMultiset( Function elementFunction, ToIntFunction countFunction) { return CollectCollectors.toImmutableMultiset(elementFunction, countFunction); } /** * Returns the empty immutable multiset. * *

Performance note: the instance returned is a singleton. */ @SuppressWarnings("unchecked") // all supported methods are covariant public static ImmutableMultiset of() { return (ImmutableMultiset) RegularImmutableMultiset.EMPTY; } /** * Returns an immutable multiset containing a single element. * * @throws NullPointerException if {@code element} is null * @since 6.0 (source-compatible since 2.0) */ public static ImmutableMultiset of(E element) { return copyFromElements(element); } /** * Returns an immutable multiset containing the given elements, in order. * * @throws NullPointerException if any element is null * @since 6.0 (source-compatible since 2.0) */ public static ImmutableMultiset of(E e1, E e2) { return copyFromElements(e1, e2); } /** * Returns an immutable multiset containing the given elements, in the "grouped iteration order" * described in the class documentation. * * @throws NullPointerException if any element is null * @since 6.0 (source-compatible since 2.0) */ public static ImmutableMultiset of(E e1, E e2, E e3) { return copyFromElements(e1, e2, e3); } /** * Returns an immutable multiset containing the given elements, in the "grouped iteration order" * described in the class documentation. * * @throws NullPointerException if any element is null * @since 6.0 (source-compatible since 2.0) */ public static ImmutableMultiset of(E e1, E e2, E e3, E e4) { return copyFromElements(e1, e2, e3, e4); } /** * Returns an immutable multiset containing the given elements, in the "grouped iteration order" * described in the class documentation. * * @throws NullPointerException if any element is null * @since 6.0 (source-compatible since 2.0) */ public static ImmutableMultiset of(E e1, E e2, E e3, E e4, E e5) { return copyFromElements(e1, e2, e3, e4, e5); } /** * Returns an immutable multiset containing the given elements, in the "grouped iteration order" * described in the class documentation. * * @throws NullPointerException if any element is null * @since 6.0 (source-compatible since 2.0) */ public static ImmutableMultiset of(E e1, E e2, E e3, E e4, E e5, E e6, E... others) { return new Builder().add(e1).add(e2).add(e3).add(e4).add(e5).add(e6).add(others).build(); } /** * Returns an immutable multiset containing the given elements, in the "grouped iteration order" * described in the class documentation. * * @throws NullPointerException if any of {@code elements} is null * @since 6.0 */ public static ImmutableMultiset copyOf(E[] elements) { return copyFromElements(elements); } /** * Returns an immutable multiset containing the given elements, in the "grouped iteration order" * described in the class documentation. * * @throws NullPointerException if any of {@code elements} is null */ public static ImmutableMultiset copyOf(Iterable elements) { if (elements instanceof ImmutableMultiset) { @SuppressWarnings("unchecked") // all supported methods are covariant ImmutableMultiset result = (ImmutableMultiset) elements; if (!result.isPartialView()) { return result; } } Multiset multiset = (elements instanceof Multiset) ? Multisets.cast(elements) : LinkedHashMultiset.create(elements); return copyFromEntries(multiset.entrySet()); } /** * Returns an immutable multiset containing the given elements, in the "grouped iteration order" * described in the class documentation. * * @throws NullPointerException if any of {@code elements} is null */ public static ImmutableMultiset copyOf(Iterator elements) { Multiset multiset = LinkedHashMultiset.create(); Iterators.addAll(multiset, elements); return copyFromEntries(multiset.entrySet()); } private static ImmutableMultiset copyFromElements(E... elements) { Multiset multiset = LinkedHashMultiset.create(); Collections.addAll(multiset, elements); return copyFromEntries(multiset.entrySet()); } static ImmutableMultiset copyFromEntries( Collection> entries) { if (entries.isEmpty()) { return of(); } else { return RegularImmutableMultiset.create(entries); } } ImmutableMultiset() {} @Override public UnmodifiableIterator iterator() { final Iterator> entryIterator = entrySet().iterator(); return new UnmodifiableIterator() { int remaining; @CheckForNull E element; @Override public boolean hasNext() { return (remaining > 0) || entryIterator.hasNext(); } @Override public E next() { if (remaining <= 0) { Entry entry = entryIterator.next(); element = entry.getElement(); remaining = entry.getCount(); } remaining--; /* * requireNonNull is safe because `remaining` starts at 0, forcing us to initialize * `element` above. After that, we never clear it. */ return requireNonNull(element); } }; } @LazyInit @CheckForNull private transient ImmutableList asList; @Override public ImmutableList asList() { ImmutableList result = asList; return (result == null) ? asList = super.asList() : result; } @Override public boolean contains(@CheckForNull Object object) { return count(object) > 0; } /** * Guaranteed to throw an exception and leave the collection unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @CanIgnoreReturnValue @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") public final int add(E element, int occurrences) { throw new UnsupportedOperationException(); } /** * Guaranteed to throw an exception and leave the collection unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @CanIgnoreReturnValue @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") public final int remove(@CheckForNull Object element, int occurrences) { throw new UnsupportedOperationException(); } /** * Guaranteed to throw an exception and leave the collection unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @CanIgnoreReturnValue @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") public final int setCount(E element, int count) { throw new UnsupportedOperationException(); } /** * Guaranteed to throw an exception and leave the collection unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @CanIgnoreReturnValue @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") public final boolean setCount(E element, int oldCount, int newCount) { throw new UnsupportedOperationException(); } @GwtIncompatible // not present in emulated superclass @Override int copyIntoArray(@Nullable Object[] dst, int offset) { for (Multiset.Entry entry : entrySet()) { Arrays.fill(dst, offset, offset + entry.getCount(), entry.getElement()); offset += entry.getCount(); } return offset; } @Override public boolean equals(@CheckForNull Object object) { return Multisets.equalsImpl(this, object); } @Override public int hashCode() { return Sets.hashCodeImpl(entrySet()); } @Override public String toString() { return entrySet().toString(); } /** @since 21.0 (present with return type {@code Set} since 2.0) */ @Override public abstract ImmutableSet elementSet(); @LazyInit @CheckForNull private transient ImmutableSet> entrySet; @Override public ImmutableSet> entrySet() { ImmutableSet> es = entrySet; return (es == null) ? (entrySet = createEntrySet()) : es; } private ImmutableSet> createEntrySet() { return isEmpty() ? ImmutableSet.>of() : new EntrySet(); } abstract Entry getEntry(int index); @WeakOuter private final class EntrySet extends IndexedImmutableSet> { @Override boolean isPartialView() { return ImmutableMultiset.this.isPartialView(); } @Override Entry get(int index) { return getEntry(index); } @Override public int size() { return elementSet().size(); } @Override public boolean contains(@CheckForNull Object o) { if (o instanceof Entry) { Entry entry = (Entry) o; if (entry.getCount() <= 0) { return false; } int count = count(entry.getElement()); return count == entry.getCount(); } return false; } @Override public int hashCode() { return ImmutableMultiset.this.hashCode(); } @GwtIncompatible @J2ktIncompatible @Override Object writeReplace() { return new EntrySetSerializedForm(ImmutableMultiset.this); } @GwtIncompatible @J2ktIncompatible private void readObject(ObjectInputStream stream) throws InvalidObjectException { throw new InvalidObjectException("Use EntrySetSerializedForm"); } @J2ktIncompatible private static final long serialVersionUID = 0; } @GwtIncompatible @J2ktIncompatible static class EntrySetSerializedForm implements Serializable { final ImmutableMultiset multiset; EntrySetSerializedForm(ImmutableMultiset multiset) { this.multiset = multiset; } Object readResolve() { return multiset.entrySet(); } } @GwtIncompatible @J2ktIncompatible @Override Object writeReplace() { return new SerializedForm(this); } @GwtIncompatible @J2ktIncompatible private void readObject(ObjectInputStream stream) throws InvalidObjectException { throw new InvalidObjectException("Use SerializedForm"); } /** * Returns a new builder. The generated builder is equivalent to the builder created by the {@link * Builder} constructor. */ public static Builder builder() { return new Builder(); } /** * A builder for creating immutable multiset instances, especially {@code public static final} * multisets ("constant multisets"). Example: * *

{@code
   * public static final ImmutableMultiset BEANS =
   *     new ImmutableMultiset.Builder()
   *         .addCopies(Bean.COCOA, 4)
   *         .addCopies(Bean.GARDEN, 6)
   *         .addCopies(Bean.RED, 8)
   *         .addCopies(Bean.BLACK_EYED, 10)
   *         .build();
   * }
* *

Builder instances can be reused; it is safe to call {@link #build} multiple times to build * multiple multisets in series. * * @since 2.0 */ public static class Builder extends ImmutableCollection.Builder { final Multiset contents; /** * Creates a new builder. The returned builder is equivalent to the builder generated by {@link * ImmutableMultiset#builder}. */ public Builder() { this(LinkedHashMultiset.create()); } Builder(Multiset contents) { this.contents = contents; } /** * Adds {@code element} to the {@code ImmutableMultiset}. * * @param element the element to add * @return this {@code Builder} object * @throws NullPointerException if {@code element} is null */ @CanIgnoreReturnValue @Override public Builder add(E element) { contents.add(checkNotNull(element)); return this; } /** * Adds each element of {@code elements} to the {@code ImmutableMultiset}. * * @param elements the elements to add * @return this {@code Builder} object * @throws NullPointerException if {@code elements} is null or contains a null element */ @CanIgnoreReturnValue @Override public Builder add(E... elements) { super.add(elements); return this; } /** * Adds a number of occurrences of an element to this {@code ImmutableMultiset}. * * @param element the element to add * @param occurrences the number of occurrences of the element to add. May be zero, in which * case no change will be made. * @return this {@code Builder} object * @throws NullPointerException if {@code element} is null * @throws IllegalArgumentException if {@code occurrences} is negative, or if this operation * would result in more than {@link Integer#MAX_VALUE} occurrences of the element */ @CanIgnoreReturnValue public Builder addCopies(E element, int occurrences) { contents.add(checkNotNull(element), occurrences); return this; } /** * Adds or removes the necessary occurrences of an element such that the element attains the * desired count. * * @param element the element to add or remove occurrences of * @param count the desired count of the element in this multiset * @return this {@code Builder} object * @throws NullPointerException if {@code element} is null * @throws IllegalArgumentException if {@code count} is negative */ @CanIgnoreReturnValue public Builder setCount(E element, int count) { contents.setCount(checkNotNull(element), count); return this; } /** * Adds each element of {@code elements} to the {@code ImmutableMultiset}. * * @param elements the {@code Iterable} to add to the {@code ImmutableMultiset} * @return this {@code Builder} object * @throws NullPointerException if {@code elements} is null or contains a null element */ @CanIgnoreReturnValue @Override public Builder addAll(Iterable elements) { if (elements instanceof Multiset) { Multiset multiset = Multisets.cast(elements); multiset.forEachEntry((e, n) -> contents.add(checkNotNull(e), n)); } else { super.addAll(elements); } return this; } /** * Adds each element of {@code elements} to the {@code ImmutableMultiset}. * * @param elements the elements to add to the {@code ImmutableMultiset} * @return this {@code Builder} object * @throws NullPointerException if {@code elements} is null or contains a null element */ @CanIgnoreReturnValue @Override public Builder addAll(Iterator elements) { super.addAll(elements); return this; } /** * Returns a newly-created {@code ImmutableMultiset} based on the contents of the {@code * Builder}. */ @Override public ImmutableMultiset build() { return copyOf(contents); } @VisibleForTesting ImmutableMultiset buildJdkBacked() { if (contents.isEmpty()) { return of(); } return JdkBackedImmutableMultiset.create(contents.entrySet()); } } static final class ElementSet extends ImmutableSet.Indexed { private final List> entries; // TODO(cpovirk): @Weak? private final Multiset delegate; ElementSet(List> entries, Multiset delegate) { this.entries = entries; this.delegate = delegate; } @Override E get(int index) { return entries.get(index).getElement(); } @Override public boolean contains(@CheckForNull Object object) { return delegate.contains(object); } @Override boolean isPartialView() { return true; } @Override public int size() { return entries.size(); } // redeclare to help optimizers with b/310253115 @SuppressWarnings("RedundantOverride") @Override @J2ktIncompatible // serialization @GwtIncompatible // serialization Object writeReplace() { return super.writeReplace(); } } @J2ktIncompatible static final class SerializedForm implements Serializable { final Object[] elements; final int[] counts; // "extends Object" works around https://github.com/typetools/checker-framework/issues/3013 SerializedForm(Multiset multiset) { int distinct = multiset.entrySet().size(); elements = new Object[distinct]; counts = new int[distinct]; int i = 0; for (Entry entry : multiset.entrySet()) { elements[i] = entry.getElement(); counts[i] = entry.getCount(); i++; } } Object readResolve() { LinkedHashMultiset multiset = LinkedHashMultiset.create(elements.length); for (int i = 0; i < elements.length; i++) { multiset.add(elements[i], counts[i]); } return ImmutableMultiset.copyOf(multiset); } private static final long serialVersionUID = 0; } private static final long serialVersionUID = 0xcafebabe; }