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.ObjectInputStream;
21 import java.io.ObjectOutputStream;
22 import java.io.Serializable;
23 import java.util.AbstractCollection;
24 import java.util.AbstractSet;
25 import java.util.Collection;
26 import java.util.Iterator;
27 import java.util.Map;
28 import java.util.NoSuchElementException;
29 import java.util.Objects;
30 import java.util.Set;
31
32 import org.apache.commons.collections4.CollectionUtils;
33 import org.apache.commons.collections4.IterableMap;
34 import org.apache.commons.collections4.MapIterator;
35 import org.apache.commons.collections4.ResettableIterator;
36 import org.apache.commons.collections4.iterators.EmptyIterator;
37 import org.apache.commons.collections4.iterators.EmptyMapIterator;
38
39
40
41
42
43
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 public class Flat3Map<K, V> implements IterableMap<K, V>, Serializable, Cloneable {
84
85 abstract static class EntryIterator<K, V> {
86 private final Flat3Map<K, V> parent;
87 private int nextIndex;
88 private FlatMapEntry<K, V> currentEntry;
89
90
91
92
93 EntryIterator(final Flat3Map<K, V> parent) {
94 this.parent = parent;
95 }
96
97 public boolean hasNext() {
98 return nextIndex < parent.size;
99 }
100
101 public Map.Entry<K, V> nextEntry() {
102 if (!hasNext()) {
103 throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
104 }
105 currentEntry = new FlatMapEntry<>(parent, ++nextIndex);
106 return currentEntry;
107 }
108
109 public void remove() {
110 if (currentEntry == null) {
111 throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
112 }
113 parent.remove(currentEntry.getKey());
114 currentEntry.setRemoved(true);
115 nextIndex--;
116 currentEntry = null;
117 }
118
119 }
120
121
122
123
124 static class EntrySet<K, V> extends AbstractSet<Map.Entry<K, V>> {
125 private final Flat3Map<K, V> parent;
126
127 EntrySet(final Flat3Map<K, V> parent) {
128 this.parent = parent;
129 }
130
131 @Override
132 public void clear() {
133 parent.clear();
134 }
135
136 @Override
137 public Iterator<Map.Entry<K, V>> iterator() {
138 if (parent.delegateMap != null) {
139 return parent.delegateMap.entrySet().iterator();
140 }
141 if (parent.isEmpty()) {
142 return EmptyIterator.<Map.Entry<K, V>>emptyIterator();
143 }
144 return new EntrySetIterator<>(parent);
145 }
146
147 @Override
148 public boolean remove(final Object obj) {
149 if (!(obj instanceof Map.Entry)) {
150 return false;
151 }
152 final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
153 final Object key = entry.getKey();
154 final boolean result = parent.containsKey(key);
155 parent.remove(key);
156 return result;
157 }
158
159 @Override
160 public int size() {
161 return parent.size();
162 }
163 }
164
165
166
167 static class EntrySetIterator<K, V> extends EntryIterator<K, V> implements Iterator<Map.Entry<K, V>> {
168 EntrySetIterator(final Flat3Map<K, V> parent) {
169 super(parent);
170 }
171
172 @Override
173 public Map.Entry<K, V> next() {
174 return nextEntry();
175 }
176 }
177 static class FlatMapEntry<K, V> implements Map.Entry<K, V> {
178 private final Flat3Map<K, V> parent;
179 private final int index;
180 private volatile boolean removed;
181
182 FlatMapEntry(final Flat3Map<K, V> parent, final int index) {
183 this.parent = parent;
184 this.index = index;
185 this.removed = false;
186 }
187
188 @Override
189 public boolean equals(final Object obj) {
190 if (removed) {
191 return false;
192 }
193 if (!(obj instanceof Map.Entry)) {
194 return false;
195 }
196 final Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
197 final Object key = getKey();
198 final Object value = getValue();
199 return (key == null ? other.getKey() == null : key.equals(other.getKey())) &&
200 (value == null ? other.getValue() == null : value.equals(other.getValue()));
201 }
202
203 @Override
204 public K getKey() {
205 if (removed) {
206 throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
207 }
208 switch (index) {
209 case 3:
210 return parent.key3;
211 case 2:
212 return parent.key2;
213 case 1:
214 return parent.key1;
215 }
216 throw new IllegalStateException("Invalid map index: " + index);
217 }
218
219 @Override
220 public V getValue() {
221 if (removed) {
222 throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
223 }
224 switch (index) {
225 case 3:
226 return parent.value3;
227 case 2:
228 return parent.value2;
229 case 1:
230 return parent.value1;
231 }
232 throw new IllegalStateException("Invalid map index: " + index);
233 }
234
235 @Override
236 public int hashCode() {
237 if (removed) {
238 return 0;
239 }
240 final Object key = getKey();
241 final Object value = getValue();
242 return (key == null ? 0 : key.hashCode()) ^
243 (value == null ? 0 : value.hashCode());
244 }
245
246
247
248
249
250
251
252
253
254
255 void setRemoved(final boolean flag) {
256 this.removed = flag;
257 }
258
259 @Override
260 public V setValue(final V value) {
261 if (removed) {
262 throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
263 }
264 final V old = getValue();
265 switch (index) {
266 case 3:
267 parent.value3 = value;
268 break;
269 case 2:
270 parent.value2 = value;
271 break;
272 case 1:
273 parent.value1 = value;
274 break;
275 default:
276 throw new IllegalStateException("Invalid map index: " + index);
277 }
278 return old;
279 }
280
281 @Override
282 public String toString() {
283 if (!removed) {
284 return getKey() + "=" + getValue();
285 }
286 return "";
287 }
288
289 }
290
291
292
293 static class FlatMapIterator<K, V> implements MapIterator<K, V>, ResettableIterator<K> {
294 private final Flat3Map<K, V> parent;
295 private int nextIndex;
296 private boolean canRemove;
297
298 FlatMapIterator(final Flat3Map<K, V> parent) {
299 this.parent = parent;
300 }
301
302 @Override
303 public K getKey() {
304 if (!canRemove) {
305 throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
306 }
307 switch (nextIndex) {
308 case 3:
309 return parent.key3;
310 case 2:
311 return parent.key2;
312 case 1:
313 return parent.key1;
314 }
315 throw new IllegalStateException("Invalid map index: " + nextIndex);
316 }
317
318 @Override
319 public V getValue() {
320 if (!canRemove) {
321 throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
322 }
323 switch (nextIndex) {
324 case 3:
325 return parent.value3;
326 case 2:
327 return parent.value2;
328 case 1:
329 return parent.value1;
330 }
331 throw new IllegalStateException("Invalid map index: " + nextIndex);
332 }
333
334 @Override
335 public boolean hasNext() {
336 return nextIndex < parent.size;
337 }
338
339 @Override
340 public K next() {
341 if (!hasNext()) {
342 throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
343 }
344 canRemove = true;
345 nextIndex++;
346 return getKey();
347 }
348
349 @Override
350 public void remove() {
351 if (!canRemove) {
352 throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
353 }
354 parent.remove(getKey());
355 nextIndex--;
356 canRemove = false;
357 }
358
359 @Override
360 public void reset() {
361 nextIndex = 0;
362 canRemove = false;
363 }
364
365 @Override
366 public V setValue(final V value) {
367 if (!canRemove) {
368 throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
369 }
370 final V old = getValue();
371 switch (nextIndex) {
372 case 3:
373 parent.value3 = value;
374 break;
375 case 2:
376 parent.value2 = value;
377 break;
378 case 1:
379 parent.value1 = value;
380 break;
381 default:
382 throw new IllegalStateException("Invalid map index: " + nextIndex);
383 }
384 return old;
385 }
386
387 @Override
388 public String toString() {
389 if (canRemove) {
390 return "Iterator[" + getKey() + "=" + getValue() + "]";
391 }
392 return "Iterator[]";
393 }
394 }
395
396
397
398 static class KeySet<K> extends AbstractSet<K> {
399 private final Flat3Map<K, ?> parent;
400
401 KeySet(final Flat3Map<K, ?> parent) {
402 this.parent = parent;
403 }
404
405 @Override
406 public void clear() {
407 parent.clear();
408 }
409
410 @Override
411 public boolean contains(final Object key) {
412 return parent.containsKey(key);
413 }
414
415 @Override
416 public Iterator<K> iterator() {
417 if (parent.delegateMap != null) {
418 return parent.delegateMap.keySet().iterator();
419 }
420 if (parent.isEmpty()) {
421 return EmptyIterator.<K>emptyIterator();
422 }
423 return new KeySetIterator<>(parent);
424 }
425
426 @Override
427 public boolean remove(final Object key) {
428 final boolean result = parent.containsKey(key);
429 parent.remove(key);
430 return result;
431 }
432
433 @Override
434 public int size() {
435 return parent.size();
436 }
437 }
438
439
440
441 static class KeySetIterator<K> extends EntryIterator<K, Object> implements Iterator<K> {
442
443 @SuppressWarnings("unchecked")
444 KeySetIterator(final Flat3Map<K, ?> parent) {
445 super((Flat3Map<K, Object>) parent);
446 }
447
448 @Override
449 public K next() {
450 return nextEntry().getKey();
451 }
452 }
453
454
455
456 static class Values<V> extends AbstractCollection<V> {
457 private final Flat3Map<?, V> parent;
458
459 Values(final Flat3Map<?, V> parent) {
460 this.parent = parent;
461 }
462
463 @Override
464 public void clear() {
465 parent.clear();
466 }
467
468 @Override
469 public boolean contains(final Object value) {
470 return parent.containsValue(value);
471 }
472
473 @Override
474 public Iterator<V> iterator() {
475 if (parent.delegateMap != null) {
476 return parent.delegateMap.values().iterator();
477 }
478 if (parent.isEmpty()) {
479 return EmptyIterator.<V>emptyIterator();
480 }
481 return new ValuesIterator<>(parent);
482 }
483
484 @Override
485 public int size() {
486 return parent.size();
487 }
488 }
489
490
491
492 static class ValuesIterator<V> extends EntryIterator<Object, V> implements Iterator<V> {
493
494 @SuppressWarnings("unchecked")
495 ValuesIterator(final Flat3Map<?, V> parent) {
496 super((Flat3Map<Object, V>) parent);
497 }
498
499 @Override
500 public V next() {
501 return nextEntry().getValue();
502 }
503 }
504
505 private static final long serialVersionUID = -6701087419741928296L;
506
507 private transient int size;
508
509 private transient int hash1;
510
511
512 private transient int hash2;
513
514
515 private transient int hash3;
516
517
518 private transient K key1;
519
520
521 private transient K key2;
522
523
524 private transient K key3;
525
526
527 private transient V value1;
528
529
530 private transient V value2;
531
532
533 private transient V value3;
534
535
536 private transient AbstractHashedMap<K, V> delegateMap;
537
538
539
540
541 public Flat3Map() {
542 }
543
544
545
546
547
548
549
550 public Flat3Map(final Map<? extends K, ? extends V> map) {
551 putAll(map);
552 }
553
554
555
556
557
558 @Override
559 public void clear() {
560 if (delegateMap != null) {
561 delegateMap.clear();
562 delegateMap = null;
563 } else {
564 size = 0;
565 hash1 = hash2 = hash3 = 0;
566 key1 = key2 = key3 = null;
567 value1 = value2 = value3 = null;
568 }
569 }
570
571
572
573
574
575
576
577 @Override
578 @SuppressWarnings("unchecked")
579 public Flat3Map<K, V> clone() {
580 try {
581 final Flat3Map<K, V> cloned = (Flat3Map<K, V>) super.clone();
582 if (cloned.delegateMap != null) {
583 cloned.delegateMap = cloned.delegateMap.clone();
584 }
585 return cloned;
586 } catch (final CloneNotSupportedException ex) {
587 throw new UnsupportedOperationException(ex);
588 }
589 }
590
591
592
593
594
595
596
597 @Override
598 public boolean containsKey(final Object key) {
599 if (delegateMap != null) {
600 return delegateMap.containsKey(key);
601 }
602 if (key == null) {
603 switch (size) {
604 case 3:
605 if (key3 == null) {
606 return true;
607 }
608 case 2:
609 if (key2 == null) {
610 return true;
611 }
612 case 1:
613 if (key1 == null) {
614 return true;
615 }
616 }
617 } else {
618 if (size > 0) {
619 final int hashCode = key.hashCode();
620 switch (size) {
621 case 3:
622 if (hash3 == hashCode && key.equals(key3)) {
623 return true;
624 }
625 case 2:
626 if (hash2 == hashCode && key.equals(key2)) {
627 return true;
628 }
629 case 1:
630 if (hash1 == hashCode && key.equals(key1)) {
631 return true;
632 }
633 }
634 }
635 }
636 return false;
637 }
638
639
640
641
642
643
644
645 @Override
646 public boolean containsValue(final Object value) {
647 if (delegateMap != null) {
648 return delegateMap.containsValue(value);
649 }
650 if (value == null) {
651 switch (size) {
652 case 3:
653 if (value3 == null) {
654 return true;
655 }
656 case 2:
657 if (value2 == null) {
658 return true;
659 }
660 case 1:
661 if (value1 == null) {
662 return true;
663 }
664 }
665 } else {
666 switch (size) {
667 case 3:
668 if (value.equals(value3)) {
669 return true;
670 }
671 case 2:
672 if (value.equals(value2)) {
673 return true;
674 }
675 case 1:
676 if (value.equals(value1)) {
677 return true;
678 }
679 }
680 }
681 return false;
682 }
683
684
685
686
687 private void convertToMap() {
688 delegateMap = createDelegateMap();
689 switch (size) {
690 case 3:
691 delegateMap.put(key3, value3);
692 case 2:
693 delegateMap.put(key2, value2);
694 case 1:
695 delegateMap.put(key1, value1);
696 case 0:
697 break;
698 default:
699 throw new IllegalStateException("Invalid map index: " + size);
700 }
701
702 size = 0;
703 hash1 = hash2 = hash3 = 0;
704 key1 = key2 = key3 = null;
705 value1 = value2 = value3 = null;
706 }
707
708
709
710
711
712
713
714
715
716
717
718 protected AbstractHashedMap<K, V> createDelegateMap() {
719 return new HashedMap<>();
720 }
721
722
723
724
725
726
727
728
729
730
731
732 @Override
733 public Set<Map.Entry<K, V>> entrySet() {
734 if (delegateMap != null) {
735 return delegateMap.entrySet();
736 }
737 return new EntrySet<>(this);
738 }
739
740
741
742
743
744
745
746 @Override
747 public boolean equals(final Object obj) {
748 if (obj == this) {
749 return true;
750 }
751 if (delegateMap != null) {
752 return delegateMap.equals(obj);
753 }
754 if (!(obj instanceof Map)) {
755 return false;
756 }
757 final Map<?, ?> other = (Map<?, ?>) obj;
758 if (size != other.size()) {
759 return false;
760 }
761 if (size > 0) {
762 Object otherValue = null;
763 switch (size) {
764 case 3:
765 if (!other.containsKey(key3)) {
766 return false;
767 }
768 otherValue = other.get(key3);
769 if (!Objects.equals(value3, otherValue)) {
770 return false;
771 }
772 case 2:
773 if (!other.containsKey(key2)) {
774 return false;
775 }
776 otherValue = other.get(key2);
777 if (!Objects.equals(value2, otherValue)) {
778 return false;
779 }
780 case 1:
781 if (!other.containsKey(key1)) {
782 return false;
783 }
784 otherValue = other.get(key1);
785 if (!Objects.equals(value1, otherValue)) {
786 return false;
787 }
788 }
789 }
790 return true;
791 }
792
793
794
795
796
797
798
799 @Override
800 public V get(final Object key) {
801 if (delegateMap != null) {
802 return delegateMap.get(key);
803 }
804 if (key == null) {
805 switch (size) {
806
807 case 3:
808 if (key3 == null) {
809 return value3;
810 }
811 case 2:
812 if (key2 == null) {
813 return value2;
814 }
815 case 1:
816 if (key1 == null) {
817 return value1;
818 }
819 }
820 } else {
821 if (size > 0) {
822 final int hashCode = key.hashCode();
823 switch (size) {
824
825 case 3:
826 if (hash3 == hashCode && key.equals(key3)) {
827 return value3;
828 }
829 case 2:
830 if (hash2 == hashCode && key.equals(key2)) {
831 return value2;
832 }
833 case 1:
834 if (hash1 == hashCode && key.equals(key1)) {
835 return value1;
836 }
837 }
838 }
839 }
840 return null;
841 }
842
843
844
845
846
847
848 @Override
849 public int hashCode() {
850 if (delegateMap != null) {
851 return delegateMap.hashCode();
852 }
853 int total = 0;
854 switch (size) {
855 case 3:
856 total += hash3 ^ (value3 == null ? 0 : value3.hashCode());
857 case 2:
858 total += hash2 ^ (value2 == null ? 0 : value2.hashCode());
859 case 1:
860 total += hash1 ^ (value1 == null ? 0 : value1.hashCode());
861 case 0:
862 break;
863 default:
864 throw new IllegalStateException("Invalid map index: " + size);
865 }
866 return total;
867 }
868
869
870
871
872
873
874 @Override
875 public boolean isEmpty() {
876 return size() == 0;
877 }
878
879
880
881
882
883
884
885
886 @Override
887 public Set<K> keySet() {
888 if (delegateMap != null) {
889 return delegateMap.keySet();
890 }
891 return new KeySet<>(this);
892 }
893
894
895
896
897
898
899
900
901
902
903
904
905 @Override
906 public MapIterator<K, V> mapIterator() {
907 if (delegateMap != null) {
908 return delegateMap.mapIterator();
909 }
910 if (size == 0) {
911 return EmptyMapIterator.<K, V>emptyMapIterator();
912 }
913 return new FlatMapIterator<>(this);
914 }
915
916
917
918
919
920
921
922
923 @Override
924 public V put(final K key, final V value) {
925 if (delegateMap != null) {
926 return delegateMap.put(key, value);
927 }
928
929 if (key == null) {
930 switch (size) {
931 case 3:
932 if (key3 == null) {
933 final V old = value3;
934 value3 = value;
935 return old;
936 }
937 case 2:
938 if (key2 == null) {
939 final V old = value2;
940 value2 = value;
941 return old;
942 }
943 case 1:
944 if (key1 == null) {
945 final V old = value1;
946 value1 = value;
947 return old;
948 }
949 }
950 } else {
951 if (size > 0) {
952 final int hashCode = key.hashCode();
953 switch (size) {
954 case 3:
955 if (hash3 == hashCode && key.equals(key3)) {
956 final V old = value3;
957 value3 = value;
958 return old;
959 }
960 case 2:
961 if (hash2 == hashCode && key.equals(key2)) {
962 final V old = value2;
963 value2 = value;
964 return old;
965 }
966 case 1:
967 if (hash1 == hashCode && key.equals(key1)) {
968 final V old = value1;
969 value1 = value;
970 return old;
971 }
972 }
973 }
974 }
975
976
977 switch (size) {
978 default:
979 convertToMap();
980 delegateMap.put(key, value);
981 return null;
982 case 2:
983 hash3 = key == null ? 0 : key.hashCode();
984 key3 = key;
985 value3 = value;
986 break;
987 case 1:
988 hash2 = key == null ? 0 : key.hashCode();
989 key2 = key;
990 value2 = value;
991 break;
992 case 0:
993 hash1 = key == null ? 0 : key.hashCode();
994 key1 = key;
995 value1 = value;
996 break;
997 }
998 size++;
999 return null;
1000 }
1001
1002
1003
1004
1005
1006
1007
1008 @Override
1009 public void putAll(final Map<? extends K, ? extends V> map) {
1010 final int size = map.size();
1011 if (size == 0) {
1012 return;
1013 }
1014 if (delegateMap != null) {
1015 delegateMap.putAll(map);
1016 return;
1017 }
1018 if (size < 4) {
1019 for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
1020 put(entry.getKey(), entry.getValue());
1021 }
1022 } else {
1023 convertToMap();
1024 delegateMap.putAll(map);
1025 }
1026 }
1027
1028
1029
1030
1031
1032
1033
1034
1035 @SuppressWarnings("unchecked")
1036 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
1037 in.defaultReadObject();
1038 final int count = in.readInt();
1039 if (count > 3) {
1040 delegateMap = createDelegateMap();
1041 }
1042 for (int i = count; i > 0; i--) {
1043 put((K) in.readObject(), (V) in.readObject());
1044 }
1045 }
1046
1047
1048
1049
1050
1051
1052
1053 @Override
1054 public V remove(final Object key) {
1055 if (delegateMap != null) {
1056 return delegateMap.remove(key);
1057 }
1058 if (size == 0) {
1059 return null;
1060 }
1061 if (key == null) {
1062 switch (size) {
1063 case 3:
1064 if (key3 == null) {
1065 final V old = value3;
1066 hash3 = 0;
1067 key3 = null;
1068 value3 = null;
1069 size = 2;
1070 return old;
1071 }
1072 if (key2 == null) {
1073 final V old = value2;
1074 hash2 = hash3;
1075 key2 = key3;
1076 value2 = value3;
1077 hash3 = 0;
1078 key3 = null;
1079 value3 = null;
1080 size = 2;
1081 return old;
1082 }
1083 if (key1 == null) {
1084 final V old = value1;
1085 hash1 = hash3;
1086 key1 = key3;
1087 value1 = value3;
1088 hash3 = 0;
1089 key3 = null;
1090 value3 = null;
1091 size = 2;
1092 return old;
1093 }
1094 return null;
1095 case 2:
1096 if (key2 == null) {
1097 final V old = value2;
1098 hash2 = 0;
1099 key2 = null;
1100 value2 = null;
1101 size = 1;
1102 return old;
1103 }
1104 if (key1 == null) {
1105 final V old = value1;
1106 hash1 = hash2;
1107 key1 = key2;
1108 value1 = value2;
1109 hash2 = 0;
1110 key2 = null;
1111 value2 = null;
1112 size = 1;
1113 return old;
1114 }
1115 return null;
1116 case 1:
1117 if (key1 == null) {
1118 final V old = value1;
1119 hash1 = 0;
1120 key1 = null;
1121 value1 = null;
1122 size = 0;
1123 return old;
1124 }
1125 }
1126 } else {
1127 if (size > 0) {
1128 final int hashCode = key.hashCode();
1129 switch (size) {
1130 case 3:
1131 if (hash3 == hashCode && key.equals(key3)) {
1132 final V old = value3;
1133 hash3 = 0;
1134 key3 = null;
1135 value3 = null;
1136 size = 2;
1137 return old;
1138 }
1139 if (hash2 == hashCode && key.equals(key2)) {
1140 final V old = value2;
1141 hash2 = hash3;
1142 key2 = key3;
1143 value2 = value3;
1144 hash3 = 0;
1145 key3 = null;
1146 value3 = null;
1147 size = 2;
1148 return old;
1149 }
1150 if (hash1 == hashCode && key.equals(key1)) {
1151 final V old = value1;
1152 hash1 = hash3;
1153 key1 = key3;
1154 value1 = value3;
1155 hash3 = 0;
1156 key3 = null;
1157 value3 = null;
1158 size = 2;
1159 return old;
1160 }
1161 return null;
1162 case 2:
1163 if (hash2 == hashCode && key.equals(key2)) {
1164 final V old = value2;
1165 hash2 = 0;
1166 key2 = null;
1167 value2 = null;
1168 size = 1;
1169 return old;
1170 }
1171 if (hash1 == hashCode && key.equals(key1)) {
1172 final V old = value1;
1173 hash1 = hash2;
1174 key1 = key2;
1175 value1 = value2;
1176 hash2 = 0;
1177 key2 = null;
1178 value2 = null;
1179 size = 1;
1180 return old;
1181 }
1182 return null;
1183 case 1:
1184 if (hash1 == hashCode && key.equals(key1)) {
1185 final V old = value1;
1186 hash1 = 0;
1187 key1 = null;
1188 value1 = null;
1189 size = 0;
1190 return old;
1191 }
1192 }
1193 }
1194 }
1195 return null;
1196 }
1197
1198
1199
1200
1201
1202
1203 @Override
1204 public int size() {
1205 if (delegateMap != null) {
1206 return delegateMap.size();
1207 }
1208 return size;
1209 }
1210
1211
1212
1213
1214
1215
1216 @Override
1217 public String toString() {
1218 if (delegateMap != null) {
1219 return delegateMap.toString();
1220 }
1221 if (size == 0) {
1222 return "{}";
1223 }
1224 final StringBuilder buf = new StringBuilder(128);
1225 buf.append('{');
1226 switch (size) {
1227 case 3:
1228 buf.append(key3 == this ? "(this Map)" : key3);
1229 buf.append('=');
1230 buf.append(value3 == this ? "(this Map)" : value3);
1231 buf.append(CollectionUtils.COMMA);
1232 case 2:
1233 buf.append(key2 == this ? "(this Map)" : key2);
1234 buf.append('=');
1235 buf.append(value2 == this ? "(this Map)" : value2);
1236 buf.append(CollectionUtils.COMMA);
1237 case 1:
1238 buf.append(key1 == this ? "(this Map)" : key1);
1239 buf.append('=');
1240 buf.append(value1 == this ? "(this Map)" : value1);
1241 break;
1242
1243 default:
1244 throw new IllegalStateException("Invalid map index: " + size);
1245 }
1246 buf.append('}');
1247 return buf.toString();
1248 }
1249
1250
1251
1252
1253
1254
1255
1256
1257 @Override
1258 public Collection<V> values() {
1259 if (delegateMap != null) {
1260 return delegateMap.values();
1261 }
1262 return new Values<>(this);
1263 }
1264
1265
1266
1267
1268
1269
1270
1271 private void writeObject(final ObjectOutputStream out) throws IOException {
1272 out.defaultWriteObject();
1273 out.writeInt(size());
1274 for (final MapIterator<?, ?> it = mapIterator(); it.hasNext();) {
1275 out.writeObject(it.next());
1276 out.writeObject(it.getValue());
1277 }
1278 }
1279
1280 }