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