1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.collection;
18
19 import java.util.Collection;
20 import java.util.HashMap;
21 import java.util.Iterator;
22 import java.util.Objects;
23 import java.util.function.Predicate;
24
25 import org.apache.commons.collections4.MultiMap;
26 import org.apache.commons.collections4.Transformer;
27 import org.apache.commons.collections4.map.MultiValueMap;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class IndexedCollection<K, C> extends AbstractCollectionDecorator<C> {
49
50
51
52
53 private static final long serialVersionUID = -5512610452568370038L;
54
55
56
57
58
59
60
61
62
63
64 public static <K, C> IndexedCollection<K, C> nonUniqueIndexedCollection(final Collection<C> coll,
65 final Transformer<C, K> keyTransformer) {
66 return new IndexedCollection<>(coll, keyTransformer,
67 MultiValueMap.<K, C>multiValueMap(new HashMap<>()),
68 false);
69 }
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public static <K, C> IndexedCollection<K, C> uniqueIndexedCollection(final Collection<C> coll,
84 final Transformer<C, K> keyTransformer) {
85 return new IndexedCollection<>(coll, keyTransformer,
86 MultiValueMap.<K, C>multiValueMap(new HashMap<>()),
87 true);
88 }
89
90
91 private final Transformer<C, K> keyTransformer;
92
93
94 private final MultiMap<K, C> index;
95
96
97 private final boolean uniqueIndex;
98
99
100
101
102
103
104
105
106
107 public IndexedCollection(final Collection<C> coll, final Transformer<C, K> keyTransformer,
108 final MultiMap<K, C> map, final boolean uniqueIndex) {
109 super(coll);
110 this.keyTransformer = keyTransformer;
111 this.index = map;
112 this.uniqueIndex = uniqueIndex;
113 reindex();
114 }
115
116
117
118
119
120
121
122 @Override
123 public boolean add(final C object) {
124 final boolean added = super.add(object);
125 if (added) {
126 addToIndex(object);
127 }
128 return added;
129 }
130
131 @Override
132 public boolean addAll(final Collection<? extends C> coll) {
133 boolean changed = false;
134 for (final C c: coll) {
135 changed |= add(c);
136 }
137 return changed;
138 }
139
140
141
142
143
144
145
146
147 private void addToIndex(final C object) {
148 final K key = keyTransformer.transform(object);
149 if (uniqueIndex && index.containsKey(key)) {
150 throw new IllegalArgumentException("Duplicate key in uniquely indexed collection.");
151 }
152 index.put(key, object);
153 }
154
155 @Override
156 public void clear() {
157 super.clear();
158 index.clear();
159 }
160
161
162
163
164
165
166 @SuppressWarnings("unchecked")
167 @Override
168 public boolean contains(final Object object) {
169 return index.containsKey(keyTransformer.transform((C) object));
170 }
171
172
173
174
175
176
177 @Override
178 public boolean containsAll(final Collection<?> coll) {
179 for (final Object o : coll) {
180 if (!contains(o)) {
181 return false;
182 }
183 }
184 return true;
185 }
186
187
188
189
190
191
192
193
194
195
196
197
198 public C get(final K key) {
199 @SuppressWarnings("unchecked")
200 final Collection<C> coll = (Collection<C>) index.get(key);
201 return coll == null ? null : coll.iterator().next();
202 }
203
204
205
206
207 public void reindex() {
208 index.clear();
209 for (final C c : decorated()) {
210 addToIndex(c);
211 }
212 }
213
214 @SuppressWarnings("unchecked")
215 @Override
216 public boolean remove(final Object object) {
217 final boolean removed = super.remove(object);
218 if (removed) {
219 removeFromIndex((C) object);
220 }
221 return removed;
222 }
223
224 @Override
225 public boolean removeAll(final Collection<?> coll) {
226 boolean changed = false;
227 for (final Object o : coll) {
228 changed |= remove(o);
229 }
230 return changed;
231 }
232
233
234
235
236
237
238 private void removeFromIndex(final C object) {
239 index.remove(keyTransformer.transform(object));
240 }
241
242
243
244
245 @Override
246 public boolean removeIf(final Predicate<? super C> filter) {
247 if (Objects.isNull(filter)) {
248 return false;
249 }
250 boolean changed = false;
251 final Iterator<C> it = iterator();
252 while (it.hasNext()) {
253 if (filter.test(it.next())) {
254 it.remove();
255 changed = true;
256 }
257 }
258 if (changed) {
259 reindex();
260 }
261 return changed;
262 }
263
264 @Override
265 public boolean retainAll(final Collection<?> coll) {
266 final boolean changed = super.retainAll(coll);
267 if (changed) {
268 reindex();
269 }
270 return changed;
271 }
272
273
274
275
276
277
278
279 @SuppressWarnings("unchecked")
280 public Collection<C> values(final K key) {
281 return (Collection<C>) index.get(key);
282 }
283
284 }