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