Platform: Already Disposed from Deferred icon
[idea/community.git] / platform / util / src / com / intellij / util / containers / MultiMap.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
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.intellij.util.containers;
18
19 import org.jetbrains.annotations.NotNull;
20
21 import java.io.Serializable;
22 import java.util.*;
23
24 /**
25  * @author Dmitry Avdeev
26  */
27 public class MultiMap<K, V> implements Serializable {
28
29   public static final MultiMap EMPTY = new MultiMap() {
30     @Override
31     protected Map createMap() {
32       return Collections.emptyMap();
33     }
34   };
35   private static final long serialVersionUID = -2632269270151455493L;
36
37   private final Map<K, Collection<V>> myMap;
38
39   private Collection<V> values;
40
41   public MultiMap() {
42     myMap = createMap();
43   }
44
45   protected Map<K, Collection<V>> createMap() {
46     return new HashMap<K, Collection<V>>();
47   }
48
49   protected Collection<V> createCollection() {
50     return new ArrayList<V>();
51   }
52
53   protected Collection<V> createEmptyCollection() {
54     return Collections.emptyList();
55   }
56
57   public void putAllValues(MultiMap<? extends K, ? extends V> from) {
58     for (K k : from.keySet()) {
59       //noinspection unchecked
60       putValues(k, ((MultiMap)from).get(k));
61     }
62   }
63
64   public void putValues(K key, Collection<? extends V> values) {
65     Collection<V> list = myMap.get(key);
66     if (list == null) {
67       list = createCollection();
68       myMap.put(key, list);
69     }
70     list.addAll(values);
71   }
72
73   public void putValue(K key, V value) {
74     Collection<V> list = myMap.get(key);
75     if (list == null) {
76       list = createCollection();
77       myMap.put(key, list);
78     }
79     list.add(value);
80   }
81
82   public Set<Map.Entry<K, Collection<V>>> entrySet() {
83     return myMap.entrySet();
84   }
85
86   public boolean isEmpty() {
87     for(Collection<V> valueList: myMap.values()) {
88       if (!valueList.isEmpty()) {
89         return false;
90       }
91     }
92     return true;    
93   }
94
95   public boolean containsKey(K key) {
96     return myMap.containsKey(key);
97   }
98   
99   public boolean containsScalarValue(V value) {
100     for(Collection<V> valueList: myMap.values()) {
101       if (valueList.contains(value)) {
102         return true;
103       }
104     }
105     return false;
106   }
107
108   @NotNull
109   public Collection<V> get(final K key) {
110     final Collection<V> collection = myMap.get(key);
111     return collection == null ? createEmptyCollection() : collection;
112   }
113
114   @NotNull
115   public Collection<V> getModifiable(final K key) {
116     Collection<V> collection = myMap.get(key);
117     if (collection == null) {
118       myMap.put(key, collection = createCollection());
119     }
120     return collection;
121   }
122
123   public Set<K> keySet() {
124     return myMap.keySet();
125   }
126
127   public int size() {
128     return myMap.size();
129   }
130
131   public void put(final K key, final Collection<V> values) {
132     myMap.put(key, values);
133   }
134
135   public void removeValue(final K key, final V value) {
136     final Collection<V> values = myMap.get(key);
137     if (values != null) {
138       values.remove(value);
139       if (values.isEmpty()) {
140         myMap.remove(key);
141       }
142     }
143   }
144
145   public Collection<? extends V> values() {
146     if (values == null) {
147       values = new AbstractCollection<V>() {
148         @Override
149         public Iterator<V> iterator() {
150           return new Iterator<V>() {
151
152             private Iterator<Collection<V>> mapIterator = myMap.values().iterator();
153
154             private Iterator<V> itr = EmptyIterator.getInstance();
155
156             @Override
157             public boolean hasNext() {
158               do {
159                 if (itr.hasNext()) return true;
160                 if (!mapIterator.hasNext()) return false;
161                 itr = mapIterator.next().iterator();
162               } while (true);
163             }
164
165             @Override
166             public V next() {
167               do {
168                 if (itr.hasNext()) return itr.next();
169                 if (!mapIterator.hasNext()) throw new NoSuchElementException();
170                 itr = mapIterator.next().iterator();
171               } while (true);
172             }
173
174             @Override
175             public void remove() {
176               itr.remove();
177             }
178           };
179         }
180
181         @Override
182         public int size() {
183           int res = 0;
184           for (Collection<V> vs : myMap.values()) {
185             res += vs.size();
186           }
187
188           return res;
189         }
190
191         // Don't remove this method!!!
192         @Override
193         public boolean contains(Object o) {
194           for (Collection<V> vs : myMap.values()) {
195             if (vs.contains(o)) return true;
196           }
197
198           return false;
199         }
200       };
201     }
202
203     return values;
204   }
205
206   public void clear() {
207     myMap.clear();
208   }
209
210   public Collection<V> remove(K key) {
211     return myMap.remove(key);
212   }
213
214   public static <K, V> MultiMap<K, V> emptyInstance() {
215     return EMPTY;
216   }
217
218   @Override
219   public boolean equals(Object o) {
220     if (this == o) return true;
221     if (!(o instanceof MultiMap)) return false;
222     return myMap.equals(((MultiMap)o).myMap);
223   }
224
225   @Override
226   public int hashCode() {
227     return myMap.hashCode();
228   }
229 }