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