001    /*
002     * Copyright (C) 2009 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.Beta;
022    import com.google.common.annotations.GwtCompatible;
023    import com.google.common.annotations.GwtIncompatible;
024    
025    import java.io.IOException;
026    import java.io.InvalidObjectException;
027    import java.io.ObjectInputStream;
028    import java.io.ObjectOutputStream;
029    import java.util.Arrays;
030    import java.util.Collection;
031    import java.util.Comparator;
032    import java.util.LinkedHashMap;
033    import java.util.Map.Entry;
034    import java.util.TreeMap;
035    
036    import javax.annotation.Nullable;
037    
038    /**
039     * An immutable {@link SetMultimap} with reliable user-specified key and value
040     * iteration order. Does not permit null keys or values.
041     *
042     * <p>Unlike {@link Multimaps#unmodifiableSetMultimap(SetMultimap)}, which is
043     * a <i>view</i> of a separate multimap which can still change, an instance of
044     * {@code ImmutableSetMultimap} contains its own data and will <i>never</i>
045     * change. {@code ImmutableSetMultimap} is convenient for
046     * {@code public static final} multimaps ("constant multimaps") and also lets
047     * you easily make a "defensive copy" of a multimap provided to your class by
048     * a caller.
049     *
050     * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
051     * it has no public or protected constructors. Thus, instances of this class
052     * are guaranteed to be immutable.
053     * 
054     * <p>See the Guava User Guide article on <a href=
055     * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
056     * immutable collections</a>.
057     *
058     * @author Mike Ward
059     * @since 2.0 (imported from Google Collections Library)
060     */
061    @GwtCompatible(serializable = true, emulated = true)
062    public class ImmutableSetMultimap<K, V>
063        extends ImmutableMultimap<K, V>
064        implements SetMultimap<K, V> {
065    
066      /** Returns the empty multimap. */
067      // Casting is safe because the multimap will never hold any elements.
068      @SuppressWarnings("unchecked")
069      public static <K, V> ImmutableSetMultimap<K, V> of() {
070        return (ImmutableSetMultimap<K, V>) EmptyImmutableSetMultimap.INSTANCE;
071      }
072    
073      /**
074       * Returns an immutable multimap containing a single entry.
075       */
076      public static <K, V> ImmutableSetMultimap<K, V> of(K k1, V v1) {
077        ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
078        builder.put(k1, v1);
079        return builder.build();
080      }
081    
082      /**
083       * Returns an immutable multimap containing the given entries, in order.
084       * Repeated occurrences of an entry (according to {@link Object#equals}) after
085       * the first are ignored.
086       */
087      public static <K, V> ImmutableSetMultimap<K, V> of(K k1, V v1, K k2, V v2) {
088        ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
089        builder.put(k1, v1);
090        builder.put(k2, v2);
091        return builder.build();
092      }
093    
094      /**
095       * Returns an immutable multimap containing the given entries, in order.
096       * Repeated occurrences of an entry (according to {@link Object#equals}) after
097       * the first are ignored.
098       */
099      public static <K, V> ImmutableSetMultimap<K, V> of(
100          K k1, V v1, K k2, V v2, K k3, V v3) {
101        ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
102        builder.put(k1, v1);
103        builder.put(k2, v2);
104        builder.put(k3, v3);
105        return builder.build();
106      }
107    
108      /**
109       * Returns an immutable multimap containing the given entries, in order.
110       * Repeated occurrences of an entry (according to {@link Object#equals}) after
111       * the first are ignored.
112       */
113      public static <K, V> ImmutableSetMultimap<K, V> of(
114          K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
115        ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
116        builder.put(k1, v1);
117        builder.put(k2, v2);
118        builder.put(k3, v3);
119        builder.put(k4, v4);
120        return builder.build();
121      }
122    
123      /**
124       * Returns an immutable multimap containing the given entries, in order.
125       * Repeated occurrences of an entry (according to {@link Object#equals}) after
126       * the first are ignored.
127       */
128      public static <K, V> ImmutableSetMultimap<K, V> of(
129          K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
130        ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
131        builder.put(k1, v1);
132        builder.put(k2, v2);
133        builder.put(k3, v3);
134        builder.put(k4, v4);
135        builder.put(k5, v5);
136        return builder.build();
137      }
138    
139      // looking for of() with > 5 entries? Use the builder instead.
140    
141      /**
142       * Returns a new {@link Builder}.
143       */
144      public static <K, V> Builder<K, V> builder() {
145        return new Builder<K, V>();
146      }
147    
148      /**
149       * Multimap for {@link ImmutableSetMultimap.Builder} that maintains key
150       * and value orderings and performs better than {@link LinkedHashMultimap}.
151       */
152      private static class BuilderMultimap<K, V> extends AbstractMultimap<K, V> {
153        BuilderMultimap() {
154          super(new LinkedHashMap<K, Collection<V>>());
155        }
156        @Override Collection<V> createCollection() {
157          return Sets.newLinkedHashSet();
158        }
159        private static final long serialVersionUID = 0;
160      }
161    
162      /**
163       * Multimap for {@link ImmutableSetMultimap.Builder} that sorts keys and
164       * maintains value orderings.
165       */
166      private static class SortedKeyBuilderMultimap<K, V> 
167          extends AbstractMultimap<K, V> {
168        SortedKeyBuilderMultimap(
169            Comparator<? super K> keyComparator, Multimap<K, V> multimap) {
170          super(new TreeMap<K, Collection<V>>(keyComparator));
171          putAll(multimap);
172        }
173        @Override Collection<V> createCollection() {
174          return Sets.newLinkedHashSet();
175        }
176        private static final long serialVersionUID = 0;
177      }
178      
179      /**
180       * A builder for creating immutable {@code SetMultimap} instances, especially
181       * {@code public static final} multimaps ("constant multimaps"). Example:
182       * <pre>   {@code
183       *
184       *   static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
185       *       new ImmutableSetMultimap.Builder<String, Integer>()
186       *           .put("one", 1)
187       *           .putAll("several", 1, 2, 3)
188       *           .putAll("many", 1, 2, 3, 4, 5)
189       *           .build();}</pre>
190       *
191       * Builder instances can be reused; it is safe to call {@link #build} multiple
192       * times to build multiple multimaps in series. Each multimap contains the
193       * key-value mappings in the previously created multimaps.
194       *
195       * @since 2.0 (imported from Google Collections Library)
196       */
197      public static final class Builder<K, V>
198          extends ImmutableMultimap.Builder<K, V> {
199        /**
200         * Creates a new builder. The returned builder is equivalent to the builder
201         * generated by {@link ImmutableSetMultimap#builder}.
202         */
203        public Builder() {
204          builderMultimap = new BuilderMultimap<K, V>();      
205        }
206    
207        /**
208         * Adds a key-value mapping to the built multimap if it is not already
209         * present.
210         */
211        @Override public Builder<K, V> put(K key, V value) {
212          builderMultimap.put(checkNotNull(key), checkNotNull(value));
213          return this;
214        }
215    
216        /**
217         * Adds an entry to the built multimap if it is not already present.
218         *
219         * @since 11.0
220         */
221        @Override public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
222          builderMultimap.put(
223              checkNotNull(entry.getKey()), checkNotNull(entry.getValue()));
224          return this;
225        }
226    
227        @Override public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
228          Collection<V> collection = builderMultimap.get(checkNotNull(key));
229          for (V value : values) {
230            collection.add(checkNotNull(value));
231          }
232          return this;
233        }
234    
235        @Override public Builder<K, V> putAll(K key, V... values) {
236          return putAll(key, Arrays.asList(values));
237        }
238    
239        @Override public Builder<K, V> putAll(
240            Multimap<? extends K, ? extends V> multimap) {
241          for (Entry<? extends K, ? extends Collection<? extends V>> entry
242              : multimap.asMap().entrySet()) {
243            putAll(entry.getKey(), entry.getValue());
244          }
245          return this;
246        }
247    
248        /**
249         * {@inheritDoc}
250         *
251         * @since 8.0
252         */
253        @Beta @Override
254        public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
255          builderMultimap = new SortedKeyBuilderMultimap<K, V>(
256              checkNotNull(keyComparator), builderMultimap);
257          return this;
258        }
259    
260        /**
261         * Specifies the ordering of the generated multimap's values for each key.
262         * 
263         * <p>If this method is called, the sets returned by the {@code get()} 
264         * method of the generated multimap and its {@link Multimap#asMap()} view
265         * are {@link ImmutableSortedSet} instances. However, serialization does not
266         * preserve that property, though it does maintain the key and value
267         * ordering.
268         * 
269         * @since 8.0
270         */
271        // TODO: Make serialization behavior consistent.
272        @Beta @Override
273        public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
274          super.orderValuesBy(valueComparator);
275          return this;
276        }
277    
278        /**
279         * Returns a newly-created immutable set multimap.
280         */
281        @Override public ImmutableSetMultimap<K, V> build() {
282          return copyOf(builderMultimap, valueComparator);
283        }
284      }
285    
286      /**
287       * Returns an immutable set multimap containing the same mappings as
288       * {@code multimap}. The generated multimap's key and value orderings
289       * correspond to the iteration ordering of the {@code multimap.asMap()} view.
290       * Repeated occurrences of an entry in the multimap after the first are
291       * ignored.
292       *
293       * <p>Despite the method name, this method attempts to avoid actually copying
294       * the data when it is safe to do so. The exact circumstances under which a
295       * copy will or will not be performed are undocumented and subject to change.
296       *
297       * @throws NullPointerException if any key or value in {@code multimap} is
298       *     null
299       */
300      public static <K, V> ImmutableSetMultimap<K, V> copyOf(
301          Multimap<? extends K, ? extends V> multimap) {
302        return copyOf(multimap, null);
303      }
304      
305      private static <K, V> ImmutableSetMultimap<K, V> copyOf(
306          Multimap<? extends K, ? extends V> multimap,
307          Comparator<? super V> valueComparator) {
308        checkNotNull(multimap); // eager for GWT
309        if (multimap.isEmpty() && valueComparator == null) {
310          return of();
311        }
312    
313        if (multimap instanceof ImmutableSetMultimap) {
314          @SuppressWarnings("unchecked") // safe since multimap is not writable
315          ImmutableSetMultimap<K, V> kvMultimap
316              = (ImmutableSetMultimap<K, V>) multimap;
317          if (!kvMultimap.isPartialView()) {
318            return kvMultimap;
319          }
320        }
321    
322        ImmutableMap.Builder<K, ImmutableSet<V>> builder = ImmutableMap.builder();
323        int size = 0;
324    
325        for (Entry<? extends K, ? extends Collection<? extends V>> entry
326            : multimap.asMap().entrySet()) {
327          K key = entry.getKey();
328          Collection<? extends V> values = entry.getValue();
329          ImmutableSet<V> set = (valueComparator == null)
330              ? ImmutableSet.copyOf(values) 
331              : ImmutableSortedSet.copyOf(valueComparator, values);
332          if (!set.isEmpty()) {
333            builder.put(key, set);
334            size += set.size();
335          }
336        }
337    
338        return new ImmutableSetMultimap<K, V>(
339            builder.build(), size, valueComparator);
340      }
341    
342      // Returned by get() when values are sorted and a missing key is provided.
343      private final transient ImmutableSortedSet<V> emptySet;
344    
345      ImmutableSetMultimap(ImmutableMap<K, ImmutableSet<V>> map, int size, 
346          @Nullable Comparator<? super V> valueComparator) {
347        super(map, size);
348        this.emptySet = (valueComparator == null) 
349            ? null : ImmutableSortedSet.<V>emptySet(valueComparator);
350      }
351    
352      // views
353    
354      /**
355       * Returns an immutable set of the values for the given key.  If no mappings
356       * in the multimap have the provided key, an empty immutable set is returned.
357       * The values are in the same order as the parameters used to build this
358       * multimap.
359       */
360      @Override public ImmutableSet<V> get(@Nullable K key) {
361        // This cast is safe as its type is known in constructor.
362        ImmutableSet<V> set = (ImmutableSet<V>) map.get(key);
363        if (set != null) {
364          return set;
365        } else if (emptySet != null) {
366          return emptySet;
367        } else {
368          return ImmutableSet.<V>of();
369        }
370      }
371    
372      private transient ImmutableSetMultimap<V, K> inverse;
373    
374      /**
375       * {@inheritDoc}
376       *
377       * <p>Because an inverse of a set multimap cannot contain multiple pairs with the same key and
378       * value, this method returns an {@code ImmutableSetMultimap} rather than the
379       * {@code ImmutableMultimap} specified in the {@code ImmutableMultimap} class.
380       *
381       * @since 11
382       */
383      @Beta
384      public ImmutableSetMultimap<V, K> inverse() {
385        ImmutableSetMultimap<V, K> result = inverse;
386        return (result == null) ? (inverse = invert()) : result;
387      }
388    
389      private ImmutableSetMultimap<V, K> invert() {
390        Builder<V, K> builder = builder();
391        for (Entry<K, V> entry : entries()) {
392          builder.put(entry.getValue(), entry.getKey());
393        }
394        ImmutableSetMultimap<V, K> invertedMultimap = builder.build();
395        invertedMultimap.inverse = this;
396        return invertedMultimap;
397      }
398    
399      /**
400       * Guaranteed to throw an exception and leave the multimap unmodified.
401       *
402       * @throws UnsupportedOperationException always
403       */
404      @Override public ImmutableSet<V> removeAll(Object key) {
405        throw new UnsupportedOperationException();
406      }
407    
408      /**
409       * Guaranteed to throw an exception and leave the multimap unmodified.
410       *
411       * @throws UnsupportedOperationException always
412       */
413      @Override public ImmutableSet<V> replaceValues(
414          K key, Iterable<? extends V> values) {
415        throw new UnsupportedOperationException();
416      }
417    
418      private transient ImmutableSet<Entry<K, V>> entries;
419    
420      /**
421       * Returns an immutable collection of all key-value pairs in the multimap.
422       * Its iterator traverses the values for the first key, the values for the
423       * second key, and so on.
424       */
425      // TODO(kevinb): Fix this so that two copies of the entries are not created.
426      @Override public ImmutableSet<Entry<K, V>> entries() {
427        ImmutableSet<Entry<K, V>> result = entries;
428        return (result == null)
429            ? (entries = ImmutableSet.copyOf(super.entries()))
430            : result;
431      }
432    
433      /**
434       * @serialData number of distinct keys, and then for each distinct key: the
435       *     key, the number of values for that key, and the key's values
436       */
437      @GwtIncompatible("java.io.ObjectOutputStream")
438      private void writeObject(ObjectOutputStream stream) throws IOException {
439        stream.defaultWriteObject();
440        Serialization.writeMultimap(this, stream);
441      }
442    
443      @GwtIncompatible("java.io.ObjectInputStream")
444      private void readObject(ObjectInputStream stream)
445          throws IOException, ClassNotFoundException {
446        stream.defaultReadObject();
447        int keyCount = stream.readInt();
448        if (keyCount < 0) {
449          throw new InvalidObjectException("Invalid key count " + keyCount);
450        }
451        ImmutableMap.Builder<Object, ImmutableSet<Object>> builder
452            = ImmutableMap.builder();
453        int tmpSize = 0;
454    
455        for (int i = 0; i < keyCount; i++) {
456          Object key = stream.readObject();
457          int valueCount = stream.readInt();
458          if (valueCount <= 0) {
459            throw new InvalidObjectException("Invalid value count " + valueCount);
460          }
461    
462          Object[] array = new Object[valueCount];
463          for (int j = 0; j < valueCount; j++) {
464            array[j] = stream.readObject();
465          }
466          ImmutableSet<Object> valueSet = ImmutableSet.copyOf(array);
467          if (valueSet.size() != array.length) {
468            throw new InvalidObjectException(
469                "Duplicate key-value pairs exist for key " + key);
470          }
471          builder.put(key, valueSet);
472          tmpSize += valueCount;
473        }
474    
475        ImmutableMap<Object, ImmutableSet<Object>> tmpMap;
476        try {
477          tmpMap = builder.build();
478        } catch (IllegalArgumentException e) {
479          throw (InvalidObjectException)
480              new InvalidObjectException(e.getMessage()).initCause(e);
481        }
482    
483        FieldSettersHolder.MAP_FIELD_SETTER.set(this, tmpMap);
484        FieldSettersHolder.SIZE_FIELD_SETTER.set(this, tmpSize);
485      }
486    
487      @GwtIncompatible("not needed in emulated source.")
488      private static final long serialVersionUID = 0;
489    }