001    /*
002     * Copyright (C) 2007 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.checkArgument;
020    
021    import com.google.common.annotations.GwtCompatible;
022    import com.google.common.annotations.GwtIncompatible;
023    import com.google.common.annotations.VisibleForTesting;
024    import com.google.common.base.Objects;
025    import com.google.common.primitives.Ints;
026    
027    import java.io.IOException;
028    import java.io.ObjectInputStream;
029    import java.io.ObjectOutputStream;
030    import java.util.Arrays;
031    import java.util.Collection;
032    import java.util.ConcurrentModificationException;
033    import java.util.Iterator;
034    import java.util.LinkedHashMap;
035    import java.util.LinkedHashSet;
036    import java.util.Map;
037    import java.util.NoSuchElementException;
038    import java.util.Set;
039    
040    import javax.annotation.Nullable;
041    
042    /**
043     * Implementation of {@code Multimap} that does not allow duplicate key-value
044     * entries and that returns collections whose iterators follow the ordering in
045     * which the data was added to the multimap.
046     *
047     * <p>The collections returned by {@code keySet}, {@code keys}, and {@code
048     * asMap} iterate through the keys in the order they were first added to the
049     * multimap. Similarly, {@code get}, {@code removeAll}, and {@code
050     * replaceValues} return collections that iterate through the values in the
051     * order they were added. The collections generated by {@code entries} and
052     * {@code values} iterate across the key-value mappings in the order they were
053     * added to the multimap.
054     *
055     * <p>The iteration ordering of the collections generated by {@code keySet},
056     * {@code keys}, and {@code asMap} has a few subtleties. As long as the set of
057     * keys remains unchanged, adding or removing mappings does not affect the key
058     * iteration order. However, if you remove all values associated with a key and
059     * then add the key back to the multimap, that key will come last in the key
060     * iteration order.
061     *
062     * <p>The multimap does not store duplicate key-value pairs. Adding a new
063     * key-value pair equal to an existing key-value pair has no effect.
064     *
065     * <p>Keys and values may be null. All optional multimap methods are supported,
066     * and all returned views are modifiable.
067     *
068     * <p>This class is not threadsafe when any concurrent operations update the
069     * multimap. Concurrent read operations will work correctly. To allow concurrent
070     * update operations, wrap your multimap with a call to {@link
071     * Multimaps#synchronizedSetMultimap}.
072     *
073     * <p>See the Guava User Guide article on <a href=
074     * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
075     * {@code Multimap}</a>.
076     *
077     * @author Jared Levy
078     * @author Louis Wasserman
079     * @since 2.0 (imported from Google Collections Library)
080     */
081    @GwtCompatible(serializable = true, emulated = true)
082    public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
083    
084      /**
085       * Creates a new, empty {@code LinkedHashMultimap} with the default initial
086       * capacities.
087       */
088      public static <K, V> LinkedHashMultimap<K, V> create() {
089        return new LinkedHashMultimap<K, V>(DEFAULT_KEY_CAPACITY, DEFAULT_VALUE_SET_CAPACITY);
090      }
091    
092      /**
093       * Constructs an empty {@code LinkedHashMultimap} with enough capacity to hold
094       * the specified numbers of keys and values without rehashing.
095       *
096       * @param expectedKeys the expected number of distinct keys
097       * @param expectedValuesPerKey the expected average number of values per key
098       * @throws IllegalArgumentException if {@code expectedKeys} or {@code
099       *      expectedValuesPerKey} is negative
100       */
101      public static <K, V> LinkedHashMultimap<K, V> create(
102          int expectedKeys, int expectedValuesPerKey) {
103        return new LinkedHashMultimap<K, V>(
104            Maps.capacity(expectedKeys),
105            Maps.capacity(expectedValuesPerKey));
106      }
107    
108      /**
109       * Constructs a {@code LinkedHashMultimap} with the same mappings as the
110       * specified multimap. If a key-value mapping appears multiple times in the
111       * input multimap, it only appears once in the constructed multimap. The new
112       * multimap has the same {@link Multimap#entries()} iteration order as the
113       * input multimap, except for excluding duplicate mappings.
114       *
115       * @param multimap the multimap whose contents are copied to this multimap
116       */
117      public static <K, V> LinkedHashMultimap<K, V> create(
118          Multimap<? extends K, ? extends V> multimap) {
119        LinkedHashMultimap<K, V> result = create(multimap.keySet().size(), DEFAULT_VALUE_SET_CAPACITY);
120        result.putAll(multimap);
121        return result;
122      }
123    
124      private interface ValueSetLink<K, V> {
125        ValueSetLink<K, V> getPredecessorInValueSet();
126        ValueSetLink<K, V> getSuccessorInValueSet();
127    
128        void setPredecessorInValueSet(ValueSetLink<K, V> entry);
129        void setSuccessorInValueSet(ValueSetLink<K, V> entry);
130      }
131    
132      private static <K, V> void succeedsInValueSet(ValueSetLink<K, V> pred, ValueSetLink<K, V> succ) {
133        pred.setSuccessorInValueSet(succ);
134        succ.setPredecessorInValueSet(pred);
135      }
136    
137      private static <K, V> void succeedsInMultimap(
138          ValueEntry<K, V> pred, ValueEntry<K, V> succ) {
139        pred.setSuccessorInMultimap(succ);
140        succ.setPredecessorInMultimap(pred);
141      }
142    
143      private static <K, V> void deleteFromValueSet(ValueSetLink<K, V> entry) {
144        succeedsInValueSet(entry.getPredecessorInValueSet(), entry.getSuccessorInValueSet());
145      }
146    
147      private static <K, V> void deleteFromMultimap(ValueEntry<K, V> entry) {
148        succeedsInMultimap(entry.getPredecessorInMultimap(), entry.getSuccessorInMultimap());
149      }
150    
151      /**
152       * LinkedHashMultimap entries are in no less than three coexisting linked lists:
153       * a row in the hash table for a Set<V> associated with a key, the linked list
154       * of insertion-ordered entries in that Set<V>, and the linked list of entries
155       * in the LinkedHashMultimap as a whole.
156       */
157      private static final class ValueEntry<K, V> extends AbstractMapEntry<K, V>
158          implements ValueSetLink<K, V> {
159        final K key;
160        final V value;
161        final int valueHash;
162    
163        @Nullable ValueEntry<K, V> nextInValueSetHashRow;
164    
165        ValueSetLink<K, V> predecessorInValueSet;
166        ValueSetLink<K, V> successorInValueSet;
167    
168        ValueEntry<K, V> predecessorInMultimap;
169        ValueEntry<K, V> successorInMultimap;
170    
171        ValueEntry(@Nullable K key, @Nullable V value, int valueHash,
172            @Nullable ValueEntry<K, V> nextInValueSetHashRow) {
173          this.key = key;
174          this.value = value;
175          this.valueHash = valueHash;
176          this.nextInValueSetHashRow = nextInValueSetHashRow;
177        }
178    
179        
180        @Override
181        public K getKey() {
182          return key;
183        }
184    
185        
186        @Override
187        public V getValue() {
188          return value;
189        }
190    
191        
192        public ValueSetLink<K, V> getPredecessorInValueSet() {
193          return predecessorInValueSet;
194        }
195    
196        
197        public ValueSetLink<K, V> getSuccessorInValueSet() {
198          return successorInValueSet;
199        }
200    
201        
202        public void setPredecessorInValueSet(ValueSetLink<K, V> entry) {
203          predecessorInValueSet = entry;
204        }
205    
206        
207        public void setSuccessorInValueSet(ValueSetLink<K, V> entry) {
208          successorInValueSet = entry;
209        }
210    
211        public ValueEntry<K, V> getPredecessorInMultimap() {
212          return predecessorInMultimap;
213        }
214    
215        public ValueEntry<K, V> getSuccessorInMultimap() {
216          return successorInMultimap;
217        }
218    
219        public void setSuccessorInMultimap(ValueEntry<K, V> multimapSuccessor) {
220          this.successorInMultimap = multimapSuccessor;
221        }
222    
223        public void setPredecessorInMultimap(ValueEntry<K, V> multimapPredecessor) {
224          this.predecessorInMultimap = multimapPredecessor;
225        }
226      }
227    
228      private static final int DEFAULT_KEY_CAPACITY = 16;
229      private static final int DEFAULT_VALUE_SET_CAPACITY = 2;
230    
231      private static final int MAX_VALUE_SET_TABLE_SIZE = Ints.MAX_POWER_OF_TWO;
232    
233      @VisibleForTesting transient int valueSetCapacity = DEFAULT_VALUE_SET_CAPACITY;
234      private transient ValueEntry<K, V> multimapHeaderEntry;
235    
236      private LinkedHashMultimap(int keyCapacity, int valueSetCapacity) {
237        super(new LinkedHashMap<K, Collection<V>>(keyCapacity));
238    
239        checkArgument(valueSetCapacity >= 0,
240            "expectedValuesPerKey must be >= 0 but was %s", valueSetCapacity);
241    
242        this.valueSetCapacity = valueSetCapacity;
243        this.multimapHeaderEntry = new ValueEntry<K, V>(null, null, 0, null);
244        succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
245      }
246    
247      /**
248       * {@inheritDoc}
249       *
250       * <p>Creates an empty {@code LinkedHashSet} for a collection of values for
251       * one key.
252       *
253       * @return a new {@code LinkedHashSet} containing a collection of values for
254       *     one key
255       */
256      
257      @Override
258      Set<V> createCollection() {
259        return new LinkedHashSet<V>(valueSetCapacity);
260      }
261    
262      /**
263       * {@inheritDoc}
264       *
265       * <p>Creates a decorated insertion-ordered set that also keeps track of the
266       * order in which key-value pairs are added to the multimap.
267       *
268       * @param key key to associate with values in the collection
269       * @return a new decorated set containing a collection of values for one key
270       */
271      
272      @Override
273      Collection<V> createCollection(K key) {
274        return new ValueSet(key, valueSetCapacity);
275      }
276    
277      /**
278       * {@inheritDoc}
279       *
280       * <p>If {@code values} is not empty and the multimap already contains a
281       * mapping for {@code key}, the {@code keySet()} ordering is unchanged.
282       * However, the provided values always come last in the {@link #entries()} and
283       * {@link #values()} iteration orderings.
284       */
285      
286      @Override
287      public Set<V> replaceValues(K key, Iterable<? extends V> values) {
288        return super.replaceValues(key, values);
289      }
290    
291      /**
292       * Returns a set of all key-value pairs. Changes to the returned set will
293       * update the underlying multimap, and vice versa. The entries set does not
294       * support the {@code add} or {@code addAll} operations.
295       *
296       * <p>The iterator generated by the returned set traverses the entries in the
297       * order they were added to the multimap.
298       *
299       * <p>Each entry is an immutable snapshot of a key-value mapping in the
300       * multimap, taken at the time the entry is returned by a method call to the
301       * collection or its iterator.
302       */
303      
304      @Override
305      public Set<Map.Entry<K, V>> entries() {
306        return super.entries();
307      }
308    
309      /**
310       * Returns a collection of all values in the multimap. Changes to the returned
311       * collection will update the underlying multimap, and vice versa.
312       *
313       * <p>The iterator generated by the returned collection traverses the values
314       * in the order they were added to the multimap.
315       */
316      
317      @Override
318      public Collection<V> values() {
319        return super.values();
320      }
321    
322      @VisibleForTesting
323      final class ValueSet extends Sets.ImprovedAbstractSet<V> implements ValueSetLink<K, V> {
324        /*
325         * We currently use a fixed load factor of 1.0, a bit higher than normal to reduce memory
326         * consumption.
327         */
328    
329        private final K key;
330        private ValueEntry<K, V>[] hashTable;
331        private int size = 0;
332        private int modCount = 0;
333    
334        // We use the set object itself as the end of the linked list, avoiding an unnecessary
335        // entry object per key.
336        private ValueSetLink<K, V> firstEntry;
337        private ValueSetLink<K, V> lastEntry;
338    
339        ValueSet(K key, int expectedValues) {
340          this.key = key;
341          this.firstEntry = this;
342          this.lastEntry = this;
343          // Round expected values up to a power of 2 to get the table size.
344          int tableSize = Integer.highestOneBit(Math.max(expectedValues, 2) - 1) << 1;
345          if (tableSize < 0) {
346            tableSize = MAX_VALUE_SET_TABLE_SIZE;
347          }
348    
349          @SuppressWarnings("unchecked")
350          ValueEntry<K, V>[] hashTable = new ValueEntry[tableSize];
351          this.hashTable = hashTable;
352        }
353    
354        
355        public ValueSetLink<K, V> getPredecessorInValueSet() {
356          return lastEntry;
357        }
358    
359        
360        public ValueSetLink<K, V> getSuccessorInValueSet() {
361          return firstEntry;
362        }
363    
364        
365        public void setPredecessorInValueSet(ValueSetLink<K, V> entry) {
366          lastEntry = entry;
367        }
368    
369        
370        public void setSuccessorInValueSet(ValueSetLink<K, V> entry) {
371          firstEntry = entry;
372        }
373    
374        
375        @Override
376        public Iterator<V> iterator() {
377          return new Iterator<V>() {
378            ValueSetLink<K, V> nextEntry = firstEntry;
379            ValueEntry<K, V> toRemove;
380            int expectedModCount = modCount;
381    
382            private void checkForComodification() {
383              if (modCount != expectedModCount) {
384                throw new ConcurrentModificationException();
385              }
386            }
387    
388            
389            public boolean hasNext() {
390              checkForComodification();
391              return nextEntry != ValueSet.this;
392            }
393    
394            
395            public V next() {
396              if (!hasNext()) {
397                throw new NoSuchElementException();
398              }
399              ValueEntry<K, V> entry = (ValueEntry<K, V>) nextEntry;
400              V result = entry.getValue();
401              toRemove = entry;
402              nextEntry = entry.getSuccessorInValueSet();
403              return result;
404            }
405    
406            
407            public void remove() {
408              checkForComodification();
409              Iterators.checkRemove(toRemove != null);
410              Object o = toRemove.getValue();
411              int hash = (o == null) ? 0 : o.hashCode();
412              int row = Hashing.smear(hash) & (hashTable.length - 1);
413              ValueEntry<K, V> prev = null;
414              for (ValueEntry<K, V> entry = hashTable[row]; entry != null;
415                   prev = entry, entry = entry.nextInValueSetHashRow) {
416                if (entry == toRemove) {
417                  if (prev == null) {
418                    // first entry in row
419                    hashTable[row] = entry.nextInValueSetHashRow;
420                  } else {
421                    prev.nextInValueSetHashRow = entry.nextInValueSetHashRow;
422                  }
423                  deleteFromValueSet(toRemove);
424                  deleteFromMultimap(toRemove);
425                  size--;
426                  expectedModCount = ++modCount;
427                  break;
428                }
429              }
430              toRemove = null;
431            }
432          };
433        }
434    
435        
436        @Override
437        public int size() {
438          return size;
439        }
440    
441        
442        @Override
443        public boolean contains(@Nullable Object o) {
444          int hash = (o == null) ? 0 : o.hashCode();
445          int row = Hashing.smear(hash) & (hashTable.length - 1);
446    
447          for (ValueEntry<K, V> entry = hashTable[row]; entry != null;
448              entry = entry.nextInValueSetHashRow) {
449            if (hash == entry.valueHash && Objects.equal(o, entry.getValue())) {
450              return true;
451            }
452          }
453          return false;
454        }
455    
456        /**
457         * The threshold above which the hash table should be rebuilt.
458         */
459        @VisibleForTesting int threshold() {
460          return hashTable.length; // load factor of 1.0
461        }
462    
463        
464        @Override
465        public boolean add(@Nullable V value) {
466          int hash = (value == null) ? 0 : value.hashCode();
467          int row = Hashing.smear(hash) & (hashTable.length - 1);
468    
469          ValueEntry<K, V> rowHead = hashTable[row];
470          for (ValueEntry<K, V> entry = rowHead; entry != null;
471              entry = entry.nextInValueSetHashRow) {
472            if (hash == entry.valueHash && Objects.equal(value, entry.getValue())) {
473              return false;
474            }
475          }
476    
477          ValueEntry<K, V> newEntry = new ValueEntry<K, V>(key, value, hash, rowHead);
478          succeedsInValueSet(lastEntry, newEntry);
479          succeedsInValueSet(newEntry, this);
480          succeedsInMultimap(multimapHeaderEntry.getPredecessorInMultimap(), newEntry);
481          succeedsInMultimap(newEntry, multimapHeaderEntry);
482          hashTable[row] = newEntry;
483          size++;
484          modCount++;
485          rehashIfNecessary();
486          return true;
487        }
488    
489        private void rehashIfNecessary() {
490          if (size > threshold() && hashTable.length < MAX_VALUE_SET_TABLE_SIZE) {
491            @SuppressWarnings("unchecked")
492            ValueEntry<K, V>[] hashTable = new ValueEntry[this.hashTable.length * 2];
493            this.hashTable = hashTable;
494            int mask = hashTable.length - 1;
495            for (ValueSetLink<K, V> entry = firstEntry;
496                  entry != this; entry = entry.getSuccessorInValueSet()) {
497              ValueEntry<K, V> valueEntry = (ValueEntry<K, V>) entry;
498              int row = Hashing.smear(valueEntry.valueHash) & mask;
499              valueEntry.nextInValueSetHashRow = hashTable[row];
500              hashTable[row] = valueEntry;
501            }
502          }
503        }
504    
505        
506        @Override
507        public boolean remove(@Nullable Object o) {
508          int hash = (o == null) ? 0 : o.hashCode();
509          int row = Hashing.smear(hash) & (hashTable.length - 1);
510    
511          ValueEntry<K, V> prev = null;
512          for (ValueEntry<K, V> entry = hashTable[row]; entry != null;
513               prev = entry, entry = entry.nextInValueSetHashRow) {
514            if (hash == entry.valueHash && Objects.equal(o, entry.getValue())) {
515              if (prev == null) {
516                // first entry in the row
517                hashTable[row] = entry.nextInValueSetHashRow;
518              } else {
519                prev.nextInValueSetHashRow = entry.nextInValueSetHashRow;
520              }
521              deleteFromValueSet(entry);
522              deleteFromMultimap(entry);
523              size--;
524              modCount++;
525              return true;
526            }
527          }
528          return false;
529        }
530    
531        
532        @Override
533        public void clear() {
534          Arrays.fill(hashTable, null);
535          size = 0;
536          for (ValueSetLink<K, V> entry = firstEntry;
537               entry != this; entry = entry.getSuccessorInValueSet()) {
538            ValueEntry<K, V> valueEntry = (ValueEntry<K, V>) entry;
539            deleteFromMultimap(valueEntry);
540          }
541          succeedsInValueSet(this, this);
542          modCount++;
543        }
544      }
545    
546      
547      @Override
548      Iterator<Map.Entry<K, V>> createEntryIterator() {
549        return new Iterator<Map.Entry<K, V>>() {
550          ValueEntry<K, V> nextEntry = multimapHeaderEntry.successorInMultimap;
551          ValueEntry<K, V> toRemove;
552    
553          
554          public boolean hasNext() {
555            return nextEntry != multimapHeaderEntry;
556          }
557    
558          
559          public Map.Entry<K, V> next() {
560            if (!hasNext()) {
561              throw new NoSuchElementException();
562            }
563            ValueEntry<K, V> result = nextEntry;
564            toRemove = result;
565            nextEntry = nextEntry.successorInMultimap;
566            return result;
567          }
568    
569          
570          public void remove() {
571            Iterators.checkRemove(toRemove != null);
572            LinkedHashMultimap.this.remove(toRemove.getKey(), toRemove.getValue());
573            toRemove = null;
574          }
575        };
576      }
577    
578      
579      @Override
580      public void clear() {
581        super.clear();
582        succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
583      }
584    
585      /**
586       * @serialData the expected values per key, the number of distinct keys,
587       * the number of entries, and the entries in order
588       */
589      @GwtIncompatible("java.io.ObjectOutputStream")
590      private void writeObject(ObjectOutputStream stream) throws IOException {
591        stream.defaultWriteObject();
592        stream.writeInt(valueSetCapacity);
593        stream.writeInt(keySet().size());
594        for (K key : keySet()) {
595          stream.writeObject(key);
596        }
597        stream.writeInt(size());
598        for (Map.Entry<K, V> entry : entries()) {
599          stream.writeObject(entry.getKey());
600          stream.writeObject(entry.getValue());
601        }
602      }
603    
604      @GwtIncompatible("java.io.ObjectInputStream")
605      private void readObject(ObjectInputStream stream)
606          throws IOException, ClassNotFoundException {
607        stream.defaultReadObject();
608        multimapHeaderEntry = new ValueEntry<K, V>(null, null, 0, null);
609        succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
610        valueSetCapacity = stream.readInt();
611        int distinctKeys = stream.readInt();
612        Map<K, Collection<V>> map =
613            new LinkedHashMap<K, Collection<V>>(Maps.capacity(distinctKeys));
614        for (int i = 0; i < distinctKeys; i++) {
615          @SuppressWarnings("unchecked")
616          K key = (K) stream.readObject();
617          map.put(key, createCollection(key));
618        }
619        int entries = stream.readInt();
620        for (int i = 0; i < entries; i++) {
621          @SuppressWarnings("unchecked")
622          K key = (K) stream.readObject();
623          @SuppressWarnings("unchecked")
624          V value = (V) stream.readObject();
625          map.get(key).add(value);
626        }
627        setMap(map);
628      }
629    
630      @GwtIncompatible("java serialization not supported")
631      private static final long serialVersionUID = 1;
632    }