001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4.bidimap; 018 019import java.util.Collection; 020import java.util.Iterator; 021import java.util.Map; 022import java.util.Objects; 023import java.util.Set; 024import java.util.function.Predicate; 025 026import org.apache.commons.collections4.BidiMap; 027import org.apache.commons.collections4.MapIterator; 028import org.apache.commons.collections4.ResettableIterator; 029import org.apache.commons.collections4.collection.AbstractCollectionDecorator; 030import org.apache.commons.collections4.iterators.AbstractIteratorDecorator; 031import org.apache.commons.collections4.keyvalue.AbstractMapEntryDecorator; 032 033/** 034 * Abstract {@link BidiMap} implemented using two maps. 035 * <p> 036 * An implementation can be written simply by implementing the 037 * {@link #createBidiMap(Map, Map, BidiMap)} method. 038 * </p> 039 * 040 * @param <K> The type of the keys in the map 041 * @param <V> The type of the values in the map 042 * @see DualHashBidiMap 043 * @see DualTreeBidiMap 044 * @since 3.0 045 */ 046public abstract class AbstractDualBidiMap<K, V> implements BidiMap<K, V> { 047 048 /** 049 * Inner class MapIterator. 050 * 051 * @param <K> The type of the keys. 052 * @param <V> The type of the values. 053 */ 054 protected static class BidiMapIterator<K, V> implements MapIterator<K, V>, ResettableIterator<K> { 055 056 /** The parent map */ 057 protected final AbstractDualBidiMap<K, V> parent; 058 059 /** The iterator being wrapped */ 060 protected Iterator<Map.Entry<K, V>> iterator; 061 062 /** The last returned entry */ 063 protected Map.Entry<K, V> last; 064 065 /** Whether remove is allowed at present */ 066 protected boolean canRemove; 067 068 /** 069 * Constructs a new instance. 070 * 071 * @param parent The parent map 072 */ 073 protected BidiMapIterator(final AbstractDualBidiMap<K, V> parent) { 074 this.parent = parent; 075 this.iterator = parent.normalMap.entrySet().iterator(); 076 } 077 078 @Override 079 public K getKey() { 080 if (last == null) { 081 throw new IllegalStateException( 082 "Iterator getKey() can only be called after next() and before remove()"); 083 } 084 return last.getKey(); 085 } 086 087 @Override 088 public V getValue() { 089 if (last == null) { 090 throw new IllegalStateException( 091 "Iterator getValue() can only be called after next() and before remove()"); 092 } 093 return last.getValue(); 094 } 095 096 @Override 097 public boolean hasNext() { 098 return iterator.hasNext(); 099 } 100 101 @Override 102 public K next() { 103 last = iterator.next(); 104 canRemove = true; 105 return last.getKey(); 106 } 107 108 @Override 109 public void remove() { 110 if (!canRemove) { 111 throw new IllegalStateException("Iterator remove() can only be called once after next()"); 112 } 113 // store value as remove may change the entry in the decorator (for example TreeMap) 114 final V value = last.getValue(); 115 iterator.remove(); 116 parent.reverseMap.remove(value); 117 last = null; 118 canRemove = false; 119 } 120 121 @Override 122 public void reset() { 123 iterator = parent.normalMap.entrySet().iterator(); 124 last = null; 125 canRemove = false; 126 } 127 128 @Override 129 public V setValue(final V value) { 130 if (last == null) { 131 throw new IllegalStateException( 132 "Iterator setValue() can only be called after next() and before remove()"); 133 } 134 if (parent.reverseMap.containsKey(value) && 135 parent.reverseMap.get(value) != last.getKey()) { 136 throw new IllegalArgumentException( 137 "Cannot use setValue() when the object being set is already in the map"); 138 } 139 return parent.put(last.getKey(), value); 140 } 141 142 @Override 143 public String toString() { 144 if (last != null) { 145 return "MapIterator[" + getKey() + "=" + getValue() + "]"; 146 } 147 return "MapIterator[]"; 148 } 149 } 150 151 /** 152 * Inner class EntrySet. 153 * 154 * @param <K> The type of the keys. 155 * @param <V> The type of the values. 156 */ 157 protected static class EntrySet<K, V> extends View<K, V, Map.Entry<K, V>> implements Set<Map.Entry<K, V>> { 158 159 /** Serialization version */ 160 private static final long serialVersionUID = 4040410962603292348L; 161 162 /** 163 * Constructs a new instance. 164 * 165 * @param parent The parent BidiMap 166 */ 167 protected EntrySet(final AbstractDualBidiMap<K, V> parent) { 168 super(parent.normalMap.entrySet(), parent); 169 } 170 171 @Override 172 public Iterator<Map.Entry<K, V>> iterator() { 173 return parent.createEntrySetIterator(super.iterator()); 174 } 175 176 @Override 177 public boolean remove(final Object obj) { 178 if (!(obj instanceof Map.Entry)) { 179 return false; 180 } 181 final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj; 182 final Object key = entry.getKey(); 183 if (parent.containsKey(key)) { 184 final V value = parent.normalMap.get(key); 185 if (Objects.equals(value, entry.getValue())) { 186 parent.normalMap.remove(key); 187 parent.reverseMap.remove(value); 188 return true; 189 } 190 } 191 return false; 192 } 193 } 194 195 /** 196 * Inner class EntrySetIterator. 197 * 198 * @param <K> The type of the keys. 199 * @param <V> The type of the values. 200 */ 201 protected static class EntrySetIterator<K, V> extends AbstractIteratorDecorator<Map.Entry<K, V>> { 202 203 /** The parent map */ 204 protected final AbstractDualBidiMap<K, V> parent; 205 206 /** The last returned entry */ 207 protected Map.Entry<K, V> last; 208 209 /** Whether remove is allowed at present */ 210 protected boolean canRemove; 211 212 /** 213 * Constructs a new instance. 214 * 215 * @param iterator The iterator to decorate 216 * @param parent The parent map 217 */ 218 protected EntrySetIterator(final Iterator<Map.Entry<K, V>> iterator, final AbstractDualBidiMap<K, V> parent) { 219 super(iterator); 220 this.parent = parent; 221 } 222 223 @Override 224 public Map.Entry<K, V> next() { 225 last = new MapEntry<>(super.next(), parent); 226 canRemove = true; 227 return last; 228 } 229 230 @Override 231 public void remove() { 232 if (!canRemove) { 233 throw new IllegalStateException("Iterator remove() can only be called once after next()"); 234 } 235 // store value as remove may change the entry in the decorator (for example TreeMap) 236 final Object value = last.getValue(); 237 super.remove(); 238 parent.reverseMap.remove(value); 239 last = null; 240 canRemove = false; 241 } 242 } 243 244 /** 245 * Inner class KeySet. 246 * 247 * @param <K> The type of elements maintained by this set 248 */ 249 protected static class KeySet<K> extends View<K, Object, K> implements Set<K> { 250 251 /** Serialization version */ 252 private static final long serialVersionUID = -7107935777385040694L; 253 254 /** 255 * Constructs a new instance. 256 * 257 * @param parent The parent BidiMap 258 */ 259 @SuppressWarnings("unchecked") 260 protected KeySet(final AbstractDualBidiMap<K, ?> parent) { 261 super(parent.normalMap.keySet(), (AbstractDualBidiMap<K, Object>) parent); 262 } 263 264 @Override 265 public boolean contains(final Object key) { 266 return parent.normalMap.containsKey(key); 267 } 268 269 @Override 270 public Iterator<K> iterator() { 271 return parent.createKeySetIterator(super.iterator()); 272 } 273 274 @Override 275 public boolean remove(final Object key) { 276 if (parent.normalMap.containsKey(key)) { 277 final Object value = parent.normalMap.remove(key); 278 parent.reverseMap.remove(value); 279 return true; 280 } 281 return false; 282 } 283 } 284 285 /** 286 * Inner class KeySetIterator. 287 * 288 * @param <K> The key type. 289 */ 290 protected static class KeySetIterator<K> extends AbstractIteratorDecorator<K> { 291 292 /** The parent map */ 293 protected final AbstractDualBidiMap<K, ?> parent; 294 295 /** The last returned key */ 296 protected K lastKey; 297 298 /** Whether remove is allowed at present */ 299 protected boolean canRemove; 300 301 /** 302 * Constructs a new instance. 303 * 304 * @param iterator The iterator to decorate 305 * @param parent The parent map 306 */ 307 protected KeySetIterator(final Iterator<K> iterator, final AbstractDualBidiMap<K, ?> parent) { 308 super(iterator); 309 this.parent = parent; 310 } 311 312 @Override 313 public K next() { 314 lastKey = super.next(); 315 canRemove = true; 316 return lastKey; 317 } 318 319 @Override 320 public void remove() { 321 if (!canRemove) { 322 throw new IllegalStateException("Iterator remove() can only be called once after next()"); 323 } 324 final Object value = parent.normalMap.get(lastKey); 325 super.remove(); 326 parent.reverseMap.remove(value); 327 lastKey = null; 328 canRemove = false; 329 } 330 } 331 332 /** 333 * Inner class MapEntry. 334 * 335 * @param <K> The type of the keys. 336 * @param <V> The type of the values. 337 */ 338 protected static class MapEntry<K, V> extends AbstractMapEntryDecorator<K, V> { 339 340 /** The parent map */ 341 protected final AbstractDualBidiMap<K, V> parent; 342 343 /** 344 * Constructs a new instance. 345 * 346 * @param entry The entry to decorate 347 * @param parent The parent map 348 */ 349 protected MapEntry(final Map.Entry<K, V> entry, final AbstractDualBidiMap<K, V> parent) { 350 super(entry); 351 this.parent = parent; 352 } 353 354 @Override 355 public V setValue(final V value) { 356 final K key = getKey(); 357 if (parent.reverseMap.containsKey(value) && 358 parent.reverseMap.get(value) != key) { 359 throw new IllegalArgumentException( 360 "Cannot use setValue() when the object being set is already in the map"); 361 } 362 final V oldValue = parent.put(key, value); 363 super.setValue(value); 364 return oldValue; 365 } 366 } 367 368 /** 369 * Inner class Values. 370 * 371 * @param <V> The type of the values. 372 */ 373 protected static class Values<V> extends View<Object, V, V> implements Set<V> { 374 375 /** Serialization version */ 376 private static final long serialVersionUID = 4023777119829639864L; 377 378 /** 379 * Constructs a new instance. 380 * 381 * @param parent The parent BidiMap 382 */ 383 @SuppressWarnings("unchecked") 384 protected Values(final AbstractDualBidiMap<?, V> parent) { 385 super(parent.normalMap.values(), (AbstractDualBidiMap<Object, V>) parent); 386 } 387 388 @Override 389 public boolean contains(final Object value) { 390 return parent.reverseMap.containsKey(value); 391 } 392 393 @Override 394 public Iterator<V> iterator() { 395 return parent.createValuesIterator(super.iterator()); 396 } 397 398 @Override 399 public boolean remove(final Object value) { 400 if (parent.reverseMap.containsKey(value)) { 401 final Object key = parent.reverseMap.remove(value); 402 parent.normalMap.remove(key); 403 return true; 404 } 405 return false; 406 } 407 } 408 409 /** 410 * Inner class ValuesIterator. 411 * 412 * @param <V> The value type. 413 */ 414 protected static class ValuesIterator<V> extends AbstractIteratorDecorator<V> { 415 416 /** The parent map */ 417 protected final AbstractDualBidiMap<Object, V> parent; 418 419 /** The last returned value */ 420 protected V lastValue; 421 422 /** Whether remove is allowed at present */ 423 protected boolean canRemove; 424 425 /** 426 * Constructs a new instance. 427 * 428 * @param iterator The iterator to decorate 429 * @param parent The parent map 430 */ 431 @SuppressWarnings("unchecked") 432 protected ValuesIterator(final Iterator<V> iterator, final AbstractDualBidiMap<?, V> parent) { 433 super(iterator); 434 this.parent = (AbstractDualBidiMap<Object, V>) parent; 435 } 436 437 @Override 438 public V next() { 439 lastValue = super.next(); 440 canRemove = true; 441 return lastValue; 442 } 443 444 @Override 445 public void remove() { 446 if (!canRemove) { 447 throw new IllegalStateException("Iterator remove() can only be called once after next()"); 448 } 449 super.remove(); // removes from maps[0] 450 parent.reverseMap.remove(lastValue); 451 lastValue = null; 452 canRemove = false; 453 } 454 } 455 456 /** 457 * Inner class View. 458 * 459 * @param <K> The type of the keys in the map. 460 * @param <V> The type of the values in the map. 461 * @param <E> The type of the elements in the collection. 462 */ 463 protected abstract static class View<K, V, E> extends AbstractCollectionDecorator<E> { 464 465 /** Generated serial version ID. */ 466 private static final long serialVersionUID = 4621510560119690639L; 467 468 /** The parent map */ 469 protected final AbstractDualBidiMap<K, V> parent; 470 471 /** 472 * Constructs a new instance. 473 * 474 * @param coll The collection view being decorated 475 * @param parent The parent BidiMap 476 */ 477 protected View(final Collection<E> coll, final AbstractDualBidiMap<K, V> parent) { 478 super(coll); 479 this.parent = parent; 480 } 481 482 @Override 483 public void clear() { 484 parent.clear(); 485 } 486 487 @Override 488 public boolean equals(final Object object) { 489 return object == this || decorated().equals(object); 490 } 491 492 @Override 493 public int hashCode() { 494 return decorated().hashCode(); 495 } 496 497 @Override 498 public boolean removeAll(final Collection<?> coll) { 499 if (parent.isEmpty() || coll.isEmpty()) { 500 return false; 501 } 502 boolean modified = false; 503 for (final Object current : coll) { 504 modified |= remove(current); 505 } 506 return modified; 507 } 508 509 /** 510 * @since 4.4 511 */ 512 @Override 513 public boolean removeIf(final Predicate<? super E> filter) { 514 if (parent.isEmpty() || Objects.isNull(filter)) { 515 return false; 516 } 517 boolean modified = false; 518 final Iterator<?> it = iterator(); 519 while (it.hasNext()) { 520 @SuppressWarnings("unchecked") 521 final E e = (E) it.next(); 522 if (filter.test(e)) { 523 it.remove(); 524 modified = true; 525 } 526 } 527 return modified; 528 } 529 530 /** 531 * {@inheritDoc} 532 * <p> 533 * This implementation iterates over the elements of this bidi map, checking each element in 534 * turn to see if it's contained in {@code coll}. If it's not contained, it's removed 535 * from this bidi map. As a consequence, it is advised to use a collection type for 536 * {@code coll} that provides a fast (for example O(1)) implementation of 537 * {@link Collection#contains(Object)}. 538 */ 539 @Override 540 public boolean retainAll(final Collection<?> coll) { 541 if (parent.isEmpty()) { 542 return false; 543 } 544 if (coll.isEmpty()) { 545 parent.clear(); 546 return true; 547 } 548 boolean modified = false; 549 final Iterator<E> it = iterator(); 550 while (it.hasNext()) { 551 if (!coll.contains(it.next())) { 552 it.remove(); 553 modified = true; 554 } 555 } 556 return modified; 557 } 558 } 559 560 /** 561 * Normal delegate map. 562 */ 563 transient Map<K, V> normalMap; 564 565 // Map delegation 566 567 /** 568 * Reverse delegate map. 569 */ 570 transient Map<V, K> reverseMap; 571 572 /** 573 * Inverse view of this map. 574 */ 575 transient BidiMap<V, K> inverseBidiMap; 576 577 /** 578 * View of the keys. 579 */ 580 transient Set<K> keySet; 581 582 /** 583 * View of the values. 584 */ 585 transient Set<V> values; 586 587 /** 588 * View of the entries. 589 */ 590 transient Set<Map.Entry<K, V>> entrySet; 591 592 /** 593 * Creates an empty map, initialized by {@code createMap}. 594 * <p> 595 * This constructor remains in place for deserialization. 596 * All other usage is deprecated in favor of 597 * {@link #AbstractDualBidiMap(Map, Map)}. 598 */ 599 protected AbstractDualBidiMap() { 600 } 601 602 /** 603 * Creates an empty map using the two maps specified as storage. 604 * <p> 605 * The two maps must be a matching pair, normal and reverse. 606 * They will typically both be empty. 607 * <p> 608 * Neither map is validated, so nulls may be passed in. 609 * If you choose to do this then the subclass constructor must populate 610 * the {@code maps[]} instance variable itself. 611 * 612 * @param normalMap The normal direction map 613 * @param reverseMap The reverse direction map 614 * @since 3.1 615 */ 616 protected AbstractDualBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap) { 617 this.normalMap = normalMap; 618 this.reverseMap = reverseMap; 619 } 620 621 // BidiMap changes 622 623 /** 624 * Constructs a map that decorates the specified maps, 625 * used by the subclass {@code createBidiMap} implementation. 626 * 627 * @param normalMap The normal direction map 628 * @param reverseMap The reverse direction map 629 * @param inverseBidiMap The inverse BidiMap 630 */ 631 protected AbstractDualBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap, 632 final BidiMap<V, K> inverseBidiMap) { 633 this.normalMap = normalMap; 634 this.reverseMap = reverseMap; 635 this.inverseBidiMap = inverseBidiMap; 636 } 637 638 @Override 639 public void clear() { 640 normalMap.clear(); 641 reverseMap.clear(); 642 } 643 644 @Override 645 public boolean containsKey(final Object key) { 646 return normalMap.containsKey(key); 647 } 648 649 @Override 650 public boolean containsValue(final Object value) { 651 return reverseMap.containsKey(value); 652 } 653 654 /** 655 * Creates a new instance of the subclass. 656 * 657 * @param normalMap The normal direction map 658 * @param reverseMap The reverse direction map 659 * @param inverseMap this map, which is the inverse in the new map 660 * @return The bidi map 661 */ 662 protected abstract BidiMap<V, K> createBidiMap(Map<V, K> normalMap, Map<K, V> reverseMap, BidiMap<K, V> inverseMap); 663 664 /** 665 * Creates an entry set iterator. 666 * Subclasses can override this to return iterators with different properties. 667 * 668 * @param iterator The iterator to decorate 669 * @return The entrySet iterator 670 */ 671 protected Iterator<Map.Entry<K, V>> createEntrySetIterator(final Iterator<Map.Entry<K, V>> iterator) { 672 return new EntrySetIterator<>(iterator, this); 673 } 674 675 /** 676 * Creates a key set iterator. 677 * Subclasses can override this to return iterators with different properties. 678 * 679 * @param iterator The iterator to decorate 680 * @return The keySet iterator 681 */ 682 protected Iterator<K> createKeySetIterator(final Iterator<K> iterator) { 683 return new KeySetIterator<>(iterator, this); 684 } 685 686 /** 687 * Creates a values iterator. 688 * Subclasses can override this to return iterators with different properties. 689 * 690 * @param iterator The iterator to decorate 691 * @return The values iterator 692 */ 693 protected Iterator<V> createValuesIterator(final Iterator<V> iterator) { 694 return new ValuesIterator<>(iterator, this); 695 } 696 697 /** 698 * Gets an entrySet view of the map. 699 * Changes made on the set are reflected in the map. 700 * The set supports remove and clear but not add. 701 * <p> 702 * The Map Entry setValue() method only allow a new value to be set. 703 * If the value being set is already in the map, an IllegalArgumentException 704 * is thrown (as setValue cannot change the size of the map). 705 * </p> 706 * 707 * @return The entrySet view 708 */ 709 @Override 710 public Set<Map.Entry<K, V>> entrySet() { 711 if (entrySet == null) { 712 entrySet = new EntrySet<>(this); 713 } 714 return entrySet; 715 } 716 717 @Override 718 public boolean equals(final Object obj) { 719 return normalMap.equals(obj); 720 } 721 722 @Override 723 public V get(final Object key) { 724 return normalMap.get(key); 725 } 726 727 @Override 728 public K getKey(final Object value) { 729 return reverseMap.get(value); 730 } 731 732 @Override 733 public int hashCode() { 734 return normalMap.hashCode(); 735 } 736 737 @Override 738 public BidiMap<V, K> inverseBidiMap() { 739 if (inverseBidiMap == null) { 740 inverseBidiMap = createBidiMap(reverseMap, normalMap, this); 741 } 742 return inverseBidiMap; 743 } 744 745 @Override 746 public boolean isEmpty() { 747 return normalMap.isEmpty(); 748 } 749 750 // Map views 751 752 /** 753 * Gets a keySet view of the map. 754 * Changes made on the view are reflected in the map. 755 * The set supports remove and clear but not add. 756 * 757 * @return The keySet view 758 */ 759 @Override 760 public Set<K> keySet() { 761 if (keySet == null) { 762 keySet = new KeySet<>(this); 763 } 764 return keySet; 765 } 766 767 // BidiMap 768 769 /** 770 * Obtains a {@code MapIterator} over the map. 771 * The iterator implements {@link BidiMapIterator}. 772 * This implementation relies on the entrySet iterator. 773 * 774 * @return A map iterator 775 */ 776 @Override 777 public MapIterator<K, V> mapIterator() { 778 return new BidiMapIterator<>(this); 779 } 780 781 @Override 782 public V put(final K key, final V value) { 783 if (normalMap.containsKey(key)) { 784 reverseMap.remove(normalMap.get(key)); 785 } 786 if (reverseMap.containsKey(value)) { 787 normalMap.remove(reverseMap.get(value)); 788 } 789 final V obj = normalMap.put(key, value); 790 reverseMap.put(value, key); 791 return obj; 792 } 793 794 @Override 795 public void putAll(final Map<? extends K, ? extends V> map) { 796 for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) { 797 put(entry.getKey(), entry.getValue()); 798 } 799 } 800 801 @Override 802 public V remove(final Object key) { 803 V value = null; 804 if (normalMap.containsKey(key)) { 805 value = normalMap.remove(key); 806 reverseMap.remove(value); 807 } 808 return value; 809 } 810 811 @Override 812 public K removeValue(final Object value) { 813 K key = null; 814 if (reverseMap.containsKey(value)) { 815 key = reverseMap.remove(value); 816 normalMap.remove(key); 817 } 818 return key; 819 } 820 821 @Override 822 public int size() { 823 return normalMap.size(); 824 } 825 826 @Override 827 public String toString() { 828 return normalMap.toString(); 829 } 830 831 /** 832 * Gets a values view of the map. 833 * Changes made on the view are reflected in the map. 834 * The set supports remove and clear but not add. 835 * 836 * @return The values view 837 */ 838 @Override 839 public Set<V> values() { 840 if (values == null) { 841 values = new Values<>(this); 842 } 843 return values; 844 } 845 846}