1/*
2 * Copyright (C) 2009 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.collect;
18
19import static com.google.common.base.Preconditions.checkNotNull;
20
21import com.google.common.annotations.Beta;
22import com.google.common.annotations.GwtCompatible;
23
24import java.util.Arrays;
25import java.util.Collection;
26import java.util.Comparator;
27import java.util.LinkedHashMap;
28import java.util.Map.Entry;
29import java.util.TreeMap;
30
31import javax.annotation.Nullable;
32
33/**
34 * An immutable {@link SetMultimap} with reliable user-specified key and value
35 * iteration order. Does not permit null keys or values.
36 *
37 * <p>Unlike {@link Multimaps#unmodifiableSetMultimap(SetMultimap)}, which is
38 * a <i>view</i> of a separate multimap which can still change, an instance of
39 * {@code ImmutableSetMultimap} contains its own data and will <i>never</i>
40 * change. {@code ImmutableSetMultimap} is convenient for
41 * {@code public static final} multimaps ("constant multimaps") and also lets
42 * you easily make a "defensive copy" of a multimap provided to your class by
43 * a caller.
44 *
45 * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
46 * it has no public or protected constructors. Thus, instances of this class
47 * are guaranteed to be immutable.
48 *
49 * @author Mike Ward
50 * @since 2.0 (imported from Google Collections Library)
51 */
52@GwtCompatible(serializable = true, emulated = true)
53public class ImmutableSetMultimap<K, V>
54    extends ImmutableMultimap<K, V>
55    implements SetMultimap<K, V> {
56
57  /** Returns the empty multimap. */
58  // Casting is safe because the multimap will never hold any elements.
59  @SuppressWarnings("unchecked")
60  public static <K, V> ImmutableSetMultimap<K, V> of() {
61    return (ImmutableSetMultimap<K, V>) EmptyImmutableSetMultimap.INSTANCE;
62  }
63
64  /**
65   * Returns an immutable multimap containing a single entry.
66   */
67  public static <K, V> ImmutableSetMultimap<K, V> of(K k1, V v1) {
68    ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
69    builder.put(k1, v1);
70    return builder.build();
71  }
72
73  /**
74   * Returns an immutable multimap containing the given entries, in order.
75   * Repeated occurrences of an entry (according to {@link Object#equals}) after
76   * the first are ignored.
77   */
78  public static <K, V> ImmutableSetMultimap<K, V> of(K k1, V v1, K k2, V v2) {
79    ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
80    builder.put(k1, v1);
81    builder.put(k2, v2);
82    return builder.build();
83  }
84
85  /**
86   * Returns an immutable multimap containing the given entries, in order.
87   * Repeated occurrences of an entry (according to {@link Object#equals}) after
88   * the first are ignored.
89   */
90  public static <K, V> ImmutableSetMultimap<K, V> of(
91      K k1, V v1, K k2, V v2, K k3, V v3) {
92    ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
93    builder.put(k1, v1);
94    builder.put(k2, v2);
95    builder.put(k3, v3);
96    return builder.build();
97  }
98
99  /**
100   * Returns an immutable multimap containing the given entries, in order.
101   * Repeated occurrences of an entry (according to {@link Object#equals}) after
102   * the first are ignored.
103   */
104  public static <K, V> ImmutableSetMultimap<K, V> of(
105      K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
106    ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
107    builder.put(k1, v1);
108    builder.put(k2, v2);
109    builder.put(k3, v3);
110    builder.put(k4, v4);
111    return builder.build();
112  }
113
114  /**
115   * Returns an immutable multimap containing the given entries, in order.
116   * Repeated occurrences of an entry (according to {@link Object#equals}) after
117   * the first are ignored.
118   */
119  public static <K, V> ImmutableSetMultimap<K, V> of(
120      K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
121    ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
122    builder.put(k1, v1);
123    builder.put(k2, v2);
124    builder.put(k3, v3);
125    builder.put(k4, v4);
126    builder.put(k5, v5);
127    return builder.build();
128  }
129
130  // looking for of() with > 5 entries? Use the builder instead.
131
132  /**
133   * Returns a new {@link Builder}.
134   */
135  public static <K, V> Builder<K, V> builder() {
136    return new Builder<K, V>();
137  }
138
139  /**
140   * Multimap for {@link ImmutableSetMultimap.Builder} that maintains key
141   * and value orderings and performs better than {@link LinkedHashMultimap}.
142   */
143  private static class BuilderMultimap<K, V> extends AbstractMultimap<K, V> {
144    BuilderMultimap() {
145      super(new LinkedHashMap<K, Collection<V>>());
146    }
147    @Override Collection<V> createCollection() {
148      return Sets.newLinkedHashSet();
149    }
150    private static final long serialVersionUID = 0;
151  }
152
153  /**
154   * Multimap for {@link ImmutableSetMultimap.Builder} that sorts keys and
155   * maintains value orderings.
156   */
157  private static class SortedKeyBuilderMultimap<K, V>
158      extends AbstractMultimap<K, V> {
159    SortedKeyBuilderMultimap(
160        Comparator<? super K> keyComparator, Multimap<K, V> multimap) {
161      super(new TreeMap<K, Collection<V>>(keyComparator));
162      putAll(multimap);
163    }
164    @Override Collection<V> createCollection() {
165      return Sets.newLinkedHashSet();
166    }
167    private static final long serialVersionUID = 0;
168  }
169
170  /**
171   * A builder for creating immutable {@code SetMultimap} instances, especially
172   * {@code public static final} multimaps ("constant multimaps"). Example:
173   * <pre>   {@code
174   *
175   *   static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
176   *       new ImmutableSetMultimap.Builder<String, Integer>()
177   *           .put("one", 1)
178   *           .putAll("several", 1, 2, 3)
179   *           .putAll("many", 1, 2, 3, 4, 5)
180   *           .build();}</pre>
181   *
182   * Builder instances can be reused; it is safe to call {@link #build} multiple
183   * times to build multiple multimaps in series. Each multimap contains the
184   * key-value mappings in the previously created multimaps.
185   *
186   * @since 2.0 (imported from Google Collections Library)
187   */
188  public static final class Builder<K, V>
189      extends ImmutableMultimap.Builder<K, V> {
190    /**
191     * Creates a new builder. The returned builder is equivalent to the builder
192     * generated by {@link ImmutableSetMultimap#builder}.
193     */
194    public Builder() {
195      builderMultimap = new BuilderMultimap<K, V>();
196    }
197
198    /**
199     * Adds a key-value mapping to the built multimap if it is not already
200     * present.
201     */
202    @Override public Builder<K, V> put(K key, V value) {
203      builderMultimap.put(checkNotNull(key), checkNotNull(value));
204      return this;
205    }
206
207    /**
208     * Adds an entry to the built multimap if it is not already present.
209     *
210     * @since 11.0
211     */
212    @Override public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
213      builderMultimap.put(
214          checkNotNull(entry.getKey()), checkNotNull(entry.getValue()));
215      return this;
216    }
217
218    @Override public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
219      Collection<V> collection = builderMultimap.get(checkNotNull(key));
220      for (V value : values) {
221        collection.add(checkNotNull(value));
222      }
223      return this;
224    }
225
226    @Override public Builder<K, V> putAll(K key, V... values) {
227      return putAll(key, Arrays.asList(values));
228    }
229
230    @Override public Builder<K, V> putAll(
231        Multimap<? extends K, ? extends V> multimap) {
232      for (Entry<? extends K, ? extends Collection<? extends V>> entry
233          : multimap.asMap().entrySet()) {
234        putAll(entry.getKey(), entry.getValue());
235      }
236      return this;
237    }
238
239    /**
240     * {@inheritDoc}
241     *
242     * @since 8.0
243     */
244    @Beta @Override
245    public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
246      builderMultimap = new SortedKeyBuilderMultimap<K, V>(
247          checkNotNull(keyComparator), builderMultimap);
248      return this;
249    }
250
251    /**
252     * Specifies the ordering of the generated multimap's values for each key.
253     *
254     * <p>If this method is called, the sets returned by the {@code get()}
255     * method of the generated multimap and its {@link Multimap#asMap()} view
256     * are {@link ImmutableSortedSet} instances. However, serialization does not
257     * preserve that property, though it does maintain the key and value
258     * ordering.
259     *
260     * @since 8.0
261     */
262    // TODO: Make serialization behavior consistent.
263    @Beta @Override
264    public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
265      super.orderValuesBy(valueComparator);
266      return this;
267    }
268
269    /**
270     * Returns a newly-created immutable set multimap.
271     */
272    @Override public ImmutableSetMultimap<K, V> build() {
273      return copyOf(builderMultimap, valueComparator);
274    }
275  }
276
277  /**
278   * Returns an immutable set multimap containing the same mappings as
279   * {@code multimap}. The generated multimap's key and value orderings
280   * correspond to the iteration ordering of the {@code multimap.asMap()} view.
281   * Repeated occurrences of an entry in the multimap after the first are
282   * ignored.
283   *
284   * <p>Despite the method name, this method attempts to avoid actually copying
285   * the data when it is safe to do so. The exact circumstances under which a
286   * copy will or will not be performed are undocumented and subject to change.
287   *
288   * @throws NullPointerException if any key or value in {@code multimap} is
289   *     null
290   */
291  public static <K, V> ImmutableSetMultimap<K, V> copyOf(
292      Multimap<? extends K, ? extends V> multimap) {
293    return copyOf(multimap, null);
294  }
295
296  private static <K, V> ImmutableSetMultimap<K, V> copyOf(
297      Multimap<? extends K, ? extends V> multimap,
298      Comparator<? super V> valueComparator) {
299    checkNotNull(multimap); // eager for GWT
300    if (multimap.isEmpty() && valueComparator == null) {
301      return of();
302    }
303
304    if (multimap instanceof ImmutableSetMultimap) {
305      @SuppressWarnings("unchecked") // safe since multimap is not writable
306      ImmutableSetMultimap<K, V> kvMultimap
307          = (ImmutableSetMultimap<K, V>) multimap;
308      if (!kvMultimap.isPartialView()) {
309        return kvMultimap;
310      }
311    }
312
313    ImmutableMap.Builder<K, ImmutableSet<V>> builder = ImmutableMap.builder();
314    int size = 0;
315
316    for (Entry<? extends K, ? extends Collection<? extends V>> entry
317        : multimap.asMap().entrySet()) {
318      K key = entry.getKey();
319      Collection<? extends V> values = entry.getValue();
320      ImmutableSet<V> set = (valueComparator == null)
321          ? ImmutableSet.copyOf(values)
322          : ImmutableSortedSet.copyOf(valueComparator, values);
323      if (!set.isEmpty()) {
324        builder.put(key, set);
325        size += set.size();
326      }
327    }
328
329    return new ImmutableSetMultimap<K, V>(
330        builder.build(), size, valueComparator);
331  }
332
333  // Returned by get() when values are sorted and a missing key is provided.
334  private final transient ImmutableSortedSet<V> emptySet;
335
336  ImmutableSetMultimap(ImmutableMap<K, ImmutableSet<V>> map, int size,
337      @Nullable Comparator<? super V> valueComparator) {
338    super(map, size);
339    this.emptySet = (valueComparator == null)
340        ? null : ImmutableSortedSet.<V>emptySet(valueComparator);
341  }
342
343  // views
344
345  /**
346   * Returns an immutable set of the values for the given key.  If no mappings
347   * in the multimap have the provided key, an empty immutable set is returned.
348   * The values are in the same order as the parameters used to build this
349   * multimap.
350   */
351  @Override public ImmutableSet<V> get(@Nullable K key) {
352    // This cast is safe as its type is known in constructor.
353    ImmutableSet<V> set = (ImmutableSet<V>) map.get(key);
354    if (set != null) {
355      return set;
356    } else if (emptySet != null) {
357      return emptySet;
358    } else {
359      return ImmutableSet.<V>of();
360    }
361  }
362
363  private transient ImmutableSetMultimap<V, K> inverse;
364
365  /**
366   * {@inheritDoc}
367   *
368   * <p>Because an inverse of a set multimap cannot contain multiple pairs with the same key and
369   * value, this method returns an {@code ImmutableSetMultimap} rather than the
370   * {@code ImmutableMultimap} specified in the {@code ImmutableMultimap} class.
371   *
372   * @since 11
373   */
374  @Beta
375  public ImmutableSetMultimap<V, K> inverse() {
376    ImmutableSetMultimap<V, K> result = inverse;
377    return (result == null) ? (inverse = invert()) : result;
378  }
379
380  private ImmutableSetMultimap<V, K> invert() {
381    Builder<V, K> builder = builder();
382    for (Entry<K, V> entry : entries()) {
383      builder.put(entry.getValue(), entry.getKey());
384    }
385    ImmutableSetMultimap<V, K> invertedMultimap = builder.build();
386    invertedMultimap.inverse = this;
387    return invertedMultimap;
388  }
389
390  /**
391   * Guaranteed to throw an exception and leave the multimap unmodified.
392   *
393   * @throws UnsupportedOperationException always
394   */
395  @Override public ImmutableSet<V> removeAll(Object key) {
396    throw new UnsupportedOperationException();
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> replaceValues(
405      K key, Iterable<? extends V> values) {
406    throw new UnsupportedOperationException();
407  }
408
409  private transient ImmutableSet<Entry<K, V>> entries;
410
411  /**
412   * Returns an immutable collection of all key-value pairs in the multimap.
413   * Its iterator traverses the values for the first key, the values for the
414   * second key, and so on.
415   */
416  // TODO(kevinb): Fix this so that two copies of the entries are not created.
417  @Override public ImmutableSet<Entry<K, V>> entries() {
418    ImmutableSet<Entry<K, V>> result = entries;
419    return (result == null)
420        ? (entries = ImmutableSet.copyOf(super.entries()))
421        : result;
422  }
423}
424
425