1/*
2 * Copyright (C) 2008 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 com.google.common.annotations.Beta;
20import com.google.common.annotations.GwtCompatible;
21
22import java.util.Collection;
23import java.util.Comparator;
24import java.util.Map.Entry;
25
26import javax.annotation.Nullable;
27
28/**
29 * An immutable {@link ListMultimap} with reliable user-specified key and value
30 * iteration order. Does not permit null keys or values.
31 *
32 * <p>Unlike {@link Multimaps#unmodifiableListMultimap(ListMultimap)}, which is
33 * a <i>view</i> of a separate multimap which can still change, an instance of
34 * {@code ImmutableListMultimap} contains its own data and will <i>never</i>
35 * change. {@code ImmutableListMultimap} is convenient for
36 * {@code public static final} multimaps ("constant multimaps") and also lets
37 * you easily make a "defensive copy" of a multimap provided to your class by
38 * a caller.
39 *
40 * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
41 * it has no public or protected constructors. Thus, instances of this class
42 * are guaranteed to be immutable.
43 *
44 * @author Jared Levy
45 * @since 2.0 (imported from Google Collections Library)
46 */
47@GwtCompatible(serializable = true, emulated = true)
48public class ImmutableListMultimap<K, V>
49    extends ImmutableMultimap<K, V>
50    implements ListMultimap<K, V> {
51
52  /** Returns the empty multimap. */
53  // Casting is safe because the multimap will never hold any elements.
54  @SuppressWarnings("unchecked")
55  public static <K, V> ImmutableListMultimap<K, V> of() {
56    return (ImmutableListMultimap<K, V>) EmptyImmutableListMultimap.INSTANCE;
57  }
58
59  /**
60   * Returns an immutable multimap containing a single entry.
61   */
62  public static <K, V> ImmutableListMultimap<K, V> of(K k1, V v1) {
63    ImmutableListMultimap.Builder<K, V> builder
64        = ImmutableListMultimap.builder();
65    builder.put(k1, v1);
66    return builder.build();
67  }
68
69  /**
70   * Returns an immutable multimap containing the given entries, in order.
71   */
72  public static <K, V> ImmutableListMultimap<K, V> of(K k1, V v1, K k2, V v2) {
73    ImmutableListMultimap.Builder<K, V> builder
74        = ImmutableListMultimap.builder();
75    builder.put(k1, v1);
76    builder.put(k2, v2);
77    return builder.build();
78  }
79
80  /**
81   * Returns an immutable multimap containing the given entries, in order.
82   */
83  public static <K, V> ImmutableListMultimap<K, V> of(
84      K k1, V v1, K k2, V v2, K k3, V v3) {
85    ImmutableListMultimap.Builder<K, V> builder
86        = ImmutableListMultimap.builder();
87    builder.put(k1, v1);
88    builder.put(k2, v2);
89    builder.put(k3, v3);
90    return builder.build();
91  }
92
93  /**
94   * Returns an immutable multimap containing the given entries, in order.
95   */
96  public static <K, V> ImmutableListMultimap<K, V> of(
97      K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
98    ImmutableListMultimap.Builder<K, V> builder
99        = ImmutableListMultimap.builder();
100    builder.put(k1, v1);
101    builder.put(k2, v2);
102    builder.put(k3, v3);
103    builder.put(k4, v4);
104    return builder.build();
105  }
106
107  /**
108   * Returns an immutable multimap containing the given entries, in order.
109   */
110  public static <K, V> ImmutableListMultimap<K, V> of(
111      K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
112    ImmutableListMultimap.Builder<K, V> builder
113        = ImmutableListMultimap.builder();
114    builder.put(k1, v1);
115    builder.put(k2, v2);
116    builder.put(k3, v3);
117    builder.put(k4, v4);
118    builder.put(k5, v5);
119    return builder.build();
120  }
121
122  // looking for of() with > 5 entries? Use the builder instead.
123
124  /**
125   * Returns a new builder. The generated builder is equivalent to the builder
126   * created by the {@link Builder} constructor.
127   */
128  public static <K, V> Builder<K, V> builder() {
129    return new Builder<K, V>();
130  }
131
132  /**
133   * A builder for creating immutable {@code ListMultimap} instances, especially
134   * {@code public static final} multimaps ("constant multimaps"). Example:
135   * <pre>   {@code
136   *
137   *   static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
138   *       new ImmutableListMultimap.Builder<String, Integer>()
139   *           .put("one", 1)
140   *           .putAll("several", 1, 2, 3)
141   *           .putAll("many", 1, 2, 3, 4, 5)
142   *           .build();}</pre>
143   *
144   * Builder instances can be reused; it is safe to call {@link #build} multiple
145   * times to build multiple multimaps in series. Each multimap contains the
146   * key-value mappings in the previously created multimaps.
147   *
148   * @since 2.0 (imported from Google Collections Library)
149   */
150  public static final class Builder<K, V>
151      extends ImmutableMultimap.Builder<K, V> {
152    /**
153     * Creates a new builder. The returned builder is equivalent to the builder
154     * generated by {@link ImmutableListMultimap#builder}.
155     */
156    public Builder() {}
157
158    @Override public Builder<K, V> put(K key, V value) {
159      super.put(key, value);
160      return this;
161    }
162
163    /**
164     * {@inheritDoc}
165     *
166     * @since 11.0
167     */
168    @Override public Builder<K, V> put(
169        Entry<? extends K, ? extends V> entry) {
170      super.put(entry);
171      return this;
172    }
173
174    @Override public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
175      super.putAll(key, values);
176      return this;
177    }
178
179    @Override public Builder<K, V> putAll(K key, V... values) {
180      super.putAll(key, values);
181      return this;
182    }
183
184    @Override public Builder<K, V> putAll(
185        Multimap<? extends K, ? extends V> multimap) {
186      super.putAll(multimap);
187      return this;
188    }
189
190    /**
191     * {@inheritDoc}
192     *
193     * @since 8.0
194     */
195    @Beta @Override
196    public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
197      super.orderKeysBy(keyComparator);
198      return this;
199    }
200
201    /**
202     * {@inheritDoc}
203     *
204     * @since 8.0
205     */
206    @Beta @Override
207    public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
208      super.orderValuesBy(valueComparator);
209      return this;
210    }
211
212    /**
213     * Returns a newly-created immutable list multimap.
214     */
215    @Override public ImmutableListMultimap<K, V> build() {
216      return (ImmutableListMultimap<K, V>) super.build();
217    }
218  }
219
220  /**
221   * Returns an immutable multimap containing the same mappings as {@code
222   * multimap}. The generated multimap's key and value orderings correspond to
223   * the iteration ordering of the {@code multimap.asMap()} view.
224   *
225   * <p>Despite the method name, this method attempts to avoid actually copying
226   * the data when it is safe to do so. The exact circumstances under which a
227   * copy will or will not be performed are undocumented and subject to change.
228   *
229   * @throws NullPointerException if any key or value in {@code multimap} is
230   *         null
231   */
232  public static <K, V> ImmutableListMultimap<K, V> copyOf(
233      Multimap<? extends K, ? extends V> multimap) {
234    if (multimap.isEmpty()) {
235      return of();
236    }
237
238    // TODO(user): copy ImmutableSetMultimap by using asList() on the sets
239    if (multimap instanceof ImmutableListMultimap) {
240      @SuppressWarnings("unchecked") // safe since multimap is not writable
241      ImmutableListMultimap<K, V> kvMultimap
242          = (ImmutableListMultimap<K, V>) multimap;
243      if (!kvMultimap.isPartialView()) {
244        return kvMultimap;
245      }
246    }
247
248    ImmutableMap.Builder<K, ImmutableList<V>> builder = ImmutableMap.builder();
249    int size = 0;
250
251    for (Entry<? extends K, ? extends Collection<? extends V>> entry
252        : multimap.asMap().entrySet()) {
253      ImmutableList<V> list = ImmutableList.copyOf(entry.getValue());
254      if (!list.isEmpty()) {
255        builder.put(entry.getKey(), list);
256        size += list.size();
257      }
258    }
259
260    return new ImmutableListMultimap<K, V>(builder.build(), size);
261  }
262
263  ImmutableListMultimap(ImmutableMap<K, ImmutableList<V>> map, int size) {
264    super(map, size);
265  }
266
267  // views
268
269  /**
270   * Returns an immutable list of the values for the given key.  If no mappings
271   * in the multimap have the provided key, an empty immutable list is
272   * returned. The values are in the same order as the parameters used to build
273   * this multimap.
274   */
275  @Override public ImmutableList<V> get(@Nullable K key) {
276    // This cast is safe as its type is known in constructor.
277    ImmutableList<V> list = (ImmutableList<V>) map.get(key);
278    return (list == null) ? ImmutableList.<V>of() : list;
279  }
280
281  private transient ImmutableListMultimap<V, K> inverse;
282
283  /**
284   * {@inheritDoc}
285   *
286   * <p>Because an inverse of a list multimap can contain multiple pairs with the same key and
287   * value, this method returns an {@code ImmutableListMultimap} rather than the
288   * {@code ImmutableMultimap} specified in the {@code ImmutableMultimap} class.
289   *
290   * @since 11
291   */
292  @Beta
293  public ImmutableListMultimap<V, K> inverse() {
294    ImmutableListMultimap<V, K> result = inverse;
295    return (result == null) ? (inverse = invert()) : result;
296  }
297
298  private ImmutableListMultimap<V, K> invert() {
299    Builder<V, K> builder = builder();
300    for (Entry<K, V> entry : entries()) {
301      builder.put(entry.getValue(), entry.getKey());
302    }
303    ImmutableListMultimap<V, K> invertedMultimap = builder.build();
304    invertedMultimap.inverse = this;
305    return invertedMultimap;
306  }
307
308  /**
309   * Guaranteed to throw an exception and leave the multimap unmodified.
310   *
311   * @throws UnsupportedOperationException always
312   */
313  @Override public ImmutableList<V> removeAll(Object key) {
314    throw new UnsupportedOperationException();
315  }
316
317  /**
318   * Guaranteed to throw an exception and leave the multimap unmodified.
319   *
320   * @throws UnsupportedOperationException always
321   */
322  @Override public ImmutableList<V> replaceValues(
323      K key, Iterable<? extends V> values) {
324    throw new UnsupportedOperationException();
325  }
326}
327