Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2007 Google Inc.
      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 com.google.common.annotations.GwtCompatible;
     20 import static com.google.common.base.Preconditions.checkNotNull;
     21 
     22 import java.util.Collection;
     23 import java.util.Iterator;
     24 import java.util.Map;
     25 import java.util.Set;
     26 
     27 import javax.annotation.Nullable;
     28 
     29 /**
     30  * Factory and utilities pertaining to the {@code MapConstraint} interface.
     31  *
     32  * @author Mike Bostock
     33  */
     34 @GwtCompatible
     35 class ConstrainedMap<K, V> extends ForwardingMap<K, V> {
     36   final Map<K, V> delegate;
     37   final MapConstraint<? super K, ? super V> constraint;
     38   private volatile Set<Entry<K, V>> entrySet;
     39 
     40   ConstrainedMap(
     41       Map<K, V> delegate, MapConstraint<? super K, ? super V> constraint) {
     42     this.delegate = checkNotNull(delegate);
     43     this.constraint = checkNotNull(constraint);
     44   }
     45 
     46   @Override protected Map<K, V> delegate() {
     47     return delegate;
     48   }
     49   @Override public Set<Entry<K, V>> entrySet() {
     50     if (entrySet == null) {
     51       entrySet = constrainedEntrySet(delegate.entrySet(), constraint);
     52     }
     53     return entrySet;
     54   }
     55   @Override public V put(K key, V value) {
     56     constraint.checkKeyValue(key, value);
     57     return delegate.put(key, value);
     58   }
     59   @Override public void putAll(Map<? extends K, ? extends V> map) {
     60     for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
     61       put(entry.getKey(), entry.getValue());
     62     }
     63   }
     64 
     65   private static <K, V> Entry<K, V> constrainedEntry(
     66       final Entry<K, V> entry,
     67       final MapConstraint<? super K, ? super V> constraint) {
     68     checkNotNull(entry);
     69     checkNotNull(constraint);
     70     return new ForwardingMapEntry<K, V>() {
     71       @Override protected Entry<K, V> delegate() {
     72         return entry;
     73       }
     74       @Override public V setValue(V value) {
     75         constraint.checkKeyValue(getKey(), value);
     76         return entry.setValue(value);
     77       }
     78     };
     79   }
     80 
     81   private static <K, V> Set<Entry<K, V>> constrainedEntrySet(
     82       Set<Entry<K, V>> entries,
     83       MapConstraint<? super K, ? super V> constraint) {
     84     return new ConstrainedEntrySet<K, V>(entries, constraint);
     85   }
     86 
     87   private static class ConstrainedEntries<K, V>
     88       extends ForwardingCollection<Entry<K, V>> {
     89     final MapConstraint<? super K, ? super V> constraint;
     90     final Collection<Entry<K, V>> entries;
     91 
     92     ConstrainedEntries(Collection<Entry<K, V>> entries,
     93         MapConstraint<? super K, ? super V> constraint) {
     94       this.entries = entries;
     95       this.constraint = constraint;
     96     }
     97     @Override protected Collection<Entry<K, V>> delegate() {
     98       return entries;
     99     }
    100 
    101     @Override public Iterator<Entry<K, V>> iterator() {
    102       final Iterator<Entry<K, V>> iterator = entries.iterator();
    103       return new ForwardingIterator<Entry<K, V>>() {
    104         @Override public Entry<K, V> next() {
    105           return constrainedEntry(iterator.next(), constraint);
    106         }
    107         @Override protected Iterator<Entry<K, V>> delegate() {
    108           return iterator;
    109         }
    110       };
    111     }
    112 
    113     // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
    114 
    115     @Override public Object[] toArray() {
    116       return ObjectArrays.toArrayImpl(this);
    117     }
    118     @Override public <T> T[] toArray(T[] array) {
    119       return ObjectArrays.toArrayImpl(this, array);
    120     }
    121     @Override public boolean contains(Object o) {
    122       return Maps.containsEntryImpl(delegate(), o);
    123     }
    124     @Override public boolean containsAll(Collection<?> c) {
    125       return Collections2.containsAll(this, c);
    126     }
    127     @Override public boolean remove(Object o) {
    128       return Maps.removeEntryImpl(delegate(), o);
    129     }
    130     @Override public boolean removeAll(Collection<?> c) {
    131       return Iterators.removeAll(iterator(), c);
    132     }
    133     @Override public boolean retainAll(Collection<?> c) {
    134       return Iterators.retainAll(iterator(), c);
    135     }
    136   }
    137 
    138   static class ConstrainedEntrySet<K, V>
    139       extends ConstrainedEntries<K, V> implements Set<Entry<K, V>> {
    140     ConstrainedEntrySet(Set<Entry<K, V>> entries,
    141         MapConstraint<? super K, ? super V> constraint) {
    142       super(entries, constraint);
    143     }
    144 
    145     // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
    146 
    147     @Override public boolean equals(@Nullable Object object) {
    148       return Collections2.setEquals(this, object);
    149     }
    150 
    151     @Override public int hashCode() {
    152       return Sets.hashCodeImpl(this);
    153     }
    154   }
    155 }
    156