TreeBidiMap.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.collections4.bidimap;

  18. import static org.apache.commons.collections4.bidimap.TreeBidiMap.DataElement.KEY;
  19. import static org.apache.commons.collections4.bidimap.TreeBidiMap.DataElement.VALUE;

  20. import java.io.IOException;
  21. import java.io.ObjectInputStream;
  22. import java.io.ObjectOutputStream;
  23. import java.io.Serializable;
  24. import java.util.AbstractSet;
  25. import java.util.ConcurrentModificationException;
  26. import java.util.Iterator;
  27. import java.util.Map;
  28. import java.util.NoSuchElementException;
  29. import java.util.Objects;
  30. import java.util.Set;

  31. import org.apache.commons.collections4.KeyValue;
  32. import org.apache.commons.collections4.MapIterator;
  33. import org.apache.commons.collections4.OrderedBidiMap;
  34. import org.apache.commons.collections4.OrderedIterator;
  35. import org.apache.commons.collections4.OrderedMapIterator;
  36. import org.apache.commons.collections4.iterators.EmptyOrderedMapIterator;
  37. import org.apache.commons.collections4.keyvalue.UnmodifiableMapEntry;

  38. /**
  39.  * Red-Black tree-based implementation of BidiMap where all objects added
  40.  * implement the {@code Comparable} interface.
  41.  * <p>
  42.  * This class guarantees that the map will be in both ascending key order
  43.  * and ascending value order, sorted according to the natural order for
  44.  * the key's and value's classes.
  45.  * </p>
  46.  * <p>
  47.  * This Map is intended for applications that need to be able to look
  48.  * up a key-value pairing by either key or value, and need to do so
  49.  * with equal efficiency.
  50.  * </p>
  51.  * <p>
  52.  * While that goal could be accomplished by taking a pair of TreeMaps
  53.  * and redirecting requests to the appropriate TreeMap (for example,
  54.  * containsKey would be directed to the TreeMap that maps values to
  55.  * keys, containsValue would be directed to the TreeMap that maps keys
  56.  * to values), there are problems with that implementation.
  57.  * If the data contained in the TreeMaps is large, the cost of redundant
  58.  * storage becomes significant. The {@link DualTreeBidiMap} and
  59.  * {@link DualHashBidiMap} implementations use this approach.
  60.  * </p>
  61.  * <p>
  62.  * This solution keeps minimizes the data storage by holding data only once.
  63.  * The red-black algorithm is based on {@link java.util.TreeMap}, but has been modified
  64.  * to simultaneously map a tree node by key and by value. This doubles the
  65.  * cost of put operations (but so does using two TreeMaps), and nearly doubles
  66.  * the cost of remove operations (there is a savings in that the lookup of the
  67.  * node to be removed only has to be performed once). And since only one node
  68.  * contains the key and value, storage is significantly less than that
  69.  * required by two TreeMaps.
  70.  * </p>
  71.  * <p>
  72.  * The Map.Entry instances returned by the appropriate methods will
  73.  * not allow setValue() and will throw an
  74.  * UnsupportedOperationException on attempts to call that method.
  75.  * </p>
  76.  *
  77.  * @param <K> the type of the keys in this map
  78.  * @param <V> the type of the values in this map
  79.  * @since 3.0 (previously DoubleOrderedMap v2.0)
  80.  */
  81. public class TreeBidiMap<K extends Comparable<K>, V extends Comparable<V>>
  82.     implements OrderedBidiMap<K, V>, Serializable {

  83.     /**
  84.      * A view of this map.
  85.      */
  86.     abstract class AbstractView<E> extends AbstractSet<E> {

  87.         /** Whether to return KEY or VALUE order. */
  88.         final DataElement orderType;

  89.         /**
  90.          * Constructs a new instance.
  91.          * @param orderType  the KEY or VALUE int for the order
  92.          */
  93.         AbstractView(final DataElement orderType) {
  94.             this.orderType = orderType;
  95.         }

  96.         @Override
  97.         public void clear() {
  98.             TreeBidiMap.this.clear();
  99.         }

  100.         @Override
  101.         public int size() {
  102.             return TreeBidiMap.this.size();
  103.         }
  104.     }

  105.     /**
  106.      * An iterator over the map.
  107.      */
  108.     abstract class AbstractViewIterator {

  109.         /** Whether to return KEY or VALUE order. */
  110.         private final DataElement orderType;
  111.         /** The last node returned by the iterator. */
  112.         Node<K, V> lastReturnedNode;
  113.         /** The next node to be returned by the iterator. */
  114.         private Node<K, V> nextNode;
  115.         /** The previous node in the sequence returned by the iterator. */
  116.         private Node<K, V> previousNode;
  117.         /** The modification count. */
  118.         private int expectedModifications;

  119.         /**
  120.          * Constructs a new instance.
  121.          * @param orderType  the KEY or VALUE int for the order
  122.          */
  123.         AbstractViewIterator(final DataElement orderType) {
  124.             this.orderType = orderType;
  125.             expectedModifications = modifications;
  126.             nextNode = leastNode(rootNode[orderType.ordinal()], orderType);
  127.             lastReturnedNode = null;
  128.             previousNode = null;
  129.         }

  130.         public final boolean hasNext() {
  131.             return nextNode != null;
  132.         }

  133.         public boolean hasPrevious() {
  134.             return previousNode != null;
  135.         }

  136.         protected Node<K, V> navigateNext() {
  137.             if (nextNode == null) {
  138.                 throw new NoSuchElementException();
  139.             }
  140.             if (modifications != expectedModifications) {
  141.                 throw new ConcurrentModificationException();
  142.             }
  143.             lastReturnedNode = nextNode;
  144.             previousNode = nextNode;
  145.             nextNode = nextGreater(nextNode, orderType);
  146.             return lastReturnedNode;
  147.         }

  148.         protected Node<K, V> navigatePrevious() {
  149.             if (previousNode == null) {
  150.                 throw new NoSuchElementException();
  151.             }
  152.             if (modifications != expectedModifications) {
  153.                 throw new ConcurrentModificationException();
  154.             }
  155.             nextNode = lastReturnedNode;
  156.             if (nextNode == null) {
  157.                 nextNode = nextGreater(previousNode, orderType);
  158.             }
  159.             lastReturnedNode = previousNode;
  160.             previousNode = nextSmaller(previousNode, orderType);
  161.             return lastReturnedNode;
  162.         }

  163.         public final void remove() {
  164.             if (lastReturnedNode == null) {
  165.                 throw new IllegalStateException();
  166.             }
  167.             if (modifications != expectedModifications) {
  168.                 throw new ConcurrentModificationException();
  169.             }
  170.             doRedBlackDelete(lastReturnedNode);
  171.             expectedModifications++;
  172.             lastReturnedNode = null;
  173.             if (nextNode == null) {
  174.                 previousNode = greatestNode(rootNode[orderType.ordinal()], orderType);
  175.             } else {
  176.                 previousNode = nextSmaller(nextNode, orderType);
  177.             }
  178.         }
  179.     }

  180.     enum DataElement {
  181.         KEY("key"), VALUE("value");

  182.         private final String description;

  183.         /**
  184.          * Creates a new TreeBidiMap.DataElement.
  185.          *
  186.          * @param description  the description for the element
  187.          */
  188.         DataElement(final String description) {
  189.             this.description = description;
  190.         }

  191.         @Override
  192.         public String toString() {
  193.             return description;
  194.         }
  195.     }
  196.     /**
  197.      * A view of this map.
  198.      */
  199.     final class EntryView extends AbstractView<Map.Entry<K, V>> {

  200.         EntryView() {
  201.             super(KEY);
  202.         }

  203.         @Override
  204.         public boolean contains(final Object obj) {
  205.             if (!(obj instanceof Map.Entry)) {
  206.                 return false;
  207.             }
  208.             final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
  209.             final Object value = entry.getValue();
  210.             final Node<K, V> node = lookupKey(entry.getKey());
  211.             return node != null && Objects.equals(node.getValue(), value);
  212.         }

  213.         @Override
  214.         public Iterator<Map.Entry<K, V>> iterator() {
  215.             return new ViewMapEntryIterator();
  216.         }

  217.         @Override
  218.         public boolean remove(final Object obj) {
  219.             if (!(obj instanceof Map.Entry)) {
  220.                 return false;
  221.             }
  222.             final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
  223.             final Object value = entry.getValue();
  224.             final Node<K, V> node = lookupKey(entry.getKey());
  225.             if (node != null && Objects.equals(node.getValue(), value)) {
  226.                 doRedBlackDelete(node);
  227.                 return true;
  228.             }
  229.             return false;
  230.         }
  231.     }
  232.     /**
  233.      * The inverse map implementation.
  234.      */
  235.     final class Inverse implements OrderedBidiMap<V, K> {

  236.         /** Store the keySet once created. */
  237.         private Set<V> inverseKeySet;
  238.         /** Store the valuesSet once created. */
  239.         private Set<K> inverseValuesSet;
  240.         /** Store the entrySet once created. */
  241.         private Set<Map.Entry<V, K>> inverseEntrySet;

  242.         @Override
  243.         public void clear() {
  244.             TreeBidiMap.this.clear();
  245.         }

  246.         @Override
  247.         public boolean containsKey(final Object key) {
  248.             return TreeBidiMap.this.containsValue(key);
  249.         }

  250.         @Override
  251.         public boolean containsValue(final Object value) {
  252.             return TreeBidiMap.this.containsKey(value);
  253.         }

  254.         @Override
  255.         public Set<Map.Entry<V, K>> entrySet() {
  256.             if (inverseEntrySet == null) {
  257.                 inverseEntrySet = new InverseEntryView();
  258.             }
  259.             return inverseEntrySet;
  260.         }

  261.         @Override
  262.         public boolean equals(final Object obj) {
  263.             return TreeBidiMap.this.doEquals(obj, VALUE);
  264.         }

  265.         @Override
  266.         public V firstKey() {
  267.             if (TreeBidiMap.this.nodeCount == 0) {
  268.                 throw new NoSuchElementException("Map is empty");
  269.             }
  270.             return leastNode(TreeBidiMap.this.rootNode[VALUE.ordinal()], VALUE).getValue();
  271.         }

  272.         @Override
  273.         public K get(final Object key) {
  274.             return TreeBidiMap.this.getKey(key);
  275.         }

  276.         @Override
  277.         public V getKey(final Object value) {
  278.             return TreeBidiMap.this.get(value);
  279.         }

  280.         @Override
  281.         public int hashCode() {
  282.             return TreeBidiMap.this.doHashCode(VALUE);
  283.         }

  284.         @Override
  285.         public OrderedBidiMap<K, V> inverseBidiMap() {
  286.             return TreeBidiMap.this;
  287.         }

  288.         @Override
  289.         public boolean isEmpty() {
  290.             return TreeBidiMap.this.isEmpty();
  291.         }

  292.         @Override
  293.         public Set<V> keySet() {
  294.             if (inverseKeySet == null) {
  295.                 inverseKeySet = new ValueView(VALUE);
  296.             }
  297.             return inverseKeySet;
  298.         }

  299.         @Override
  300.         public V lastKey() {
  301.             if (TreeBidiMap.this.nodeCount == 0) {
  302.                 throw new NoSuchElementException("Map is empty");
  303.             }
  304.             return greatestNode(TreeBidiMap.this.rootNode[VALUE.ordinal()], VALUE).getValue();
  305.         }

  306.         @Override
  307.         public OrderedMapIterator<V, K> mapIterator() {
  308.             if (isEmpty()) {
  309.                 return EmptyOrderedMapIterator.<V, K>emptyOrderedMapIterator();
  310.             }
  311.             return new InverseViewMapIterator(VALUE);
  312.         }

  313.         @Override
  314.         public V nextKey(final V key) {
  315.             checkKey(key);
  316.             final Node<K, V> node = nextGreater(TreeBidiMap.this.<V>lookup(key, VALUE), VALUE);
  317.             return node == null ? null : node.getValue();
  318.         }

  319.         @Override
  320.         public V previousKey(final V key) {
  321.             checkKey(key);
  322.             final Node<K, V> node = TreeBidiMap.this.nextSmaller(TreeBidiMap.this.<V>lookup(key, VALUE), VALUE);
  323.             return node == null ? null : node.getValue();
  324.         }

  325.         @Override
  326.         public K put(final V key, final K value) {
  327.             final K result = get(key);
  328.             TreeBidiMap.this.doPut(value, key);
  329.             return result;
  330.         }

  331.         @Override
  332.         public void putAll(final Map<? extends V, ? extends K> map) {
  333.             for (final Map.Entry<? extends V, ? extends K> e : map.entrySet()) {
  334.                 put(e.getKey(), e.getValue());
  335.             }
  336.         }

  337.         @Override
  338.         public K remove(final Object key) {
  339.             return TreeBidiMap.this.removeValue(key);
  340.         }

  341.         @Override
  342.         public V removeValue(final Object value) {
  343.             return TreeBidiMap.this.remove(value);
  344.         }

  345.         @Override
  346.         public int size() {
  347.             return TreeBidiMap.this.size();
  348.         }

  349.         @Override
  350.         public String toString() {
  351.             return TreeBidiMap.this.doToString(VALUE);
  352.         }

  353.         @Override
  354.         public Set<K> values() {
  355.             if (inverseValuesSet == null) {
  356.                 inverseValuesSet = new KeyView(VALUE);
  357.             }
  358.             return inverseValuesSet;
  359.         }
  360.     }
  361.     /**
  362.      * A view of this map.
  363.      */
  364.     final class InverseEntryView extends AbstractView<Map.Entry<V, K>> {

  365.         InverseEntryView() {
  366.             super(VALUE);
  367.         }

  368.         @Override
  369.         public boolean contains(final Object obj) {
  370.             if (!(obj instanceof Map.Entry)) {
  371.                 return false;
  372.             }
  373.             final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
  374.             final Object value = entry.getValue();
  375.             final Node<K, V> node = lookupValue(entry.getKey());
  376.             return node != null && Objects.equals(node.getKey(), value);
  377.         }

  378.         @Override
  379.         public Iterator<Map.Entry<V, K>> iterator() {
  380.             return new InverseViewMapEntryIterator();
  381.         }

  382.         @Override
  383.         public boolean remove(final Object obj) {
  384.             if (!(obj instanceof Map.Entry)) {
  385.                 return false;
  386.             }
  387.             final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
  388.             final Object value = entry.getValue();
  389.             final Node<K, V> node = lookupValue(entry.getKey());
  390.             if (node != null && Objects.equals(node.getKey(), value)) {
  391.                 doRedBlackDelete(node);
  392.                 return true;
  393.             }
  394.             return false;
  395.         }
  396.     }
  397.     /**
  398.      * An iterator over the inverse map entries.
  399.      */
  400.     final class InverseViewMapEntryIterator extends AbstractViewIterator implements OrderedIterator<Map.Entry<V, K>> {

  401.         /**
  402.          * Constructs a new instance.
  403.          */
  404.         InverseViewMapEntryIterator() {
  405.             super(VALUE);
  406.         }

  407.         private Map.Entry<V, K> createEntry(final Node<K, V> node) {
  408.             return new UnmodifiableMapEntry<>(node.getValue(), node.getKey());
  409.         }

  410.         @Override
  411.         public Map.Entry<V, K> next() {
  412.             return createEntry(navigateNext());
  413.         }

  414.         @Override
  415.         public Map.Entry<V, K> previous() {
  416.             return createEntry(navigatePrevious());
  417.         }
  418.     }
  419.     /**
  420.      * An iterator over the map.
  421.      */
  422.     final class InverseViewMapIterator extends AbstractViewIterator implements OrderedMapIterator<V, K> {

  423.         /**
  424.          * Creates a new TreeBidiMap.InverseViewMapIterator.
  425.          */
  426.         InverseViewMapIterator(final DataElement orderType) {
  427.             super(orderType);
  428.         }

  429.         @Override
  430.         public V getKey() {
  431.             if (lastReturnedNode == null) {
  432.                 throw new IllegalStateException(
  433.                         "Iterator getKey() can only be called after next() and before remove()");
  434.             }
  435.             return lastReturnedNode.getValue();
  436.         }

  437.         @Override
  438.         public K getValue() {
  439.             if (lastReturnedNode == null) {
  440.                 throw new IllegalStateException(
  441.                         "Iterator getValue() can only be called after next() and before remove()");
  442.             }
  443.             return lastReturnedNode.getKey();
  444.         }

  445.         @Override
  446.         public V next() {
  447.             return navigateNext().getValue();
  448.         }

  449.         @Override
  450.         public V previous() {
  451.             return navigatePrevious().getValue();
  452.         }

  453.         @Override
  454.         public K setValue(final K value) {
  455.             throw new UnsupportedOperationException();
  456.         }
  457.     }
  458.     final class KeyView extends AbstractView<K> {

  459.         /**
  460.          * Creates a new TreeBidiMap.KeyView.
  461.          */
  462.         KeyView(final DataElement orderType) {
  463.             super(orderType);
  464.         }

  465.         @Override
  466.         public boolean contains(final Object obj) {
  467.             checkNonNullComparable(obj, KEY);
  468.             return lookupKey(obj) != null;
  469.         }

  470.         @Override
  471.         public Iterator<K> iterator() {
  472.             return new ViewMapIterator(orderType);
  473.         }

  474.         @Override
  475.         public boolean remove(final Object o) {
  476.             return doRemoveKey(o) != null;
  477.         }

  478.     }

  479.     /**
  480.      * A node used to store the data.
  481.      */
  482.     static class Node<K extends Comparable<K>, V extends Comparable<V>> implements Map.Entry<K, V>, KeyValue<K, V> {

  483.         private final K key;
  484.         private final V value;
  485.         private final Node<K, V>[] leftNode;
  486.         private final Node<K, V>[] rightNode;
  487.         private final Node<K, V>[] parentNode;
  488.         private final boolean[] blackColor;
  489.         private int hashCodeValue;
  490.         private boolean calculatedHashCode;

  491.         /**
  492.          * Makes a new cell with given key and value, and with null
  493.          * links, and black (true) colors.
  494.          *
  495.          * @param key the key of this node
  496.          * @param value the value of this node
  497.          */
  498.         @SuppressWarnings("unchecked")
  499.         Node(final K key, final V value) {
  500.             this.key = key;
  501.             this.value = value;
  502.             leftNode = new Node[2];
  503.             rightNode = new Node[2];
  504.             parentNode = new Node[2];
  505.             blackColor = new boolean[] { true, true };
  506.             calculatedHashCode = false;
  507.         }

  508.         /**
  509.          * Makes this node the same color as another.
  510.          *
  511.          * @param node  the node whose color we're adopting
  512.          * @param dataElement  either the {@link DataElement#KEY key}
  513.          *                     or the {@link DataElement#VALUE value}.
  514.          */
  515.         private void copyColor(final Node<K, V> node, final DataElement dataElement) {
  516.             blackColor[dataElement.ordinal()] = node.blackColor[dataElement.ordinal()];
  517.         }

  518.         /**
  519.          * Compares the specified object with this entry for equality.
  520.          * Returns true if the given object is also a map entry and
  521.          * the two entries represent the same mapping.
  522.          *
  523.          * @param obj  the object to be compared for equality with this entry.
  524.          * @return true if the specified object is equal to this entry.
  525.          */
  526.         @Override
  527.         public boolean equals(final Object obj) {
  528.             if (obj == this) {
  529.                 return true;
  530.             }
  531.             if (!(obj instanceof Map.Entry)) {
  532.                 return false;
  533.             }
  534.             final Map.Entry<?, ?> e = (Map.Entry<?, ?>) obj;
  535.             return Objects.equals(getKey(), e.getKey()) && Objects.equals(getValue(), e.getValue());
  536.         }

  537.         private Object getData(final DataElement dataElement) {
  538.             switch (dataElement) {
  539.             case KEY:
  540.                 return getKey();
  541.             case VALUE:
  542.                 return getValue();
  543.             default:
  544.                 throw new IllegalArgumentException();
  545.             }
  546.         }

  547.         /**
  548.          * Gets the key.
  549.          *
  550.          * @return the key corresponding to this entry.
  551.          */
  552.         @Override
  553.         public K getKey() {
  554.             return key;
  555.         }

  556.         private Node<K, V> getLeft(final DataElement dataElement) {
  557.             return leftNode[dataElement.ordinal()];
  558.         }

  559.         /**
  560.          * Gets the parent node.
  561.          *
  562.          * @param dataElement  either the {@link DataElement#KEY key}
  563.          *                     or the {@link DataElement#VALUE value}.
  564.          * @return the parent node, may be null
  565.          */
  566.         private Node<K, V> getParent(final DataElement dataElement) {
  567.             return parentNode[dataElement.ordinal()];
  568.         }

  569.         private Node<K, V> getRight(final DataElement dataElement) {
  570.             return rightNode[dataElement.ordinal()];
  571.         }

  572.         /**
  573.          * Gets the value.
  574.          *
  575.          * @return the value corresponding to this entry.
  576.          */
  577.         @Override
  578.         public V getValue() {
  579.             return value;
  580.         }

  581.         /**
  582.          * @return the hash code value for this map entry.
  583.          */
  584.         @Override
  585.         public int hashCode() {
  586.             if (!calculatedHashCode) {
  587.                 hashCodeValue = getKey().hashCode() ^ getValue().hashCode();
  588.                 calculatedHashCode = true;
  589.             }
  590.             return hashCodeValue;
  591.         }

  592.         /**
  593.          * Is this node black?
  594.          *
  595.          * @param dataElement  either the {@link DataElement#KEY key}
  596.          *                     or the {@link DataElement#VALUE value}.
  597.          * @return true if black (which is represented as a true boolean)
  598.          */
  599.         private boolean isBlack(final DataElement dataElement) {
  600.             return blackColor[dataElement.ordinal()];
  601.         }

  602.         private boolean isLeftChild(final DataElement dataElement) {
  603.             return parentNode[dataElement.ordinal()] != null
  604.                     && parentNode[dataElement.ordinal()].leftNode[dataElement.ordinal()] == this;
  605.         }

  606.         /**
  607.          * Is this node red?
  608.          *
  609.          * @param dataElement  either the {@link DataElement#KEY key}
  610.          *                     or the {@link DataElement#VALUE value}.
  611.          * @return true if non-black
  612.          */
  613.         private boolean isRed(final DataElement dataElement) {
  614.             return !blackColor[dataElement.ordinal()];
  615.         }

  616.         private boolean isRightChild(final DataElement dataElement) {
  617.             return parentNode[dataElement.ordinal()] != null
  618.                     && parentNode[dataElement.ordinal()].rightNode[dataElement.ordinal()] == this;
  619.         }

  620.         /**
  621.          * Makes this node black.
  622.          *
  623.          * @param dataElement  either the {@link DataElement#KEY key}
  624.          *                     or the {@link DataElement#VALUE value}.
  625.          */
  626.         private void setBlack(final DataElement dataElement) {
  627.             blackColor[dataElement.ordinal()] = true;
  628.         }

  629.         private void setLeft(final Node<K, V> node, final DataElement dataElement) {
  630.             leftNode[dataElement.ordinal()] = node;
  631.         }

  632.         /**
  633.          * Sets this node's parent node.
  634.          *
  635.          * @param node  the new parent node
  636.          * @param dataElement  either the {@link DataElement#KEY key}
  637.          *                     or the {@link DataElement#VALUE value}.
  638.          */
  639.         private void setParent(final Node<K, V> node, final DataElement dataElement) {
  640.             parentNode[dataElement.ordinal()] = node;
  641.         }

  642.         /**
  643.          * Makes this node red.
  644.          *
  645.          * @param dataElement  either the {@link DataElement#KEY key}
  646.          *                     or the {@link DataElement#VALUE value}.
  647.          */
  648.         private void setRed(final DataElement dataElement) {
  649.             blackColor[dataElement.ordinal()] = false;
  650.         }

  651.         private void setRight(final Node<K, V> node, final DataElement dataElement) {
  652.             rightNode[dataElement.ordinal()] = node;
  653.         }

  654.         /**
  655.          * Optional operation that is not permitted in this implementation.
  656.          *
  657.          * @param ignored this parameter is ignored.
  658.          * @return does not return
  659.          * @throws UnsupportedOperationException always
  660.          */
  661.         @Override
  662.         public V setValue(final V ignored) throws UnsupportedOperationException {
  663.             throw new UnsupportedOperationException("Map.Entry.setValue is not supported");
  664.         }

  665.         /**
  666.          * Exchanges colors with another node.
  667.          *
  668.          * @param node  the node to swap with
  669.          * @param dataElement  either the {@link DataElement#KEY key}
  670.          *                     or the {@link DataElement#VALUE value}.
  671.          */
  672.         private void swapColors(final Node<K, V> node, final DataElement dataElement) {
  673.             // Swap colors -- old hacker's trick
  674.             blackColor[dataElement.ordinal()]      ^= node.blackColor[dataElement.ordinal()];
  675.             node.blackColor[dataElement.ordinal()] ^= blackColor[dataElement.ordinal()];
  676.             blackColor[dataElement.ordinal()]      ^= node.blackColor[dataElement.ordinal()];
  677.         }
  678.     }

  679.     final class ValueView extends AbstractView<V> {

  680.         /**
  681.          * Creates a new TreeBidiMap.ValueView.
  682.          */
  683.         ValueView(final DataElement orderType) {
  684.             super(orderType);
  685.         }

  686.         @Override
  687.         public boolean contains(final Object obj) {
  688.             checkNonNullComparable(obj, VALUE);
  689.             return lookupValue(obj) != null;
  690.         }

  691.         @Override
  692.         public Iterator<V> iterator() {
  693.             return new InverseViewMapIterator(orderType);
  694.         }

  695.         @Override
  696.         public boolean remove(final Object o) {
  697.             return doRemoveValue(o) != null;
  698.         }

  699.     }

  700.     /**
  701.      * An iterator over the map entries.
  702.      */
  703.     final class ViewMapEntryIterator extends AbstractViewIterator implements OrderedIterator<Map.Entry<K, V>> {

  704.         /**
  705.          * Constructs a new instance.
  706.          */
  707.         ViewMapEntryIterator() {
  708.             super(KEY);
  709.         }

  710.         @Override
  711.         public Map.Entry<K, V> next() {
  712.             return navigateNext();
  713.         }

  714.         @Override
  715.         public Map.Entry<K, V> previous() {
  716.             return navigatePrevious();
  717.         }
  718.     }

  719.     /**
  720.      * An iterator over the map.
  721.      */
  722.     final class ViewMapIterator extends AbstractViewIterator implements OrderedMapIterator<K, V> {

  723.         /**
  724.          * Constructs a new instance.
  725.          */
  726.         ViewMapIterator(final DataElement orderType) {
  727.             super(orderType);
  728.         }

  729.         @Override
  730.         public K getKey() {
  731.             if (lastReturnedNode == null) {
  732.                 throw new IllegalStateException(
  733.                         "Iterator getKey() can only be called after next() and before remove()");
  734.             }
  735.             return lastReturnedNode.getKey();
  736.         }

  737.         @Override
  738.         public V getValue() {
  739.             if (lastReturnedNode == null) {
  740.                 throw new IllegalStateException(
  741.                         "Iterator getValue() can only be called after next() and before remove()");
  742.             }
  743.             return lastReturnedNode.getValue();
  744.         }

  745.         @Override
  746.         public K next() {
  747.             return navigateNext().getKey();
  748.         }

  749.         @Override
  750.         public K previous() {
  751.             return navigatePrevious().getKey();
  752.         }

  753.         @Override
  754.         public V setValue(final V value) {
  755.             throw new UnsupportedOperationException();
  756.         }
  757.     }

  758.     private static final long serialVersionUID = 721969328361807L;

  759.     /**
  760.      * Checks a key for validity (non-null and implements Comparable)
  761.      *
  762.      * @param key the key to be checked
  763.      * @throws NullPointerException if key is null
  764.      * @throws ClassCastException if key is not Comparable
  765.      */
  766.     private static void checkKey(final Object key) {
  767.         checkNonNullComparable(key, KEY);
  768.     }

  769.     /**
  770.      * Checks a key and a value for validity (non-null and implements
  771.      * Comparable)
  772.      *
  773.      * @param key the key to be checked
  774.      * @param value the value to be checked
  775.      * @throws NullPointerException if key or value is null
  776.      * @throws ClassCastException if key or value is not Comparable
  777.      */
  778.     private static void checkKeyAndValue(final Object key, final Object value) {
  779.         checkKey(key);
  780.         checkValue(value);
  781.     }

  782.     /**
  783.      * Checks if an object is fit to be proper input ... has to be
  784.      * Comparable and non-null.
  785.      *
  786.      * @param obj the object being checked
  787.      * @param dataElement  either the {@link DataElement#KEY key}
  788.      *                     or the {@link DataElement#VALUE value}.
  789.      *
  790.      * @throws NullPointerException if o is null
  791.      * @throws ClassCastException if o is not Comparable
  792.      */
  793.     private static void checkNonNullComparable(final Object obj, final DataElement dataElement) {
  794.         Objects.requireNonNull(obj, Objects.toString(dataElement));
  795.         if (!(obj instanceof Comparable)) {
  796.             throw new ClassCastException(dataElement + " must be Comparable");
  797.         }
  798.     }

  799.     /**
  800.      * Checks a value for validity (non-null and implements Comparable)
  801.      *
  802.      * @param value the value to be checked
  803.      * @throws NullPointerException if value is null
  804.      * @throws ClassCastException if value is not Comparable
  805.      */
  806.     private static void checkValue(final Object value) {
  807.         checkNonNullComparable(value, VALUE);
  808.     }

  809.     /**
  810.      * Compares two objects.
  811.      *
  812.      * @param o1  the first object
  813.      * @param o2  the second object
  814.      * @return negative value if o1 &lt; o2; 0 if o1 == o2; positive
  815.      *         value if o1 &gt; o2
  816.      */
  817.     private static <T extends Comparable<T>> int compare(final T o1, final T o2) {
  818.         return o1.compareTo(o2);
  819.     }

  820.     /**
  821.      * Is the specified black red? If the node does not exist, sure,
  822.      * it's black, thank you.
  823.      *
  824.      * @param node the node (may be null) in question
  825.      * @param dataElement  either the {@link DataElement#KEY key}
  826.      *                     or the {@link DataElement#VALUE value}.
  827.      */
  828.     private static boolean isBlack(final Node<?, ?> node, final DataElement dataElement) {
  829.         return node == null || node.isBlack(dataElement);
  830.     }

  831.     /**
  832.      * Is the specified node red? If the node does not exist, no, it's
  833.      * black, thank you.
  834.      *
  835.      * @param node the node (may be null) in question
  836.      * @param dataElement  either the {@link DataElement#KEY key}
  837.      *                     or the {@link DataElement#VALUE value}.
  838.      */
  839.     private static boolean isRed(final Node<?, ?> node, final DataElement dataElement) {
  840.         return node != null && node.isRed(dataElement);
  841.     }

  842.     /**
  843.      * Forces a node (if it exists) black.
  844.      *
  845.      * @param node the node (may be null) in question
  846.      * @param dataElement  either the {@link DataElement#KEY key}
  847.      *                     or the {@link DataElement#VALUE value}.
  848.      */
  849.     private static void makeBlack(final Node<?, ?> node, final DataElement dataElement) {
  850.         if (node != null) {
  851.             node.setBlack(dataElement);
  852.         }
  853.     }

  854.     /**
  855.      * Forces a node (if it exists) red.
  856.      *
  857.      * @param node the node (may be null) in question
  858.      * @param dataElement  either the {@link DataElement#KEY key}
  859.      *                     or the {@link DataElement#VALUE value}.
  860.      */
  861.     private static void makeRed(final Node<?, ?> node, final DataElement dataElement) {
  862.         if (node != null) {
  863.             node.setRed(dataElement);
  864.         }
  865.     }

  866.     private transient Node<K, V>[] rootNode;

  867.     private transient int nodeCount;

  868.     private transient int modifications;

  869.     private transient Set<K> keySet;

  870.     private transient Set<V> valuesSet;

  871.     private transient Set<Map.Entry<K, V>> entrySet;

  872.     private transient Inverse inverse;

  873.     /**
  874.      * Constructs a new empty TreeBidiMap.
  875.      */
  876.     @SuppressWarnings("unchecked")
  877.     public TreeBidiMap() {
  878.         rootNode = new Node[2];
  879.     }

  880.     /**
  881.      * Constructs a new TreeBidiMap by copying an existing Map.
  882.      *
  883.      * @param map  the map to copy
  884.      * @throws ClassCastException if the keys/values in the map are
  885.      *  not Comparable or are not mutually comparable
  886.      * @throws NullPointerException if any key or value in the map is null
  887.      */
  888.     public TreeBidiMap(final Map<? extends K, ? extends V> map) {
  889.         this();
  890.         putAll(map);
  891.     }

  892.     /**
  893.      * Removes all mappings from this map.
  894.      */
  895.     @Override
  896.     public void clear() {
  897.         modify();

  898.         nodeCount = 0;
  899.         rootNode[KEY.ordinal()] = null;
  900.         rootNode[VALUE.ordinal()] = null;
  901.     }

  902.     /**
  903.      * Checks whether this map contains a mapping for the specified key.
  904.      * <p>
  905.      * The key must implement {@code Comparable}.
  906.      *
  907.      * @param key  key whose presence in this map is to be tested
  908.      * @return true if this map contains a mapping for the specified key
  909.      * @throws ClassCastException if the key is of an inappropriate type
  910.      * @throws NullPointerException if the key is null
  911.      */
  912.     @Override
  913.     public boolean containsKey(final Object key) {
  914.         checkKey(key);
  915.         return lookupKey(key) != null;
  916.     }

  917.     /**
  918.      * Checks whether this map contains a mapping for the specified value.
  919.      * <p>
  920.      * The value must implement {@code Comparable}.
  921.      *
  922.      * @param value  value whose presence in this map is to be tested
  923.      * @return true if this map contains a mapping for the specified value
  924.      * @throws ClassCastException if the value is of an inappropriate type
  925.      * @throws NullPointerException if the value is null
  926.      */
  927.     @Override
  928.     public boolean containsValue(final Object value) {
  929.         checkValue(value);
  930.         return lookupValue(value) != null;
  931.     }

  932.     /**
  933.      * Copies the color from one node to another, dealing with the fact
  934.      * that one or both nodes may, in fact, be null.
  935.      *
  936.      * @param from the node whose color we're copying; may be null
  937.      * @param to the node whose color we're changing; may be null
  938.      * @param dataElement  either the {@link DataElement#KEY key}
  939.      *                     or the {@link DataElement#VALUE value}.
  940.      */
  941.     private void copyColor(final Node<K, V> from, final Node<K, V> to, final DataElement dataElement) {
  942.         if (to != null) {
  943.             if (from == null) {
  944.                 // by default, make it black
  945.                 to.setBlack(dataElement);
  946.             } else {
  947.                 to.copyColor(from, dataElement);
  948.             }
  949.         }
  950.     }

  951.     /**
  952.      * Compares for equals as per the API.
  953.      *
  954.      * @param obj  the object to compare to
  955.      * @param dataElement  either the {@link DataElement#KEY key}
  956.      *                     or the {@link DataElement#VALUE value}.
  957.      * @return true if equal
  958.      */
  959.     private boolean doEquals(final Object obj, final DataElement dataElement) {
  960.         if (obj == this) {
  961.             return true;
  962.         }
  963.         if (!(obj instanceof Map)) {
  964.             return false;
  965.         }
  966.         final Map<?, ?> other = (Map<?, ?>) obj;
  967.         if (other.size() != size()) {
  968.             return false;
  969.         }

  970.         if (nodeCount > 0) {
  971.             try {
  972.                 for (final MapIterator<?, ?> it = getMapIterator(dataElement); it.hasNext(); ) {
  973.                     final Object key = it.next();
  974.                     final Object value = it.getValue();
  975.                     if (!value.equals(other.get(key))) {
  976.                         return false;
  977.                     }
  978.                 }
  979.             } catch (final ClassCastException | NullPointerException ex) {
  980.                 return false;
  981.             }
  982.         }
  983.         return true;
  984.     }

  985.     /**
  986.      * Gets the hash code value for this map as per the API.
  987.      *
  988.      * @param dataElement  either the {@link DataElement#KEY key}
  989.      *                     or the {@link DataElement#VALUE value}.
  990.      * @return the hash code value for this map
  991.      */
  992.     private int doHashCode(final DataElement dataElement) {
  993.         int total = 0;
  994.         if (nodeCount > 0) {
  995.             for (final MapIterator<?, ?> it = getMapIterator(dataElement); it.hasNext(); ) {
  996.                 final Object key = it.next();
  997.                 final Object value = it.getValue();
  998.                 total += key.hashCode() ^ value.hashCode();
  999.             }
  1000.         }
  1001.         return total;
  1002.     }

  1003.     /**
  1004.      * Puts logic.
  1005.      *
  1006.      * @param key  the key, always the main map key
  1007.      * @param value  the value, always the main map value
  1008.      */
  1009.     private void doPut(final K key, final V value) {
  1010.         checkKeyAndValue(key, value);

  1011.         // store previous and remove previous mappings
  1012.         doRemoveKey(key);
  1013.         doRemoveValue(value);

  1014.         Node<K, V> node = rootNode[KEY.ordinal()];
  1015.         if (node == null) {
  1016.             // map is empty
  1017.             final Node<K, V> root = new Node<>(key, value);
  1018.             rootNode[KEY.ordinal()] = root;
  1019.             rootNode[VALUE.ordinal()] = root;
  1020.             grow();

  1021.         } else {
  1022.             // add new mapping
  1023.             while (true) {
  1024.                 final int cmp = compare(key, node.getKey());

  1025.                 if (cmp == 0) {
  1026.                     // shouldn't happen
  1027.                     throw new IllegalArgumentException("Cannot store a duplicate key (\"" + key + "\") in this Map");
  1028.                 }
  1029.                 if (cmp < 0) {
  1030.                     if (node.getLeft(KEY) == null) {
  1031.                         final Node<K, V> newNode = new Node<>(key, value);

  1032.                         insertValue(newNode);
  1033.                         node.setLeft(newNode, KEY);
  1034.                         newNode.setParent(node, KEY);
  1035.                         doRedBlackInsert(newNode, KEY);
  1036.                         grow();

  1037.                         break;
  1038.                     }
  1039.                     node = node.getLeft(KEY);
  1040.                 } else { // cmp > 0
  1041.                     if (node.getRight(KEY) == null) {
  1042.                         final Node<K, V> newNode = new Node<>(key, value);

  1043.                         insertValue(newNode);
  1044.                         node.setRight(newNode, KEY);
  1045.                         newNode.setParent(node, KEY);
  1046.                         doRedBlackInsert(newNode, KEY);
  1047.                         grow();

  1048.                         break;
  1049.                     }
  1050.                     node = node.getRight(KEY);
  1051.                 }
  1052.             }
  1053.         }
  1054.     }

  1055.     /**
  1056.      * Complicated red-black delete stuff. Based on Sun's TreeMap
  1057.      * implementation, though it's barely recognizable anymore.
  1058.      *
  1059.      * @param deletedNode the node to be deleted
  1060.      */
  1061.     private void doRedBlackDelete(final Node<K, V> deletedNode) {
  1062.         for (final DataElement dataElement : DataElement.values()) {
  1063.             // if deleted node has both left and children, swap with
  1064.             // the next greater node
  1065.             if (deletedNode.getLeft(dataElement) != null && deletedNode.getRight(dataElement) != null) {
  1066.                 swapPosition(nextGreater(deletedNode, dataElement), deletedNode, dataElement);
  1067.             }
  1068.             final Node<K, V> replacement = deletedNode.getLeft(dataElement) != null ? deletedNode.getLeft(dataElement) : deletedNode.getRight(dataElement);
  1069.             if (replacement != null) {
  1070.                 replacement.setParent(deletedNode.getParent(dataElement), dataElement);
  1071.                 if (deletedNode.getParent(dataElement) == null) {
  1072.                     rootNode[dataElement.ordinal()] = replacement;
  1073.                 } else if (deletedNode == deletedNode.getParent(dataElement).getLeft(dataElement)) {
  1074.                     deletedNode.getParent(dataElement).setLeft(replacement, dataElement);
  1075.                 } else {
  1076.                     deletedNode.getParent(dataElement).setRight(replacement, dataElement);
  1077.                 }
  1078.                 deletedNode.setLeft(null, dataElement);
  1079.                 deletedNode.setRight(null, dataElement);
  1080.                 deletedNode.setParent(null, dataElement);
  1081.                 if (isBlack(deletedNode, dataElement)) {
  1082.                     doRedBlackDeleteFixup(replacement, dataElement);
  1083.                 }
  1084.             } else if (deletedNode.getParent(dataElement) == null) {
  1085.                 // replacement is null
  1086.                 // empty tree
  1087.                 rootNode[dataElement.ordinal()] = null;
  1088.             } else {
  1089.                 // deleted node had no children
  1090.                 if (isBlack(deletedNode, dataElement)) {
  1091.                     doRedBlackDeleteFixup(deletedNode, dataElement);
  1092.                 }
  1093.                 if (deletedNode.getParent(dataElement) != null) {
  1094.                     if (deletedNode == deletedNode.getParent(dataElement).getLeft(dataElement)) {
  1095.                         deletedNode.getParent(dataElement).setLeft(null, dataElement);
  1096.                     } else {
  1097.                         deletedNode.getParent(dataElement).setRight(null, dataElement);
  1098.                     }
  1099.                     deletedNode.setParent(null, dataElement);
  1100.                 }
  1101.             }
  1102.         }
  1103.         shrink();
  1104.     }

  1105.     /**
  1106.      * Complicated red-black delete stuff. Based on Sun's TreeMap
  1107.      * implementation, though it's barely recognizable anymore. This
  1108.      * rebalances the tree (somewhat, as red-black trees are not
  1109.      * perfectly balanced -- perfect balancing takes longer)
  1110.      *
  1111.      * @param replacementNode the node being replaced
  1112.      * @param dataElement  the KEY or VALUE int
  1113.      */
  1114.     private void doRedBlackDeleteFixup(final Node<K, V> replacementNode, final DataElement dataElement) {
  1115.         Node<K, V> currentNode = replacementNode;

  1116.         while (currentNode != rootNode[dataElement.ordinal()] && isBlack(currentNode, dataElement)) {
  1117.             if (currentNode.isLeftChild(dataElement)) {
  1118.                 Node<K, V> siblingNode = getRightChild(getParent(currentNode, dataElement), dataElement);

  1119.                 if (isRed(siblingNode, dataElement)) {
  1120.                     makeBlack(siblingNode, dataElement);
  1121.                     makeRed(getParent(currentNode, dataElement), dataElement);
  1122.                     rotateLeft(getParent(currentNode, dataElement), dataElement);

  1123.                     siblingNode = getRightChild(getParent(currentNode, dataElement), dataElement);
  1124.                 }

  1125.                 if (isBlack(getLeftChild(siblingNode, dataElement), dataElement)
  1126.                     && isBlack(getRightChild(siblingNode, dataElement), dataElement)) {
  1127.                     makeRed(siblingNode, dataElement);

  1128.                     currentNode = getParent(currentNode, dataElement);
  1129.                 } else {
  1130.                     if (isBlack(getRightChild(siblingNode, dataElement), dataElement)) {
  1131.                         makeBlack(getLeftChild(siblingNode, dataElement), dataElement);
  1132.                         makeRed(siblingNode, dataElement);
  1133.                         rotateRight(siblingNode, dataElement);

  1134.                         siblingNode = getRightChild(getParent(currentNode, dataElement), dataElement);
  1135.                     }

  1136.                     copyColor(getParent(currentNode, dataElement), siblingNode, dataElement);
  1137.                     makeBlack(getParent(currentNode, dataElement), dataElement);
  1138.                     makeBlack(getRightChild(siblingNode, dataElement), dataElement);
  1139.                     rotateLeft(getParent(currentNode, dataElement), dataElement);

  1140.                     currentNode = rootNode[dataElement.ordinal()];
  1141.                 }
  1142.             } else {
  1143.                 Node<K, V> siblingNode = getLeftChild(getParent(currentNode, dataElement), dataElement);

  1144.                 if (isRed(siblingNode, dataElement)) {
  1145.                     makeBlack(siblingNode, dataElement);
  1146.                     makeRed(getParent(currentNode, dataElement), dataElement);
  1147.                     rotateRight(getParent(currentNode, dataElement), dataElement);

  1148.                     siblingNode = getLeftChild(getParent(currentNode, dataElement), dataElement);
  1149.                 }

  1150.                 if (isBlack(getRightChild(siblingNode, dataElement), dataElement)
  1151.                     && isBlack(getLeftChild(siblingNode, dataElement), dataElement)) {
  1152.                     makeRed(siblingNode, dataElement);

  1153.                     currentNode = getParent(currentNode, dataElement);
  1154.                 } else {
  1155.                     if (isBlack(getLeftChild(siblingNode, dataElement), dataElement)) {
  1156.                         makeBlack(getRightChild(siblingNode, dataElement), dataElement);
  1157.                         makeRed(siblingNode, dataElement);
  1158.                         rotateLeft(siblingNode, dataElement);

  1159.                         siblingNode = getLeftChild(getParent(currentNode, dataElement), dataElement);
  1160.                     }

  1161.                     copyColor(getParent(currentNode, dataElement), siblingNode, dataElement);
  1162.                     makeBlack(getParent(currentNode, dataElement), dataElement);
  1163.                     makeBlack(getLeftChild(siblingNode, dataElement), dataElement);
  1164.                     rotateRight(getParent(currentNode, dataElement), dataElement);

  1165.                     currentNode = rootNode[dataElement.ordinal()];
  1166.                 }
  1167.             }
  1168.         }

  1169.         makeBlack(currentNode, dataElement);
  1170.     }

  1171.     /**
  1172.      * Complicated red-black insert stuff. Based on Sun's TreeMap
  1173.      * implementation, though it's barely recognizable anymore.
  1174.      *
  1175.      * @param insertedNode the node to be inserted
  1176.      * @param dataElement  the KEY or VALUE int
  1177.      */
  1178.     private void doRedBlackInsert(final Node<K, V> insertedNode, final DataElement dataElement) {
  1179.         Node<K, V> currentNode = insertedNode;
  1180.         makeRed(currentNode, dataElement);

  1181.         while (currentNode != null
  1182.             && currentNode != rootNode[dataElement.ordinal()]
  1183.             && isRed(currentNode.getParent(dataElement), dataElement)) {
  1184.             if (currentNode.isLeftChild(dataElement)) {
  1185.                 final Node<K, V> y = getRightChild(getGrandParent(currentNode, dataElement), dataElement);

  1186.                 if (isRed(y, dataElement)) {
  1187.                     makeBlack(getParent(currentNode, dataElement), dataElement);
  1188.                     makeBlack(y, dataElement);
  1189.                     makeRed(getGrandParent(currentNode, dataElement), dataElement);

  1190.                     currentNode = getGrandParent(currentNode, dataElement);
  1191.                 } else {
  1192.                     //dead code?
  1193.                     if (currentNode.isRightChild(dataElement)) {
  1194.                         currentNode = getParent(currentNode, dataElement);

  1195.                         rotateLeft(currentNode, dataElement);
  1196.                     }

  1197.                     makeBlack(getParent(currentNode, dataElement), dataElement);
  1198.                     makeRed(getGrandParent(currentNode, dataElement), dataElement);

  1199.                     if (getGrandParent(currentNode, dataElement) != null) {
  1200.                         rotateRight(getGrandParent(currentNode, dataElement), dataElement);
  1201.                     }
  1202.                 }
  1203.             } else {

  1204.                 // just like clause above, except swap left for right
  1205.                 final Node<K, V> y = getLeftChild(getGrandParent(currentNode, dataElement), dataElement);

  1206.                 if (isRed(y, dataElement)) {
  1207.                     makeBlack(getParent(currentNode, dataElement), dataElement);
  1208.                     makeBlack(y, dataElement);
  1209.                     makeRed(getGrandParent(currentNode, dataElement), dataElement);

  1210.                     currentNode = getGrandParent(currentNode, dataElement);
  1211.                 } else {
  1212.                     //dead code?
  1213.                     if (currentNode.isLeftChild(dataElement)) {
  1214.                         currentNode = getParent(currentNode, dataElement);

  1215.                         rotateRight(currentNode, dataElement);
  1216.                     }

  1217.                     makeBlack(getParent(currentNode, dataElement), dataElement);
  1218.                     makeRed(getGrandParent(currentNode, dataElement), dataElement);

  1219.                     if (getGrandParent(currentNode, dataElement) != null) {
  1220.                         rotateLeft(getGrandParent(currentNode, dataElement), dataElement);
  1221.                     }
  1222.                 }
  1223.             }
  1224.         }

  1225.         makeBlack(rootNode[dataElement.ordinal()], dataElement);
  1226.     }

  1227.     private V doRemoveKey(final Object key) {
  1228.         final Node<K, V> node = lookupKey(key);
  1229.         if (node == null) {
  1230.             return null;
  1231.         }
  1232.         doRedBlackDelete(node);
  1233.         return node.getValue();
  1234.     }

  1235.     private K doRemoveValue(final Object value) {
  1236.         final Node<K, V> node = lookupValue(value);
  1237.         if (node == null) {
  1238.             return null;
  1239.         }
  1240.         doRedBlackDelete(node);
  1241.         return node.getKey();
  1242.     }

  1243.     /**
  1244.      * Gets the string form of this map as per AbstractMap.
  1245.      *
  1246.      * @param dataElement  either the {@link DataElement#KEY key}
  1247.      *                     or the {@link DataElement#VALUE value}.
  1248.      * @return the string form of this map
  1249.      */
  1250.     private String doToString(final DataElement dataElement) {
  1251.         if (nodeCount == 0) {
  1252.             return "{}";
  1253.         }
  1254.         final StringBuilder buf = new StringBuilder(nodeCount * 32);
  1255.         buf.append('{');
  1256.         final MapIterator<?, ?> it = getMapIterator(dataElement);
  1257.         boolean hasNext = it.hasNext();
  1258.         while (hasNext) {
  1259.             final Object key = it.next();
  1260.             final Object value = it.getValue();
  1261.             buf.append(key == this ? "(this Map)" : key)
  1262.                 .append('=')
  1263.                 .append(value == this ? "(this Map)" : value);

  1264.             hasNext = it.hasNext();
  1265.             if (hasNext) {
  1266.                 buf.append(", ");
  1267.             }
  1268.         }

  1269.         buf.append('}');
  1270.         return buf.toString();
  1271.     }

  1272.     /**
  1273.      * Returns a set view of the entries contained in this map in key order.
  1274.      * For simple iteration through the map, the MapIterator is quicker.
  1275.      * <p>
  1276.      * The set is backed by the map, so changes to the map are reflected in
  1277.      * the set, and vice-versa. If the map is modified while an iteration over
  1278.      * the set is in progress, the results of the iteration are undefined.
  1279.      * <p>
  1280.      * The set supports element removal, which removes the corresponding mapping
  1281.      * from the map. It does not support the add or addAll operations.
  1282.      * The returned MapEntry objects do not support setValue.
  1283.      *
  1284.      * @return a set view of the values contained in this map.
  1285.      */
  1286.     @Override
  1287.     public Set<Map.Entry<K, V>> entrySet() {
  1288.         if (entrySet == null) {
  1289.             entrySet = new EntryView();
  1290.         }
  1291.         return entrySet;
  1292.     }

  1293.     /**
  1294.      * Compares for equals as per the API.
  1295.      *
  1296.      * @param obj  the object to compare to
  1297.      * @return true if equal
  1298.      */
  1299.     @Override
  1300.     public boolean equals(final Object obj) {
  1301.         return this.doEquals(obj, KEY);
  1302.     }

  1303.     /**
  1304.      * Gets the first (lowest) key currently in this map.
  1305.      *
  1306.      * @return the first (lowest) key currently in this sorted map
  1307.      * @throws NoSuchElementException if this map is empty
  1308.      */
  1309.     @Override
  1310.     public K firstKey() {
  1311.         if (nodeCount == 0) {
  1312.             throw new NoSuchElementException("Map is empty");
  1313.         }
  1314.         return leastNode(rootNode[KEY.ordinal()], KEY).getKey();
  1315.     }

  1316.     /**
  1317.      * Gets the value to which this map maps the specified key.
  1318.      * Returns null if the map contains no mapping for this key.
  1319.      * <p>
  1320.      * The key must implement {@code Comparable}.
  1321.      *
  1322.      * @param key  key whose associated value is to be returned
  1323.      * @return the value to which this map maps the specified key,
  1324.      *  or null if the map contains no mapping for this key
  1325.      * @throws ClassCastException if the key is of an inappropriate type
  1326.      * @throws NullPointerException if the key is null
  1327.      */
  1328.     @Override
  1329.     public V get(final Object key) {
  1330.         checkKey(key);
  1331.         final Node<K, V> node = lookupKey(key);
  1332.         return node == null ? null : node.getValue();
  1333.     }

  1334.     /**
  1335.      * Gets a node's grandparent. mind you, the node, its parent, or
  1336.      * its grandparent may not exist. No problem.
  1337.      *
  1338.      * @param node the node (may be null) in question
  1339.      * @param dataElement  either the {@link DataElement#KEY key}
  1340.      *                     or the {@link DataElement#VALUE value}.
  1341.      */
  1342.     private Node<K, V> getGrandParent(final Node<K, V> node, final DataElement dataElement) {
  1343.         return getParent(getParent(node, dataElement), dataElement);
  1344.     }

  1345.     /**
  1346.      * Gets the key to which this map maps the specified value.
  1347.      * Returns null if the map contains no mapping for this value.
  1348.      * <p>
  1349.      * The value must implement {@code Comparable}.
  1350.      *
  1351.      * @param value  value whose associated key is to be returned.
  1352.      * @return the key to which this map maps the specified value,
  1353.      *  or null if the map contains no mapping for this value.
  1354.      * @throws ClassCastException if the value is of an inappropriate type
  1355.      * @throws NullPointerException if the value is null
  1356.      */
  1357.     @Override
  1358.     public K getKey(final Object value) {
  1359.         checkValue(value);
  1360.         final Node<K, V> node = lookupValue(value);
  1361.         return node == null ? null : node.getKey();
  1362.     }

  1363.     /**
  1364.      * Gets a node's left child. mind you, the node may not exist. no
  1365.      * problem.
  1366.      *
  1367.      * @param node the node (may be null) in question
  1368.      * @param dataElement  either the {@link DataElement#KEY key}
  1369.      *                     or the {@link DataElement#VALUE value}.
  1370.      */
  1371.     private Node<K, V> getLeftChild(final Node<K, V> node, final DataElement dataElement) {
  1372.         return node == null ? null : node.getLeft(dataElement);
  1373.     }

  1374.     private MapIterator<?, ?> getMapIterator(final DataElement dataElement) {
  1375.         switch (dataElement) {
  1376.         case KEY:
  1377.             return new ViewMapIterator(KEY);
  1378.         case VALUE:
  1379.             return new InverseViewMapIterator(VALUE);
  1380.         default:
  1381.             throw new IllegalArgumentException();
  1382.         }
  1383.     }

  1384.     /**
  1385.      * Gets a node's parent. mind you, the node, or its parent, may not
  1386.      * exist. no problem.
  1387.      *
  1388.      * @param node the node (may be null) in question
  1389.      * @param dataElement  either the {@link DataElement#KEY key}
  1390.      *                     or the {@link DataElement#VALUE value}.
  1391.      */
  1392.     private Node<K, V> getParent(final Node<K, V> node, final DataElement dataElement) {
  1393.         return node == null ? null : node.getParent(dataElement);
  1394.     }

  1395.     /**
  1396.      * Gets a node's right child. mind you, the node may not exist. no
  1397.      * problem.
  1398.      *
  1399.      * @param node the node (may be null) in question
  1400.      * @param dataElement  either the {@link DataElement#KEY key}
  1401.      *                     or the {@link DataElement#VALUE value}.
  1402.      */
  1403.     private Node<K, V> getRightChild(final Node<K, V> node, final DataElement dataElement) {
  1404.         return node == null ? null : node.getRight(dataElement);
  1405.     }

  1406.     /**
  1407.      * Finds the greatest node from a given node.
  1408.      *
  1409.      * @param node  the node from which we will start searching
  1410.      * @param dataElement  either the {@link DataElement#KEY key}
  1411.      *                     or the {@link DataElement#VALUE value}.
  1412.      * @return the greatest node, from the specified node
  1413.      */
  1414.     private Node<K, V> greatestNode(final Node<K, V> node, final DataElement dataElement) {
  1415.         Node<K, V> rval = node;
  1416.         if (rval != null) {
  1417.             while (rval.getRight(dataElement) != null) {
  1418.                 rval = rval.getRight(dataElement);
  1419.             }
  1420.         }
  1421.         return rval;
  1422.     }

  1423.     /**
  1424.      * Bumps up the size and note that the map has changed.
  1425.      */
  1426.     private void grow() {
  1427.         modify();
  1428.         nodeCount++;
  1429.     }

  1430.     /**
  1431.      * Gets the hash code value for this map as per the API.
  1432.      *
  1433.      * @return the hash code value for this map
  1434.      */
  1435.     @Override
  1436.     public int hashCode() {
  1437.         return this.doHashCode(KEY);
  1438.     }

  1439.     /**
  1440.      * Inserts a node by its value.
  1441.      *
  1442.      * @param newNode the node to be inserted
  1443.      * @throws IllegalArgumentException if the node already exists
  1444.      *                                     in the value mapping
  1445.      */
  1446.     private void insertValue(final Node<K, V> newNode) throws IllegalArgumentException {
  1447.         Node<K, V> node = rootNode[VALUE.ordinal()];

  1448.         while (true) {
  1449.             final int cmp = compare(newNode.getValue(), node.getValue());

  1450.             if (cmp == 0) {
  1451.                 throw new IllegalArgumentException(
  1452.                     "Cannot store a duplicate value (\"" + newNode.getData(VALUE) + "\") in this Map");
  1453.             }
  1454.             if (cmp < 0) {
  1455.                 if (node.getLeft(VALUE) == null) {
  1456.                     node.setLeft(newNode, VALUE);
  1457.                     newNode.setParent(node, VALUE);
  1458.                     doRedBlackInsert(newNode, VALUE);

  1459.                     break;
  1460.                 }
  1461.                 node = node.getLeft(VALUE);
  1462.             } else { // cmp > 0
  1463.                 if (node.getRight(VALUE) == null) {
  1464.                     node.setRight(newNode, VALUE);
  1465.                     newNode.setParent(node, VALUE);
  1466.                     doRedBlackInsert(newNode, VALUE);

  1467.                     break;
  1468.                 }
  1469.                 node = node.getRight(VALUE);
  1470.             }
  1471.         }
  1472.     }

  1473.     /**
  1474.      * Gets the inverse map for comparison.
  1475.      *
  1476.      * @return the inverse map
  1477.      */
  1478.     @Override
  1479.     public OrderedBidiMap<V, K> inverseBidiMap() {
  1480.         if (inverse == null) {
  1481.             inverse = new Inverse();
  1482.         }
  1483.         return inverse;
  1484.     }

  1485.     /**
  1486.      * Checks whether the map is empty or not.
  1487.      *
  1488.      * @return true if the map is empty
  1489.      */
  1490.     @Override
  1491.     public boolean isEmpty() {
  1492.         return nodeCount == 0;
  1493.     }

  1494.     /**
  1495.      * Returns a set view of the keys contained in this map in key order.
  1496.      * <p>
  1497.      * The set is backed by the map, so changes to the map are reflected in
  1498.      * the set, and vice-versa. If the map is modified while an iteration over
  1499.      * the set is in progress, the results of the iteration are undefined.
  1500.      * <p>
  1501.      * The set supports element removal, which removes the corresponding mapping
  1502.      * from the map. It does not support the add or addAll operations.
  1503.      *
  1504.      * @return a set view of the keys contained in this map.
  1505.      */
  1506.     @Override
  1507.     public Set<K> keySet() {
  1508.         if (keySet == null) {
  1509.             keySet = new KeyView(KEY);
  1510.         }
  1511.         return keySet;
  1512.     }

  1513.     /**
  1514.      * Gets the last (highest) key currently in this map.
  1515.      *
  1516.      * @return the last (highest) key currently in this sorted map
  1517.      * @throws NoSuchElementException if this map is empty
  1518.      */
  1519.     @Override
  1520.     public K lastKey() {
  1521.         if (nodeCount == 0) {
  1522.             throw new NoSuchElementException("Map is empty");
  1523.         }
  1524.         return greatestNode(rootNode[KEY.ordinal()], KEY).getKey();
  1525.     }

  1526.     /**
  1527.      * Finds the least node from a given node.
  1528.      *
  1529.      * @param node  the node from which we will start searching
  1530.      * @param dataElement  either the {@link DataElement#KEY key}
  1531.      *                     or the {@link DataElement#VALUE value}.
  1532.      * @return the smallest node, from the specified node, in the
  1533.      *         specified mapping
  1534.      */
  1535.     private Node<K, V> leastNode(final Node<K, V> node, final DataElement dataElement) {
  1536.         Node<K, V> rval = node;
  1537.         if (rval != null) {
  1538.             while (rval.getLeft(dataElement) != null) {
  1539.                 rval = rval.getLeft(dataElement);
  1540.             }
  1541.         }
  1542.         return rval;
  1543.     }

  1544.     /**
  1545.      * Does the actual lookup of a piece of data.
  1546.      *
  1547.      * @param data the key or value to be looked up
  1548.      * @param dataElement  either the {@link DataElement#KEY key}
  1549.      *                     or the {@link DataElement#VALUE value}.
  1550.      * @return the desired Node, or null if there is no mapping of the
  1551.      *         specified data
  1552.      */
  1553.     @SuppressWarnings("unchecked")
  1554.     private <T extends Comparable<T>> Node<K, V> lookup(final Object data, final DataElement dataElement) {
  1555.         Node<K, V> rval = null;
  1556.         Node<K, V> node = rootNode[dataElement.ordinal()];

  1557.         while (node != null) {
  1558.             final int cmp = compare((T) data, (T) node.getData(dataElement));
  1559.             if (cmp == 0) {
  1560.                 rval = node;
  1561.                 break;
  1562.             }
  1563.             node = cmp < 0 ? node.getLeft(dataElement) : node.getRight(dataElement);
  1564.         }

  1565.         return rval;
  1566.     }

  1567.     private Node<K, V> lookupKey(final Object key) {
  1568.         return this.<K>lookup(key, KEY);
  1569.     }

  1570.     private Node<K, V> lookupValue(final Object value) {
  1571.         return this.<V>lookup(value, VALUE);
  1572.     }

  1573.     @Override
  1574.     public OrderedMapIterator<K, V> mapIterator() {
  1575.         if (isEmpty()) {
  1576.             return EmptyOrderedMapIterator.<K, V>emptyOrderedMapIterator();
  1577.         }
  1578.         return new ViewMapIterator(KEY);
  1579.     }

  1580.     /**
  1581.      * Increments the modification count -- used to check for
  1582.      * concurrent modification of the map through the map and through
  1583.      * an Iterator from one of its Set or Collection views.
  1584.      */
  1585.     private void modify() {
  1586.         modifications++;
  1587.     }

  1588.     /**
  1589.      * Gets the next larger node from the specified node.
  1590.      *
  1591.      * @param node the node to be searched from
  1592.      * @param dataElement  either the {@link DataElement#KEY key}
  1593.      *                     or the {@link DataElement#VALUE value}.
  1594.      * @return the specified node
  1595.      */
  1596.     private Node<K, V> nextGreater(final Node<K, V> node, final DataElement dataElement) {
  1597.         final Node<K, V> rval;
  1598.         if (node == null) {
  1599.             rval = null;
  1600.         } else if (node.getRight(dataElement) != null) {
  1601.             // everything to the node's right is larger. The least of
  1602.             // the right node's descendants is the next larger node
  1603.             rval = leastNode(node.getRight(dataElement), dataElement);
  1604.         } else {
  1605.             // traverse up our ancestry until we find an ancestor that
  1606.             // is null or one whose left child is our ancestor. If we
  1607.             // find a null, then this node IS the largest node in the
  1608.             // tree, and there is no greater node. Otherwise, we are
  1609.             // the largest node in the subtree on that ancestor's left
  1610.             // ... and that ancestor is the next greatest node
  1611.             Node<K, V> parent = node.getParent(dataElement);
  1612.             Node<K, V> child = node;

  1613.             while (parent != null && child == parent.getRight(dataElement)) {
  1614.                 child = parent;
  1615.                 parent = parent.getParent(dataElement);
  1616.             }
  1617.             rval = parent;
  1618.         }
  1619.         return rval;
  1620.     }

  1621.     /**
  1622.      * Gets the next key after the one specified.
  1623.      * <p>
  1624.      * The key must implement {@code Comparable}.
  1625.      *
  1626.      * @param key the key to search for next from
  1627.      * @return the next key, null if no match or at end
  1628.      */
  1629.     @Override
  1630.     public K nextKey(final K key) {
  1631.         checkKey(key);
  1632.         final Node<K, V> node = nextGreater(lookupKey(key), KEY);
  1633.         return node == null ? null : node.getKey();
  1634.     }

  1635.     /**
  1636.      * Gets the next smaller node from the specified node.
  1637.      *
  1638.      * @param node the node to be searched from
  1639.      * @param dataElement  either the {@link DataElement#KEY key}
  1640.      *                     or the {@link DataElement#VALUE value}.
  1641.      * @return the specified node
  1642.      */
  1643.     private Node<K, V> nextSmaller(final Node<K, V> node, final DataElement dataElement) {
  1644.         final Node<K, V> rval;
  1645.         if (node == null) {
  1646.             rval = null;
  1647.         } else if (node.getLeft(dataElement) != null) {
  1648.             // everything to the node's left is smaller. The greatest of
  1649.             // the left node's descendants is the next smaller node
  1650.             rval = greatestNode(node.getLeft(dataElement), dataElement);
  1651.         } else {
  1652.             // traverse up our ancestry until we find an ancestor that
  1653.             // is null or one whose right child is our ancestor. If we
  1654.             // find a null, then this node IS the largest node in the
  1655.             // tree, and there is no greater node. Otherwise, we are
  1656.             // the largest node in the subtree on that ancestor's right
  1657.             // ... and that ancestor is the next greatest node
  1658.             Node<K, V> parent = node.getParent(dataElement);
  1659.             Node<K, V> child = node;

  1660.             while (parent != null && child == parent.getLeft(dataElement)) {
  1661.                 child = parent;
  1662.                 parent = parent.getParent(dataElement);
  1663.             }
  1664.             rval = parent;
  1665.         }
  1666.         return rval;
  1667.     }

  1668.     /**
  1669.      * Gets the previous key before the one specified.
  1670.      * <p>
  1671.      * The key must implement {@code Comparable}.
  1672.      *
  1673.      * @param key the key to search for previous from
  1674.      * @return the previous key, null if no match or at start
  1675.      */
  1676.     @Override
  1677.     public K previousKey(final K key) {
  1678.         checkKey(key);
  1679.         final Node<K, V> node = nextSmaller(lookupKey(key), KEY);
  1680.         return node == null ? null : node.getKey();
  1681.     }

  1682.     /**
  1683.      * Puts the key-value pair into the map, replacing any previous pair.
  1684.      * <p>
  1685.      * When adding a key-value pair, the value may already exist in the map
  1686.      * against a different key. That mapping is removed, to ensure that the
  1687.      * value only occurs once in the inverse map.
  1688.      * <pre>
  1689.      *  BidiMap map1 = new TreeBidiMap();
  1690.      *  map.put("A","B");  // contains A mapped to B, as per Map
  1691.      *  map.put("A","C");  // contains A mapped to C, as per Map
  1692.      *
  1693.      *  BidiMap map2 = new TreeBidiMap();
  1694.      *  map.put("A","B");  // contains A mapped to B, as per Map
  1695.      *  map.put("C","B");  // contains C mapped to B, key A is removed
  1696.      * </pre>
  1697.      * <p>
  1698.      * Both key and value must implement {@code Comparable}.
  1699.      *
  1700.      * @param key  key with which the specified value is to be  associated
  1701.      * @param value  value to be associated with the specified key
  1702.      * @return the previous value for the key
  1703.      * @throws ClassCastException if the key is of an inappropriate type
  1704.      * @throws NullPointerException if the key is null
  1705.      */
  1706.     @Override
  1707.     public V put(final K key, final V value) {
  1708.         final V result = get(key);
  1709.         doPut(key, value);
  1710.         return result;
  1711.     }

  1712.     /**
  1713.      * Puts all the mappings from the specified map into this map.
  1714.      * <p>
  1715.      * All keys and values must implement {@code Comparable}.
  1716.      *
  1717.      * @param map  the map to copy from
  1718.      */
  1719.     @Override
  1720.     public void putAll(final Map<? extends K, ? extends V> map) {
  1721.         for (final Map.Entry<? extends K, ? extends V> e : map.entrySet()) {
  1722.             put(e.getKey(), e.getValue());
  1723.         }
  1724.     }

  1725.     /**
  1726.      * Deserializes the content of the stream.
  1727.      *
  1728.      * @param stream the input stream
  1729.      * @throws IOException if an error occurs while reading from the stream
  1730.      * @throws ClassNotFoundException if an object read from the stream cannot be loaded
  1731.      */
  1732.     @SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect
  1733.     private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException {
  1734.         stream.defaultReadObject();
  1735.         rootNode = new Node[2];
  1736.         final int size = stream.readInt();
  1737.         for (int i = 0; i < size; i++) {
  1738.             final K k = (K) stream.readObject();
  1739.             final V v = (V) stream.readObject();
  1740.             put(k, v);
  1741.         }
  1742.     }

  1743.     /**
  1744.      * Removes the mapping for this key from this map if present.
  1745.      * <p>
  1746.      * The key must implement {@code Comparable}.
  1747.      *
  1748.      * @param key  key whose mapping is to be removed from the map.
  1749.      * @return previous value associated with specified key,
  1750.      *  or null if there was no mapping for key.
  1751.      * @throws ClassCastException if the key is of an inappropriate type
  1752.      * @throws NullPointerException if the key is null
  1753.      */
  1754.     @Override
  1755.     public V remove(final Object key) {
  1756.         return doRemoveKey(key);
  1757.     }

  1758.     /**
  1759.      * Removes the mapping for this value from this map if present.
  1760.      * <p>
  1761.      * The value must implement {@code Comparable}.
  1762.      *
  1763.      * @param value  value whose mapping is to be removed from the map
  1764.      * @return previous key associated with specified value,
  1765.      *  or null if there was no mapping for value.
  1766.      * @throws ClassCastException if the value is of an inappropriate type
  1767.      * @throws NullPointerException if the value is null
  1768.      */
  1769.     @Override
  1770.     public K removeValue(final Object value) {
  1771.         return doRemoveValue(value);
  1772.     }

  1773.     /**
  1774.      * Does a rotate left. standard fare in the world of balanced trees.
  1775.      *
  1776.      * @param node the node to be rotated
  1777.      * @param dataElement  either the {@link DataElement#KEY key}
  1778.      *                     or the {@link DataElement#VALUE value}.
  1779.      */
  1780.     private void rotateLeft(final Node<K, V> node, final DataElement dataElement) {
  1781.         final Node<K, V> rightChild = node.getRight(dataElement);
  1782.         node.setRight(rightChild.getLeft(dataElement), dataElement);

  1783.         if (rightChild.getLeft(dataElement) != null) {
  1784.             rightChild.getLeft(dataElement).setParent(node, dataElement);
  1785.         }
  1786.         rightChild.setParent(node.getParent(dataElement), dataElement);

  1787.         if (node.getParent(dataElement) == null) {
  1788.             // node was the root ... now its right child is the root
  1789.             rootNode[dataElement.ordinal()] = rightChild;
  1790.         } else if (node.getParent(dataElement).getLeft(dataElement) == node) {
  1791.             node.getParent(dataElement).setLeft(rightChild, dataElement);
  1792.         } else {
  1793.             node.getParent(dataElement).setRight(rightChild, dataElement);
  1794.         }

  1795.         rightChild.setLeft(node, dataElement);
  1796.         node.setParent(rightChild, dataElement);
  1797.     }

  1798.     /**
  1799.      * Does a rotate right. standard fare in the world of balanced trees.
  1800.      *
  1801.      * @param node the node to be rotated
  1802.      * @param dataElement  either the {@link DataElement#KEY key}
  1803.      *                     or the {@link DataElement#VALUE value}.
  1804.      */
  1805.     private void rotateRight(final Node<K, V> node, final DataElement dataElement) {
  1806.         final Node<K, V> leftChild = node.getLeft(dataElement);
  1807.         node.setLeft(leftChild.getRight(dataElement), dataElement);
  1808.         if (leftChild.getRight(dataElement) != null) {
  1809.             leftChild.getRight(dataElement).setParent(node, dataElement);
  1810.         }
  1811.         leftChild.setParent(node.getParent(dataElement), dataElement);

  1812.         if (node.getParent(dataElement) == null) {
  1813.             // node was the root ... now its left child is the root
  1814.             rootNode[dataElement.ordinal()] = leftChild;
  1815.         } else if (node.getParent(dataElement).getRight(dataElement) == node) {
  1816.             node.getParent(dataElement).setRight(leftChild, dataElement);
  1817.         } else {
  1818.             node.getParent(dataElement).setLeft(leftChild, dataElement);
  1819.         }

  1820.         leftChild.setRight(node, dataElement);
  1821.         node.setParent(leftChild, dataElement);
  1822.     }

  1823.     /**
  1824.      * Decrements the size and note that the map has changed.
  1825.      */
  1826.     private void shrink() {
  1827.         modify();
  1828.         nodeCount--;
  1829.     }

  1830.     /**
  1831.      * Returns the number of key-value mappings in this map.
  1832.      *
  1833.      * @return the number of key-value mappings in this map
  1834.      */
  1835.     @Override
  1836.     public int size() {
  1837.         return nodeCount;
  1838.     }

  1839.     /**
  1840.      * Swaps two nodes (except for their content), taking care of
  1841.      * special cases where one is the other's parent ... hey, it
  1842.      * happens.
  1843.      *
  1844.      * @param x one node
  1845.      * @param y another node
  1846.      * @param dataElement  the KEY or VALUE int
  1847.      */
  1848.     private void swapPosition(final Node<K, V> x, final Node<K, V> y, final DataElement dataElement) {
  1849.         // Save initial values.
  1850.         final Node<K, V> xFormerParent = x.getParent(dataElement);
  1851.         final Node<K, V> xFormerLeftChild = x.getLeft(dataElement);
  1852.         final Node<K, V> xFormerRightChild = x.getRight(dataElement);
  1853.         final Node<K, V> yFormerParent = y.getParent(dataElement);
  1854.         final Node<K, V> yFormerLeftChild = y.getLeft(dataElement);
  1855.         final Node<K, V> yFormerRightChild = y.getRight(dataElement);
  1856.         final boolean xWasLeftChild =
  1857.                 x.getParent(dataElement) != null && x == x.getParent(dataElement).getLeft(dataElement);
  1858.         final boolean yWasLeftChild =
  1859.                 y.getParent(dataElement) != null && y == y.getParent(dataElement).getLeft(dataElement);

  1860.         // Swap, handling special cases of one being the other's parent.
  1861.         if (x == yFormerParent) { // x was y's parent
  1862.             x.setParent(y, dataElement);

  1863.             if (yWasLeftChild) {
  1864.                 y.setLeft(x, dataElement);
  1865.                 y.setRight(xFormerRightChild, dataElement);
  1866.             } else {
  1867.                 y.setRight(x, dataElement);
  1868.                 y.setLeft(xFormerLeftChild, dataElement);
  1869.             }
  1870.         } else {
  1871.             x.setParent(yFormerParent, dataElement);

  1872.             if (yFormerParent != null) {
  1873.                 if (yWasLeftChild) {
  1874.                     yFormerParent.setLeft(x, dataElement);
  1875.                 } else {
  1876.                     yFormerParent.setRight(x, dataElement);
  1877.                 }
  1878.             }

  1879.             y.setLeft(xFormerLeftChild, dataElement);
  1880.             y.setRight(xFormerRightChild, dataElement);
  1881.         }

  1882.         if (y == xFormerParent) { // y was x's parent
  1883.             y.setParent(x, dataElement);

  1884.             if (xWasLeftChild) {
  1885.                 x.setLeft(y, dataElement);
  1886.                 x.setRight(yFormerRightChild, dataElement);
  1887.             } else {
  1888.                 x.setRight(y, dataElement);
  1889.                 x.setLeft(yFormerLeftChild, dataElement);
  1890.             }
  1891.         } else {
  1892.             y.setParent(xFormerParent, dataElement);

  1893.             if (xFormerParent != null) {
  1894.                 if (xWasLeftChild) {
  1895.                     xFormerParent.setLeft(y, dataElement);
  1896.                 } else {
  1897.                     xFormerParent.setRight(y, dataElement);
  1898.                 }
  1899.             }

  1900.             x.setLeft(yFormerLeftChild, dataElement);
  1901.             x.setRight(yFormerRightChild, dataElement);
  1902.         }

  1903.         // Fix children's parent pointers
  1904.         if (x.getLeft(dataElement) != null) {
  1905.             x.getLeft(dataElement).setParent(x, dataElement);
  1906.         }

  1907.         if (x.getRight(dataElement) != null) {
  1908.             x.getRight(dataElement).setParent(x, dataElement);
  1909.         }

  1910.         if (y.getLeft(dataElement) != null) {
  1911.             y.getLeft(dataElement).setParent(y, dataElement);
  1912.         }

  1913.         if (y.getRight(dataElement) != null) {
  1914.             y.getRight(dataElement).setParent(y, dataElement);
  1915.         }

  1916.         x.swapColors(y, dataElement);

  1917.         // Check if root changed
  1918.         if (rootNode[dataElement.ordinal()] == x) {
  1919.             rootNode[dataElement.ordinal()] = y;
  1920.         } else if (rootNode[dataElement.ordinal()] == y) {
  1921.             rootNode[dataElement.ordinal()] = x;
  1922.         }
  1923.     }

  1924.     /**
  1925.      * Returns a string version of this Map in standard format.
  1926.      *
  1927.      * @return a standard format string version of the map
  1928.      */
  1929.     @Override
  1930.     public String toString() {
  1931.         return this.doToString(KEY);
  1932.     }

  1933.     /**
  1934.      * Returns a set view of the values contained in this map in key order.
  1935.      * The returned object can be cast to a Set.
  1936.      * <p>
  1937.      * The set is backed by the map, so changes to the map are reflected in
  1938.      * the set, and vice-versa. If the map is modified while an iteration over
  1939.      * the set is in progress, the results of the iteration are undefined.
  1940.      * <p>
  1941.      * The set supports element removal, which removes the corresponding mapping
  1942.      * from the map. It does not support the add or addAll operations.
  1943.      *
  1944.      * @return a set view of the values contained in this map.
  1945.      */
  1946.     @Override
  1947.     public Set<V> values() {
  1948.         if (valuesSet == null) {
  1949.             valuesSet = new ValueView(KEY);
  1950.         }
  1951.         return valuesSet;
  1952.     }

  1953.     /**
  1954.      * Serializes this object to an ObjectOutputStream.
  1955.      *
  1956.      * @param out the target ObjectOutputStream.
  1957.      * @throws IOException thrown when an I/O errors occur writing to the target stream.
  1958.      */
  1959.     private void writeObject(final ObjectOutputStream out) throws IOException {
  1960.         out.defaultWriteObject();
  1961.         out.writeInt(this.size());
  1962.         for (final Entry<K, V> entry : entrySet()) {
  1963.             out.writeObject(entry.getKey());
  1964.             out.writeObject(entry.getValue());
  1965.         }
  1966.     }

  1967. }