    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}