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 static org.apache.commons.collections4.bidimap.TreeBidiMap.DataElement.KEY;
020import static org.apache.commons.collections4.bidimap.TreeBidiMap.DataElement.VALUE;
021
022import java.io.IOException;
023import java.io.ObjectInputStream;
024import java.io.ObjectOutputStream;
025import java.io.Serializable;
026import java.util.AbstractSet;
027import java.util.ConcurrentModificationException;
028import java.util.Iterator;
029import java.util.Map;
030import java.util.NoSuchElementException;
031import java.util.Objects;
032import java.util.Set;
033import java.util.TreeMap;
034
035import org.apache.commons.collections4.KeyValue;
036import org.apache.commons.collections4.MapIterator;
037import org.apache.commons.collections4.OrderedBidiMap;
038import org.apache.commons.collections4.OrderedIterator;
039import org.apache.commons.collections4.OrderedMapIterator;
040import org.apache.commons.collections4.iterators.EmptyOrderedMapIterator;
041import org.apache.commons.collections4.keyvalue.UnmodifiableMapEntry;
042
043/**
044 * Red-Black tree-based implementation of BidiMap where all objects added
045 * implement the {@code Comparable} interface.
046 * <p>
047 * This class guarantees that the map will be in both ascending key order
048 * and ascending value order, sorted according to the natural order for
049 * the key's and value's classes.
050 * </p>
051 * <p>
052 * This Map is intended for applications that need to be able to look
053 * up a key-value pairing by either key or value, and need to do so
054 * with equal efficiency.
055 * </p>
056 * <p>
057 * While that goal could be accomplished by taking a pair of TreeMaps
058 * and redirecting requests to the appropriate TreeMap (for example,
059 * containsKey would be directed to the TreeMap that maps values to
060 * keys, containsValue would be directed to the TreeMap that maps keys
061 * to values), there are problems with that implementation.
062 * If the data contained in the TreeMaps is large, the cost of redundant
063 * storage becomes significant. The {@link DualTreeBidiMap} and
064 * {@link DualHashBidiMap} implementations use this approach.
065 * </p>
066 * <p>
067 * This solution keeps minimizes the data storage by holding data only once.
068 * The red-black algorithm is based on {@link TreeMap}, but has been modified
069 * to simultaneously map a tree node by key and by value. This doubles the
070 * cost of put operations (but so does using two TreeMaps), and nearly doubles
071 * the cost of remove operations (there is a savings in that the lookup of the
072 * node to be removed only has to be performed once). And since only one node
073 * contains the key and value, storage is significantly less than that
074 * required by two TreeMaps.
075 * </p>
076 * <p>
077 * The Map.Entry instances returned by the appropriate methods will
078 * not allow setValue() and will throw an
079 * UnsupportedOperationException on attempts to call that method.
080 * </p>
081 *
082 * @param <K> The type of the keys in this map
083 * @param <V> The type of the values in this map
084 * @since 3.0 (previously DoubleOrderedMap v2.0)
085 */
086public class TreeBidiMap<K extends Comparable<K>, V extends Comparable<V>>
087    implements OrderedBidiMap<K, V>, Serializable {
088
089    /**
090     * A view of this map.
091     */
092    abstract class AbstractView<E> extends AbstractSet<E> {
093
094        /** Whether to return KEY or VALUE order. */
095        final DataElement orderType;
096
097        /**
098         * Constructs a new instance.
099         *
100         * @param orderType  The KEY or VALUE int for the order
101         */
102        AbstractView(final DataElement orderType) {
103            this.orderType = orderType;
104        }
105
106        @Override
107        public void clear() {
108            TreeBidiMap.this.clear();
109        }
110
111        @Override
112        public int size() {
113            return TreeBidiMap.this.size();
114        }
115    }
116
117    /**
118     * An iterator over the map.
119     */
120    abstract class AbstractViewIterator {
121
122        /** Whether to return KEY or VALUE order. */
123        private final DataElement orderType;
124
125        /** The last node returned by the iterator. */
126        Node<K, V> lastReturnedNode;
127
128        /** The next node to be returned by the iterator. */
129        private Node<K, V> nextNode;
130
131        /** The previous node in the sequence returned by the iterator. */
132        private Node<K, V> previousNode;
133
134        /** The modification count. */
135        private int expectedModifications;
136
137        /**
138         * Constructs a new instance.
139         *
140         * @param orderType  The KEY or VALUE int for the order
141         */
142        AbstractViewIterator(final DataElement orderType) {
143            this.orderType = orderType;
144            expectedModifications = modifications;
145            nextNode = leastNode(rootNode[orderType.ordinal()], orderType);
146            lastReturnedNode = null;
147            previousNode = null;
148        }
149
150        public final boolean hasNext() {
151            return nextNode != null;
152        }
153
154        public boolean hasPrevious() {
155            return previousNode != null;
156        }
157
158        protected Node<K, V> navigateNext() {
159            if (nextNode == null) {
160                throw new NoSuchElementException();
161            }
162            if (modifications != expectedModifications) {
163                throw new ConcurrentModificationException();
164            }
165            lastReturnedNode = nextNode;
166            previousNode = nextNode;
167            nextNode = nextGreater(nextNode, orderType);
168            return lastReturnedNode;
169        }
170
171        protected Node<K, V> navigatePrevious() {
172            if (previousNode == null) {
173                throw new NoSuchElementException();
174            }
175            if (modifications != expectedModifications) {
176                throw new ConcurrentModificationException();
177            }
178            nextNode = lastReturnedNode;
179            if (nextNode == null) {
180                nextNode = nextGreater(previousNode, orderType);
181            }
182            lastReturnedNode = previousNode;
183            previousNode = nextSmaller(previousNode, orderType);
184            return lastReturnedNode;
185        }
186
187        public final void remove() {
188            if (lastReturnedNode == null) {
189                throw new IllegalStateException();
190            }
191            if (modifications != expectedModifications) {
192                throw new ConcurrentModificationException();
193            }
194            doRedBlackDelete(lastReturnedNode);
195            expectedModifications++;
196            lastReturnedNode = null;
197            if (nextNode == null) {
198                previousNode = greatestNode(rootNode[orderType.ordinal()], orderType);
199            } else {
200                previousNode = nextSmaller(nextNode, orderType);
201            }
202        }
203    }
204
205    enum DataElement {
206        KEY("key"), VALUE("value");
207
208        private final String description;
209
210        /**
211         * Creates a new TreeBidiMap.DataElement.
212         *
213         * @param description  The description for the element
214         */
215        DataElement(final String description) {
216            this.description = description;
217        }
218
219        @Override
220        public String toString() {
221            return description;
222        }
223    }
224
225    /**
226     * A view of this map.
227     */
228    final class EntryView extends AbstractView<Map.Entry<K, V>> {
229
230        EntryView() {
231            super(KEY);
232        }
233
234        @Override
235        public boolean contains(final Object obj) {
236            if (!(obj instanceof Map.Entry)) {
237                return false;
238            }
239            final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
240            final Object value = entry.getValue();
241            final Node<K, V> node = lookupKey(entry.getKey());
242            return node != null && Objects.equals(node.getValue(), value);
243        }
244
245        @Override
246        public Iterator<Map.Entry<K, V>> iterator() {
247            return new ViewMapEntryIterator();
248        }
249
250        @Override
251        public boolean remove(final Object obj) {
252            if (!(obj instanceof Map.Entry)) {
253                return false;
254            }
255            final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
256            final Object value = entry.getValue();
257            final Node<K, V> node = lookupKey(entry.getKey());
258            if (node != null && Objects.equals(node.getValue(), value)) {
259                doRedBlackDelete(node);
260                return true;
261            }
262            return false;
263        }
264    }
265
266    /**
267     * The inverse map implementation.
268     */
269    final class Inverse implements OrderedBidiMap<V, K> {
270
271        /** Store the keySet once created. */
272        private Set<V> inverseKeySet;
273
274        /** Store the valuesSet once created. */
275        private Set<K> inverseValuesSet;
276
277        /** Store the entrySet once created. */
278        private Set<Map.Entry<V, K>> inverseEntrySet;
279
280        @Override
281        public void clear() {
282            TreeBidiMap.this.clear();
283        }
284
285        @Override
286        public boolean containsKey(final Object key) {
287            return TreeBidiMap.this.containsValue(key);
288        }
289
290        @Override
291        public boolean containsValue(final Object value) {
292            return TreeBidiMap.this.containsKey(value);
293        }
294
295        @Override
296        public Set<Map.Entry<V, K>> entrySet() {
297            if (inverseEntrySet == null) {
298                inverseEntrySet = new InverseEntryView();
299            }
300            return inverseEntrySet;
301        }
302
303        @Override
304        public boolean equals(final Object obj) {
305            return TreeBidiMap.this.doEquals(obj, VALUE);
306        }
307
308        @Override
309        public V firstKey() {
310            if (TreeBidiMap.this.nodeCount == 0) {
311                throw new NoSuchElementException("Map is empty");
312            }
313            return leastNode(TreeBidiMap.this.rootNode[VALUE.ordinal()], VALUE).getValue();
314        }
315
316        @Override
317        public K get(final Object key) {
318            return TreeBidiMap.this.getKey(key);
319        }
320
321        @Override
322        public V getKey(final Object value) {
323            return TreeBidiMap.this.get(value);
324        }
325
326        @Override
327        public int hashCode() {
328            return TreeBidiMap.this.doHashCode(VALUE);
329        }
330
331        @Override
332        public OrderedBidiMap<K, V> inverseBidiMap() {
333            return TreeBidiMap.this;
334        }
335
336        @Override
337        public boolean isEmpty() {
338            return TreeBidiMap.this.isEmpty();
339        }
340
341        @Override
342        public Set<V> keySet() {
343            if (inverseKeySet == null) {
344                inverseKeySet = new ValueView(VALUE);
345            }
346            return inverseKeySet;
347        }
348
349        @Override
350        public V lastKey() {
351            if (TreeBidiMap.this.nodeCount == 0) {
352                throw new NoSuchElementException("Map is empty");
353            }
354            return greatestNode(TreeBidiMap.this.rootNode[VALUE.ordinal()], VALUE).getValue();
355        }
356
357        @Override
358        public OrderedMapIterator<V, K> mapIterator() {
359            if (isEmpty()) {
360                return EmptyOrderedMapIterator.<V, K>emptyOrderedMapIterator();
361            }
362            return new InverseViewMapIterator(VALUE);
363        }
364
365        @Override
366        public V nextKey(final V key) {
367            checkKey(key);
368            final Node<K, V> node = nextGreater(TreeBidiMap.this.<V>lookup(key, VALUE), VALUE);
369            return node == null ? null : node.getValue();
370        }
371
372        @Override
373        public V previousKey(final V key) {
374            checkKey(key);
375            final Node<K, V> node = TreeBidiMap.this.nextSmaller(TreeBidiMap.this.<V>lookup(key, VALUE), VALUE);
376            return node == null ? null : node.getValue();
377        }
378
379        @Override
380        public K put(final V key, final K value) {
381            final K result = get(key);
382            TreeBidiMap.this.doPut(value, key);
383            return result;
384        }
385
386        @Override
387        public void putAll(final Map<? extends V, ? extends K> map) {
388            for (final Map.Entry<? extends V, ? extends K> e : map.entrySet()) {
389                put(e.getKey(), e.getValue());
390            }
391        }
392
393        @Override
394        public K remove(final Object key) {
395            return TreeBidiMap.this.removeValue(key);
396        }
397
398        @Override
399        public V removeValue(final Object value) {
400            return TreeBidiMap.this.remove(value);
401        }
402
403        @Override
404        public int size() {
405            return TreeBidiMap.this.size();
406        }
407
408        @Override
409        public String toString() {
410            return TreeBidiMap.this.doToString(VALUE);
411        }
412
413        @Override
414        public Set<K> values() {
415            if (inverseValuesSet == null) {
416                inverseValuesSet = new KeyView(VALUE);
417            }
418            return inverseValuesSet;
419        }
420    }
421
422    /**
423     * A view of this map.
424     */
425    final class InverseEntryView extends AbstractView<Map.Entry<V, K>> {
426
427        InverseEntryView() {
428            super(VALUE);
429        }
430
431        @Override
432        public boolean contains(final Object obj) {
433            if (!(obj instanceof Map.Entry)) {
434                return false;
435            }
436            final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
437            final Object value = entry.getValue();
438            final Node<K, V> node = lookupValue(entry.getKey());
439            return node != null && Objects.equals(node.getKey(), value);
440        }
441
442        @Override
443        public Iterator<Map.Entry<V, K>> iterator() {
444            return new InverseViewMapEntryIterator();
445        }
446
447        @Override
448        public boolean remove(final Object obj) {
449            if (!(obj instanceof Map.Entry)) {
450                return false;
451            }
452            final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
453            final Object value = entry.getValue();
454            final Node<K, V> node = lookupValue(entry.getKey());
455            if (node != null && Objects.equals(node.getKey(), value)) {
456                doRedBlackDelete(node);
457                return true;
458            }
459            return false;
460        }
461    }
462
463    /**
464     * An iterator over the inverse map entries.
465     */
466    final class InverseViewMapEntryIterator extends AbstractViewIterator implements OrderedIterator<Map.Entry<V, K>> {
467
468        /**
469         * Constructs a new instance.
470         */
471        InverseViewMapEntryIterator() {
472            super(VALUE);
473        }
474
475        private Map.Entry<V, K> createEntry(final Node<K, V> node) {
476            return new UnmodifiableMapEntry<>(node.getValue(), node.getKey());
477        }
478
479        @Override
480        public Map.Entry<V, K> next() {
481            return createEntry(navigateNext());
482        }
483
484        @Override
485        public Map.Entry<V, K> previous() {
486            return createEntry(navigatePrevious());
487        }
488    }
489
490    /**
491     * An iterator over the map.
492     */
493    final class InverseViewMapIterator extends AbstractViewIterator implements OrderedMapIterator<V, K> {
494
495        /**
496         * Creates a new TreeBidiMap.InverseViewMapIterator.
497         */
498        InverseViewMapIterator(final DataElement orderType) {
499            super(orderType);
500        }
501
502        @Override
503        public V getKey() {
504            if (lastReturnedNode == null) {
505                throw new IllegalStateException(
506                        "Iterator getKey() can only be called after next() and before remove()");
507            }
508            return lastReturnedNode.getValue();
509        }
510
511        @Override
512        public K getValue() {
513            if (lastReturnedNode == null) {
514                throw new IllegalStateException(
515                        "Iterator getValue() can only be called after next() and before remove()");
516            }
517            return lastReturnedNode.getKey();
518        }
519
520        @Override
521        public V next() {
522            return navigateNext().getValue();
523        }
524
525        @Override
526        public V previous() {
527            return navigatePrevious().getValue();
528        }
529
530        /**
531         * Always throws {@link UnsupportedOperationException}.
532         *
533         * @param value Ignored.
534         * @throws UnsupportedOperationException Always thrown.
535         */
536        @Override
537        public K setValue(final K value) {
538            throw new UnsupportedOperationException();
539        }
540    }
541    final class KeyView extends AbstractView<K> {
542
543        /**
544         * Creates a new TreeBidiMap.KeyView.
545         */
546        KeyView(final DataElement orderType) {
547            super(orderType);
548        }
549
550        @Override
551        public boolean contains(final Object obj) {
552            checkNonNullComparable(obj, KEY);
553            return lookupKey(obj) != null;
554        }
555
556        @Override
557        public Iterator<K> iterator() {
558            return new ViewMapIterator(orderType);
559        }
560
561        @Override
562        public boolean remove(final Object o) {
563            return doRemoveKey(o) != null;
564        }
565
566    }
567
568    /**
569     * A node used to store the data.
570     */
571    static class Node<K extends Comparable<K>, V extends Comparable<V>> implements Map.Entry<K, V>, KeyValue<K, V> {
572
573        private final K key;
574        private final V value;
575        private final Node<K, V>[] leftNode;
576        private final Node<K, V>[] rightNode;
577        private final Node<K, V>[] parentNode;
578        private final boolean[] blackColor;
579        private int hashCodeValue;
580        private boolean calculatedHashCode;
581
582        /**
583         * Makes a new cell with given key and value, and with null
584         * links, and black (true) colors.
585         *
586         * @param key The key of this node
587         * @param value The value of this node
588         */
589        @SuppressWarnings("unchecked")
590        Node(final K key, final V value) {
591            this.key = key;
592            this.value = value;
593            leftNode = new Node[2];
594            rightNode = new Node[2];
595            parentNode = new Node[2];
596            blackColor = new boolean[] { true, true };
597            calculatedHashCode = false;
598        }
599
600        /**
601         * Makes this node the same color as another.
602         *
603         * @param node  The node whose color we're adopting
604         * @param dataElement  either the {@link DataElement#KEY key}
605         *                     or the {@link DataElement#VALUE value}.
606         */
607        private void copyColor(final Node<K, V> node, final DataElement dataElement) {
608            blackColor[dataElement.ordinal()] = node.blackColor[dataElement.ordinal()];
609        }
610
611        /**
612         * Compares the specified object with this entry for equality.
613         * Returns true if the given object is also a map entry and
614         * the two entries represent the same mapping.
615         *
616         * @param obj  The object to be compared for equality with this entry.
617         * @return true if the specified object is equal to this entry.
618         */
619        @Override
620        public boolean equals(final Object obj) {
621            if (obj == this) {
622                return true;
623            }
624            if (!(obj instanceof Map.Entry)) {
625                return false;
626            }
627            final Map.Entry<?, ?> e = (Map.Entry<?, ?>) obj;
628            return Objects.equals(getKey(), e.getKey()) && Objects.equals(getValue(), e.getValue());
629        }
630
631        private Object getData(final DataElement dataElement) {
632            switch (dataElement) {
633            case KEY:
634                return getKey();
635            case VALUE:
636                return getValue();
637            default:
638                throw new IllegalArgumentException();
639            }
640        }
641
642        /**
643         * Gets the key.
644         *
645         * @return The key corresponding to this entry.
646         */
647        @Override
648        public K getKey() {
649            return key;
650        }
651
652        private Node<K, V> getLeft(final DataElement dataElement) {
653            return leftNode[dataElement.ordinal()];
654        }
655
656        /**
657         * Gets the parent node.
658         *
659         * @param dataElement  either the {@link DataElement#KEY key}
660         *                     or the {@link DataElement#VALUE value}.
661         * @return The parent node, may be null
662         */
663        private Node<K, V> getParent(final DataElement dataElement) {
664            return parentNode[dataElement.ordinal()];
665        }
666
667        private Node<K, V> getRight(final DataElement dataElement) {
668            return rightNode[dataElement.ordinal()];
669        }
670
671        /**
672         * Gets the value.
673         *
674         * @return The value corresponding to this entry.
675         */
676        @Override
677        public V getValue() {
678            return value;
679        }
680
681        /**
682         * @return The hash code value for this map entry.
683         */
684        @Override
685        public int hashCode() {
686            if (!calculatedHashCode) {
687                hashCodeValue = getKey().hashCode() ^ getValue().hashCode();
688                calculatedHashCode = true;
689            }
690            return hashCodeValue;
691        }
692
693        /**
694         * Is this node black?
695         *
696         * @param dataElement  either the {@link DataElement#KEY key}
697         *                     or the {@link DataElement#VALUE value}.
698         * @return true if black (which is represented as a true boolean)
699         */
700        private boolean isBlack(final DataElement dataElement) {
701            return blackColor[dataElement.ordinal()];
702        }
703
704        private boolean isLeftChild(final DataElement dataElement) {
705            return parentNode[dataElement.ordinal()] != null
706                    && parentNode[dataElement.ordinal()].leftNode[dataElement.ordinal()] == this;
707        }
708
709        /**
710         * Is this node red?
711         *
712         * @param dataElement  either the {@link DataElement#KEY key}
713         *                     or the {@link DataElement#VALUE value}.
714         * @return true if non-black
715         */
716        private boolean isRed(final DataElement dataElement) {
717            return !blackColor[dataElement.ordinal()];
718        }
719
720        private boolean isRightChild(final DataElement dataElement) {
721            return parentNode[dataElement.ordinal()] != null
722                    && parentNode[dataElement.ordinal()].rightNode[dataElement.ordinal()] == this;
723        }
724
725        /**
726         * Makes this node black.
727         *
728         * @param dataElement  either the {@link DataElement#KEY key}
729         *                     or the {@link DataElement#VALUE value}.
730         */
731        private void setBlack(final DataElement dataElement) {
732            blackColor[dataElement.ordinal()] = true;
733        }
734
735        private void setLeft(final Node<K, V> node, final DataElement dataElement) {
736            leftNode[dataElement.ordinal()] = node;
737        }
738
739        /**
740         * Sets this node's parent node.
741         *
742         * @param node  The new parent node
743         * @param dataElement  either the {@link DataElement#KEY key}
744         *                     or the {@link DataElement#VALUE value}.
745         */
746        private void setParent(final Node<K, V> node, final DataElement dataElement) {
747            parentNode[dataElement.ordinal()] = node;
748        }
749
750        /**
751         * Makes this node red.
752         *
753         * @param dataElement  either the {@link DataElement#KEY key}
754         *                     or the {@link DataElement#VALUE value}.
755         */
756        private void setRed(final DataElement dataElement) {
757            blackColor[dataElement.ordinal()] = false;
758        }
759
760        private void setRight(final Node<K, V> node, final DataElement dataElement) {
761            rightNode[dataElement.ordinal()] = node;
762        }
763
764        /**
765         * Optional operation that is not permitted in this implementation.
766         *
767         * @param ignored this parameter is ignored.
768         * @return does not return
769         * @throws UnsupportedOperationException always
770         */
771        @Override
772        public V setValue(final V ignored) throws UnsupportedOperationException {
773            throw new UnsupportedOperationException("Map.Entry.setValue is not supported");
774        }
775
776        /**
777         * Exchanges colors with another node.
778         *
779         * @param node  The node to swap with
780         * @param dataElement  either the {@link DataElement#KEY key}
781         *                     or the {@link DataElement#VALUE value}.
782         */
783        private void swapColors(final Node<K, V> node, final DataElement dataElement) {
784            // Swap colors -- old hacker's trick
785            blackColor[dataElement.ordinal()]      ^= node.blackColor[dataElement.ordinal()];
786            node.blackColor[dataElement.ordinal()] ^= blackColor[dataElement.ordinal()];
787            blackColor[dataElement.ordinal()]      ^= node.blackColor[dataElement.ordinal()];
788        }
789    }
790
791    final class ValueView extends AbstractView<V> {
792
793        /**
794         * Creates a new TreeBidiMap.ValueView.
795         */
796        ValueView(final DataElement orderType) {
797            super(orderType);
798        }
799
800        @Override
801        public boolean contains(final Object obj) {
802            checkNonNullComparable(obj, VALUE);
803            return lookupValue(obj) != null;
804        }
805
806        @Override
807        public Iterator<V> iterator() {
808            return new InverseViewMapIterator(orderType);
809        }
810
811        @Override
812        public boolean remove(final Object o) {
813            return doRemoveValue(o) != null;
814        }
815
816    }
817
818    /**
819     * An iterator over the map entries.
820     */
821    final class ViewMapEntryIterator extends AbstractViewIterator implements OrderedIterator<Map.Entry<K, V>> {
822
823        /**
824         * Constructs a new instance.
825         */
826        ViewMapEntryIterator() {
827            super(KEY);
828        }
829
830        @Override
831        public Map.Entry<K, V> next() {
832            return navigateNext();
833        }
834
835        @Override
836        public Map.Entry<K, V> previous() {
837            return navigatePrevious();
838        }
839    }
840
841    /**
842     * An iterator over the map.
843     */
844    final class ViewMapIterator extends AbstractViewIterator implements OrderedMapIterator<K, V> {
845
846        /**
847         * Constructs a new instance.
848         */
849        ViewMapIterator(final DataElement orderType) {
850            super(orderType);
851        }
852
853        @Override
854        public K getKey() {
855            if (lastReturnedNode == null) {
856                throw new IllegalStateException(
857                        "Iterator getKey() can only be called after next() and before remove()");
858            }
859            return lastReturnedNode.getKey();
860        }
861
862        @Override
863        public V getValue() {
864            if (lastReturnedNode == null) {
865                throw new IllegalStateException(
866                        "Iterator getValue() can only be called after next() and before remove()");
867            }
868            return lastReturnedNode.getValue();
869        }
870
871        @Override
872        public K next() {
873            return navigateNext().getKey();
874        }
875
876        @Override
877        public K previous() {
878            return navigatePrevious().getKey();
879        }
880
881        /**
882         * Always throws {@link UnsupportedOperationException}.
883         *
884         * @param value Ignored.
885         * @throws UnsupportedOperationException Always thrown.
886         */
887        @Override
888        public V setValue(final V value) {
889            throw new UnsupportedOperationException();
890        }
891    }
892
893    private static final long serialVersionUID = 721969328361807L;
894
895    /**
896     * Checks a key for validity (non-null and implements Comparable)
897     *
898     * @param key The key to be checked
899     * @throws NullPointerException if key is null
900     * @throws ClassCastException if key is not Comparable
901     */
902    private static void checkKey(final Object key) {
903        checkNonNullComparable(key, KEY);
904    }
905
906    /**
907     * Checks a key and a value for validity (non-null and implements
908     * Comparable)
909     *
910     * @param key The key to be checked
911     * @param value The value to be checked
912     * @throws NullPointerException if key or value is null
913     * @throws ClassCastException if key or value is not Comparable
914     */
915    private static void checkKeyAndValue(final Object key, final Object value) {
916        checkKey(key);
917        checkValue(value);
918    }
919
920    /**
921     * Checks if an object is fit to be proper input ... has to be
922     * Comparable and non-null.
923     *
924     * @param obj The object being checked
925     * @param dataElement  either the {@link DataElement#KEY key}
926     *                     or the {@link DataElement#VALUE value}.
927     *
928     * @throws NullPointerException if o is null
929     * @throws ClassCastException if o is not Comparable
930     */
931    private static void checkNonNullComparable(final Object obj, final DataElement dataElement) {
932        Objects.requireNonNull(obj, Objects.toString(dataElement));
933        if (!(obj instanceof Comparable)) {
934            throw new ClassCastException(dataElement + " must be Comparable");
935        }
936    }
937
938    /**
939     * Checks a value for validity (non-null and implements Comparable)
940     *
941     * @param value The value to be checked
942     * @throws NullPointerException if value is null
943     * @throws ClassCastException if value is not Comparable
944     */
945    private static void checkValue(final Object value) {
946        checkNonNullComparable(value, VALUE);
947    }
948
949    /**
950     * Compares two objects.
951     *
952     * @param o1  The first object
953     * @param o2  The second object
954     * @return negative value if o1 &lt; o2; 0 if o1 == o2; positive
955     *         value if o1 &gt; o2
956     */
957    private static <T extends Comparable<T>> int compare(final T o1, final T o2) {
958        return o1.compareTo(o2);
959    }
960
961    /**
962     * Is the specified black red? If the node does not exist, sure,
963     * it's black, thank you.
964     *
965     * @param node The node (may be null) in question
966     * @param dataElement  either the {@link DataElement#KEY key}
967     *                     or the {@link DataElement#VALUE value}.
968     */
969    private static boolean isBlack(final Node<?, ?> node, final DataElement dataElement) {
970        return node == null || node.isBlack(dataElement);
971    }
972
973    /**
974     * Is the specified node red? If the node does not exist, no, it's
975     * black, thank you.
976     *
977     * @param node The node (may be null) in question
978     * @param dataElement  either the {@link DataElement#KEY key}
979     *                     or the {@link DataElement#VALUE value}.
980     */
981    private static boolean isRed(final Node<?, ?> node, final DataElement dataElement) {
982        return node != null && node.isRed(dataElement);
983    }
984
985    /**
986     * Forces a node (if it exists) black.
987     *
988     * @param node The node (may be null) in question
989     * @param dataElement  either the {@link DataElement#KEY key}
990     *                     or the {@link DataElement#VALUE value}.
991     */
992    private static void makeBlack(final Node<?, ?> node, final DataElement dataElement) {
993        if (node != null) {
994            node.setBlack(dataElement);
995        }
996    }
997
998    /**
999     * Forces a node (if it exists) red.
1000     *
1001     * @param node The node (may be null) in question
1002     * @param dataElement  either the {@link DataElement#KEY key}
1003     *                     or the {@link DataElement#VALUE value}.
1004     */
1005    private static void makeRed(final Node<?, ?> node, final DataElement dataElement) {
1006        if (node != null) {
1007            node.setRed(dataElement);
1008        }
1009    }
1010
1011    private transient Node<K, V>[] rootNode;
1012
1013    private transient int nodeCount;
1014
1015    private transient int modifications;
1016
1017    private transient Set<K> keySet;
1018
1019    private transient Set<V> valuesSet;
1020
1021    private transient Set<Map.Entry<K, V>> entrySet;
1022
1023    private transient Inverse inverse;
1024
1025    /**
1026     * Constructs a new empty TreeBidiMap.
1027     */
1028    @SuppressWarnings("unchecked")
1029    public TreeBidiMap() {
1030        rootNode = new Node[2];
1031    }
1032
1033    /**
1034     * Constructs a new TreeBidiMap by copying an existing Map.
1035     *
1036     * @param map  The map to copy
1037     * @throws ClassCastException if the keys/values in the map are
1038     *  not Comparable or are not mutually comparable
1039     * @throws NullPointerException if any key or value in the map is null
1040     */
1041    public TreeBidiMap(final Map<? extends K, ? extends V> map) {
1042        this();
1043        putAll(map);
1044    }
1045
1046    /**
1047     * Removes all mappings from this map.
1048     */
1049    @Override
1050    public void clear() {
1051        modify();
1052
1053        nodeCount = 0;
1054        rootNode[KEY.ordinal()] = null;
1055        rootNode[VALUE.ordinal()] = null;
1056    }
1057
1058    /**
1059     * Checks whether this map contains a mapping for the specified key.
1060     * <p>
1061     * The key must implement {@code Comparable}.
1062     *
1063     * @param key  key whose presence in this map is to be tested
1064     * @return true if this map contains a mapping for the specified key
1065     * @throws ClassCastException if the key is of an inappropriate type
1066     * @throws NullPointerException if the key is null
1067     */
1068    @Override
1069    public boolean containsKey(final Object key) {
1070        checkKey(key);
1071        return lookupKey(key) != null;
1072    }
1073
1074    /**
1075     * Checks whether this map contains a mapping for the specified value.
1076     * <p>
1077     * The value must implement {@code Comparable}.
1078     *
1079     * @param value  value whose presence in this map is to be tested
1080     * @return true if this map contains a mapping for the specified value
1081     * @throws ClassCastException if the value is of an inappropriate type
1082     * @throws NullPointerException if the value is null
1083     */
1084    @Override
1085    public boolean containsValue(final Object value) {
1086        checkValue(value);
1087        return lookupValue(value) != null;
1088    }
1089
1090    /**
1091     * Copies the color from one node to another, dealing with the fact
1092     * that one or both nodes may, in fact, be null.
1093     *
1094     * @param from The node whose color we're copying; may be null
1095     * @param to The node whose color we're changing; may be null
1096     * @param dataElement  either the {@link DataElement#KEY key}
1097     *                     or the {@link DataElement#VALUE value}.
1098     */
1099    private void copyColor(final Node<K, V> from, final Node<K, V> to, final DataElement dataElement) {
1100        if (to != null) {
1101            if (from == null) {
1102                // by default, make it black
1103                to.setBlack(dataElement);
1104            } else {
1105                to.copyColor(from, dataElement);
1106            }
1107        }
1108    }
1109
1110    /**
1111     * Compares for equals as per the API.
1112     *
1113     * @param obj  The object to compare to
1114     * @param dataElement  either the {@link DataElement#KEY key}
1115     *                     or the {@link DataElement#VALUE value}.
1116     * @return true if equal
1117     */
1118    private boolean doEquals(final Object obj, final DataElement dataElement) {
1119        if (obj == this) {
1120            return true;
1121        }
1122        if (!(obj instanceof Map)) {
1123            return false;
1124        }
1125        final Map<?, ?> other = (Map<?, ?>) obj;
1126        if (other.size() != size()) {
1127            return false;
1128        }
1129
1130        if (nodeCount > 0) {
1131            try {
1132                for (final MapIterator<?, ?> it = getMapIterator(dataElement); it.hasNext(); ) {
1133                    final Object key = it.next();
1134                    final Object value = it.getValue();
1135                    if (!value.equals(other.get(key))) {
1136                        return false;
1137                    }
1138                }
1139            } catch (final ClassCastException | NullPointerException ex) {
1140                return false;
1141            }
1142        }
1143        return true;
1144    }
1145
1146    /**
1147     * Gets the hash code value for this map as per the API.
1148     *
1149     * @param dataElement  either the {@link DataElement#KEY key}
1150     *                     or the {@link DataElement#VALUE value}.
1151     * @return The hash code value for this map
1152     */
1153    private int doHashCode(final DataElement dataElement) {
1154        int total = 0;
1155        if (nodeCount > 0) {
1156            for (final MapIterator<?, ?> it = getMapIterator(dataElement); it.hasNext(); ) {
1157                final Object key = it.next();
1158                final Object value = it.getValue();
1159                total += key.hashCode() ^ value.hashCode();
1160            }
1161        }
1162        return total;
1163    }
1164
1165    /**
1166     * Puts logic.
1167     *
1168     * @param key  The key, always the main map key
1169     * @param value  The value, always the main map value
1170     */
1171    private void doPut(final K key, final V value) {
1172        checkKeyAndValue(key, value);
1173
1174        // store previous and remove previous mappings
1175        doRemoveKey(key);
1176        doRemoveValue(value);
1177
1178        Node<K, V> node = rootNode[KEY.ordinal()];
1179        if (node == null) {
1180            // map is empty
1181            final Node<K, V> root = new Node<>(key, value);
1182            rootNode[KEY.ordinal()] = root;
1183            rootNode[VALUE.ordinal()] = root;
1184            grow();
1185
1186        } else {
1187            // add new mapping
1188            while (true) {
1189                final int cmp = compare(key, node.getKey());
1190
1191                if (cmp == 0) {
1192                    // shouldn't happen
1193                    throw new IllegalArgumentException("Cannot store a duplicate key (\"" + key + "\") in this Map");
1194                }
1195                if (cmp < 0) {
1196                    if (node.getLeft(KEY) == null) {
1197                        final Node<K, V> newNode = new Node<>(key, value);
1198
1199                        insertValue(newNode);
1200                        node.setLeft(newNode, KEY);
1201                        newNode.setParent(node, KEY);
1202                        doRedBlackInsert(newNode, KEY);
1203                        grow();
1204
1205                        break;
1206                    }
1207                    node = node.getLeft(KEY);
1208                } else { // cmp > 0
1209                    if (node.getRight(KEY) == null) {
1210                        final Node<K, V> newNode = new Node<>(key, value);
1211
1212                        insertValue(newNode);
1213                        node.setRight(newNode, KEY);
1214                        newNode.setParent(node, KEY);
1215                        doRedBlackInsert(newNode, KEY);
1216                        grow();
1217
1218                        break;
1219                    }
1220                    node = node.getRight(KEY);
1221                }
1222            }
1223        }
1224    }
1225
1226    /**
1227     * Complicated red-black delete stuff. Based on Sun's TreeMap
1228     * implementation, though it's barely recognizable anymore.
1229     *
1230     * @param deletedNode The node to be deleted
1231     */
1232    private void doRedBlackDelete(final Node<K, V> deletedNode) {
1233        for (final DataElement dataElement : DataElement.values()) {
1234            // if deleted node has both left and children, swap with
1235            // the next greater node
1236            if (deletedNode.getLeft(dataElement) != null && deletedNode.getRight(dataElement) != null) {
1237                swapPosition(nextGreater(deletedNode, dataElement), deletedNode, dataElement);
1238            }
1239            final Node<K, V> replacement = deletedNode.getLeft(dataElement) != null ? deletedNode.getLeft(dataElement) : deletedNode.getRight(dataElement);
1240            if (replacement != null) {
1241                replacement.setParent(deletedNode.getParent(dataElement), dataElement);
1242                if (deletedNode.getParent(dataElement) == null) {
1243                    rootNode[dataElement.ordinal()] = replacement;
1244                } else if (deletedNode == deletedNode.getParent(dataElement).getLeft(dataElement)) {
1245                    deletedNode.getParent(dataElement).setLeft(replacement, dataElement);
1246                } else {
1247                    deletedNode.getParent(dataElement).setRight(replacement, dataElement);
1248                }
1249                deletedNode.setLeft(null, dataElement);
1250                deletedNode.setRight(null, dataElement);
1251                deletedNode.setParent(null, dataElement);
1252                if (isBlack(deletedNode, dataElement)) {
1253                    doRedBlackDeleteFixup(replacement, dataElement);
1254                }
1255            } else if (deletedNode.getParent(dataElement) == null) {
1256                // replacement is null
1257                // empty tree
1258                rootNode[dataElement.ordinal()] = null;
1259            } else {
1260                // deleted node had no children
1261                if (isBlack(deletedNode, dataElement)) {
1262                    doRedBlackDeleteFixup(deletedNode, dataElement);
1263                }
1264                if (deletedNode.getParent(dataElement) != null) {
1265                    if (deletedNode == deletedNode.getParent(dataElement).getLeft(dataElement)) {
1266                        deletedNode.getParent(dataElement).setLeft(null, dataElement);
1267                    } else {
1268                        deletedNode.getParent(dataElement).setRight(null, dataElement);
1269                    }
1270                    deletedNode.setParent(null, dataElement);
1271                }
1272            }
1273        }
1274        shrink();
1275    }
1276
1277    /**
1278     * Complicated red-black delete stuff. Based on Sun's TreeMap
1279     * implementation, though it's barely recognizable anymore. This
1280     * rebalances the tree (somewhat, as red-black trees are not
1281     * perfectly balanced -- perfect balancing takes longer)
1282     *
1283     * @param replacementNode The node being replaced
1284     * @param dataElement  The KEY or VALUE int
1285     */
1286    private void doRedBlackDeleteFixup(final Node<K, V> replacementNode, final DataElement dataElement) {
1287        Node<K, V> currentNode = replacementNode;
1288
1289        while (currentNode != rootNode[dataElement.ordinal()] && isBlack(currentNode, dataElement)) {
1290            if (currentNode.isLeftChild(dataElement)) {
1291                Node<K, V> siblingNode = getRightChild(getParent(currentNode, dataElement), dataElement);
1292
1293                if (isRed(siblingNode, dataElement)) {
1294                    makeBlack(siblingNode, dataElement);
1295                    makeRed(getParent(currentNode, dataElement), dataElement);
1296                    rotateLeft(getParent(currentNode, dataElement), dataElement);
1297
1298                    siblingNode = getRightChild(getParent(currentNode, dataElement), dataElement);
1299                }
1300
1301                if (isBlack(getLeftChild(siblingNode, dataElement), dataElement)
1302                    && isBlack(getRightChild(siblingNode, dataElement), dataElement)) {
1303                    makeRed(siblingNode, dataElement);
1304
1305                    currentNode = getParent(currentNode, dataElement);
1306                } else {
1307                    if (isBlack(getRightChild(siblingNode, dataElement), dataElement)) {
1308                        makeBlack(getLeftChild(siblingNode, dataElement), dataElement);
1309                        makeRed(siblingNode, dataElement);
1310                        rotateRight(siblingNode, dataElement);
1311
1312                        siblingNode = getRightChild(getParent(currentNode, dataElement), dataElement);
1313                    }
1314
1315                    copyColor(getParent(currentNode, dataElement), siblingNode, dataElement);
1316                    makeBlack(getParent(currentNode, dataElement), dataElement);
1317                    makeBlack(getRightChild(siblingNode, dataElement), dataElement);
1318                    rotateLeft(getParent(currentNode, dataElement), dataElement);
1319
1320                    currentNode = rootNode[dataElement.ordinal()];
1321                }
1322            } else {
1323                Node<K, V> siblingNode = getLeftChild(getParent(currentNode, dataElement), dataElement);
1324
1325                if (isRed(siblingNode, dataElement)) {
1326                    makeBlack(siblingNode, dataElement);
1327                    makeRed(getParent(currentNode, dataElement), dataElement);
1328                    rotateRight(getParent(currentNode, dataElement), dataElement);
1329
1330                    siblingNode = getLeftChild(getParent(currentNode, dataElement), dataElement);
1331                }
1332
1333                if (isBlack(getRightChild(siblingNode, dataElement), dataElement)
1334                    && isBlack(getLeftChild(siblingNode, dataElement), dataElement)) {
1335                    makeRed(siblingNode, dataElement);
1336
1337                    currentNode = getParent(currentNode, dataElement);
1338                } else {
1339                    if (isBlack(getLeftChild(siblingNode, dataElement), dataElement)) {
1340                        makeBlack(getRightChild(siblingNode, dataElement), dataElement);
1341                        makeRed(siblingNode, dataElement);
1342                        rotateLeft(siblingNode, dataElement);
1343
1344                        siblingNode = getLeftChild(getParent(currentNode, dataElement), dataElement);
1345                    }
1346
1347                    copyColor(getParent(currentNode, dataElement), siblingNode, dataElement);
1348                    makeBlack(getParent(currentNode, dataElement), dataElement);
1349                    makeBlack(getLeftChild(siblingNode, dataElement), dataElement);
1350                    rotateRight(getParent(currentNode, dataElement), dataElement);
1351
1352                    currentNode = rootNode[dataElement.ordinal()];
1353                }
1354            }
1355        }
1356
1357        makeBlack(currentNode, dataElement);
1358    }
1359
1360    /**
1361     * Complicated red-black insert stuff. Based on Sun's TreeMap
1362     * implementation, though it's barely recognizable anymore.
1363     *
1364     * @param insertedNode The node to be inserted
1365     * @param dataElement  The KEY or VALUE int
1366     */
1367    private void doRedBlackInsert(final Node<K, V> insertedNode, final DataElement dataElement) {
1368        Node<K, V> currentNode = insertedNode;
1369        makeRed(currentNode, dataElement);
1370
1371        while (currentNode != null
1372            && currentNode != rootNode[dataElement.ordinal()]
1373            && isRed(currentNode.getParent(dataElement), dataElement)) {
1374            if (currentNode.isLeftChild(dataElement)) {
1375                final Node<K, V> y = getRightChild(getGrandParent(currentNode, dataElement), dataElement);
1376
1377                if (isRed(y, dataElement)) {
1378                    makeBlack(getParent(currentNode, dataElement), dataElement);
1379                    makeBlack(y, dataElement);
1380                    makeRed(getGrandParent(currentNode, dataElement), dataElement);
1381
1382                    currentNode = getGrandParent(currentNode, dataElement);
1383                } else {
1384                    //dead code?
1385                    if (currentNode.isRightChild(dataElement)) {
1386                        currentNode = getParent(currentNode, dataElement);
1387
1388                        rotateLeft(currentNode, dataElement);
1389                    }
1390
1391                    makeBlack(getParent(currentNode, dataElement), dataElement);
1392                    makeRed(getGrandParent(currentNode, dataElement), dataElement);
1393
1394                    if (getGrandParent(currentNode, dataElement) != null) {
1395                        rotateRight(getGrandParent(currentNode, dataElement), dataElement);
1396                    }
1397                }
1398            } else {
1399
1400                // just like clause above, except swap left for right
1401                final Node<K, V> y = getLeftChild(getGrandParent(currentNode, dataElement), dataElement);
1402
1403                if (isRed(y, dataElement)) {
1404                    makeBlack(getParent(currentNode, dataElement), dataElement);
1405                    makeBlack(y, dataElement);
1406                    makeRed(getGrandParent(currentNode, dataElement), dataElement);
1407
1408                    currentNode = getGrandParent(currentNode, dataElement);
1409                } else {
1410                    //dead code?
1411                    if (currentNode.isLeftChild(dataElement)) {
1412                        currentNode = getParent(currentNode, dataElement);
1413
1414                        rotateRight(currentNode, dataElement);
1415                    }
1416
1417                    makeBlack(getParent(currentNode, dataElement), dataElement);
1418                    makeRed(getGrandParent(currentNode, dataElement), dataElement);
1419
1420                    if (getGrandParent(currentNode, dataElement) != null) {
1421                        rotateLeft(getGrandParent(currentNode, dataElement), dataElement);
1422                    }
1423                }
1424            }
1425        }
1426
1427        makeBlack(rootNode[dataElement.ordinal()], dataElement);
1428    }
1429
1430    private V doRemoveKey(final Object key) {
1431        final Node<K, V> node = lookupKey(key);
1432        if (node == null) {
1433            return null;
1434        }
1435        doRedBlackDelete(node);
1436        return node.getValue();
1437    }
1438
1439    private K doRemoveValue(final Object value) {
1440        final Node<K, V> node = lookupValue(value);
1441        if (node == null) {
1442            return null;
1443        }
1444        doRedBlackDelete(node);
1445        return node.getKey();
1446    }
1447
1448    /**
1449     * Gets the string form of this map as per AbstractMap.
1450     *
1451     * @param dataElement  either the {@link DataElement#KEY key}
1452     *                     or the {@link DataElement#VALUE value}.
1453     * @return The string form of this map
1454     */
1455    private String doToString(final DataElement dataElement) {
1456        if (nodeCount == 0) {
1457            return "{}";
1458        }
1459        final StringBuilder buf = new StringBuilder(nodeCount * 32);
1460        buf.append('{');
1461        final MapIterator<?, ?> it = getMapIterator(dataElement);
1462        boolean hasNext = it.hasNext();
1463        while (hasNext) {
1464            final Object key = it.next();
1465            final Object value = it.getValue();
1466            buf.append(key == this ? "(this Map)" : key)
1467                .append('=')
1468                .append(value == this ? "(this Map)" : value);
1469
1470            hasNext = it.hasNext();
1471            if (hasNext) {
1472                buf.append(", ");
1473            }
1474        }
1475
1476        buf.append('}');
1477        return buf.toString();
1478    }
1479
1480    /**
1481     * Returns a set view of the entries contained in this map in key order.
1482     * For simple iteration through the map, the MapIterator is quicker.
1483     * <p>
1484     * The set is backed by the map, so changes to the map are reflected in
1485     * the set, and vice-versa. If the map is modified while an iteration over
1486     * the set is in progress, the results of the iteration are undefined.
1487     * <p>
1488     * The set supports element removal, which removes the corresponding mapping
1489     * from the map. It does not support the add or addAll operations.
1490     * The returned MapEntry objects do not support setValue.
1491     *
1492     * @return A set view of the values contained in this map.
1493     */
1494    @Override
1495    public Set<Map.Entry<K, V>> entrySet() {
1496        if (entrySet == null) {
1497            entrySet = new EntryView();
1498        }
1499        return entrySet;
1500    }
1501
1502    /**
1503     * Compares for equals as per the API.
1504     *
1505     * @param obj  The object to compare to
1506     * @return true if equal
1507     */
1508    @Override
1509    public boolean equals(final Object obj) {
1510        return this.doEquals(obj, KEY);
1511    }
1512
1513    /**
1514     * Gets the first (lowest) key currently in this map.
1515     *
1516     * @return The first (lowest) key currently in this sorted map
1517     * @throws NoSuchElementException if this map is empty
1518     */
1519    @Override
1520    public K firstKey() {
1521        if (nodeCount == 0) {
1522            throw new NoSuchElementException("Map is empty");
1523        }
1524        return leastNode(rootNode[KEY.ordinal()], KEY).getKey();
1525    }
1526
1527    /**
1528     * Gets the value to which this map maps the specified key.
1529     * Returns null if the map contains no mapping for this key.
1530     * <p>
1531     * The key must implement {@code Comparable}.
1532     *
1533     * @param key  key whose associated value is to be returned
1534     * @return The value to which this map maps the specified key,
1535     *  or null if the map contains no mapping for this key
1536     * @throws ClassCastException if the key is of an inappropriate type
1537     * @throws NullPointerException if the key is null
1538     */
1539    @Override
1540    public V get(final Object key) {
1541        checkKey(key);
1542        final Node<K, V> node = lookupKey(key);
1543        return node == null ? null : node.getValue();
1544    }
1545
1546    /**
1547     * Gets a node's grandparent. mind you, the node, its parent, or
1548     * its grandparent may not exist. No problem.
1549     *
1550     * @param node The node (may be null) in question
1551     * @param dataElement  either the {@link DataElement#KEY key}
1552     *                     or the {@link DataElement#VALUE value}.
1553     */
1554    private Node<K, V> getGrandParent(final Node<K, V> node, final DataElement dataElement) {
1555        return getParent(getParent(node, dataElement), dataElement);
1556    }
1557
1558    /**
1559     * Gets the key to which this map maps the specified value.
1560     * Returns null if the map contains no mapping for this value.
1561     * <p>
1562     * The value must implement {@code Comparable}.
1563     *
1564     * @param value  value whose associated key is to be returned.
1565     * @return The key to which this map maps the specified value,
1566     *  or null if the map contains no mapping for this value.
1567     * @throws ClassCastException if the value is of an inappropriate type
1568     * @throws NullPointerException if the value is null
1569     */
1570    @Override
1571    public K getKey(final Object value) {
1572        checkValue(value);
1573        final Node<K, V> node = lookupValue(value);
1574        return node == null ? null : node.getKey();
1575    }
1576
1577    /**
1578     * Gets a node's left child. mind you, the node may not exist. no
1579     * problem.
1580     *
1581     * @param node The node (may be null) in question
1582     * @param dataElement  either the {@link DataElement#KEY key}
1583     *                     or the {@link DataElement#VALUE value}.
1584     */
1585    private Node<K, V> getLeftChild(final Node<K, V> node, final DataElement dataElement) {
1586        return node == null ? null : node.getLeft(dataElement);
1587    }
1588
1589    private MapIterator<?, ?> getMapIterator(final DataElement dataElement) {
1590        switch (dataElement) {
1591        case KEY:
1592            return new ViewMapIterator(KEY);
1593        case VALUE:
1594            return new InverseViewMapIterator(VALUE);
1595        default:
1596            throw new IllegalArgumentException();
1597        }
1598    }
1599
1600    /**
1601     * Gets a node's parent. mind you, the node, or its parent, may not
1602     * exist. no problem.
1603     *
1604     * @param node The node (may be null) in question
1605     * @param dataElement  either the {@link DataElement#KEY key}
1606     *                     or the {@link DataElement#VALUE value}.
1607     */
1608    private Node<K, V> getParent(final Node<K, V> node, final DataElement dataElement) {
1609        return node == null ? null : node.getParent(dataElement);
1610    }
1611
1612    /**
1613     * Gets a node's right child. mind you, the node may not exist. no
1614     * problem.
1615     *
1616     * @param node The node (may be null) in question
1617     * @param dataElement  either the {@link DataElement#KEY key}
1618     *                     or the {@link DataElement#VALUE value}.
1619     */
1620    private Node<K, V> getRightChild(final Node<K, V> node, final DataElement dataElement) {
1621        return node == null ? null : node.getRight(dataElement);
1622    }
1623
1624    /**
1625     * Finds the greatest node from a given node.
1626     *
1627     * @param node  The node from which we will start searching
1628     * @param dataElement  either the {@link DataElement#KEY key}
1629     *                     or the {@link DataElement#VALUE value}.
1630     * @return The greatest node, from the specified node
1631     */
1632    private Node<K, V> greatestNode(final Node<K, V> node, final DataElement dataElement) {
1633        Node<K, V> rval = node;
1634        if (rval != null) {
1635            while (rval.getRight(dataElement) != null) {
1636                rval = rval.getRight(dataElement);
1637            }
1638        }
1639        return rval;
1640    }
1641
1642    /**
1643     * Bumps up the size and note that the map has changed.
1644     */
1645    private void grow() {
1646        modify();
1647        nodeCount++;
1648    }
1649
1650    /**
1651     * Gets the hash code value for this map as per the API.
1652     *
1653     * @return The hash code value for this map
1654     */
1655    @Override
1656    public int hashCode() {
1657        return this.doHashCode(KEY);
1658    }
1659
1660    /**
1661     * Inserts a node by its value.
1662     *
1663     * @param newNode The node to be inserted
1664     * @throws IllegalArgumentException if the node already exists
1665     *                                     in the value mapping
1666     */
1667    private void insertValue(final Node<K, V> newNode) throws IllegalArgumentException {
1668        Node<K, V> node = rootNode[VALUE.ordinal()];
1669
1670        while (true) {
1671            final int cmp = compare(newNode.getValue(), node.getValue());
1672
1673            if (cmp == 0) {
1674                throw new IllegalArgumentException(
1675                    "Cannot store a duplicate value (\"" + newNode.getData(VALUE) + "\") in this Map");
1676            }
1677            if (cmp < 0) {
1678                if (node.getLeft(VALUE) == null) {
1679                    node.setLeft(newNode, VALUE);
1680                    newNode.setParent(node, VALUE);
1681                    doRedBlackInsert(newNode, VALUE);
1682
1683                    break;
1684                }
1685                node = node.getLeft(VALUE);
1686            } else { // cmp > 0
1687                if (node.getRight(VALUE) == null) {
1688                    node.setRight(newNode, VALUE);
1689                    newNode.setParent(node, VALUE);
1690                    doRedBlackInsert(newNode, VALUE);
1691
1692                    break;
1693                }
1694                node = node.getRight(VALUE);
1695            }
1696        }
1697    }
1698
1699    /**
1700     * Gets the inverse map for comparison.
1701     *
1702     * @return The inverse map
1703     */
1704    @Override
1705    public OrderedBidiMap<V, K> inverseBidiMap() {
1706        if (inverse == null) {
1707            inverse = new Inverse();
1708        }
1709        return inverse;
1710    }
1711
1712    /**
1713     * Checks whether the map is empty or not.
1714     *
1715     * @return true if the map is empty
1716     */
1717    @Override
1718    public boolean isEmpty() {
1719        return nodeCount == 0;
1720    }
1721
1722    /**
1723     * Returns a set view of the keys contained in this map in key order.
1724     * <p>
1725     * The set is backed by the map, so changes to the map are reflected in
1726     * the set, and vice-versa. If the map is modified while an iteration over
1727     * the set is in progress, the results of the iteration are undefined.
1728     * <p>
1729     * The set supports element removal, which removes the corresponding mapping
1730     * from the map. It does not support the add or addAll operations.
1731     *
1732     * @return A set view of the keys contained in this map.
1733     */
1734    @Override
1735    public Set<K> keySet() {
1736        if (keySet == null) {
1737            keySet = new KeyView(KEY);
1738        }
1739        return keySet;
1740    }
1741
1742    /**
1743     * Gets the last (highest) key currently in this map.
1744     *
1745     * @return The last (highest) key currently in this sorted map
1746     * @throws NoSuchElementException if this map is empty
1747     */
1748    @Override
1749    public K lastKey() {
1750        if (nodeCount == 0) {
1751            throw new NoSuchElementException("Map is empty");
1752        }
1753        return greatestNode(rootNode[KEY.ordinal()], KEY).getKey();
1754    }
1755
1756    /**
1757     * Finds the least node from a given node.
1758     *
1759     * @param node  The node from which we will start searching
1760     * @param dataElement  either the {@link DataElement#KEY key}
1761     *                     or the {@link DataElement#VALUE value}.
1762     * @return The smallest node, from the specified node, in the
1763     *         specified mapping
1764     */
1765    private Node<K, V> leastNode(final Node<K, V> node, final DataElement dataElement) {
1766        Node<K, V> rval = node;
1767        if (rval != null) {
1768            while (rval.getLeft(dataElement) != null) {
1769                rval = rval.getLeft(dataElement);
1770            }
1771        }
1772        return rval;
1773    }
1774
1775    /**
1776     * Does the actual lookup of a piece of data.
1777     *
1778     * @param data The key or value to be looked up
1779     * @param dataElement  either the {@link DataElement#KEY key}
1780     *                     or the {@link DataElement#VALUE value}.
1781     * @return The desired Node, or null if there is no mapping of the
1782     *         specified data
1783     */
1784    @SuppressWarnings("unchecked")
1785    private <T extends Comparable<T>> Node<K, V> lookup(final Object data, final DataElement dataElement) {
1786        Node<K, V> rval = null;
1787        Node<K, V> node = rootNode[dataElement.ordinal()];
1788
1789        while (node != null) {
1790            final int cmp = compare((T) data, (T) node.getData(dataElement));
1791            if (cmp == 0) {
1792                rval = node;
1793                break;
1794            }
1795            node = cmp < 0 ? node.getLeft(dataElement) : node.getRight(dataElement);
1796        }
1797
1798        return rval;
1799    }
1800
1801    private Node<K, V> lookupKey(final Object key) {
1802        return this.<K>lookup(key, KEY);
1803    }
1804
1805    private Node<K, V> lookupValue(final Object value) {
1806        return this.<V>lookup(value, VALUE);
1807    }
1808
1809    @Override
1810    public OrderedMapIterator<K, V> mapIterator() {
1811        if (isEmpty()) {
1812            return EmptyOrderedMapIterator.<K, V>emptyOrderedMapIterator();
1813        }
1814        return new ViewMapIterator(KEY);
1815    }
1816
1817    /**
1818     * Increments the modification count -- used to check for
1819     * concurrent modification of the map through the map and through
1820     * an Iterator from one of its Set or Collection views.
1821     */
1822    private void modify() {
1823        modifications++;
1824    }
1825
1826    /**
1827     * Gets the next larger node from the specified node.
1828     *
1829     * @param node The node to be searched from
1830     * @param dataElement  either the {@link DataElement#KEY key}
1831     *                     or the {@link DataElement#VALUE value}.
1832     * @return The specified node
1833     */
1834    private Node<K, V> nextGreater(final Node<K, V> node, final DataElement dataElement) {
1835        final Node<K, V> rval;
1836        if (node == null) {
1837            rval = null;
1838        } else if (node.getRight(dataElement) != null) {
1839            // everything to the node's right is larger. The least of
1840            // the right node's descendants is the next larger node
1841            rval = leastNode(node.getRight(dataElement), dataElement);
1842        } else {
1843            // traverse up our ancestry until we find an ancestor that
1844            // is null or one whose left child is our ancestor. If we
1845            // find a null, then this node IS the largest node in the
1846            // tree, and there is no greater node. Otherwise, we are
1847            // the largest node in the subtree on that ancestor's left
1848            // ... and that ancestor is the next greatest node
1849            Node<K, V> parent = node.getParent(dataElement);
1850            Node<K, V> child = node;
1851
1852            while (parent != null && child == parent.getRight(dataElement)) {
1853                child = parent;
1854                parent = parent.getParent(dataElement);
1855            }
1856            rval = parent;
1857        }
1858        return rval;
1859    }
1860
1861    /**
1862     * Gets the next key after the one specified.
1863     * <p>
1864     * The key must implement {@code Comparable}.
1865     *
1866     * @param key The key to search for next from
1867     * @return The next key, null if no match or at end
1868     */
1869    @Override
1870    public K nextKey(final K key) {
1871        checkKey(key);
1872        final Node<K, V> node = nextGreater(lookupKey(key), KEY);
1873        return node == null ? null : node.getKey();
1874    }
1875
1876    /**
1877     * Gets the next smaller node from the specified node.
1878     *
1879     * @param node The node to be searched from
1880     * @param dataElement  either the {@link DataElement#KEY key}
1881     *                     or the {@link DataElement#VALUE value}.
1882     * @return The specified node
1883     */
1884    private Node<K, V> nextSmaller(final Node<K, V> node, final DataElement dataElement) {
1885        final Node<K, V> rval;
1886        if (node == null) {
1887            rval = null;
1888        } else if (node.getLeft(dataElement) != null) {
1889            // everything to the node's left is smaller. The greatest of
1890            // the left node's descendants is the next smaller node
1891            rval = greatestNode(node.getLeft(dataElement), dataElement);
1892        } else {
1893            // traverse up our ancestry until we find an ancestor that
1894            // is null or one whose right child is our ancestor. If we
1895            // find a null, then this node IS the largest node in the
1896            // tree, and there is no greater node. Otherwise, we are
1897            // the largest node in the subtree on that ancestor's right
1898            // ... and that ancestor is the next greatest node
1899            Node<K, V> parent = node.getParent(dataElement);
1900            Node<K, V> child = node;
1901
1902            while (parent != null && child == parent.getLeft(dataElement)) {
1903                child = parent;
1904                parent = parent.getParent(dataElement);
1905            }
1906            rval = parent;
1907        }
1908        return rval;
1909    }
1910
1911    /**
1912     * Gets the previous key before the one specified.
1913     * <p>
1914     * The key must implement {@code Comparable}.
1915     *
1916     * @param key The key to search for previous from
1917     * @return The previous key, null if no match or at start
1918     */
1919    @Override
1920    public K previousKey(final K key) {
1921        checkKey(key);
1922        final Node<K, V> node = nextSmaller(lookupKey(key), KEY);
1923        return node == null ? null : node.getKey();
1924    }
1925
1926    /**
1927     * Puts the key-value pair into the map, replacing any previous pair.
1928     * <p>
1929     * When adding a key-value pair, the value may already exist in the map
1930     * against a different key. That mapping is removed, to ensure that the
1931     * value only occurs once in the inverse map.
1932     * <pre>
1933     *  BidiMap map1 = new TreeBidiMap();
1934     *  map.put("A","B");  // contains A mapped to B, as per Map
1935     *  map.put("A","C");  // contains A mapped to C, as per Map
1936     *
1937     *  BidiMap map2 = new TreeBidiMap();
1938     *  map.put("A","B");  // contains A mapped to B, as per Map
1939     *  map.put("C","B");  // contains C mapped to B, key A is removed
1940     * </pre>
1941     * <p>
1942     * Both key and value must implement {@code Comparable}.
1943     *
1944     * @param key  key with which the specified value is to be  associated
1945     * @param value  value to be associated with the specified key
1946     * @return The previous value for the key
1947     * @throws ClassCastException if the key is of an inappropriate type
1948     * @throws NullPointerException if the key is null
1949     */
1950    @Override
1951    public V put(final K key, final V value) {
1952        final V result = get(key);
1953        doPut(key, value);
1954        return result;
1955    }
1956
1957    /**
1958     * Puts all the mappings from the specified map into this map.
1959     * <p>
1960     * All keys and values must implement {@code Comparable}.
1961     *
1962     * @param map  The map to copy from
1963     */
1964    @Override
1965    public void putAll(final Map<? extends K, ? extends V> map) {
1966        for (final Map.Entry<? extends K, ? extends V> e : map.entrySet()) {
1967            put(e.getKey(), e.getValue());
1968        }
1969    }
1970
1971    /**
1972     * Deserializes the content of the stream.
1973     *
1974     * @param stream The input stream
1975     * @throws IOException Thrown if an error occurs while reading from the stream
1976     * @throws ClassNotFoundException if an object read from the stream cannot be loaded
1977     */
1978    @SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect
1979    private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException {
1980        stream.defaultReadObject();
1981        rootNode = new Node[2];
1982        final int size = stream.readInt();
1983        for (int i = 0; i < size; i++) {
1984            final K k = (K) stream.readObject();
1985            final V v = (V) stream.readObject();
1986            put(k, v);
1987        }
1988    }
1989
1990    /**
1991     * Removes the mapping for this key from this map if present.
1992     * <p>
1993     * The key must implement {@code Comparable}.
1994     *
1995     * @param key  key whose mapping is to be removed from the map.
1996     * @return previous value associated with specified key,
1997     *  or null if there was no mapping for key.
1998     * @throws ClassCastException if the key is of an inappropriate type
1999     * @throws NullPointerException if the key is null
2000     */
2001    @Override
2002    public V remove(final Object key) {
2003        return doRemoveKey(key);
2004    }
2005
2006    /**
2007     * Removes the mapping for this value from this map if present.
2008     * <p>
2009     * The value must implement {@code Comparable}.
2010     *
2011     * @param value  value whose mapping is to be removed from the map
2012     * @return previous key associated with specified value,
2013     *  or null if there was no mapping for value.
2014     * @throws ClassCastException if the value is of an inappropriate type
2015     * @throws NullPointerException if the value is null
2016     */
2017    @Override
2018    public K removeValue(final Object value) {
2019        return doRemoveValue(value);
2020    }
2021
2022    /**
2023     * Does a rotate left. standard fare in the world of balanced trees.
2024     *
2025     * @param node The node to be rotated
2026     * @param dataElement  either the {@link DataElement#KEY key}
2027     *                     or the {@link DataElement#VALUE value}.
2028     */
2029    private void rotateLeft(final Node<K, V> node, final DataElement dataElement) {
2030        final Node<K, V> rightChild = node.getRight(dataElement);
2031        node.setRight(rightChild.getLeft(dataElement), dataElement);
2032
2033        if (rightChild.getLeft(dataElement) != null) {
2034            rightChild.getLeft(dataElement).setParent(node, dataElement);
2035        }
2036        rightChild.setParent(node.getParent(dataElement), dataElement);
2037
2038        if (node.getParent(dataElement) == null) {
2039            // node was the root ... now its right child is the root
2040            rootNode[dataElement.ordinal()] = rightChild;
2041        } else if (node.getParent(dataElement).getLeft(dataElement) == node) {
2042            node.getParent(dataElement).setLeft(rightChild, dataElement);
2043        } else {
2044            node.getParent(dataElement).setRight(rightChild, dataElement);
2045        }
2046
2047        rightChild.setLeft(node, dataElement);
2048        node.setParent(rightChild, dataElement);
2049    }
2050
2051    /**
2052     * Does a rotate right. standard fare in the world of balanced trees.
2053     *
2054     * @param node The node to be rotated
2055     * @param dataElement  either the {@link DataElement#KEY key}
2056     *                     or the {@link DataElement#VALUE value}.
2057     */
2058    private void rotateRight(final Node<K, V> node, final DataElement dataElement) {
2059        final Node<K, V> leftChild = node.getLeft(dataElement);
2060        node.setLeft(leftChild.getRight(dataElement), dataElement);
2061        if (leftChild.getRight(dataElement) != null) {
2062            leftChild.getRight(dataElement).setParent(node, dataElement);
2063        }
2064        leftChild.setParent(node.getParent(dataElement), dataElement);
2065
2066        if (node.getParent(dataElement) == null) {
2067            // node was the root ... now its left child is the root
2068            rootNode[dataElement.ordinal()] = leftChild;
2069        } else if (node.getParent(dataElement).getRight(dataElement) == node) {
2070            node.getParent(dataElement).setRight(leftChild, dataElement);
2071        } else {
2072            node.getParent(dataElement).setLeft(leftChild, dataElement);
2073        }
2074
2075        leftChild.setRight(node, dataElement);
2076        node.setParent(leftChild, dataElement);
2077    }
2078
2079    /**
2080     * Decrements the size and note that the map has changed.
2081     */
2082    private void shrink() {
2083        modify();
2084        nodeCount--;
2085    }
2086
2087    /**
2088     * Returns the number of key-value mappings in this map.
2089     *
2090     * @return The number of key-value mappings in this map
2091     */
2092    @Override
2093    public int size() {
2094        return nodeCount;
2095    }
2096
2097    /**
2098     * Swaps two nodes (except for their content), taking care of
2099     * special cases where one is the other's parent ... hey, it
2100     * happens.
2101     *
2102     * @param x one node
2103     * @param y another node
2104     * @param dataElement  The KEY or VALUE int
2105     */
2106    private void swapPosition(final Node<K, V> x, final Node<K, V> y, final DataElement dataElement) {
2107        // Save initial values.
2108        final Node<K, V> xFormerParent = x.getParent(dataElement);
2109        final Node<K, V> xFormerLeftChild = x.getLeft(dataElement);
2110        final Node<K, V> xFormerRightChild = x.getRight(dataElement);
2111        final Node<K, V> yFormerParent = y.getParent(dataElement);
2112        final Node<K, V> yFormerLeftChild = y.getLeft(dataElement);
2113        final Node<K, V> yFormerRightChild = y.getRight(dataElement);
2114        final boolean xWasLeftChild =
2115                x.getParent(dataElement) != null && x == x.getParent(dataElement).getLeft(dataElement);
2116        final boolean yWasLeftChild =
2117                y.getParent(dataElement) != null && y == y.getParent(dataElement).getLeft(dataElement);
2118
2119        // Swap, handling special cases of one being the other's parent.
2120        if (x == yFormerParent) { // x was y's parent
2121            x.setParent(y, dataElement);
2122
2123            if (yWasLeftChild) {
2124                y.setLeft(x, dataElement);
2125                y.setRight(xFormerRightChild, dataElement);
2126            } else {
2127                y.setRight(x, dataElement);
2128                y.setLeft(xFormerLeftChild, dataElement);
2129            }
2130        } else {
2131            x.setParent(yFormerParent, dataElement);
2132
2133            if (yFormerParent != null) {
2134                if (yWasLeftChild) {
2135                    yFormerParent.setLeft(x, dataElement);
2136                } else {
2137                    yFormerParent.setRight(x, dataElement);
2138                }
2139            }
2140
2141            y.setLeft(xFormerLeftChild, dataElement);
2142            y.setRight(xFormerRightChild, dataElement);
2143        }
2144
2145        if (y == xFormerParent) { // y was x's parent
2146            y.setParent(x, dataElement);
2147
2148            if (xWasLeftChild) {
2149                x.setLeft(y, dataElement);
2150                x.setRight(yFormerRightChild, dataElement);
2151            } else {
2152                x.setRight(y, dataElement);
2153                x.setLeft(yFormerLeftChild, dataElement);
2154            }
2155        } else {
2156            y.setParent(xFormerParent, dataElement);
2157
2158            if (xFormerParent != null) {
2159                if (xWasLeftChild) {
2160                    xFormerParent.setLeft(y, dataElement);
2161                } else {
2162                    xFormerParent.setRight(y, dataElement);
2163                }
2164            }
2165
2166            x.setLeft(yFormerLeftChild, dataElement);
2167            x.setRight(yFormerRightChild, dataElement);
2168        }
2169
2170        // Fix children's parent pointers
2171        if (x.getLeft(dataElement) != null) {
2172            x.getLeft(dataElement).setParent(x, dataElement);
2173        }
2174
2175        if (x.getRight(dataElement) != null) {
2176            x.getRight(dataElement).setParent(x, dataElement);
2177        }
2178
2179        if (y.getLeft(dataElement) != null) {
2180            y.getLeft(dataElement).setParent(y, dataElement);
2181        }
2182
2183        if (y.getRight(dataElement) != null) {
2184            y.getRight(dataElement).setParent(y, dataElement);
2185        }
2186
2187        x.swapColors(y, dataElement);
2188
2189        // Check if root changed
2190        if (rootNode[dataElement.ordinal()] == x) {
2191            rootNode[dataElement.ordinal()] = y;
2192        } else if (rootNode[dataElement.ordinal()] == y) {
2193            rootNode[dataElement.ordinal()] = x;
2194        }
2195    }
2196
2197    /**
2198     * Returns a string version of this Map in standard format.
2199     *
2200     * @return A standard format string version of the map
2201     */
2202    @Override
2203    public String toString() {
2204        return this.doToString(KEY);
2205    }
2206
2207    /**
2208     * Returns a set view of the values contained in this map in key order.
2209     * The returned object can be cast to a Set.
2210     * <p>
2211     * The set is backed by the map, so changes to the map are reflected in
2212     * the set, and vice-versa. If the map is modified while an iteration over
2213     * the set is in progress, the results of the iteration are undefined.
2214     * <p>
2215     * The set supports element removal, which removes the corresponding mapping
2216     * from the map. It does not support the add or addAll operations.
2217     *
2218     * @return A set view of the values contained in this map.
2219     */
2220    @Override
2221    public Set<V> values() {
2222        if (valuesSet == null) {
2223            valuesSet = new ValueView(KEY);
2224        }
2225        return valuesSet;
2226    }
2227
2228    /**
2229     * Serializes this object to an ObjectOutputStream.
2230     *
2231     * @param out The target ObjectOutputStream.
2232     * @throws IOException thrown when an I/O errors occur writing to the target stream.
2233     */
2234    private void writeObject(final ObjectOutputStream out) throws IOException {
2235        out.defaultWriteObject();
2236        out.writeInt(this.size());
2237        for (final Entry<K, V> entry : entrySet()) {
2238            out.writeObject(entry.getKey());
2239            out.writeObject(entry.getValue());
2240        }
2241    }
2242
2243}