• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 
17 package com.google.common.collect;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import com.google.common.annotations.Beta;
22 import com.google.common.annotations.GwtCompatible;
23 
24 import java.util.Collection;
25 import java.util.Comparator;
26 import java.util.Iterator;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import java.util.Set;
32 import java.util.SortedSet;
33 
34 import javax.annotation.Nullable;
35 
36 /**
37  * Factory and utilities pertaining to the {@code MapConstraint} interface.
38  *
39  * @see Constraints
40  * @author Mike Bostock
41  * @since 3.0
42  */
43 @Beta
44 @GwtCompatible
45 public final class MapConstraints {
MapConstraints()46   private MapConstraints() {}
47 
48   /**
49    * Returns a constraint that verifies that neither the key nor the value is
50    * null. If either is null, a {@link NullPointerException} is thrown.
51    */
notNull()52   public static MapConstraint<Object, Object> notNull() {
53     return NotNullMapConstraint.INSTANCE;
54   }
55 
56   // enum singleton pattern
57   private enum NotNullMapConstraint implements MapConstraint<Object, Object> {
58     INSTANCE;
59 
60     @Override
checkKeyValue(Object key, Object value)61     public void checkKeyValue(Object key, Object value) {
62       checkNotNull(key);
63       checkNotNull(value);
64     }
65 
toString()66     @Override public String toString() {
67       return "Not null";
68     }
69   }
70 
71   /**
72    * Returns a constrained view of the specified map, using the specified
73    * constraint. Any operations that add new mappings will call the provided
74    * constraint. However, this method does not verify that existing mappings
75    * satisfy the constraint.
76    *
77    * <p>The returned map is not serializable.
78    *
79    * @param map the map to constrain
80    * @param constraint the constraint that validates added entries
81    * @return a constrained view of the specified map
82    */
constrainedMap( Map<K, V> map, MapConstraint<? super K, ? super V> constraint)83   public static <K, V> Map<K, V> constrainedMap(
84       Map<K, V> map, MapConstraint<? super K, ? super V> constraint) {
85     return new ConstrainedMap<K, V>(map, constraint);
86   }
87 
88   /**
89    * Returns a constrained view of the specified multimap, using the specified
90    * constraint. Any operations that add new mappings will call the provided
91    * constraint. However, this method does not verify that existing mappings
92    * satisfy the constraint.
93    *
94    * <p>Note that the generated multimap's {@link Multimap#removeAll} and
95    * {@link Multimap#replaceValues} methods return collections that are not
96    * constrained.
97    *
98    * <p>The returned multimap is not serializable.
99    *
100    * @param multimap the multimap to constrain
101    * @param constraint the constraint that validates added entries
102    * @return a constrained view of the multimap
103    */
constrainedMultimap( Multimap<K, V> multimap, MapConstraint<? super K, ? super V> constraint)104   public static <K, V> Multimap<K, V> constrainedMultimap(
105       Multimap<K, V> multimap, MapConstraint<? super K, ? super V> constraint) {
106     return new ConstrainedMultimap<K, V>(multimap, constraint);
107   }
108 
109   /**
110    * Returns a constrained view of the specified list multimap, using the
111    * specified constraint. Any operations that add new mappings will call the
112    * provided constraint. However, this method does not verify that existing
113    * mappings satisfy the constraint.
114    *
115    * <p>Note that the generated multimap's {@link Multimap#removeAll} and
116    * {@link Multimap#replaceValues} methods return collections that are not
117    * constrained.
118    *
119    * <p>The returned multimap is not serializable.
120    *
121    * @param multimap the multimap to constrain
122    * @param constraint the constraint that validates added entries
123    * @return a constrained view of the specified multimap
124    */
constrainedListMultimap( ListMultimap<K, V> multimap, MapConstraint<? super K, ? super V> constraint)125   public static <K, V> ListMultimap<K, V> constrainedListMultimap(
126       ListMultimap<K, V> multimap,
127       MapConstraint<? super K, ? super V> constraint) {
128     return new ConstrainedListMultimap<K, V>(multimap, constraint);
129   }
130 
131   /**
132    * Returns a constrained view of the specified set multimap, using the
133    * specified constraint. Any operations that add new mappings will call the
134    * provided constraint. However, this method does not verify that existing
135    * mappings satisfy the constraint.
136    *
137    * <p>Note that the generated multimap's {@link Multimap#removeAll} and
138    * {@link Multimap#replaceValues} methods return collections that are not
139    * constrained.
140    * <p>The returned multimap is not serializable.
141    *
142    * @param multimap the multimap to constrain
143    * @param constraint the constraint that validates added entries
144    * @return a constrained view of the specified multimap
145    */
constrainedSetMultimap( SetMultimap<K, V> multimap, MapConstraint<? super K, ? super V> constraint)146   public static <K, V> SetMultimap<K, V> constrainedSetMultimap(
147       SetMultimap<K, V> multimap,
148       MapConstraint<? super K, ? super V> constraint) {
149     return new ConstrainedSetMultimap<K, V>(multimap, constraint);
150   }
151 
152   /**
153    * Returns a constrained view of the specified sorted-set multimap, using the
154    * specified constraint. Any operations that add new mappings will call the
155    * provided constraint. However, this method does not verify that existing
156    * mappings satisfy the constraint.
157    *
158    * <p>Note that the generated multimap's {@link Multimap#removeAll} and
159    * {@link Multimap#replaceValues} methods return collections that are not
160    * constrained.
161    * <p>The returned multimap is not serializable.
162    *
163    * @param multimap the multimap to constrain
164    * @param constraint the constraint that validates added entries
165    * @return a constrained view of the specified multimap
166    */
constrainedSortedSetMultimap( SortedSetMultimap<K, V> multimap, MapConstraint<? super K, ? super V> constraint)167   public static <K, V> SortedSetMultimap<K, V> constrainedSortedSetMultimap(
168       SortedSetMultimap<K, V> multimap,
169       MapConstraint<? super K, ? super V> constraint) {
170     return new ConstrainedSortedSetMultimap<K, V>(multimap, constraint);
171   }
172 
173   /**
174    * Returns a constrained view of the specified entry, using the specified
175    * constraint. The {@link Entry#setValue} operation will be verified with the
176    * constraint.
177    *
178    * @param entry the entry to constrain
179    * @param constraint the constraint for the entry
180    * @return a constrained view of the specified entry
181    */
constrainedEntry( final Entry<K, V> entry, final MapConstraint<? super K, ? super V> constraint)182   private static <K, V> Entry<K, V> constrainedEntry(
183       final Entry<K, V> entry,
184       final MapConstraint<? super K, ? super V> constraint) {
185     checkNotNull(entry);
186     checkNotNull(constraint);
187     return new ForwardingMapEntry<K, V>() {
188       @Override protected Entry<K, V> delegate() {
189         return entry;
190       }
191       @Override public V setValue(V value) {
192         constraint.checkKeyValue(getKey(), value);
193         return entry.setValue(value);
194       }
195     };
196   }
197 
198   /**
199    * Returns a constrained view of the specified {@code asMap} entry, using the
200    * specified constraint. The {@link Entry#setValue} operation will be verified
201    * with the constraint, and the collection returned by {@link Entry#getValue}
202    * will be similarly constrained.
203    *
204    * @param entry the {@code asMap} entry to constrain
205    * @param constraint the constraint for the entry
206    * @return a constrained view of the specified entry
207    */
208   private static <K, V> Entry<K, Collection<V>> constrainedAsMapEntry(
209       final Entry<K, Collection<V>> entry,
210       final MapConstraint<? super K, ? super V> constraint) {
211     checkNotNull(entry);
212     checkNotNull(constraint);
213     return new ForwardingMapEntry<K, Collection<V>>() {
214       @Override protected Entry<K, Collection<V>> delegate() {
215         return entry;
216       }
217       @Override public Collection<V> getValue() {
218         return Constraints.constrainedTypePreservingCollection(
219             entry.getValue(), new Constraint<V>() {
220           @Override
221           public V checkElement(V value) {
222             constraint.checkKeyValue(getKey(), value);
223             return value;
224           }
225         });
226       }
227     };
228   }
229 
230   /**
231    * Returns a constrained view of the specified set of {@code asMap} entries,
232    * using the specified constraint. The {@link Entry#setValue} operation will
233    * be verified with the constraint, and the collection returned by {@link
234    * Entry#getValue} will be similarly constrained. The {@code add} and {@code
235    * addAll} operations simply forward to the underlying set, which throws an
236    * {@link UnsupportedOperationException} per the multimap specification.
237    *
238    * @param entries the entries to constrain
239    * @param constraint the constraint for the entries
240    * @return a constrained view of the entries
241    */
242   private static <K, V> Set<Entry<K, Collection<V>>> constrainedAsMapEntries(
243       Set<Entry<K, Collection<V>>> entries,
244       MapConstraint<? super K, ? super V> constraint) {
245     return new ConstrainedAsMapEntries<K, V>(entries, constraint);
246   }
247 
248   /**
249    * Returns a constrained view of the specified collection (or set) of entries,
250    * using the specified constraint. The {@link Entry#setValue} operation will
251    * be verified with the constraint, along with add operations on the returned
252    * collection. The {@code add} and {@code addAll} operations simply forward to
253    * the underlying collection, which throws an {@link
254    * UnsupportedOperationException} per the map and multimap specification.
255    *
256    * @param entries the entries to constrain
257    * @param constraint the constraint for the entries
258    * @return a constrained view of the specified entries
259    */
260   private static <K, V> Collection<Entry<K, V>> constrainedEntries(
261       Collection<Entry<K, V>> entries,
262       MapConstraint<? super K, ? super V> constraint) {
263     if (entries instanceof Set) {
264       return constrainedEntrySet((Set<Entry<K, V>>) entries, constraint);
265     }
266     return new ConstrainedEntries<K, V>(entries, constraint);
267   }
268 
269   /**
270    * Returns a constrained view of the specified set of entries, using the
271    * specified constraint. The {@link Entry#setValue} operation will be verified
272    * with the constraint, along with add operations on the returned set. The
273    * {@code add} and {@code addAll} operations simply forward to the underlying
274    * set, which throws an {@link UnsupportedOperationException} per the map and
275    * multimap specification.
276    *
277    * <p>The returned multimap is not serializable.
278    *
279    * @param entries the entries to constrain
280    * @param constraint the constraint for the entries
281    * @return a constrained view of the specified entries
282    */
283   private static <K, V> Set<Entry<K, V>> constrainedEntrySet(
284       Set<Entry<K, V>> entries,
285       MapConstraint<? super K, ? super V> constraint) {
286     return new ConstrainedEntrySet<K, V>(entries, constraint);
287   }
288 
289   /** @see MapConstraints#constrainedMap */
290   static class ConstrainedMap<K, V> extends ForwardingMap<K, V> {
291     private final Map<K, V> delegate;
292     final MapConstraint<? super K, ? super V> constraint;
293     private transient Set<Entry<K, V>> entrySet;
294 
295     ConstrainedMap(
296         Map<K, V> delegate, MapConstraint<? super K, ? super V> constraint) {
297       this.delegate = checkNotNull(delegate);
298       this.constraint = checkNotNull(constraint);
299     }
300     @Override protected Map<K, V> delegate() {
301       return delegate;
302     }
303     @Override public Set<Entry<K, V>> entrySet() {
304       Set<Entry<K, V>> result = entrySet;
305       if (result == null) {
306         entrySet = result =
307             constrainedEntrySet(delegate.entrySet(), constraint);
308       }
309       return result;
310     }
311     @Override public V put(K key, V value) {
312       constraint.checkKeyValue(key, value);
313       return delegate.put(key, value);
314     }
315     @Override public void putAll(Map<? extends K, ? extends V> map) {
316       delegate.putAll(checkMap(map, constraint));
317     }
318   }
319 
320   /**
321    * Returns a constrained view of the specified bimap, using the specified
322    * constraint. Any operations that modify the bimap will have the associated
323    * keys and values verified with the constraint.
324    *
325    * <p>The returned bimap is not serializable.
326    *
327    * @param map the bimap to constrain
328    * @param constraint the constraint that validates added entries
329    * @return a constrained view of the specified bimap
330    */
331   public static <K, V> BiMap<K, V> constrainedBiMap(
332       BiMap<K, V> map, MapConstraint<? super K, ? super V> constraint) {
333     return new ConstrainedBiMap<K, V>(map, null, constraint);
334   }
335 
336   /** @see MapConstraints#constrainedBiMap */
337   private static class ConstrainedBiMap<K, V> extends ConstrainedMap<K, V>
338       implements BiMap<K, V> {
339     /*
340      * We could switch to racy single-check lazy init and remove volatile, but
341      * there's a downside. That's because this field is also written in the
342      * constructor. Without volatile, the constructor's write of the existing
343      * inverse BiMap could occur after inverse()'s read of the field's initial
344      * null value, leading inverse() to overwrite the existing inverse with a
345      * doubly indirect version. This wouldn't be catastrophic, but it's
346      * something to keep in mind if we make the change.
347      *
348      * Note that UnmodifiableBiMap *does* use racy single-check lazy init.
349      * TODO(cpovirk): pick one and standardize
350      */
351     volatile BiMap<V, K> inverse;
352 
353     ConstrainedBiMap(BiMap<K, V> delegate, @Nullable BiMap<V, K> inverse,
354         MapConstraint<? super K, ? super V> constraint) {
355       super(delegate, constraint);
356       this.inverse = inverse;
357     }
358 
359     @Override protected BiMap<K, V> delegate() {
360       return (BiMap<K, V>) super.delegate();
361     }
362 
363     @Override
364     public V forcePut(K key, V value) {
365       constraint.checkKeyValue(key, value);
366       return delegate().forcePut(key, value);
367     }
368 
369     @Override
370     public BiMap<V, K> inverse() {
371       if (inverse == null) {
372         inverse = new ConstrainedBiMap<V, K>(delegate().inverse(), this,
373             new InverseConstraint<V, K>(constraint));
374       }
375       return inverse;
376     }
377 
378     @Override public Set<V> values() {
379       return delegate().values();
380     }
381   }
382 
383   /** @see MapConstraints#constrainedBiMap */
384   private static class InverseConstraint<K, V> implements MapConstraint<K, V> {
385     final MapConstraint<? super V, ? super K> constraint;
386 
387     public InverseConstraint(MapConstraint<? super V, ? super K> constraint) {
388       this.constraint = checkNotNull(constraint);
389     }
390     @Override
391     public void checkKeyValue(K key, V value) {
392       constraint.checkKeyValue(value, key);
393     }
394   }
395 
396   /** @see MapConstraints#constrainedMultimap */
397   private static class ConstrainedMultimap<K, V>
398       extends ForwardingMultimap<K, V> {
399     final MapConstraint<? super K, ? super V> constraint;
400     final Multimap<K, V> delegate;
401     transient Collection<Entry<K, V>> entries;
402     transient Map<K, Collection<V>> asMap;
403 
404     public ConstrainedMultimap(Multimap<K, V> delegate,
405         MapConstraint<? super K, ? super V> constraint) {
406       this.delegate = checkNotNull(delegate);
407       this.constraint = checkNotNull(constraint);
408     }
409 
410     @Override protected Multimap<K, V> delegate() {
411       return delegate;
412     }
413 
414     @Override public Map<K, Collection<V>> asMap() {
415       Map<K, Collection<V>> result = asMap;
416       if (result == null) {
417         final Map<K, Collection<V>> asMapDelegate = delegate.asMap();
418 
419         asMap = result = new ForwardingMap<K, Collection<V>>() {
420           Set<Entry<K, Collection<V>>> entrySet;
421           Collection<Collection<V>> values;
422 
423           @Override protected Map<K, Collection<V>> delegate() {
424             return asMapDelegate;
425           }
426 
427           @Override public Set<Entry<K, Collection<V>>> entrySet() {
428             Set<Entry<K, Collection<V>>> result = entrySet;
429             if (result == null) {
430               entrySet = result = constrainedAsMapEntries(
431                   asMapDelegate.entrySet(), constraint);
432             }
433             return result;
434           }
435 
436           @SuppressWarnings("unchecked")
437           @Override public Collection<V> get(Object key) {
438             try {
439               Collection<V> collection = ConstrainedMultimap.this.get((K) key);
440               return collection.isEmpty() ? null : collection;
441             } catch (ClassCastException e) {
442               return null; // key wasn't a K
443             }
444           }
445 
446           @Override public Collection<Collection<V>> values() {
447             Collection<Collection<V>> result = values;
448             if (result == null) {
449               values = result = new ConstrainedAsMapValues<K, V>(
450                   delegate().values(), entrySet());
451             }
452             return result;
453           }
454 
455           @Override public boolean containsValue(Object o) {
456             return values().contains(o);
457           }
458         };
459       }
460       return result;
461     }
462 
463     @Override public Collection<Entry<K, V>> entries() {
464       Collection<Entry<K, V>> result = entries;
465       if (result == null) {
466         entries = result = constrainedEntries(delegate.entries(), constraint);
467       }
468       return result;
469     }
470 
471     @Override public Collection<V> get(final K key) {
472       return Constraints.constrainedTypePreservingCollection(
473           delegate.get(key), new Constraint<V>() {
474         @Override
475         public V checkElement(V value) {
476           constraint.checkKeyValue(key, value);
477           return value;
478         }
479       });
480     }
481 
482     @Override public boolean put(K key, V value) {
483       constraint.checkKeyValue(key, value);
484       return delegate.put(key, value);
485     }
486 
487     @Override public boolean putAll(K key, Iterable<? extends V> values) {
488       return delegate.putAll(key, checkValues(key, values, constraint));
489     }
490 
491     @Override public boolean putAll(
492         Multimap<? extends K, ? extends V> multimap) {
493       boolean changed = false;
494       for (Entry<? extends K, ? extends V> entry : multimap.entries()) {
495         changed |= put(entry.getKey(), entry.getValue());
496       }
497       return changed;
498     }
499 
500     @Override public Collection<V> replaceValues(
501         K key, Iterable<? extends V> values) {
502       return delegate.replaceValues(key, checkValues(key, values, constraint));
503     }
504   }
505 
506   /** @see ConstrainedMultimap#asMap */
507   private static class ConstrainedAsMapValues<K, V>
508       extends ForwardingCollection<Collection<V>> {
509     final Collection<Collection<V>> delegate;
510     final Set<Entry<K, Collection<V>>> entrySet;
511 
512     /**
513      * @param entrySet map entries, linking each key with its corresponding
514      *     values, that already enforce the constraint
515      */
516     ConstrainedAsMapValues(Collection<Collection<V>> delegate,
517         Set<Entry<K, Collection<V>>> entrySet) {
518       this.delegate = delegate;
519       this.entrySet = entrySet;
520     }
521     @Override protected Collection<Collection<V>> delegate() {
522       return delegate;
523     }
524 
525     @Override public Iterator<Collection<V>> iterator() {
526       final Iterator<Entry<K, Collection<V>>> iterator = entrySet.iterator();
527       return new Iterator<Collection<V>>() {
528         @Override
529         public boolean hasNext() {
530           return iterator.hasNext();
531         }
532         @Override
533         public Collection<V> next() {
534           return iterator.next().getValue();
535         }
536         @Override
537         public void remove() {
538           iterator.remove();
539         }
540       };
541     }
542 
543     @Override public Object[] toArray() {
544       return standardToArray();
545     }
546     @Override public <T> T[] toArray(T[] array) {
547       return standardToArray(array);
548     }
549     @Override public boolean contains(Object o) {
550       return standardContains(o);
551     }
552     @Override public boolean containsAll(Collection<?> c) {
553       return standardContainsAll(c);
554     }
555     @Override public boolean remove(Object o) {
556       return standardRemove(o);
557     }
558     @Override public boolean removeAll(Collection<?> c) {
559       return standardRemoveAll(c);
560     }
561     @Override public boolean retainAll(Collection<?> c) {
562       return standardRetainAll(c);
563     }
564   }
565 
566   /** @see MapConstraints#constrainedEntries */
567   private static class ConstrainedEntries<K, V>
568       extends ForwardingCollection<Entry<K, V>> {
569     final MapConstraint<? super K, ? super V> constraint;
570     final Collection<Entry<K, V>> entries;
571 
572     ConstrainedEntries(Collection<Entry<K, V>> entries,
573         MapConstraint<? super K, ? super V> constraint) {
574       this.entries = entries;
575       this.constraint = constraint;
576     }
577     @Override protected Collection<Entry<K, V>> delegate() {
578       return entries;
579     }
580 
581     @Override public Iterator<Entry<K, V>> iterator() {
582       final Iterator<Entry<K, V>> iterator = entries.iterator();
583       return new ForwardingIterator<Entry<K, V>>() {
584         @Override public Entry<K, V> next() {
585           return constrainedEntry(iterator.next(), constraint);
586         }
587         @Override protected Iterator<Entry<K, V>> delegate() {
588           return iterator;
589         }
590       };
591     }
592 
593     // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
594 
595     @Override public Object[] toArray() {
596       return standardToArray();
597     }
598     @Override public <T> T[] toArray(T[] array) {
599       return standardToArray(array);
600     }
601     @Override public boolean contains(Object o) {
602       return Maps.containsEntryImpl(delegate(), o);
603     }
604     @Override public boolean containsAll(Collection<?> c) {
605       return standardContainsAll(c);
606     }
607     @Override public boolean remove(Object o) {
608       return Maps.removeEntryImpl(delegate(), o);
609     }
610     @Override public boolean removeAll(Collection<?> c) {
611       return standardRemoveAll(c);
612     }
613     @Override public boolean retainAll(Collection<?> c) {
614       return standardRetainAll(c);
615     }
616   }
617 
618   /** @see MapConstraints#constrainedEntrySet */
619   static class ConstrainedEntrySet<K, V>
620       extends ConstrainedEntries<K, V> implements Set<Entry<K, V>> {
621     ConstrainedEntrySet(Set<Entry<K, V>> entries,
622         MapConstraint<? super K, ? super V> constraint) {
623       super(entries, constraint);
624     }
625 
626     // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
627 
628     @Override public boolean equals(@Nullable Object object) {
629       return Sets.equalsImpl(this, object);
630     }
631 
632     @Override public int hashCode() {
633       return Sets.hashCodeImpl(this);
634     }
635   }
636 
637   /** @see MapConstraints#constrainedAsMapEntries */
638   static class ConstrainedAsMapEntries<K, V>
639       extends ForwardingSet<Entry<K, Collection<V>>> {
640     private final MapConstraint<? super K, ? super V> constraint;
641     private final Set<Entry<K, Collection<V>>> entries;
642 
643     ConstrainedAsMapEntries(Set<Entry<K, Collection<V>>> entries,
644         MapConstraint<? super K, ? super V> constraint) {
645       this.entries = entries;
646       this.constraint = constraint;
647     }
648 
649     @Override protected Set<Entry<K, Collection<V>>> delegate() {
650       return entries;
651     }
652 
653     @Override public Iterator<Entry<K, Collection<V>>> iterator() {
654       final Iterator<Entry<K, Collection<V>>> iterator = entries.iterator();
655       return new ForwardingIterator<Entry<K, Collection<V>>>() {
656         @Override public Entry<K, Collection<V>> next() {
657           return constrainedAsMapEntry(iterator.next(), constraint);
658         }
659         @Override protected Iterator<Entry<K, Collection<V>>> delegate() {
660           return iterator;
661         }
662       };
663     }
664 
665     // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
666 
667     @Override public Object[] toArray() {
668       return standardToArray();
669     }
670 
671     @Override public <T> T[] toArray(T[] array) {
672       return standardToArray(array);
673     }
674 
675     @Override public boolean contains(Object o) {
676       return Maps.containsEntryImpl(delegate(), o);
677     }
678 
679     @Override public boolean containsAll(Collection<?> c) {
680       return standardContainsAll(c);
681     }
682 
683     @Override public boolean equals(@Nullable Object object) {
684       return standardEquals(object);
685     }
686 
687     @Override public int hashCode() {
688       return standardHashCode();
689     }
690 
691     @Override public boolean remove(Object o) {
692       return Maps.removeEntryImpl(delegate(), o);
693     }
694 
695     @Override public boolean removeAll(Collection<?> c) {
696       return standardRemoveAll(c);
697     }
698 
699     @Override public boolean retainAll(Collection<?> c) {
700       return standardRetainAll(c);
701     }
702   }
703 
704   private static class ConstrainedListMultimap<K, V>
705       extends ConstrainedMultimap<K, V> implements ListMultimap<K, V> {
706     ConstrainedListMultimap(ListMultimap<K, V> delegate,
707         MapConstraint<? super K, ? super V> constraint) {
708       super(delegate, constraint);
709     }
710     @Override public List<V> get(K key) {
711       return (List<V>) super.get(key);
712     }
713     @Override public List<V> removeAll(Object key) {
714       return (List<V>) super.removeAll(key);
715     }
716     @Override public List<V> replaceValues(
717         K key, Iterable<? extends V> values) {
718       return (List<V>) super.replaceValues(key, values);
719     }
720   }
721 
722   private static class ConstrainedSetMultimap<K, V>
723       extends ConstrainedMultimap<K, V> implements SetMultimap<K, V> {
724     ConstrainedSetMultimap(SetMultimap<K, V> delegate,
725         MapConstraint<? super K, ? super V> constraint) {
726       super(delegate, constraint);
727     }
728     @Override public Set<V> get(K key) {
729       return (Set<V>) super.get(key);
730     }
731     @Override public Set<Map.Entry<K, V>> entries() {
732       return (Set<Map.Entry<K, V>>) super.entries();
733     }
734     @Override public Set<V> removeAll(Object key) {
735       return (Set<V>) super.removeAll(key);
736     }
737     @Override public Set<V> replaceValues(
738         K key, Iterable<? extends V> values) {
739       return (Set<V>) super.replaceValues(key, values);
740     }
741   }
742 
743   private static class ConstrainedSortedSetMultimap<K, V>
744       extends ConstrainedSetMultimap<K, V> implements SortedSetMultimap<K, V> {
745     ConstrainedSortedSetMultimap(SortedSetMultimap<K, V> delegate,
746         MapConstraint<? super K, ? super V> constraint) {
747       super(delegate, constraint);
748     }
749     @Override public SortedSet<V> get(K key) {
750       return (SortedSet<V>) super.get(key);
751     }
752     @Override public SortedSet<V> removeAll(Object key) {
753       return (SortedSet<V>) super.removeAll(key);
754     }
755     @Override public SortedSet<V> replaceValues(
756         K key, Iterable<? extends V> values) {
757       return (SortedSet<V>) super.replaceValues(key, values);
758     }
759     @Override
760     public Comparator<? super V> valueComparator() {
761       return ((SortedSetMultimap<K, V>) delegate()).valueComparator();
762     }
763   }
764 
765   private static <K, V> Collection<V> checkValues(K key,
766       Iterable<? extends V> values,
767       MapConstraint<? super K, ? super V> constraint) {
768     Collection<V> copy = Lists.newArrayList(values);
769     for (V value : copy) {
770       constraint.checkKeyValue(key, value);
771     }
772     return copy;
773   }
774 
775   private static <K, V> Map<K, V> checkMap(Map<? extends K, ? extends V> map,
776       MapConstraint<? super K, ? super V> constraint) {
777     Map<K, V> copy = new LinkedHashMap<K, V>(map);
778     for (Entry<K, V> entry : copy.entrySet()) {
779       constraint.checkKeyValue(entry.getKey(), entry.getValue());
780     }
781     return copy;
782   }
783 }
784