1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.map;
18
19 import java.io.IOException;
20 import java.io.InvalidObjectException;
21 import java.io.ObjectInputStream;
22 import java.io.ObjectOutputStream;
23 import java.io.Serializable;
24 import java.util.AbstractList;
25 import java.util.AbstractSet;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.IdentityHashMap;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.ListIterator;
34 import java.util.Map;
35 import java.util.NoSuchElementException;
36 import java.util.Set;
37
38 import org.apache.commons.collections4.OrderedMap;
39 import org.apache.commons.collections4.OrderedMapIterator;
40 import org.apache.commons.collections4.ResettableIterator;
41 import org.apache.commons.collections4.iterators.AbstractUntypedIteratorDecorator;
42 import org.apache.commons.collections4.keyvalue.AbstractMapEntry;
43 import org.apache.commons.collections4.list.UnmodifiableList;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 public class ListOrderedMap<K, V>
88 extends AbstractMapDecorator<K, V>
89 implements OrderedMap<K, V>, Serializable {
90
91 static class EntrySetView<K, V> extends AbstractSet<Map.Entry<K, V>> {
92 private final ListOrderedMap<K, V> parent;
93 private final List<K> insertOrder;
94 private Set<Map.Entry<K, V>> entrySet;
95
96 EntrySetView(final ListOrderedMap<K, V> parent, final List<K> insertOrder) {
97 this.parent = parent;
98 this.insertOrder = insertOrder;
99 }
100
101 @Override
102 public void clear() {
103 parent.clear();
104 }
105
106 @Override
107 public boolean contains(final Object obj) {
108 return getEntrySet().contains(obj);
109 }
110 @Override
111 public boolean containsAll(final Collection<?> coll) {
112 return getEntrySet().containsAll(coll);
113 }
114
115 @Override
116 public boolean equals(final Object obj) {
117 if (obj == this) {
118 return true;
119 }
120 return getEntrySet().equals(obj);
121 }
122
123 private Set<Map.Entry<K, V>> getEntrySet() {
124 if (entrySet == null) {
125 entrySet = parent.decorated().entrySet();
126 }
127 return entrySet;
128 }
129
130 @Override
131 public int hashCode() {
132 return getEntrySet().hashCode();
133 }
134
135 @Override
136 public boolean isEmpty() {
137 return parent.isEmpty();
138 }
139
140 @Override
141 public Iterator<Map.Entry<K, V>> iterator() {
142 return new ListOrderedIterator<>(parent, insertOrder);
143 }
144
145 @Override
146 @SuppressWarnings("unchecked")
147 public boolean remove(final Object obj) {
148 if (!(obj instanceof Map.Entry)) {
149 return false;
150 }
151 if (getEntrySet().contains(obj)) {
152 final Object key = ((Map.Entry<K, V>) obj).getKey();
153 parent.remove(key);
154 return true;
155 }
156 return false;
157 }
158
159 @Override
160 public int size() {
161 return parent.size();
162 }
163
164 @Override
165 public String toString() {
166 return getEntrySet().toString();
167 }
168 }
169
170 static class KeySetView<K> extends AbstractSet<K> {
171 private final ListOrderedMap<K, Object> parent;
172
173 @SuppressWarnings("unchecked")
174 KeySetView(final ListOrderedMap<K, ?> parent) {
175 this.parent = (ListOrderedMap<K, Object>) parent;
176 }
177
178 @Override
179 public void clear() {
180 parent.clear();
181 }
182
183 @Override
184 public boolean contains(final Object value) {
185 return parent.containsKey(value);
186 }
187
188 @Override
189 public Iterator<K> iterator() {
190 return new AbstractUntypedIteratorDecorator<Map.Entry<K, Object>, K>(parent.entrySet().iterator()) {
191 @Override
192 public K next() {
193 return getIterator().next().getKey();
194 }
195 };
196 }
197
198 @Override
199 public int size() {
200 return parent.size();
201 }
202 }
203
204 static class ListOrderedIterator<K, V> extends AbstractUntypedIteratorDecorator<K, Map.Entry<K, V>> {
205 private final ListOrderedMap<K, V> parent;
206 private K last;
207
208 ListOrderedIterator(final ListOrderedMap<K, V> parent, final List<K> insertOrder) {
209 super(insertOrder.iterator());
210 this.parent = parent;
211 }
212
213 @Override
214 public Map.Entry<K, V> next() {
215 last = getIterator().next();
216 return new ListOrderedMapEntry<>(parent, last);
217 }
218
219 @Override
220 public void remove() {
221 super.remove();
222 parent.decorated().remove(last);
223 }
224 }
225
226 static class ListOrderedMapEntry<K, V> extends AbstractMapEntry<K, V> {
227 private final ListOrderedMap<K, V> parent;
228
229 ListOrderedMapEntry(final ListOrderedMap<K, V> parent, final K key) {
230 super(key, null);
231 this.parent = parent;
232 }
233
234 @Override
235 public V getValue() {
236 return parent.get(getKey());
237 }
238
239 @Override
240 public V setValue(final V value) {
241 return parent.decorated().put(getKey(), value);
242 }
243 }
244
245 static class ListOrderedMapIterator<K, V> implements OrderedMapIterator<K, V>, ResettableIterator<K> {
246 private final ListOrderedMap<K, V> parent;
247 private ListIterator<K> iterator;
248 private K last;
249 private boolean readable;
250
251 ListOrderedMapIterator(final ListOrderedMap<K, V> parent) {
252 this.parent = parent;
253 this.iterator = parent.insertOrder.listIterator();
254 }
255
256 @Override
257 public K getKey() {
258 if (!readable) {
259 throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
260 }
261 return last;
262 }
263
264 @Override
265 public V getValue() {
266 if (!readable) {
267 throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
268 }
269 return parent.get(last);
270 }
271
272 @Override
273 public boolean hasNext() {
274 return iterator.hasNext();
275 }
276
277 @Override
278 public boolean hasPrevious() {
279 return iterator.hasPrevious();
280 }
281
282 @Override
283 public K next() {
284 last = iterator.next();
285 readable = true;
286 return last;
287 }
288
289 @Override
290 public K previous() {
291 last = iterator.previous();
292 readable = true;
293 return last;
294 }
295
296 @Override
297 public void remove() {
298 if (!readable) {
299 throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
300 }
301 iterator.remove();
302 parent.map.remove(last);
303 readable = false;
304 }
305
306 @Override
307 public void reset() {
308 iterator = parent.insertOrder.listIterator();
309 last = null;
310 readable = false;
311 }
312
313 @Override
314 public V setValue(final V value) {
315 if (!readable) {
316 throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
317 }
318 return parent.map.put(last, value);
319 }
320
321 @Override
322 public String toString() {
323 if (readable) {
324 return "Iterator[" + getKey() + "=" + getValue() + "]";
325 }
326 return "Iterator[]";
327 }
328 }
329
330 static class ValuesView<V> extends AbstractList<V> {
331 private final ListOrderedMap<Object, V> parent;
332
333 @SuppressWarnings("unchecked")
334 ValuesView(final ListOrderedMap<?, V> parent) {
335 this.parent = (ListOrderedMap<Object, V>) parent;
336 }
337
338 @Override
339 public void clear() {
340 parent.clear();
341 }
342
343 @Override
344 public boolean contains(final Object value) {
345 return parent.containsValue(value);
346 }
347
348 @Override
349 public V get(final int index) {
350 return parent.getValue(index);
351 }
352
353 @Override
354 public Iterator<V> iterator() {
355 return new AbstractUntypedIteratorDecorator<Map.Entry<Object, V>, V>(parent.entrySet().iterator()) {
356 @Override
357 public V next() {
358 return getIterator().next().getValue();
359 }
360 };
361 }
362
363 @Override
364 public V remove(final int index) {
365 return parent.remove(index);
366 }
367
368 @Override
369 public V set(final int index, final V value) {
370 return parent.setValue(index, value);
371 }
372
373 @Override
374 public int size() {
375 return parent.size();
376 }
377 }
378
379
380 private static final long serialVersionUID = 2728177751851003750L;
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395 public static <K, V> ListOrderedMap<K, V> listOrderedMap(final Map<K, V> map) {
396 return new ListOrderedMap<>(map);
397 }
398
399
400 private final List<K> insertOrder = new ArrayList<>();
401
402
403
404
405
406
407
408 public ListOrderedMap() {
409 this(new HashMap<>());
410 }
411
412
413
414
415
416
417
418 protected ListOrderedMap(final Map<K, V> map) {
419 super(map);
420 insertOrder.addAll(decorated().keySet());
421 }
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442 public List<K> asList() {
443 return keyList();
444 }
445
446 @Override
447 public void clear() {
448 decorated().clear();
449 insertOrder.clear();
450 }
451
452
453
454
455
456
457
458
459
460 @Override
461 public Set<Map.Entry<K, V>> entrySet() {
462 return new EntrySetView<>(this, insertOrder);
463 }
464
465
466
467
468
469
470
471 @Override
472 public K firstKey() {
473 if (isEmpty()) {
474 throw new NoSuchElementException("Map is empty");
475 }
476 return insertOrder.get(0);
477 }
478
479
480
481
482
483
484
485
486 public K get(final int index) {
487 return insertOrder.get(index);
488 }
489
490
491
492
493
494
495
496
497 public V getValue(final int index) {
498 return get(insertOrder.get(index));
499 }
500
501
502
503
504
505
506
507 public int indexOf(final Object key) {
508 return insertOrder.indexOf(key);
509 }
510
511
512
513
514
515
516
517
518
519
520
521
522 public List<K> keyList() {
523 return UnmodifiableList.unmodifiableList(insertOrder);
524 }
525
526
527
528
529
530
531
532
533
534
535 @Override
536 public Set<K> keySet() {
537 return new KeySetView<>(this);
538 }
539
540
541
542
543
544
545
546 @Override
547 public K lastKey() {
548 if (isEmpty()) {
549 throw new NoSuchElementException("Map is empty");
550 }
551 return insertOrder.get(size() - 1);
552 }
553
554 @Override
555 public OrderedMapIterator<K, V> mapIterator() {
556 return new ListOrderedMapIterator<>(this);
557 }
558
559
560
561
562
563
564
565
566 @Override
567 public K nextKey(final Object key) {
568 final int index = insertOrder.indexOf(key);
569 if (index >= 0 && index < size() - 1) {
570 return insertOrder.get(index + 1);
571 }
572 return null;
573 }
574
575
576
577
578
579
580
581
582 @Override
583 public K previousKey(final Object key) {
584 final int index = insertOrder.indexOf(key);
585 if (index > 0) {
586 return insertOrder.get(index - 1);
587 }
588 return null;
589 }
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612 public V put(int index, final K key, final V value) {
613 if (index < 0 || index > insertOrder.size()) {
614 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + insertOrder.size());
615 }
616
617 final Map<K, V> m = decorated();
618 if (m.containsKey(key)) {
619 final V result = m.remove(key);
620 final int pos = insertOrder.indexOf(key);
621 insertOrder.remove(pos);
622 if (pos < index) {
623 index--;
624 }
625 insertOrder.add(index, key);
626 m.put(key, value);
627 return result;
628 }
629 insertOrder.add(index, key);
630 m.put(key, value);
631 return null;
632 }
633
634 @Override
635 public V put(final K key, final V value) {
636 if (decorated().containsKey(key)) {
637
638 return decorated().put(key, value);
639 }
640
641 final V result = decorated().put(key, value);
642 insertOrder.add(key);
643 return result;
644 }
645
646
647
648
649
650
651
652
653
654 public void putAll(int index, final Map<? extends K, ? extends V> map) {
655 if (index < 0 || index > insertOrder.size()) {
656 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + insertOrder.size());
657 }
658 for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
659 final K key = entry.getKey();
660 final boolean contains = containsKey(key);
661
662
663 put(index, entry.getKey(), entry.getValue());
664 if (!contains) {
665
666 index++;
667 } else {
668
669 index = indexOf(entry.getKey()) + 1;
670 }
671 }
672 }
673
674 @Override
675 public void putAll(final Map<? extends K, ? extends V> map) {
676 for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
677 put(entry.getKey(), entry.getValue());
678 }
679 }
680
681
682
683
684
685
686
687
688
689 @SuppressWarnings("unchecked")
690 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
691 in.defaultReadObject();
692 map = (Map<K, V>) in.readObject();
693 if (insertOrder.size() != map.size() || !new HashSet<>(insertOrder).equals(map.keySet())) {
694 throw new InvalidObjectException("Inconsistent ListOrderedMap deserialized: key order does not match the map keys");
695 }
696 }
697
698
699
700
701
702
703
704
705 public V remove(final int index) {
706 return remove(get(index));
707 }
708
709 @Override
710 public V remove(final Object key) {
711 V result = null;
712 if (decorated().containsKey(key)) {
713 result = decorated().remove(key);
714 insertOrder.remove(key);
715 }
716 return result;
717 }
718
719
720
721
722
723
724
725
726
727
728 public V setValue(final int index, final V value) {
729 final K key = insertOrder.get(index);
730 return put(key, value);
731 }
732
733
734
735
736
737
738 @Override
739 public String toString() {
740 if (isEmpty()) {
741 return "{}";
742 }
743 final StringBuilder buf = new StringBuilder();
744 buf.append('{');
745 boolean first = true;
746 for (final Map.Entry<K, V> entry : entrySet()) {
747 final K key = entry.getKey();
748 final V value = entry.getValue();
749 if (first) {
750 first = false;
751 } else {
752 buf.append(", ");
753 }
754 buf.append(key == this ? "(this Map)" : key);
755 buf.append('=');
756 buf.append(value == this ? "(this Map)" : value);
757 }
758 buf.append('}');
759 return buf.toString();
760 }
761
762
763
764
765
766
767
768
769
770
771
772
773 public List<V> valueList() {
774 return new ValuesView<>(this);
775 }
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790 @Override
791 public Collection<V> values() {
792 return new ValuesView<>(this);
793 }
794
795
796
797
798
799
800
801
802 private void writeObject(final ObjectOutputStream out) throws IOException {
803 out.defaultWriteObject();
804 out.writeObject(map);
805 }
806
807 }