Coverage Summary for Class: AbstractMultimap (com.google.common.collect)
| Class | Method, % | Line, % |
|---|---|---|
| AbstractMultimap | 35% (7/20) | 25% (11/44) |
| AbstractMultimap$Entries | 0% (0/4) | 0% (0/4) |
| AbstractMultimap$EntrySet | 0% (0/3) | 0% (0/3) |
| AbstractMultimap$Values | 0% (0/6) | 0% (0/6) |
| Total | 21.2% (7/33) | 19.3% (11/57) |
1 /* 2 * Copyright (C) 2012 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.GwtCompatible; 22 import com.google.errorprone.annotations.CanIgnoreReturnValue; 23 import com.google.errorprone.annotations.concurrent.LazyInit; 24 import com.google.j2objc.annotations.WeakOuter; 25 import java.util.AbstractCollection; 26 import java.util.Collection; 27 import java.util.Iterator; 28 import java.util.Map; 29 import java.util.Map.Entry; 30 import java.util.Set; 31 import java.util.Spliterator; 32 import java.util.Spliterators; 33 import org.checkerframework.checker.nullness.qual.Nullable; 34 35 /** 36 * A skeleton {@code Multimap} implementation, not necessarily in terms of a {@code Map}. 37 * 38 * @author Louis Wasserman 39 */ 40 @GwtCompatible 41 abstract class AbstractMultimap<K, V> implements Multimap<K, V> { 42 @Override 43 public boolean isEmpty() { 44 return size() == 0; 45 } 46 47 @Override 48 public boolean containsValue(@Nullable Object value) { 49 for (Collection<V> collection : asMap().values()) { 50 if (collection.contains(value)) { 51 return true; 52 } 53 } 54 55 return false; 56 } 57 58 @Override 59 public boolean containsEntry(@Nullable Object key, @Nullable Object value) { 60 Collection<V> collection = asMap().get(key); 61 return collection != null && collection.contains(value); 62 } 63 64 @CanIgnoreReturnValue 65 @Override 66 public boolean remove(@Nullable Object key, @Nullable Object value) { 67 Collection<V> collection = asMap().get(key); 68 return collection != null && collection.remove(value); 69 } 70 71 @CanIgnoreReturnValue 72 @Override 73 public boolean put(@Nullable K key, @Nullable V value) { 74 return get(key).add(value); 75 } 76 77 @CanIgnoreReturnValue 78 @Override 79 public boolean putAll(@Nullable K key, Iterable<? extends V> values) { 80 checkNotNull(values); 81 // make sure we only call values.iterator() once 82 // and we only call get(key) if values is nonempty 83 if (values instanceof Collection) { 84 Collection<? extends V> valueCollection = (Collection<? extends V>) values; 85 return !valueCollection.isEmpty() && get(key).addAll(valueCollection); 86 } else { 87 Iterator<? extends V> valueItr = values.iterator(); 88 return valueItr.hasNext() && Iterators.addAll(get(key), valueItr); 89 } 90 } 91 92 @CanIgnoreReturnValue 93 @Override 94 public boolean putAll(Multimap<? extends K, ? extends V> multimap) { 95 boolean changed = false; 96 for (Entry<? extends K, ? extends V> entry : multimap.entries()) { 97 changed |= put(entry.getKey(), entry.getValue()); 98 } 99 return changed; 100 } 101 102 @CanIgnoreReturnValue 103 @Override 104 public Collection<V> replaceValues(@Nullable K key, Iterable<? extends V> values) { 105 checkNotNull(values); 106 Collection<V> result = removeAll(key); 107 putAll(key, values); 108 return result; 109 } 110 111 @LazyInit private transient @Nullable Collection<Entry<K, V>> entries; 112 113 @Override 114 public Collection<Entry<K, V>> entries() { 115 Collection<Entry<K, V>> result = entries; 116 return (result == null) ? entries = createEntries() : result; 117 } 118 119 abstract Collection<Entry<K, V>> createEntries(); 120 121 @WeakOuter 122 class Entries extends Multimaps.Entries<K, V> { 123 @Override 124 Multimap<K, V> multimap() { 125 return AbstractMultimap.this; 126 } 127 128 @Override 129 public Iterator<Entry<K, V>> iterator() { 130 return entryIterator(); 131 } 132 133 @Override 134 public Spliterator<Entry<K, V>> spliterator() { 135 return entrySpliterator(); 136 } 137 } 138 139 @WeakOuter 140 class EntrySet extends Entries implements Set<Entry<K, V>> { 141 @Override 142 public int hashCode() { 143 return Sets.hashCodeImpl(this); 144 } 145 146 @Override 147 public boolean equals(@Nullable Object obj) { 148 return Sets.equalsImpl(this, obj); 149 } 150 } 151 152 abstract Iterator<Entry<K, V>> entryIterator(); 153 154 Spliterator<Entry<K, V>> entrySpliterator() { 155 return Spliterators.spliterator( 156 entryIterator(), size(), (this instanceof SetMultimap) ? Spliterator.DISTINCT : 0); 157 } 158 159 @LazyInit private transient @Nullable Set<K> keySet; 160 161 @Override 162 public Set<K> keySet() { 163 Set<K> result = keySet; 164 return (result == null) ? keySet = createKeySet() : result; 165 } 166 167 abstract Set<K> createKeySet(); 168 169 @LazyInit private transient @Nullable Multiset<K> keys; 170 171 @Override 172 public Multiset<K> keys() { 173 Multiset<K> result = keys; 174 return (result == null) ? keys = createKeys() : result; 175 } 176 177 abstract Multiset<K> createKeys(); 178 179 @LazyInit private transient @Nullable Collection<V> values; 180 181 @Override 182 public Collection<V> values() { 183 Collection<V> result = values; 184 return (result == null) ? values = createValues() : result; 185 } 186 187 abstract Collection<V> createValues(); 188 189 @WeakOuter 190 class Values extends AbstractCollection<V> { 191 @Override 192 public Iterator<V> iterator() { 193 return valueIterator(); 194 } 195 196 @Override 197 public Spliterator<V> spliterator() { 198 return valueSpliterator(); 199 } 200 201 @Override 202 public int size() { 203 return AbstractMultimap.this.size(); 204 } 205 206 @Override 207 public boolean contains(@Nullable Object o) { 208 return AbstractMultimap.this.containsValue(o); 209 } 210 211 @Override 212 public void clear() { 213 AbstractMultimap.this.clear(); 214 } 215 } 216 217 Iterator<V> valueIterator() { 218 return Maps.valueIterator(entries().iterator()); 219 } 220 221 Spliterator<V> valueSpliterator() { 222 return Spliterators.spliterator(valueIterator(), size(), 0); 223 } 224 225 @LazyInit private transient @Nullable Map<K, Collection<V>> asMap; 226 227 @Override 228 public Map<K, Collection<V>> asMap() { 229 Map<K, Collection<V>> result = asMap; 230 return (result == null) ? asMap = createAsMap() : result; 231 } 232 233 abstract Map<K, Collection<V>> createAsMap(); 234 235 // Comparison and hashing 236 237 @Override 238 public boolean equals(@Nullable Object object) { 239 return Multimaps.equalsImpl(this, object); 240 } 241 242 /** 243 * Returns the hash code for this multimap. 244 * 245 * <p>The hash code of a multimap is defined as the hash code of the map view, as returned by 246 * {@link Multimap#asMap}. 247 * 248 * @see Map#hashCode 249 */ 250 @Override 251 public int hashCode() { 252 return asMap().hashCode(); 253 } 254 255 /** 256 * Returns a string representation of the multimap, generated by calling {@code toString} on the 257 * map returned by {@link Multimap#asMap}. 258 * 259 * @return a string representation of the multimap 260 */ 261 @Override 262 public String toString() { 263 return asMap().toString(); 264 } 265 }