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