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.io.IOException;
020import java.io.ObjectInputStream;
021import java.io.ObjectOutputStream;
022import java.io.Serializable;
023import java.util.ArrayList;
024import java.util.Comparator;
025import java.util.Iterator;
026import java.util.ListIterator;
027import java.util.Map;
028import java.util.SortedMap;
029import java.util.TreeMap;
030
031import org.apache.commons.collections4.BidiMap;
032import org.apache.commons.collections4.OrderedBidiMap;
033import org.apache.commons.collections4.OrderedMap;
034import org.apache.commons.collections4.OrderedMapIterator;
035import org.apache.commons.collections4.ResettableIterator;
036import org.apache.commons.collections4.SortedBidiMap;
037import org.apache.commons.collections4.map.AbstractSortedMapDecorator;
038
039/**
040 * Implementation of {@link BidiMap} that uses two {@link TreeMap} instances.
041 * <p>
042 * The setValue() method on iterators will succeed only if the new value being set is
043 * not already in the bidi map.
044 * </p>
045 * <p>
046 * When considering whether to use this class, the {@link TreeBidiMap} class should
047 * also be considered. It implements the interface using a dedicated design, and does
048 * not store each object twice, which can save on memory use.
049 * </p>
050 * <p>
051 * NOTE: From Commons Collections 3.1, all subclasses will use {@link TreeMap}
052 * and the flawed {@code createMap} method is ignored.
053 * </p>
054 *
055 * @param <K> the type of the keys in this map
056 * @param <V> the type of the values in this map
057 * @since 3.0
058 */
059public class DualTreeBidiMap<K, V> extends AbstractDualBidiMap<K, V>
060        implements SortedBidiMap<K, V>, Serializable {
061
062    /**
063     * Inner class MapIterator.
064     *
065     * @param <K> the type of the keys.
066     * @param <V> the type of the values.
067     */
068    protected static class BidiOrderedMapIterator<K, V> implements OrderedMapIterator<K, V>, ResettableIterator<K> {
069
070        /** The parent map */
071        private final AbstractDualBidiMap<K, V> parent;
072
073        /** The iterator being decorated */
074        private ListIterator<Map.Entry<K, V>> iterator;
075
076        /** The last returned entry */
077        private Map.Entry<K, V> last;
078
079        /**
080         * Constructs a new instance.
081         * @param parent  the parent map
082         */
083        protected BidiOrderedMapIterator(final AbstractDualBidiMap<K, V> parent) {
084            this.parent = parent;
085            iterator = new ArrayList<>(parent.entrySet()).listIterator();
086        }
087
088        @Override
089        public K getKey() {
090            if (last == null) {
091                throw new IllegalStateException(
092                        "Iterator getKey() can only be called after next() and before remove()");
093            }
094            return last.getKey();
095        }
096
097        @Override
098        public V getValue() {
099            if (last == null) {
100                throw new IllegalStateException(
101                        "Iterator getValue() can only be called after next() and before remove()");
102            }
103            return last.getValue();
104        }
105
106        @Override
107        public boolean hasNext() {
108            return iterator.hasNext();
109        }
110
111        @Override
112        public boolean hasPrevious() {
113            return iterator.hasPrevious();
114        }
115
116        @Override
117        public K next() {
118            last = iterator.next();
119            return last.getKey();
120        }
121
122        @Override
123        public K previous() {
124            last = iterator.previous();
125            return last.getKey();
126        }
127
128        @Override
129        public void remove() {
130            iterator.remove();
131            parent.remove(last.getKey());
132            last = null;
133        }
134
135        @Override
136        public void reset() {
137            iterator = new ArrayList<>(parent.entrySet()).listIterator();
138            last = null;
139        }
140
141        @Override
142        public V setValue(final V value) {
143            if (last == null) {
144                throw new IllegalStateException(
145                        "Iterator setValue() can only be called after next() and before remove()");
146            }
147            if (parent.reverseMap.containsKey(value) &&
148                parent.reverseMap.get(value) != last.getKey()) {
149                throw new IllegalArgumentException(
150                        "Cannot use setValue() when the object being set is already in the map");
151            }
152            final V oldValue = parent.put(last.getKey(), value);
153            // Map.Entry specifies that the behavior is undefined when the backing map
154            // has been modified (as we did with the put), so we also set the value
155            last.setValue(value);
156            return oldValue;
157        }
158
159        @Override
160        public String toString() {
161            if (last != null) {
162                return "MapIterator[" + getKey() + "=" + getValue() + "]";
163            }
164            return "MapIterator[]";
165        }
166    }
167
168    /**
169     * Internal sorted map view.
170     *
171     * @param <K> the type of the keys.
172     * @param <V> the type of the values.
173     */
174    protected static class ViewMap<K, V> extends AbstractSortedMapDecorator<K, V> {
175        /**
176         * Constructs a new instance.
177         * @param bidi  the parent bidi map
178         * @param sm  the subMap sorted map
179         */
180        protected ViewMap(final DualTreeBidiMap<K, V> bidi, final SortedMap<K, V> sm) {
181            // the implementation is not great here...
182            // use the normalMap as the filtered map, but reverseMap as the full map
183            // this forces containsValue and clear to be overridden
184            super(new DualTreeBidiMap<>(sm, bidi.reverseMap, bidi.inverseBidiMap));
185        }
186
187        @Override
188        public void clear() {
189            // override as default implementation uses reverseMap
190            for (final Iterator<K> it = keySet().iterator(); it.hasNext();) {
191                it.next();
192                it.remove();
193            }
194        }
195
196        @Override
197        public boolean containsValue(final Object value) {
198            // override as default implementation uses reverseMap
199            return decorated().normalMap.containsValue(value);
200        }
201
202        @Override
203        protected DualTreeBidiMap<K, V> decorated() {
204            return (DualTreeBidiMap<K, V>) super.decorated();
205        }
206
207        @Override
208        public SortedMap<K, V> headMap(final K toKey) {
209            return new ViewMap<>(decorated(), super.headMap(toKey));
210        }
211
212        @Override
213        public K nextKey(final K key) {
214            return decorated().nextKey(key);
215        }
216
217        @Override
218        public K previousKey(final K key) {
219            return decorated().previousKey(key);
220        }
221
222        @Override
223        public SortedMap<K, V> subMap(final K fromKey, final K toKey) {
224            return new ViewMap<>(decorated(), super.subMap(fromKey, toKey));
225        }
226
227        @Override
228        public SortedMap<K, V> tailMap(final K fromKey) {
229            return new ViewMap<>(decorated(), super.tailMap(fromKey));
230        }
231    }
232
233    /** Ensure serialization compatibility */
234    private static final long serialVersionUID = 721969328361809L;
235
236    /** The key comparator to use */
237    private final Comparator<? super K> comparator;
238
239    /** The value comparator to use */
240    private final Comparator<? super V> valueComparator;
241
242    /**
243     * Creates an empty {@link DualTreeBidiMap}.
244     */
245    public DualTreeBidiMap() {
246        super(new TreeMap<>(), new TreeMap<>());
247        this.comparator = null;
248        this.valueComparator = null;
249    }
250
251    /**
252     * Constructs a {@link DualTreeBidiMap} using the specified {@link Comparator}.
253     *
254     * @param keyComparator  the comparator
255     * @param valueComparator  the values comparator to use
256     */
257    public DualTreeBidiMap(final Comparator<? super K> keyComparator, final Comparator<? super V> valueComparator) {
258        super(new TreeMap<>(keyComparator), new TreeMap<>(valueComparator));
259        this.comparator = keyComparator;
260        this.valueComparator = valueComparator;
261    }
262
263    /**
264     * Constructs a {@link DualTreeBidiMap} and copies the mappings from
265     * specified {@link Map}.
266     *
267     * @param map  the map whose mappings are to be placed in this map
268     */
269    public DualTreeBidiMap(final Map<? extends K, ? extends V> map) {
270        super(new TreeMap<>(), new TreeMap<>());
271        putAll(map);
272        this.comparator = null;
273        this.valueComparator = null;
274    }
275
276    /**
277     * Constructs a {@link DualTreeBidiMap} that decorates the specified maps.
278     *
279     * @param normalMap  the normal direction map
280     * @param reverseMap  the reverse direction map
281     * @param inverseBidiMap  the inverse BidiMap
282     */
283    protected DualTreeBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap,
284                              final BidiMap<V, K> inverseBidiMap) {
285        super(normalMap, reverseMap, inverseBidiMap);
286        this.comparator = ((SortedMap<K, V>) normalMap).comparator();
287        this.valueComparator = ((SortedMap<V, K>) reverseMap).comparator();
288    }
289
290    @Override
291    public Comparator<? super K> comparator() {
292        return ((SortedMap<K, V>) normalMap).comparator();
293    }
294
295    /**
296     * Creates a new instance of this object.
297     *
298     * @param normalMap  the normal direction map
299     * @param reverseMap  the reverse direction map
300     * @param inverseMap  the inverse BidiMap
301     * @return new bidi map
302     */
303    @Override
304    protected DualTreeBidiMap<V, K> createBidiMap(final Map<V, K> normalMap, final Map<K, V> reverseMap,
305                                                  final BidiMap<K, V> inverseMap) {
306        return new DualTreeBidiMap<>(normalMap, reverseMap, inverseMap);
307    }
308
309    @Override
310    public K firstKey() {
311        return ((SortedMap<K, V>) normalMap).firstKey();
312    }
313
314    @Override
315    public SortedMap<K, V> headMap(final K toKey) {
316        final SortedMap<K, V> sub = ((SortedMap<K, V>) normalMap).headMap(toKey);
317        return new ViewMap<>(this, sub);
318    }
319
320    @Override
321    public SortedBidiMap<V, K> inverseBidiMap() {
322        return (SortedBidiMap<V, K>) super.inverseBidiMap();
323    }
324
325    public OrderedBidiMap<V, K> inverseOrderedBidiMap() {
326        return inverseBidiMap();
327    }
328
329    public SortedBidiMap<V, K> inverseSortedBidiMap() {
330        return inverseBidiMap();
331    }
332
333    @Override
334    public K lastKey() {
335        return ((SortedMap<K, V>) normalMap).lastKey();
336    }
337
338    /**
339     * Obtains an ordered map iterator.
340     * <p>
341     * This implementation copies the elements to an ArrayList in order to
342     * provide the forward/backward behavior.
343     *
344     * @return a new ordered map iterator
345     */
346    @Override
347    public OrderedMapIterator<K, V> mapIterator() {
348        return new BidiOrderedMapIterator<>(this);
349    }
350
351    @Override
352    public K nextKey(final K key) {
353        if (isEmpty()) {
354            return null;
355        }
356        if (normalMap instanceof OrderedMap) {
357            return ((OrderedMap<K, ?>) normalMap).nextKey(key);
358        }
359        final SortedMap<K, V> sm = (SortedMap<K, V>) normalMap;
360        final Iterator<K> it = sm.tailMap(key).keySet().iterator();
361        it.next();
362        if (it.hasNext()) {
363            return it.next();
364        }
365        return null;
366    }
367
368    @Override
369    public K previousKey(final K key) {
370        if (isEmpty()) {
371            return null;
372        }
373        if (normalMap instanceof OrderedMap) {
374            return ((OrderedMap<K, V>) normalMap).previousKey(key);
375        }
376        final SortedMap<K, V> sm = (SortedMap<K, V>) normalMap;
377        final SortedMap<K, V> hm = sm.headMap(key);
378        if (hm.isEmpty()) {
379            return null;
380        }
381        return hm.lastKey();
382    }
383
384    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
385        in.defaultReadObject();
386        normalMap = new TreeMap<>(comparator);
387        reverseMap = new TreeMap<>(valueComparator);
388        @SuppressWarnings("unchecked") // will fail at runtime if the stream is incorrect
389        final Map<K, V> map = (Map<K, V>) in.readObject();
390        putAll(map);
391    }
392
393    @Override
394    public SortedMap<K, V> subMap(final K fromKey, final K toKey) {
395        final SortedMap<K, V> sub = ((SortedMap<K, V>) normalMap).subMap(fromKey, toKey);
396        return new ViewMap<>(this, sub);
397    }
398
399    @Override
400    public SortedMap<K, V> tailMap(final K fromKey) {
401        final SortedMap<K, V> sub = ((SortedMap<K, V>) normalMap).tailMap(fromKey);
402        return new ViewMap<>(this, sub);
403    }
404
405    @Override
406    public Comparator<? super V> valueComparator() {
407        return ((SortedMap<V, K>) reverseMap).comparator();
408    }
409
410    // Serialization
411    private void writeObject(final ObjectOutputStream out) throws IOException {
412        out.defaultWriteObject();
413        out.writeObject(normalMap);
414    }
415
416}