View Javadoc

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